| 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 |
|
|---|