在利用ObjectARX进行CAD二次开发时,如何选择块参照中嵌套的实体,并进行进行下一步操作?这个问题的难点是:如何判断用户选中的实体到底是块参照里面的非嵌套对象实体?还是块参照中嵌套的块参照的实体?本文利用全局函数acedNEnsSelP解决了这个问题,并可实现:如果用户选择块参照中嵌套的实体,直接视为用户选择了这个嵌套的块参照,效果如图。
一、全局函数acedNEntSelP介绍
为了选中块参照中的实体,ObjectARX提供了一个接口:
int acedNEntSelP(
const ACHAR * str,
ads_name entres,
ads_point ptres,
int pickflag,
ads_matrix xformres,
struct resbuf ** refstkres
);
const ACHAR * str:在选择块参照中实体时的提示语,如果为NULL,AutoCAD 显示默认的提示语。
ads_name entres:选择实体的ads_name名称。
ads_point ptres:选择实体时点取的点。
int pickflag:指定acedNEntSelP是否用于和用户交互;如果为假,acedNEntSelP提示用户指定实体并忽略ptres;如果为真,使用ptres的初始值去选择实体。
ads_matrix xformres:该4×4变换矩阵可以将实体的任意ECS坐标转换为WCS坐标。如果选择的实体不是嵌套实体,该值设为单位矩阵。利用这个矩阵,可以将选中的实体从ECS坐标系转换到WCS坐标系。
struct resbuf ** refstkres :包含嵌套实体的各级块参照。
注意,最后一个参数最为重要,它实际记录了选择对象的各级嵌套块参照。
二、实现方法介绍
利用acedNEntSelP参数中最后的链表参数,查看选择对象的各级嵌套块参照,并对块参照进行坐标变换,将其坐标转为当前图形的WCS坐标。
BOOL SelectEntsFromBlock(CString csPrompt, PickSet &ssResult,AcGePoint3d& ptBase) { ads_name ent; ads_point pt; ads_matrix mat; struct resbuf* pHead = NULL; int iRet = acedNEntSelP(csPrompt, ent, pt, FALSE, mat, &pHead); ads_name entOuterBlock; if (iRet == RTNORM) { if (!pHead) { acutPrintf(_T("这并不是一个块参照中的对象")); return FALSE; } ptBase.x = pt[0]; ptBase.y = pt[1]; ptBase.z = pt[2]; //如果ent为块参照中的嵌套块参照对象,例如块参照A嵌套块参照B,块参照B嵌套块参照C, //用户点取了嵌套块C的某个实体,以下循环可以将ent修改为块参照B;并且获得最外层的块参照的ads_name while (pHead && pHead->restype == RTENAME) { if (pHead && !pHead->rbnext)//如果点取的是块参照中的非嵌套对象 { ads_name_set(pHead->resval.rlname, entOuterBlock); break; } else if (pHead->rbnext && !pHead->rbnext->rbnext)//如果点取的是块参照的嵌套对象 { ads_name_set(pHead->resval.rlname, ent); ads_name_set(pHead->rbnext->resval.rlname, entOuterBlock); break; } pHead = pHead->rbnext; } //求解块参照的变换矩阵 AcGeMatrix3d matBlockRef; AcDbObjectId id; acdbGetObjectId(id, entOuterBlock);//获取最外层块参照的ID AcDbBlockReference* pOuterBlockRef = NULL; if (Acad::eOk == acdbOpenObject(pOuterBlockRef, id, AcDb::kForRead)) { if (pOuterBlockRef) { //获取转换矩阵,从块表记录中的MCS坐标转为当前图形的WCS坐标 matBlockRef = pOuterBlockRef->blockTransform(); } pOuterBlockRef->close(); } acdbGetObjectId(id, ent);//获取用户选中实体的ID AcDbEntity* pEnt = NULL; AcDbEntity* pEntClone = NULL; if (Acad::eOk == acdbOpenObject(pEnt, id, AcDb::kForRead)) { if (pEnt) { pEntClone = (AcDbEntity*)pEnt->clone(); //此步骤是关键,复制出来实体以后,将实体从块参照自己的WCS坐标系转换为当前数据库的WCS pEntClone->transformBy(matBlockRef); AddToCurrentSpace(pEntClone, true);//加入到当前数据库 } pEnt->close(); } //这里省略了对选择对象进行拖动的代码 //........... return TRUE; } else return FALSE; }
文章评论