目录
一、基本概念
1.1 基本定义
- ADS:autocad design system 简称,早期CAD面向过程编程系统,现在整合入objectarx中
- 功能:对CAD全局参数编辑,提供与用户交互函数,头文件:adslib.h、adsdlg.h,默认已加入
1.2 关键类型
-
类型定义
类型名 特性 对象id
AcDbObjectId在一个CAD进程中管理多个CAD文件,所有打开的数据库对象在内存中都有唯一的id,每个对象在每次加载后id值都不同,此对象是以下各类型的中介 实体名
ads_name为ADS存储实体对象的临时变量,关闭文件即丢失,此对象通常用来接收用户选择实体或选择集 句柄
AcDbHandle数据库文件dwg真实标记实体的数据类型,每次打开文件,同一实体,句柄不变 -
转换关系
二、数据类型
2.1 ads数据类型
- 包含:浮点型、整型、字符串、点、实体名
- 代码
// 整形 int num = 5; // 打印写法:跟C语言printf一样 acutPrintf(_T("%d\n"), num); // 浮点型:typedef double ads_real; ads_real r1=3.14; acutPrintf(_T("%0.3f\n"), r1); // 字符串型:以下二者可相互转换 ACHAR * str = _T("兼容性最好\n"); CString cstr = _T("此类为mfc项目默认字符串,函数更友好\n"); acutPrintf(str); acutPrintf(cstr); // 点:typedef ads_real ads_point[3]; ads_point pt1, pt2; // 三个坐标不可留空 pt1[X] = pt1[Y] = pt1[Z] = 1.0; // 点覆盖式赋值:用pt1赋值pt2 ads_point_set(pt1, pt2); acutPrintf(_T("%0.3f\n"),pt2[X]); // 实体名(由鼠标选择赋值),通常由其获得对象id // typedef int64_t ads_name[2]; ads_name en, en1; // 将en0深拷贝给en1 ads_name_set(en0, en1);
2.2 类型转换
2.2.1 浮点数 与 字符串
- 代码示例
ads_real rel = 1.23456789; ACHAR str[12]; // 浮点数转字符串:浮点数、转换模式、小数位数、待接收字符串 // 转换正常ret为RTNORM,否则见第3.1节 int ret = acdbRToS(rel, 1, 3, str); acutPrintf(str); // 字符串转浮点数:字符串、转换模式、浮点数(注意取地址符) ACHAR str_a[12]= _T("9.87654"); // ret用于存储结果类型码(本篇3.1) 判断是否正常转换:RTNORM为正常 // 转换正常ret为RTNORM,否则见第3.1节 ret = acdbDisToF(str_a,1,&rel); acutPrintf(_T("\n%f"),rel);
转换模式:
- 1科学记数法:结果为1.235E+00
- 2十进制:结果为1.235
- 3工程、4建筑:略
- 5分数:结果为1 1/4
2.2.2 角值 转换
- 弧度 转 字符串(由控制符 控制 转换格式)
// 函数acdbAngToS参数:弧度值、控制符、精度、字符串指针 // 转换正常ret为RTNORM,否则见第3.1节 ACHAR str[12]; // 0弧度转角度 int ret = acdbAngToS(MathUtil::PI() / 4, 0, 4, str); // 返回:45.0000,0都省略了 acutPrintf(_T("\n%s"),str); // 1弧度转角度 ret = acdbAngToS(MathUtil::PI()/4, 1, 4, str); // 返回:45d0'0" acutPrintf(_T("\n%s"), str); // 2弧度转工程 ret =acdbAngToS(MathUtil::PI() / 4, 2, 4, str); // 返回:50g acutPrintf(_T("\n%s"), str); // 3弧度(ads_real)转弧度(字符串)(带r标识) ret =acdbAngToS(MathUtil::PI() / 4, 3, 4, str); // 返回:0.7854r acutPrintf(_T("\n%s"), str);
- 角 转 浮点数
// 函数acdbAngToF参数:字符串(弧度/角度值)、控制符、浮点数 // 转换正常ret为RTNORM,否则见第3.1节 ads_real rel; // 0:百分角度 转弧度 int ret = acdbAngToF(_T("45"), 0, &rel); acutPrintf(_T("\n%.4f"),rel); // 1:度分秒角度 转弧度 ret = acdbAngToF(_T("45d0'0\""), 1, &rel); acutPrintf(_T("\n%.4f"), rel); // 2:工程 转弧度 ret = acdbAngToF(_T("50g"), 2, &rel); acutPrintf(_T("\n%.4f"), rel); // 3:弧度(带r标识) 转弧度(不含r标识) ret = acdbAngToF(_T("0.7854r"), 3, &rel); acutPrintf(_T("\n%.4f"), rel);
关系:acdbAngTo与acdbAngToS为互补函数
2.2 结果缓冲区
- 功能:CAD中数据种类多样,需要有一个进行数据临时交换与存储的媒介
2.2.1 定义
- 源文件声明
// 结果缓冲区节点为结构体 struct resbuf { // 用于构造单链表,未设置则为NULL struct resbuf *rbnext; // 用于定义ads_u_val 的类型 short restype; // 联合体:用于存储具体值 union ads_u_val resval; }; // 联合体ads_u_val的定义 union ads_u_val { // 浮点型:常用 ads_real rreal; // 点:常用 ads_real rpoint[3]; // 短整型:常用 short rint; // 字符串:常用 ACHAR *rstring; // 剩下不常用略,可以转到结果缓冲区查看 };
2.2.2 结果类型码
- 类型码列表
#define RTNONE 5000 /* 无结果 */ #define RTREAL 5001 /* 浮点型 */ #define RTPOINT 5002 /* 2D点 */ #define RTSHORT 5003 /* 短整型 */ #define RTANG 5004 /* 角度 */ #define RTSTR 5005 /* 字符串 */ #define RTENAME 5006 /* 实体名 */ #define RTPICKS 5007 /* 选择集 */ #define RTORINT 5008 /* 方向*/ #define RT3DPOINT 5009 /* 3D点 */ #define RTLONG 5010 /* 长整型 */ #define RTVOID 5014 /* 空白符号 */ #define RTLB 5016 /* 列表开始 */ #define RTLE 5017 /* 列表结束 */ #define RTDOTE 5018 /* 点对 */ #define RTNIL 5019 /* 零*/ #define RTDXF0 5020 /* DXF码,仅供ads_buildlist使用 */ #define RTRESBUF 5023 /* 结果缓冲区 */
用于指定结果缓冲区节点的值类型
- 组码:特殊的类型码,≤1071的类型码有特殊含义,传送门
2.2.3 简单使用
- 结果缓冲区链表
void test() { // 自制结果缓冲区的迭代器,提取链表每个节点 resbuf* rb_iter; resbuf* cmdlist; ads_point pt1 = { 1,1,1 }; int num = 3; // 函数:构建结果缓冲区链表 cmdlist = acutBuildList(RTSTR, _T("test"), RTPOINT,pt1, RTSHORT,num, RTNONE); // 拷贝 链表 首节点 的 指针 给 迭代器 rb_iter = cmdlist; // rb_iter的指针不为空 while (rb_iter != NULL) { acutPrintf(_T("结果类型码:%d\n"), rb_iter->restype); switch (rb_iter->restype) { case RTSTR: acutPrintf(_T("值为:%s\n"), rb_iter->resval.rstring); break; case RTPOINT: acutPrintf(_T("值为:%f\n"), rb_iter->resval.rpoint[X]); break; case RTSHORT: acutPrintf(_T("值为:%d\n"), rb_iter->resval.rint); break; } rb_iter = rb_iter->rbnext; } acutPrintf(_T("执行完毕\n")); // 手动释放结果缓冲区 acutRelRb(rb_iter); acutRelRb(cmdlist); }
- 效果
2.2.4 链表命令
- 函数用法
// 必须包含头文件 #include "acedCmdNF.h" // 模拟人工输入命令:隐式构建结果缓冲区链表 acedCommandS(RTSTR, _T("circle"), RTSTR, _T("0,0"), RTSTR, _T("300"), RTNONE);
三、用户交互
3.1 函数返回码
- 功能:用于标识函数执行情况
- 常用返回码列表(重要)
#define RTNORM 5100 /* 正常 */ #define RTERROR (-5001) // 其他错误 #define RTCAN (-5002) // 用户按Ctl-C或ECS #define RTREJ (-5003) // AutoCAD拒绝的请求--无效 #define RTFAIL (-5004) // 连接失败 -- Lisp脚本可能崩溃了 #define RTKWORD (-5005) // 来自 getxxx() 的关键字 #define RTINPUTTRUNCATED (-5008) // 输入不完全适合缓冲区
3.2 常用
- 弹出警告框:
acedAlert(_T("弹出警告框"));
- 命令行打印:
acutPrintf(_T("跟C语言printf函数一样\n"));
- 捕捉离光标最近的中点、端点、中心点(最好关掉对象捕捉)
acedOsnap(pt, _T("midp,endp,center"), pt1);
,pt是传入的点,pt1是返回的点 - 遍历全图实体(包括隐藏实体)
ads_name en0, en1; // 遍历全图:首参数为null,则获取第一个元素的ads_name if (acdbEntNext(NULL, en0) != RTNORM) return; // acdbEntNext遍历链表,以首参数为参照,获取第二个参数ads_name do { // 从ads_name获取对象id AcDbObjectId id; acdbGetObjectId(id, en0); // ld 长整型 acutPrintf(_T("\n对象id为:%ld"), id); // acedUsrBrk()用于判断用户是否按下esc键 if (acedUsrBrk()) return; // 将en0深拷贝给en1 ads_name_set(en0, en1); // en1变为参考点,en0值被覆盖,从而获取下一个链表节点的ads_name } while (acdbEntNext(en1, en0) == RTNORM);
3.3 acedGetXXX函数
3.3.1 常规
-
获取整型:acedGetInt
// 获取整型:提示字符串、变量地址(看函数头文件) int num; if (acedGetInt(_T("\n请输入整数:"), &num) == RTNORM) acutPrintf(_T("\n整数为:%d"),num);
-
获取浮点数:acedGetReal
// 获取浮点数:提示字符串、变量地址 ads_real num_real; if (acedGetReal(_T("\n请输入浮点数:"), &num_real) == RTNORM) acutPrintf(_T("\n浮点数为:%0.3f"), num_real);
-
获取字符串:acedGetString
// 获得字符串:是否允许空格(1允许)、提示字符串、字符串指针、字符串变量长度(包括结尾\0) // 如果超出长度ret返回RTINPUTTRUNCATED,超出的字符串丢弃,正常返回RTNORM ACHAR str[6]; int ret = acedGetString(0, _T("\n请输入字符串:"), str, 6); if ( ret == RTNORM) acutPrintf(_T("\n字符串为:%s"), str); else { acutPrintf(_T("\n结果返回码为:%d"), ret); } // 字符串正则匹配函数:待校验字符串指针、匹配规则 if (acutWcMatch(str, _T("ro*b"))==RTNORM) { acedAlert(_T("此字符串匹配了定义的正则表达式")); }
-
获取点坐标:acedGetPoint
// 获取点坐标:是否允许空格(1允许)、提示字符串、点变量 ads_point pt; if (acedGetPoint(0, _T("\n请选取点:"), pt) == RTNORM) acutPrintf(_T("\n点为:%f,%f"), pt[X],pt[Y]); // 极坐标法获得点坐标:基点ads_point、弧度ads_real,极半径ads_real,返回点ads_point acutPolar(pt,ang, 100.0, pt3);
-
获取夹角弧度:acedGetAngle
// 获取与三点钟方向夹角弧度:基准点(若为NULL则在屏幕上点)、提示字符串、接收弧度值 ads_point pt_ang = { 0,0,0 }; ads_real ang; if (acedGetAngle(pt_ang, _T("\n请角度点:"), &ang) == RTNORM) acutPrintf(_T("\n角弧度为:%f"), ang); // 方法2:直接计算pt与pt1线段与x轴正向夹角弧度 ads_real ang = acutAngle(pt, pt1);
方框内角度:非弧度,会跟着十字光标动态变化
-
获取两点间距离:acedGetDist
// 返回屏幕上两点间距离:基准点(若为NULL则在屏幕上点)、提示字符串, ads_real distance; if (acedGetDist(NULL, _T("\n请选择点:"), &distance) == RTNORM) acutPrintf(_T("\n距离为:%f"), distance);
3.3.2 acedInitGet
-
功能一:循环检测用户非法输入
-
关键字代码:
// 过滤用户非法输入,输入符合要求才能通过,可esc退出 acedInitGet(RSG_NONEG + RSG_NOZERO + RSG_NONULL, NULL); int num; if (acedGetInt(_T("\n请输入整数:"), &num) == RTNORM) acutPrintf(_T("\n整数为:%d"),num);
控制位开关:
- 非负:RSG_NONEG ,非零 RSG_NOZERO,非空RSG_NONULL
- 开启橡皮筋或虚矩形追踪RSG_DASH
- 去掉Z坐标:RSG_2D,仅用于acedGetDist
特点:仅对紧跟着的那个acedGetXXX函数起效
-
功能二:关键字选项控制
// 禁止输入空,并明确关键字为以下四个(空格分隔) acedInitGet(RSG_NONULL, _T("1 2 3 4")); ACHAR kw[5]; // 这是控制关键字显示:见下面效果图 acedGetKword(_T("\n选择一个关键字[ONE(1)/TWO(2)/THREE(3)]:"), kw); switch (tc) { case RTCAN: acutPrintf(_T("\n你取消了输入")); break; case RTNORM: if (_tcscmp(kw, _T("1")) == 0) { // 可以通过关键字跳转其他程序处理后续 acutPrintf(_T("\n你选择了1")); break; } else if (_tcscmp(kw, _T("2")) == 0) { acutPrintf(_T("\n你选择了2")); break; } else if (_tcscmp(kw, _T("3")) == 0) { acutPrintf(_T("\n你选择了3")); break; } default: break; } acutPrintf(_T("\n程序结束"));
-
效果
3.3.3 选择实体
- 功能:获取实体ads_name和选择点
- 代码示例
// 获取与三点钟方向夹角弧度:基准点(若为NULL则在屏幕上点)、提示字符串、接收弧度值 ads_point pt; ads_name en; if (acedEntSel(NULL, en, pt) == RTNORM) acutPrintf(_T("点选处为:%f,%f"), pt[X], pt[Y]);
- 常用函数
ads_name en1, en2; ads_point pt1, pt2; acedEntSel(NULL, en1, pt1); acedEntSel(NULL, en2, pt2); // 判断ads_name是否相等 if (acdbNameEqual(en1, en2)) acutPrintf(_T("\n选择了同一个实体")); else acutPrintf(_T("\n选择了两个实体")); // 清空ads_name值 acdbNameClear(en2); // 判断ads_name是否为空,为空则为true if (acdbNameNil(en2)) acutPrintf(_T("\n清除成功")); // 用en2给en1赋值 acdbNameSet(en1,en2); if (acdbNameEqual(en1, en2)) acutPrintf(_T("\n赋值成功"));
- 效果
3.4 选择集
- 定义:实体的有名集合
- 特性:
- 非互斥性:一个实体可以包含在不同选择集中
- 唯一性:多次选择一个实体,选择集中只包含一次
- 易用性:可空,可手动框选添加实体进选择集
3.4.1 常用函数
- 代码示例
// 图上框选创建选择集 ads_name en1, en2, ss1; acedSSGet(NULL, NULL, NULL, NULL, ss1); // 获得选择集长度 int len; acedSSLength(ss1, &len); acutPrintf(_T("\n初始选择集实体个数为%d"), len); // 获取 选择集 首元素 的ads_name赋值en:一般用在for循环里 acedSSName(ss1,0,en1); // 判断实体是否在选择集里 if(acedSSMemb(en1, ss1)) acutPrintf(_T("\n实体在选择集中")); // 获取实体en2 acedEntSel(NULL, en2, NULL); // 将实体添加进现有选择集:第2、3参数均为选择集 acedSSAdd(en2,ss1,ss1); acedSSLength(ss1, &len); acutPrintf(_T("\n新增后选择集实体个数为%d"), len); // 从选择集中删除实体,实体还在图中 acedSSDel(en1, ss1); acedSSLength(ss1, &len); acutPrintf(_T("\n删除后选择集实体个数为%d"), len); // 释放选择集:选择集数量有上限,及时释放 acedSSFree(ss1); acutPrintf(_T("\n程序结束"));
- 效果
3.4.2 acedSSGet函数详解
- 常用
写法 注释 acedSSGet(_T("A"), NULL, NULL, NULL, ss1);
选择全部实体 acedSSGet(_T("W"), pt1, pt2, NULL, ss1);
矩形框选window:包住的、跟边线重合的实体 acedSSGet(_T("C"), pt1, pt2, NULL, ss1);
矩形叉选crossing:包住的、跟边线重合、相交的实体 - 围区点列表
点列表框选:acedSSGet(_T("WP"), pointlist, NULL, NULL, ss1); 点列表叉选:acedSSGet(_T("CP"), pointlist, NULL, NULL, ss1);
// 图上框选创建选择集 ads_name ss1; ads_point pt1 = { 0,0,0 }, pt2 = { 100,100,0 }, pt3 = { 100,0,0 }, pt4 = { 0,100,0 }; // 点列表构建 resbuf * pointlist; pointlist = acutBuildList(RT3DPOINT, pt1, RT3DPOINT, pt3, RT3DPOINT, pt2, RT3DPOINT, pt4, RTNONE); // 必须有这个,否则cad崩溃 // CP可以换成WP或F(栏选:仅选择跟边线交叉的实体), // 点列首尾自动闭合,P为Polygon acedSSGet(_T("CP"), pointlist, NULL, NULL, ss1); // 显示选择集内实体个数 int len; acedSSLength(ss1, &len); acutPrintf(_T("\n选择集内实体个数为%d"), len); // 释放选择集、释放结果缓冲区 acedSSFree(ss1); acutRelRb(pointlist); acutPrintf(_T("程序结束"));
- 过滤选择集
- 常规过滤
ads_name ss1; resbuf * filter; // 构建筛选器:RTDXF0为实体类型组码、8为图层组码、结尾要有RTNONE filter = acutBuildList(RTDXF0, _T("CIRCLE"), 8, _T("0"), RTNONE); // X 开启筛选器,filter为筛选器缓冲区指针 acedSSGet(_T("X"), NULL, NULL, filter, ss1); // 打印选择集内实体数 int len; acedSSLength(ss1, &len); acutPrintf(_T("\n选择集内实体个数为%d"), len); acedSSFree(ss1); acutRelRb(filter); acutPrintf(_T("程序结束"));
- 关系过滤 filter写法
// -4:条件运算符,40:圆半径组码(必须是100.0有小数) filter = acutBuildList(RTDXF0, _T("CIRCLE"), -4, _T(">="), 40, 100.0, RTNONE);
- 条件过滤 filter写法
// 为了好读,加了缩进:选取所有0层上的直线和所有半径为100的圆 filter = acutBuildList( // or内为或关系:内部有一个就选择 -4, _T("<OR"), // and内为与关系,一个整体 -4, _T("<AND"), RTDXF0, _T("LINE"), 8, _T("0"), -4, _T("AND>"), // and内为与关系,一个整体 -4, _T("<AND"), RTDXF0, _T("CIRCLE"), 40, 100.0, -4, _T("AND>"), -4, _T("OR>"), RTNONE);
- 常规过滤
四、系统变量
-
浮点型
// 对结果缓冲区 浮点型 操作 resbuf rb, rb1; // 获取系统变量:圆角半径 acedGetVar(_T("FILLETRAD"), &rb); acutPrintf(_T("系统变量值为:%.3f"), rb.resval.rreal); // 给自定义结果缓冲区变量赋值,rb1.next默认为null rb1.restype = RTREAL; rb1.resval.rreal = 1.0; // 提取并操作系统变量值 if (rb.resval.rreal < 1.0) // 设置系统变量值:传入自定义结果缓冲区变量 if (acedSetVar(_T("FILLETRAD"), &rb1) != RTNORM) return;
-
整型
// 对结果缓冲区 整型 操作 resbuf rb2, rb3; acedGetVar(_T("CMDECHO"), &rb2); acutPrintf(_T("\n当前的CMECHO变量的值为%d."), rb2.resval.rint); // 给自定义结果缓冲区变量赋值,rb1.next默认为null rb3.restype = RTSHORT; rb3.resval.rint = 0; if (acedSetVar(_T("CMDECHO"), &rb3) == RTNORM) { acutPrintf(_T("\n系统变量值CMDECHO,已修改,现在的值为%d"), rb3.resval.rint); } else acutPrintf(_T("\n设置系统变量值失败!"));
-
字符串型
// 对结果缓冲区 字符串 操作 resbuf rb4, rb5; // 获取系统变量:字体样式 acedGetVar(_T("TEXTSTYLE"), &rb4); if (rb4.resval.rstring != NULL) { // 打印当前字体样式、随后释放结果缓冲区 acutPrintf(_T("\n当前的文字样式是%s"), rb4.resval.rstring); acdbFree(rb4.resval.rstring); // 自定义结果缓冲区rb5,类型 rb5.restype = RTSTR; // C语言的分配内存空间,判断分配成功 // 指针自身 = (指针类型*)malloc(sizeof(指针类型)*数据数量) // mallo函数返回的实际是一个无类型指针,必须在其前面加上指针类型强制转换才可以使用 if ((rb5.resval.rstring = (ACHAR *)malloc(20)) != NULL) { // 给结果缓冲区赋值 _tcscpy(rb5.resval.rstring, _T("STANDARD")); // 用自定义的设置结果缓冲区 acedSetVar(_T("TEXTSTYLE"), &rb5); acutPrintf(_T("\n新修改的文字样式是:%s"), rb5.resval.rstring); acdbFree(rb5.resval.rstring); } else acedAlert(_T("内存不足!")); }
-
点坐标
// 对结果缓冲区点 坐标 操作 resbuf rb6, rb7; ads_real lx, ly; // 获取系统变量:当前图形最大点、最小点 acedGetVar(_T("EXTMAX"), &rb6); acedGetVar(_T("EXTMIN"), &rb7); // 结果缓冲区点提取 lx = rb6.resval.rpoint[X] - rb7.resval.rpoint[X]; ly = rb6.resval.rpoint[Y] - rb7.resval.rpoint[Y]; acutPrintf(_T("\n当前图形的水平长度和垂直长度分别为<%.3f , %.3f>"), lx, ly);
-
总体效果