firstinti 发表于 2012-4-26 11:08:16

写给新手,也谈已知选择集中根据实体类型筛选实体及代码优化

本帖最后由 firstinti 于 2012-4-26 11:11 编辑

看到斑竹在讨论这个问题,http://bbs.mjtd.com/thread-84990-1-1.html
刚好最近写程序也遇上,以前虽然也有做过但是没有系统考虑过,而且斑竹也提到代码简化的问题,所以现在整理一下把成果发上来,大家讨论讨论,一起感受下lisp的语言之美
我们目的就是要从一个已知选择集中剥离出需要的类型实体,一种办法可以采用网友lazybug 的办法:
(defun c:test ()
(setq ss1 nil ss2 nil)
(if (setq ss1 (ssget '((0 . "LINE,circle"))))
    (progn
      (setq ss2 (ssget "p" '((0 . "circle"))))
      (command "select" ss1 "")
      (setq ss1 (ssget "p" '((0 . "LINE"))))
    )
)
)
这个代码关键其实就是上面的红字部分,采用命令select来解决重复选择的问题,但是一般对我来说是尽量避免直接采用命令来嵌入程序,因为有时候会有副作用
我的做法是采用(sssetfirst nil ss),也可以达到目的
下面是筛选天正实体的一段代码:
(setq ss(ssget))
;墙
(setq ss-wall(ssget "p" (list(cons 0 "TCH_WALL"))))
(sssetfirst nil ss)
;窗
(setq ss-window(ssget "p" (list(cons 0 "TCH_OPENING")(cons71 1))))
(sssetfirst nil ss)
;柱
(setq ss-column(ssget "p" (list(cons 0 "TCH_COLUMN"))))
这两种办法既有区别也有相通之处,区别下面再说,相同之处就是如果要筛选出不同的实体集就需要不停的重复选择,筛选实体写多了的话就会有大段大段的重复代码。这其实不符合lisp精简高效的结构,所以代码需要优化。经验告诉我们,只要重复的,就是多余的。
比如下面这段代码:
(setq ss(ssget))
;圆
(setq ss-circle(ssget "p" (list(cons 0 "circle"))))
(sssetfirst nil ss)
;线
(setq ss-line(ssget "p" (list(cons 0 "*line"))))
(sssetfirst nil ss)
;文字
(setq ss-text(ssget "p" (list(cons 0 "*text"))))
sssetfirst nil ss)
仅仅筛选三个实体集,就写了这么长的一段,太冗长,这种情况可以用子函数解决:
(defun wmg-ssgetp (ss filter)
(sssetfirst nil ss)
(ssget "p" (list (cons 0 filter)))
)
(这里我顺便说一下,我习惯采用 (list (cons 0 filter)))这种结构,因为参数是可以变化的,这样的做法对于lisp来说好处非常多,而'((0 . "circle"))的局限比较多,尽量少用为好)
后面的代码就简单了:
(setq ss-circle(wmg-ssgetpss "circle") )
(setq ss-lline(wmg-ssgetpss "*line") )
(setqss-text(wmg-ssgetpss "*text") )
筛选选择集个数越多,子函数的优势越明显。但是,是不是觉得还是有很多代码结构是一样的?所以代码还可以进一步优化。
现在面临的问题就是:如何把筛选出的多个选择集赋给多个变量?这里我采用的是字符串转为变量的办法,看看下面这段代码:
(defun c:tt ()
(setq ss (ssget))
(setq vartxtlst (list "ss1" "ss2" "ss3")
filterlst (list "circle" "*line" "*text")
)
(mapcar (function (lambda (x y) (set x (wmg-ssgetp ss y))))
   (mapcar 'read vartxtlst)
   filterlst
)
)
上面这段代码有两个小技巧,一个是read函数,一个是set函数,这两个函数其实用处是相当大的,但是很容易被忽略,我个人是把这样的函数归类为代码函数,就是专门用来优化程序语言本身的函数,程序优化后,完整的代码如下:
(defun c:tt ()
(defun wmg-ssgetp (ss filter)
(sssetfirst nil ss)
(ssget "p" (list (cons 0 filter)))
)

(setq ss (ssget))
(setq vartxtlst (list "ss1" "ss2" "ss3")
filterlst (list "circle" "*line" "*text")
)
(mapcar (function (lambda (x y) (set x (wmg-ssgetp ss y))))
   (mapcar 'read vartxtlst)
   filterlst
)
)

到此好像大功告成了,但是真的就结束了么?不是的,其实上面的代码是有问题的,上面代码运行是不会得到想要的结果的。
问题在哪?其实是出在 (sssetfirst nil ss)这个语句上,正确的做法是把 (sssetfirst nil ss)改为(vl-cmdf "select" ss ""),这也就是前面我说有区别的原因。
最后的代码:
(defun c:tt ()

(defun wmg-ssgetp (ss filter)   
    (vl-cmdf "select" ss "")
    (ssget "p" (list (cons 0 filter)))
)

(setq ss (ssget))
(setq vartxtlst (list "ss1" "ss2" "ss3")
filterlst (list "circle" "*line" "*text")
)
(mapcar (function (lambda (x y) (set x (wmg-ssgetp ss y))))
   (mapcar 'read vartxtlst)
   filterlst
)
)
但是,这样就完了?只要你愿意,你完全可以把上述代码写成一个函数,以后直接调用就好了,lisp的优化之路永远没有尽头。
=======================================================
其实好几年我一直在明经潜水,在这里学习了很多,收获了很多,今天刚好看到斑竹的问题,突然想特别写一个给新手的帖子,因为我也是从新手菜鸟过来的,但是个人水平很差,其实不应该写这些的,希望高手包含。

xiaxiang 发表于 2012-7-11 08:29:27

说得非常好!之前没有关注到这个帖子

fangmin723 发表于 2020-5-29 11:11:13

(defun C:swed(/ ss ssgetpy)
      (defun ssgetpy(ssall entpy)
                (sssetfirst nil ssall)
                ;(vl-cmdf "SELECT" ssall "")
                (ssget "P" (list (cons 1 entpy)))
      )
      (if (setq ss (ssget '((0 . "*TEXT") (1 . "A*,B*,C*,D*") (7 . "宋 宽0.7 高3,宋 宽0.75 高3"))))
                (progn
                        (setq
                              alst (ssgetpy ss "A*")
                              blst (ssgetpy ss "B*")
                              clst (ssgetpy ss "C*")
                              dlst (ssgetpy ss "D*")
                        )
                )
      )
)
这个程序中ssgetpy函数只有效一次,不知道是啥原因!

masterlong 发表于 2021-2-17 03:08:51

直接保存选择集是不行的,可以变通一下,选择集转图元表,再转handent表,后表存为全局LDATA。不要再问记录以后怎么调用,能实现记录,自然就知道了该如何读取。

fdb2007 发表于 2012-4-26 13:22:04

学习了,现在还是新手,要学的还很多啊

cabinsummer 发表于 2012-4-26 14:45:42

我的明细表程序中也有大量的read和set、eval等函数

自贡黄明儒 发表于 2012-4-26 15:58:22

写得太好了!!!

gcho 发表于 2012-4-26 16:53:34

楼主写的很好,很值得我们新手去研究。我这儿有一处选择集的问题想请教,比如程序中用entmake创建了text的list 表,可否将这个表定义为一个新的ssget,供程序下一步提取应用?

VBALISPER 发表于 2012-4-26 18:39:59

偶也来学习学习

smartstar 发表于 2012-4-26 18:50:37

做个记号,回头来学习。

yjr111 发表于 2012-6-27 22:05:09

代码优化:质和量。。。无止境啊

dalin1985 发表于 2012-6-27 22:37:29

谢谢楼主,学习学习。

hhh454 发表于 2012-6-28 08:39:48

讲的很详细,学习无止境
页: [1] 2 3 4
查看完整版本: 写给新手,也谈已知选择集中根据实体类型筛选实体及代码优化