明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 1858|回复: 4

[已解答] gu 版《基于方位角计算的拓扑多边形自动构建快速算法》的源码

[复制链接]
发表于 2020-5-14 22:29:44 | 显示全部楼层 |阅读模式
5明经币
本帖最后由 Gu_xl 于 2021-3-3 15:39 编辑

帖子【Gu_xl】基于方位角计算的拓扑多边形自动构建快速算法 》,

其地址
http://bbs.mjtd.com/forum.php?mod=viewthread&tid=82692&extra=page%3D2%26filter%3Dtypeid%26typeid%3D109%26orderby%3Ddateline



待写的程序需要参考 gu 版“构建多边形”的思路, 源码谁能共享一下。

由于本人的发帖数未能达到要求,帖子中的隐藏内容看不到。





最佳答案

查看完整内容

一些程序用到的函数
发表于 2020-5-14 22:29:45 | 显示全部楼层
  1. ;;;===============================================================================================
  2. ;;;基于方位角计算的拓扑多边形自动构建快速算法
  3. ;;;===============================================================================================
  4. ;;;线段图元进行预处理,构建线段图元表,自动交点打断后生成图元表,参见论坛里其他帖子,预处理后的直线、圆弧互相首位连接
  5. ;;;(gxl-Break_ss ss)

  6. ;;;根据线段图元表构建二维坐标表'((首端点 末端点)  ...)
  7. (defun gxl-ent->Coordinates (enLst)
  8.   (mapcar '(lambda (x)
  9.      (list (list (car (setq a (vlax-curve-getStartPoint x))) (cadr a))
  10.    (list (car (setq a (vlax-curve-getendPoint x))) (cadr a))
  11.      ) ;_ list
  12.    ) ;_ lambda
  13.   enlst
  14.   ) ;_ mapcar
  15. ) ;_ defun
  16. ;;;根据二维坐标表建立弧段拓扑邻接表,'((弧段序号 (首端点关联表 ...) (末端点关联表 ...))...),从 1 开始
  17. ;|若某一弧段N 的首端点与另一弧段
  18. 相关联, 则在弧段拓扑邻接关系表中标记为N ; 若
  19. 末端点与另一弧段相关联, 则标记为- N
  20. |;
  21. ;;;如果拓扑表中有nil,则表明线段有断头、悬挂的情况
  22. (defun gxl-Toupu-LineList (Coordinates / toupulist nn n k pstart pend pl new old t2)
  23.   ;;;测试时间
  24.   (setq t2 (getvar "cdate"))
  25.   (setq nn (length Coordinates)
  26. n 1)
  27.     ;;;建立一个拓扑空表 '((1 '() '()) (2 '() '()) ...),以序号索引
  28.   (repeat nn
  29.     (setq toupulist (append toupulist (list (list n nil nil))))
  30.     (setq n (1+ n))
  31.     )
  32.   (setq n 0
  33. to (* nn nn))
  34.   (GXL-SYS-PROGRESS-INIT "拓扑邻接表" to)
  35.   (repeat nn
  36.     (setq pstart (car (setq pl (nth n Coordinates)))
  37.   pend (cadr pl)
  38.   )
  39.     (setq k 0)
  40.     (repeat nn
  41.       (GXL-SYS-PROGRESS   to -1)
  42.       (if (/= n k)
  43. (progn
  44.   (setq pstart1 (car (setq pl (nth k Coordinates)))
  45.   pend1 (cadr pl)
  46.   )
  47.   (if (equal pstart pstart1 0.000001)
  48.     (progn
  49.       (setq old (assoc (1+ k) toupulist))
  50.       (setq new (list (1+ k) (append (cadr old) (list (1+ n))) (caddr old)))
  51.       (setq toupulist (subst new old toupulist))
  52.       )
  53.     (if (equal pstart pend1 0.000001)
  54.       (progn
  55.       (setq old (assoc (1+ k) toupulist))
  56.       (setq new (list (1+ k) (cadr old) (append (caddr old) (list (1+ n)))))
  57.       (setq toupulist (subst new old toupulist))
  58.       )
  59.       )
  60.     )
  61.   (if (equal pend pstart1 0.000001)
  62.     (progn
  63.       (setq old (assoc (1+ k) toupulist))
  64.       (setq new (list (1+ k) (append (cadr old) (list (* -1 (1+ n)))) (caddr old)))
  65.       (setq toupulist (subst new old toupulist))
  66.       )
  67.     (if (equal pend pend1 0.000001)
  68.       (progn
  69.       (setq old (assoc (1+ k) toupulist))
  70.       (setq new (list (1+ k) (cadr old) (append (caddr old) (list (* -1 (1+ n))))))
  71.       (setq toupulist (subst new old toupulist))
  72.       )
  73.       )
  74.     )
  75.   )
  76. )
  77.       (setq k (1+ k))
  78.       )
  79.     (setq n (1+ n))
  80.     )
  81.   (GXL-SYS-PROGRESS-DONE)
  82.   (princ " \n弧段拓扑邻接表")
  83.   (GXL-SYS-TIMEOUT t2)
  84.   toupulist
  85.   )
  86. ;;;根据建立的弧段拓扑邻接表,按照最小角法则搜索多边形,返回 弧段与多边形拓扑关联表 '((多边形序号 (弧段号 ...))...)
  87. ;|一条弧段可作为一个或两个多边形的组成边而
  88. 存在, 亦即从一条弧段出发最多可以搜索出两个正确
  89. 的多边形. 如图2 所示, 若从弧段A 1 的一端O 出发,
  90. 并把它作为起始弧段, 把与A 1 的O 端拓扑关联的其
  91. 它弧段作为中止弧段, 然后比较并找出与A 1 夹角最
  92. 小的中止弧段A 2, 并把A 2 作为新的起始弧段, 再从
  93. 它的另一端点出发重复以上过程继续搜索, 直到回到
  94. 出发弧段A 1 的另一端为止, 则所有搜索出的弧段就
  95. 构成了一个多边形. 同样, 从A 1 的O 端开始, 并把它
  96. 作为中止弧段, 把与它拓扑关联的其它弧段作为起始
  97. 弧段, 然后比较并找出与该弧段夹角最小的弧段, 并
  98. 把找出的弧段作为新的中止弧段, 再从新弧段的另一
  99. 端点出发重复以上搜索过程, 直到回到A 1 的另一端
  100. 为止, 则所有搜索出的弧段就构成了另一个多边形.
  101. 这样, 从一条弧段出发可以跟踪出两个多边形, 此方
  102. 法可称为多边形搜索的最小角法则.
  103. 多边形的搜索按照最小角法则进行. 从编号为
  104. 1 的弧段的始端出发, 查找弧段拓扑邻接表中与该
  105. 端点关联的弧段, 按照最小角法则可以搜索出两个
  106. 多边形. 依照上述方法, 依次把其它弧段作为开始弧
  107. 段, 共可找出2N (N 为总弧段数) 个多边形. 搜索过
  108. 程中, 记录构成多边形的弧段编号(一弧段首端与上
  109. 一弧段关联用正边号, 否则用负边号) 和弧段数, 即
  110. 形成多边形与弧段的拓扑关联表.
  111. |;
  112. (defun gxl-MakePolyList (toupulist Coordinates      /       PolyTouPuList nn n
  113.    pstart   pend     flag     p0       p1 a0 a1
  114.    a2     B1      B2       polytoupu toupu0 next t2
  115.   )
  116.     ;;;测试时间
  117.   (setq t2 (getvar "cdate"))
  118.   (setq nn (length toupulist)
  119. n 0
  120. to nn)
  121.   (GXL-SYS-PROGRESS-INIT "拓扑多边形" to)
  122.   (repeat nn
  123.     (GXL-SYS-PROGRESS   to -1)
  124.     (setq pstart (car (nth n Coordinates))
  125.   pend (cadr (nth n Coordinates))
  126.   flag t
  127.     ) ;_ setq
  128.     ;;;首端点搜索多边形
  129.     (setq p0 pstart
  130.   p1 pend
  131.   a0 (angle p0 p1) ;_ 首端点弧段角度
  132.   toupu0 (cadr (nth n toupulist)) ;_ 首端点弧段拓扑邻接表
  133.   polytoupu (list (1+ n))
  134.   )
  135.    
  136.     (while flag
  137.       ;;;计算最小角度相邻边
  138.       (setq toupu0
  139.      (vl-sort toupu0
  140.       '(lambda (e1 e2)
  141. (if (> e1 0)
  142.    (setq a1 (angle (car (nth (1- e1) Coordinates))  (cadr (nth (1- e1) Coordinates))))
  143.    (setq a1 (angle (cadr (nth (abs (1+ e1)) Coordinates))  (car (nth (abs (1+ e1)) Coordinates))))
  144.    )
  145. (if (> e2 0)
  146.    (setq a2 (angle (car (nth (1- e2) Coordinates))  (cadr (nth (1- e2) Coordinates))))
  147.    (setq a2 (angle (cadr (nth (abs (1+ e2)) Coordinates))  (car (nth (abs (1+ e2)) Coordinates))))
  148.    )
  149. (if (>= a0 a1) (setq B1 (- a0 a1)) (setq B1 (+ 2pi (- a0 a1))))
  150. (if (>= a0 a2) (setq B2 (- a0 a2)) (setq B2 (+ 2pi (- a0 a2))))
  151. (< B1 B2)
  152. )
  153.       )
  154.     )
  155.       (setq polytoupu (append polytoupu (list (setq next (car toupu0))))) ;_ next 下一邻接边序号
  156.       (if (> next 0)
  157. (progn
  158.   (setq p0 (cadr (nth (1- next) Coordinates))
  159. a0 (angle p0 (car (nth (1- next) Coordinates)))
  160. toupu0 (caddr (nth (1- next) toupulist))
  161. )
  162.   (if (equal p0 pend 0.00001) (setq flag nil))
  163.   )
  164. (progn
  165.   (setq p0 (car (nth (abs (1+ next)) Coordinates))
  166. a0 (angle p0 (cadr (nth (abs (1+ next)) Coordinates)))
  167. toupu0 (cadr (nth (abs (1+ next)) toupulist))
  168. )
  169.   (if (equal p0 pend 0.00001) (setq flag nil))
  170.   )
  171. )
  172.       
  173.       )
  174.     (setq PolyTouPuList (append PolyTouPuList (list polytoupu)))
  175.    
  176.     ;;;末端点搜索
  177.     (setq p0 pend
  178.   p1 pstart
  179.   a0 (angle p0 p1) ;_ 起点角度
  180.   toupu0 (caddr (nth n toupulist))
  181.   polytoupu (list (* -1 (1+ n)))
  182.   flag t
  183.   )
  184.     (while flag
  185.       ;;;计算最小角度相邻边
  186.       (setq toupu0
  187.      (vl-sort toupu0
  188.       '(lambda (e1 e2)
  189. (if (> e1 0)
  190.    (setq a1 (angle (car (nth (1- e1) Coordinates))  (cadr (nth (1- e1) Coordinates))))
  191.    (setq a1 (angle (cadr (nth (abs (1+ e1)) Coordinates))  (car (nth (abs (1+ e1)) Coordinates))))
  192.    )
  193. (if (> e2 0)
  194.    (setq a2 (angle (car (nth (1- e2) Coordinates))  (cadr (nth (1- e2) Coordinates))))
  195.    (setq a2 (angle (cadr (nth (abs (1+ e2)) Coordinates))  (car (nth (abs (1+ e2)) Coordinates))))
  196.    )
  197. (if (>= a0 a1) (setq B1 (- a0 a1)) (setq B1 (+ 2pi (- a0 a1))))
  198. (if (>= a0 a2) (setq B2 (- a0 a2)) (setq B2 (+ 2pi (- a0 a2))))
  199. (< B1 B2)
  200. )
  201.       )
  202.     )
  203.       (setq polytoupu (append polytoupu (list (setq next (car toupu0))))) ;_ next 下一邻接边序号
  204.       (if (> next 0)
  205. (progn
  206.   (setq p0 (cadr (nth (1- next) Coordinates))
  207. a0 (angle p0 (car (nth (1- next) Coordinates)))
  208. toupu0 (caddr (nth (1- next) toupulist))
  209. )
  210.   (if (equal p0 pstart 0.00001) (setq flag nil))
  211.   )
  212. (progn
  213.   (setq p0 (car (nth (abs (1+ next)) Coordinates))
  214. a0 (angle p0 (cadr (nth (abs (1+ next)) Coordinates)))
  215. toupu0 (cadr (nth (abs (1+ next)) toupulist))
  216. )
  217.   (if (equal p0 pstart 0.00001) (setq flag nil))
  218.   )
  219. )
  220.       
  221.       )
  222.     (setq PolyTouPuList (append PolyTouPuList (list polytoupu)))
  223.    

  224.     (setq n (1+ n))
  225.     )
  226.   (GXL-SYS-PROGRESS-DONE)
  227.     (princ " \n多边形拓扑 ")
  228.   (GXL-SYS-TIMEOUT t2)

  229.   PolyTouPuList
  230.   )
  231. ;;;多余多边形的消除
  232. ;|由于按照最小角法则搜索出的多边形, 其中部
  233. 分是重复的(例如“岛”被搜索了两次) , 部分是错误
  234. 的(例如外围轮廓多边形) , 因此这两种多边形需要
  235. 去除. 其中重复多边形的去除是从多边形与弧段的
  236. 拓扑关联表中按照边数相等, 且边号绝对值相等的
  237. 原则来进行; 而错误多边形的去除则按照下面原则
  238. 进行: 一个多边形与另一多边形有公共边, 同时它又
  239. 包含另一多边形的非公共边上一点, 则该多边形是
  240. 错误多边形.
  241. |;
  242. (defun gxl-dumpPolyTouPuList (PolyTouPuList / rtn pl nn n a)
  243.   (setq pl PolyTouPuList
  244. nn (length pl)
  245. )
  246.   (princ "\n处理多余多边形...")
  247.       ;;;测试时间
  248.   (setq t2 (getvar "cdate"))
  249. (while (setq a    (car pl)
  250.            rtn  (cons a rtn)
  251.            pl (vl-remove-if '(lambda (x) (equal (vl-sort (mapcar 'abs x) '<) (vl-sort (mapcar 'abs a) '<))) pl)
  252.      )
  253.   )
  254.   (GXL-SYS-TIMEOUT t2)

  255.   (reverse rtn)
  256.   )
  257. ;;;测试
  258. (defun c:tt ()
  259.   (setundoerr)
  260.   (princ "\n自动拓扑多边形测试!编制:Gu_xl 2010年8月")
  261.   (princ "\n选择线段:")
  262.   ;;;选择的线段必须已经做完打断预处理,请自行添加处理代码
  263.   (setq ss (ssget '((0 . "line,arc"))))
  264.   (setq t1 (getvar "cdate"))
  265.   (setq ssl (GXL-SEL-SS->LIST ss))
  266.   (setq coordlist (gxl-ent->Coordinates ssl))
  267.   (setq touplist (gxl-Toupu-LineList coordlist))
  268.   (setq polylist (gxl-MakePolyList touplist coordlist))
  269.   (setq polylist (gxl-dumpPolyTouPuList polylist))
  270.   (setq n 1)
  271.   (foreach poly polylist
  272.     (setq enlist (mapcar '(lambda (x) (nth (1- (abs x)) ssl)) poly)
  273.   enss (GXL-SEL-LIST->SS enlist)
  274.   )
  275.     (setq en (entlast))
  276.     (command "copy" enss "" '(0 0 0) '(0 0 0))
  277.     (setq enss (GXL-SEL-ENTNEXTALL en))
  278.     (command "pedit" (ssname enss 0) "y" "j" enss "" "")
  279.     (setq en (entlast))
  280.     (gxl-CH_Ent en 62 1)
  281.     (gxl-CH_Ent en 8 "多边形层")
  282.     )
  283.   (princ "\n总计 ")
  284.   (GXL-SYS-TIMEOUT t1)
  285.   (princ "\n共生成 ")
  286.   (princ (length polylist))
  287.   (princ " 个多边形!")
  288.   (reerr)
  289.   )




一些程序用到的函数[code="lisp]
;;;==================================================================
;;;(gxl-Sys-TimeOut t1) 耗尽用时计算函数
;;;==================================================================
(defun gxl-Sys-TimeOut (t1 / t2 t3 t4 t5 t6 t7 t8)
(setq t2 (getvar "Cdate"))
(setq t3 t1)
(setq t4 (fix (* 100 t3))
t5 (- (fix (* 10000 t3)) (* t4 100))
t6 (- (* 1000000 t3) (* t5 100) (* t4 10000))
t7 (+ (* t4 3600) (* t5 60) t6)
)
(setq t3 t2)
(setq t4 (fix (* 100 t3))
t5 (- (fix (* 10000 t3)) (* t4 100))
t6 (- (* 1000000 t3) (* t5 100) (* t4 10000))
t8 (+ (* t4 3600) (* t5 60) t6)
)
(princ "\n 用时 ")
(princ (- t8 t7))
(princ " 秒 ")
(princ)
)
;;;================================================================================================
;;; 进程条初始化 (gxl-Sys-Progress-Init 提示 进程总数)
;;; 进程步进 (gxl-Sys-Progress 进程总数 -1)
;;; 进程结束 (gxl-Sys-Progress-Done)
(setq *ProgressID* 0
*ProgressPrompt* ""
*ProgressBFB* " 0%")

(defun gxl-Sys-Progress-Init (str to)
(if *FlagINIT* (alert "上一次进程条没有结束!"))
(setq *ProgressID* 0
*ProgressTo* to
*ProgressPrompt* str
*ProgressBFB* 2
*FlagINIT* T)
)
(defun gxl-Sys-Progress-Done ()
(setq *ProgressID* 0
*ProgressTo* nil
*ProgressPrompt* ""
*ProgressBFB* 2
*FlagINIT* nil)
(setvar "modemacro" "")
)

;;;进程条函数,to 为进程总数,i为已到达进程数
;;;第一次使用 i应为1,以后 i = -1 为步进数,也可以为已到达进程数

(defun gxl-Sys-Progress (to i / CS_TEXT MYI bfb corstate LL)
;(setq cs_text ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
;(setq corstate (getvar "coords"))
;(setvar "coords" 0)
;(setq cs_text "||||||||||||||||||||||||||||||"
; LL (strlen cs_text)
(if (and *FlagINIT* *ProgressTo*)
(setq to *ProgressTo*)
)
(setq cs_text "████████████████████"
LL (strlen cs_text)
)
(if (= -1 i)
(setq i (1+ *ProgressID*)
*ProgressID* i
)
(setq *ProgressID* i)
)
(if (> i to)
(setq i to)
)
(setq myi (fix (/ (* (strlen cs_text) i) to))
myi (* 2 (/ myi 2))
)
(if (= 0 myi)
(setq myi 2)
)
(if (/= *ProgressBFB* myi)
(progn
(setq
cs_text (substr cs_text 1 myi)
cs_text (strcat cs_text (gxl-Str-Space (- LL myi)))
)

(setq bfb (fix (* 100 i (/ 1.0 to))))
(setq bfb (itoa bfb))
(cond
((= 1 (strlen bfb))
(setq bfb (strcat " " bfb "% "))
)
((= 2 (strlen bfb)) (setq bfb (strcat " " bfb "% ")))
((= 3 (strlen bfb)) (setq bfb (strcat bfb "% ")))
)
;(grtext -1 (strcat "已完成" cs_text bfb))
(setvar "modemacro"
(strcat *ProgressPrompt*
"已完成"
cs_text
bfb
)
)
(setq *ProgressBFB* myi)

)
(if (= 2 myi)
(progn
(setvar "modemacro"
(strcat *ProgressPrompt*
"已完成"
"| "
"1%"
)
)
) ;progn
) ;if
)
;(setvar "coords" corstate)
)
;;;gxl-Sel-EntNextAll en 返回 en 之后的所有物体选择集,无则返回 nil
(defun gxl-Sel-EntNextAll (ent / ss ent1)
(setq ss (ssadd))
(while (setq ent1 (entnext ent))
(ssadd ent1 ss)
(setq ent ent1)
)
(if (= 0 (sslength ss))
nil
ss
)
)
;;;选择集转为图元列表
(defun gxl-Sel-SS->List (ss / cs_i out)
(if (= (type ss) 'PICKSET)
(progn
(setq cs_i 0.0
out '()
)
(repeat (sslength ss)
(setq out (cons (ssname ss cs_i) out))
(setq cs_i (1+ cs_i))
)
(setq out (reverse out))
)
)
)
(defun gxl-Sel-List->SS (Lst / en ss)
(setq ss (ssadd)
kk 0)
(foreach en Lst
(ssadd en ss)
(setq kk (1+ kk))
)
ss
)
;;;==================================================================
;;;(gxl-dxf ent i )取出图元索引i对应的值
;;;==================================================================
(defun gxl-dxf (ent i)
(if (= (type ent) 'ename)
(setq ent (entget ent))
)
(cdr (assoc i ent))

)
;;;==================================================================
;;;(gxl-CH_Ent ent i pt) 用新值pt更新图元ent索引i对应的值
;;;==================================================================
(defun gxl-CH_Ent (ent i pt / en)
(if (assoc i (setq en (entget ent)))
(setq en (subst (cons i pt) (assoc i en) en))
(setq en (append en (list (cons i pt))))
)
(entmod en)
)[/code]

回复

使用道具 举报

发表于 2021-2-28 19:02:16 | 显示全部楼层
请教一下,这个(setundoerr)是什么函数呢 ?
回复

使用道具 举报

发表于 2021-9-22 23:49:25 | 显示全部楼层
感谢分享,前辈以前做的研究太厉害了
回复

使用道具 举报

发表于 2021-12-30 15:00:57 | 显示全部楼层
提示错误: 输入的字符串太长,啥原因?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-11-14 14:25 , Processed in 0.387058 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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