Let's write β

プログラミング中にできたことか、思ったこととか

Bezier曲線

TwitterでBezier曲線のつぶやきを見たので

(defstruct point x y)

(defun point (x y)
  (make-point :x x :y y))

(defmethod point-diff ((p1 point) (p2 point))
  (sqrt (+ (expt (- (point-x p1) (point-x p2)) 2)
           (expt (- (point-y p1) (point-y p2)) 2))))

(defstruct line p1 p2)

(defmethod line ((p1 point) (p2 point))
  (make-line :p1 p1 :p2 p2))

;;division point of line i:1-i
(defmethod div-point ((l line) i)
  (let ((x-diff (- (point-x (line-p2 l)) (point-x (line-p1 l))))
        (y-diff (- (point-y (line-p2 l)) (point-y (line-p1 l)))))
    (make-point
      :x (+ (point-x (line-p1 l)) (* x-diff (/ i 1)))
      :y (+ (point-y (line-p1 l)) (* y-diff (/ i 1))))))

(defun inter (list fn)
  (mapcar fn
          list 
          (cdr list)))

(defun %bezier (time &rest control-points)
  (mapcar (lambda (l)
            (div-point l time))
            (inter control-points #'line)))

(defun %%bezier (time &rest control-points)
  (loop for points = (apply #'%bezier `(,time ,@control-points)) then (apply #'%bezier `(,time ,@points))
        until (= 1 (length points))
        finally (return (car points))))

(defun bezier (&rest control-points)
  (loop for time from 0.0 upto 1.0 by 0.001
        collect
        (apply #'%%bezier `(,time ,@control-points))))

(ql:quickload :lispbuilder-sdl)
(ql:quickload :lispbuilder-sdl-gfx)

(defun bezier-viewer (&rest control-points)
  (let ((points (apply #'bezier control-points)))
    (sdl:with-init ()
           (sdl:window 600 600 :title-caption "Bezier")
           (sdl:clear-display sdl:*black*)
           ;;Draw ControlPoint
           (loop for cpoint in control-points
                 do
                 (sdl:draw-circle-* (round (point-x cpoint)) (round (point-y cpoint)) 10 :color sdl:*cyan*))
           ;;Draw Bezier Curve
           (loop for point in points
                 do
                 (sdl:draw-pixel-* (round (point-x point)) (round (point-y point)) :color sdl:*white*))
           (sdl:update-display)
           (sdl:with-events ()
                            (:quit-event () t)
                            (:idle () (sdl:update-display))))))

こんなかんじ

CL-USER(65): (bezier-viewer (point 200 200) (point 250 350) (point 350 350) (point 400 200))

f:id:Pocket7878_dev:20130203211132p:plain