问题描述: 

在 CAD 二次开发中,对块表记录、模型空间等进行遍历并收集 `ObjectId`,再参与后续操作(如设置绘图顺序、批量克隆等)时,在 AutoCAD 上运行正常,而在中望 CAD 上可能报错,例如:

场景 1:对收集到的多个 ObjectId调用 setRelativeDrawOrder() 时,中望返回 eInvalidObjectId,而 AutoCAD 无问题。
场景 2:将某 DWG 模型空间内所有实体的 ObjectId`收集后,用 WblockCloneObjects克隆到当前图,部分图纸报 ePermanentlyErased错误。

原因简述:图纸中可能含有**已删除、已擦除、无效或非驻留**的对象 ID。AutoCAD 部分 API 在内部会过滤或容错,而中望 CAD 会严格校验,传入非法 ID 即报错。因此需要在**收集或使用 ObjectId 之前**做合法性判断,只保留“可安全使用”的 ID。

步骤指引:

  1. 推荐做法:统一使用 ObjectId 合法性校验

    在**遍历块表记录、模型空间或任意 Id 集合**时,凡是要参与后续操作的 `ObjectId`,都应先通过下面的条件过滤,再加入集合或参与运算。

    ### 合法性校验条件(推荐)

    同时满足以下条件时,再认为该 ObjectId 可安全使用:

    !id.IsNull非空 ID 
    id.IsValid在当前数据库中有效 
    !id.IsErased 未被擦除 
    !id.IsEffectivelyErased未被“逻辑擦除”(例如所在块被擦除) 
    id.IsResident对象驻留在当前数据库(非 xref 等非驻留) 

C++示例:

bool IsObjectIdSafeToUse(const AcDbObjectId& id)
{
    return !id.isNull() && id.isValid() && !id.isErased()
           && !id.isEffectivelyErased() && id.isResident();
}

// 遍历时只收集合法 ID
AcDbObjectIdArray ids;
for (AcDbBlockTableRecordIterator* pIt = nullptr;
     pBtr->newIterator(pIt) == Acad::eOk && pIt;)
{
    AcDbObjectId id;
    if (pIt->getEntityId(id) == Acad::eOk && IsObjectIdSafeToUse(id))
        ids.append(id);
    pIt->step();
    delete pIt;
}

C#示例:

static bool IsObjectIdSafeToUse(ObjectId id)
{
    return !id.IsNull && id.IsValid && !id.IsErased
           && !id.IsEffectivelyErased && id.IsResident;
}

// 遍历模型空间时只加入合法 ID
ObjectIdCollection idCollection = new ObjectIdCollection();
using (Transaction trans = db.TransactionManager.StartTransaction())
{
    BlockTableRecord model = trans.GetObject(db.ModelSpaceId, OpenMode.ForRead) as BlockTableRecord;
    foreach (ObjectId id in model)
    {
        if (IsObjectIdSafeToUse(id))
            idCollection.Add(id);
    }
    trans.Commit();
}


英文空间链接


★★ 遍历 DWG 实体或 ObjectId 时的异常处理与合法性校验https://confluence.zwcad.com/pages/viewpage.action?pageId=319951386

  • No labels