ObjectARX中关于选择集和实体图元名的常用接口

1 选择集和实体图元名概述

 很多用于处理选择集或者实体的ObjectARX函数通过图元名来标识它们,这个名称实际上是一对long型整数。在ObjectARX中,选择集和实体的图元名类型均为ads_name。
 在处理选择集或者实体之前,ObjectARX函数必须获得当前选择集或者实体的图元名,可以通过调用库函数来获取。
 注意选择集和实体图元名称是可变的;它们仅在您使用 AutoCAD 处理图形时适用,并且在退出 AutoCAD 或切换到其他图形时会丢失。
 对于同样仅适用于当前进程的选择集,名称的易失性不会造成问题,但对于保存在图形数据库中的实体,则存在问题。必须在不同时间引用同一图形(或多个图形)中的相同实体的应用程序可以使用实体句柄。

2 选择集相关函数

2.2 常用选择集全局接口

函数名称作用
acedSSGet通过各种方式选择实体以创建一个选择集
acedSSAdd创建一个新的选择集,或者添加一个实体到已存在的选择集中
acedSSDel删除选择集中的某个实体
acedSSLength返回选择集中实体的数目
acedSSName返回选择集中某个实体的图元名

 这里面特别说明两个函数。
 一、acedSSGet 函数

int acedSSGet (
const char *str,
const void *pt1,
const void *pt2,
const struct resbuf *entmask,
ads_name ss);

 注意选择集用完以后需要使用acedSSFree(ssname); 释放选择集。
 AutoCAD不能一次性同时打开超过128个选择集。这个限制包括所有同时运行的ObjectARX和AutoLISP程序中的选择集。如果达到了这个限制,AutoCAD拒绝创建更多的选择集。不建议同时管理大量的选择集。相反,在任何时候需要保持一个合理的选择集数量,并且调用acedSSFree去及时释放不用的选择集。
  二、acedSSAdd函数说明

int acedSSAdd(
const ads_name ename,
const ads_name sname,
ads_name result
);

 这个函数可以创建新的选择集或将实体添加到现有选择集。
 如果 ename 和 sname 都是空指针,acedSSAdd() 将创建一个没有成员的新选择集。如果 ename 是有效实体,但 sname 为空,则 acedSSAdd() 会创建一个新的选择集,其(单个)成员是 ename。如果 ename 指定了有效的实体,而 sname 指定了现有的选择集,则 acedSSAdd() 会将 ename 实体添加到由 sname 指定的集中。参数result为新建的或者更新后的选择集。
 如果 ename 指定的实体已在集合 sname 中,则 acedSSAdd() 将忽略该请求并且不会报告错误。
 sname 和result参数可以指定相同的选择集。这是将 ename 实体添加到现有选择集的最直观方法。
 通过使用空 sname 调用 acedSSAdd() 创建的每个选择集都必须在以后通过调用 acedSSFree() 来释放。这甚至适用于空选择集(当 ename 也为空时)。如果 aceedSSAdd() 返回错误状态代码,则不会创建任何选择集。必须在处理完选择后释放分配的选择集。如果不这样做,选择集将保留在堆栈上,直到 AutoCAD 终止。由于 AutoCAD 每个会话只能容纳 128 个基于应用程序的选择集,因此未发布的选择集可能会导致通过 ObjectARX 选择对象失败。
 下面的代码将图纸的首个、最后一个实体添加到了选择集中。

ads_name fname, lname; // Entity names
ads_name ourset; // Selection set name

// Get the first entity in the drawing.
if (acdbEntNext(NULL, fname) != RTNORM) { 
 acdbFail("No entities in drawing\n"); 
 return BAD; 
} 

// Create a selection set that contains the first entity.
if (acedSSAdd(fname, NULL, ourset) != RTNORM) { 
 acdbFail("Unable to create selection set\n"); 
 return BAD; 
} 

// Get the last entity in the drawing.
if (acdbEntLast(lname) != RTNORM) { 
 acdbFail("No entities in drawing\n"); 
 return BAD; 
} 
// Add the last entity to the same selection set.
if (acedSSAdd(lname, ourset, ourset) != RTNORM) { 
 acdbFail("Unable to add entity to selection set\n"); 
 return BAD; 
 
} 

 在选择集当中,经常需要迭代选择集中的每个实体,通常的做法是通过acedSSName取出每个实体的ads_name,然后打开实体;以下示例代码描述了acedSSName()的用法

ads_name sset, ent1, ent4, lastent; 
long ilast; 

// Create the selection set (by prompting the user).
acedSSGet(NULL, NULL, NULL, NULL, sset); 

// Get the name of first entity in sset.
if (acedSSName(sset, 0L, ent1) != RTNORM) 
 return BAD; 

// Get the name of the fourth entity in sset.
if (acedSSName(sset, 3L, ent4) != RTNORM) { 
 acdbFail("Need to select at least four entities\n"); 
 return BAD; 
} 

// Find the index of the last entity in sset.
if (acedSSLength(sset, &ilast) != RTNORM) 
 return BAD; 

// Get the name of the last entity in sset.
if (acedSSName(sset, ilast-1, lastent) != RTNORM) 
 return BAD; 

2.3 选择集变形转换

 选择集中提供了一个函数acedXformSS(),用于选择集的矩阵转换,这比调用acedCommand对选择集进行旋转、缩放、镜像和移动操作要高效的多。

int rc, i, j; 
ads_point pt1, pt2; 
ads_matrix matrix; 
ads_name ssname; 

// Initialize pt1 and pt2 here.

rc = acedSSGet("C", pt1, pt2, NULL, ssname); 
if (rc == RTNORM) { 
// Initialize to identity.
 ident_init(matrix); 
// Initialize scale factors.
 matrix[0][0] = matrix[1][1] = matrix[2][2] = 0.5; 
// Initialize translation vector.
 matrix[0][T] = 20.0;	 
 matrix[1][T] = 5.0; 

 rc = acedXformSS(ssname, matrix); 
} 

2.4 拖动选择集

 拖动选择集可以使用acedDragGen()函数。

int acedDragGen(
    const ads_name ss, 
    const ACHAR * pmt, 
    int cursor, 
    int (*scnf) (ads_point pt, ads_matrix mt), 
    ads_point p
);

 其中scnf是一个函数指针,其原型为

int scnf(ads_point pt, ads_matrix mt) 

 如果scnf修改了mt矩阵,必须返回RTNORM;否则为RTNONE;如果检测出错误,则会返回RTERROR。
在拖动过程中,每一次鼠标移动都会调用该函数,然后在scnf函数中修改该矩阵,再之后acedDragGen会将修改后的矩阵作用在选择集中的每一个实体。
 下面的例程函数设置了一个平移矩阵。

int dragsample(ads_point usrpt, ads_matrix matrix) 
{ 
 ident_init(matrix); // Initialize to identity.
// Initialize translation vector.
 matrix[0][T] = usrpt[X]; 
 matrix[1][T] = usrpt[Y]; 
 matrix[2][T] = usrpt[Z]; 

 return RTNORM; // Matrix was modified.
} 

 相反,下面版本的dragsample函数在XY平面上缩放选择集,但是不移动它。

int dragsample(ads_point usrpt , ads_matrix matrix) 
{ 
 ident_init(matrix); // Initialize to identity.
 matrix[0][0] = userpt[X]; 
 matrix[1][1] = userpt[Y]; 

 return RTNORM; // Matrix was modified.
} 

 以下是一段调用代码,展示了acedDragGen的使用方法。

int rc; 
ads_name ssname; 
ads_point return_pt; 

// Prompt the user for a general entity selection: 
if (acedSSGet(NULL, NULL, NULL, NULL, ssname) == RTNORM) 

 rc = acedDragGen(ssname, // The new entities
 "Scale the selected objects by dragging", // Prompt
 0, // Display normal cursor (crosshairs) 
 dragsample, // Pointer to the transform function 
 return_pt); // Set to the specified location 

3 实体图元名相关函数

3.1 实体图元名获取函数

 若要对实体进行操作,ObjectARX程序必须获取实体的图元名,以便在后续调用实体数据函数或者选择集函数中使用。函数 acedEntSel()、acedNEntSelP() 和 acedNEntSel() 不仅返回实体的名称,还返回供应用程序使用的其他信息。
 如果对 acedEntSel()、aceedNEntSelP() 或 aceedNEntSel() 的调用返回 RTERROR,并且想知道错误的原因,可以检查 ERRNO 系统变量的值。如果用户指定了一个空点,则 ERRNO 等于 7 (OL_ENTSELPICK)。如果用户按 RETURN,则 ERRNO 等于 52 (OL_ENTSELNULL)。(如果您的程序包含头文件 ol_errno.h,则可以使用符号名称。
 下面的代码片段描述了如何通过acedSSAdd和acdbEntNext创建选择集,以及给选择集添加新元素。

ads_name ss, e1, e2; 

// Set e1 to the name of first entity.
if (acdbEntNext(NULL, e1) != RTNORM) { 
 acdbFail("No entities in drawing\n"); 
 return BAD; 
} 

// Set ss to a null selection set.
acedSSAdd(NULL, NULL, ss); 

// Return the selection set ss with entity name e1 added.
if (acedSSAdd(e1, ss, ss) != RTNORM) { 
 acdbFail("Unable to add entity to selection set\n"); 
 return BAD; 
} 

// Get the entity following e1.
if (acdbEntNext(e1, e2) != RTNORM) { 
 acdbFail("Not enough entities in drawing\n"); 
 return BAD; 
} 

// Add e2 to selection set ss  
if (acedSSAdd(e2, ss, ss) != RTNORM) { 
 acdbFail("Unable to add entity to selection set\n"); 
 return BAD; 
} 

3.2 实体定义数据获取

 下面示例代码描述了如何使用acdbEntNext迭代数据库,并获取每个实体的定义数据。

ads_name ent0, ent1; 
struct resbuf *entdata; 

if (acdbEntNext(NULL, ent0) != RTNORM) { 
 acdbFail("Drawing is empty\n"); 
 return BAD; 
} 
do { 
// Get entity's definition data.
 entdata = acdbEntGet(ent0); 
 if (entdata == NULL) { 
 acdbFail("Failed to get entity\n"); 
 return BAD; 
 } 
 . 
 . // Process new entity.
 . 
 if (acedUsrBrk() == TRUE) { 
 acdbFail("User break\n"); 
 return BAD; 
 } 
 acutRelRb(entdata); // Release the list.
 ads_name_set(ent0, ent1); // Bump the name.
} while (acdbEntNext(ent1, ent0) == RTNORM); 

3.3 利用实体数据修改、创建实体

 acdbEntMod用于修改实体,acdbEntMake用于创建实体。
 在下面示例代码中,首先获取图纸中第一个实体的定义数据,然后更改该实体的图层为MYLAYER。

	ads_name en;
	struct resbuf *ed, *cb;
	char *nl = "MYLAYER";

	if (acdbEntNext(NULL, en) != RTNORM)
		return BAD; // Error status  

	ed = acdbEntGet(en); // Retrieve entity data.

	for (cb = ed; cb != NULL; cb = cb->rbnext)
		if (cb->restype == 8)
		{											// DXF code for Layer
		// Check to make sure string buffer is long enough.
			if (strlen(cb->resval.rstring) < (strlen(nl)))
				// Allocate a new string buffer.
				cb->resval.rstring = realloc(cb->resval.rstring,
					strlen(nl) + 1);

			strcpy(cb->resval.rstring, nl);

			if (acdbEntMod(ed) != RTNORM) {
				acutRelRb(ed);
				return BAD; // Error
			}
			break; // From the for loop
		}
	acutRelRb(ed); // Release result buffer.

 应用程序还可以通过调用 acdbEntMake() 函数将实体添加到图形数据库。与 acdbEntMod() 一样,acdbEntMake() 的参数是一个结果缓冲区列表,其格式类似于 acdbEntGet() 返回的列表。(acdbEntMake() 调用会忽略实体名称字段 [-1](如果存在)。新图元将追加到图形数据库中(它将成为图形中的最后一个图元)。如果实体是复杂实体(折线或块),则在完成之前不会将其追加到数据库中。
 以下示例代码片段在 MYLAYER 层上创建一个圆圈。

int status; 
struct resbuf *entlist; 
ads_point center = {5.0, 7.0, 0.0}; 
char *layer = "MYLAYER"; 

entlist = acutBuildList(RTDXF0, "CIRCLE",// Entity type
 8, layer, // Layer name 
 10, center, // Center point 
 40, 1.0, // Radius 
 0 ); 

if (entlist == NULL) { 
 acdbFail("Unable to create result buffer list\n"); 
 return BAD; 
} 

status = acdbEntMake(entlist); 
acutRelRb(entlist); // Release acdbEntMake buffer.

if (status == RTERROR) { 
 acdbFail("Unable to make circle entity\n"); 
 return BAD; 
} 
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_Santiago

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值