;;; -*- Mode:LISP; Package:VIF; Base:10; Readtable:CL -*- (defstruct (line :named) slope y-intercept) (defstruct (singular-line :named (:constructor make-singular-line (x-intercept))) x-intercept) (defun y-from-x-and-line (x line) (if (typep line 'singular-line) nil (+ (* x (line-slope line)) (line-y-intercept line)))) (defun line-from-point-and-slope (x1 y1 slope) (make-line :slope slope :y-intercept (- y1 (* slope x1)))) (defun line-from-two-points (x1 y1 x2 y2) (if (= x1 x2) (make-singular-line x1) (let ((slope (/ (float (- y2 y1)) (float (- x2 x1))))) (line-from-point-and-slope x1 y1 slope)))) (defun line-through-point-perpendicular-to-line (x1 y1 line) (cond ((= (line-slope line) 0) ;horizontal (make-singular-line x1)) ((typep line 'singular-line) (make-line :slope 0 :y-intercept y1)) (t (line-from-point-and-slope x1 y1 (- (/ (line-slope line))))))) (defun line-parallel-p (line1 line2) (cond ((and (typep line1 'singular-line) (typep line2 'singular-line)) t) ((= (line-slope line1) (line-slope line2)) t) (t nil))) (defun lines-intersect-at (line1 line2) (cond ((line-parallel-p line1 line2) nil) ((typep line1 'singular-line) (let* ((x (singular-line-x-intercept line1)) (y (y-from-x-and-line x line2))) (list x y))) ((typep line2 'singular-line) (let* ((x (singular-line-x-intercept line2)) (y (y-from-x-and-line x line1))) (list x y))) (t (let* ((slope1 (line-slope line1)) (slope2 (line-slope line2)) (intercept1 (line-y-intercept line1)) (intercept2 (line-y-intercept line2)) (x (/ (- intercept2 intercept1) (- slope1 slope2))) (y (+ (* slope1 x) intercept1))) (list x y))))) (defun line-segment-length (x1 y1 x2 y2) (flet ((square (n) (* n n))) (sqrt (float (+ (square (- x2 x1)) (square (- y2 y1))))))) (defun line-segment-middle-point (x1 y1 x2 y2) (list (/ (float (+ x1 x2)) 2) (/ (float (+ y1 y2)) 2))) (defun circle-center-and-radius-from-3-points (x1 y1 x2 y2 x3 y3) (flet ((circle-radius (x1 y1 x2 y2) (let ((midpoint (line-segment-middle-point x1 y1 x2 y2))) (line-through-point-perpendicular-to-line (first midpoint) (second midpoint) (line-from-two-points x1 y1 x2 y2))))) (let* ((radius1 (circle-radius x1 y1 x2 y2)) (radius2 (circle-radius x2 y2 x3 y3)) (circle-center (lines-intersect-at radius1 radius2)) (circle-radius (line-segment-length x1 y1 (first circle-center) (second circle-center)))) (values (first circle-center)(second circle-center) circle-radius))))