lohas1118 发表于 2012-2-15 15:00:29

删重复线LISP,那里出了问题,不能使用.求指点

*********************************************************************************************************************
;;;;;;;删重复线
;;;内容:
;;;清重 LINE
;;;消除重线,不生成任何新的LINE
;;;程序没考虑图层,只要是重线,就处理
;;;内有详细的注释,帮助朋友理解开发思路。
;;;这个程序很复杂,用了很多技巧。希望能对朋友有帮助
;;;命令:c:see
(setvar "cmdecho" 0)
;;;子程序 (ran), 将LISP表按关键字排序。参数 'a' 为要排序的LISP表。
;;;例如执行程序:   (ran '((3 3.2) (5.4 4.8) (3 3) (-0.4 5.5) (3 3)))
;;;该程序将返回:   ((-0.4 5.5) (3 3) (3 3.2) (5.4 4.8))
(defun ran (a / b c d mn mx)
(setq      c(mapcar 'car a)
      mn (apply 'min c)
      mn (1- mn)
)
(while (< mn (setq mx (apply 'max c)))
    (setq c (subst mn mx c))
    (while (setq d (assoc mx a))
      (setq a (subst '(nil) d a)
            b (cons d b)
      )
    )
)
b
)
;;;子程序 (rz), 消去点 'p' 的 Z-坐标。
(defun rz (p) (list (car p) (cadr p)))
;;;子程序 (p-l1), 求点到直线距离程序的前半部分 (求常数'c1','c2'和'c3')。
;;;参数 'p1' 和 'p2' 为直线的两个端点。
(defun p-l1 (p1 p2 / x1 y1 x2 y2)
(setq      x1 (car p1)
      y1 (cadr p1)
      x2 (car p2)
      y2 (cadr p2)
      c1 (- y2 y1)
      c2 (- x1 x2)
      c3 (sqrt (+ (* c1 c1) (* c2 c2)))
      c1 (/ c1 c3)
      c2 (/ c2 c3)
      c3 (/ (- (* x2 y1) (* x1 y2)) c3)
)
)
;;;子程序 (p-l2), 求点到直线距离程序的后半部分 (返回距离值)。
;;;参数 'p0' 为点坐标。
(defun p-l2 (p0) (+ (* c1 (car p0)) (* c2 (cadr p0)) c3))
;;;子程序 (rddo1), 合并一条直线上的各线段。
(defun rddo1 (l2 / e el c1 c2 c3 ln1 ll1 ll2 ll3 ll4 lle len len1 p z)
(setq      ll (car l2)
      p1 (car ll)
      p2 (cadr ll)
      a1 (angle p1 p2)
      p3 (polar p1 (+ pi2 a1) mx)
      n(+ n (length l2))
)
;;;分别求出直线上某点到各线段上两个端点的距离, 并与实体名一同存入表 'll1'。
;;;表 'll1' 的格式为   ((距离1 实体名1) (距离2 实体名2) . . .)。
;;;'lle' 为各线段的实体名表, 格式为   (实体名1实体名2 . . .)
(p-l1 p1 p3)
(foreach ll l2
    (setq e   (last ll)
          ll1 (cons (list (p-l2 (car ll)) e) ll1)
          ll1 (cons (list (p-l2 (cadr ll)) e) ll1)
          lle (cons e lle)
    )
)
;;;'ll2' 为临时实体名表, 格式为 (实体名1 实体名2 . . .)。
;;;'ll4' 为合并完成后的线段表, 格式为 ((首端1 . 末端1) (首端2 . 末端2) . . .)。
(setq      ll1 (ran ll1)
      ln1 (+ mx (caar ll1))
      ll4 nil
)
(foreach ll ll1
    (setq ln (car ll)
          e(cadr ll)
    )
    (if      ll2
      (progn
;;;此时有重叠的线段。
      (setq ll3 (member e ll2)
            ll2 (if ll3
                  (append (cdr ll3) (cdr (member e (reverse ll2))))
;;;结束一条重线。
                  (cons e ll2)      ;将新重线的实体名加入 'll2'。
                  )
      )
      (if (not ll2)
;;;结束一条线的合并, 将其存入 'll4'。
          (setq      ll4 (cons (cons (polar p1 a1 ln) p2) ll4)
                ln1 ln
          )
      )
      )
      (progn
;;;此时没有重叠的线段。
      (if (equal ln1 ln mm)
          (setq ll4 (cdr ll4))                ;消去前一条线, 使首尾相接的两条线连续。
          (setq p2 (polar p1 a1 ln))      ;求出一条新线的起始点。
      )
      (setq ll2 (cdr ll))                ;将起点实体名加入 'll2'。
      )
    )
)
(if (> (setq len(length ll4)
               len1 (length lle)
         )
         len
      )
    (progn
      (repeat (- len1 len)
      (setq e          (car lle)
            lle (cdr lle)
      )
      (entdel e)
      )
;;;用表 'll4' 中的线段更新表 'lle' 中的线段。
      (foreach ll ll4
      (setq e          (car lle)
            lle (cdr lle)
            el(entget e)
            p          (assoc 10 el)
            z          (cdddr p)
            el(subst (cons 10 (append (car ll) z)) p el)
            el(subst (cons 11 (append (cdr ll) z)) (assoc 11 el) el)
      )
      (entmod el)
      )
    )
)
(setq n (- n len))
;;;每画 40 根线, 在提示行更新一次报数。
(if (> (- n n2) 40)
    (progn
      (setq n2 n)
      (princ (strcat st2 (itoa n)))
    )
)
)
;;;子程序 (rddo), 对一组同角度的线段进行重线合并。
;;;参数 'l0' 为线段表, 其格式为
;;;    ((首端1 末端1 实体名1) (首端2 末端2 实体名2) . . .)。
(defun rddo (l0 / e1 a1 p1 p2 p3 c1 c2 c3 ln l1 l2 ll ll1)
(setq      ll (car l0)
      p1 (car ll)
      p2 (cadr ll)
      l1 (list (list 0. ll))
)
;;;将 'l0' 中各项, 按距离进行分类存入表 'l1'
;;;'l1' 的格式为 ((距离1 (首端1 末端1 实体名1)
;;;                      (首端2 末端2 实体名2) . . .) . . .)
(p-l1 p1 p2)
(foreach ll (cdr l0)
;;;变量 'ln' 为该线段与首根直线的距离。
    (setq ln (p-l2 (car ll))
          l2 l1
    )
    (while (and (setq ll1 (car l2)) (not (equal ln (car ll1) mm)))
      (setq l2 (cdr l2))
    )
;;;将距离值近似的线段归入同一个子表内, 否则另开一个新的子表。
    (setq l1 (if ll1
               (subst (append ll1 (list ll)) ll1 l1)
               (cons (list ln ll) l1)
             )
    )
)
;;;对表 'l1' 中各组同距离 (即在一条直线上) 的线段进行重线合并。
(foreach l2 l1
    (setq l2 (cdr l2))
    (if      (cdr l2)
      (rddo1 l2)
    )                                        ;一组线多于一根才进行处理。
)
)
;;;主程序 (c:see), 合并或去除重线 (处理图内全部 LINE 实体)。
(defun c:EEE (/ osm mm      mx pi2 st1 st2 ss1 e1 el1 n n1 n2 a1 p1      p2 l1 ll
               ll1)
(gc)
(prompt "\n选取要处理的LINE<全选>:")
(if (not (setq ss1 (ssget '((0 . "LINE")))))
    (setq ss1 (ssget "x" '((0 . "LINE"))))
)
;;;变量 'mm' 为距离微量 (在该距离内的线段均视为重合)。
(command "undo" "be")
(setq      osm (getvar "osmode")
      mx(getvar "viewsize")
      mm(* 3e-4 mx)
      pi2 (/ pi 2)
      st1 "\r搜索到直线数: "
      st2 "\r已经去除重线数: "
      n   0
      n10
      n20
)
(setvar "osmode" 0)
(setvar "highlight" 0)
(princ "\n")
;;;对全体 LINE 实体, 按角度进行分类存入表 'l1'。
;;;'l1' 的格式为 ((角度1 (首端1 末端1 实体名1)
;;;                      (首端2 末端2 实体名2) . . .) . . .)。
(while (setq e1 (ssname ss1 n))
    (setq n   (1+ n)
          el1 (entget e1)
          p1(rz (cdr (assoc 10 el1)))
          p2(rz (cdr (assoc 11 el1)))
    )
    (if      (equal p1 p2 mm)
      (progn;;;线段长度小于 'mm', 认为是超短线, 做擦除处理。
      (entdel e1)
      (setq n1 (1+ n1))
      );;;将角度值近似的线段归入同一个子表内, 否则另开一个新的子表。
      (setq ll1      (list (list p1 p2 e1))
            a1      (angle p1 p2)
            a1      (rtos (if (< a1 pi)
                        a1
                        (- a1 pi)
                      )
                      2
                      3
                )
            ll      (assoc a1 l1)
            l1      (if ll
                  (subst (append ll ll1) ll l1)
                  (cons (cons a1 ll1) l1)
                )
      )
    )
;;;每处理 128 根线, 在提示行更新一次报数。
    (if      (= 127 (logand 127 n))
      (princ (strcat st1 (itoa n)))
    )
)
(princ (strcat st1
               (itoa n)
               (if (zerop n1)
                   ""
                   (strcat ".删除超短线 " (itoa n1))
               )
               ".\n"
         )
)
(setq      n1 (- n n1)
      n0
);;;对表 'l1' 中各组同角度的线段进行重线合并。
(foreach ll l1
    (setq ll (cdr ll))
    (if      (cdr ll)
      (rddo ll)
    );;;一组线多于一根才进行处理。
)
(princ (strcat st2
               (itoa n)
               ".还剩 "
               (itoa (- n1 n))
               " 条线."
         )
)
(redraw)
(command "undo" "e")
(setvar "osmode" osm)
(setvar "highlight" 1)
(princ)
)
;;;
(defun xd_GetObjectBoundingBox (ename / ll ur)
(vla-GetBoundingBox (vlax-ename->vla-object ename) 'll 'ur)
(list
    (vlax-safearray->list ll)
    (vlax-safearray->list ur)
)
)

AMTONNY 发表于 2012-2-15 15:00:30

试试这个,比较好用的

Andyhon 发表于 2012-2-15 15:58:04

;;;命令:c:see
...
...
;;;主程序 (c:see), 合并或去除重线 (处理图内全部 LINE 实体)。
(defun c:EEE (/ osm mm   ....
-------------------------------------
试试
Command: eee

lohas1118 发表于 2012-2-16 10:47:31

AMTONNY 发表于 2012-2-15 15:00 static/image/common/back.gif
试试这个,比较好用的

谢谢,不错.好用

lohas1118 发表于 2012-2-16 10:48:28

Andyhon 发表于 2012-2-15 15:58 static/image/common/back.gif
;;;命令:c:see
...
...


多谢指点,发现原来是命令错误.

laiz3000 发表于 2012-4-18 09:38:43

谢谢分享!~~~

F3117021 发表于 2012-4-19 19:49:45

谢谢分享,学习!!!!

qq229918602 发表于 2012-4-19 20:12:57

请问“子程序 (rz), 消去点 'p' 的 Z-坐标。”这一句是什么意思???谢谢

623080655 发表于 2012-8-9 14:20:28

我找了好久了才找到 谢谢了

燃烧 发表于 2012-9-15 16:47:45

我试了你的程序,会少掉很多线啊,我是用UG导出来的图试的!
页: [1] 2
查看完整版本: 删重复线LISP,那里出了问题,不能使用.求指点