如何在多点之间绘制最短的不交叉连线(附一个用于植物图块标注的程序源码)
本帖最后由 hb198075 于 2012-3-31 13:57 编辑对选择的图块进行连线,要求获得最短的一种自身不交叉的连线方式。
已完成如下代码,感觉不理想,图块少时还不错,图块多了就乱了。望高手们赐教!
;;;测试程序
(defun c:tt1 ( / e10 ent itm n na ptlst ss)
(if (setq ss (ssget '((0 . "INSERT"))))
(progn
(setq n 0)
(repeat (sslength ss)
(setq na (ssname ss n)
ent (entget na)
e10 (cdr (assoc 10 ent))
ptlst (cons e10 ptlst)
n (1+ n)
)
)
(setq ptlst (bz-dianjuLst ptlst))
(command "_.PLINE")
(foreach itm ptlst
(command itm)
)
(command "")
)
)
(princ)
)
;;;获得最短的总点距
(defun bz-dianjuLst (lst / a all b jd jl n pt tglst)
(setq n 0)
(while (< n (length lst))
(setq pt (nth n lst)
tglst (bz-getNextPoint pt lst)
jl (HB_GETdist tglst)
)
(setq jd(bz-getPlistInsert tglst)
jl(* jl jd)
);_根据交点数设置优先级,每多一个交点,则距加一倍
(setq all (cons (cons jl tglst) all)
n (1+ n)
)
)
(setq all(vl-sort all '(LAMBDA (a b)(< (car a)(car b)))))
(cdar all)
)
;;;获得离当前点最近的下一点
(defun bz-getNextPoint (pt lst / a b rel tmplst)
(setq tmplst lst)
(while tmplst
(setq tmplst (vl-sort tmplst
'(LAMBDA (a b) (< (DISTANCE pt a) (DISTANCE pt b)))
)
pt(car tmplst)
)
(setq rel(cons pt rel)
tmplst (cdr tmplst)
)
)
(REVERSE rel)
)
;;;判断当前连线自身的交点数
(defun bz-getPlistInsert (lst / jd len m n p1 p2 pt1 pt2 rel)
(setq n 0
len (length lst)
rel 1
)
(repeat (- len 2)
(setq p1 (nth n lst)
p2 (nth (1+ n) lst)
n(1+ n)
m(1+ n)
)
(repeat (- len n 2)
(setq pt1 (nth m lst)
pt2 (nth (1+ m) lst)
jd (INTERS p1 p2 pt1 pt2)
m (1+ m)
)
(if jd
(setq rel (1+ rel))
)
)
)
rel
)
;;;获得点连线的总长度
(defun HB_GETdist (lst / rel n p1 p2 tmp)
(setq rel 0.0)
(if (> (length lst) 1)
(progn
(setq n 0)
(repeat (1- (length lst))
(setq p1(nth n lst)
p2(nth (1+ n) lst)
n (1+ n)
tmp (DISTANCE p1 p2)
rel (+ tmp rel)
)
)
)
)
rel
)
下面是测试图
下面是自己使用多年的一个用于植物图块标注与统计的程序,先附图:
命令执行方式:ZW
学习了,谢谢分享. 为什么看不到了?显示“提示: 作者被禁止或删除 内容自动屏蔽” 感谢诸位高手分享程序!!!! 谢谢楼主和各位高手,学习中 hb198075 发表于 2012-3-31 14:06
下面是自己使用多年的一个用于植物图块标注与统计的程序,先附图:
命令执行方式:ZW
楼主还在么?那个植物的lsp。好像还有个CAD样板文件吧. 学习学习。 Gu_xl 发表于 2012-4-1 23:33 static/image/common/back.gif
发个动态串线程序:
看起来很好用的,速度应该比我那个快多了,不知道G版能不提供源码让我学习一下,我想加上自动计算最佳连线方式的功能,而不是由人来判断。 这个是应用公司制图标准自动设置的标注,你手动建一个名称为“yD10"的标注样式就可以了。(后面的数字表示标注样式的比例) 参考帖子
http://bbs.mjtd.com/forum.php?mod=viewthread&tid=88065&page=1&extra=#pid472441pid472441
6楼代码:
hb198075 发表于 2012-3-31 14:06 static/image/common/back.gif
下面是自己使用多年的一个用于植物图块标注与统计的程序,先附图:
命令执行方式:ZW
很多的个人函数哦,收下了 感谢G版的热情,我先去看看~ 本帖最后由 hb198075 于 2012-3-31 14:34 编辑
Gu_xl 发表于 2012-3-31 14:10 http://bbs.mjtd.com/static/image/common/back.gif
参考帖子
http://bbs.mjtd.com/forum.php?mod=viewthread&tid=88065&page=1&extra=#pid472441pid472441
6 ...
G版你那个程序的思路比我灵活多了,不过也是在图块稍多些时连线就不大如意。只实现了不交叉,但没有实现最短连线,希望能有个更完美的算法了。
本帖最后由 hb198075 于 2012-4-1 17:36 编辑
想了一天总算搞出来了,虽然法子比较笨,运算也有些慢,不过在处理100个图块以下时速度还是能忍受的,关键是连线比较完美的。先附个图
把源码也奉上,。。。循环用得比较多,速度有点慢,希望有朋友能帮着也优化一下~
;;;测试程序
(defun c:tt1 ( / e10 ent itm n na ptlst ss oldvar)
(setq oldvar(getvar "OSMODE"))
(setvar "OSMODE" 0)
(if (setq ss (ssget '((0 . "INSERT"))))
(progn
(setq n 0)
(repeat (sslength ss)
(setq na (ssname ss n)
ent (entget na)
e10 (cdr (assoc 10 ent))
ptlst (cons e10 ptlst)
n (1+ n)
)
)
(setq ptlst (bz-dianjuLst ptlst))
(command "_.PLINE")
(foreach itm ptlst
(command itm)
)
(command "")
)
)
(setvar "OSMODE" oldvar)
(princ)
)
;;;获得最短的总点距
(defun bz-dianjuLst
(lst / a all b jd jl n n_sd newlst pt tglst)
(setq n 0
n_sd 0
)
(while (< n (length lst))
(setq pt (nth n lst)
tglst (bz-getNextPoint pt lst)
)
(setq newlst (bz-getPlistInsert tglst)
tglst(cadr newlst)
jl(HB_GETdist tglst)
)
(setq all (cons (cons jl tglst) all)
n (1+ n)
)
)
(setq all (vl-sort all '(LAMBDA (a b) (< (car a) (car b)))))
(cdar all)
)
;;;获得离当前点最近的下一点
(defun bz-getNextPoint (pt lst / a b rel tmplst)
(setq tmplst lst)
(while tmplst
(setq tmplst (vl-sort tmplst
'(LAMBDA (a b) (< (DISTANCE pt a) (DISTANCE pt b)))
)
pt(car tmplst)
)
(setq rel(cons pt rel)
tmplst (cdr tmplst)
)
)
(REVERSE rel)
)
;;;判断当前连线自身的交点数
(defun bz-getPlistInsert (lst / 1lst 2lst leftitm len mjd n num p1 p2 pt1 pt2 rellst)
(setq n 0
len (length lst)
num 1
rellst (list (car lst))
1lst lst
)
(while (and (setq p1 (car 1lst))
(setq p2 (cadr 1lst))
)
(setq mjdnil
1lst (cdr 1lst)
2lst (cdr 1lst)
)
(while (and (null mjd)
(setq pt1 (car 2lst))
(setq pt2 (cadr 2lst))
(setq 2lst (cdr 2lst))
)
(if (INTERS p1 p2 pt1 pt2)
(setq mjd pt1)
)
)
(if mjd
(setq num(1+ num)
leftitm (HB_LIST_LEFTITEM mjd 1lst)
1lst (cdr (member mjd 1lst))
1lst (append (list p1 mjd) (REVERSE leftitm) 1lst)
)
(setq rellst (cons p2 rellst))
)
)
(list num (REVERSE rellst))
)
;;;获得点连线的总长度
(defun HB_GETdist (lst / rel n p1 p2 tmp)
(setq rel 0.0)
(if (> (length lst) 1)
(progn
(setq n 0)
(repeat (1- (length lst))
(setq p1(nth n lst)
p2(nth (1+ n) lst)
n (1+ n)
tmp (DISTANCE p1 p2)
rel (+ tmp rel)
)
)
)
)
rel
)
;;;返回列表中某元素之前的列表
(defun hb_list_leftItem (itm lst / tmplst rel)
(setq tmplst (REVERSE lst))
(while (setq tmplst (cdr (member itm tmplst)))
(setq rel tmplst)
)
(REVERSE rel)
)
本帖最后由 Gu_xl 于 2013-4-10 14:55 编辑
发个动态串线程序:
程序文件下载:
学习一下~~~~~