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

  

最終效果如圖,

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM