⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 最小包围圆.lsp

📁 计算几何中的几种lisp语言的算法
💻 LSP
字号:
;;;************************************
;;;求最小包围圆的lisp程序--------------
;;;其算法为参见了有关文献--------------
;;;这种算法在退化很严重的情况结果也正确
;;;其中程序主段是核心算法,其他的附加程
;;;序为取点,画点,画圆和半径,用来测试
;;;************************************
(defun C:test (/ olderr en errmsg oce oldmode ss 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 sl ' ( (-4 . "<OR" )
	      (0 . "POINT")
	      (0 . "LINE")
	      (0 . "POLYLINE")
	      (0 . "LWPOLYLINE")
	      (-4 . "OR>" )))
  (setq ss (ssget sl))
  (setq ptlist (ssgetpoint1 ss))
  (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)
    (polar p1 (angle p1 p2) (* (distance p1 p2) 0.5)) 
  )
  ;;判断有效点个数---------------------
  (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 (< (- (distance pt cen) r) 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 
)
(defun ssgetpoint1 (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 ename (cdr (assoc 0 b)))
      (cond
	( (or nil (= ename  "POLYLINE") (= ename "LWPOLYLINE"))
	  (progn
	    (setq c (GetListOfPline a))
	    (setq listpp (append c listpp))
	  )
        )
	( (= ename "LINE")
	  (progn 
            (setq c (cdr (assoc 10 b)))
            (setq d (cdr (assoc 11 b)))
            (setq listpp (cons c listpp))
            (setq listpp (cons d listpp))
	  )
	)
	( (= ename "POINT")
	  (progn
	    (setq c (cdr (assoc 10 b)))
	    (setq listpp (cons c listpp))
	  )
	)
      )
      (setq i (1+ i))
    )	    
  )  
  listpp 
)
;; Get all nodes of the LWPolyline, Polyline.
(defun GetListOfPline (EntityName / SSE_Pline N newEntityName)
  (setq SSE_Pline (entget EntityName))
  (setq LastList nil)
  (if (= (cdr (assoc 0 SSE_Pline)) "LWPOLYLINE")
    (progn
      (setq LastList (LIST (LIST 0 0)))
      (setq N 0)
      (while (/= (nth N SSE_Pline) nil)
	(if (= (car (nth N SSE_Pline)) 10)
	  (setq	LastList (append LastList
				 (list (list (cadr (nth N SSE_Pline))
					     (caddr (nth N SSE_Pline))
					     0
				       )
				 )
			 )
	  )
	)
	(setq N (+ N 1))
      )
      (setq LastList (cdr LastList))
    )
  )
  (if (= (cdr (ASSOC 0 SSE_Pline)) "POLYLINE")
    (PROGN
      (setq LastList (list (list 0 0)))
      (setq newEntityName (entnext EntityName))
      (while (= (cdr (assoc 0 (entget newEntityName))) "VERTEX")
	(setq
	  LastList (append
		     LastList
		     (list
		       (list (cadr (assoc 10 (entget newEntityName)))
			     (caddr (assoc 10 (entget newEntityName)))
			     0
		       )
		     )
		   )
	)
	(setq newEntityName (entnext newEntityName))
      )
      (setq LastList (cdr LastList))
    )
  )
  (setq LastList LastList)
) ;_defun

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -