明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 6065|回复: 6

ARX选择集的应用[连载]

[复制链接]
发表于 2003-11-29 00:21 | 显示全部楼层 |阅读模式
大多数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()的例子:
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.0;
//如果有的话,获取当前RICKFIRST选择集,没有则提供用户选择一个
acedSSGet(NULL,NULL,NULL,NULL,ssname);
//如果有的话,获取当前RICKFIRST选择集
acedSSGet(“I”,NULL,NULL,NULL,ssname);
//使用最近使用过的选择集
acedSSGet(“P”,NULL,NULL,NULL,ssname);
//选择最后加入到数据库中的对象
acedSSGet(“L”,NULL,NULL,NULL,ssname);
//选择通过点(5,5)的实体
acedSSGet(NULL,pt2,NULL,NULL,ssname);
//选择从点(0,0)到点(5,5)的窗口中的实体
acedSSGet(“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(“WP”,pointlist,NULL,NULL,ssname);

//选择选择从点(0,0)到点(5,5)的窗口内交叉的实体
acedSSGet(“C”,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(“F”,pointlist,NULL,NULL,ssname);
acutRelRb(pointlist);

    对acedSSGet()的补充函数是acedSSFree(),它能在应用程序用完选择集后释放选择集。选择集是按名字来被使用的。对上面程序段中定义的ads_name,在这里使用为:
acedSSFree(ssname);
注意:AutoCAD不能同时打开多于128个选择集,包括运行中的ObjectARX和AutoLISP应用程序打开选择集的总和。在不同的系统有可能有所不同。如果超过上限,AutoCAD拒绝创建选择集。因此在不用选择集时,应尽快用acedSSFree()释放。

下一贴是《选择集筛选》

评分

参与人数 1威望 +1 金钱 +3 贡献 +2 激情 +3 收起 理由
leeyeafu + 1 + 3 + 2 + 3 【好评】好文章

查看全部评分

发表于 2003-11-29 17:19 | 显示全部楼层
":$"这个怎么用?
 楼主| 发表于 2003-11-29 19:00 | 显示全部楼层
选择集筛选表
当acedSSGet()函数的entmask参数明确记录了实体的范围值列表时,acedSSGet()扫描被选择的实体,同时建立一个包含主实体名的选择集,这些实体与筛选条件相匹配。比如,使用这种方法,用户可以得到一个给定的选择集,这个选择集包括给定的层、类型、颜色的所有实体。
筛选表可以与任何的选择项联合使用。如果用“X”选择方式,意味着建立一个仅使用筛选表的选择集。在AutoCAD以前的版本中,如果用“X”选项,acedSSGet()将扫描全部图形数据库。
注意:要是仅仅筛选表指定为“X”,而参数entmask是NULLL,则acedSSGet()选择所有在数据库中的实体。
参数entmask必须是一个结果缓冲区表。每一个缓冲区指定一个检查参数和匹配的值;缓冲区的restype段是一个DXF组码,它指定要查询的参数的种类,而缓冲区的restype域指定要匹配的值。下面是相应的例子:
struct resbuf eb1,eb2,eb3;
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指定了多个参数,那么只有匹配所有指定条件的实体才能被包含在选择集里。就象下面的例子:
eb2.restype=62;//实体颜色
eb3.resval.rint=1;//红色
eb3.rbnext=NULL;
eb1.rbnext=&eb2;//增加另外两个条件
eb2.rbnext=&eb3;//建立链表
//检索在图层FLOOR3层上所有红色的圆
acedSSGet(“X”,NULL,NULL,&eb1,ssname1);
除非表中包括关系和条件操作符,否则实体的所有域都要被测试。
如果在数据库中没有实体与指定的筛选条件匹配,函数acedSSGet()将返回RTERROR。
前面关于acedSSGet()的例子用的是“X”选项,它扫描整个图形数据库;如果筛选表与其他选项(如用户选择、窗口选择等)联合使用,筛选条件只能在被选中的实体上起作用。请看下面的一组例子:
筛选用户选择的实体:
eb1.restype=0;//实体类型组
strcpy(sbuf1,”TEXT”);
eb1.resval.rstring=sbuf1;//类型为TEXE
eb1.rbnext=NULL;

//让用户生成选择集,但该选择集中只能有TEXT实体
acedSSGet(NULL,NULL,NULL,&eb1,ssname1);
筛选前一个选择集:
eb1.restype=0;//实体类型组
strcpy(sbuf1,”LINE”);
eb1.resval.rsting=sbuf1;//类型为LINE.
Eb1.rbnext=NULL;
//选择在上一个选择集中符合条件的实体
acedSSGet(“P”,NULL,NULL,&eb1,ssname1);
在选择窗口内筛选实体:
eb1.restype=8;//层
strcpy(sbuf1,”FLOOR8”);
eb1.resval.rstring=sbuf1;//层名
eb1.rbnext=NULL;
//选择在窗口内并在FLOOR8层上的实体
注意:某些组码在不同的实体里有不同的含义,并且不是所有的组码都存在于所有的实体内。如果在筛选程序中指定一个特定的组码,不包含该组码的实体将被排除在acedSSGet()所返回的选择集之外。
筛选表中的通配符
筛选表中指定的符号可以包括通配符。由函数acedSSGet()织别的通配符与函数acutWcMatch()织别的通配符完全一样。
例如,下面的程序代码可以检索一个名为K2的匿名块:
eb2.restype=2;//块名
strcpy(sbuf1,”*K2”);
eb2.resval.rstring=sbuf1;//匿名块名
eb2.rbnext=NULL;
//选择匿名块*K2的块插入引用
acedSSGet(“X”,NULL,NULL,&eb2,ssname1);



下一贴是筛选扩展数据、关系检测
 楼主| 发表于 2003-11-29 22:11 | 显示全部楼层
筛选扩展数据
扩展数据是字符串、数据、三维点、距离、层名,或者是其他附加在对象上得数据,特别是由外部应用程序附加到对象上得数据。
扩展数据大小为16KB。
通过指定,我们可以为一个特殊的应用程序使用-3组码在筛选表中指定扩展数据来检索扩展数据。例如:,函数acedSSGet()返回一个以指定名字注册的带扩展数据的实体。acedSSGet()不检索每个扩展数据项(组码的范围为1000—2000)。
下面程序用于选择所有带有扩展数据的圆(Circle),应用程序为这些扩展数据注册的一个标志符(ID)为“APPNAME”。
eb1.restype=0;//实体类型
strcpy(sbuf1,”CIRCLE”);
eb1.resval.rstring=sbuf1;//实体为CIRCLE
eb1.rbnext=&eb2;
eb2.restype=-3;//扩展数据
eb2.rbnext=&eb3;
eb3.restype=1001;
strcpy(sbuf2,”APPNAME”);
eb3.resval.rstring=sbuf2;//APPNAME应用程序
eb3.rbnext=NULL;
//选择注册到APPNAME应用程序中的圆的扩展数据
acedSSGet(“X”,NULL,NULL,&eb1,ssname1);
如果不止一个应用程序名包含在表中,则acedSSGet()在选择集中所包含实体,必须对所有指定的应用程序都有扩展数据。比如,下面的程序选择带有注册到“APP1”和“APP2”中的扩展数据的圆。
eb1.restype=0;//实体类型
strcpy(sbuf1,”CIRCLE”);
eb1.resval.rstring=sbuf1;//圆
eb1.rbnext=&eb2;

eb2.restype=-3;//扩展数据
eb2.rbnext=&eb3;
eb3.restype=1001;
strcpy(sbuf2,”APP1”);
eb2.resval.restring=sbuf2;//应用程序APP1
eb2.rbnext=&eb4;
eb4.restype=1001;//扩展数据
strcpy(sbuf3,”APP2”);
eb4.resval.rstring=sbuf3;//应用程序APP2
eb4.rbnext=NULL;
//选择注册应用程序APP1和APP2的圆扩展数据
acedSSGet(“X”,NULL,NULL,&eb1,ssname1);
我们可以指定通配符表示的应用程序名,也就是说,可以一次性寻找到多个应用程序的数据。下面的程序选择所有的圆,带有注册“APP1”或“APP2”(或两者都包括)之中的扩展数据:
eb1.restype=0;//实体类型
strcpy(sbuf1,”CIRCLE”);
eb1.resval.rstring=sbuf1;//圆
eb1.rbnext=&eb2;

eb2.restype=-3;//扩展数据
eb2.rbnext=&eb3;
eb3.restype=1001;//扩展数据
strcpy(sbuf2,”APP1,APP2”);
eb3.resval.rstring=sbuf2;//应用程序名
eb3.rbnext=NULL;
//选择注册到APP1和APP2的圆的扩展数据
acedSSGet(“X”,NULL,NULL,&eb1,ssname1);

下面的程序与上面的作用相同。
eb1.restype=0;
strcpy(sbuf1,”CIRCLE”);
eb1.resval.rstring=sbuf1;
eb1.rbnext=&eb2;

eb2.restype=-3;
eb2.rbnext=&eb3;
eb3.restype=1001;
strcpy(sbuf2,”APP[12]”);
eb3.resval.rstring=sbuf2;
eb3.rbnext=NULL;
//选择注册到APP1和APP2的圆的扩展数据
acedSSGet(“X”,NULL,NULL,&eb1,ssname1);


关系检测
除非用户另外指定,在一个筛选表中的每一项与实体之间,有一个隐含的等量(equals)检测,对于数字量(整数、实数值、点和向量),通过在筛选表中包括关系操作符,用户可指定另外一些关系,关系操作符当做一个特殊的组(即-4组)传递,其值是一个在筛选表中将被应用于下一组检测的字符串。
下面的程序可以挑选半径大于等于2。0的圆:
eb3.restype=40;//半径
eb3.resval.rreal=2.0;
eb3.rbnext=NULL;

eb2.restype=-4;//筛选操作
strcpy(sbuf1,”>=”);
eb2.resval.rstring=&eb3;

eb1.restype=0;//实体类型
strcpy(sbuf2,”CIRCLE”);
eb1.resval.rstring=sbuf2;//圆
eb1.rbnext=&eb2;

//选择半径大于等于2。0的圆
acedSSGet(“X”,NULL,NULL,&eb1,ssname1);

下一贴是条件筛选和选择集的管理
 楼主| 发表于 2003-11-30 19:35 | 显示全部楼层
条件筛选
前一贴描述的关系操作符是二进制操作符,我们可以通过建立使用条件操作符的嵌套逻辑表达式来检测不同的组。条件操作符也可由-4组指定,但它们必须是配对的。
下面的的程序用来挑选半径为1。0的圆,并且在“ABC”层上的所有直线:
eb1=acutBuildList(-4,”<or”,-4,”<and”,RTDXF0,”CIRCLE”,40,1.0,-4,”and>”-4,”<and”,RTDXF0,”LINE”,8,”ABC”,-4,”AND>”-4,”or>”);
acedSSGet(“X”,NULL,NULL,&eb1,ssname1);
条件操作符不是大小写敏感的,可以使用小写形式。用于检测扩展数据的条件表达式只能包含-3组。
为了选择带有寄存于“APP1”和“APP2”其中之一的扩展数据的所有圆,可以用以下程序来实现:
eb1=acutBuildList(-4,”<xor”,-3,”APP1”,-3,”APP2”,-4,”xor>”,0);
acedSSGet(“X”,NULL,NULL,&eb1,ssname1);
选择集的管理
建立好选择集后,就可以调用函数acedSSAdd()和acedSSDel()来将实体放进选择集或从选择集中删去,类似于当AutoCAD提示用户选择对象(Select objects)或删除对象(Remove objects)时的Add和Remove选项一样。
注意:如下面的例子所示,函数acedSSAdd()也可以用于建立一个新的选择集。只有其返回RTNORM时,acedSSGet()和acedSSAdd()才建立一个新集。
下面的程序段建立一个包括当前图的第一个和最后一个实体的选择集:
ads_name fname lname;//实体名
ads_name ourset;//选择集名
//获取图中第一个实体
if(acdbEntNext(NULL,fname)!=RTNORM){
  acdbFail(“图中没有实体\n”);
  return BAD;
}
//创建一个包含第一实体的选择集
if(acedSSAdd(fname,NULL,ourset)!=RTNORM){
  acdbFail(“不能创建选择集\n”);
  return BAD;
}
//获取图形中的最后一个实体
if(acdbEntLast(lname)!=RTNORM){
  acdbFail(“图中没有实体\n”);
  return BAD;
}
//将最后一个实体添加到同一个选择集中
if(acedSSAdd(lname,ourset,ourset)!=RTNORM){
  acdbFail(“不能将实体添加到选择集中去!\n”);
  return BAD;
}
即使在数据库中只有一个实体,上面的程序也能正确运行。如果将一个已在选择集中的实体名字传递给函数acedSSAdd(),该函数就忽略选择实体请求,而且也不会报告错误信息。
上面的程序还表明,函数acedSSAdd()的第二个和第三个参数可以以同一个选择集的名字来传递,如果调用成功,由两个参数命名的这个选择集在函数acedSSAdd()返回后,就会包含一个附加的成员。
下面调用将删除在前一个实例中用于建立选择集的实体:
acedSSDel(fname,ourset);
如果图中不只有一个实体(即fname和lname不相等),选择集ourset现在只包含图中的最后一个实体_lname。
函数acedSSLength()返回在选择集中的实体个数,函数acedSSMemb()检测某个特殊的实体是否是一个选择集的一员。最后,函数acedSSName()返回一个选择集包含的某个特定实体名字,即该选择集的索引号。
下面的程序列举几个对acedSSName()调用:
ads_name sset,ent1,ent4,lastent;
long ilast;
//通过提示创建一个选择集
acedSSGet(NULL,NULL,NULL,sset);
//获取在sset中的第一个实体
if(acedSSName(sset,0L,ent1)!=RTNORM)
return BAD;

//获取在sset中的第四个实体
if(acedSSName(sset,3L,ent4)!=RTNORM){
   acdbFail(“至少要选择四个实体!\n”);
return BAD;
}

//寻找在sset中最后一个实体的索引号
if(acedSSLength(sset,3L,&ilast)!=RTNORM)
return BAD;
//获取在sset中最后一个实体的实体名
if(acedSSName(sset,3L,ilast-1,lastent)!=RTNORM)
return BAD;
发表于 2011-11-10 14:07 | 显示全部楼层
学习了!
发表于 2015-5-3 22:45 | 显示全部楼层
受用
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2024-4-26 11:21 , Processed in 0.458051 second(s), 27 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表