[CpmlPair] Improved API
[adg.git] / cpml / cpml-pair.c
blobe5a76d244bbf6596a6e2894232f31d2a3fbb9485
1 /* CPML - Cairo Path Manipulation Library
2 * Copyright (C) 2008, Nicola Fontana <ntd at entidi.it>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library 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 GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
21 /**
22 * SECTION:cpmlpair
23 * @title: CpmlPair
24 * @short_description: A structure holding a couple of values
26 * The CpmlPair is a generic 2D structure. It can be used to represent points,
27 * sizes, offsets or whatever have two components.
29 * The name comes from MetaFont.
32 /**
33 * CpmlPair:
34 * @x: the x component of the pair
35 * @y: the y component of the pair
37 * A generic 2D structure.
40 /**
41 * CpmlVector:
42 * @x: the x component of the vector
43 * @y: the y component of the vector
45 * A subclass of a #CpmlPair. A vector represents the coordinates of a point
46 * distant 1 from the origin (0, 0). The vectors are useful to define a
47 * direction and are better suited than angles for simplifying interpolations.
50 #include "cpml-pair.h"
52 #include <stdlib.h>
55 static CpmlPair fallback_pair = { 0., 0. };
58 /**
59 * cpml_pair_copy:
60 * @pair: the destination #CpmlPair struct
61 * @src: the source #CpmlPair struct
63 * Assign @src to @pair.
65 * Return value: 1 if @pair was set, 0 on errors
67 cairo_bool_t
68 cpml_pair_copy(CpmlPair *pair, const CpmlPair *src)
70 pair->x = src->x;
71 pair->y = src->y;
72 return 1;
75 /**
76 * cpml_pair_transform:
77 * @pair: the destination #CpmlPair struct
78 * @matrix: the transformation matrix
80 * Shortcut to apply a specific transformation matrix to @pair.
82 * Return value: 1 if @pair was transformed, 0 on errors
83 **/
84 cairo_bool_t
85 cpml_pair_transform(CpmlPair *pair, const cairo_matrix_t *matrix)
87 cairo_matrix_transform_point(matrix, &pair->x, &pair->y);
88 return 1;
92 /**
93 * cpml_pair_squared_distance:
94 * @from: the first #CpmlPair struct
95 * @to: the second #CpmlPair struct
97 * Gets the squared distance between @from and @to. This value is useful
98 * for comparation purpose: if you need to get the real distance, use
99 * cpml_pair_distance().
101 * @from or @to could be %NULL, in which case the fallback (0, 0) pair
102 * will be used.
104 * Return value: the squared distance
106 double
107 cpml_pair_squared_distance(const CpmlPair *from, const CpmlPair *to)
109 double x, y;
111 if (from == NULL)
112 from = &fallback_pair;
113 if (to == NULL)
114 to = &fallback_pair;
116 x = to->x - from->x;
117 y = to->y - from->y;
119 return x * x + y * y;
123 * cpml_pair_distance:
124 * @from: the first #CpmlPair struct
125 * @to: the second #CpmlPair struct
126 * @distance: where to store the result
128 * Gets the distance between @from and @to, storing the result in @distance.
129 * If you need this value only for comparation purpose, you could use
130 * cpm_pair_squared_distance() instead.
132 * @from or @to could be %NULL, in which case the fallback (0, 0) pair
133 * will be used.
135 * The algorithm used is adapted from:
136 * "Replacing Square Roots by Pythagorean Sums"
137 * by Clave Moler and Donald Morrison (1983)
138 * IBM Journal of Research and Development 27 (6): 577–581
139 * http://www.research.ibm.com/journal/rd/276/ibmrd2706P.pdf
141 * Return value: 1 if @distance was properly set, 0 on errors
143 double
144 cpml_pair_distance(const CpmlPair *from, const CpmlPair *to)
146 double x, y;
147 double p, q, r, s;
149 if (from == NULL)
150 from = &fallback_pair;
151 if (to == NULL)
152 to = &fallback_pair;
154 x = to->x - from->x;
155 y = to->y - from->y;
157 if (x < 0)
158 x = -x;
159 if (y < 0)
160 y = -y;
162 if (x > y) {
163 p = x;
164 q = y;
165 } else {
166 p = y;
167 q = x;
170 if (p > 0) {
171 for (;;) {
172 r = q/p;
173 r *= r;
174 if (r == 0)
175 break;
177 s = r / (4+r);
178 p += 2*s*p;
179 q *= s;
183 return p;
187 * cpml_pair_angle:
188 * @from: the first #CpmlPair struct
189 * @to: the second #CpmlPair struct
190 * @angle: where to store the result
192 * Gets the angle between @from and @to, storing the result in @angle.
194 * @from or @to could be %NULL, in which case the fallback (0, 0) pair
195 * will be used.
197 * Return value: 1 if @angle was properly set, 0 on errors
199 cairo_bool_t
200 cpml_pair_angle(double *angle, const CpmlPair *from, const CpmlPair *to)
202 static CpmlPair cached_pair = { 1., 0. };
203 static double cached_angle = 0.;
204 CpmlPair pair;
206 if (from == NULL)
207 from = &fallback_pair;
208 if (to == NULL)
209 to = &fallback_pair;
211 pair.x = to->x - from->x;
212 pair.y = to->y - from->y;
214 /* Check for cached result */
215 if (pair.x == cached_pair.x && pair.y == cached_pair.y) {
216 *angle = cached_angle;
217 } else if (pair.y == 0.) {
218 *angle = pair.x >= 0. ? CPML_DIR_RIGHT : CPML_DIR_LEFT;
219 } else if (pair.x == 0.) {
220 *angle = pair.y > 0. ? CPML_DIR_UP : CPML_DIR_DOWN;
221 } else if (pair.x == pair.y) {
222 *angle = pair.x > 0. ? M_PI / 4. : 5. * M_PI / 4.;
223 } else if (pair.x == -pair.y) {
224 *angle = pair.x > 0. ? 7. * M_PI / 4. : 3. * M_PI / 4.;
225 } else {
226 *angle = atan(pair.y / pair.x);
228 if (pair.x < 0.0)
229 *angle += M_PI;
230 else if (pair.y < 0.0)
231 *angle += 2.0 * M_PI;
233 /* Cache registration */
234 cached_angle = *angle;
235 cpml_pair_copy(&cached_pair, &pair);
238 return 1;
242 * cpml_vector_from_pair:
243 * @vector: an allocated #CpmlPair struct
244 * @pair: the source pair
245 * @length: the final vector length
247 * Unitizes @pair, that is given the line L passing throught the origin and
248 * @pair, gets the coordinate of the point on this line far @length from
249 * the origin, and store the result in @vector. If @pair itsself is the origin,
250 * (0, 0) is returned.
252 * @pair and @vector can be the same struct.
254 void
255 cpml_vector_from_pair(CpmlPair *vector, const CpmlPair *pair, double length)
257 double distance, factor;
259 distance = cpml_pair_distance(NULL, pair);
260 factor = length / distance;
262 vector->x = pair->x * factor;
263 vector->y = pair->y * factor;
267 * cpml_vector_from_angle:
268 * @vector: an allocated #CpmlPair struct
269 * @angle: angle of direction, in radians
270 * @length: the final vector length
272 * Calculates the coordinates of the point far @length from the origin
273 * in the @angle direction. The result is stored in @vector.
275 void
276 cpml_vector_from_angle(CpmlPair *vector, double angle, double length)
278 static double cached_angle = 0.;
279 static CpmlPair cached_vector = { 1., 0. };
281 /* Check for cached result */
282 if (angle == cached_angle) {
283 vector->x = cached_vector.x;
284 vector->y = cached_vector.y;
285 } else {
286 vector->x = cos(angle);
287 vector->y = sin(angle);
289 /* Cache registration */
290 cached_angle = angle;
291 cpml_pair_copy(&cached_vector, vector);
294 vector->x *= length;
295 vector->y *= length;