大多数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("
插入第一点"), p1);
acedGetPoint(p1, _T("
插入第二点"), 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(" 实体数:%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)
#
非几何选择(ALLLASTPrevious)
:$
仅提供提示
.
用户选择模式
:?
其他回调选择模式
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("
"));
acutPrintf(strName);
/////如果只限制直线
/*if(ent->isKindOf(AcDbLine::desc())){
acutPrintf(_T("
find 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);