masterlong 发表于 2019-6-22 14:02:37

多组条件过滤选择【2022.02.10更新】

本帖最后由 masterlong 于 2022-2-10 21:45 编辑

看到群里经常有讨论多组条件过滤选择
可能是程序本身要求比较简单
所以采用的方法也略显粗糙
当然这也没啥不对
程序能用就行

不过我的观点是
随着编程水平的提高
程序也会越复杂
相应用到复杂过滤分组的可能性也越大
掌握一个相对灵活易用的方法
更有利于把精力
投入到程序主要功能的编写上

;------------------------------------------------------------------------------------------------------

发一个自己用的多组条件过滤选择的函数
选择后分组
(ssgetsome( mode ptlist someflist divmode))
返回
所有图元选择集or(所有图元选择集 (第1条件图元列表)   (第2条件图元列表)... )




;999```多组条件过滤选择    ;;(ssgetsome   mode ptlist someflist divmode)
;|
第1个参数为字符,指定选择方式; 第2个参数为多点表(WCS坐标,点表不作校验)或图元;
""——手动;    ——任意格式(始终忽略)
"x" ——全图;    ——任意格式(始终忽略)
"p" ——前一选择;——任意格式(始终忽略)
"w" ——窗口内选择;——点表(3点以上自动转换为最小正交包围盒两点) ——图元(自动转换为正交包围盒两点)
"wp" ——多边形选择;——多点表            ——闭合PL线(自动转换PL线节点为多点表[忽略圆弧段]),其它图元取最小正交包围盒四点
"c" ——窗口交叉选择; ——点表(3点以上自动转换为最小正交包围盒两点) ——图元(自动转换为最小包围盒两点)
"cp" ——多边形交叉选择;——多点表            ——闭合PL线(自动转换PL线节点为多点表,忽略圆弧段),其它图元取最小正交包围盒四点

第3个参数为由多个过滤条件组成的复合表。
例:
'(
((0 . "insert")(2 . "灯1*"))
((0 . "text")(8 . "f_hide"))
)
自动转换为ssget可以识别的过滤条件,传递给ssget进行一次选择
'( (-4 . "<or")
(-4 . "<and") (0 . "text")(8 . "f_hide") (-4 . "and>")
(-4 . "<and") (0 . "insert")(2 . "灯1*") (-4 . "and>")
(-4 . "or>")
)
选择完成后,再根据子表进行二次过滤分组

第4个参数 T/nil ,控制是否细分
未选择到任何图元,函数返回nil
成功选择
————要求细分时,函数返回一个复合表。第一个子表为本次选择的所有图元选择集,其后子表均为图元列表或nil,并与第3个参数子表一一对应
————不要求时,函数返回选择集
【注意1】
若过滤条件复合表中各子表过滤条件之间有交叉,返回子表中的图元也是交叉存在的(即存在重复)。
【注意2】
第2个参数提供图元时,即使该图元本身符合过滤条件,该图元也将被自动排除。
【注意3】
WP/CP模式时,若点表参数提供闭合PL线时,真假闭合均可,但是PL线节点数需>=3,同时非自交(自交点表不符合ssget‘WP/CP的执行条件)。
|;
;;使用教程
;|
;555````先建立多组过滤条件列表,各组条件之间不用考虑 <-4`and> + <-4`or> 的组合,此由函数自动完成拼接
(setq somefi
'(
   ((0 . "INSERT") (2 . "AAA*") (8 . "非打印云线"))
   ((0 . "INSERT") (2 . "BBB*") (-4 . "!=")(62 . 6))
   ((-4 . "<not")(2 . "AAA*,BBB*") (-4 . "not>"))
)
)
;555````调用函数进行过滤选择
(setq somess (ssgetsome "" nil somefi T))
;555````选择后分组调用
(setq ss0 (nth 0 somess)
ss1 (nth 1 somess)
ss2 (nth 2 somess)
ss3 (nth 3 somess)
)
|;
;
;999```多组条件过滤选择    ;;(ssgetsome   mode ptlist someflist divmode)
;
(defun ssgetsome( mode ptlist someflist divmode / box pt1 pt2 ss tmp temp1 temp2 someselsslist )
(setq mode (strcase mode))
;;点表处理
(cond
((or (= mode "W") (= mode "C"))
   (if (= (type ptlist) 'ENAME)
    (setq box (entbox ptlist)
      pt1 (carbox)
      pt2 (cadr box)
    )
    (setq box (npt2box ptlist)
      pt1 (carbox)
      pt2 (cadr box)
    )
   )
)
((or (= mode "WP") (= mode "CP"))
   (if (= (type ptlist) 'ENAME)
    (if (= (dxf 0 ptlist) "LWPOLYLINE")
   (setq tmpl ptlist
       ptlist (massoc 10 (entget ptlist))
       box (npt2box ptlist)
   )
   (setq box (entbox ptlist))
    )
    (setq box ptlist)
   )
)
)
(if box
(progn
   (zoomsave)
   (zoomptlist box 3)
)
)
;;过滤表处理
(setq temp1 (mapcar ''((x) (append '((-4 . "<and")) x '((-4 . "and>")))) someflist))
(setq temp2 '())
(mapcar ''((x) (setq temp2 (append x temp2))) temp1)
(setq oped_someflist (append '((-4 . "<or")) temp2 '((-4 . "or>"))))
;;执行过滤
(cond
((= mode "")   (setq ss (ssget oped_someflist)))
((= mode "X")   (setq ss (ssget "X"oped_someflist)))
((= mode "P")   (setq ss (ssget "P"oped_someflist)))
((= mode "W")   (setq ss (ssget "W"pt1 pt2 oped_someflist)))
((= mode "WP")(setq ss (ssget "WP" ptlistoped_someflist)))
((= mode "C")   (setq ss (ssget "C"pt1 pt2 oped_someflist)))
((= mode "CP")(setq ss (ssget "CP" ptlistoped_someflist)))
)
(if box (zoomload))
;;选择集首先排除用于点表参数的图元本身
(if (and ss tmpl (ssmemb tmpl ss))
(setq ss (ssdel tmpl ss)   tmpl (print "!!!"))
)
;;细分
(if (and ss divmode)
(progn
   ;;按过滤条件分类
   ;;由于在过滤条件中,可能存在通配符或者其它测试条件存在。分类分组的方式,不方便采用vl-remove-if-not去筛选
   ;;所以采用的多次ssget'P方式。速度会慢一点,但是省去了大量的代码
       ;;(setq someselsslist (mapcar ''((x) (oldss2act ss) (ssget "p" x)) someflist))    ;;希望返回子表为选择集时
   (setq someselsslist (mapcar ''((x) (oldss2act ss) (ss2list (ssget "p" x))) someflist))
   (oldss2act ss)
   (cons ss someselsslist)
)
ss
)
)
;999当前视窗save   ----(getvar "viewctr")得到的是UCS坐标
(defun zoomsave()
(setq zoom*savelist (list (getvar "ctab") (vlax-3D-Point (trans (getvar "viewctr") 1 0)) (getvar "viewsize")))
)
;999当前视窗load
(defun zoomload()
(if zoom*savelist
(progn
   (setvar "ctab" (car zoom*savelist))
   (vla-ZoomCenter *acad* (cadr zoom*savelist) (caddr zoom*savelist))
)
)
)
;999公共函数
;;单个物体的最小(正交)包围框---------------------------------这个程序在遇到无法显示的图元时,还是会出错的,比如形。天正图元会不会也不支持,未测试
(defun entbox ( ent / ll ur )
(vla-getboundingbox (vlax-ename->vla-object ent) 'll 'ur)
(mapcar 'vlax-safearray->list (list ll ur))
)
;999公共函数
;;求n个点的正交包围框
;;(setq npt (list p1 p2 p3 p4 ... ))
(defun npt2box( npt )
(list
(apply 'mapcar (cons 'min npt))
(apply 'mapcar (cons 'max npt))
)
)
;999公共函数
;;dxf获取图元某个dxf组码(内参不限种类顺序::: n ent )
(defun dxf( n ent / temp )
(if (/= (type n) 'int)
(setq tempent
    ent n
    ntemp
)
)
(if (= (type ent) 'ENAME)
(setq temp (entget ent))
(setq temp ent)
)
(cdr (assoc n temp))
)
;999公共函数
;;返回包含每一出现在列表中的指定键的cdr(点对的后部分)的列表<适合处理pl线>
;;例 (massoc 40 (entget (car (entsel)))) 每个顶点的宽度
;;返回 (0.0 0.0 200.0 0.0)
(defun massoc( key alist / x nlist)
(if (= (type alist) 'ename)
(setq nlist (entget alist))
(setq nlist alist)
)
(mapcar 'cdr (vl-remove-if-not ''((x) (= (car x) key)) nlist))
)
;999公共函数
;;以指定点表的包围框中心,缩放窗口——————主要用来保证后续可执行 (ssget 'CP/'WP ptlist)
(defun zoomptlist( ptlist sc / box x midpo )
(setq box (npt2box ptlist))
(setq midpo (getmidpo box))
(vla-ZoomCenter (vlax-get-acad-object) (vlax-3d-point midpo) (* sc (- (cadr (cadr box)) (cadr (car box)))))
box
)
;999公共函数
;;求点对中点
(defun getmidpo( pts / P1 P2 X Y )
(setq p1 (car pts) p2 (cadr pts))
(if (= (length p1) (length p2))
nil
(setq p1 (list (car p1) (cadr p1))
    p2 (list (car p2) (cadr p2))
)
)
(mapcar '(lambda (X Y) (/ (+ X Y) 2.0)) P1 P2)
)
;999公共函数
;;选择集转为图元列表
(defun ss2list ( ss / n i elist )
(cond
((= (type ss) 'Pickset)
   (setq n(sslength ss)
   i n
   elist '()
   )
   (repeat n
    (setq i (1- i))
    ;;如果没有这个if,那么选择集中被删除的图元,也会被加入到列表之中————但是极其偶尔也有可能,图元不存在但是能entget(遇到过一次,原因不明,或许是CAD的BUG)
    (if (entget (ssname ss i))
   (setq elist (cons (ssname ss i) elist))
    )
   )
   elist
)
((= (type ss) 'ename)
   (list ss)
)
((= (type ss) 'list)
   (vl-remove-if-not ''((x) (and (= (type x) 'ename) (entget x))) ss)
)
( T NIL)
)
)
;999公共函数
;;图元列表转为选择集(判断图元是否存在,空表时返回空选择集)
(defun list2ss( biao / ss )
(cond
((= (type biao) 'list)
   (setq biao (vl-remove-if-not ''((x) (and (= (type x) 'ename) (entget x))) biao))
   (setq ss (ssadd))
   (mapcar '(lambda (x) (if (entget x) (setq ss (ssadd x ss)))) biao)
   (if ss ss (ssadd))
)
((= (type biao) 'ename)
   (ssadd biao)
)
((= (type biao) 'Pickset)
   (setq biao (ss2list biao))
   (setq biao (vl-remove-if-not ''((x) (and (= (type x) 'ename) (entget x))) biao))
   (setq ss (ssadd))
   (mapcar ''((x) (setq ss (ssadd x ss))) biao)
   ss
)
( T (ssadd))
)
)
;999公共函数
;;一个已存在的选择集,设置成当前选择集
(defun oldss2act( oldss )
(sssetfirst Nil oldss);;将选择集设为夹点显示模式
(ssget "i")
(sssetfirst nil nil)
)







masterlong 发表于 2022-2-10 21:25:36

这个函数的编写思路

首先是尽量模拟ssget本身的书写格式

其次可以根据指定的选择方式
传递一个图元转化为点表
比如指定“WP”同时传递一个PL图元
函数会提取PL的顶点进行多边形选择

第三是简化多组过滤条件的编写

具体的详见函数开头的注释部分

masterlong 发表于 2019-6-22 14:03:53

本帖最后由 masterlong 于 2022-2-10 21:00 编辑

首次使用代码模式发帖
结果是这样?:(

总算掌握了代码发帖的奥义

迷失2004 发表于 2019-6-23 12:11:07

谢谢分享,对我有帮助

USER2128 发表于 2019-6-24 09:38:43

要为单独的一行才行

masterlong 发表于 2019-6-24 19:41:19

本帖最后由 masterlong 于 2019-6-24 19:45 编辑 <br /><br />实验半天不成功<br><br>

masterlong 发表于 2019-6-24 19:45:51

还是不成功
是浏览器的问题?
算了不管了

e2002 发表于 2019-6-24 20:16:45

好像是有点问题,不是总能成功的加入代码并语法高亮

ynhh 发表于 2019-6-25 08:36:40

谢谢分享

sdls 发表于 2019-6-28 21:08:39

虽然现在不知道怎么使用,但感谢楼主的无私分享!

masterlong 发表于 2022-2-10 20:50:10

做了点更新重新上传
页: [1] 2 3
查看完整版本: 多组条件过滤选择【2022.02.10更新】