
近日,应朋友之托,看了看关于AutoCAD二次开发的事情。关于朋友的诉求,其实非常简单,就是在一个既定的DWG文件中,有一条折线和许多标注点。需要寻找在线上的标注点,并将其按照顺序输出到文件中。
如果上述工作采用人工选择的话,不仅费时费力,而且容易遗漏,因此自动化 *** 作很有必要。所以就研究一下二次开发的事情。
网上关于AutoCAD二次开发的方法有很多种,其中AutoCAD软件自带了Visiual Lisp编辑器,实现很方便,但是,对于新手而言,常用函数和语法不熟悉的情况,函数非常难于寻找(很可能是我不熟悉lisp语法吧)。比如:lisp获取所有对象的语句为
而visiual studio 有强大的提示功能,且函数命名比较直观。
因此,对于c#熟悉的使用这个较好。
我是用的是AutoCAD2016简体中文版和Visiual Studio 2019(这个不一定要2019版)。根据网上搜索来的资料,首先测试自己搭建的环境是否有效。
在visiual studio 中新建一个类库项目,dotnet framework 版本设为45 ,这个和AutoCAD2016的类库是对应的。
进入所建好的类库项目后,主要做如下工作:
(1)添加对CAD类库的引用
在项目引用中利用右键添加引用,在AutoCAD程序安装目录找到accoremgddll,acdbmgddll和acmgddll三个动态链接库,添加后成功后,如下图所示:
(2)在类中新建如下测试函数
依据错误内容提示,添加using语句:
(3)设置项目启动项
打开新建类库的属性页,在调试选项卡中,启动外部程序部分,选择autoCAD安装目录的主程序,这样在启动调试时,直接打开AutoCAD软件。
(4)启动调试后,程序自动打开AutoCAD软件,在CAD界面的命令窗口,输入netload,在d出的窗口,选择上一步所构建的类库输出dll文件。然后,在命令输入框,输入testdemo命令,如果出现“测试环境搭建成功”,则表示环境搭建成功。
在上一步搭建好环境的类库中,新建一个读取数据的函数。该函数主要逻辑为:
(1)获得用户选择的polyline对象
(2)获取用户要保存结果文件的名字
(3)获取文件所有待分拣的块对象
(4)判断块对象是否在线上,如果在,则计算该块对象到polyline起点的距离
(5)输出符合条件的块对象属性和距离到指定文件中
对于新手而言,主要的难点在于cad提供的哪些函数具备上述功能。这里将我找到的一些介绍如下,这里需要说明的是,对于cad二次开发,我也是新手,所选函数,仅仅是满足实现功能的目的,而不是最优的解决方案。
//下面为对话框函数
PromptFileNameResult resFile = edGetFileNameForSave("结果保存");
if (resFileStatus==PromptStatusOK)
{
点到线最近距离点函数:GetClosestPointTo
某点到线起点距离计算:GetDistAtPoint,该函数的点必须在线上。我们找到的所有块对象,原则上是在线上的,但是实际测量中,可能存在偏差,所以就需要就近找到线上点。此外,所有的块对象并不是都属于改线,也可能有其他线的块对象,因此,需要计算改点和线上点位置,如果小于一定阈值,则可以认为改点是线上点,否则,属于其他对象。
输出结果用c#常用的的streamwriter函数即可。
;;设置空表ss3
(setq ss3 '())
;;循环提取ss的对象
;;取得数据对象,提取坐标@p1及内容#k;
(setq i 0 ss1 (ssname ss i) ss2 (entget ss1) @p1 (cdr (assoc 10 ss2)) #k (cdr (assoc 1 ss2)) i (+ i 1))
;;设置空表ss3,坐标及内容为一个表加入ss3
(setq ss3 (cons (list @p1 #k)ss3))
;;循环结束得到ss3
;;对表ss3排序
(setq ss3 (vl-sort ss3 (function (lambda (x y)(< (car (car x)) (car (car y)))))));;X排序从左到右
(setq ss3 (vl-sort ss3 (function (lambda (x y)(> (cadr (car x)) (cadr (car y)))))));;Y排序从上到下
(defun c:test()
(setq oldos (getvar "osmode"))
(setvar "osmode" 4)
(initget 0)
(setq pt (getpoint "\nEnter a point:"))
(setvar "osmode" oldos)
(terpri)
(princ pt)
(princ)
)
(command "GROUP" "C" "" "" en1 en2 en3 en4 "");;编组
编组的功能我不是很清楚,只是用到这个的时候才研究了一下,编组的时候要命名,但是对象一多的话,命名就显的多余了,所以用""取消命名。
en1 en2 这个对象,如果用ssget选择&kw的话,对象就是i=0,(setq en1 (ssname &kw i))(setq i (+ i 1))的方法提取。
如果用entsel选择的对象&kw的话,对象就是(setq en1 (car &kw));
如果是刚刚绘制的图形用(setq en1 (entlast))得到的图形就是图元名。
创建了选择集后将此选择集保存为一个编组,我没有测试,不过可以试试这样的方法你测试一下:
&kw是(ssget)选择集:
(setq &k1 (ssname &kw 0));;提取(ssget)选择集里面的第一个对象
(setq i 2);;
(command "GROUP" "C" "" "" &k1);;这个对象加入并准备编组,根据多段线绘制方法差不多
(setq &k1 (ssname &kw 1));;提取第二个对象,编组的话,应当要两个对象以上,
(while &k1;;选择循环
(command &k1);;加入编组
(setq &k1 (ssname &kw i));;取得第三个对象如果没有就结束循环
(setq i (+ i 1));;
)
(command "");;编组结束
你测试一下是不是可行,我没有测试,就是提供思路给你。
;;;首先获得INSERT的2组码信息:
(setq @iName (cdr(assoc -2(entget(car(entsel"\n选取图面上的块:"))))))
;;;比如返回值为"myBlock"
之后查询block中组码相同的信息:
(setq @bEnt (tblobjname "block" @iName))
;;;由此获得insert对应的block图元名。
之后用entget获取@bEnt组码-2里包含的图元
(setq @child (cdr(assoc -2(entget @bEnt))))
;;;此时@child就是insert中第一个图元的图元名,继续entget可以获得详细信息:
(entget @child)
;;;如果要获取insert是由多个图形组成,要获取中第二个或者第三个图元或者更多:
;;;第二个图元图元名:(entnext @child)
;;;第三个图元图元名:(entnext (entnext @child))
;;;第四个图元图元名:(entnext(entnext (entnext @child)))
;;;……
;;;由此规律,可以写一个简单的函数来获取固定第几个图元的图元名
(defun GETOBJ(#num / @@gtEt)
(setq @@gtEt "@child");定义一个基础字符串
(if (>= #num 1)(fix #num)(exit));错误处理部分,如果#num<1或者不为数字,则退出
(repeat #num ;循环#num"整数部分"次
(setq @@gtEt (strcat "(entnext" @@gtEt ")"));将字符串@@gtEt前加"(entnext",后加")"
)
(eval (read @@gtEt));用read转换@@gtEt为表,并用eval执行该表
)
;;;由此,(GETOBJ 10)可以获得@child后第10个图元的图元名。如果要查看详细信息,则:
(entget(GETOBJ 10))
;;;====================================================================================
;;;汇总整段代码:
(defun GETOBJ(#num / @@gtEt)
(setq @@gtEt "@child")
(repeat #num
(setq @@gtEt (strcat "(entnext" @@gtEt ")"))
)
(eval (read @@gtEt))
)
(defun c:INSOBJ(/ @num @iName @bEnt )
(setq @iName (cdr(assoc -2(entget(car(entsel"\n选取图面上的块:"))))))
(setq @bEnt (tblobjname "block" @iName))
(setq @child (cdr(assoc -2(entget @bEnt))))
(setq @num (getint "\n输入获取的图元序号:"))
(if (< @num 0)
(progn
(princ "\n序号必须不小于0。")
(exit)
)
)
(if (= @num 0)(entget @child))
(if (> @num 0)(entget(GETOBJ @num)))
(princ)
)
;;;以上,调用后CAD输入INSOBJ就可以了。
支持,面向对象不是可视化,只是一种自定义扩展,一种思路,lisp的强大是主要是表 *** 作的运用,与objectarx相比,要简单的多,你完全可以针对CAD的对象扩展lisp函数,或者说,编写特定对象。
我以前一直以为lisp只是用于CAD开发的……,今天才知道天才都是用LISP!……
以上就是关于基于c#的AutoCAD二次开发(1)全部的内容,包括:基于c#的AutoCAD二次开发(1)、autocad lisp函数 ssname 框选的对象,怎么设置使的所选的对象依次从左至右的排序、lisp CAD请高手帮忙!用代码实现取直径特定的园的坐标信息!等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)