mahuan1279 发表于 2014-10-13 23:36:46

算法值得推敲?从3点到4点没问题,但怎么保证从n-1至n点没问题,即是最小包围圆(可能包含其他所有点,但不是最小圆)?

dbqtju 发表于 2015-3-18 11:15:46

好东西,以后会用得到!

shujiansd 发表于 2015-4-4 09:05:53

学习,谢谢!

革天明 发表于 2015-11-10 16:37:47


楼主您好!http://highflybird.mjtd.com/blog/?p=507里面的凸包的LISP实现能否实现右下角的同凸包算法?左边图形为原始图形(特殊了一些)想得到右下角的凸包,请问原程序如何修改?

前生 发表于 2019-9-5 00:48:06

高人。解决了一个大问题。谢谢!致敬!

zst1978 发表于 2020-2-17 21:14:23

好东西,谢谢大神

西红柿 发表于 2020-2-24 19:11:05

;;;************************************
;;;求最小包围圆的lisp程序--------------
;;;其算法为参见了有关文献--------------
;;;这种算法在退化很严重的情况结果也正确
;;;其中程序主段是核心算法,其他的附加程
;;;序为取点,画点,画圆和半径,用来测试
;;;************************************
(defun C:test (/ olderr en errmsgoce
oldmodessp ptlist x cen radius ptmax)
;;定义错误函数和预处理---------------
(setvar "errno" 0)
(setq olderr *error*)
(defun *error* (msg / en errmsg)
    (setq en (getvar "errno"))
    (setq errmsg (strcat "errno=" (itoa en) "\nError:" msg))
    (alert errmsg)
    (setq *error* olderr)
)
(graphscr)
(setq oldmode (getvar "osmode"))
(setq oce (getvar "cmdecho"))
(setvar "cmdecho" 0)
(command ".ucs" "W")
;;取点,画点,并对函数用时计算-------
(setq ssp (ssget '((0 . "POINT"))))
(setq ptlist (ssgetpoint ssp))
(setq t1 (getvar "CDATE"))
(setq x (mincir ptlist))
(setq t2 (getvar "CDATE"))
(setq usetime (* (- t2 t1) 1e6))
(princ (strcat "\n用时=" (rtos usetime 2 6) "秒"))
(if (= nil x)
    (progn
      (alert "点的有效数目太小,请重新输入!")
      (command ".ucs" "p")
      (setvar "osmode" oldmode)
      (setvar "cmdecho" oce)
      (princ "\n")
      (princ)
    )
    (progn
      (setq cen (car x) radius (cadr x) ptmax (caddr x))
      ;;;画圆及半径,列出圆的圆心半径值
      (entmake
      (append
          '((0 . "circle") (100 . "AcDbEntity") (100 . "AcDbCircle"))
          (list (cons 10 cen))(list (cons 40 radius))(list (cons 62 1))
      )
      )
      (entmake
      (append
          '((0 . "line") (100 . "AcDbEntity") (100 . "AcDbLine"))
          (list (cons 10 cen))(list (cons 11 ptmax))(list (cons 62 1))
      )
      )
      (command ".ucs" "p")
      (setvar "osmode" oldmode)
      (setvar "cmdecho" oce)
      (princ "\n")
      (list cen radius)
    )
)
)
;;;************************************
;;;求最小包围圆的函数,空集返回空集,否
;;;则返回最小圆的圆心,半径和圆上的一点
;;;这是程序的主段----------------------
;;;************************************
(defun mincir (ptlist / p1 p2 p3 ptmax cen_r cen radius)
;;定义中点函数,本来R2004版中无须定义
;;但不知道为什么到R2006版没有定义了。
(defun mid (p1 p2)
    (if (or nil (= (length p1) 2) (= (length p2) 2))
      (list (/ (+ (car p1) (car p2)) 2.0) (/ (+ (cadr p1) (cadr p2)) 2.0) 0.0)
      (list (/ (+ (car p1) (car p2)) 2.0) (/ (+ (cadr p1) (cadr p2)) 2.0) (/ (+ (caddr p1) (caddr p2)) 2.0))
    )
)
;;判断有效点个数---------------------
(cond
    ((= (length ptlist) 0)
   nil
    )
    ((= (length ptlist) 1)
   (progn
       (alert "点集合为一点,最小圆半径为0")
       (list (car ptlist) 0 (car ptlist))
   )
    )
    ((= (length ptlist) 2)
   (progn
       (alert "点集合为两点,最小圆直径为其两点距离,\n圆心为其连线中点")
       (setq cen (mid (car ptlist) (cadr ptlist)) radius (/ (distance (car ptlist) (cadr ptlist)) 2))
       (list cen radius (car ptlist))
   )
    )
    (t
   (progn
       ;;上面啰嗦的一大段在实际情况中一般不会出现
       ;;判断点是否在圆内------------------------
       (defun in1 (pt cen r)
(if (> (- r (distance pt cen)) (- 1e-8))
    t
    nil
)
       )
       ;;判断点集是否在圆内----------------------
       (defun in2 (ptl cen r)
(if (apply 'and (mapcar '(lambda (x) (in1 x cen r))ptl))
    t
    nil
)
       )
       ;;定义三点最小圆圆心及其半径,若是锐角三角
       ;;形,则是其三点圆,否则是其最大边的直径圆
       (defun 3pc (pa pb pc / a b c l p ja jb jc ppa ppb ppc cen radius)
(setq a (list (distance pb pc) pa))
(setq b (list (distance pc pa) pb))
(setq c (list (distance pa pb) pc))
(setq l (list a b c))
(setq p (/ (+ (car a) (car b) (car c)) 2))
(setq a (nth (car (vl-sort-i (mapcar 'car l) '>)) l))
(setq b (nth (cadr (vl-sort-i (mapcar 'car l) '>)) l))
(setq c (nth (caddr (vl-sort-i (mapcar 'car l) '>)) l))
(setq l (+ (* (car b) (car b)) (* (car c) (car c)) (* (car a) (car a) -1.0)))
;;上面l利用了余弦定理作为判断-----------
(if (< l 1e-8)
    (list (mid (cadr b) (cadr c))(/ (car a) 2)(list (cadr b) (cadr c) (cadr a)))
    (progn
      (setq ja (angle pb pc))
      (setq jb (angle pc pa))
      (setq jc (angle pa pb))
      (setq ppc (polar (mid pa pb) (+ (/ pi 2) jc) p))
      (setq ppa (polar (mid pb pc) (+ (/ pi 2) ja) p))
      (setq ppb (polar (mid pc pa) (+ (/ pi 2) jb) p))
      (setq cen (inters ppc (mid pa pb) ppa (mid pb pc) nil))
      (setq radius (distance cen pa))
      (list cen radius (list pa pb pc))
    )
)
       )
       ;;定义四点的最小圆圆心半径,并返回三点坐标
       (defun 4pc (p1 p2 p3 ptmax / pts 3pt)
(setq pts (list (3pc p1 p2 p3) (3pc p1 p2 ptmax) (3pc p1 p3 ptmax) (3pc p2 p3 ptmax)))
(setq 3pt (vl-sort-i (mapcar 'cadr pts) '<))
(setq pts (list (nth (car 3pt) pts)(nth (cadr 3pt) pts)
         (nth (caddr 3pt) pts)(nth (cadddr 3pt) pts)))
(nth (vl-position t (mapcar '(lambda (x) (in2 (list p1 p2 p3 ptmax) (car x) (cadr x))) pts)) pts)
       )
       ;;定义求点集中离圆心最远的点的函数--------
       (defun maxd-cir (ptl cen / distl)
(setq distl (mapcar '(lambda (x) (distance x cen)) ptl))
(nth (car (vl-sort-i distl '>)) ptl)
       )
       ;;开始递归运算----------------------------
       (setq p1 (car ptlist) p2 (cadr ptlist) p3 (caddr ptlist))
       (setq cen_r (3pc p1 p2 p3))
       (setq ptmax (maxd-cir ptlist (car cen_r)))
       (while (= nil (in1 ptmax (car cen_r) (cadr cen_r)))
         (setq cen_r (4pc p1 p2 p3 ptmax))
         (setq p1 (car (caddr cen_r)) p2 (cadr (caddr cen_r)) p3 (caddr (caddr cen_r)))
(setq ptmax (maxd-cir ptlist (car cen_r)))
       )
       (list (car cen_r) (cadr cen_r) ptmax)
      );;for progn
    );;for t   
);;    for cond
);;      for defun
;;以下代码来自晓东
;;定义取点函数----
(defun ssgetpoint (ss / i listpp a b c)
(setq i 0 listpp nil )
(if ss
    (repeat (sslength ss)
      (setq a (ssname ss i))
      (setq b (entget a))
      (setq c (cdr (assoc 10 b)))
      (setq listpp (cons c listpp))
      (setq i (1+ i))
    )
)
listpp
)

LIULISHENG 发表于 2020-3-13 09:07:19

都是大神哦

风流少年时 发表于 2020-5-28 15:06:21

好东西啊,值得学习。

LIULISHENG 发表于 2021-8-25 11:02:50

学习了学习了
页: 1 2 3 4 [5] 6
查看完整版本: 【飞鸟集】最小包围圆的最佳算法