Author Topic: Fit Circle to a Selection Set of Points  (Read 5878 times)

0 Members and 1 Guest are viewing this topic.

ymg

  • Guest
Fit Circle to a Selection Set of Points
« on: October 27, 2013, 05:43:26 AM »
Probably been done before but I could not find it in the usual sources.

Would appreciate if somebody with access to C3D would check it, and let me know.

For Derivation of formulas see: Least-Squares Circle Fit

ymg

Code - Auto/Visual Lisp: [Select]
  1. ;; fitcircle    by ymg                                                        ;
  2. ;; Fit a Circle to a Selection Set of Points                                  ;
  3. ;;                                                                            ;
  4. ;; For Derivation of Formulas see:                                            ;
  5. ;; http://www.dtcenter.org/met/users/docs/write_ups/circle_fit.pdf            ;
  6. ;;           by R. Bullock                                                    ;
  7.  
  8.  
  9. (defun c:fc (/ *AcadDoc* *error* a avg b cen cu cv dif diff errl m n p pl rad res s ss sum x)
  10.    (defun *error* (msg)
  11.         (mapcar 'eval errl)
  12.         (if (and msg (not (wcmatch (strcase msg) "*BREAK*,*CANCEL*,*EXIT*")))
  13.            (princ (strcat "\nError: " msg))
  14.         )
  15.         (and *AcadDoc* (vla-endundomark *AcadDoc*))
  16.         (princ)
  17.    )
  18.      
  19.    (setq errl '("CMDECHO" "DIMZIN")
  20.          errl (mapcar (function (lambda (a) (list 'setvar a (getvar a)))) errl)
  21.    )
  22.      
  23.      
  24.    (or *AcadDoc*
  25.    )
  26.    
  27.    (princ (strcat "\n Select Points"))
  28.    (if (setq  n 0
  29.              pl nil
  30.              ss (ssget '((0 . "POINT")))             
  31.        )
  32.       (progn
  33.          (vla-startundomark *AcadDoc*)     
  34.          (setvar 'CMDECHO 0)
  35.          (setvar 'DIMZIN 0)
  36.          (repeat (sslength ss)
  37.                  (setq pl (cons (cdr (assoc 10 (entget (ssname ss n)))) pl)
  38.                         n (1+ n)
  39.                  )
  40.          )
  41.          (setq  avg  (mapcar '/  (apply 'mapcar (cons '+ pl)) (list n n n))
  42.                 dif  (mapcar '(lambda (a) (mapcar '- a avg)) pl)
  43.                 sum  (apply
  44.                         'mapcar
  45.                            (cons '+
  46.                               (mapcar
  47.                                  '(lambda (a)
  48.                                       (list (* (car a) (car a))
  49.                                             (* (car a) (cadr a))
  50.                                             (* (cadr a) (cadr a))
  51.                                             (* (car a) (car a) (car a))
  52.                                             (* (car a) (cadr a) (cadr a))
  53.                                             (* (car a) (car a) (cadr a))
  54.                                             (* (cadr a) (cadr a) (cadr a))
  55.                                       )
  56.                                   )
  57.                                   dif
  58.                               )
  59.                            )
  60.                      )
  61.                 ;; sum contains:  (sUU sUV sVV sUUU sUVV sUUV sVVV)        ;
  62.                    a (list (car sum) (cadr sum) (/ (+ (cadddr sum) (car (cddddr sum))) 2))
  63.                    b (list (cadr sum) (caddr sum) (/ (+ (cadr (cddddr sum))(caddr (cddddr sum))) 2))
  64.                    m (/ (car a) (car b))
  65.                    s (mapcar '- a (mapcar '(lambda (x) (* x m)) b))
  66.                   cv (/ (caddr s) (cadr s))
  67.                   cu (/ (- (caddr a) (* (cadr a) cv)) (car a))
  68.                  cen (mapcar '+ (list cu cv) avg)
  69.                  rad (sqrt (+ (* cu cu) (* cv cv) (/ (+ (car sum) (caddr sum)) n)))
  70.                    n (1- n)
  71.          )
  72.          (entmakex (list '(0 . "POINT") (cons 10 cen)))
  73.          (entmakex (list '(0 . "CIRCLE") (cons 10 cen) (cons 40 rad)))
  74.          (while (> n -1)
  75.              (setq   p (cdr (assoc 10 (entget (ssname ss n))))
  76.                    res (- rad (distance p cen))
  77.                      n (1- n)
  78.              )      
  79.              (entmakex (list '(0 . "TEXT") '(8 . "Residuals") (cons 10 p) (cons 40 3.0) '(50 . 1.5708) (cons 1 (rtos res 2 3))))
  80.          )
  81.       )
  82.    )
  83.    (*error* nil)
  84. )
  85.  
  86. (princ "\nFit a Circle to Selection Set of Points, Type FC to run")
  87.  
« Last Edit: October 27, 2013, 07:04:25 AM by ymg »

edata

  • Mosquito
  • Posts: 2
Re: Fit Circle to a Selection Set of Points
« Reply #1 on: October 27, 2013, 02:14:02 PM »
Thanks in advance.

When the number of points is 1 of the code will go Eorror.
Code: [Select]
(if (setq  n 0
     pl nil
     ss (ssget '((0 . "POINT")))      
       )

ep.
Code: [Select]
(if (and (setq  n 0
     pl nil
     ss (ssget '((0 . "POINT"))))
  (if ss (if (> (sslength ss) 1) t) t))
  (progn
    ;;progn code

    ))
« Last Edit: October 27, 2013, 02:22:44 PM by edata »

ymg

  • Guest
Re: Fit Circle to a Selection Set of Points
« Reply #2 on: October 27, 2013, 09:30:55 PM »
Quote
When the number of points is 1 of the code will go Eorror.


You are right, but no need for a double if. To do a fit you need at least 3 points.

You will also get funny results if all your points are colinear.

Code - Auto/Visual Lisp: [Select]
  1. (if (setq  n 0
  2.              pl nil
  3.              ss (ssget '((0 . "POINT")))
  4.              go (> (sslength ss) 2)
  5.        )
  6.       (progn
  7.           ...
  8.           ...
  9.  

ymg
« Last Edit: October 27, 2013, 09:59:36 PM by ymg »

Lee Mac

  • Seagull
  • Posts: 12913
  • London, England
Re: Fit Circle to a Selection Set of Points
« Reply #3 on: October 28, 2013, 07:19:04 AM »
Code - Auto/Visual Lisp: [Select]
  1. (if (setq  n 0
  2.              pl nil
  3.              ss (ssget '((0 . "POINT")))
  4.              go (> (sslength ss) 2)
  5.        )
  6.       (progn
  7.           ...
  8.  

(sslength nil) will error  :wink:

ymg

  • Guest
Re: Fit Circle to a Selection Set of Points
« Reply #4 on: October 28, 2013, 08:32:16 AM »
Quote
(sslength nil) will error  :wink:

So... will pulling the plug!  :-D

ymg

Lee Mac

  • Seagull
  • Posts: 12913
  • London, England
Re: Fit Circle to a Selection Set of Points
« Reply #5 on: October 28, 2013, 08:54:23 AM »
Quote
(sslength nil) will error  :wink:

So... will pulling the plug!  :-D

If that is indeed your attitude, why bother to include any error trapping at all...? :roll:

Krushert

  • Seagull
  • Posts: 13679
  • FREE BEER Tomorrow!!
Re: Fit Circle to a Selection Set of Points
« Reply #6 on: October 28, 2013, 10:11:40 AM »
If that is indeed your attitude, why bother to include any error trapping at all...? :roll:
Is that like going commando?   :|   ^-^
I + XI = X is true ...  ... if you change your perspective.

I no longer CAD or Model, I just hang out here picking up the empties beer cans

ymg

  • Guest
Re: Fit Circle to a Selection Set of Points
« Reply #7 on: October 28, 2013, 11:25:50 AM »
There U go, Lee.

Did it on the batteries.  :lmao:

But on a serious note, would dearly like to see a comparison of results with Civil 3d.

ymg


Code: [Select]
(princ (strcat "\n Select Points"))
   (if (and (setq ss (ssget '((0 . "POINT"))))
            (> (sslength ss) 2)
       )     
      (progn
         (vla-startundomark *AcadDoc*)    
         (setvar 'CMDECHO 0)
         (setvar 'DIMZIN 0)
         
         (setq  n 0  pl nil)       
(repeat (sslength ss)
         (setq pl (cons (cdr (assoc 10 (entget (ssname ss n)))) pl)




ymg

  • Guest
Re: Fit Circle to a Selection Set of Points
« Reply #8 on: November 11, 2013, 06:39:06 AM »
Here is a slightly better version of the Fit circle routine.

This one does a Non Linear regression and thus really minimize the distance to the circle.

The linearized form sumitted before is used to obtain an approach position.

Then the non linear regression is applied until correction is smaller than 1e-06,
and make use of Evgenyi's implementation of Gaussian Elimination.

ymg

Code - Auto/Visual Lisp: [Select]
  1. ;; fitcircle    by ymg                                                        ;
  2. ;; Fit a Circle to a Selection Set of Points                                  ;
  3. ;;                                                                            ;
  4. ;; For Derivation of Formulas see:                                            ;
  5. ;; http://www.dtcenter.org/met/users/docs/write_ups/circle_fit.pdf            ;
  6. ;;           by R. Bullock                                                    ;
  7.  
  8.  
  9. (defun c:fc (/ *AcadDoc* *error* a avg b cen cu cv dif diff errl m n p pl rad res s ss sum x)
  10.    (defun *error* (msg)
  11.         (mapcar 'eval errl)
  12.         (if (and msg (not (wcmatch (strcase msg) "*BREAK*,*CANCEL*,*EXIT*")))
  13.            (princ (strcat "\nError: " msg))
  14.         )
  15.         (and *AcadDoc* (vla-endundomark *AcadDoc*))
  16.         (princ)
  17.    )
  18.      
  19.    (setq errl '("CMDECHO" "DIMZIN")
  20.          errl (mapcar (function (lambda (a) (list 'setvar a (getvar a)))) errl)
  21.    )
  22.      
  23.      
  24.    (or *AcadDoc*
  25.    )
  26.    
  27.    (princ (strcat "\n Select Points"))
  28.    (if (setq  n 0
  29.              pl nil
  30.              ss (ssget '((0 . "POINT")))
  31.              go (> (sslength ss) 2)
  32.        )
  33.       (progn
  34.          (vla-startundomark *AcadDoc*)     
  35.          (setvar 'CMDECHO 0)
  36.          (setvar 'DIMZIN 0)
  37.          (repeat (sslength ss)
  38.                  (setq pl (cons (cdr (assoc 10 (entget (ssname ss n)))) pl)
  39.                         n (1+ n)
  40.                  )
  41.          )
  42.          (setq  avg  (mapcar '/  (apply 'mapcar (cons '+ pl)) (list n n n))
  43.                 dif  (mapcar '(lambda (a) (mapcar '- a avg)) pl)
  44.                 sum  (apply
  45.                         'mapcar
  46.                            (cons '+
  47.                               (mapcar
  48.                                  '(lambda (a)
  49.                                       (list (* (car a) (car a))
  50.                                             (* (car a) (cadr a))
  51.                                             (* (cadr a) (cadr a))
  52.                                             (* (car a) (car a) (car a))
  53.                                             (* (car a) (cadr a) (cadr a))
  54.                                             (* (car a) (car a) (cadr a))
  55.                                             (* (cadr a) (cadr a) (cadr a))
  56.                                       )
  57.                                   )
  58.                                   dif
  59.                               )
  60.                            )
  61.                      )
  62.                 ;; sum contains:  (sUU sUV sVV sUUU sUVV sUUV sVVV)        ;
  63.                    a (list (car sum) (cadr sum) (/ (+ (cadddr sum) (car (cddddr sum))) 2))
  64.                    b (list (cadr sum) (caddr sum) (/ (+ (cadr (cddddr sum))(caddr (cddddr sum))) 2))
  65.                    m (/ (car a) (car b))
  66.                    s (mapcar '- a (mapcar '(lambda (x) (* x m)) b))
  67.                   y0 (/ (caddr s) (cadr s))
  68.                   x0 (/ (- (caddr a) (* (cadr a) y0)) (car a))
  69.                   r0 (sqrt (+ (* x0 x0) (* y0 y0) (/ (+ (car sum) (caddr sum)) n)))
  70.                   x0 (+ x0 (car avg))
  71.                   y0 (+ y0 (cadr avg))
  72.                    n (1- n)
  73.          )
  74.  
  75.          (setq corr 9999999999
  76.                tol 1e-06
  77.              astep 0
  78.            areport "Circular Non-Linear Regression Results \n"
  79.          )
  80.          (princ (strcat aReport  "\n"
  81.                                  "  Initial: " (itoa aStep) "\n"
  82.                                  "       Xo: " (rtos x0 2 8)  "\n"
  83.                                  "       Yo: " (rtos y0 2 8)  "\n"
  84.                                  "       R : " (rtos r0 2 8) "\n\n")
  85.          )      
  86.          (while (and (< astep 21) (> corr tol))
  87.              (setq astep (1+ astep)
  88.                    a00 0.0 a01 0.0 a02 0.0 a03 0.0
  89.                    a10 0.0 a11 0.0 a12 0.0 a13 0.0
  90.                    a20 0.0 a21 0.0 a22 0.0 a23 0.0
  91.              )
  92.              (foreach p pl
  93.                   (setq x (car p) y (cadr p))
  94.                   (setq bott (sqrt(+ (* x x) (* -2.0 x x0) (* y y)(* -2.0 y0 y) (* x0 x0)(* y0 y0)))
  95.                           k1 (sqrt (+ (*(- x x0)(- x x0)) (* (- y y0) (- y y0))))
  96.                            a (/ (- x0 x) bott)
  97.                            b (/ (- y0 y) bott)
  98.                            c -1.0
  99.                            k (- 0.0 (- k1 r0))
  100.                          a00 (+ a00 (* a a))  ; A*Sum(A**2)+B*2Sum(AB) +C*Sum(AC) +Sum(AK) =0
  101.                          a01 (+ a01 (* a b))  ; A*Sum(AB) +B*2Sum(B**2)+C*Sum(BC) +Sum(BK) =0
  102.                          a02 (+ a02 (* a c))  ; A*Sum(AC) +B*2Sum(BC) +C*Sum(C**2)+Sum(-K) =0
  103.                          a03 (+ a03 (* a k))
  104.                          a11 (+ a11 (* b b))
  105.                          a12 (+ a12 (* b c))
  106.                          a13 (+ a13 (* b k))
  107.                          a22 (+ a22 (* c c))
  108.                          a23 (+ a23 (* -1. k))
  109.                   )
  110.              )
  111.              (setq a10 a01 a20 a02 a21 a12)
  112.              (setq  MatA (list  (list a00 a01 a02 a03)
  113.                                 (list a10 a11 a12 a13)
  114.                                 (list a20 a21 a22 a23)
  115.                          )       
  116.                     MatR (Gauss MatA)
  117.                  
  118.                        c (/ (last (last MatR)) (caddr(last MatR)))
  119.                        b (/ (- (last (cadr MatR)) (* (caddr (cadr MatR)) c)) (cadr(cadr MatR)))
  120.                        a (/ (- (last (car  MatR)) (* (cadr (car MatR)) b) (* (caddr (car MatR)) c)) (car(car MatR)))
  121.                     corr (min (max (abs a)(abs b)(abs c)) corr)
  122.                       x0 (+ x0 a)
  123.                       y0 (+ y0 b)
  124.                       r0 (+ r0 c)
  125.            
  126.              )
  127.              (setq aReport (strcat  "\n"
  128.                               "Iteration: " (itoa aStep) "\n"
  129.                               "       Xo: " (rtos x0 2 8)  "\n"
  130.                               "       Yo: " (rtos y0 2 8)  "\n"
  131.                               "       R : " (rtos r0 2 8) "\n\n"
  132.                               "  Matrix : " (rtos a00 2 3) "  " (rtos a01 2 3) "  " (rtos a02 2 3) "  " (rtos a03 2 3) "\n"
  133.                               "           " (rtos a10 2 3) "  " (rtos a11 2 3) "  " (rtos a12 2 3) "  " (rtos a13 2 3) "\n"
  134.                               "           " (rtos a20 2 3) "  " (rtos a21 2 3) "  " (rtos a22 2 3) "  " (rtos a23 2 3) "\n\n"
  135.                               "  Delta X: " (rtos a 2 8) "\n"
  136.                               "  Delta Y: " (rtos b 2 8) "\n"
  137.                               "  Delta R: " (rtos c 2 8) "\n\n"
  138.                            )
  139.              )
  140.              (princ aReport)
  141.              (setq aReport "")
  142.          )
  143.          (entmakex (list '(0 . "POINT") (cons 10 (list x0 y0))))
  144.          (entmakex (list '(0 . "CIRCLE") (cons 10 (list x0 y0)) (cons 40 r0)))
  145.          (foreach p pl
  146.              (setq   ;p (cdr (assoc 10 (entget (ssname ss n))))
  147.                    res (- r0 (distance p (list x0 y0)))
  148.                      n (1- n)
  149.              )      
  150.              (entmakex (list '(0 . "TEXT") '(8 . "Residuals") (cons 10 p) (cons 40 3.0) '(50 . 1.5708) (cons 1 (rtos res 2 3))))
  151.          )
  152.       )
  153.    )
  154. )
  155.  
  156. ;*****************************************************************************;
  157. ;; gauss                                                                      ;
  158. ;; Implementation Gaussian Elimination     by ElpanovEvgeniy                  ;
  159. ;; For text:  1x+2y+3z=2                                                      ;
  160. ;;           10x+1y+8z=17                                                     ;
  161. ;;               7z+2y=5                                                      ;
  162. ;; (gauss '((1.0 2.0 3.0 2.0) (10.0 1.0 8.0 17.0) (0.0 2.0 7.0 5.0)))         ;
  163. ;; =>                                                                         ;
  164. ;; ((1.0 2.0 3.0 2.0) (0.0 -19.0 -22.0 -3.0) (0.0 0.0 4.68421 4.68421))       ;
  165. ;;****************************************************************************;
  166.  
  167. (defun gauss (lst)
  168.  
  169.   (if (car lst)
  170.     (if (zerop (caar lst))
  171.       (if (vl-every (function zerop) (mapcar (function car) lst))
  172.         (if (cdr lst)
  173.           (cons
  174.             (car lst)
  175.             (mapcar
  176.               (function (lambda (x) (cons 0. x)))
  177.               (gauss (mapcar (function cdr) (cdr lst)))
  178.             )
  179.           )
  180.           lst
  181.         )
  182.         (gauss
  183.           (cons
  184.             (mapcar
  185.               (function +)
  186.               (car lst)
  187.               (car (vl-remove-if
  188.                      (function (lambda (x) (zerop (car x))))
  189.                      (cdr lst)
  190.                    )
  191.               )
  192.             )
  193.             (cdr lst)
  194.           )
  195.         )
  196.       )
  197.       (cons
  198.         (car lst)
  199.         (mapcar
  200.           (function (lambda (x) (cons 0. x)))
  201.           (gauss
  202.             (mapcar
  203.               (function
  204.                 (lambda (x / i)
  205.                   (setq i (/ (car x) (caar lst)))
  206.                   (mapcar
  207.                     (function -)
  208.                     (cdr x)
  209.                     (mapcar (function (lambda (x1) (* x1 i)))
  210.                             (cdar lst)
  211.                     )
  212.                   )
  213.                 )
  214.               )
  215.               (cdr lst)
  216.             )
  217.           )
  218.         )
  219.       )
  220.     )
  221.   )
  222. )
  223.  
  224.  

jarekw90

  • Guest
Re: Fit Circle to a Selection Set of Points
« Reply #9 on: March 23, 2017, 04:08:08 AM »
Your Lisp is great, but I've one proposition to update.
Could you modify your Lisp to maked circle in the average elevation of selected points? It would be very usefull.;)