问题描述:
在 CAD 二次开发中,对块表记录、模型空间等进行遍历并收集 `ObjectId`,再参与后续操作(如设置绘图顺序、批量克隆等)时,在 AutoCAD 上运行正常,而在中望 CAD 上可能报错,例如:
场景 1:对收集到的多个 ObjectId调用 setRelativeDrawOrder() 时,中望返回 eInvalidObjectId,而 AutoCAD 无问题。
场景 2:将某 DWG 模型空间内所有实体的 ObjectId`收集后,用 WblockCloneObjects克隆到当前图,部分图纸报 ePermanentlyErased错误。
原因简述:图纸中可能含有**已删除、已擦除、无效或非驻留**的对象 ID。AutoCAD 部分 API 在内部会过滤或容错,而中望 CAD 会严格校验,传入非法 ID 即报错。因此需要在**收集或使用 ObjectId 之前**做合法性判断,只保留“可安全使用”的 ID。
步骤指引:
推荐做法:统一使用 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