有不少人是從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);
}
最終效果如圖,

