大多數ObjectARX函數在處理選擇集和實體時,都用名字來識別選擇集或實體,該名字用一個長整型對來表示的,並對AutoCAD來維護。在ObjectARX中,該名字的類型為ads_name。
在對選擇集或實體進行操作之前,ObjectARX應用程序必須通過調用一個返回其名字的庫函數來得到選擇集或實體名字。
注意:選擇集和實體的名字是不穩定的,它們僅僅在AutoCAD當前圖形工作時有效。如果從AutoCAD退出或切換到另一個圖形時其值就會丟失。
對於選擇集來說,它也是與當前圖有關聯的,所以其名字的不穩定性不會影響選擇集。但是對於實體就不一樣了,因為它是被存放在圖形數據庫中的,名字的不穩定性要影響到對實體的操作。應用程序必須在下一次對同一圖文件中的同一實體進行操作,可以使用實體句柄,重新獲取其實體名。
選擇集的處理
ObjectARX函數對選擇集的處理類似於AutoLISP。acedSSGet()函數提供大多數創建選擇集方法。它一般通過以下三種方法之一創建選擇集:
(1)提供讓用戶選擇對象。
(2)象交互式應用AutoCAD一樣,利用RICKFIRST定義、Crossing、Crossing Polygon、Fence、Last、Previous、Window、Window Polygon等匹配條件的方式來選擇實體對象,也可以通過指定一個單獨點或Fence點來選擇。
(3)使用一系列屬性和條件篩選當前圖數據庫來選擇實體對象。
該函數原型為:
int acedSSGet(const chat *str,const void *pt1,const void *pt2,const struct resbuf *entmask,ads_name ss);
acedSSGet()的第一個參數str,說明所使用的選擇條件,如下:
表示碼 意義
NULL 單點選擇(如果指定了pt1)或用戶選擇(如果pt1也為NULL)
# 非幾何選擇(all、last、previous)
:$ 提供提示文字
. 用戶拾取方式
:? 其他回調函數
A All選擇方式
B Box選擇方式
C Crossing選擇方式
CP Crossing Polygon選擇方式
:D 可以重復,即可以重復選擇一個實體,並加入選擇集中
:E 在aperture中的所有實體
F Fence選擇方式
G Groups選擇
I 如果存在RICKFIRST集、則用該集
:K 關鍵字回調函數
L Last選擇方式
M 多重選擇方式
P Previous選擇方式
:S 強制單個實體對象被選擇
W Window選擇方式
WP Window Polygon選擇方式
X 用於篩選程序搜索整個圖形數據庫
緊跟着的兩個參數用於指定與某些選擇方式有關的可選擇的點。當不使用他們時,應該取NULL值。如果第四個參數entmask不是NULL,則它指向一個緩沖區表,用於存放用篩選選擇方式的結果。第五個參數ss是選擇集的識別名字。
下列是調用acedSSGet()的例子:
2 struct resbuf *pointlist;
3 ads_name ssname;
4 pt1[x]=pt1[y]=pt1[z]=0.0;
5 pt2[x]=pt2[y]=5.0;pt2[z]=0.0;
6 //如果有的話,獲取當前RICKFIRST選擇集,沒有則提供用戶選擇一個
7 acedSSGet(NULL,NULL,NULL,NULL,ssname);
8 //如果有的話,獲取當前RICKFIRST選擇集
9 acedSSGet(“I”,NULL,NULL,NULL,ssname);
10 //使用最近使用過的選擇集
11 acedSSGet(“P”,NULL,NULL,NULL,ssname);
12 //選擇最后加入到數據庫中的對象
13 acedSSGet(“L”,NULL,NULL,NULL,ssname);
14 //選擇通過點(5,5)的實體
15 acedSSGet(NULL,pt2,NULL,NULL,ssname);
16 //選擇從點(0,0)到點(5,5)的窗口中的實體
17 acedSSGet(“W”,pt1,pt2,NULL,ssname);
18
19 //選擇指定多邊形包圍的實體
20 pt3[x]=10.0;pt3[y]=5.0;pt3[z]=0.0;
21 pt4[x]=5.0;pt4[y]=pt4[z]=0.0;
22 pointlist=acutBuildlist(RTPOINT,pt1, RTPOINT,pt2, RTPOINT,pt3, RTPOINT,pt4,0);
23 acedSSGet(“WP”,pointlist,NULL,NULL,ssname);
24
25 //選擇選擇從點(0,0)到點(5,5)的窗口內交叉的實體
26 acedSSGet(“C”,pointlist,NULL,NULL,ssname);
27
28 acutRelRb(pointlist);
29
30 //選擇與指定柵欄交叉的實體
31 pt4[y]=15.0;pt4[z]=0.0;
32 pointlist=acutBuildlist(RTPOINT,pt1, RTPOINT,pt2, RTPOINT,pt3, RTPOINT,pt4,0);
33 acedSSGet(“F”,pointlist,NULL,NULL,ssname);
34 acutRelRb(pointlist);
對acedSSGet()的補充函數是acedSSFree(),它能在應用程序用完選擇集后釋放選擇集。選擇集是按名字來被使用的。對上面程序段中定義的ads_name,在這里使用為:
acedSSFree(ssname);
注意:AutoCAD不能同時打開多於128個選擇集,包括運行中的ObjectARX和AutoLISP應用程序打開選擇集的總和。在不同的系統有可能有所不同。如果超過上限,AutoCAD拒絕創建選擇集。因此在不用選擇集時,應盡快用acedSSFree()釋放。
選擇集篩選表
當acedSSGet()函數的entmask參數明確記錄了實體的范圍值列表時,acedSSGet()掃描被選擇的實體,同時建立一個包含主實體名的選擇集,這些實體與篩選條件相匹配。比如,使用這種方法,用戶可以得到一個給定的選擇集,這個選擇集包括給定的層、類型、顏色的所有實體。
篩選表可以與任何的選擇項聯合使用。如果用“X”選擇方式,意味着建立一個僅使用篩選表的選擇集。在AutoCAD以前的版本中,如果用“X”選項,acedSSGet()將掃描全部圖形數據庫。
注意:要是僅僅篩選表指定為“X”,而參數entmask是NULLL,則acedSSGet()選擇所有在數據庫中的實體。
參數entmask必須是一個結果緩沖區表。每一個緩沖區指定一個檢查參數和匹配的值;緩沖區的restype段是一個DXF組碼,它指定要查詢的參數的種類,而緩沖區的restype域指定要匹配的值。下面是相應的例子:


char sbuf1[10],sbuf2[10];
ads_name ssname1,ssname2;
eb1.restype=0; //實體名
strcpy(sbuf1,”CIRCLE”);
eb1.resval.restring=sbuf1;
eb1.rbnext=NULL; //無其他內容
//檢索所有圓
acedSSGet(“X”,NULL,NULL,&eb1,ssname1);
eb2.restype=8;//層名
strcpy(sbuf2,”FLOOR3”);
eb2.resval.rstring=sbuf2;
eb2.rbnext=NULL;
//檢索在圖層FLOOR3上的所有實體
acedSSGet(“X”,NULL,NULL,&eb2,ssname2);
注意: 在每個緩沖區中指定的resval必須屬於合適的類型,比如:名字類型是字符串(resval.rstring);標高和厚度是雙精度浮點型(resval.rreal);顏色、屬性和標志值是短整型(resval.rint);拉伸向量是三維的點(resval.rpoint),等等。
如果entmask指定了多個參數,那么只有匹配所有指定條件的實體才能被包含在選擇集里。就象下面的例子:
2 eb3.resval.rint=1;//紅色
3 eb3.rbnext=NULL;
4 eb1.rbnext=&eb2;//增加另外兩個條件
5 eb2.rbnext=&eb3;//建立鏈表
6 //檢索在圖層FLOOR3層上所有紅色的圓
7 acedSSGet(“X”,NULL,NULL,&eb1,ssname1);
除非表中包括關系和條件操作符,否則實體的所有域都要被測試。
如果在數據庫中沒有實體與指定的篩選條件匹配,函數acedSSGet()將返回RTERROR。
前面關於acedSSGet()的例子用的是“X”選項,它掃描整個圖形數據庫;如果篩選表與其他選項(如用戶選擇、窗口選擇等)聯合使用,篩選條件只能在被選中的實體上起作用。請看下面的一組例子:
篩選用戶選擇的實體:
2 strcpy(sbuf1,”TEXT”);
3 eb1.resval.rstring=sbuf1;//類型為TEXE
4 eb1.rbnext=NULL;
5
6 //讓用戶生成選擇集,但該選擇集中只能有TEXT實體
7 acedSSGet(NULL,NULL,NULL,&eb1,ssname1);
篩選前一個選擇集:
2 strcpy(sbuf1,”LINE”);
3 eb1.resval.rsting=sbuf1;//類型為LINE.
4 Eb1.rbnext=NULL;
5 //選擇在上一個選擇集中符合條件的實體
6 acedSSGet(“P”,NULL,NULL,&eb1,ssname1);
在選擇窗口內篩選實體:
2 strcpy(sbuf1,”FLOOR8”);
3 eb1.resval.rstring=sbuf1;//層名
4 eb1.rbnext=NULL;
5 //選擇在窗口內並在FLOOR8層上的實體
6 acedSSGet("W", pt1, pt2, &eb1, ssname1);
注意:某些組碼在不同的實體里有不同的含義,並且不是所有的組碼都存在於所有的實體內。如果在篩選程序中指定一個特定的組碼,不包含該組碼的實體將被排除在acedSSGet()所返回的選擇集之外。
篩選表中的通配符
篩選表中指定的符號可以包括通配符。由函數acedSSGet()織別的通配符與函數acutWcMatch()織別的通配符完全一樣。
例如,下面的程序代碼可以檢索一個名為K2的匿名塊:
2 strcpy(sbuf1,”*K2”);
3 eb2.resval.rstring=sbuf1;//匿名塊名
4 eb2.rbnext=NULL;
5 //選擇匿名塊*K2的塊插入引用
6 acedSSGet(“X”,NULL,NULL,&eb2,ssname1);
篩選擴展數據
擴展數據是字符串、數據、三維點、距離、層名,或者是其他附加在對象上得數據,特別是由外部應用程序附加到對象上得數據。
擴展數據大小為16KB。
通過指定,我們可以為一個特殊的應用程序使用-3組碼在篩選表中指定擴展數據來檢索擴展數據。例如:,函數acedSSGet()返回一個以指定名字注冊的帶擴展數據的實體。acedSSGet()不檢索每個擴展數據項(組碼的范圍為1000—2000)。
下面程序用於選擇所有帶有擴展數據的圓(Circle),應用程序為這些擴展數據注冊的一個標志符(ID)為“APPNAME”。
2 strcpy(sbuf1,”CIRCLE”);
3 eb1.resval.rstring=sbuf1;//實體為CIRCLE
4 eb1.rbnext=&eb2;
5 eb2.restype=-3;//擴展數據
6 eb2.rbnext=&eb3;
7 eb3.restype=1001;
8 strcpy(sbuf2,”APPNAME”);
9 eb3.resval.rstring=sbuf2;//APPNAME應用程序
10 eb3.rbnext=NULL;
11 //選擇注冊到APPNAME應用程序中的圓的擴展數據
12 acedSSGet(“X”,NULL,NULL,&eb1,ssname1);
如果不止一個應用程序名包含在表中,則acedSSGet()在選擇集中所包含實體,必須對所有指定的應用程序都有擴展數據。比如,下面的程序選擇帶有注冊到“APP1”和“APP2”中的擴展數據的圓。
2 strcpy(sbuf1,”CIRCLE”);
3 eb1.resval.rstring=sbuf1;//圓
4 eb1.rbnext=&eb2;
5
6 eb2.restype=-3;//擴展數據
7 eb2.rbnext=&eb3;
8 eb3.restype=1001;
9 strcpy(sbuf2,”APP1”);
10 eb2.resval.restring=sbuf2;//應用程序APP1
11 eb2.rbnext=&eb4;
12 eb4.restype=1001;//擴展數據
13 strcpy(sbuf3,”APP2”);
14 eb4.resval.rstring=sbuf3;//應用程序APP2
15 eb4.rbnext=NULL;
16 //選擇注冊應用程序APP1和APP2的圓擴展數據
17 acedSSGet(“X”,NULL,NULL,&eb1,ssname1);
下面的程序與上面的作用相同。
2 strcpy(sbuf1,”CIRCLE”);
3 eb1.resval.rstring=sbuf1;
4 eb1.rbnext=&eb2;
5
6 eb2.restype=-3;
7 eb2.rbnext=&eb3;
8 eb3.restype=1001;
9 strcpy(sbuf2,”APP[12]”);//”APP[12]”
10 eb3.resval.rstring=sbuf2;
11 eb3.rbnext=NULL;
12 //選擇注冊到APP1和APP2的圓的擴展數據
13 acedSSGet(“X”,NULL,NULL,&eb1,ssname1);
關系檢測
除非用戶另外指定,在一個篩選表中的每一項與實體之間,有一個隱含的等量(equals)檢測,對於數字量(整數、實數值、點和向量),通過在篩選表中包括關系操作符,用戶可指定另外一些關系,關系操作符當做一個特殊的組(即-4組)傳遞,其值是一個在篩選表中將被應用於下一組檢測的字符串。
下面的程序可以挑選半徑大於等於2。0的圓:
2 eb3.resval.rreal=2.0;
3 eb3.rbnext=NULL;
4
5 eb2.restype=-4;//篩選操作
6 strcpy(sbuf1,”>=”);
7 eb2.resval.rstring=&eb3;
8
9 eb1.restype=0;//實體類型
10 strcpy(sbuf2,”CIRCLE”);
11 eb1.resval.rstring=sbuf2;//圓
12 eb1.rbnext=&eb2;
13
14 //選擇半徑大於等於2。0的圓
15 acedSSGet(“X”,NULL,NULL,&eb1,ssname1);
acedssget F 方式
ads_point p1;
ads_point p2;
acedGetPoint(NULL, _T("\n插入第一點"), p1);
acedGetPoint(p1, _T("\n插入第二點"), p2);
//通過亮點來獲取選中實體
ads_name ssName;
resbuf *pRb = acutBuildList(RTPOINT, p1, RTPOINT, p2, 0);
acedSSGet(_T("F"),pRb, NULL, NULL, ssName);
acutRelRb(pRb);
//遍歷選擇集
long len = 0;
acedSSLength(ssName, &len);
for (long index = 0; index < len;index++)
{
ads_name ent;
AcDbObjectId pId;
acedSSName(ssName, index, ent);
acdbGetObjectId(pId, ent);
if (!pId.isValid())
{
continue;
}
pidArr.append(pId);
}
acedSSFree(ssName);
Arx二次開發“選擇集”
展開
一、本節課程
Arx二次開發“選擇集”
二、本節要講解的知識點
1、選擇集的創建和刪除。
2、選擇集中對象的增加和刪除。
3、對象選擇的方法。
4、選擇集過濾器的使用。
三、具體內容
1、選擇集的創建和刪除
選擇集是AUTOCAD中當前圖形中的一組實體,通過圖元名進行引用,就是一個ads_name變量。創建選擇集可以使用acedSSAdd、acedSSGet函數。
acedSSGet函數提供了絕大多數創建選擇集的方法。
(1)提示用戶選擇實體
(2)使用PICKFIRST選擇集(在未執行命令時用戶已經選擇的圖形集合,也就是AUTOCAD中的先選擇,再輸入命令)或者交叉Crossing、多邊形交叉polygon crossing、柵欄fence、最后一個last、前一個previous、窗口window、多邊形窗口window polygon等方式,也可以指定一個點或者一系列點來明確的限定所要選擇的實體。
(3)指定選擇實體所要滿足的一系列屬性和條件來過濾當前數據庫,可以和前面的選擇方式配合使用。
在程序結束之前需要使用acedSSFree函數釋放選擇集的內存空間。
static void YunyouMyGroupCreateSSet()//1、選擇集的創建:全部選擇
{
ads_name sset;
acedSSGet(TEXT("A"),NULL,NULL,NULL,sset);
long length;
acedSSLength(sset,&length);
acutPrintf(TEXT("\n實體數:%d"),length);
acedSSFree(sset);
}
命令: CREATESSET
實體數:7
2、選擇集中元素的增加和刪除
AcedSSAdd、acedSSDel用戶已經獲得了對象引用的情況下,來添加或者刪除選擇集中的元素。
int acedSSAdd(
const ads_name ename, //將要添加到選擇集中的實體的圖元名
const ads_name sname, //指定選擇集的圖元名
ads_name result//返回了被創建的選擇集或者是被更新的選擇集
);
(1)ename sname 都是NULL ,創建了一個選擇集 沒有包含任何成員。
(2)ename 是一個有效實體,sname 是空指針,則創建了包含一個成員ename
的選擇集。
(3)Ename和sname 都是有效的實體、選擇集,那么返回的結果實際上就是在sname的基礎上去擴充成員。
int acedSSDel(
const ads_name ename,
const ads_name ss
);
就是表示從選擇集ss中刪除ename實體。
3、對象選擇的方法
int acedSSGet(
const ACHAR * str,
const void * pt1,
const void * pt2,
const struct resbuf * filter,
ads_name ss
);
其中str描述了創建選擇集的方法,可以是用的參數值見下表,pt1,pt2為相關創建方式提供了點參數,如果不需要指定可以輸入NULL作為參數值;filter用於指定創建選擇集的過濾條件;ss則指定了要操作的選擇集的圖元名。
acedSSGet函數的選擇模式選項
值(選擇模式)str
說明
NULL
單點選擇(如果指定了pt1),提示用戶選擇( pt1: NULL)
#
非幾何選擇(ALL\LAST\Previous)
:$
僅提供提示
.
用戶選擇模式
:?
其他回調選擇模式
A
全部選擇
B
框選模式
C
窗交模式
CP
圈交模式
:D
允許復制選擇模式
:E
小孔中的所有實體
F
欄選模式
G
選擇編組
I
獲取當前圖形中已經選擇的實體(就是PICKFIRST)
:K
鍵盤回調選擇模式
L
選擇最后一次創建的可見的實體
M
指定多次選擇而不高亮顯示對象,從而加寬復雜對象的選擇過程
P
選擇最近創建的選擇集
:S
單一對象選擇模式
W
窗口選擇模式
WP
圈圍選擇模式
X
過濾選擇模式
實例:我們使用了多種不同的模式來創建選擇集。
static void YunyouMyGroupSelectEnt()//各種方式選擇實體
{
ads_point pt1,pt2,pt3,pt4;
struct resbuf *pointlist;
ads_name ssname;
pt1[X]=pt1[Y]=pt1[Z]=0.0;
pt2[X]=pt2[Y]=5.0;
pt2[Z]=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);
//選擇通過點PT2的所有實體
acedSSGet(NULL,pt2,NULL,NULL,ssname);
//選擇通過點PT1 和PT2的組成的窗體內的所有的實體
acedSSGet(TEXT("W"),pt1,pt2,NULL,ssname);
//選擇被指定的多邊形包圍的所有實體
pt3[X]=10.0;pt3[Y]=5.0;pt3[Z]=0;
pt4[X]=5.0;pt4[Y]=pt4[Z]=0;
pointlist=acutBuildList(RTPOINT,pt1,RTPOINT,pt2,RTPOINT,pt3,RTPOINT,pt4,RTNONE);
acedSSGet(TEXT("WP"),pointlist,NULL,NULL,ssname);
//由角點PT1 PT2組成的區域相交的所有實體
acedSSGet(TEXT("C'"),pt1,pt2,NULL,ssname);
//選擇與指定多邊形區域相交的所有實體
acedSSGet(TEXT("CP"),pointlist,NULL,NULL,ssname);
acutRelRb(pointlist);
//選擇與選擇欄相交的所有對象
pt4[Y]=15.0;pt4[Z]=0;
pointlist=acutBuildList(RTPOINT,pt1,RTPOINT,pt2,RTPOINT,pt3,RTPOINT,pt4,RTNONE);
acedSSGet(TEXT("F"),pointlist,NULL,NULL,ssname);
acutRelRb(pointlist);
acedSSFree(ssname);
}
4、使用選擇集過濾器
四、總結
1、int acedSSGet(
const ACHAR * str,
const void * pt1,
const void * pt2,
const struct resbuf * filter,
ads_name ss
);
2、acedSSGet函數的選擇模式選項
3、int acedSSAdd(
const ads_name ename, //將要添加到選擇集中的實體的圖元名
const ads_name sname, //指定選擇集的圖元名
ads_name result//返回了被創建的選擇集或者是被更新的選擇集
);
int acedSSDel(
const ads_name ename,
const ads_name ss
);
4、選擇集過濾器
5、每次使用完acedSSAdd acedSSFree我們都要記得使用acedSSFree函數來釋放內存空間。
OBJECT ARX 修改選中實體的顏色 選擇集的使用
////修改選中實體的顏色
static void TESTchangecolorcmd(){
ads_name ssname;
////選擇多個實體,傳遞NULL,讓用戶自己來選
acedSSGet(NULL,NULL,NULL,NULL,ssname);
long len;
acedSSLength(ssname,&len);
CString ss;
ss.Format(_T("已選中%d個實體"),len);
acutPrintf(ss);
ads_name entname;
AcDbObjectId id;
AcDbEntity* ent = NULL;
CString strName;
int nNewColor;
////彈出顏色選擇對話框
if(acedSetColorDialog(nNewColor,Adesk::kFalse,256) != IDOK){
return;
}
for(int i=0;i<len;i++)
{
if(acedSSName(ssname, i, entname) == RTNORM)
{
////根據名稱得到ID
acdbGetObjectId(id,entname);
////以寫模式,根據ID索引到對象,並打開ENTITY
acdbOpenObject(ent,id,AcDb::OpenMode::kForWrite);
strName.Format(_T("%d"),ent->colorIndex());
acutPrintf(_T("\n"));
acutPrintf(strName);
/////如果只限制直線
/*if(ent->isKindOf(AcDbLine::desc())){
acutPrintf(_T("\nfind line"));
ent->setColorIndex(nNewColor);
ent->close();
}*/
ent->setColorIndex(nNewColor);
ent->close();
}
}
acedSSFree(ssname);
}
ObjectArx選擇集的遍歷
ads_name ssname;
long len; long i=0;
//選擇所有對象
if(RTNORM == acedSSGet(_ACRX_T("A"),NULL, NULL, NULL, ssname))
{
acedSSLength(ssname,&len)
//遍歷選擇集
for(i=0; i<len; i++)
{
ads_name ent;
acedSSName(ssname, i, ent);
AcDbObjectId eId;
acdbGetObjectId(eId, ent);
//其它操作
....
}
//釋放選擇集
acedSSFree(ssname);
ObjectARX獲取實體個數
ads_name entSet;
acedSSGet(_T("A"), NULL, NULL, NULL, entSet);
long llen;
acedSSLength(entSet, &llen);
acutPrintf(_T("實體為:%d"),llen);
條件篩選
條件操作符也可由-4組指定,但它們必須是配對的。下面的的程序用來挑選半徑為1。0的圓,並且在“ABC”層上的所有直線:
2 acedSSGet("X", NULL, NULL, prb, ssname1);
條件操作符不是大小寫敏感的,可以使用小寫形式。
用於檢測擴展數據的條件表達式只能包含-3組。為了選擇帶有寄存於“APP1”和“APP2”其中之一的擴展數據的所有圓,可以用以下程序來實現:
2 acedSSGet("X", NULL, NULL, prb, ssname1);