基于c#的AutoCAD二次开发(1)

基于c#的AutoCAD二次开发(1),第1张

近日,应朋友之托,看了看关于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请高手帮忙!用代码实现取直径特定的园的坐标信息!等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/9572116.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-29
下一篇2023-04-29

发表评论

登录后才能评论

评论列表(0条)

    保存