/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2019, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2019 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// #include "OdaCommon.h" #include "DbAssocNetCloneCtx.h" #include "DbAssocNetworkDeepCloneReactor.h" #include "DbAssocNetworkLongTransactionReactor.h" #include "DbAssoc2dConstraintGroup.h" #include "DbAssocNetwork.h" #include "DbAssocValueDependency.h" #include "DbImpAssocDependency.h" #include "OdExpression.h" #include "OdUnitsFormatter.h" #include "DbAssocVariable.h" #include "DbImpAssoc2dConstraintGroup.h" #include "DbDictionary.h" #include "OdCharConverter.h" #include "OdDbAssocPersSubentIdPE.h" #include "OdImplicitConstr.h" #define STL_USING_ALGORITHM #include "OdaSTL.h" #include "DbHostAppServices.h" #include "DbImpAssocVariable.h" #include "DbDictionaryVar.h" #include "OdHashSet.h" #include "DbPlaceHolder.h" #include "DbBlockTableRecord.h" #include "DbAssocManager.h" #include "DebugStuff.h" ODRX_CONS_DEFINE_MEMBERS(OdDbAssocNetCloneCtx, OdDbObjectReactor, RXIMPL_CONSTR); static bool isInLongTransaction(OdDbIdMapping& idMap) { if (OdApLongTransactionManager* pTM = odapLongTransactionManager()) { const OdDbObjectId origTransId = pTM->currentLongTransactionFor(idMap.origDb()); const OdDbObjectId destTransId = pTM->currentLongTransactionFor(idMap.destDb()); if (origTransId || destTransId) return true; } return false; } void OdDbAssocNetCloneCtx::attach(OdDbIdMapping& idMap) { ODA_ASSERT(OdDbAssocNetCloneCtx::fromDatabase(idMap.destDb()).isNull()); OdSmartPtr res = OdRxObjectImpl::createObject(); res->idMap = &idMap; idMap.destDb()->OdDbObject::addReactor( res ); } bool OdDbAssocNetCloneCtx::detach(OdDbDatabase* fromDestDb) { OdDbAssocNetCloneCtxPtr ctx = OdDbAssocNetCloneCtx::fromDatabase(fromDestDb); if(ctx.get()) { fromDestDb->OdDbObject::removeReactor(ctx); return true; } return false; } class DimConstraintData : public OdRxObjectImpl { public: ODRX_DECLARE_MEMBERS(DimConstraintData); virtual ~DimConstraintData() {}; virtual bool init(OdGeomConstraint* pConstraint) = 0; virtual bool fill(OdDbAssoc2dConstraintGroup * pDestGroup) = 0; protected: bool init(OdExplicitConstraint* pConstraint, unsigned int reqGeomsLength) { OdArray apConsGeoms; pConstraint->getConnectedGeometries(apConsGeoms); unsigned int consGeomsLength = apConsGeoms.length(); if (consGeomsLength != reqGeomsLength) return false; ODA_ASSERT(consGeomsLength <= 3); m_valueDependencyId = pConstraint->valueDependencyId(); m_dimDependencyId = pConstraint->dimDependencyId(); for (unsigned int i=0; igetFullSubentPaths(m_aSubentPath[i]); if (res != eOk) return false; } return true; } bool getGeometries(OdDbAssoc2dConstraintGroupPtr pGroup, OdConstrainedGeometry * apConsGeom[3], const unsigned int reqGeomsLength) { ODA_ASSERT(reqGeomsLength <= 3); bool bCreateArcLineMid = true; for (unsigned int i = 0; igetConstrainedGeometry(m_aSubentPath[i][0], apConsGeom[i], bCreateArcLineMid)) return false; } return true; } OdDbObjectId m_valueDependencyId; OdDbObjectId m_dimDependencyId; private: OdDbFullSubentPathArray m_aSubentPath[3]; }; ODRX_NO_CONS_DEFINE_MEMBERS(DimConstraintData, OdRxObject); typedef OdSmartPtr DimConstraintDataPtr; class DistanceConstraintData : public DimConstraintData { public: ODRX_DECLARE_MEMBERS(DistanceConstraintData); ~DistanceConstraintData() {}; bool init(OdGeomConstraint* pConstraint) { OdDistanceConstraint * pDC = (OdDistanceConstraint *) pConstraint; if (!DimConstraintData::init(pDC, 2)) return false; m_directionType = pDC->directionType(); m_fixedDirection = pDC->direction(); return true; } bool fill(OdDbAssoc2dConstraintGroup * pDestGroup) { OdConstrainedGeometry * apConsGeom[2]; if (!getGeometries(pDestGroup, apConsGeom, 2)) return false; OdGeVector3d * pFixedDirection = (m_directionType == OdDistanceConstraint::kFixedDirection) ? &m_fixedDirection : NULL; OdConstrainedLine* pDirectionLine = NULL; OdDistanceConstraint * pConstr = 0; pDestGroup->addDistanceConstraint(apConsGeom[0], apConsGeom[1], m_directionType, m_valueDependencyId, m_dimDependencyId, pFixedDirection, pDirectionLine, &pConstr); return true; } private: OdDistanceConstraint::DirectionType m_directionType; OdGeVector3d m_fixedDirection; }; ODRX_CONS_DEFINE_MEMBERS(DistanceConstraintData, DimConstraintData, RXIMPL_CONSTR); class AngleConstraintData : public DimConstraintData { public: ODRX_DECLARE_MEMBERS(AngleConstraintData); ~AngleConstraintData() {} bool init(OdGeomConstraint* pConstraint) { OdAngleConstraint * pAC = (OdAngleConstraint *) pConstraint; if (!DimConstraintData::init(pAC, 2)) return false; m_sectorType = pAC->sectorType(); return true; } bool fill(OdDbAssoc2dConstraintGroup * pDestGroup) { OdConstrainedGeometry * apConsGeom[2]; if (!getGeometries(pDestGroup, apConsGeom, 2)) return false; OdAngleConstraint * pConstr = 0; pDestGroup->addAngleConstraint((OdConstrainedLine*) apConsGeom[0], (OdConstrainedLine*) apConsGeom[1], m_sectorType, m_valueDependencyId, m_dimDependencyId, &pConstr); return true; } private: OdAngleConstraint::SectorType m_sectorType; }; ODRX_CONS_DEFINE_MEMBERS(AngleConstraintData, DimConstraintData, RXIMPL_CONSTR); class ThreePointAngleConstraintData : public DimConstraintData { public: ODRX_DECLARE_MEMBERS(ThreePointAngleConstraintData); ~ThreePointAngleConstraintData() {} bool init(OdGeomConstraint* pConstraint) { Od3PointAngleConstraint * pAC = (Od3PointAngleConstraint *) pConstraint; if (!DimConstraintData::init(pAC, 3)) return false; return true; } bool fill(OdDbAssoc2dConstraintGroup * pDestGroup) { OdConstrainedGeometry * apConsGeom[3]; if (!getGeometries(pDestGroup, apConsGeom, 3)) return false; Od3PointAngleConstraint * pConstr = 0; pDestGroup->add3PointAngleConstraint((OdConstrainedPoint *) apConsGeom[0], (OdConstrainedPoint *) apConsGeom[1], (OdConstrainedPoint *) apConsGeom[2], m_sectorType, m_valueDependencyId, m_dimDependencyId, &pConstr); return true; } private: OdAngleConstraint::SectorType m_sectorType; }; ODRX_CONS_DEFINE_MEMBERS(ThreePointAngleConstraintData, DimConstraintData, RXIMPL_CONSTR); class RadiusDiameterConstraintData : public DimConstraintData { public: ODRX_DECLARE_MEMBERS(RadiusDiameterConstraintData); ~RadiusDiameterConstraintData() {} bool init(OdGeomConstraint* pConstraint) { OdRadiusDiameterConstraint * pRC = (OdRadiusDiameterConstraint *) pConstraint; if (!DimConstraintData::init(pRC, 1)) return false; m_rdType = pRC->constrType(); return true; } bool fill(OdDbAssoc2dConstraintGroup * pDestGroup) { OdConstrainedGeometry * apConsGeom[1]; if (!getGeometries(pDestGroup, apConsGeom, 1)) return false; OdRadiusDiameterConstraint * pConstr = 0; pDestGroup->addRadiusDiameterConstraint(apConsGeom[0], m_rdType, m_valueDependencyId, m_dimDependencyId, &pConstr); return true; } private: OdRadiusDiameterConstraint::RadiusDiameterConstrType m_rdType; }; ODRX_CONS_DEFINE_MEMBERS(RadiusDiameterConstraintData, DimConstraintData, RXIMPL_CONSTR); void moveDepFromSrcGroup(OdDbAssoc2dConstraintGroup * pSrcGroup, OdDbAssoc2dConstraintGroup * pDestGroup) { // collect constraints OdArray > aExistingConstraints; OdArray aExistingDimConstraints; OdArray apSrcConstraints; pSrcGroup->getConstraints(apSrcConstraints); unsigned int constrLength = apSrcConstraints.length(); for (unsigned int k=0; kisInternal()) { continue; } // Note that order constraints are checked is important due to some constraints derive from others! DimConstraintDataPtr pDimData; OdGeomConstraint::GeomConstraintType type; if (pConstraint->isKindOf(OdHorizontalConstraint::desc())) // Derived from OdParallelConstraint type = OdGeomConstraint::kHorizontal; else if (pConstraint->isKindOf(OdVerticalConstraint::desc())) type = OdGeomConstraint::kVertical; else if (pConstraint->isKindOf(OdG2SmoothConstraint::desc())) // Derived from OdCompositeConstraint type = OdGeomConstraint::kG2Smooth; else if (pConstraint->isKindOf(OdColinearConstraint::desc())) type = OdGeomConstraint::kColinear; else if (pConstraint->isKindOf(OdConcentricConstraint::desc())) type = OdGeomConstraint::kConcentric; else if (pConstraint->isKindOf(OdEqualLengthConstraint::desc())) type = OdGeomConstraint::kEqualLength; else if (pConstraint->isKindOf(OdEqualRadiusConstraint::desc())) type = OdGeomConstraint::kEqualRadius; else if (pConstraint->isKindOf(OdFixedConstraint::desc())) type = OdGeomConstraint::kFix; else if (pConstraint->isKindOf(OdNormalConstraint::desc())) type = OdGeomConstraint::kNormal; else if (pConstraint->isKindOf(OdParallelConstraint::desc())) // Derived from OdGeomConstraint type = OdGeomConstraint::kParallel; else if (pConstraint->isKindOf(OdPerpendicularConstraint::desc())) type = OdGeomConstraint::kPerpendicular; else if (pConstraint->isKindOf(OdPointCoincidenceConstraint::desc())) type = OdGeomConstraint::kCoincident; else if (pConstraint->isKindOf(OdSymmetricConstraint::desc())) type = OdGeomConstraint::kSymmetric; else if (pConstraint->isKindOf(OdTangentConstraint::desc())) type = OdGeomConstraint::kTangent; else if (pConstraint->isKindOf(Od3PointAngleConstraint::desc())) pDimData = ThreePointAngleConstraintData::createObject(); else if (pConstraint->isKindOf(OdAngleConstraint::desc())) pDimData = AngleConstraintData::createObject(); else if (pConstraint->isKindOf(OdDistanceConstraint::desc())) // Derived from OdExplicitConstraint pDimData = DistanceConstraintData::createObject(); else if (pConstraint->isKindOf(OdRadiusDiameterConstraint::desc())) pDimData = RadiusDiameterConstraintData::createObject(); if (!pDimData.isNull()) { if (!pDimData->init(pConstraint)) continue; aExistingDimConstraints.append(pDimData); continue; } OdArray apConsGeoms; pConstraint->getConnectedGeometries(apConsGeoms); OdDbFullSubentPathArray subentPaths; unsigned int consGeomLength = apConsGeoms.length(); if (consGeomLength) { for (unsigned int l=0; lgetFullSubentPaths(subentPath); if (subentPath.length() > 0) subentPaths.append(subentPath[0]); } } else { if (pConstraint->isKindOf(OdCompositeConstraint::desc())) { OdCompositeConstraint * pCG = OdCompositeConstraint::cast(pConstraint); OdArray apSubConstraints; pCG->getOwnedConstraints(apSubConstraints); for (unsigned int k=0; k apSubCompConsGeoms; pSubConstr->getConnectedGeometries(apSubCompConsGeoms); bool metOnlyImplicitGeometry = false; for (unsigned int l=0; lisKindOf(OdConstrainedImplicitPoint::desc())) { metOnlyImplicitGeometry = false; break; } metOnlyImplicitGeometry = true; OdDbFullSubentPathArray subentPath; pCG->getFullSubentPaths(subentPath); if (subentPath.length() > 0) subentPaths.append(subentPath[0]); } if (!metOnlyImplicitGeometry) subentPaths.clear(); else if (subentPaths.length()) break; } } } aExistingConstraints.append(std::pair (type, subentPaths)); } // move dependencies unsigned int i; OdDbObjectIdArray aSrcDependencyIds; pSrcGroup->getDependencies(true, true, aSrcDependencyIds); unsigned int srcDepLength = aSrcDependencyIds.length(); for (i=0; igetDependentOnCompoundObject(compId); OdDbObjectId objectId = compId->leafId(); OdDbEntityPtr pObject = OdDbEntity::cast(objectId.openObject(OdDb::kForRead)); OdSmartPtr persSubentIdPE = OdDbAssocPersSubentIdPE::cast(pObject); if (persSubentIdPE.isNull()) continue; OdDbAssocGeomDependencyPtr pGeomDep = OdDbAssocGeomDependency::cast(pDep); if (!pGeomDep.isNull()) { OdArray aSubentIds; persSubentIdPE->getTransientSubentIds(pObject, pGeomDep->persistentSubentId(), aSubentIds); if (aSubentIds.size() < 1) { const OdDb::SubentType subentType = (pGeomDep->persistentSubentId().isNull()) ? OdDb::kEdgeSubentType : pGeomDep->persistentSubentId()->subentType(pObject); persSubentIdPE->getAllSubentities(pObject, subentType, aSubentIds); if (aSubentIds.size() < 1) continue; } persSubentIdPE.release(); OdDbObjectIdArray fullPath; compId->getFullPath(fullPath); OdDbFullSubentPath fsPath(fullPath, aSubentIds[0]); pSrcGroup->removeDependency(depId, false); pGeomDep->upgradeOpen(); pDestGroup->assertWriteEnabled(); OdDbImpAssoc2dConstraintGroup *pDestImp = (OdDbImpAssoc2dConstraintGroup*)OdDbImpAssocAction::getImpObject(pDestGroup); pDestImp->moveConstrainedGeometry(fsPath, pGeomDep, pDestGroup); } else { pSrcGroup->removeDependency(depId, false); pDestGroup->addDependency(depId, true); } } OdArray >::iterator it = aExistingConstraints.begin(); for (; it != aExistingConstraints.end(); ++it) { for (unsigned idx = 0; idx < it->second.size(); idx++) { // dna: note: this fix (for CORE-14042) adds some geometry nodes that will be wiped out after evaluation OdConstrainedGeometry* pG = 0; pDestGroup->addConstrainedGeometry(it->second[idx], pG); } OdGeomConstraint* ppNewConstraint = 0; ODA_VERIFY(eOk == pDestGroup->addGeometricalConstraint(it->first, it->second, &ppNewConstraint)); } OdArray::iterator dimIt = aExistingDimConstraints.begin(); bool res; for (; dimIt != aExistingDimConstraints.end(); ++dimIt) { res = (*dimIt)->fill(pDestGroup); ODA_ASSERT(res); } pSrcGroup->erase(); } void OdDbAssocVarCloneCtx::addDestVariables(OdDbAssocNetwork* network) { const OdDbObjectIdArray aActionIds = network->getActions(); for (unsigned i = 0; i < aActionIds.size(); ++i) { const OdDbObjectId actionId = aActionIds[i]; if (actionId.objectClass()->isDerivedFrom(OdDbAssocVariable::desc())) { OdDbAssocVariablePtr pVar = OdDbAssocVariable::cast(actionId.openObject()); if (pVar.get() && !pVar->isAnonymous()) addDestVariable(pVar->name()); } } } void OdDbAssocVarCloneCtx::addSourceVariables(OdDbAssocVariable* variable) { if (variable && !variable->isAnonymous() && addSourceVariable(variable->name())) { OdDbObjectIdArray aDeps; variable->getDependencies(true, true, aDeps); for (unsigned i = 0; i < aDeps.size(); ++i) { const OdDbObjectId depId = aDeps[i]; if (depId.objectClass() == OdDbAssocValueDependency::desc()) { OdDbAssocValueDependencyPtr valDep = OdDbAssocValueDependency::cast(depId.openObject()); if (valDep.get()) { OdDbAssocVariablePtr dependentVar = OdDbAssocVariable::cast(valDep->dependentOnObject().openObject()); addSourceVariables(dependentVar); } } } } } bool OdDbAssocVarCloneCtx::addSourceVariable(const OdString& srcName) { OdString2IdxMap::value_type record(OdString(srcName).makeUpper(), 0); std::pair insertRes = m_forwardIndex.insert(record); if (insertRes.second) { DataEntry entry; entry.m_srcName = srcName; entry.m_isCloned = false; m_data.append(entry); insertRes.first->second = m_data.size() - 1; } return insertRes.second; } bool OdDbAssocVarCloneCtx::addDestVariable(const OdString& dstName) { OdString2IdxMap::value_type record(OdString(dstName).makeUpper(), 0); std::pair insertRes = m_invertedIndex.insert(record); if (insertRes.second) { DataEntry entry; entry.m_dstName = dstName; entry.m_isCloned = false; m_data.append(entry); insertRes.first->second = m_data.size() - 1; } return insertRes.second; } void OdDbAssocVarCloneCtx::recordVariableClone(const OdString& srcName, const OdString& dstName) { const OdString srcKey = OdString(srcName).makeUpper(); const OdString dstKey = OdString(dstName).makeUpper(); ODA_ASSERT(m_invertedIndex.find(OdString(dstName).makeUpper()) == m_invertedIndex.end() && "A variable with name matching distination name already exists"); OdString2IdxMap::value_type forwardIndexRecord(srcKey, 0); std::pair forwardInsertRes = m_forwardIndex.insert(forwardIndexRecord); if (forwardInsertRes.second) { DataEntry entry; entry.m_srcName = srcName; entry.m_dstName = dstName; entry.m_isCloned = true; m_data.append(entry); forwardInsertRes.first->second = m_data.size() - 1; } else { const unsigned idx = forwardInsertRes.first->second; DataEntry& entry = m_data[idx]; entry.m_dstName = dstName; entry.m_isCloned = true; } m_invertedIndex[dstKey] = forwardInsertRes.first->second; } const OdDbAssocVarCloneCtx::DataEntry* OdDbAssocVarCloneCtx::getEntryBySourceName(const OdString& srcName) const { OdString2IdxMap::const_iterator it = m_forwardIndex.find(OdString(srcName).makeUpper()); return it != m_forwardIndex.end() ? &m_data[it->second] : NULL; } const OdDbAssocVarCloneCtx::DataEntry* OdDbAssocVarCloneCtx::getEntryByDestName(const OdString& dstName) const { OdString2IdxMap::const_iterator it = m_invertedIndex.find(OdString(dstName).makeUpper()); return it != m_invertedIndex.end() ? &m_data[it->second] : NULL; } int OdDbAssocVarCloneCtx::destVariableCount() const { return int(m_invertedIndex.size()); } int OdDbAssocVarCloneCtx::clonedVariableCount() const { return int(m_forwardIndex.size()); } class RecordSourceVarName { OdDbIdMapping& m_idMap; OdDbAssocVarCloneCtx& m_varCtx; OdDbAssocNetwork& m_net; public: RecordSourceVarName(OdDbIdMapping& idMap, OdDbAssocVarCloneCtx& varCtx, OdDbAssocNetwork& net) : m_idMap(idMap), m_varCtx(varCtx), m_net(net) {} void operator()(const OdDbObjectId& actionId) { if (actionId.objectClass()->isDerivedFrom(OdDbAssocVariable::desc())) { OdDbIdPair cloneSearch(actionId); if (m_idMap.compute(cloneSearch) && cloneSearch.isCloned()) { OdDbObjectPtr clone = cloneSearch.value().openObject(); if (clone->ownerId() == m_net.objectId() || clone->ownerId() == m_net.objectThatOwnsNetworkInstance()) { OdDbAssocVariablePtr origVar = OdDbAssocVariable::cast(actionId.openObject()); m_varCtx.addSourceVariables(origVar); } } } } }; OdDbAssocVarCloneCtx& OdDbAssocNetCloneCtx::varCloneContext(OdDbAssocNetwork* destNetwork) { NetworkVariableIndex::iterator it = variableIndices.find(destNetwork); if (it == variableIndices.end()) { OdDbAssocVarCloneCtx varCtx; varCtx.addDestVariables(destNetwork); std::for_each(actionsToAppend.begin(), actionsToAppend.end(), RecordSourceVarName(*idMap, varCtx, *destNetwork)); it = variableIndices.insert(NetworkVariableIndex::value_type(destNetwork, varCtx)).first; } return it->second; } struct ReactorKeeper { OdStaticRxObject m_assocNetworkDeepCloneReactor; OdStaticRxObject m_assocNetworkLongTransactionReactor; }; ReactorKeeper * gpReactorKeeper = 0; void OdDbAssocNetCloneCtx::createAssocNetworkCloneReactors() { DimConstraintData::rxInit(); DistanceConstraintData::rxInit(); AngleConstraintData::rxInit(); ThreePointAngleConstraintData::rxInit(); RadiusDiameterConstraintData::rxInit(); OdDbAssocNetworkObjectModificationReactor::rxInit(); OdDbAssocNetCloneOverrule::rxInit(); gpReactorKeeper = new ReactorKeeper; gpReactorKeeper->m_assocNetworkDeepCloneReactor.addRefReactor(); gpReactorKeeper->m_assocNetworkLongTransactionReactor.addRefReactor(); } void OdDbAssocNetCloneCtx::deleteAssocNetworkCloneReactors() { gpReactorKeeper->m_assocNetworkDeepCloneReactor.releaseReactor(); gpReactorKeeper->m_assocNetworkLongTransactionReactor.releaseReactor(); delete gpReactorKeeper; gpReactorKeeper = 0; OdDbAssocNetCloneOverrule::rxUninit(); OdDbAssocNetworkObjectModificationReactor::rxUninit(); DistanceConstraintData::rxUninit(); AngleConstraintData::rxUninit(); ThreePointAngleConstraintData::rxUninit(); RadiusDiameterConstraintData::rxUninit(); DimConstraintData::rxUninit(); } void OdDbAssocNetCloneCtx::onBlockCloned(const OdDbBlockTableRecord& originalBlock) { OdDbIdPair ownerMapping(originalBlock.objectId()); idMap->compute(ownerMapping); OdDbObjectPtr destOwner = ownerMapping.value().openObject(); const OdDbObjectId networkId = OdDbAssocNetwork::getInstanceFromObject(originalBlock.objectId(), false); OdDbAssocNetworkPtr network = OdDbAssocNetwork::cast(networkId.openObject()); if (network.get() && destOwner.get()) { const OdDbObjectIdArray actionIds = network->getActions(); for (unsigned int i = 0; i < actionIds.size(); ++i) { OdDbObjectPtr action = actionIds[i].openObject(); if (action.get()) { OdDbAssocNetCloneCtx::cloneObject(*idMap, action, destOwner); } } } } void OdDbAssocNetCloneCtx::onDependentObjectCloned(const OdDbObject& originalObject) { OdDbObjectIdArray ids; OdDbAssocDependency::getDependenciesOnObject(&originalObject, true, true, ids); if (ids.size()) { dependentOnObjectsCloned.insert(originalObject.objectId()); do { OdDbAssocDependencyPtr dep = OdDbAssocDependency::cast(ids.last().openObject()); if (dep.get()) actionsToClone.insert(dep->owningAction()); ids.removeLast(); } while (ids.size()); } } void OdDbAssocNetCloneCtx::onActionCloned(const OdDbAssocAction* action) { OdDbIdPair idPair(action->objectId()); if (idMap->compute(idPair)) { if (!idPair.isOwnerXlated()) { idPair.setOwnerXlated(true); // suppress default appending to owner idMap->assign(idPair); actionsToAppend.insert(idPair.key()); } actionsToClone.insert(idPair.key()); clonedActions().append(idPair.key()); } } OdDbObjectId cloneOwner(OdDbIdMapping& idMap, const OdDbObject* action) { OdDbObjectPtr clone = ::oddbTranslateCloned(action->objectId(), idMap).openObject(); if(clone.get()) return clone->ownerId(); return OdDbObjectId::kNull; } class CallAddMoreObjects { OdDbIdMapping& idMap; public: CallAddMoreObjects(OdDbIdMapping& idM) : idMap(idM) { } void operator()(const OdDbObjectId& id) { OdDbAssocActionPtr action = id.openObject(); OdDbObjectIdArray objects; OdResult result = action->addMoreObjectsToDeepClone(idMap, objects); if (result == eOk && objects.size()) { OdDbBlockTableRecordPtr destBlock; for (OdDbObjectIdArray::const_iterator i = objects.begin(), e = objects.end(); i != e; ++i) { OdDbIdPair pair(*i); if (!idMap.compute(pair) || !pair.isCloned()) { OdDbObjectPtr object = pair.key().openObject(); if (object.get()) { OdDbObjectPtr owner; if (object->isKindOf(OdDbBlockTableRecord::desc())) { owner = idMap.destDb()->getBlockTableId().openObject(); } else if (object.get() == action.get()) { OdDbAssocNetCloneCtx::lookupDestinationBlock(idMap, action, destBlock); owner = destBlock; // see OdDbAssocAction::appendToOwner() } else if (object->isKindOf(OdDbAssocAction::desc())) { OdDbObjectPtr cloneOwner = ::cloneOwner(idMap, action).openObject(); if (cloneOwner.get()) owner = cloneOwner; else { OdDbAssocNetCloneCtx::lookupDestinationBlock(idMap, action, destBlock); owner = destBlock; // see OdDbAssocAction::appendToOwner() } } else if (object->isKindOf(OdDbEntity::desc())) { owner = destBlock; } ODA_ASSERT(!owner.isNull() && "can't automatiacally obtain cloned action destination owner.\n" "Action was not cloned.\n" "Action should clone itself inside addMoreObjectsToDeepClone() providing destination owner explicitly"); OdDbAssocNetCloneCtx::cloneObject(idMap, object, owner); } } } } } }; OdDbObjectId getDependentOnObjectId_or_topIdOfCompound_from(OdDbAssocDependency* dependency) { if (dependency->isDependentOnCompoundObject()) { OdDbCompoundObjectIdPtr compound; dependency->getDependentOnCompoundObject(compound); if (compound.get()) return compound->topId(); } return dependency->dependentOnObject(); } void OdDbAssocNetCloneCtx::lookupDestinationBlock(OdDbIdMapping& idMap, OdDbAssocAction* action, OdDbBlockTableRecordPtr& destBlock) { if (destBlock.get()) return; OdDbObjectIdArray dependencies; action->getDependencies(true, false, dependencies); OdDbObjectId actionOwningBlock = action->objectThatOwnsNetworkInstance(); for (unsigned int i = 0; i < dependencies.length(); i++) { OdDbAssocDependencyPtr dependency = dependencies[i].openObject(); if (dependency.get()) { OdDbIdPair pair( getDependentOnObjectId_or_topIdOfCompound_from(dependency) ); if (idMap.compute(pair) && pair.isCloned()) { OdDbObjectPtr original = pair.key().openObject(); OdDbObjectPtr clone = pair.value().openObject(); if ( original.get() && original->ownerId()==actionOwningBlock && clone.get() && clone->isKindOf(OdDbEntity::desc()) ) { // found dependent dbentity that was cloned from the same block that owns the action OdDbObjectId cloneOwnerId = clone->ownerId(); if (clone->isOdDbObjectIdsInFlux()) { OdDbObjectId ownerIdToTranslate = cloneOwnerId ? cloneOwnerId : actionOwningBlock; OdDbObjectId translatedCloneOwnerId = ::oddbTranslate(ownerIdToTranslate, idMap); if(!translatedCloneOwnerId.isNull()) // may be not cloned cloneOwnerId = translatedCloneOwnerId; } destBlock = OdDbBlockTableRecord::cast(cloneOwnerId.openObject()); if(destBlock.get()) return; } } } } ODA_ASSERT(!destBlock.isNull() && "can't automatiacally obtain cloned action destination owner\n" "action should clone itself inside addMoreObjectsToDeepClone() providing destination owner explicitly"); } OdDbObjectPtr OdDbAssocNetCloneCtx::lookupActionCloneOwner(OdDbIdMapping& idMap, OdDbBlockTableRecord* destBlock) { OdDbObjectId network = OdDbAssocNetwork::getInstanceFromObject(destBlock->objectId(), true); if (network.database() != idMap.destDb()) { OdDbIdPair pair(network); if (!idMap.compute(pair) || !pair.isCloned()) return OdDbObjectPtr(network.openObject())->wblockClone(idMap, idMap.destDb(), false); return pair.value().openObject(); } return network.openObject(); } OdDbObjectPtr OdDbAssocNetCloneCtx::lookupActionCloneOwner(OdDbIdMapping& idMap, OdDbAssocAction* action) { OdDbBlockTableRecordPtr destBlock; OdDbAssocNetCloneCtx::lookupDestinationBlock(idMap, action, destBlock); return OdDbAssocNetCloneCtx::lookupActionCloneOwner(idMap, destBlock); } OdDbObjectPtr OdDbAssocNetCloneCtx::lookupActionCloneOwner(OdDbIdMapping& idMap, OdDbEntity* destActionEntity) { OdDbBlockTableRecordPtr destBlock = OdDbBlockTableRecord::cast(destActionEntity->ownerId().openObject()); if (destBlock.get()) return OdDbAssocNetCloneCtx::lookupActionCloneOwner(idMap, destBlock); ODA_ASSERT(!!!"can't automatiacally obtain cloned action destination owner\n" "action should clone itself inside addMoreObjectsToDeepClone() providing destination owner explicitly"); throw OdError(eNotApplicable); } void OdDbAssocNetCloneCtx::addMoreObjectsToDeepClone() { OdHashSet > actionsToClone0; do { std::swap(actionsToClone0, actionsToClone); std::for_each(actionsToClone0.begin(), actionsToClone0.end(), CallAddMoreObjects(*idMap)); actionsToClone0.clear(); } while (!actionsToClone.empty()); } class RelinkDependecies { OdDbIdMapping& idMap; public: RelinkDependecies(OdDbIdMapping& idM) : idMap(idM) { } void operator()(const OdDbObjectId& id) { OdDbIdPair idPair(id); if (idMap.compute(idPair) && idPair.isCloned()) OdDbImpAssocDependency::relinkDependenciesOn(idPair.value().openObject()); } }; void OdDbAssocNetCloneCtx::relinkDependenciesOnObjects() { std::for_each(dependentOnObjectsCloned.begin(), dependentOnObjectsCloned.end(), RelinkDependecies(*idMap)); } class AppendActions { OdDbIdMapping& idMap; public: AppendActions(OdDbIdMapping& idM) : idMap(idM) { } void operator()(const OdDbObjectId& id) { OdDbAssocActionPtr pSourceAction = id.openObject(); if (pSourceAction.get()) { OdDbIdPair idPair(id); if (idMap.compute(idPair) && idPair.isCloned()) { OdDbAssocActionPtr clone = OdDbAssocAction::cast(idPair.value().openObject(OdDb::kForWrite)); if (clone.get()) { OdDbObjectPtr owner = clone->ownerId().openObject(OdDb::kForWrite); if (owner.get()) { idPair.setOwnerXlated(false); clone->appendToOwner(idPair, owner, idMap); idPair.setOwnerXlated(true); idMap.assign(idPair); } } } } } }; void attachToOwniningNetwork(OdDbAssocAction* clone, OdDbObjectId owner, bool setAsDbOwner) { OdDbAssocStatus status = clone->status(); clone->setStatus(kIsUpToDateAssocStatus); clone->setOwningNetwork(owner, setAsDbOwner); clone->setStatus(status); } void OdDbAssocNetCloneCtx::appendActionsToOwners() { std::for_each(actionsToAppend.begin(), actionsToAppend.end(), AppendActions(*idMap)); OdDbObjectIdLinkedArray& actions = clonedActions(); OdDbObjectId global; for(OdDbObjectIdLinkedArray::const_iterator it = actions.begin(), end = actions.end(); it!=end; ++it) { OdDbAssocActionPtr pSourceAction = it->openObject(); if (pSourceAction.get()) { OdDbIdPair idPair(*it); if (idMap->compute(idPair) && idPair.isCloned()) { OdDbAssocActionPtr clone = OdDbAssocAction::cast(idPair.value().openObject(OdDb::kForWrite)); if (clone.get() && clone->owningNetwork().isNull()) { OdDbObjectPtr owner = clone->ownerId().openObject(OdDb::kForWrite); if (owner.get()) { if(owner->isKindOf(OdDbAssocNetwork::desc())) { ::attachToOwniningNetwork(clone, owner->objectId(), true); } else if(owner->isKindOf(OdDbDictionary::desc())) { if(global.isNull()) global = OdDbAssocNetwork::getInstanceFromDatabase(idMap->destDb(), true); ::attachToOwniningNetwork(clone, global, false); } } } } } } } OdDbObjectPtr OdDbAssocNetCloneOverrule::deepClone(const OdDbObject* subject, OdDbIdMapping& idMap, OdDbObject* owner, bool primary /*= true*/) { OdDbObjectPtr clone = OdDbObjectOverrule::deepClone(subject, idMap, owner, primary); if(clone.get()) { OdDbAssocNetCloneCtxPtr ctx = OdDbAssocNetCloneCtx::fromDatabase(idMap.destDb()); if (ctx.get()) { if (subject->isA()->isDerivedFrom(OdDbBlockTableRecord::desc())) { ctx->onBlockCloned(static_cast(*subject)); } else if (!isInLongTransaction(idMap)){ ctx->onDependentObjectCloned(*subject); } } } return clone; } OdDbObjectPtr OdDbAssocNetCloneOverrule::wblockClone(const OdDbObject* subject, OdDbIdMapping& idMap, OdDbObject* owner, bool primary /*= true*/) { OdDbObjectPtr clone = OdDbObjectOverrule::wblockClone(subject, idMap, owner, primary); if (clone.get()) { OdDbAssocNetCloneCtxPtr ctx = OdDbAssocNetCloneCtx::fromDatabase(idMap.destDb()); if (ctx.get()) { if (subject->isA()->isDerivedFrom(OdDbBlockTableRecord::desc())) { ctx->onBlockCloned(static_cast(*subject)); } else if (!isInLongTransaction(idMap)) { ctx->onDependentObjectCloned(*subject); } } } return clone; } bool OdDbAssocNetCloneOverrule::isApplicable(const OdRxObject* pOverruledSubject) const { if (pOverruledSubject && pOverruledSubject->isA()->isDerivedFrom(OdDbObject::desc())) { const OdDbObject* pDbObject = static_cast(pOverruledSubject); return pDbObject->isA()->isDerivedFrom(OdDbBlockTableRecord::desc()) || !OdDbAssocDependency::getFirstDependencyOnObject(pDbObject).isNull(); } return false; } OdDbAssocNetCloneOverrule::OdDbAssocNetCloneOverrule() : m_clients(0), m_WasOverruling(false) {} void OdDbAssocNetCloneOverrule::addOverruleClient() { if (!(m_clients++)) { m_WasOverruling = OdRxOverrule::isOverruling(); OdDbObjectOverrule::addOverrule(OdDbObject::desc(), this); OdRxOverrule::setIsOverruling(true); } ODA_ASSERT(m_clients > 0); } void OdDbAssocNetCloneOverrule::removeOverruleClient() { if (!(--m_clients)) { if(OdRxOverrule::removeOverrule(OdDbObject::desc(), this)) OdRxOverrule::setIsOverruling(m_WasOverruling); } ODA_ASSERT(m_clients >= 0); }