|
在 ObjectARX 开发过程中,经常需要用户和 AutoCAD 之间进行交互操作,除了前面介绍的acedGetXX 系列函数之外,选择集是 AutoCAD 和用户交互操作的重要手段。与 acedEntSel 函数不同,acedEntSel 函数用于提示用户选择一个实体,选择集允许用户同时选择多个图形对象,同时提供了丰富的手段来选择符合特定条件的实体。
本篇的实例详细介绍了选择集的使用,可以分为以下几个方面:
选择集的创建和删除。
选择集中对象的增加和删除。
对象选择的方法。
选择集过滤器的使用。
2. 思路
(1) 选择集的创建和删除
选择集是 AutoCAD 当前图形中的一组实体,通过图元名进行引用,也就是一个 ads_name 变量。创建选择集可以使用 acedSSAdd 和 acedSSGet 函数,其中 acedSSGet 函数提供了绝大 多数创建选择集的方法:
提示用户选择实体。
使用 PICKFIRST 选择集(在未执行命令时用户已经选择的图形集合,也就是 AutoCAD 中的先选择、再输入命令)或者交叉( Crossing )、多变性交叉( Crossing Polygon)、栅栏( Fence )、最后一个( Last )、前一个( Previous )、窗口( Window )、 多边形窗口(Window Polygon )等方式,也可以指定一个点或者一系列点来明确地 限定所要选择的实体。
指定选择实体所要满足的一系列属性和条件来过滤当前数据库,可以和前面的选择
方式配合使用。
无论使用 acedSSAdd 还是 acedSSGet 函数,都需要在程序结束之前使用 acedSSFree 函数
释放选择集的内存空间。
(2) 选择集中元素的增加和删除
这里所说的元素增加和删除,仅指在已经获得对象引用的情况下,使用 acedSSAdd 和 acedSSDel 函数对选择集进行元素的增加和删除。
//acedSSAdd 函数定义为:
int acedSSAdd(const ads_name ename, //ename 指定要添加到选择集的实体的图元名
const ads_name sname, //sname 指定选择集的图元名
ads_name result); //result返回被创建或者更新的选择集
// 根据 ename 和 sname 的不同取值,acedSSAdd 有以下几种可能的执行结果:
如果 ename 和 sname 都是空指针,则创建一个未包含任何成员的选择集。
如果 ename 指向一个有效的实体,但 sname 是空指针,则创建一个选择集,该选择集仅包含一个成员 ename。
如果 ename 指向有效的实体,且 sname 指向有效的选择集,则将 ename 所指向的实体添加到 sname 所指向的选择集中。
// acedSSDel 函数定义为:
int acedSSDel(const ads_name ename, //ename 指定了要从选择集中删除的实体
const ads_name ss); //ss 指定了所要操作的选择集
(3) 对象选择的方法
所谓对象选择的方法,就是以某种方式从图形窗口中获得满足某些条件的图形对象。这里要介绍的是使用 acedSSGet 函数所实现的选择对象的方法,该函数被定义为:
/*
//所谓对象选择的方法,就是以某种方式从图形窗口中获得满足某些条件的图形对象,用acedSSGet
int acedSSGet (const char *str, //str 参数描述了创建选择集的方法,可以使用的参数值参见下表
const void *pt1, //pt1 和 pt2 为相关的创建方式提供了点参数,
const void *pt2, //如果不需要指定可以输入 NULL 作为参数值;
const struct resbuf *entmask, //entmask 用于指定选择实体的过滤条件
ads_name ss); //ss 则指定了要操作的选择集的图元名
*/
4. 使用选择集过滤器
在使用各种选择对象的方法时,可以使用过滤器来限定选择的对象。例如,可以指定仅选择图层 0 上的直线对象,也可以指定仅选择蓝色的半径大于 30 的圆,等等。
如果仅使用一个过滤条件,可以使用下面的代码:
//过滤器例子(一个过滤条件)
struct resbuf rb;
char sbuf[10]; // 存储字符串的缓冲区
ads_name ssname;
rb.restype = 0; // 实体名
strcpy(sbuf, "CIRCLE");
rb.resval.rstring = sbuf;
rb.rbnext = NULL; // 不需要设置其他的属性
// 选择图形中所有的圆
acedSSGet("X", NULL, NULL, &rb, ssname);
acedSSFree(ssname);
//上面的代码中虽然使用了结果缓冲区,但是仅是在栈上声明,由编译器自动管理它所使
//用的内存空间,不需要使用 acutRelRb 函数来手工销毁它。
如果要指定多个过滤条件,可以使用 acutBuildList 函数来构造结果缓冲区。如果要选择当前图形窗口中位于 0 层上的所有直线,就可以使用下面的方法:
//过滤器例子(多个过滤条件)
struct resbuf *rb; // 结果缓冲区链表
ads_name ssname;
rb = acutBuildList(RTDXF0, "LINE", // 实体类型
8, "0", // 图层
RTNONE);
// 选择图形中位于0层上的所有直线
acedSSGet("X", NULL, NULL, rb, ssname);
acutRelRb(rb);
acedSSFree(ssname);
//在标准的 DXF 组码中,0 用于表示实体类型,但是在 acutBuildList 函数中 0 也可以用于
//表示结束链表,因此用 RTDXF0 来代替 0。
在标准的 DXF 组码中, 0 用于表示实体类型,但是在 acutBuildList 函数中 0 也可以用于表示结束链表,因此用 RTDXF0 来代替 0 。
过滤器列表由成对的参数组成。第一个参数标识过滤器的类型(例如对象),第二个参数指定要过滤的值(例如圆)。
过滤器类型是指定使用哪种过滤器的 DXF 组码,下面列出了一些最常用的过滤器类型:
0 :对象类型(字符串),例如“ Line ”、“ Arc ”等。
1 :图元的主文字值(字符串),例如文字、属性的字符串内容。
2 :对象名(字符串),例如属性标记、块名等。
8:图层名(字符串)。
10 :主要点(直线或文字图元的起点、圆的圆心等),用三个实数的数组来表示三维点。
60 :对象可见性(整数), 0 表示可见, 1 表示不可见。
62 :颜色编号(整数),可取 0 ~ 256 的整数值,其中 0 表示 ByBlock , 256 表示 ByLayer 。
67 :模型/图纸空间标识符(整数), 0 (默认)表示在模型空间, 1 表示在图纸空间。
1000 :扩展数据中的 ASCII 字符串,最多可以包含 255 个字节。
1001 :扩展数据的注册应用程序名,最多可以包含 31 个字节的 ASCII 字符串。
1003 :扩展数据图层名。
值得一提的是,在大部分选择模式中均可以使用选择集过滤器,下面的代码提示用户选
择实体的同时使用了选择集过滤器:
acedSSGet(NULL, NULL, NULL, rb, ssname);
3. 步骤
(1) 选择集的创建和删除
//选择集(Select set)的创建和删除
static void CreateSSet(); //选择集(Select set)的创建和删除
//选择集(Select set)的创建和删除
void CUserInteraction::CreateSSet()
{
ads_name sset; // 选择集名称
// 选择图形数据库中所有的实体
acedSSGet(_T("A"), NULL, NULL, NULL, sset);
// 进行其他操作
acedSSFree(sset);
}
(2) 对象选择的方法
A. 创建一个函数 SelectEnt ,使用多种不同的模式创建选择集
下边演示了 acedSSGet 函数的几个典型应用。使用 CP 和 WP 选 择模式时,需要用 acutBuildList 函数创建一个包含多边形顶点的结果缓冲区链表, acedSSGet 函数会自动闭合顶点列表,因此不必创建一个首尾顶点相同的结果缓冲区链表。
//选择对象
static void SelectEnt(); //选择对象
//选择对象,演示 acedSSGet 函数的几个典型应用
//使用 CP 和 WP 选择模式时,需要用 acutBuildList 函数创建一个包含多边形顶点的结果缓冲区链表,
//acedSSGet 函数会自动闭合顶点列表,因此不必创建一个首尾顶点相同的结果缓冲区链表。
void CUserInteraction::SelectEnt()
{
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;
// 如果已经选择到了实体,就获得当前的PICKFIRST选择集
// 否则提示用户选择实体
acedSSGet(NULL, NULL, NULL, NULL, ssname);
// 如果存在,就获得当前的PickFirst选择集
acedSSGet(_T("I"), NULL, NULL, NULL, ssname);
// 选择最近创建的选择集
acedSSGet(_T("P"), NULL, NULL, NULL, ssname);
// 选择最后一次创建的可见实体
acedSSGet(_T("L"), NULL, NULL, NULL, ssname);
// 选择通过点(5,5)的所有实体
acedSSGet(NULL, pt2, NULL, NULL, ssname);
// 选择位于角点(0,0)和(5,5)组成的窗口内所有的实体
acedSSGet(_T("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(_T("WP"), pointlist, NULL, NULL, ssname);
// 选择与角点(0,0)和(5,5)组成的区域相交的所有实体
acedSSGet(_T("C"), pt1, pt2, NULL, ssname);
// 选择与指定多边形区域相交的所有实体
acedSSGet(_T("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(_T("F"), pointlist, NULL, NULL, ssname);
acutRelRb(pointlist);
acedSSFree(ssname);
}
B. 1. 函数参数前面的*&表示该参数是一个指针的引用,使用指
针的引用作为参数,能够在函数内部对指针的本身的内容进行修改。
2. 首先使用 segType 成员函数来判断多段线某一段的类型,
如果是直线段就创建一个AcGeLineSeg2d 对象,
如果是圆弧段则创建一个 AcGeCircArc2d 对象,并将创建的几何类对象添加到一个对象指针数组中。
3. 如果多段线闭合,并且最后的一段是圆弧段,那么还要将终点和起点之间的那一段曲线添加到最终的几何曲线中,
这样才能保证多段线与对应的几何类曲线形状完全一致。
如果最后一段是直线段,则不需要添加,其理由将在下一个函数的分析中说明。
4. pArc->setAngles(arc.startAng(), arc.endAng() - (arc.endAng() - arc.startAng()) / 100);
这句代码将会使最后一段曲线的终点发生一个小的偏移(偏移后仍在原来的圆弧上,但
不与原来的终点重合),其原因同样会在下一个函数的分析中说明。
5. if (geCurves.length() == 1)
{
pGeCurve = (AcGeCurve2d *)geCurves[0];
}
else
{
pGeCurve = new AcGeCompositeCurve2d(geCurves);
}
如果多段线仅包含一段曲线,直接将几何曲线的指针指向新建的几何曲线对象;
否则根据对象指针数组中的元素创建一个新的复合曲线,并且为其分配相应的内存。
对应地,当多段线的段数大于 1 时,函数结束前应该用 delete 操作符释放用 new 运算符分配
所有的几何曲线的存储空间。
//根据指定的多段线创建对应的几何类曲线, pPline 指定已知的多段线,pGeCurve 参数输出创建的几何曲线
bool PolyToGeCurve(const AcDbPolyline *pPline, AcGeCurve2d *&pGeCurve);
bool CUserInteraction::PolyToGeCurve(const 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;
}
C. 选择指定多段线内部(或者与多段线构成的区域相交)的所有实体
//选择指定多段线内部(或者与多段线构成的区域相交)的所有实体。
//pPline 指定已知的多段线
//ObjectIdArray 输出选择到的所有实体的 ObjectId 数组
//selectMode 指定选择模式(可以输入“CP”或者“WP”)
//approxEps 指定构造多段线对应几何曲线时的误差。
bool SelectEntInPoly(AcDbPolyline *pPline, AcDbObjectIdArray &ObjectIdArray, const TCHAR *selectMode, double approxEps);
//pPline 指定已知的多段线
//ObjectIdArray 输出选择到的所有实体的 ObjectId 数组
//selectMode 指定选择模式(可以输入“CP”或者“WP”)
//approxEps 指定构造多段线对应几何曲线时的误差。
bool CUserInteraction::SelectEntInPoly(AcDbPolyline *pPline,
AcDbObjectIdArray &ObjectIdArray,
const TCHAR *selectMode,
double approxEps)
{
// 判断selectMode的有效性
if (_tcscmp(selectMode, _T("CP")) != 0 && _tcscmp(selectMode, _T("WP")) != 0)
{
acedAlert(_T("函数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);
}
// 创建对应的几何类曲线
CUserInteraction::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 = CUserInteraction::BuildRbFromPtArray(SamplePtArray);
// 使用acedSSGet函数创建选择集
ads_name ssName; // 选择集名称
int rt = acedSSGet(selectMode, rb, NULL, NULL, ssName);
if (rt != RTNORM)
{
acutRelRb(rb); // 释放结果缓冲区链表
return false;
}
// 将选择集中所有的对象添加到ObjectIdArray
long length;
acedSSLength(ssName, &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;
}
首先判断 selectMode 参数的有效性,清空 ObjectIdArray 的所有元素(引用类型传递的参 数,防止该参数在函数外的修改影响该函数执行的结果),然后使用 PolyToGeCurve 函数创建与指定多段线对应的几何类曲线。
此后,使用 AcGeCurve2d 类的 getSamplePoints 函数来获得多段线的样本点。为什么不直
接用数据库实体类 AcDbPolyline 来获得多段线的顶点来作为样本点呢?样本点是用于描述曲线形状的一组点,获得多段线的形状,可以使用两种方法:
等距获得样本点。输入一个固定的长度值,从起点开始,每到这个固定的长度就在曲线上取一个样本点,最后得到的样本点是等间距的。
按照弦切距的误差极限来获得样本点,这种方法可以控制样本点的精度。要根据一定的精度来获得几何类对象的样本点,
必须深入理解几何类的getSamplePoints函数
void getSamplePoints(
double fromParam, //fromParam是开始处的参数
double toParam, //toParam是结束处的参数
double approxEps, //approxEps是弦高误差
AcGePoint3dArray& pointArray, //pointArray输出曲线上位于开始参数fromParam和
AcGeDoubleArray& paramArray) const; //终止参数toParam之间的所有点的数组
// paramArray输出与数组pointArray中的点相对应的参数数组。
// 这里所说的“参数”,是一个与长度有关的值,其具体含义Autodesk并未公开。
弦高误差的含义如图 所示:
对一条多段线取样本点,能够得到类似下图所示的结果:
多段线的顶点 A 、 B 、C、 D 仍然会是样本点。从图中可以看出,样本点很好地描述了多段线的形状,而仅由顶点组成的多边形根本无法描述带有圆弧段的多段线形状。
接下来的代码根据样本点创建结果缓冲区链表,在此之前,需要确保样本点数组中首尾两点不重合,其中的原因在前面已经介绍,acedSSGet 函数会自动闭合顶点列表。创建结果缓冲区链表使用了一个自定义函数 BuildRbFromPtArray,该函数的定义将在下面的步骤中介绍。
创建选择集之后,遍历选择集,将选择到的实体添加到 ObjectId 数组中,但是有时候作为边界的多段线也被添加到选择集中,在添加 ObjectId 的时候就要将其排除。此时多段线还没有被关闭,因此使用 acdbOpenAcDbEntity 函数打开时会返回 Acad::eWasOpenForWrite,可以此作为辨别边界多段线的依据。
在函数的最后,不能忘记释放结果缓冲区链表和选择集。
D. 创建一个新的成员函数 BuildRbFromPtArray,用于根据指定的一组点创建一个结果缓冲区链表,它接受一个参数 arrPoints,该参数指定一组点,而函数返回创建的结果缓冲区链表。该函数的实现代码为:
//根据指定的一组点创建一个结果缓冲区链表
struct resbuf* BuildRbFromPtArray(const AcGePoint2dArray &arrPoints);//根据指定的一组点创建一个结果缓冲区链表
//根据指定的一组点创建一个结果缓冲区链表
struct resbuf* CUserInteraction::BuildRbFromPtArray(const AcGePoint2dArray &arrPoints)
{
struct resbuf *retRb = NULL;
int count = arrPoints.length();
if (count <= 1)
{
acedAlert(_T("函数BuildBbFromPtArray中,点数组包含元素个数不足!"));
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;
// 动态创建新的节点,并将其链接到原来的链表尾部
nextRb->rbnext = acutBuildList(RTPOINT, adsPt, RTNONE);
nextRb = nextRb->rbnext;
}
return retRb;
}
(3) 使用选择集过滤器
A. 创建一个带有通配符的过滤器, 在过滤器中使用通配符。添加函数 Filter1()
//创建一个带有通配符的过滤器, 在过滤器中使用通配符。
void Filter1();
//创建一个带有通配符的过滤器, 在过滤器中使用通配符。
void CUserInteraction::Filter1()
{
struct resbuf *rb; // 结果缓冲区链表
ads_name ssname;
rb = acutBuildList(RTDXF0, _T("TEXT"), // 实体类型
8, _T("0,图层1"), // 图层
1, _T("*cadhelp*"), // 包含的字符串
RTNONE);
// 选择复合要求的文字
acedSSGet(_T("X"), NULL, NULL, rb, ssname);
long length;
acedSSLength(ssname, &length);
acutPrintf(_T("\n实体数:%d"), length);
acutRelRb(rb);
acedSSFree(ssname);
}
上面的代码构建的过滤器,能够获得位于图层“0 ”或者“图层 1 ”中、字符串内容包含 cadhelp 的所有文字对象。其中,“ 0, 图层 1 ”中的逗号(,)是一个通配符,用于分隔两个模式,表示两种情况均可;“*mjtd* ”中的星号(*)是一个通配符,用于匹配任意的字符序列,表示任何包含 cadhelp 的字符串均可.
关于 AutoCAD 能够识别的通配符及其含义
B. 创建包含逻辑运算符的过滤器, 在过滤器中使用逻辑运算符。添加新函数 Filter2()
//创建包含逻辑运算符的过滤器, 在过滤器中使用逻辑运算符
void Filter2();
//创建包含逻辑运算符的过滤器, 在过滤器中使用逻辑运算符
void CUserInteraction::Filter2()
{
struct resbuf *rb; //结果缓冲区链表
ads_name ssname;
rb = acutBuildList(-4, _T("<OR"), //逻辑运算符开始
RTDXF0, _T("TEXT"), //一个条件
RTDXF0, _T("MTEXT"), //另一个条件
-4, _T("OR<"), //逻辑运算符结束
RTNONE);
//选择符合要求的文字
acedSSGet(_T("X"), NULL, NULL, rb, ssname);
long length;
acedSSLength(ssname, (Adesk::Int32 *)&length);
acutPrintf(_T("\n实体数:%d"), length);
acutRelRb(rb);
acedSSFree(ssname);
}
上面构建的过滤器,能够选择图形中所有的文字和多行文字。过滤器列表中的逻辑运算符用DXF组码-4 来指示。逻辑运算符是字符串但必须成对出现,运算符以小于号开始(<), 以大于号结束(>)。图 5.13列出了可以在选择集过滤中使用的逻辑运算符
C. 创建包含关系运算符的过滤器, 在过滤器中使用关系运算符。添加新函数 Filter3()
//创建包含关系运算符的过滤器, 在过滤器中使用关系运算符
void Filter3();
//创建包含关系运算符的过滤器, 在过滤器中使用关系运算符
void CUserInteraction::Filter3()
{
struct resbuf *rb; //结果缓冲区链表
ads_name ssname;
//选择图形中半径大于或等于30的所有圆
rb = acutBuildList(RTDXF0, _T("CIRCLE"), //实体类型
-4, _T(">="), //关系运算符;组码-4指示过滤器列表中的关系运算符
40, 30, //半径;组码40用于指定圆的半径
RTNONE);
//选择符合要求的圆
acedSSGet(_T("X"), NULL, NULL, rb, ssname);
long length;
acedSSLength(ssname, (Adesk::Int32 *)&length);
acutPrintf(_T("\n实体数:%d"), length);
acutRelRb(rb);
}
上面构建的过滤器,能够选择图形中半径大于或等于 30 的所有圆,其中的组码 40 用于指定圆的半径。过滤器列表中的关系运算符以DXF 组码- 4 来指示,用字符串来表示关系运算符。
D. 结合使用通配符和关系运算符,创建更为复杂的过滤器,添加新函数 Filter4()
//结合使用通配符和关系运算符,创建更为复杂的过滤器
void Filter4();
//结合使用通配符和关系运算符,创建更为复杂的过滤器
//选择图形中圆心在 pt1 和 pt2 两点构成的矩形内的圆,其中的组码 10 用于指定圆的圆心。
void CUserInteraction::Filter4()
{
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,_T(">,>,*"), //关系运算符和通配符
10,pt1, //圆心;组码10用于指定圆的圆心
-4,_T("<,<,*"), //关系运算符和通配符
10,pt2, //圆心
RTNONE);
acedSSGet(_T("X"), NULL, NULL, rb, ssname);
long length;
acedSSLength(ssname, (Adesk::Int32 *)&length);
acutPrintf(_T("\n实体数:%d"), length);
acutRelRb(rb);
}
上面构建的过滤器,能够选择图形中圆心在 pt1 和 pt2 两点构成的矩形内的圆,其中的
组码 10 用于指定圆的圆心。
E. 创建过滤扩展数据的过滤器,使用过滤器过滤扩展数据。添加新函数 Filter5()
上面构建的过滤器,能够选择图形中所有包含“Xdata ”应用程序扩展数据的图元。令人遗憾的是,除轻量多段线之外,其他的实体都不支持扩展数据内容的过滤,也就是说,如果使用下面的代码:
rb = acutBuildList(1000,
"Road", // 扩展数据中的ASCII字符串
RTNONE);
上面的过滤器仅能选择到图形中所有包含字符串“Road ”扩展数据的轻量多段线,其他类型的实体不起作用。
讲到这里,相信你一定感觉在创建选择集过滤器时,如何获得所需要的组码是一个令人头疼的问题。
|
|