root/trunk/thirdparty/cl-gd-0.5.6/drawing.lisp

Revision 2428, 15.4 kB (checked in by hhubner, 1 year ago)

Update cl-gd.

Line 
1 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-GD; Base: 10 -*-
2 ;;; $Header: /usr/local/cvsrep/gd/drawing.lisp,v 1.28 2007/01/01 23:41:00 edi Exp $
3
4 ;;; Copyright (c) 2003-2007, Dr. Edmund Weitz.  All rights reserved.
5
6 ;;; Redistribution and use in source and binary forms, with or without
7 ;;; modification, are permitted provided that the following conditions
8 ;;; are met:
9
10 ;;;   * Redistributions of source code must retain the above copyright
11 ;;;     notice, this list of conditions and the following disclaimer.
12
13 ;;;   * Redistributions in binary form must reproduce the above
14 ;;;     copyright notice, this list of conditions and the following
15 ;;;     disclaimer in the documentation and/or other materials
16 ;;;     provided with the distribution.
17
18 ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED
19 ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 ;;; ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
24 ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 (in-package :cl-gd)
31
32 (defun get-pixel (x y &key (image *default-image*))
33   "Gets the color associated with point \(X,Y)."
34   (check-type image image)
35   (with-transformed-alternative
36       ((x x-transformer)
37        (y y-transformer))
38     (gd-image-get-pixel (img image) x y)))
39
40 (defun set-pixel (x y &key (color *default-color*) (image *default-image*))
41   "Draws a pixel with color COLOR at point \(X,Y)."
42   (check-type image image)
43   (with-color-argument
44     (with-transformed-alternative
45         ((x x-transformer)
46          (y y-transformer))
47       (gd-image-set-pixel (img image) x y color)))
48   (values x y))
49
50 (defgeneric set-pixels (points &key color image)
51   (:documentation "Draws a list \(X1 Y1 X2 Y2 ...) or vector #\(X1 Y1
52 X2 Y2 ...) of pixels."))
53
54 (defmethod set-pixels ((points list) &key (color *default-color*) (image *default-image*))
55   (check-type image image)
56   (unless (evenp (length points))
57     (error "List ~S must have an even number of elements"
58            points))
59   (loop with img = (img image)
60         for (x y) on points by #'cddr do
61         (check-type x integer)
62         (check-type y integer)
63         (with-transformed-alternative
64             ((x x-transformer)
65              (y y-transformer))
66           (gd-image-set-pixel img x y color))
67         finally (return image)))
68
69 (defmethod set-pixels ((points vector) &key (color *default-color*) (image *default-image*))
70   (check-type image image)
71   (let ((length (length points)))
72     (unless (evenp length)
73       (error "List ~S must have an even number of elements"
74              points))
75     (loop with img = (img image)
76           for i below length by 2 do
77           (check-type (aref points i) integer)
78           (check-type (aref points (1+ i)) integer)
79           (with-transformed-alternative
80               (((aref points i) x-transformer)
81                ((aref points (1+ i)) y-transformer))
82             (gd-image-set-pixel img
83                                 (aref points i)
84                                 (aref points (1+ i))
85                                 color))
86           finally (return image))))
87
88 (defun draw-line (x1 y1 x2 y2 &key (color *default-color*) (image *default-image*))
89   "Draws a line with color COLOR from point \(X1,Y1) to point \(X2,Y2)."
90   (check-type image image)
91   (with-color-argument
92     (with-transformed-alternative
93         ((x1 x-transformer)
94          (y1 y-transformer)
95          (x2 x-transformer)
96          (y2 y-transformer))
97       (gd-image-line (img image) x1 y1 x2 y2 color)))
98   (values x1 y1 x2 y2))
99
100 (defun draw-rectangle* (x1 y1 x2 y2 &key filled (color *default-color*) (image *default-image*))
101   "Draws a rectangle with upper left corner \(X1,Y1) and lower right
102 corner \(X2,Y2). If FILLED is true the rectangle will be filled with
103 COLOR, otherwise it will be outlined."
104   (check-type image image)
105   (with-color-argument
106     (with-transformed-alternative
107         ((x1 x-transformer)
108          (y1 y-transformer)
109          (x2 x-transformer)
110          (y2 y-transformer))
111       (if filled
112         (gd-image-filled-rectangle (img image) x1 y1 x2 y2 color)
113         (gd-image-rectangle (img image) x1 y1 x2 y2 color))))
114   (values x1 y1 x2 y2))
115
116 (defun draw-rectangle (rectangle &key filled (color *default-color*) (image *default-image*))
117   "Draws a rectangle with upper left corner \(X1,Y1) and lower right
118 corner \(X2,Y2) where RECTANGLE is the list \(X1 Y1 X2 Y2). If FILLED
119 is true the rectangle will be filled with COLOR, otherwise it will be
120 outlined."
121   (draw-rectangle* (first rectangle)
122                    (second rectangle)
123                    (third rectangle)
124                    (fourth rectangle)
125                    :filled filled
126                    :color color
127                    :image image)
128   rectangle)
129
130 (defgeneric draw-polygon (vertices &key filled start end color image)
131   (:documentation "Draws a polygon with the VERTICES \(at least three)
132 specified as a list \(x1 y1 x2 y2 ...) or as a vector #\(x1 y1 x2 y2
133 ...). If FILLED is true the polygon will be filled with COLOR,
134 otherwise it will be outlined. If START and/or END are specified then
135 only the corresponding part of VERTICES is used as input."))
136
137 (defmethod draw-polygon ((vertices vector) &key filled (start 0) (end (length vertices)) (color *default-color*) (image *default-image*))
138   (check-type start integer)
139   (check-type end integer)
140   (check-type image image)
141   (let ((effective-length (- end start)))
142     (unless (and (>= effective-length 6)
143                  (evenp effective-length))
144       (error "We need an even number of at least six vertices"))
145     (with-safe-alloc (arr (allocate-foreign-object 'gd-point (/ effective-length 2))
146                           (free-foreign-object arr))
147       (with-color-argument
148           (with-transformed-alternative
149               (((aref vertices i) x-transformer)
150                ((aref vertices (1+ i)) y-transformer))
151             (loop for i from start below end by 2
152                   for point-ptr = (deref-array arr '(:array gd-point) (/ (- i start) 2))
153                   do (setf (get-slot-value point-ptr 'gd-point 'x)
154                              (aref vertices i)
155                            (get-slot-value point-ptr 'gd-point 'y)
156                              (aref vertices (1+ i))))
157             (funcall (if filled
158                        #'gd-image-filled-polygon
159                        #'gd-image-polygon)
160                      (img image) arr (/ effective-length 2) color)
161             vertices)))))
162
163 (defmethod draw-polygon ((vertices list) &key filled (start 0) (end (length vertices)) (color *default-color*) (image *default-image*))
164   (check-type start integer)
165   (check-type end integer)
166   (check-type image image)
167   (let ((effective-length (- end start)))
168     (unless (and (>= effective-length 6)
169                  (evenp effective-length))
170       (error "We need an even number of at least six vertices"))
171     (with-safe-alloc (arr (allocate-foreign-object 'gd-point (/ effective-length 2))
172                           (free-foreign-object arr))
173       (with-color-argument
174           (with-transformed-alternative
175               (((first x/y) x-transformer)
176                ((second x/y) y-transformer))
177             (loop for i below (- end start) by 2
178                   ;; we don't use LOOP's destructuring capabilities here
179                   ;; because of your simple WITH-TRANSFORMED-ALTERNATIVE
180                   ;; macro which would get confused
181                   for x/y on (nthcdr start vertices) by #'cddr
182                   for point-ptr = (deref-array arr '(:array gd-point) (/ i 2))
183                   do (setf (get-slot-value point-ptr 'gd-point 'x)
184                              (first x/y)
185                            (get-slot-value point-ptr 'gd-point 'y)
186                              (second x/y)))
187             (funcall (if filled
188                        #'gd-image-filled-polygon
189                        #'gd-image-polygon)
190                      (img image) arr (/ effective-length 2) color)
191             vertices)))))
192
193 (defun draw-filled-ellipse (center-x center-y width height &key (color *default-color*) (image *default-image*))
194   "Draws a filled ellipse centered at \(CENTER-X, CENTER-Y) with width
195 WIDTH and height HEIGHT."
196   (check-type image image)
197   (with-color-argument
198     (with-transformed-alternative
199         ((center-x x-transformer)
200          (center-y y-transformer)
201          (width w-transformer)
202          (height h-transformer))
203       (gd-image-filled-ellipse (img image) center-x center-y width height color)))
204   (values center-x center-y width height))
205
206 (defun draw-filled-circle (center-x center-y radius &key (color *default-color*) (image *default-image*))
207   "Draws a filled circle centered at \(CENTER-X, CENTER-Y) with radius
208 RADIUS."
209   (draw-filled-ellipse center-x center-y (* 2 radius) (* 2 radius)
210                 :color color :image image)
211   (values center-x center-y radius))
212
213 (defun draw-arc (center-x center-y width height start end &key straight-line center-connect filled (color *default-color*) (image *default-image*))
214   "Draws a partial ellipse centered at \(CENTER-X, CENTER-Y) with
215 width WIDTH and height HEIGHT. The arc begins at angle START and ends
216 at angle END. If STRAIGHT-LINE is true the start and end points are
217 just connected with a straight line. If CENTER-CONNECT is true, they
218 are connected to the center \(which is useful to create 'pie
219 slices'). If FILLED is true the arc will be filled with COLOR,
220 otherwise it will be outlined."
221   (check-type image image)
222   (with-color-argument
223     (with-transformed-alternative
224         ((center-x x-transformer)
225          (center-y y-transformer)
226          (width w-transformer)
227          (height h-transformer)
228          (start angle-transformer)
229          (end angle-transformer))
230       (cond ((not (or straight-line filled center-connect))
231               (gd-image-arc (img image) center-x center-y width height start end color))
232             (t
233               (gd-image-filled-arc (img image) center-x center-y width height start end color
234                                    (logior (if straight-line +gd-chord+ 0)
235                                            (if filled 0 +gd-no-fill+)
236                                            (if center-connect +gd-edged+ 0)))))))
237   (values center-x center-y width height start end))
238
239 (defun fill-image (x y &key border (color *default-color*) (image *default-image*))
240   "Floods a portion of the image IMAGE with the color COLOR beginning
241 at point \(X, Y) and extending into the surrounding region. If BORDER
242 is true it must be a color and the filling will stop at the specified
243 border color. Otherwise only points with the same color as the
244 starting point will be colored."
245   (check-type border (or null integer))
246   (check-type image image)
247   (with-color-argument
248     (with-transformed-alternative
249         ((x x-transformer)
250          (y y-transformer))
251       (if border
252         (gd-image-fill-to-border (img image) x y border color)
253         (gd-image-fill (img image) x y color))))
254   (values x y))
255
256 (defun clipping-rectangle (&optional (image *default-image*))
257   "Returns the clipping rectangle of IMAGE as a list of four
258 elements."
259   (check-type image image)
260   (with-transformed-alternative
261       (((deref-pointer x1p) x-inv-transformer)
262        ((deref-pointer y1p) y-inv-transformer)
263        ((deref-pointer x2p) x-inv-transformer)
264        ((deref-pointer y2p) y-inv-transformer))
265     (with-foreign-object (x1p :int)
266       (with-foreign-object (y1p :int)
267         (with-foreign-object (x2p :int)
268           (with-foreign-object (y2p :int)
269             (gd-image-get-clip (img image) x1p y1p x2p y2p)
270             (list (deref-pointer x1p :int)
271                   (deref-pointer y1p :int)
272                   (deref-pointer x2p :int)
273                   (deref-pointer y2p :int))))))))
274
275 (defun (setf clipping-rectangle) (rectangle &optional (image *default-image*))
276   "Sets the clipping rectangle of IMAGE where rectangle should be a
277 list \(X1 Y1 X2 Y2)."
278   (check-type image image)
279   (with-transformed-alternative
280       (((first rectangle) x-transformer)
281        ((second rectangle) y-transformer)
282        ((third rectangle) x-transformer)
283        ((fourth rectangle) y-transformer))
284     (gd-image-set-clip (img image)
285                        (first rectangle)
286                        (second rectangle)
287                        (third rectangle)
288                        (fourth rectangle)))
289   rectangle)
290
291 (defun clipping-rectangle* (&optional (image *default-image*))
292   "Returns the clipping rectangle of IMAGE as four values."
293   (check-type image image)
294   (with-transformed-alternative
295       (((deref-pointer x1p) x-inv-transformer)
296        ((deref-pointer y1p) y-inv-transformer)
297        ((deref-pointer x2p) x-inv-transformer)
298        ((deref-pointer y2p) y-inv-transformer))
299     (with-foreign-object (x1p :int)
300       (with-foreign-object (y1p :int)
301         (with-foreign-object (x2p :int)
302           (with-foreign-object (y2p :int)
303             (gd-image-get-clip (img image) x1p y1p x2p y2p)
304             (values (deref-pointer x1p :int)
305                     (deref-pointer y1p :int)
306                     (deref-pointer x2p :int)
307                     (deref-pointer y2p :int))))))))
308
309 (defun set-clipping-rectangle* (x1 y1 x2 y2 &optional (image *default-image*))
310   "Sets the clipping rectangle of IMAGE to be the rectangle with upper
311 left corner \(X1, Y1) and lower right corner \(X2, Y2)."
312   (check-type image image)
313   (with-transformed-alternative
314       ((x1 x-transformer)
315        (y1 y-transformer)
316        (x2 x-transformer)
317        (y2 y-transformer))
318     (gd-image-set-clip (img image) x1 y1 x2 y2))
319   (values x1 y1 x2 y2))
320
321 (defmacro with-clipping-rectangle ((rectangle &key (image '*default-image*)) &body body)
322   "Executes BODY with the clipping rectangle of IMAGE set to RECTANGLE
323 which should be a list \(X1 Y1 X2 Y2). The previous clipping rectangle
324 is guaranteed to be restored before the macro exits."
325   ;; we rebind everything so we have left-to-right evaluation
326   (with-rebinding (rectangle image)
327     (with-unique-names (%x1 %y1 %x2 %y2)
328       `(multiple-value-bind (,%x1 ,%y1 ,%x2 ,%y2)
329            (without-transformations
330              (clipping-rectangle* ,image))
331          (unwind-protect
332              (progn
333                (setf (clipping-rectangle ,image) ,rectangle)
334                ,@body)
335            (without-transformations
336              (set-clipping-rectangle* ,%x1 ,%y1 ,%x2 ,%y2 ,image)))))))
337
338 (defmacro with-clipping-rectangle* ((x1 y1 x2 y2 &key (image '*default-image*)) &body body)
339   "Executes BODY with the clipping rectangle of IMAGE set to the
340 rectangle with upper left corner \(X1, Y1) and lower right corner
341 \(X2, Y2). The previous clipping rectangle is guaranteed to be
342 restored before the macro exits."
343   ;; we rebind everything so we have left-to-right evaluation
344   (with-rebinding (x1 y1 x2 y2 image)
345     (with-unique-names (%x1 %y1 %x2 %y2)
346       `(multiple-value-bind (,%x1 ,%y1 ,%x2 ,%y2)
347            (without-transformations
348              (clipping-rectangle* ,image))
349          (unwind-protect
350              (progn
351                (set-clipping-rectangle* ,x1 ,y1 ,x2 ,y2 ,image)
352                ,@body)
353            (without-transformations
354              (set-clipping-rectangle* ,%x1 ,%y1 ,%x2 ,%y2 ,image)))))))
Note: See TracBrowser for help on using the browser.