ObjectARX 使用std::sort坐标点排序带图元排序例子
有不少人是从autolisp转向ObjectARX开发,习惯了一些lisp的数据结构.虽然objectARX编程和lisp编程是不同编程语言,但是编程思想是可以相互借鉴的.
就拿这个点表排序来说,在lisp中常用的方式就是构建一个(点 图元名)的表集合,使用vl-sort来排序.
而在ObjectARX中,同样我们也可以实现这样的操作..排序的时候按点坐标排序,点附带了对象ID,便于排序后处理实体对象..
我们这里使用一个struct来构造 点 和对象ID的结构体;
代码
//定义结构体 pt,ObjId struct ListPtEntId { AcGePoint3d pt; AcDbObjectId objId; };
然后可以使用 AcArray动态数组模板来实现这个结构体的集合.
为了简化代码,我们可以给这个数组模板typedef一个别名
代码
//定义命名AcArray typedef AcArray<ListPtEntId> ListPtEntIdArray;
代码会使用std::sort来实现排序的算法.需要先添加头文件的包含,确保sort正常使用.
个人建议这里不使用std命名空间.使用std::sort避免命名冲突.
同时我们可以声明一个double类型的静态全局变量来实现点值比较的容差(公差);
代码
//加入std算法头文件 #include <algorithm> //定义点值比较的容差(公差) static double g_dTolerance=1.0e-8;
添加比较算法
//比较函数,先从左向右,再从上到下 static bool mySortByX(const ListPtEntId &s1,const ListPtEntId &s2) { //如果点的y值相等,x从小到大,否则y从大到小 if (fabs(s1.pt.y - s2.pt.y) < g_dTolerance) return (s1.pt.x<s2.pt.x); else return (s1.pt.y> s2.pt.y); }
准备工作完成,开始测试
代码
static void testMySort() { ads_name ss; //堆上创建过滤圆链表 resbuf *rbList=acutBuildList(RTDXF0,_T("CIRCLE"),RTNONE); acutPrintf(_T("\n请选择圆: ")); if (RTNORM != acedSSGet(NULL,NULL,NULL,rbList,ss)) { //提前return退出,要释放链表. acutRelRb(rbList); acutPrintf(_T("\n未选择到有效对象!")); return; } //释放链表 acutRelRb(rbList); //高版本acedSSLength要求用Adesk::Int32 Adesk::Int32 nSSLength=0; acedSSLength(ss,&nSSLength); ads_name ent; AcDbObjectId objId; //创建ListPtEntId数组 ListPtEntIdArray listEnts; for (Adesk::Int32 i=0;i<nSSLength;i++) { acedSSName(ss,i,ent);//此处无需错误处理. acdbGetObjectId(objId,ent);//此处无需错误处理. //使用ARX智能指针打开对象,在循环内的变量(作用域)的进入下一次循环会清空 AcDbObjectPointer<AcDbCircle> pCircle(objId,AcDb::kForRead); if (Acad::eOk != pCircle.openStatus()) { //跳过此次循环,进入下一次循环. continue; } //创建ListPtEntId对象并赋值 ListPtEntId listEnt; listEnt.pt=pCircle->center(); listEnt.objId=objId; //添加到ListPtEntId数组 listEnts.append(listEnt); if (0 == i) { //设置公差(容差)值 g_dTolerance=pCircle->radius(); } } //及时释放选择集 acedSSFree(ss); //设置公差(容差)值 //g_dTolerance=100.0; //执行std::sort排序 std::sort(listEnts.asArrayPtr(),listEnts.asArrayPtr()+listEnts.logicalLength(),mySortByX); //验证排序后的结果 for (Adesk::Int32 i=0;i<listEnts.length();i++) { //同样使用ARX指针,尽管上个循环打开过,但是出了循环就会自动关闭,所以这里打开不会失败. AcDbObjectPointer<AcDbCircle> pCircle(listEnts.at(i).objId,AcDb::kForWrite); if (Acad::eOk != pCircle.openStatus()) { continue; } //使用智能指针创建单行文本 AcDbObjectPointer<AcDbText> pText; if (Acad::eOk!= pText.create()) { continue; } //设置文字属性,按pt点居中显示,字高为半径的0.5倍 pText->setPosition(listEnts.at(i).pt); pText->setHeight(pCircle->radius()*0.5); pText->setHorizontalMode(AcDb::kTextMid); pText->setVerticalMode(AcDb::kTextVertMid); pText->setAlignmentPoint(listEnts.at(i).pt); CString str; str.Format(_T("%02d"),i+1); pText->setTextString(str); //添加到当前工作空间 PostToCurrentSpace(pText); //前256个对象直接修改颜色,此处仅做演示. if (i<256) { pCircle->setColorIndex(i+1); } } }
添加实体到当前空间函数
static Acad::ErrorStatus PostToCurrentSpace(AcDbEntity *pEnt) { AcDbDatabase *pDb=acdbHostApplicationServices()->workingDatabase(); AcDbBlockTableRecordPointer pBlkRcd(pDb->currentSpaceId(),AcDb::kForWrite); if (Acad::eOk != pBlkRcd.openStatus()) { return pBlkRcd.openStatus(); } return pBlkRcd->appendAcDbEntity(pEnt); }
最终效果如图,