[AdgToyText] Refactored using maps
[adg.git] / cpml / cpml-pair.c
blob82ebe842e49967f5e4d54bf1e6ba39d17548e2f9
1 /* CPML - Cairo Path Manipulation Library
2 * Copyright (C) 2008, 2009 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.
20 /**
21 * SECTION:pair
22 * @title: CpmlPair
23 * @short_description: A structure holding a couple of values
25 * The CpmlPair is a generic 2D structure. It can be used to represent
26 * coordinates, sizes, offsets or whatever have two components.
28 * The name comes from MetaFont.
29 **/
31 /**
32 * CpmlPair:
33 * @x: the x component of the pair
34 * @y: the y component of the pair
36 * A generic 2D structure.
37 **/
39 /**
40 * CpmlVector:
41 * @x: the x component of the vector
42 * @y: the y component of the vector
44 * Another name for #CpmlPair. It is used to clarify when a function expects
45 * a pair or a vector.
47 * A vector represents a line starting from the origin (0,0) and ending
48 * to the given coordinates pair. Vectors are useful to define directions
49 * and length at once. Keep in mind the cairo default coordinates system
50 * is not problably what you expect: the x axis increases at right
51 * (as usual) but the y axis increases at down (the reverse of a usual
52 * cartesian plan). An angle of 0 is at V=(1; 0) (middle right).
53 **/
55 #include "cpml-pair.h"
56 #include "cpml-macros.h"
58 #include <stdlib.h>
59 #include <string.h>
60 #include <math.h>
63 static CpmlPair fallback_pair = { 0, 0 };
66 /**
67 * cpml_pair_copy:
68 * @pair: the destination #CpmlPair
69 * @src: the source #CpmlPair
71 * Copies @src in @pair.
73 * Return value: @pair
74 **/
75 CpmlPair *
76 cpml_pair_copy(CpmlPair *pair, const CpmlPair *src)
78 return memcpy(pair, src, sizeof(CpmlPair));
81 /**
82 * cpml_pair_from_cairo:
83 * @pair: the destination #CpmlPair
84 * @path_data: the original path data point
86 * Gets @pair from a #cairo_path_data_t struct. @path_data should contains
87 * a point data: it is up to the caller to be sure @path_data is valid.
89 * Return value: @pair
90 **/
91 CpmlPair *
92 cpml_pair_from_cairo(CpmlPair *pair, const cairo_path_data_t *path_data)
94 pair->x = path_data->point.x;
95 pair->y = path_data->point.y;
96 return pair;
101 * cpml_pair_negate:
102 * @pair: a #CpmlPair
104 * Negates the coordinates of @pair.
106 void
107 cpml_pair_negate(CpmlPair *pair)
109 pair->x = - pair->x;
110 pair->y = - pair->y;
114 * cpml_pair_invert:
115 * @pair: a #CpmlPair
117 * Inverts (1/x) the coordinates of @pair. If @pair cannot be inverted
118 * because one coordinate is 0, 0 is returned and no transformation is
119 * performed.
121 * Return value: 1 on success, 0 on errors
123 cairo_bool_t
124 cpml_pair_invert(CpmlPair *pair)
126 if (pair->x == 0 || pair->y == 0)
127 return 0;
129 pair->x = 1. / pair->x;
130 pair->y = 1. / pair->y;
131 return 1;
135 * cpml_pair_add:
136 * @pair: the destination #CpmlPair
137 * @src: the source pair to add
139 * Adds @src to @pair and stores the result in @pair. In other words,
140 * @pair = @pair + @src.
142 void
143 cpml_pair_add(CpmlPair *pair, const CpmlPair *src)
145 pair->x += src->x;
146 pair->y += src->y;
150 * cpml_pair_sub:
151 * @pair: the destination #CpmlPair
152 * @src: the source pair to subtract
154 * Subtracts @src from @pair and stores the result in @pair. In other words,
155 * @pair = @pair - @src.
157 void
158 cpml_pair_sub(CpmlPair *pair, const CpmlPair *src)
160 pair->x -= src->x;
161 pair->y -= src->y;
165 * cpml_pair_mul:
166 * @pair: the destination #CpmlPair
167 * @src: the source pair factor
169 * Multiplies the x coordinate of @pair by the @src x factor and the
170 * y coordinate by the @src y factor.
172 void
173 cpml_pair_mul(CpmlPair *pair, const CpmlPair *src)
175 pair->x *= src->x;
176 pair->y *= src->y;
180 * cpml_pair_div:
181 * @pair: the destination #CpmlPair
182 * @src: the source pair divisor
184 * Divides the x coordinate of @pair by the @src x divisor and the
185 * y coordinate by the @src y divisor. If @pair cannot be divided
186 * because of a division by 0, 0 is returned and no transformation
187 * is performed.
189 * Return value: 1 on success, 0 on errors
191 cairo_bool_t
192 cpml_pair_div(CpmlPair *pair, const CpmlPair *src)
194 if (src->x == 0 || src->y == 0)
195 return 0;
197 pair->x /= src->x;
198 pair->y /= src->y;
199 return 1;
203 * cpml_pair_transform:
204 * @pair: the destination #CpmlPair struct
205 * @matrix: the transformation matrix
207 * Shortcut to apply a specific transformation matrix to @pair.
209 void
210 cpml_pair_transform(CpmlPair *pair, const cairo_matrix_t *matrix)
212 cairo_matrix_transform_point(matrix, &pair->x, &pair->y);
217 * cpml_pair_squared_distance:
218 * @from: the first #CpmlPair struct
219 * @to: the second #CpmlPair struct
221 * Gets the squared distance between @from and @to. This value is useful
222 * for comparation purpose: if you need to get the real distance, use
223 * cpml_pair_distance().
225 * @from or @to could be %NULL, in which case the fallback (0, 0) pair
226 * will be used.
228 * Return value: the squared distance
230 double
231 cpml_pair_squared_distance(const CpmlPair *from, const CpmlPair *to)
233 double x, y;
235 if (from == NULL)
236 from = &fallback_pair;
237 if (to == NULL)
238 to = &fallback_pair;
240 x = to->x - from->x;
241 y = to->y - from->y;
243 return x * x + y * y;
247 * cpml_pair_distance:
248 * @from: the first #CpmlPair struct
249 * @to: the second #CpmlPair struct
250 * @distance: where to store the result
252 * Gets the distance between @from and @to, storing the result in @distance.
253 * If you need this value only for comparation purpose, you could use
254 * cpm_pair_squared_distance() instead.
256 * @from or @to could be %NULL, in which case the fallback (0, 0) pair
257 * will be used.
259 * The algorithm used is adapted from:
260 * "Replacing Square Roots by Pythagorean Sums"
261 * by Clave Moler and Donald Morrison (1983)
262 * IBM Journal of Research and Development 27 (6): 577–581
263 * http://www.research.ibm.com/journal/rd/276/ibmrd2706P.pdf
265 * Return value: the distance
267 double
268 cpml_pair_distance(const CpmlPair *from, const CpmlPair *to)
270 double x, y;
271 double p, q, r, s;
273 if (from == NULL)
274 from = &fallback_pair;
275 if (to == NULL)
276 to = &fallback_pair;
278 x = to->x - from->x;
279 y = to->y - from->y;
281 if (x < 0)
282 x = -x;
283 if (y < 0)
284 y = -y;
286 if (x > y) {
287 p = x;
288 q = y;
289 } else {
290 p = y;
291 q = x;
294 if (p > 0) {
295 for (;;) {
296 r = q/p;
297 r *= r;
298 if (r == 0)
299 break;
301 s = r / (4+r);
302 p += 2*s*p;
303 q *= s;
307 return p;
311 * cpml_vector_from_angle:
312 * @vector: the destination #CpmlVector
313 * @angle: angle of direction, in radians
314 * @length: the length of the vector
316 * Calculates the coordinates of the point far @length from the origin
317 * in the @angle direction. The result is stored in @vector.
319 * Return value: @vector
321 CpmlVector *
322 cpml_vector_from_angle(CpmlVector *vector, double angle, double length)
324 /* Check for common conditions */
325 if (angle == -M_PI_2) {
326 vector->x = 0;
327 vector->y = -1;
328 return vector;
330 if (angle == M_PI_2) {
331 vector->x = 0;
332 vector->y = +1;
333 return vector;
335 if (angle == M_PI || angle == -M_PI) {
336 vector->x = -1;
337 vector->y = 0;
338 return vector;
340 if (angle == 0) {
341 vector->x = +1;
342 vector->y = 0;
343 return vector;
346 vector->x = cos(angle);
347 vector->y = sin(angle);
349 return vector;
353 * cpml_vector_set_length:
354 * @vector: a #CpmlVector
355 * @length: the new length
357 * Imposes the specified @length to @vector. If the old length is 0
358 * (and so the direction is not known), nothing happens.
360 void
361 cpml_vector_set_length(CpmlVector *vector, double length)
363 double divisor = cpml_pair_distance(NULL, vector);
365 /* Check for valid length (anything other than 0) */
366 if (divisor <= 0)
367 return;
369 divisor /= length;
370 vector->x /= divisor;
371 vector->y /= divisor;
375 * cpml_vector_angle:
376 * @vector: the source #CpmlVector
378 * Gets the angle of @vector, in radians. If @vector is (0, 0),
379 * 0 is returned.
381 * Return value: the angle in radians, a value between -M_PI and M_PI
383 double
384 cpml_vector_angle(const CpmlVector *vector)
386 /* Check for common conditions */
387 if (vector->y == 0)
388 return vector->x >= 0 ? 0 : M_PI;
389 if (vector->x == 0)
390 return vector->y > 0 ? M_PI_2 : -M_PI_2;
391 if (vector->x == vector->y)
392 return vector->x > 0 ? M_PI_4 : -M_PI_4 * 3;
393 if (vector->x == -vector->y)
394 return vector->x > 0 ? -M_PI_4 : M_PI_4 * 3;
396 return atan2(vector->y, vector->x);
400 * cpml_vector_normal:
401 * @vector: the subject #CpmlVector
403 * Stores in @vector a vector normal to the original @vector.
404 * The length is retained.
406 * The algorithm is really quick because no trigonometry is involved.
408 void
409 cpml_vector_normal(CpmlVector *vector)
411 double tmp = vector->x;
413 vector->x = -vector->y;
414 vector->y = tmp;
418 * cpml_pair_to_cairo:
419 * @pair: the destination #CpmlPair
420 * @path_data: the original path data point
422 * Sets a #cairo_path_data_t struct to @pair. This is exactly the reverse
423 * operation of cpml_pair_from_cairo().
425 void
426 cpml_pair_to_cairo(const CpmlPair *pair, cairo_path_data_t *path_data)
428 path_data->point.x = pair->x;
429 path_data->point.y = pair->y;