一,選擇集的創建和刪除
(1)使用的的ObjectARX的向導創建一個新工程名稱為SelectionSet
創建完成后,編譯,若出錯:
錯誤C2338:/ RTCc拒絕符合代碼,因此C ++標准庫不支持它。刪除此編譯器選項,或定義_ALLOW_RTCc_IN_STL以確認您已收到此警告。
需要做如下修改:
①debug設置為64位
②較小類型檢查設置為:否
(2)注冊一個新命令CreateSSet,用於演示選擇集的創建和刪除
static void AAAMyGroupCreateSSet() {
// Put your command code here
ads_name sset;//選擇集名稱
//選擇圖形數據庫中所有的實體
acedSSGet(TEXT("A"), NULL, NULL, NULL, sset);
long length;
acedSSLength(sset, (Adesk::Int32*) &length);
acutPrintf(TEXT("\n實體數:%d"), length);
//進行其他操作
acedSSFree(sset);
}
注意:acedSSLength(sset,(Adesk :: Int32 *)&length);的第二個參數需要強制類型轉換
acedSSGet函數:
通過指定一個的AutoCAD中的選擇模式來返回一個選擇集。選擇模式是通過提示的AutoCAD中的用戶或過濾繪圖數據庫來指定的。在處理完選擇之后,您必須釋放所分配的選擇集。
int acedSSGet(
const ACHAR * str,
const void * pt1,
const void * pt2,
const struct resbuf * filter,
ads_name ss
);
const ACHAR * str:指定要使用的實體選擇模式的可選字符串 |
一下是模式列表:
const void * pt1:與某些選擇模式相關的可選點;或者一個包含多邊形或籬笆選擇選項的多個點的結果緩沖列表; |
const void * pt2:與某些選擇模式相關的可選點 |
const struct resbuf * filter:可選的結果緩沖列表,使用acedSSGet()能夠過濾繪圖以選擇某些類型的實體或具有某些屬性 |
ads_name ss:選擇集的名稱。 |
(3)效果1
在CAD中創建3個實體:
按Ctrl + F2:
二,對象選擇的方法
(1)注冊一個新命令SelectEnt2,使用多種不同的模式創建選擇集
static void AAAMyGroupSelectEnt2() {
//因為CAD默認快捷鍵中已經存在SelectEnt,所以在這里我們注冊命令為SelectEnt2
// Put your command code here
ads_point pt1, pt2, pt3, pt4;
struct resbuf *pointlist; //結果緩沖區鏈表
ads_name ssname; //選擇集的圖元名
pt1[X] = pt2[Y] = pt1[Z] = 0.0;
pt2[X] = pt2[Y] = 5.0; pt2[Z] = 0.0;
//如果已經選擇到了實體,就獲得當前的PICKFIRST選擇集
//否則提示用戶選擇實體
acedSSGet(NULL, NULL, NULL, NULL, ssname);
//如果存在,就獲得當前的PickFirst選擇集
acedSSGet(TEXT("I"), NULL, NULL, NULL, ssname);
//選擇最近創建的選擇集
acedSSGet(TEXT("P"), NULL, NULL, NULL, ssname);
//選擇最后一次創建的可見實體
acedSSGet(TEXT("L"), NULL, NULL, NULL, ssname);
//選擇通過點(5,5)的所有實體
acedSSGet(NULL, pt2, NULL, NULL, ssname);
//選擇位於角點(0,0)和(5,5)組成的窗口內所有的實體
acedSSGet(TEXT("W"), pt1, pt2, NULL, ssname);
//選擇被指定的多邊形包圍的所有實體
pt3[X] = 10.0; pt3[Y] = 5.0; pt3[Z] = 0.0;
pt4[X] = 5.0; pt4[Y] = pt4[Z] = 0.0;
pointlist = acutBuildList(RTPOINT, pt1, RTPOINT, pt2,
RTPOINT, pt3, RTPOINT, pt4, 0);
acedSSGet(TEXT("WP"), pointlist, NULL, NULL, ssname);
//選擇與角點(0.0)和(5,5)組成的區域相交的所有實體
acedSSGet(TEXT("C"), pt1, pt2, NULL, ssname);
//選擇與指定多邊形區域相交的所有實體
acedSSGet(TEXT("CP"), pointlist, NULL, NULL, ssname);
acutRelRb(pointlist);
//選擇與選擇欄相交的所有實體
pt4[Y] = 15.0; pt4[Z] = 0.0;
pointlist = acutBuildList(RTPOINT, pt1, RTPOINT, pt2,
RTPOINT, pt3, RTPOINT, pt4, 0);
acedSSGet(TEXT("F"), pointlist, NULL, NULL, ssname);
acutRelRb(pointlist);//釋放分配給指定結果緩沖區的內存
acedSSFree(ssname);
}
(2)在acrxEntryPoint.cpp文件的開頭部分添加PolyToCurve函數,該函數用於根據指定的多段線創建對應的幾何類曲線,包含兩個參數,pPline指定已知的多段線,pGeCurve參數輸出創建的幾何曲線。
實現函數:
static bool PolyToGeCurve(AcDbPolyline *pPline, AcGeCurve2d *&pGeCurve)
{
int nSegs; //多段線的段數
AcGeLineSeg2d line, *pLine; //幾何曲線的直線段部分
AcGeCircArc2d arc, *pArc; //幾何曲線的圓弧部分
AcGeVoidPointerArray geCurves; //指向組成幾何曲線各分段的指針數組
nSegs = pPline->numVerts() - 1;
//根據多段線創建對應的分段幾何曲線
for (int i = 0; i < nSegs; i++)
{
if (pPline->segType(i) == AcDbPolyline::kLine)
{
pPline->getLineSegAt(i, line);
pLine = new AcGeLineSeg2d(line);
geCurves.append(pLine);
}
else if (pPline->segType(i) == AcDbPolyline::kArc)
{
pPline->getArcSegAt(i, arc);
pArc = new AcGeCircArc2d(arc);
geCurves.append(pArc);
}
}
//處理閉合多段線最后一段是圓弧的情況
if (pPline->isClosed() && pPline->segType(nSegs) == AcDbPolyline::kArc)
{
pPline->getArcSegAt(nSegs, arc);
pArc = new AcGeCircArc2d(arc);
pArc->setAngles(arc.startAng(), arc.endAng() -
(arc.endAng() - arc.startAng()) / 100);
geCurves.append(pArc);
}
//根據分段的幾何曲線創建對應的復合曲線
if (geCurves.length() == 1)
{
pGeCurve = (AcGeCurve2d*)geCurves[0];
}
else
{
pGeCurve = new AcGeCompositeCurve2d(geCurves);
}
//釋放動態分配的內存
if (geCurves.length() > 1)
{
for (int i = 0; i < geCurves.length(); i++)
{
delete geCurves[i];
}
}
return true;
}
①getLineSegAt(I,線)函數:
如果頂點索引中的線段是一條直線,那么“線”將被設置為該段的一個代表性的2D副本,在折線自己的對象坐標系統(OCS)中。
②getArcSegAt(nSegs,弧)函數:
如果頂點索引nSegs中的線段是一個弧,那么這個函數將在折線自己的坐標中從折線中填充2D“弧”信息(半徑,中心等)。
(3)在acrxEntryPoint.cpp中添加一個新的函數SelectEntInPoly,用於選擇指定多段線內部(或者與多段線構成的區域相交的所有實體)
函數的實現代碼為:
static bool SelectEntInPoly(AcDbPolyline *pPline, AcDbObjectIdArray &ObjectIdArray, const char *selectMode, double approxEps)
{
//判斷selectMode的有效性
if (_tcscmp((const wchar_t *)selectMode, TEXT("CP")) != 0 && _tcscmp((const wchar_t *)selectMode, TEXT("WP")) != 0)
{
acedAlert(TEXT("函數SelectEntInPline中,指定了無效的選擇模式!"));
return false;
}
//清除數組中所有的ObjectId
for (int i = 0; i < ObjectIdArray.length(); i++)
{
ObjectIdArray.removeAt(i);
}
AcGeCurve2d *pGeCurve; //多段線對應的幾何曲線
Adesk::Boolean bClosed = pPline->isClosed(); //多段線是否閉合
if (bClosed != Adesk::kTrue) //確保多段線作為選擇邊界時是閉合的
{
pPline->setClosed(!bClosed);
}
//創建對應的幾何類曲線
PolyToGeCurve(pPline, pGeCurve);
//獲得幾何曲線的樣本點
AcGePoint2dArray SamplePtArray; //存儲曲線的樣本點
AcGeDoubleArray ParamArray; //存儲樣本點對應的參數值
AcGePoint2d ptStart, ptEnd; //幾何曲線的起點和終點
Adesk::Boolean bRet = pGeCurve->hasStartPoint(ptStart);
bRet = pGeCurve->hasEndPoint(ptEnd);
double valueSt = pGeCurve->paramOf(ptStart);
double valueEn = pGeCurve->paramOf(ptEnd);
pGeCurve->getSamplePoints(valueSt, valueEn, approxEps,
SamplePtArray, ParamArray);
delete pGeCurve; //在函數PolyToGeCurve中分配了內存
//確保樣本點的起點和終點不重合
AcGeTol tol;
tol.setEqualPoint(0.01);
AcGePoint2d ptFirst = SamplePtArray[0];
AcGePoint2d ptLast = SamplePtArray[SamplePtArray.length() - 1];
if (ptFirst.isEqualTo(ptLast))
{
SamplePtArray.removeLast();
}
//根據樣本點創建結果緩沖區鏈表
struct resbuf *rb;
rb = BuildRbFromPtArray(SamplePtArray);
//使用acedSSGet函數選擇集
ads_name ssName; //選擇集名稱
int rt = acedSSGet((ACHAR *)selectMode, NULL, NULL, rb, ssName);
if (rt != RTNORM)
{
acutRelRb(rb); //釋放結果緩沖區
return false;
}
//將選擇集中所有的對象添加到ObjectIdArray
long length;
acedSSLength(ssName, (Adesk::Int32 *)&length);
for (int i = 0; i < length; i++)
{
//獲得指定元素的ObjectId
ads_name ent;
acedSSName(ssName, i, ent);
AcDbObjectId objId;
acdbGetObjectId(objId, ent);
//獲得指向當前元素的指針
AcDbEntity *pEnt;
Acad::ErrorStatus es = acdbOpenAcDbEntity(pEnt, objId, AcDb::kForRead);
//選擇到作為邊界的多段線了,直接跳過該次循環
if (es == Acad::eWasOpenForWrite)
{
continue;
}
ObjectIdArray.append(pEnt->objectId());
pEnt->close();
}
//釋放內存
acutRelRb(rb); //釋放結果緩沖區鏈表
acedSSFree(ssName); //刪除選擇集
return true;
}
①_tcscmp(selectMode,TEXT(“CP”)):編譯是出錯:
錯誤C2664:“int wcscmp(const wchar_t *,const wchar_t *)”:無法將參數1從“const char *”轉換為“const wchar_t *”
需要類型轉換:
_tcscmp((const wchar_t *)selectMode,TEXT(“CP”))
②getSamplePoints(valueSt,valueEn,approxEps,SamplePtArray,的ParamArray)函數:
void getSamplePoints(
double fromParam,
double toParam,
double approxEps,
AcGePoint2dArray& pointArray,
AcGeDoubleArray& paramArray
) const;
double fromParam:輸入起始參數 |
double toParam:輸入結束參數 |
double approxEps:弦高誤差 |
AcGePoint2dArray&pointArray:從PARAM和topam之間的曲線上的點的輸出陣列 |
AcGeDoubleArray與ParamArray參數:與點對點對應的參數的輸出陣列 |
函數描述:返回從PARAM和topam之間的曲線上的點列表在點數組返回的任意兩個連續點之間的線段,不會偏離曲線的約值。
③acedSSGet((ACHAR *)selectMode,NULL,NULL,rb,ssName)函數:
int acedSSGet(
const ACHAR * str,
const void * pt1,
const void * pt2,
const struct resbuf * filter,
ads_name ss
);
const ACHAR * str |
指定要使用的實體選擇模式的可選字符串 |
const void * pt1 |
與某些選擇模式相關的可選點;或者一個包含多邊形或籬笆選擇選項的多個點的結果緩沖列表;或者是兩根字符串的數組,它們是一個:$模式選項的替換提示 |
const void * pt2 |
與某些選擇模式相關的可選點 |
const struct resbuf * filter |
可選的結果緩沖列表,使acedSSGet()能夠過濾繪圖以選擇某些類型的實體或具有某些屬性 |
ads_name ss |
選擇集的名稱 |
函數描述:通過指定一個AutoCAD中的選擇模式來返回一個選擇集選擇模式是通過提示的AutoCAD的用戶或過濾繪圖數據庫來指定的。
④acedSSName(ssName,I,ENT)函數:
int acedSSName(
const ads_name ss,
int i,
ads_name entres
);
File
const ads_name ss |
包含實體的選擇集 |
int i |
實體的零基指數位置;必須是非負的,並且不大於選擇集中的最后一個實體的索引(acedSSLength(SS)-1) |
ads_name entres |
返回的實體名稱 |
函數描述:返回一個實體的名稱,由它在選擇集中的位置指定。
⑤acdbOpenAcDbEntity(pEnt,objId,AcDb :: kForRead)函數:
inline Acad::ErrorStatus acdbOpenAcDbEntity(
AcDbEntity*& pEnt,
AcDbObjectId id,
AcDb::OpenMode mode,
bool openErasedEntity = false
);
AcDbEntity *&pEnt |
輸出指針指向打開的對象 |
AcDbObjectId id |
要打開的對象的輸入對象ID |
AcDb :: OpenMode模式 |
打開對象的輸入模式 |
bool openErasedEntity = false |
輸入布爾值表示打開一個被擦除的實體是否可以 |
函數描述:這個函數提供了一種方法來打開源自AcDbEntity(即擁有圖形)的數據庫駐留對象
(4)創建一個新的函數BuildRbFromPtArray,根據用於指定的一組點創建³³查詢一個查詢查詢查詢結果緩沖區鏈表
函數的實現:
static struct resbuf* BuildRbPtArray(const AcGePoint2dArray &arrPoints)
{
struct resbuf *retRb = NULL;
int count = arrPoints.length();
if (count <= 1)
{
acedAlert(TEXT("函數BuildRbFromPtArray中,點數組包含元素個數不足!"));
return retRb;
}
//使用第一個點來構建結果緩沖區鏈表的頭結點
ads_point adsPt;
adsPt[X] = arrPoints[0].x;
adsPt[Y] = arrPoints[0].y;
retRb = acutBuildList(RTPOINT, adsPt, RTNONE);
struct resbuf *nextRb = retRb;//輔助指針
for (int i = 1; i < count; i++)//注意:不考慮第一個元素,因此i從1開始
{
adsPt[X] = arrPoints[i].x;
adsPt[Y] = arrPoints[i].y;
//動態創建新的節點,並將其鏈接到原來的鏈表尾部
acutBuildList(RTPOINT, adsPt, RTNONE);
nextRb = nextRb->rbnext;
}
return retRb;
}
acutBuildList(RTPOINT,adsPt,RTNONE)函數:
struct resbuf * acutBuildList(
int rtype,
ads_point adsPt
);
函數描述::通過分配結果緩沖區,從單個數據項中建立一個鏈表的結果緩沖區列表,分配由acutBuildList()參數指定的值,並將緩沖區鏈接在一起。
(5)注冊一個新命令SelectEntPoly,提示用戶選擇一條多段線,在命令窗口中顯示與多段線形成的區域相交的實體個數
函數的實現:
static void AAAMyGroupSelectEntInPoly() {
// Put your command code here
//提示用戶選擇多段線
ads_name entName;
ads_point pt;
if (acedEntSel(TEXT("\n選擇多段線:"), entName, pt) != RTNORM)
return;
AcDbObjectId entId;
acdbGetObjectId(entId, entName);
//判斷選擇的實體是否是多段線
AcDbEntity *pEnt;
acdbOpenObject(pEnt, entId, AcDb::kForWrite);
if (pEnt->isKindOf(AcDbPolyline::desc()))
{
AcDbPolyline *pPoly = AcDbPolyline::cast(pEnt);
AcDbObjectIdArray ObjectIdArray;//選擇到的實體ID集合
SelectEntInPoly(pPoly, ObjectIdArray, "CP", 1);
acutPrintf(TEXT("\n選擇到%d個實體"), ObjectIdArray.length());
}
pEnt->close();
}
①acedEntSel(TEXT(“\ n選擇多段線:”),entName,pt)函數:
int acedEntSel(
const ACHAR * str,
ads_name entres,
ads_point ptres
);
File
const ACHAR * str |
acedEntSel()在停頓之前顯示的可選字符串;如果一個空指針時,則AutoCAD將顯示選擇對象默認提示符 |
ads_name entres |
所選實體名稱 |
ads_point ptres |
用於選擇實體名稱的點 |
函數描述:提示用戶通過指定一個點來選擇一個實體對用戶輸入的暫停,並返回實體名稱和用於選擇實體的點。
②acdbOpenObject(pEnt,entId,AcDb :: kForWrite)函數:
template <class T_OBJECT> inline Acad::ErrorStatus acdbOpenObject(
T_OBJECT *& pObj,
AcDbObjectId id,
AcDb::OpenMode mode = AcDb::kForRead,
bool openErased = false
);
T_OBJECT *&pObj |
輸出指針指向打開的對象 |
AcDbObjectId id |
要打開的對象的輸入對象ID |
AcDb :: OpenMode mode = AcDb :: kForRead |
打開對象的輸入模式 |
bool openErased = false |
輸入布爾值指示是否可以打開一個擦除對象 |
函數描述:這個函數提供了一種方法來打開任何數據庫電阻器對象,而不知道對象是否來自AcDbEntity這個函數在一個空指針中傳遞,pObj要打開的物體的對象ID是OBJID打開的模式是模式。開擦掉是一個布爾值,指示是否在被擦除時打開該對象。
三,使用選擇集過濾器
(1)注冊一個新命令過濾器1,創建一個帶有通配符的過濾器
實現代碼:
static void AAAMyGroupFilter1() {
// Put your command code here
struct resbuf *rb; //結果緩沖區鏈表
ads_name ssname;
rb = acutBuildList(RTDXF0, TEXT("TEXT"),//實體類型
8, TEXT("0,圖層1"), //圖層
1, TEXT("*cadhelp*"), // 包含的字符串
RTNONE);
//選擇符合要求的文字
acedSSGet(TEXT("X"), NULL, NULL, rb, ssname);
long length;
acedSSLength(ssname, (Adesk::Int32 *)&length);
acutPrintf(TEXT("\n實體數:%d"), length);
acutRelRb(rb);
acedSSFree(ssname);
}
查看效果:
在CAD中創建一行當行文字“acadhelp”,輸出1:
(2)注冊一個新命令過濾器2,創建包含邏輯運算符的過濾器
實現代碼:
static void AAAMyGroupFilter2() {
struct resbuf *rb; //結果緩沖區鏈表
ads_name ssname;
rb = acutBuildList(-4, TEXT("<OR"), //邏輯運算符開始
RTDXF0, TEXT("TEXT"), //一個條件
RTDXF0, TEXT("MTEXT"), //另一個條件
-4, TEXT("OR<"), //邏輯運算符結束
RTNONE);
//選擇符合要求的文字
acedSSGet(TEXT("X"), NULL, NULL, rb, ssname);
long length;
acedSSLength(ssname, (Adesk::Int32 *)&length);
acutPrintf(TEXT("\n實體數:%d"), length);
acutRelRb(rb);
acedSSFree(ssname);
}
(3)注冊以一個命令Fiter3,創建包含關系運算符的過濾器
static void AAAMyGroupFilter3() {
struct resbuf *rb; //結果緩沖區鏈表
ads_name ssname;
//選擇圖形中半徑大於或等於30的所有圓
rb = acutBuildList(RTDXF0, TEXT("CIRCLE"), //實體類型
-4, TEXT(">="), //關系運算符;組碼-4指示過濾器列表中的關系運算符
40, 30, //半徑;組碼40用於指定圓的半徑
RTNONE);
//選擇符合要求的圓
acedSSGet(TEXT("X"), NULL, NULL, rb, ssname);
long length;
acedSSLength(ssname, (Adesk::Int32 *)&length);
acutPrintf
(TEXT("\n實體數:%d"), length);
acutRelRb(rb);
}
查看效果:
(4)注冊以一個命令Fiter4,創建包含運算符和通配符的過濾器
static void AAAMyGroupFilter4() {
struct resbuf *rb; //結果緩沖區鏈表
ads_name ssname;
ads_point pt1 = { 0,0,0 };
ads_point pt2 = { 100,100,0 };
//選擇圖形中圓心在pt1和pt2兩點構成的矩形內的圓
rb = acutBuildList(RTDXF0,TEXT("CIRCLE"),//實體類型
-4,TEXT(">,>,*"), //關系運算符和通配符
10,pt1, //圓心;組碼10用於指定圓的圓心
-4,TEXT("<,<,*"), //關系運算符和通配符
10,pt2, //圓心
RTNONE);
acedSSGet(TEXT("X"), NULL, NULL, rb, ssname);
long length;
acedSSLength(ssname, (Adesk::Int32 *)&length);
acutPrintf
(TEXT("\n實體數:%d"), length);
acutRelRb(rb);
}
查看效果:
(5)注冊以一個命令Fiter5,創建擴展數據的過濾器
static void AAAMyGroupFilter5() {
struct resbuf *rb; //結果緩沖區鏈表
ads_name ssname;
rb = acutBuildList(1001, TEXT("XData"), RTNONE);//擴展數據的應用程序名
acedSSGet(TEXT("X"), NULL, NULL, rb, ssname);
long length;
acedSSLength(ssname, (Adesk::Int32 *)&length);
acutPrintf
(TEXT("\n實體數:%d"), length);
acutRelRb(rb);
}
能夠選擇圖形中所有包含“擴展數據”應用程序擴展數據的圖元。
項目流程圖:
<全文完>
項目SelectionSet的完整代碼:
鏈接:https://pan.baidu.com/s/18XzWD3ukWcFHMdpELYagCQ密碼:by0m
參考資料:
“AutoCAD ObjectARX(VC)開發基礎與實例教程”