CAD开发者社区

 找回密码
 立即注册

QQ登录

只需一步,快速开始

AutoCAD 2024 开发者帮助

覆盖 wblockClone() 函数

2024-5-18 19:12| 发布者: admin| 查看: 71| 评论: 0|原作者: admin|来自: AutoCAD

覆盖 wblockClone() 函数

执行 wblock 克隆操作时,AutoCAD 将为新图形构建一个有效的数据库,其中包含命名对象字典、所有符号表和完整的标题变量集。以下代码近似于 的默认实现。列出的步骤与重写 deepClone() 函数一节中列出的步骤相对应。wblockClone()

该函数使用类 AcDbWblockCloneFiler 的文件管理器,该文件管理器返回主对象的硬指针和硬所有者连接的列表。在调用这些子对象之前,您需要检查子对象的所有者。此时,你将执行以下两项操作之一:wblockClone()wblockClone()

  • 如果您是对象的所有者,请将子对象的所有者设置为您自己的克隆。
  • 如果您不是对象的所有者,请在函数调用中将克隆的数据库作为参数传入。此时,对象将追加到新数据库,接收对象 ID,并放入 ID 映射中。此对象的 ID 映射条目将为字段指定 FALSE。pOwnerwBlockClone()isOwnerTranslated

如果设置为数据库,则必须将克隆对象的所有者设置为与原始对象相同的所有者。然后,当AutoCAD转换参照时,它将更新对新数据库中克隆对象的所有者参照。pOwnerwblockClone()

请务必确保克隆所有拥有对象。在 wblock 克隆期间,AutoCAD 始终克隆符号表、命名对象字典、模型空间和图纸空间(对于除 之外的克隆上下文)。具有所属对象的应用程序负责确保在必要时克隆这些对象。如果所属对象未被克隆且在 ID 映射中未找到,则 wblock clone 将使用 中止。AcDb::kDcXrefBindAcDb::eOwnerNotSet

在复制引用符号表记录的实体时,必须以对象所有者的身份传入数据库。例如,假设您正在调用一个球体对象。块表记录是此球体对象的硬所有者。sphere 对象包含对图层表的硬引用。wblockClone()

首先,在该阶段,使用默认元素创建并设置新数据库。下图显示了模型空间块表记录和层表,因为它们与本主题相关。在此阶段发生的克隆始终发生在 wblock 操作期间。beginDeepClone()

在阶段,选择集被克隆,如下图所示。在此示例中,球体是克隆的。beginWblock()

因为球体包含指向图层的硬指针 1 1 被克隆。

接下来,需要翻译指针以引用克隆的对象,如下图所示。该通知指示此阶段的开始。beginDeepCloneXlation()

上图当时的ID图如下:beginDeepCloneXlation()

上图的ID图

       

钥匙

价值

是克隆的

是主

isOwnerXlated

BTR1型

BTR2型

SPH1型

SPH2型

LT1型

LT2型

*

LTR1型

LTR2型

假**

*图层表的所有者是数据库本身,因此此条目毫无意义。

**在转换过程中,此设置表示图层的所有者将从 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);

路过

雷人

握手

鲜花

鸡蛋

最新评论

QQ|Archiver|CAD开发者社区 ( 苏ICP备2022047690号-1   苏公网安备32011402011833)

GMT+8, 2024-12-15 22:21

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

返回顶部