找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 6307|回复: 21

[原创]:最小包围圆的最佳算法

[复制链接]

已领礼包: 8121个

财富等级: 富甲天下

发表于 2006-11-11 23:28:27 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

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

×
最小包围圆的算法在实际和理论中都有值得探讨的必要。
在国内网站,对于此类算法鲜有介绍,今天完成了它的一个lisp程序,甚高兴。
《计算几何-算法与应用》中介绍的方法为随机增量式算法,可在O(n)的期望时间中算出来,
而这个算法有别于上种算法,其时间为O(|lg(d/R)|*n),也就是说很可能比上种算法时间更少。
请大家指教指教检查。


  1. ;;;************************************
  2. ;;;求最小包围圆的lisp程序--------------
  3. ;;;其算法为参见了有关文献--------------
  4. ;;;这种算法在退化很严重的情况结果也正确
  5. ;;;其中程序主段是核心算法,其他的附加程
  6. ;;;序为取点,画点,画圆和其半径,可舍弃
  7. ;;;************************************
  8. (defun C:mincir        (/ p1 p2 p3 ptmax cen_r cen radius oldmode oce x)
  9.   ;;定义错误函数和预处理---------------
  10.   (setvar "errno" 0)
  11.   (setq olderr *error*)
  12.   (defun *error* (msg / en errmsg)
  13.     (setq en (getvar "errno"))
  14.     (setq errmsg (strcat "errno=" (itoa en) "\nError:" msg))
  15.     (alert errmsg)
  16.     (setq *error* olderr)
  17.   )
  18.   (graphscr)
  19.   (setq oldmode (getvar "osmode"))
  20.   (setq oce (getvar "cmdecho"))
  21.   (setvar "cmdecho" 0)
  22.   ;;定义取点函数-----------------------
  23.   (defun getp (/ m)
  24.     (setq m (fix (getint "\n请输入点数目:")))
  25.     (if        (< m 1) nil
  26.       (progn
  27.         (setq m (1- m))
  28.         ;;定义0-N的有序整数集函数------
  29.         (defun listn (a / n x)
  30.           (setq n 1)
  31.           (setq x (list 0))
  32.           (while (<= n a)
  33.             (setq x (append (list n) x))
  34.             (setq n (1+ n))
  35.           )
  36.           (reverse x)
  37.         )
  38.         (setq x (listn m))
  39.         ;;取得点集---------------------
  40.         (setq x (mapcar '(lambda (x) (getpoint "\n输入点: ")) x))
  41.       )
  42.     )
  43.   )
  44.   ;;定义中点函数,本来R2004版中无须定义
  45.   ;;但不知道为什么到R2006版没有定义了。
  46.   (defun mid (p1 p2)
  47.     (if (or nil (= (length p1) 2) (= (length p2) 2))
  48.       (list (/ (+ (car p1) (car p2)) 2.0) (/ (+ (cadr p1) (cadr p2)) 2.0) 0.0)
  49.       (list (/ (+ (car p1) (car p2)) 2.0) (/ (+ (cadr p1) (cadr p2)) 2.0) (/ (+ (caddr p1) (caddr p2)) 2.0))
  50.     )
  51.   )
  52.   ;;取点,画点-------------------------
  53.   (command ".ucs" "W")
  54.   (setq x (vl-remove nil (getp)))
  55.   (mapcar
  56.     '(lambda (pt)
  57.        (entmake
  58.          (append
  59.            '((0 . "Point") (100 . "AcDbEntity") (100 . "AcDbPoint"))
  60.            (list (cons 10 pt))
  61.          )
  62.        )
  63.      )
  64.     x
  65.   )
  66.   ;;判断有效点个数---------------------
  67.   (cond
  68.     ((< (length x) 1)
  69.      (progn
  70.        (alert "点的有效数目太小,请重新输入!")
  71.        (command ".ucs" "p")
  72.        (setvar "osmode" oldmode)
  73.        (setvar "cmdecho" oce)
  74.        nil
  75.      )
  76.     )
  77.     ((= (length x) 1)
  78.      (progn
  79.        (alert "点集合为一点,最小圆半径为0")
  80.        (command ".ucs" "p")
  81.        (setvar "osmode" oldmode)
  82.        (setvar "cmdecho" oce)
  83.        (list (car x) 0)
  84.      )
  85.     )
  86.     ((= (length x) 2)
  87.      (progn
  88.        (alert "点集合为两点,最小圆直径为其两点距离,\n圆心为其连线中点")
  89.        (setq cen (midp (car x) (cadr x)) radius (/ (distance (car x) (cadr x)) 2))
  90.        (entmake
  91.          (append
  92.            '((0 . "line") (100 . "AcDbEntity") (100 . "AcDbLine"))
  93.            (list (cons 10 cen))(list (cons 11 (car x)))(list (cons 62 1))
  94.          )
  95.        )
  96.        (entmake
  97.          (append
  98.            '((0 . "circle") (100 . "AcDbEntity") (100 . "AcDbCircle"))
  99.            (list (cons 10 cen))(list (cons 40 radius))(list (cons 62 1))
  100.          )
  101.        )
  102.        (command ".ucs" "p")
  103.        (setvar "osmode" oldmode)
  104.        (setvar "cmdecho" oce)
  105.        (list cen radius)
  106.      )
  107.     )
  108.     (t
  109.      (progn
  110.        ;;****************************************
  111.        ;;上面啰嗦的一大段在实际情况中一般不会出现
  112.        ;;这是程序最主要的段----------------------
  113.        ;;****************************************
  114.        ;;判断点是否在圆内------------------------
  115.        (defun in1 (pt cen r)
  116.          (if (> (- r (distance pt cen)) (- 1e-8))
  117.            t
  118.            nil
  119.          )
  120.        )
  121.        ;;判断点集是否在圆内----------------------
  122.        (defun in2 (ptl cen r)
  123.          (if (apply 'and (mapcar '(lambda (x) (in1 x cen r))  ptl))
  124.            t
  125.            nil
  126.          )
  127.        )
  128.        ;;定义三点最小圆圆心及其半径,若是锐角三角
  129.        ;;形,则是其三点圆,否则是其最大边的直径圆
  130.        (defun 3pc (pa pb pc / a b c l p ja jb jc ppa ppb ppc cen radius)
  131.          (setq a (list (distance pb pc) pa))
  132.          (setq b (list (distance pc pa) pb))
  133.          (setq c (list (distance pa pb) pc))
  134.          (setq l (list a b c))
  135.          (setq p (/ (+ (car a) (car b) (car c)) 2))
  136.          (setq a (nth (car (vl-sort-i (mapcar 'car l) '>)) l))
  137.          (setq b (nth (cadr (vl-sort-i (mapcar 'car l) '>)) l))
  138.          (setq c (nth (caddr (vl-sort-i (mapcar 'car l) '>)) l))
  139.          (setq l (+ (* (car b) (car b)) (* (car c) (car c)) (* (car a) (car a) -1.0)))
  140.          (if (< l 1e-8)
  141.            (list (mid (cadr b) (cadr c))(/ (car a) 2)(list (cadr b) (cadr c) (cadr a)))
  142.            (progn
  143.              (setq ja (angle pb pc))
  144.              (setq jb (angle pc pa))
  145.              (setq jc (angle pa pb))
  146.              (setq ppc (polar (mid pa pb) (+ (/ pi 2) jc) p))
  147.              (setq ppa (polar (mid pb pc) (+ (/ pi 2) ja) p))
  148.              (setq ppb (polar (mid pc pa) (+ (/ pi 2) jb) p))
  149.              (setq cen (inters ppc (mid pa pb) ppa (mid pb pc) nil))
  150.              (setq radius (distance cen pa))
  151.              (list cen radius (list pa pb pc))
  152.            )
  153.          )
  154.        )
  155.        ;;定义四点的最小圆圆心半径,并返回三点坐标
  156.        (defun 4pc (p1 p2 p3 ptmax / pts 3pt)
  157.          (setq pts (list (3pc p1 p2 p3) (3pc p1 p2 ptmax) (3pc p1 p3 ptmax) (3pc p2 p3 ptmax)))
  158.          (setq 3pt (vl-sort-i (mapcar 'cadr pts) '<))
  159.          (setq pts (list (nth (car 3pt) pts)  (nth (cadr 3pt) pts)
  160.                          (nth (caddr 3pt) pts)(nth (cadddr 3pt) pts)))
  161.          (nth (vl-position t (mapcar '(lambda (x) (in2 (list p1 p2 p3 ptmax) (car x) (cadr x))) pts)) pts)
  162.        )
  163.        ;;定义求点集中离圆心最远的点的函数--------
  164.        (defun maxd-cir (ptl cen / distl)
  165.          (setq distl (mapcar '(lambda (x) (distance x cen)) ptl))
  166.          (nth (car (vl-sort-i distl '>)) ptl)
  167.        )
  168.        ;;开始递归运算----------------------------
  169.        (setq p1        (car x) p2 (cadr x) p3 (caddr x))
  170.        (setq cen_r (3pc p1 p2 p3))
  171.        (setq ptmax (maxd-cir x (car cen_r)))
  172.        (while (= nil (in1 ptmax (car cen_r) (cadr cen_r)))
  173.           (setq cen_r (4pc p1 p2 p3 ptmax))
  174.           (setq p1 (car (caddr cen_r)) p2 (cadr (caddr cen_r)) p3 (caddr (caddr cen_r)))
  175.           (setq ptmax (maxd-cir x (car cen_r)))
  176.        )
  177.        ;;画圆,画半径,并列出最小圆的圆心、半径值
  178.        (entmake
  179.          (append
  180.            '((0 . "circle") (100 . "AcDbEntity") (100 . "AcDbCircle"))
  181.            (list (cons 10 (car cen_r)))(list (cons 40 (cadr cen_r)))(list (cons 62 1))
  182.          )
  183.        )
  184.        (entmake
  185.          (append
  186.            '((0 . "line") (100 . "AcDbEntity") (100 . "AcDbLine"))
  187.            (list (cons 10 (car cen_r)))(list (cons 11 ptmax))(list (cons 62 1))
  188.          )
  189.        )
  190.        (command ".ucs" "p")
  191.        (setvar "osmode" oldmode)
  192.        (setvar "cmdecho" oce)
  193.        (list (car cen_r) (cadr cen_r))
  194.       );;for progn
  195.     );;  for t   
  196.   );;    for cond
  197. );;      for defun


附件为其lisp程序,加载,运行mincir 即可。

本帖被以下淘专辑推荐:

论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
发表于 2006-11-12 09:48:41 | 显示全部楼层
:)

前段时间也匆匆忙忙写过一个
http://www.xdcad.net/forum/showthread.php?s=&threadid=571449

但是是赶时间,用比较暴力的方法,比不上兄台的优质算法.
《计算几何-算法与应用》确实是本好书, 计算几何确实挺有趣.

希望能再多共享一些这样的程序,谢谢:)
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 6个

财富等级: 恭喜发财

发表于 2006-11-12 11:38:29 | 显示全部楼层
highflybird  ^)^写的不错!你与snoopychen  老大一起给我上了很多非常好的几何课!
在这之前我要将几何忘记的差不多了~多谢两位!

提点个人的小意见一家之言只供参考!
在你的子函数4pc中算法可以优化~
3pc调用次数太多了可能是这个程序主要费时函数!
而事实上在求一点pt是不是在过a b c 的圆的内,外,上 可以不用求出cen,r的啦!
比如说用同弧所对圆周角等于弧角度一半,大于则在圆内,小于则在外~
p在圆上 角apc=角abc
p在圆外 角apc<角abc
p在圆内 角apc>角abc
角的取值在什么范围也是要处理一下!
我没测验理论上可以速率比求cen&R的要快点
事实上快不快就只有测试下知道啦!只供参考!
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2006-11-12 15:56:53 | 显示全部楼层
如果结果只有两个点在圆上,这两个点一定是距离最远的点,位于直径上
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 8121个

财富等级: 富甲天下

 楼主| 发表于 2006-11-12 17:28:35 | 显示全部楼层
多谢各位,我学lisp不久,向大家学习的地方很多。
fsxm 兄,很高兴能与我讨论。现我回答如下:
先说说程序思路:
1、找出三点ABC最小圆和圆心O。
2、再找出点集中离这个圆心O距离最远的那一点PTMAX。
3、如果这点在三点的最小圆内,这个圆为所求,算法结束。
4、否则三点和这个最远点PTMAX组成四点,求四点最小圆和圆心,并返回三点ABC(圆周上两点和另一点)
5、再求出离四点最小圆的圆心最远的点PTMAX,如果这点在四点最小圆内,则算法结束,否则以返回的三点和最远点PTMAX迭代进入第4 步。直到最远点PTMAX在跌代后的最小圆内。
因此程序中,3pc这个子函数是必不可少的,有了3pc,才有4pc,递推才能进行。
实际上迭代的次数并不是所取的点数n(可能几万个以上),跌代的次数很少,这种递归形成的级数收敛很快,开始前三点是随机选择的,如果选择得好的话,只要一两次迭代就足矣。
另外,我判断点在圆内圆外,并不是这个函数,而是根据:如果圆心到点距离大于半径则不在圆内,否则在圆内。是in1 和in2 这两个函数,in2 用来判断点集是否在圆内,但并不是判断点集合所有的元素,而是判断递归中形成的四点。
所以真正调用次数太多的并不是3pc,而是到圆心距离最远点的那个函数maxd-cir,因为这个函数每递归一次,就要判断点集合中的点到圆心得最远距离(实际上可以除去一些点,但那样的话又得把点集中的点判断一次),影响时间的是这个。我个人以为。
至于4pc这个函数,我也不知道如何优化,我是这样设计的:
对四点三点一组形成集合,每一组求其最小圆和半径(3pc) ,然后对半径按照从小到大排序,找到能包围四点的那一组。
希望大家能帮忙看看何处可以优化。

  1. ;;;************************************
  2. ;;;求最小包围圆的lisp程序--------------
  3. ;;;其算法为参见了有关文献--------------
  4. ;;;这种算法在退化很严重的情况结果也正确
  5. ;;;其中程序主段是核心算法,其他的附加程
  6. ;;;序为取点,画点,画圆和半径,用来测试
  7. ;;;************************************
  8. (defun C:test (/ olderr en errmsg oldmode oce ssp ptlist x cen radius ptmax)
  9.   ;;定义错误函数和预处理---------------
  10.   (setvar "errno" 0)
  11.   (setq olderr *error*)
  12.   (defun *error* (msg / en errmsg)
  13.     (setq en (getvar "errno"))
  14.     (setq errmsg (strcat "errno=" (itoa en) "\nError:" msg))
  15.     (alert errmsg)
  16.     (setq *error* olderr)
  17.   )
  18.   (graphscr)
  19.   (setq oldmode (getvar "osmode"))
  20.   (setq oce (getvar "cmdecho"))
  21.   (setvar "cmdecho" 0)
  22.   (command ".ucs" "W")
  23.   ;;取点,画点,并对函数用时计算-------
  24.   (setq ssp (ssget '((0 . "POINT"))))
  25.   (setq ptlist (ssgetpoint ssp))
  26.    (setq t1 (getvar "CDATE"))
  27.   (setq x (mincir ptlist))
  28.   (setq t2 (getvar "CDATE"))
  29.   (setq usetime (* (- t2 t1) 1e6))
  30.   (princ (strcat "\n用时=" (rtos usetime 2 6) "秒"))
  31.   (if (= nil x)
  32.     (progn
  33.       (alert "点的有效数目太小,请重新输入!")
  34.       (command ".ucs" "p")
  35.       (setvar "osmode" oldmode)
  36.       (setvar "cmdecho" oce)
  37.       (princ "\n")
  38.       (princ)
  39.     )
  40.     (progn
  41.       (setq cen (car x) radius (cadr x) ptmax (caddr x))
  42.       ;;;画圆及半径,列出圆的圆心半径值
  43.       (entmake
  44.         (append
  45.           '((0 . "circle") (100 . "AcDbEntity") (100 . "AcDbCircle"))
  46.           (list (cons 10 cen))(list (cons 40 radius))(list (cons 62 1))
  47.         )
  48.       )
  49.       (entmake
  50.         (append
  51.           '((0 . "line") (100 . "AcDbEntity") (100 . "AcDbLine"))
  52.           (list (cons 10 cen))(list (cons 11 ptmax))(list (cons 62 1))
  53.         )
  54.       )
  55.       (command ".ucs" "p")
  56.       (setvar "osmode" oldmode)
  57.       (setvar "cmdecho" oce)
  58.       (princ "\n")
  59.       (list cen radius)
  60.     )
  61.   )
  62. )
  63. ;;;************************************
  64. ;;;求最小包围圆的函数,空集返回空集,否
  65. ;;;则返回最小圆的圆心,半径和圆上的一点
  66. ;;;这是程序的主段----------------------
  67. ;;;************************************
  68. (defun mincir (ptlist / p1 p2 p3 ptmax cen_r cen radius)
  69.   ;;定义中点函数,本来R2004版中无须定义
  70.   ;;但不知道为什么到R2006版没有定义了。
  71.   (defun mid (p1 p2)
  72.     (if (or nil (= (length p1) 2) (= (length p2) 2))
  73.       (list (/ (+ (car p1) (car p2)) 2.0) (/ (+ (cadr p1) (cadr p2)) 2.0) 0.0)
  74.       (list (/ (+ (car p1) (car p2)) 2.0) (/ (+ (cadr p1) (cadr p2)) 2.0) (/ (+ (caddr p1) (caddr p2)) 2.0))
  75.     )
  76.   )
  77.   ;;判断有效点个数---------------------
  78.   (cond
  79.     ((= (length ptlist) 0)
  80.      nil
  81.     )
  82.     ((= (length ptlist) 1)
  83.      (progn
  84.        (alert "点集合为一点,最小圆半径为0")
  85.        (list (car ptlist) 0 (car ptlist))
  86.      )
  87.     )
  88.     ((= (length ptlist) 2)
  89.      (progn
  90.        (alert "点集合为两点,最小圆直径为其两点距离,\n圆心为其连线中点")
  91.        (setq cen (mid (car ptlist) (cadr ptlist)) radius (/ (distance (car ptlist) (cadr ptlist)) 2))
  92.        (list cen radius (car ptlist))
  93.      )
  94.     )
  95.     (t
  96.      (progn
  97.        ;;上面啰嗦的一大段在实际情况中一般不会出现
  98.        ;;判断点是否在圆内------------------------
  99.        (defun in1 (pt cen r)
  100.          (if (> (- r (distance pt cen)) (- 1e-8))
  101.            t
  102.            nil
  103.          )
  104.        )
  105.        ;;判断点集是否在圆内----------------------
  106.        (defun in2 (ptl cen r)
  107.          (if (apply 'and (mapcar '(lambda (x) (in1 x cen r))  ptl))
  108.            t
  109.            nil
  110.          )
  111.        )
  112.        ;;定义三点最小圆圆心及其半径,若是锐角三角
  113.        ;;形,则是其三点圆,否则是其最大边的直径圆
  114.        (defun 3pc (pa pb pc / a b c l p ja jb jc ppa ppb ppc cen radius)
  115.          (setq a (list (distance pb pc) pa))
  116.          (setq b (list (distance pc pa) pb))
  117.          (setq c (list (distance pa pb) pc))
  118.          (setq l (list a b c))
  119.          (setq p (/ (+ (car a) (car b) (car c)) 2))
  120.          (setq a (nth (car (vl-sort-i (mapcar 'car l) '>)) l))
  121.          (setq b (nth (cadr (vl-sort-i (mapcar 'car l) '>)) l))
  122.          (setq c (nth (caddr (vl-sort-i (mapcar 'car l) '>)) l))
  123.          (setq l (+ (* (car b) (car b)) (* (car c) (car c)) (* (car a) (car a) -1.0)))
  124.          ;;上面l利用了余弦定理作为判断-----------
  125.          (if (< l 1e-8)
  126.            (list (mid (cadr b) (cadr c))(/ (car a) 2)(list (cadr b) (cadr c) (cadr a)))
  127.            (progn
  128.              (setq ja (angle pb pc))
  129.              (setq jb (angle pc pa))
  130.              (setq jc (angle pa pb))
  131.              (setq ppc (polar (mid pa pb) (+ (/ pi 2) jc) p))
  132.              (setq ppa (polar (mid pb pc) (+ (/ pi 2) ja) p))
  133.              (setq ppb (polar (mid pc pa) (+ (/ pi 2) jb) p))
  134.              (setq cen (inters ppc (mid pa pb) ppa (mid pb pc) nil))
  135.              (setq radius (distance cen pa))
  136.              (list cen radius (list pa pb pc))
  137.            )
  138.          )
  139.        )
  140.        ;;定义四点的最小圆圆心半径,并返回三点坐标
  141.        (defun 4pc (p1 p2 p3 ptmax / pts 3pt)
  142.          (setq pts (list (3pc p1 p2 p3) (3pc p1 p2 ptmax) (3pc p1 p3 ptmax) (3pc p2 p3 ptmax)))
  143.          (setq 3pt (vl-sort-i (mapcar 'cadr pts) '<))
  144.          (setq pts (list (nth (car 3pt) pts)  (nth (cadr 3pt) pts)
  145.                          (nth (caddr 3pt) pts)(nth (cadddr 3pt) pts)))
  146.          (nth (vl-position t (mapcar '(lambda (x) (in2 (list p1 p2 p3 ptmax) (car x) (cadr x))) pts)) pts)
  147.        )
  148.        ;;定义求点集中离圆心最远的点的函数--------
  149.        (defun maxd-cir (ptl cen / distl)
  150.          (setq distl (mapcar '(lambda (x) (distance x cen)) ptl))
  151.          (nth (car (vl-sort-i distl '>)) ptl)
  152.        )
  153.        ;;开始递归运算----------------------------
  154.        (setq p1        (car ptlist) p2 (cadr ptlist) p3 (caddr ptlist))
  155.        (setq cen_r (3pc p1 p2 p3))
  156.        (setq ptmax (maxd-cir ptlist (car cen_r)))
  157.        (while (= nil (in1 ptmax (car cen_r) (cadr cen_r)))
  158.          (setq cen_r (4pc p1 p2 p3 ptmax))
  159.          (setq p1 (car (caddr cen_r)) p2 (cadr (caddr cen_r)) p3 (caddr (caddr cen_r)))
  160.          (setq ptmax (maxd-cir ptlist (car cen_r)))
  161.        )
  162.        (list (car cen_r) (cadr cen_r) ptmax)
  163.       );;for progn
  164.     );;  for t   
  165.   );;    for cond
  166. );;      for defun
  167. ;;以下代码来自晓东
  168. ;;定义取点函数----
  169. (defun ssgetpoint (ss / i listpp a b c)
  170.   (setq i 0 listpp nil )
  171.   (if ss
  172.     (repeat (sslength ss)
  173.       (setq a (ssname ss i))
  174.       (setq b (entget a))
  175.       (setq c (cdr (assoc 10 b)))
  176.       ;;(setq listpp (append listpp (list c)))
  177.       (setq listpp (cons c listpp))
  178.       (setq i (1+ i))  
  179.     )
  180.   )
  181.   listpp
  182. )

我重新修改了程序,使得求最小圆成了一个函数。
然后在做了一个test 程序,我选择了50000个点,然后对其求值
发现,竟然取得点集合的那个时间占了绝大部分时间,而求最小圆的函数计算时间很短 。
如果大家有其他算法的不妨作下比较(把局部变量变成全局的,然后从取得点集合后开始做比较)
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 593个

财富等级: 财运亨通

发表于 2006-11-12 18:44:05 | 显示全部楼层
这样改取点函数后试试
(setq listpp (append listpp (list c))) -> (setq listpp (cons c listpp)
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 8121个

财富等级: 富甲天下

 楼主| 发表于 2006-11-12 19:14:36 | 显示全部楼层
版主改得太妙了!(尽管我还不知道为什么)
我把snoopychen老大提供的暴力算法和我的算法作了下比较:(没别的意思)简直有天壤之别。
理论上用暴力算法的时间是O(n^4),可见是很费时的。
看来除非万不得已最好莫用暴力算法。
向各位学习!
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 488个

财富等级: 日进斗金

发表于 2006-11-12 22:40:32 | 显示全部楼层
是不是一个最小圆,里面圈住所有的点?
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 8121个

财富等级: 富甲天下

 楼主| 发表于 2006-11-13 17:39:21 | 显示全部楼层
是这样的。

对于这个程序,只要再作稍微改动
1、把取得点集函数改成如下:

  1. (defun ssgetpoint1 (ss / i listpp a b c)
  2.   (setq i 0 listpp nil )
  3.   (if ss
  4.     (repeat (sslength ss)
  5.       (setq a (ssname ss i))
  6.       (setq b (entget a))
  7.       (setq c (cdr (assoc 10 b)));;直线起点
  8.       (setq d (cdr (assoc 11 b)));;直线端点
  9.       (setq listpp (cons c listpp))
  10.       (setq listpp (cons d listpp))
  11.       (setq i (1+ i))  
  12.     )
  13.   )
  14.   listpp
  15. )

在TEST中修改成选取直线对象:

  1. (setq ssp (ssget '((0 . "LINE"))))
  2.   (setq ptlist (ssgetpoint1 ssp))

那么这个程序就可以成为直线集合的最小包围圆了。
我记得在明经上有人问过:如何求包含一个多边形的最小的圆?
那么这个程序基本可以解答了。

对于曲线(包括圆弧)集合,也可以通过对每个曲线用有限的点(不要太多)进行拟合,然后用这种方法来得到粗略解,然后细化,估计也行。但我想这样做肯定不是最佳解了。
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2006-11-14 14:55:09 | 显示全部楼层
曾经发现:同样的功能如果不用mapcar这个函数,速度要快不少,不知是否都是这样
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 8121个

财富等级: 富甲天下

发表于 2013-4-9 17:02:09 | 显示全部楼层
本帖最后由 Highflybird 于 2013-4-9 17:03 编辑

程序稍微做了一下改进。日期:2013-4-9.参见附件:
请点击此处下载

查看状态:需购买或无权限

您的用户组是:游客

文件名称:最小包围圆改进.rar 
下载次数:110  文件大小:2.16 KB 
下载权限: 不限 以上  [免费赚D豆]


其实我以前还有个随机增量算法版本的。但是相比这个,在大数量时候还是慢了很多,故没贴出来。
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2013-4-17 08:19:09 | 显示全部楼层
高手果然是高手啊
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2013-4-27 09:23:05 | 显示全部楼层
看不懂!还有待提高!
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 6468个

财富等级: 富甲天下

发表于 2013-5-3 02:17:15 | 显示全部楼层
学习的好例子。
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 1757个

财富等级: 堆金积玉

发表于 2013-5-22 11:25:22 | 显示全部楼层
还有一些问题
RTX截图未命名.png
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

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

本版积分规则

QQ|申请友链|Archiver|手机版|小黑屋|辽公网安备|晓东CAD家园 ( 辽ICP备15016793号 )

GMT+8, 2024-3-29 10:05 , Processed in 0.567107 second(s), 65 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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