明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 1132|回复: 8

[提问] 【已解决】程序如何跳过(或强制拉伸)不能“EXTRUDE”为“三维实体”的“自交曲线”

[复制链接]
发表于 2020-11-4 11:45:53 | 显示全部楼层 |阅读模式
本帖最后由 zxjing 于 2020-11-5 23:34 编辑

一、程序功能
批量拉伸平面图形(主要是PL线)至三维实体。
具体为:把当前“打开状态”的每个图层上的图元(主要是闭合多段线)根据图层名称沿Z轴拉伸一定高度。(高度由图元所在的图层的名称“30-60m”的“-”和“m”之间的数值决定)
调用的命令为“EXTRUDE”,工具条位置为“建模工具条\拉伸命令”。

二、面临问题
程序执行至遇到不能拉伸的“自相交曲线”时,程序提示“不能扫掠或拉伸自交的曲线”并中断运行,要求“重新选择拉伸对象”。
论坛里有类似的问题,只找到两种解决思路,但是没试出来怎么用,还请大咖们不吝赐教。思路①VLISP中vl-catch-all-apply 函数;思路②(defun *error*(msg)  (princ "error: ")  (princ msg) (princ))。

三、已知条件
因为CAD的图层是按照高度分层的,所以,
①   手动“拉伸”的话,可以“选层”,然后把本层所有图元统一拉伸一个高度。手动拉伸时,不能拉伸的图元(自相交曲线)会保持不变,但只要能拉伸的图元全部都能完成拉伸。(但程序执行时遇到“自交的曲线”就会中断,并一直要求输入待拉伸的图元(但并没有退出程序,也不是程序报错))
②   剩下的“自相交曲线”可以通过工具条“拉伸”命令后面的“-presspull(按住并拖动)”命令来手动拉伸。
4、CAD版本:AutoCAD2008和AutoCAD2018


四、该问题的三种解决思路
1、 提前筛选自交曲线,不参与拉伸——目前网上找到的都不能满足需要,主要是两种情况:
①   只要是闭合的就认为是自交——(我的图元都是闭合多段线);
②   不能把“不能拉伸的图元”判定为自交曲线。
2、 跳过自交曲线,继续执行程序——能画个圈圈标注一下就更好了。这个不会弄,请求论坛大咖帮助啊。
3、CAD2018中调用“-presspull”命令——昨晚发现AutoCAD2018的“-presspull(按住并拖动)”命令可以直接操作图元而不需要像CAD2008一样“点击图元内部的点”才可以拉伸。但是没有试出来调用的方法,一直提示“-presspull”。


五、代码
  1. (defun C:PLLS ( / *error* error_bak );显示层按图层名高度 批量拉伸
  2. (print "\n请把需要拉伸的图层独立。不允许“空图层”和不能拉伸的图元!")

  3. ;;;获取打开状态的图层列表=====-=========================

  4.   (setq n 1)
  5. (while (setq lay (tblnext "layer" (not lay)))
  6.   (if (> (cdr (assoc 62 lay)) 0)
  7.     (if (= n 1)
  8.       (progn (setq date (cdr (assoc 2 lay))  ) (setq n 2))
  9. (print(setq date (strcat date " " (cdr (assoc 2 lay)))   ))
  10.       )
  11. ))
  12. ;;;获取打开状态的图层列表=====-=========================



  13.   
  14.     (setq i 0)
  15.    (setq str1 (mapcar '(lambda(x)(set(read(strcat"dl"(itoa(setq i(1+ i)))))x))(read (strcat"(" date ")"))))
  16.    (setq n 0)   
  17. (repeat (length (setq str1(reverse (setq str1(mapcar 'vl-princ-to-string str1)))))
  18. (print (setq XStuceng;|显示图层|; (nth n str1)))   ;获取一个打开的图层名


  19. (setq ss (ssget "x" (list(cons 8  XStuceng)))) ;按图层名称选择本层所有图元
  20. (sssetfirst nil ss)



  21.   

  22. ;;;  获取图层名内“-”与“m”之间的数值作为拉伸的高度============
  23. ;;;(ascii "M(-+" ) ;查询ascii码
  24.       (setq pos (vl-string-position 45 XStuceng))
  25.     (setq gaodu (atoi(substr XStuceng (+ pos 2) (1- (- (vl-string-position 77 XStuceng) pos)))));返回以后的字串符
  26. ;;;  获取图层名内“-”与“m”之间的数值作为拉伸的高度============




  27.   
  28.   (command "layer" "s" XStuceng "")
  29.   (setq m 0) ;序号的初值设为0
  30. (repeat (sslength ss);重复执行ss的长度的次数,即对象的个数
  31. (setq name (ssname ss m));得到选择集内第n个对象的图元名
  32. ;;; (setq ent (entget name));得到该对象的图元表





  33. ;;; 核心执行的“拉伸”命令在这里 ===========
  34. (if(=(command "extrude" name "" gaodu  ) nil);这句判断好像直接执行了,一点判断作用也没有,否的情况从来没执行过
  35. ;;;  (progn (setq ss2 (ssadd))
  36. ;;;  (ssadd name ss2)
  37. ;;;  (sssetfirst nil (ssadd (setq name (ssname ss (1- m))) ss2));
  38.   (progn (setq m (1+ m))
  39.     (princ m)
  40.     )

  41.   (progn(command "extrude" name "" gaodu  )
  42. (setq m (1+ m))
  43. ;;;    (setq m(+ m 100))
  44.         )
  45.   );if cishu_nil   ;序号M的数量加1
  46. ;;; 核心执行的“拉伸”命令在这里 ===========

  47.   
  48.   
  49.   )
  50.   
  51. (setq n (1+ n))
  52. )

  53.   (prin1)
  54. );程序结束




  55. (defun C:PLLS2 () ;查找批量拉伸失败的那个图元
  56.   (command "regen")
  57. (setq ss2 (ssadd))
  58.   (sssetfirst nil (ssadd (setq name (ssname ss (1- m))) ss2))
  59. )



六、实例文件




上面的这个文件下载后显示为“无效文件”,百度网盘连接为:
提取码:1234





1、文件中共有三个不能拉伸的“自交曲线”,打开线宽就可以很明显的看到。程序中断的时候用“plls2”就可以看到,但只能找到本次卡住的那一个。

2、示例文件在在三维视图下的,打开“视图”工具条即可调整视图角度,或者shift+鼠标中键。


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x

本帖被以下淘专辑推荐:

  • · 3D|主题: 8, 订阅: 0
发表于 2020-11-5 06:43:25 | 显示全部楼层
本帖最后由 wyl219 于 2020-11-5 07:02 编辑

command 只会返回nil...

为什么要分别extrude每个图元呢?直接extrude选择集不就好了

没用过3D相关命令,我的思路是:
1.遍历图层,寻找打开状态的,图层名符合要求的图层,并从图层名(lay)中获取拉伸高度h.
2.通过(ssget "x" (list(cons 8 lay)))获取该图层下所有对象
3.通过(command "extrude" ss "" h ) 自动拉伸能拉伸的对象,这样就能实现自动跳过不能拉伸的对象.
4.重新用(ssget "x" (list (cons 0 "~3DSOLID")(cons 8 lay)))获取该图层下所有不为三维实体的对象,这次获取到的就能不能拉伸的漏网之鱼.
5.遍历选择集,在组码10插入圆.

不太理解题主的问题所在,如果是需要对图层下的对象筛选以后,排除部分图元,可以ssdel以后拉伸选择集
另外还有一个思路,对一个选择集拉伸以后,选择集还在,但是拉伸后的对象图元名不在了,因此entget会返回nil,即对选择集拉伸以后,还能获取到信息表的对象是不能拉伸被跳过的对象
 楼主| 发表于 2020-11-5 22:07:19 | 显示全部楼层
wyl219 发表于 2020-11-5 06:43
command 只会返回nil...

为什么要分别extrude每个图元呢?直接extrude选择集不就好了

好的,谢谢。
 楼主| 发表于 2020-11-5 22:08:52 | 显示全部楼层

我再试一下选择集。第一次用选择集的时候记得是提示参数错误了。   现在想也可能是图层或别的原因导致的。现在已经排除了这些干扰,可以再试一下。谢谢提醒:P
 楼主| 发表于 2020-11-5 22:17:46 | 显示全部楼层
wyl219 发表于 2020-11-5 06:43
command 只会返回nil...

为什么要分别extrude每个图元呢?直接extrude选择集不就好了

3.通过(command "extrude" ss "" h ) 自动拉伸能拉伸的对象,这样就能实现自动跳过不能拉伸的对象.
太感谢啦,这一句完美拉伸了所有可拉伸的图元
 楼主| 发表于 2020-11-5 23:25:51 | 显示全部楼层
(defun C:PLLS ( / *error* error_bak );显示层按图层名高度 批量拉伸
(print "\n请把需要拉伸的图层独立,关闭0层。不允许“空图层”和不能拉伸的图元!")
(setq ssbnls (ssadd))
  (command "-layer"  "off" "0" "")
;;;获取打开状态的图层列表=====-=========================

  (setq n 1)
(while (setq lay (tblnext "layer" (not lay)))
  (if (> (cdr (assoc 62 lay)) 0)
    (if (= n 1)
      (progn (setq date (cdr (assoc 2 lay))  ) (setq n 2))
(print(setq date (strcat date " " (cdr (assoc 2 lay)))   ))
      )
))
;;;获取打开状态的图层列表=====-=========================



  
    (setq i 0)
   (setq str1 (mapcar '(lambda(x)(set(read(strcat"dl"(itoa(setq i(1+ i)))))x))(read (strcat"(" date ")"))))
   (setq n 0)   
(repeat (length (setq str1(reverse (setq str1(mapcar 'vl-princ-to-string str1)))))
(print (setq XStuceng;|显示图层|; (nth n str1)))   ;获取一个打开的图层名


(setq ss (ssget "x" (list(cons 8  XStuceng)))) ;按图层名称选择本层所有图元
(sssetfirst nil ss)



  

;;;  获取图层名内“-”与“m”之间的数值作为拉伸的高度============
;;;(ascii "M(-+" ) ;查询ascii码
      (setq pos (vl-string-position 45 XStuceng))
    (setq gaodu (atoi(substr XStuceng (+ pos 2) (1- (- (vl-string-position 77 XStuceng) pos)))));返回以后的字串符
;;;  获取图层名内“-”与“m”之间的数值作为拉伸的高度============




  
  (command "layer" "s" XStuceng "")

  (command "extrude" ss "" gaodu )
  
(if (/=  (setq bunenglashen (ssget "x" (list (cons 0 "~3DSOLID")(cons 8 XStuceng))))nil);选择不能拉伸的图元
   (progn (sssetfirst nil bunenglashen)
;;; (setq ssbnls (ssadd ssbnls bunenglashen))

(setq k 0)
(repeat (sslength bunenglashen)
  (setq ssbnls (ssadd (ssname bunenglashen k) ssbnls))
  (setq k (1+ k))
)
(sssetfirst nil ssbnls)
     
     ));(progn   ;if


  
(setq n (1+ n))
)

  
(sssetfirst nil ssbnls)
  (prin1)
(if (= (tblobjname "layer" "0-未不能拉伸的图元") nil)
    (command "-layer" "m" "0-未不能拉伸的图元" "c" "6" "" "")
      (setvar "clayer" "0-未不能拉伸的图元")
  )


   (setq m 0) ;序号的初值设为0
(repeat (sslength ssbnls);重复执行ss的长度的次数,即对象的个数
(setq name (ssname ssbnls m));得到选择集内第n个对象的图元名
(setq ent (entget name);得到该对象的图元表
              pt1 (cdr (assoc 10 ent))
;;;              pt2 (cdr (assoc 10 (reverse ent)))
;;;              r          (* (getvar "DIMSCALE") 2)
        )
  (command ".CIRCLE" pt1 100 )(prin1)
  (setq m (1+ m))
)
  (sssetfirst nil ssbnls)
  
);程序结束



(defun C:PLLS2 () ;查找批量拉伸失败的图元
  (command "regen")
(sssetfirst nil ssbnls)
)
 楼主| 发表于 2020-11-6 19:12:48 | 显示全部楼层
本帖最后由 zxjing 于 2020-11-6 19:17 编辑
  1. ;兼容AutoCAD2018,设置为拉伸后删除图元。可以多次添加新图元进行拉伸
  2. (defun C:PLLS ( / *error* error_bak );显示层按图层名高度 批量拉伸
  3. (alert "\n请确保①已把需要拉伸的图层独立显示;②无“空图层”;③关闭0层和无关层!")
  4. (print "\n请把需要拉伸的图层独立,关闭0层。不允许“空图层”和不能拉伸的图元!")
  5. (setvar "DELOBJ" -1);设置拉伸后原图元是否保留。3,默认删除; 0,保留;-1,提示是否删除
  6. (setq ssbnls (ssadd))
  7.   (command "-layer"  "off" "0" "")

  8. (if (/= (getvar "clayer") "0-未能拉伸的图元")
  9. (command "-layer"  "off" "0-未能拉伸的图元" "")
  10. (command "-layer"  "off" "0-未能拉伸的图元" "y" ""))
  11. ;;;获取打开状态的图层列表=====-=========================

  12.   (setq n 1)
  13. (while (setq lay (tblnext "layer" (not lay)))
  14.   (if (> (cdr (assoc 62 lay)) 0)
  15.     (if (= n 1)
  16.       (progn (setq date (cdr (assoc 2 lay))  ) (setq n 2))
  17. (print(setq date (strcat date " " (cdr (assoc 2 lay)))   ))
  18.       )
  19. ))
  20. ;;;获取打开状态的图层列表=====-=========================



  21.   
  22.     (setq i 0)
  23.    (setq str1 (mapcar '(lambda(x)(set(read(strcat"dl"(itoa(setq i(1+ i)))))x))(read (strcat"(" date ")"))))
  24.    (setq n 0)   
  25. (repeat (length (setq str1(reverse (setq str1(mapcar 'vl-princ-to-string str1)))))
  26. (print (setq XStuceng;|显示图层|; (nth n str1)))   ;获取一个打开的图层名


  27. (setq ss (ssget "x" (list(cons 0 "~3DSOLID")(cons 8  XStuceng)))) ;按图层名称选择本层所有图元
  28. (sssetfirst nil ss)



  29.   

  30. ;;;  获取图层名内“-”与“m”之间的数值作为拉伸的高度============
  31. ;;;(ascii "M(-+" ) ;查询ascii码
  32.       (setq pos (vl-string-position 45 XStuceng))
  33.     (setq gaodu (atoi(substr XStuceng (+ pos 2) (1- (- (vl-string-position 77 XStuceng) pos)))));返回以后的字串符
  34. ;;;  获取图层名内“-”与“m”之间的数值作为拉伸的高度============




  35.   
  36.   (command "layer" "s" XStuceng "")

  37.   (command "extrude" ss "" gaodu )
  38.   
  39. (if (/=  (setq bunenglashen (ssget "x" (list (cons 0 "~3DSOLID")(cons 8 XStuceng))))nil);选择不能拉伸的图元
  40.    (progn (sssetfirst nil bunenglashen)
  41. ;;; (setq ssbnls (ssadd ssbnls bunenglashen))

  42. (setq k 0)
  43. (repeat (sslength bunenglashen)
  44.   (setq ssbnls (ssadd (ssname bunenglashen k) ssbnls))
  45.   (setq k (1+ k))
  46. )
  47. (sssetfirst nil ssbnls)
  48.      
  49.      ));(progn   ;if


  50.   
  51. (setq n (1+ n))
  52. )

  53.   
  54. (sssetfirst nil ssbnls)
  55.   (prin1)
  56. (if (= (tblobjname "layer" "0-未能拉伸的图元") nil)
  57.     (command "-layer" "m" "0-未能拉伸的图元" "c" "6" "" "")
  58.        (progn (setvar "clayer" "0-未能拉伸的图元")(command "-layer"  "on" "0-未能拉伸的图元" ""))
  59.   )


  60.    (setq m 0) ;序号的初值设为0
  61. (repeat (sslength ssbnls);重复执行ss的长度的次数,即对象的个数
  62. (setq name (ssname ssbnls m));得到选择集内第n个对象的图元名
  63. (setq ent (entget name);得到该对象的图元表
  64.         pt1 (cdr (assoc 10 ent))
  65. ;;;        pt2 (cdr (assoc 10 (reverse ent)))
  66. ;;;        r    (* (getvar "DIMSCALE") 2)
  67.   )
  68. (command ".CIRCLE" pt1 100 )(prin1)
  69.   (setq m (1+ m))
  70. )
  71.   (sssetfirst nil ssbnls)
  72.   
  73. );程序结束



  74. (defun C:PLLS2 () ;查找批量拉伸失败的图元
  75.   (command "regen")
  76. (sssetfirst nil ssbnls)
  77. )





  78. (defun C:PLLS3 () ;查找批量拉伸失败的那个图元
  79.   (command "regen")
  80. (setq ss2 (ssadd))
  81.   (sssetfirst nil (ssadd (setq name (ssname ss (1- m))) ss2))
  82. )



发表于 2020-11-6 20:51:45 | 显示全部楼层
本帖最后由 wyl219 于 2020-11-6 21:04 编辑

(if (/= ss nil))
可以修改为 (if ss )
(if (= ss nil))
可以修改为 (if (not ss ))


可以尝试一下以下代码:
;|
说明:筛选选择集ss中未被extrude命令处理的图元并画框标注
参数:ss:要被筛选的选择集
ss2:用于存放筛选出来的图元的选择集
返回值:无,但是ss2会被修改
|;
(defun flll_ss_by_extrude(ss ss2 / entmake_CIRCLE getbox old_lay en i)
        (vl-load-com)
        (setq entmake_CIRCLE (lambda (pt r)
                                                                                                 (entmake (list '(0 . "CIRCLE")
                                                                                                                                                '(8 . "0-未能拉伸的图元") ;图层
                                                                                                                                                (cons 10 pt) ;圆心
                                                                                                                                                (cons 40 r) ;半径
                                                                                                                                        )) ));画圆的临时函数
        (setq old_lay (getvar "CLAYER"));保存当前图层
        (if (tblobjname "layer" "0-未能拉伸的图元")
                (command "-layer"  "on" "0-未能拉伸的图元" "");如果有图层打开图层
    (command "-layer" "m" "0-未能拉伸的图元" "c" "6" "" "");如果没有图层,建立图层
        )
        (setq getbox (lambda (en) ;获取对象的最小包围盒
                                                                 (vla-GetBoundingBox (vlax-ename->vla-object en) 'll 'rr)  ;得到对象的包围盒
                                                                 (list (vlax-safearray->list ll) (vlax-safearray->list rr));返回左下右上坐标
                                                         ))
        (repeat (setq i (sslength ss))
                (setq i (1- i))
                (if  (entget (setq en (ssname ss i)))
                        (progn;如果能找到信息表,说明未被处理
                                (ssadd en ss2)
                                (apply 'entmake_CIRCLE (apply '(lambda (p1 p2)
                                                                                                                                                                 (list (mapcar '(lambda (x1 x2) (+ x1 (* (- x2 x1) 0.5))) p1 p2);包围盒的中点,圆心
                                                                                                                                                                         (* 0.5 (distance p1 p2));半径r
                                                                                                                                                                 ))
                                                                                                                                 (getbox en);获取最小包围盒
                                                                                                                         ));画圆
                        )
                )
        )
        (setvar "CLAYER" old_lay);恢复保存的图层
        (princ)
)


;|
说明:示例函数
|;

(defun c:ttt ( /)
        (setq ss (ssget (list(cons 0 "~3DSOLID"))));要被拉伸的选择集
        (if(not ss2)
                (setq ss2 (ssadd)));用于存放的选择集
        (command "EXTRUDE" ss "" 100 );批量拉伸
        (flll_ss_by_extrude ss ss2)
        (sssetfirst nil ss2)
        
)
(princ)



发表于 2020-11-6 20:56:14 | 显示全部楼层
建议写程序的时候遵照模块化的原则,这样修改和增减功能会方便很多
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2024-11-22 21:19 , Processed in 0.204237 second(s), 28 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表