1 ;;; Gacela, a GNU Common Lisp extension for fast games development
2 ;;; Copyright (C) 2009 by Javier Sancho Fernandez <jsf at jsancho dot org>
4 ;;; This program is free software: you can redistribute it and/or modify
5 ;;; it under the terms of the GNU General Public License as published by
6 ;;; the Free Software Foundation, either version 3 of the License, or
7 ;;; (at your option) any later version.
9 ;;; This program is distributed in the hope that it will be useful,
10 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 ;;; GNU General Public License for more details.
14 ;;; You should have received a copy of the GNU General Public License
15 ;;; along with this program. If not, see <http://www.gnu.org/licenses/>.
20 (defconstant INFINITY MOST-POSITIVE-LONG-FLOAT)
22 (defun append-if (new test tree &key (key #'first) (test-if #'equal))
23 (cond ((atom tree) tree)
27 (mapcar (lambda (x) (append-if new test x :key key :test-if test-if)) tree)
31 (defun append-if-1 (new test tree &key (key #'first) (test-if #'equal))
32 (cond ((funcall test-if (funcall key tree) test) (append tree new))
36 (if (listp var) (car var) var))
38 (defun avg (&rest numbers)
40 (dolist (n numbers) (incf total n))
41 (/ total (length numbers))))
47 (let ((sig (signum num)))
51 (defmacro destructure (destructuring-list &body body)
52 (let ((lambda-list nil) (exp-list nil))
53 (dolist (pair destructuring-list)
54 (setq exp-list (cons (car pair) exp-list))
55 (setq lambda-list (cons (cadr pair) lambda-list)))
56 `(destructuring-bind ,lambda-list ,(cons 'list exp-list) ,@body)))
58 (defun match-pattern (list pattern)
59 (cond ((and (null list) (null pattern)) t)
60 ((and (consp list) (consp pattern))
61 (and (match-pattern (car list) (car pattern)) (match-pattern (cdr list) (cdr pattern))))
62 ((and (atom list) (atom pattern))
63 (cond ((or (numberp list) (numberp pattern)) (and (numberp list) (numberp pattern)))
66 (defun nearest-power-of-two (n)
68 (cond ((> (* p 2) n) p)
69 (t (power (* p 2) n)))))
72 (defmacro mapcconst (type c-type name)
73 (let ((c-header (concatenate 'string c-type " gacela_" name " (void)"))
74 (c-body (concatenate 'string "return " name ";"))
75 (c-name (concatenate 'string "gacela_" name))
76 (lisp-name (intern (string-upcase name))))
78 (defcfun ,c-header 0 ,c-body)
79 (defentry ,lisp-name () (,type ,c-name))
80 (eval-when (load) (defconstant ,lisp-name (,lisp-name))))))
84 (match-pattern dot '(0 0)))
86 (defun vectorp (vector)
87 (match-pattern vector '(0 0)))
89 (defun circlep (circle)
90 (match-pattern circle '((0 0) 0)))
92 (defun polygonp (polygon)
93 (cond ((consp polygon)
94 (and (dotp (car polygon))
95 (if (null (cdr polygon)) t (polygonp (cdr polygon)))))))
100 (defun make-vector (x y)
103 (defun make-line (dot1 dot2)
106 (defun make-rectangle (x1 y1 x2 y2)
107 `((,x1 ,y1) (,x2 ,y1) (,x2 ,y2) (,x1 ,y2)))
109 (defun polygon-center (polygon)
110 (apply #'mapcar #'avg polygon))
112 (defun dots-distance (dot1 dot2)
113 (destructure ((dot1 (x1 y1))
115 (sqrt (+ (expt (- x2 x1) 2)
116 (expt (- y2 y1) 2)))))
118 (defun dot-line-distance (dot line)
119 (destructure ((line ((ax ay) (bx by)))
121 (let* ((r-numerator (+ (* (- cx ax) (- bx ax)) (* (- cy ay) (- by ay))))
122 (r-denomenator (+ (expt (- bx ax) 2) (expt (- by ay) 2)))
123 (r (/ r-numerator r-denomenator)))
125 (* (abs (/ (- (* (- ay cy) (- bx ax)) (* (- ax cx) (- by ay)))
127 (sqrt r-denomenator))
130 (defun dot-segment-distance (dot segment)
132 (dist r) (dot-line-distance dot segment)
133 (cond ((and (>= r 0) (<= r 1)) dist)
134 (t (let ((dist1 (dots-distance dot (car segment)))
135 (dist2 (dots-distance dot (cadr segment))))
136 (if (< dist1 dist2) dist1 dist2))))))
138 (defun perpendicular-line (dot line)
139 (destructure ((line ((ax ay) (bx by))))
141 (dist r) (dot-line-distance dot line)
143 (make-dot (+ ax (* r (- bx ax)))
144 (+ ay (* r (- by ay))))))))
146 (defun line-angle (line)
147 (destructure ((line ((ax ay) (bx by))))
148 (let ((x (- bx ax)) (y (- by ay)))
149 (if (and (= x 0) (= y 0)) 0 (atan y x)))))
151 (defun inverse-angle (angle)
152 (cond ((< angle pi) (+ angle pi))
155 (defun translate-dot (dot dx dy)
156 (destructure ((dot (x y)))
157 (list (+ x dx) (+ y dy))))
159 (defun translate-circle (circle dx dy)
160 (destructure ((circle (center radius)))
161 (list (translate-dot center dx dy) radius)))
163 (defun translate-polygon (pol dx dy)
164 (mapcar (lambda (dot)
165 (translate-dot dot dx dy))
168 (defun polygon-edges (pol)
169 (mapcar (lambda (v1 v2) (list v1 v2))
171 (union (cdr pol) (list (car pol)))))
173 (defun polygon-dot-intersection (polygon dot)
174 ;Eric Haines algorithm
175 (let ((edges (polygon-edges
176 (translate-polygon polygon (neg (car dot)) (neg (cadr dot)))))
179 (destructure ((edge ((x1 y1) (x2 y2))))
180 (cond ((/= (signum+ y1) (signum+ y2))
181 (cond ((and (> x1 0) (> x2 0)) (incf counter))
182 ((and (or (> x1 0) (> x2 0))
183 (> (- x1 (* y1 (/ (- x2 x1) (- y2 y1)))) 0))
185 (not (evenp counter))))
187 (defun circle-segment-intersection (circle segment)
188 (destructure ((circle (center radius)))
189 (<= (dot-segment-distance center segment) radius)))
191 (defun circle-edges-intersection (circle polygon)
192 (let ((edges (polygon-edges polygon))
195 (cond ((circle-segment-intersection circle edge) (setq edges-i (cons edge edges-i)))))
198 (defun circle-polygon-intersection (circle polygon)
199 (or (polygon-dot-intersection polygon (car circle))
200 (circle-edges-intersection circle polygon)))
202 (defun circle-circle-intersection (circle1 circle2)
203 (destructure ((circle1 (center1 radius1))
204 (circle2 (center2 radius2)))
205 (<= (dots-distance center1 center2) (+ r1 r2))))