root/trunk/thirdparty/cl-pdf/pdf-geom.lisp

Revision 2636, 7.8 kB (checked in by hans, 10 months ago)

add cl-pdf for pixel->pdf converter

Line 
1 ;;; cl-pdf copyright 2002-2003 Marc Battyani see license.txt for details.
2 ;;; You can reach me at marc.battyani@fractalconcept.com or marc@battyani.net
3 ;;; The homepage of cl-pdf is here: http://www.fractalconcept.com/asp/html/cl-pdf.html
4
5 (in-package #:pdf)
6
7 ;;; Geometry functions contributed by Eduardo Muñoz
8
9 ;;; Exported functions
10
11 (defconstant +2pi+ (* 2 pi))
12 (defconstant +pi/2+ (/ pi 2))
13
14 (defun arc (center-x center-y radius start extent)
15   (move-to (+ center-x (* radius (cos start)))
16            (+ center-y (* radius (sin start))))
17   (arc-to center-x center-y radius start extent))
18
19 (defun pie (center-x center-y radius start extent)
20   (move-to center-x center-y)
21   (line-to (+ center-x (* radius (cos start)))
22            (+ center-y (* radius (sin start))))
23   (arc-to center-x center-y radius start extent)
24   (line-to center-x center-y))
25
26 (defun circle (center-x center-y radius)
27   (move-to (+ center-x radius) center-y)
28   (arc-to center-x center-y radius 0 +2pi+))
29
30
31 (defun ellipse (center-x center-y radius-a radius-b)
32   (move-to (+ center-x radius-a) center-y)
33   (let ((kappa (* 4 (/ (- (sqrt 2) 1) 3.0))))
34     (bezier-to (+ center-x radius-a) (+ center-y (* kappa radius-b))
35                (+ center-x (* kappa radius-a)) (+ center-y radius-b)
36                center-x (+ center-y radius-b))
37     (bezier-to (- center-x (* kappa radius-a)) (+ center-y radius-b)
38                (- center-x radius-a) (+ center-y (* kappa radius-b))
39                (- center-x radius-a) center-y)
40     (bezier-to (- center-x radius-a) (- center-y (* kappa radius-b))
41                (- center-x (* kappa radius-a)) (- center-y radius-b)
42                center-x (- center-y radius-b))
43     (bezier-to (+ center-x (* kappa radius-a)) (- center-y radius-b)
44                (+ center-x radius-a) (- center-y (* kappa radius-b))
45                (+ center-x radius-a) center-y)))
46
47 (defun rectangle (x y dx dy &key (radius 0))
48   (if (zerop radius)
49       (basic-rect x y dx dy)
50       (progn
51         (move-to (+ x dx) (- (+ y dy) radius))
52         (polyline (list (list x y) (list (+ x dx) y)
53                         (list (+ x dx) (+ y dy)) (list x (+ y dy)))
54                   :radius radius :closed t))))
55
56 (defun polyline (points &key (radius 0) (closed nil))
57   (if (zerop radius)
58       (destructuring-bind ((x1 y1) . other-points) points
59         (move-to x1 y1)
60         (loop for (x y) in other-points
61               do (line-to x y)
62               finally (when closed (line-to x1 y1))))
63       (progn
64           (when closed
65             (let ((break-point (midpoint (first points) (first (last points)) 0.5)))
66               (setf points `(,break-point ,@points ,break-point))))
67           (move-to (first (first points)) (second (first points)))
68           (dotimes (i (- (length points) 2))
69             (let ((p1 (nth i points))
70                   (p2 (nth (1+ i) points))
71                   (p3 (nth (+ 2 i) points)))
72               (fillet p2 p1 p3 radius)))
73           (line-to (first (first (last points)))
74                    (second (first (last points)))))))
75
76 (defun regular-polygon (center-x center-y radius sides &key (fillet-radius 0))
77   (polyline (loop with step-angle = (/ +2pi+ sides)
78                   repeat sides
79                   for current-angle from +pi/2+ by step-angle
80                   collect (list (+ center-x (* radius (cos current-angle)))
81                                 (+ center-y (* radius (sin current-angle)))))
82             :radius fillet-radius :closed t))
83
84 (defun star (center-x center-y ext-radius int-radius sides
85              &key (fillet-radius 0))
86   (let* ((current-angle +pi/2+)
87          (step-angle (/ +2pi+ sides))
88          (half-step (/ step-angle 2.0))
89          (points '()))
90     (dotimes (i sides)
91       (push (list (+ center-x (* ext-radius (cos current-angle)))
92                   (+ center-y (* ext-radius (sin current-angle))))
93             points)
94       (push (list (+ center-x (* int-radius (cos (+ current-angle half-step))))
95                   (+ center-y (* int-radius (sin (+ current-angle half-step)))))
96                   points)
97       (setf current-angle (+ current-angle step-angle)))
98     (polyline points :radius fillet-radius :closed t)))
99
100
101
102 ;;; Non exported functions
103
104 (defun arc-to (center-x center-y radius start extent)
105   ;; An arc of extent zero will generate an error at bezarc (divide by zero).
106   ;; This case may be given by two aligned points in a polyline.
107   ;; Better do nothing.
108   (unless (zerop extent)
109     (if (<= (abs extent) (/ pi 2.0))
110         (multiple-value-bind (x1 y1 x2 y2 x3 y3)
111             (bezarc center-x center-y radius start extent)
112           (bezier-to x1 y1 x2 y2 x3 y3))
113         (let ((half-extent (/ extent 2.0)))
114           (arc-to center-x center-y radius start half-extent)
115           (arc-to center-x center-y radius (+ start half-extent) half-extent)))))
116
117 (defun bezarc (center-x center-y radius start extent)
118   ;; start and extent should be in radians.
119   ;; Returns first-control-point-x first-control-point-y
120   ;;         second-control-point-x second-control-point-y
121   ;;         end-point-x end-point-y
122   (let* ((end (+ start extent))
123          (s-start (sin start)) (c-start (cos start))
124          (s-end (sin end)) (c-end (cos end))
125          (ang/2 (/ extent 2.0))
126          (kappa (* (/ 4.0 3.0)
127                    (/ (- 1 (cos ang/2))
128                       (sin ang/2))))
129          (x1 (- c-start (* kappa s-start)))
130          (y1 (+ s-start (* kappa c-start)))
131          (x2 (+ c-end   (* kappa s-end)))
132          (y2 (- s-end   (* kappa c-end))))
133     (values (+ (* x1 radius) center-x)(+ (* y1 radius) center-y)
134             (+ (* x2 radius) center-x)(+ (* y2 radius) center-y)
135             (+ (* c-end radius) center-x)(+ (* s-end radius) center-y))))
136
137
138 (defun distance (p1 p2)
139   (sqrt (+ (expt (- (first p2)  (first p1))  2)
140            (expt (- (second p2) (second p1)) 2))))
141
142 (defun angle (p1 p2)
143   (if (zerop (distance p1 p2))
144       0.0
145       (atan (- (second p2) (second p1)) (- (first p2) (first p1)))))
146
147
148 ;;;============================================================================;
149 ;;;
150 ;;; (angle-3points <point> <point> <point>)
151 ;;;
152 ;;; Devuelve el angulo en radianes entre tres puntos.  Se considera el punto
153 ;;; 'pt1' como vertice del angulo.  El rango del angulo de salida es [+Pi -Pi)
154 ;;;
155
156 (defun angle-3points (pt1 pt2 pt3)
157   (let ((ang (- (angle pt1 pt3) (angle pt1 pt2))))
158     (if (or (> ang pi) (<= ang (- pi)))
159         (- ang (* (signum ang) +2pi+))
160         ang)))
161
162
163 ;;;============================================================================;
164 ;;;
165 ;;; (midpoint <point> <point> <real>)
166 ;;;
167 ;;; Devuelve un punto situado entre los dos que se dan como argumento. El
168 ;;; factor de posición indica la relación de las distancias entre los puntos
169 ;;; de entrada y el de salida.
170 ;;;
171
172 (defun midpoint (pt1 pt2 ratio)
173   (let ((x1 (first pt1))(y1 (second pt1))
174         (x2 (first pt2))(y2 (second pt2)))
175     (list (+ x1 (* ratio (- x2 x1)))
176           (+ y1 (* ratio (- y2 y1))))))
177
178
179 ;; This function is the support to create rounded polylines
180 ;;
181 ;; p1 = corner
182 ;; p2 = start
183 ;; p3 = end
184 ;; -> no usefull return value
185 (defun fillet (p1 p2 p3 radius)
186   (let* ((gamma (/ (abs (angle-3points p1 p2 p3)) 2))
187          (dist-p1-t (/ radius (tan gamma)))
188          (dist-p1-s (/ (sqrt (+ (expt radius 2) (expt dist-p1-t 2)))
189                        (cos gamma)))
190          (dist-p1-p2 (distance p1 p2))
191          (dist-p1-p3 (distance p1 p3)))
192     (if (or (< dist-p1-p2 dist-p1-t)
193             (< dist-p1-p3 dist-p1-t))
194         ;; Radius is too large, so we aren't going to draw the arc.
195         (line-to (first p1) (second p1))
196         ;; Else, draw the arc.
197         (let ((t2 (midpoint p1 p2 (/ dist-p1-t dist-p1-p2)))
198               (t3 (midpoint p1 p3 (/ dist-p1-t dist-p1-p3)))
199               (center (midpoint (midpoint p1 p2 (/ dist-p1-s dist-p1-p2))
200                                 (midpoint p1 p3 (/ dist-p1-s dist-p1-p3))
201                                 0.5)))
202           (line-to (first t2) (second t2))
203           (arc-to (first center) (second center) radius
204                   (angle center t2) (angle-3points center t2 t3))))))
205
Note: See TracBrowser for help on using the browser.