覆盖 wblockClone() 函数
执行 wblock 克隆操作时,AutoCAD 将为新图形构建一个有效的数据库,其中包含命名对象字典、所有符号表和完整的标题变量集。以下代码近似于 的默认实现。列出的步骤与重写 deepClone() 函数一节中列出的步骤相对应。wblockClone() 该函数使用类 AcDbWblockCloneFiler 的文件管理器,该文件管理器返回主对象的硬指针和硬所有者连接的列表。在调用这些子对象之前,您需要检查子对象的所有者。此时,你将执行以下两项操作之一:wblockClone()wblockClone()
如果设置为数据库,则必须将克隆对象的所有者设置为与原始对象相同的所有者。然后,当AutoCAD转换参照时,它将更新对新数据库中克隆对象的所有者参照。pOwnerwblockClone() 请务必确保克隆所有拥有对象。在 wblock 克隆期间,AutoCAD 始终克隆符号表、命名对象字典、模型空间和图纸空间(对于除 之外的克隆上下文)。具有所属对象的应用程序负责确保在必要时克隆这些对象。如果所属对象未被克隆且在 ID 映射中未找到,则 wblock clone 将使用 中止。AcDb::kDcXrefBindAcDb::eOwnerNotSet 在复制引用符号表记录的实体时,必须以对象所有者的身份传入数据库。例如,假设您正在调用一个球体对象。块表记录是此球体对象的硬所有者。sphere 对象包含对图层表的硬引用。wblockClone() 首先,在该阶段,使用默认元素创建并设置新数据库。下图显示了模型空间块表记录和层表,因为它们与本主题相关。在此阶段发生的克隆始终发生在 wblock 操作期间。beginDeepClone() 在阶段,选择集被克隆,如下图所示。在此示例中,球体是克隆的。beginWblock() 因为球体包含指向图层的硬指针 1 层 1 被克隆。 接下来,需要翻译指针以引用克隆的对象,如下图所示。该通知指示此阶段的开始。beginDeepCloneXlation() 上图当时的ID图如下:beginDeepCloneXlation()
*图层表的所有者是数据库本身,因此此条目毫无意义。 **在转换过程中,此设置表示图层的所有者将从 LayerTable 转换 1 到图层表 2 . wblock 克隆过程用于外部参照绑定和 wblock。两者的需求非常相似,但在覆盖 .wblockClone() Wblock 克隆所有选定的实体。但是,外部参照绑定从不克隆图纸空间中的实体。这在创建对象或实体以及使用 .首先,在任何 的开头,检查克隆上下文是否是,如果是,则检查实体是否正在纸张空间中克隆。如果是,则不应进行克隆,而应返回 。AcDbHardPointerIdsAcDbEntitywblockClone()AcDb::kDcXrefBindwblockClone()Acad::eOk 如果您的自定义类具有任何可以指向实体的实体(例如我们所做的),则这些实体可能位于纸张空间中,因此不会被克隆。在这种情况下,将设置为 。AcDbHardPointerIdsAcDbGroupAcDbHardPointerIdsNULL Wblock 不遵循跨数据库的硬指针引用。但是,xref bind 始终执行此操作。例如,外部参照图形中的图元可以位于主体图形的 VISRETAIN 图层上。因此,如果实现 with 循环来检查子对象,并且子对象的数据库与要克隆的对象的数据库不同,则如果克隆上下文不是 ,则必须跳过子对象。例如:wblockClone()AcDb::kDcXrefBind if(pSubObject->database() != database() && idMap.deepCloneContext() != AcDb::kDcXrefBind) { pSubObject->close(); continue; } 以下代码演示了为自定义实体 () 实现它的重写。此函数使用编辑器反应器通知函数中显示的代码调用。wblockClone()AsdkPoly Acad::ErrorStatus AsdkPoly::wblockClone(AcRxObject* pOwner, AcDbObject*& pClonedObject, AcDbIdMapping& idMap, Adesk::Boolean isPrimary) const { // You should always pass back pClonedObject == NULL // if, for any reason, you do not actually clone it // during this call. The caller should pass it in // as NULL, but to be safe, it is set here as well. // pClonedObject = NULL; // If this is a fast wblock operation, no cloning // should take place, so we simply call the base class's // wblockClone() and return whatever it returns. // // For fast wblock, the source and destination databases // are the same, so we can use that as the test to see // if a fast wblock is in progress. // AcDbDatabase *pDest, *pOrig; idMap.destDb(pDest); idMap.origDb(pOrig); if (pDest == pOrig) return AcDbCurve::wblockClone(pOwner, pClonedObject, idMap, isPrimary); // If this is an xref bind operation and this AsdkPoly // entity is in paper space, then we don't want to // clone because xref bind doesn't support cloning // entities in paper space. Simply return Acad::eOk. // AcDbObjectId pspace; AcDbBlockTable *pTable; database()->getSymbolTable(pTable, AcDb::kForRead); pTable->getAt(ACDB_PAPER_SPACE, pspace); pTable->close(); if ( idMap.deepCloneContext() == AcDb::kDcXrefBind && ownerId() == pspace) return Acad::eOk; // If this object is in the idMap and is already // cloned, then return. // bool isPrim = false; if (isPrimary) isPrim = true; AcDbIdPair idPair(objectId(), (AcDbObjectId)NULL, false, isPrim); if (idMap.compute(idPair) && (idPair.value() != NULL)) return Acad::eOk; // The owner object can be either an AcDbObject or an // AcDbDatabase. AcDbDatabase is used if the caller is // not the owner of the object being cloned (because it // is being cloned as part of an AcDbHardPointerId // reference). In this case, the correct ownership // will be set during reference translation. If // the owner is an AcDbDatabase, then pOwn will be left // NULL here, and is used as a "flag" later. // AcDbObject *pOwn = AcDbObject::cast(pOwner); AcDbDatabase *pDb = AcDbDatabase::cast(pOwner); if (pDb == NULL) pDb = pOwn->database(); // Step 1: Create the clone. // AsdkPoly *pClone = (AsdkPoly*)isA()->create(); if (pClone != NULL) pClonedObject = pClone; // Set the return value. else return Acad::eOutOfMemory; // Step 2: If the owner is an AcDbBlockTableRecord, go ahead // and append the clone. If not, but we know who the // owner is, set the clone's ownerId to it. Otherwise, // we set the clone's ownerId to our own ownerId (in // other words, the original ownerId). This ID will // then be used later, in reference translation, as // a key to finding who the new owner should be. This // means that the original owner must also be cloned at // some point during the wblock operation. // EndDeepClone's reference translation aborts if the // owner is not found in the ID map. // // The most common situation where this happens is // AcDbEntity references to symbol table records, such // as the layer an entity is on. This is when you will // have to pass in the destination database as the owner // of the layer table record. Since all symbol tables // are always cloned in wblock, you do not need to make // sure that symbol table record owners are cloned. // // However, if the owner is one of your own classes, // then it is up to you to make sure that it gets // cloned. This is probably easiest to do at the end // of this function. Otherwise you may have problems // with recursion when the owner, in turn, attempts // to clone this object as one of its subobjects. // AcDbBlockTableRecord *pBTR = NULL; if (pOwn != NULL) pBTR = AcDbBlockTableRecord::cast(pOwn); if (pBTR != NULL && isPrimary) { pBTR->appendAcDbEntity(pClone); } else { pDb->addAcDbObject(pClonedObject); } // Step 3: The AcDbWblockCloneFiler makes a list of // AcDbHardOwnershipIds and AcDbHardPointerIds. These // are the references that must be cloned during a // wblock operation. // AcDbWblockCloneFiler filer; dwgOut(&filer); // Step 4: Rewind the filer and read the data into the clone. // filer.seek(0L, AcDb::kSeekFromStart); pClone->dwgIn(&filer); // Step 5: Add the new information to the ID map. // We must let the idMap entry know whether the clone's owner is // correct, or needs to be translated later. // idMap.assign(AcDbIdPair(objectId(), pClonedObject->objectId(), Adesk::kTrue, isPrim, (Adesk::Boolean)(pOwn != NULL) )); pClonedObject->setOwnerId((pOwn != NULL) ? pOwn->objectId() : ownerId()); // Step 6: // This must be called for all newly created objects // in wblockClone. It is turned off by endDeepClone() // after it has translated the references to their // new values. // pClone->setAcDbObjectIdsInFlux(); // Step 7: Using the filer list created above, find and clone // any hard references. // AcDbObjectId id; while (filer.getNextHardObject(id)) { AcDbObject *pSubObject; AcDbObject *pClonedSubObject; // Some object references may be set to NULL, // so don't try to clone them. // if (id == NULL) continue; // If the referenced object is from a different // database, such as an xref, do not clone it. // acdbOpenAcDbObject(pSubObject, id, AcDb::kForRead); if (pSubObject->database() != database()) { pSubObject->close(); continue; } // To find out if this is an AcDbHardPointerId // versus an AcDbHardOwnershipId, check if we are the // owner of the pSubObject. If we are not, // then we cannot pass our clone in as the owner // for the pSubObject's clone. In that case, we // pass in our clone's database (the destination // database). // // Note that "isPrimary" is set to kFalse here // because the object is being cloned, not as part // of the primary set, but because it is owned by // something in the primary set. // pClonedSubObject = NULL; if (pSubObject->ownerId() == objectId()) { pSubObject->wblockClone(pClone, pClonedSubObject, idMap, Adesk::kFalse); } else { pSubObject->wblockClone( pClone->database(), pClonedSubObject, idMap, Adesk::kFalse); } pSubObject->close(); // The pSubObject may either already have been // cloned, or for some reason has chosen not to be // cloned. In that case, the returned pointer will // be NULL. Otherwise, since there is no immediate // use for it now, the clone can be closed. // if (pClonedSubObject != NULL) pClonedSubObject->close(); } // Leave pClonedObject open for the caller. // return Acad::eOk; } 注意:请记住,在执行函数的过程中,目标数据库中的指针引用尚未转换。以下代码无法正常工作,因为尽管它尝试打开目标数据库的模型空间块表记录,但源数据库的模型空间块表记录却被打开。目标数据库块表中未翻译的引用仍是指源数据库的模型空间。wblock()
void AsdkWblockReactor::otherWblock( AcDbDatabase* pDestDb, AcDbIdMapping& idMap, AcDbDatabase* pSrcDb) { AcDbBlockTable *pDestBlockTable; AcDbBlockTableRecord *pDestBTR; pDestDb->getSymbolTable(pDestBlockTable, AcDb::kForRead); pDestBlockTable->getAt(ACDB_MODEL_SPACE, pDestBTR, AcDb::kForRead); pDestBlockTable->close(); // Now pDestBTR is pointing to pSrcDb database's model // space, not to the destination database's model space! // The code above is not correct! } 要查找目标模型空间,必须在 ID 映射中查找它:
void AsdkWblockReactor::otherWblock( AcDbDatabase* pDestDb, AcDbIdMapping& idMap, AcDbDatabase* pSrcDb) { // To find the destination model space, you must look // it up in the ID map: AcDbBlockTable *pSrcBlockTable; pSrcDb->getSymbolTable(pSrcBlockTable, AcDb::kForRead); AcDbObjectId srcModelSpaceId; pSrcBlockTable->getAt(ACDB_MODEL_SPACE, srcModelSpaceId); pSrcBlockTable->close(); if (pDestDb == pSrcDb) { // It's a fastWblock, so we use the source objectId. destId = srcModelSpaceId; } else { AcDbIdPair idPair; idPair.setKey(srcModelSpaceId); idMap.compute(idPair); destId = idPair.value(); } AcDbBlockTableRecord *pDestBTR; acdbOpenAcDbObject((AcDbObject*&)pDestBTR, destId, AcDb::kForRead, Adesk::kTrue); 父主题: |
|Archiver|CAD开发者社区 ( 苏ICP备2022047690号-1 苏公网安备32011402011833)
GMT+8, 2024-12-15 22:21
Powered by Discuz! X3.4
Copyright © 2001-2021, Tencent Cloud.