明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
楼主: highflybir

[越飞越高] 【飞鸟集】最小包围圆的最佳算法

    [复制链接]
发表于 2014-10-13 23:36:46 | 显示全部楼层
算法值得推敲?从3点到4点没问题,但怎么保证从n-1至n点没问题,即是最小包围圆(可能包含其他所有点,但不是最小圆)?
发表于 2015-3-18 11:15:46 | 显示全部楼层
好东西,以后会用得到!
发表于 2015-4-4 09:05:53 | 显示全部楼层
学习,谢谢!
发表于 2015-11-10 16:37:47 | 显示全部楼层

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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x
发表于 2019-9-5 00:48:06 | 显示全部楼层
高人。解决了一个大问题。谢谢!致敬!
发表于 2020-2-17 21:14:23 | 显示全部楼层
好东西,谢谢大神
发表于 2020-2-24 19:11:05 | 显示全部楼层
;;;************************************
;;;求最小包围圆的lisp程序--------------
;;;其算法为参见了有关文献--------------
;;;这种算法在退化很严重的情况结果也正确
;;;其中程序主段是核心算法,其他的附加程
;;;序为取点,画点,画圆和半径,用来测试
;;;************************************
(defun C:test (/ olderr en errmsg  oce
  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
)
发表于 2020-3-13 09:07:19 | 显示全部楼层
都是大神哦
发表于 2020-5-28 15:06:21 | 显示全部楼层
好东西啊,值得学习。
发表于 2021-8-25 11:02:50 | 显示全部楼层
学习了学习了
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-12-23 04:27 , Processed in 0.182112 second(s), 18 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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