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);		
	}

  

最终效果如图,

 

 

posted @ 2020-04-02 13:37  edata  阅读(1198)  评论(0编辑  收藏  举报