覆盖 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, 2025-10-30 07:10
Powered by Discuz! X3.4
Copyright © 2001-2021, Tencent Cloud.