[ADG] Added AdgProjectionScheme
[adg.git] / cpml / cpml-pair.c
blobf6699a41ecc9e0515425c611a82ba9f3d2ff31f0
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.
21 /**
22 * SECTION:cpml-pair
23 * @Section_Id:CpmlPair
24 * @title: CpmlPair
25 * @short_description: Basic struct holding a couple of values
27 * The #CpmlPair is a generic 2D structure. It can be used to represent
28 * coordinates, sizes, offsets or whatever have two components.
30 * The name comes from MetaFont.
31 **/
33 /**
34 * CpmlPair:
35 * @x: the x component of the pair
36 * @y: the y component of the pair
38 * A generic 2D structure.
39 **/
41 /**
42 * CpmlVector:
43 * @x: the x component of the vector
44 * @y: the y component of the vector
46 * Another name for #CpmlPair. It is used to clarify when a function expects
47 * a pair or a vector.
49 * A vector represents a line starting from the origin (0,0) and ending
50 * to the given coordinates pair. Vectors are useful to define directions
51 * and length at once. Keep in mind the cairo default coordinates system
52 * is not problably what you expect: the x axis increases at right
53 * (as usual) but the y axis increases at down (the reverse of a usual
54 * cartesian plan). An angle of 0 is at V=(1; 0) (middle right).
55 **/
58 #include "cpml-pair.h"
60 #include <stdlib.h>
61 #include <string.h>
62 #include <math.h>
65 static CpmlPair fallback_pair = { 0, 0 };
68 /**
69 * cpml_pair_copy:
70 * @pair: the destination #CpmlPair
71 * @src: the source #CpmlPair
73 * Copies @src in @pair.
75 * Return value: @pair
76 **/
77 CpmlPair *
78 cpml_pair_copy(CpmlPair *pair, const CpmlPair *src)
80 return memcpy(pair, src, sizeof(CpmlPair));
83 /**
84 * cpml_pair_from_cairo:
85 * @pair: the destination #CpmlPair
86 * @path_data: the original path data point
88 * Gets @pair from a #cairo_path_data_t struct. @path_data should contains
89 * a point data: it is up to the caller to be sure @path_data is valid.
91 * Return value: @pair
92 **/
93 CpmlPair *
94 cpml_pair_from_cairo(CpmlPair *pair, const cairo_path_data_t *path_data)
96 pair->x = path_data->point.x;
97 pair->y = path_data->point.y;
98 return pair;
103 * cpml_pair_negate:
104 * @pair: a #CpmlPair
106 * Negates the coordinates of @pair.
108 void
109 cpml_pair_negate(CpmlPair *pair)
111 pair->x = - pair->x;
112 pair->y = - pair->y;
116 * cpml_pair_invert:
117 * @pair: a #CpmlPair
119 * Inverts (1/x) the coordinates of @pair. If @pair cannot be inverted
120 * because one coordinate is 0, 0 is returned and no transformation is
121 * performed.
123 * Return value: 1 on success, 0 on errors
125 cairo_bool_t
126 cpml_pair_invert(CpmlPair *pair)
128 if (pair->x == 0 || pair->y == 0)
129 return 0;
131 pair->x = 1. / pair->x;
132 pair->y = 1. / pair->y;
133 return 1;
137 * cpml_pair_add:
138 * @pair: the destination #CpmlPair
139 * @src: the source pair to add
141 * Adds @src to @pair and stores the result in @pair. In other words,
142 * @pair = @pair + @src.
144 void
145 cpml_pair_add(CpmlPair *pair, const CpmlPair *src)
147 pair->x += src->x;
148 pair->y += src->y;
152 * cpml_pair_sub:
153 * @pair: the destination #CpmlPair
154 * @src: the source pair to subtract
156 * Subtracts @src from @pair and stores the result in @pair. In other words,
157 * @pair = @pair - @src.
159 void
160 cpml_pair_sub(CpmlPair *pair, const CpmlPair *src)
162 pair->x -= src->x;
163 pair->y -= src->y;
167 * cpml_pair_mul:
168 * @pair: the destination #CpmlPair
169 * @src: the source pair factor
171 * Multiplies the x coordinate of @pair by the @src x factor and the
172 * y coordinate by the @src y factor.
174 void
175 cpml_pair_mul(CpmlPair *pair, const CpmlPair *src)
177 pair->x *= src->x;
178 pair->y *= src->y;
182 * cpml_pair_div:
183 * @pair: the destination #CpmlPair
184 * @src: the source pair divisor
186 * Divides the x coordinate of @pair by the @src x divisor and the
187 * y coordinate by the @src y divisor. If @pair cannot be divided
188 * because of a division by 0, 0 is returned and no transformation
189 * is performed.
191 * Return value: 1 on success, 0 on errors
193 cairo_bool_t
194 cpml_pair_div(CpmlPair *pair, const CpmlPair *src)
196 if (src->x == 0 || src->y == 0)
197 return 0;
199 pair->x /= src->x;
200 pair->y /= src->y;
201 return 1;
205 * cpml_pair_transform:
206 * @pair: the destination #CpmlPair struct
207 * @matrix: the transformation matrix
209 * Shortcut to apply a specific transformation matrix to @pair.
211 void
212 cpml_pair_transform(CpmlPair *pair, const cairo_matrix_t *matrix)
214 cairo_matrix_transform_point(matrix, &pair->x, &pair->y);
218 * cpml_pair_squared_distance:
219 * @from: the first #CpmlPair struct
220 * @to: the second #CpmlPair struct
222 * Gets the squared distance between @from and @to. This value is useful
223 * for comparation purpose: if you need to get the real distance, use
224 * cpml_pair_distance().
226 * @from or @to could be %NULL, in which case the fallback (0, 0) pair
227 * will be used.
229 * Return value: the squared distance
231 double
232 cpml_pair_squared_distance(const CpmlPair *from, const CpmlPair *to)
234 double x, y;
236 if (from == NULL)
237 from = &fallback_pair;
238 if (to == NULL)
239 to = &fallback_pair;
241 x = to->x - from->x;
242 y = to->y - from->y;
244 return x * x + y * y;
248 * cpml_pair_distance:
249 * @from: the first #CpmlPair struct
250 * @to: the second #CpmlPair struct
251 * @distance: where to store the result
253 * Gets the distance between @from and @to, storing the result in @distance.
254 * If you need this value only for comparation purpose, you could use
255 * cpm_pair_squared_distance() instead.
257 * @from or @to could be %NULL, in which case the fallback (0, 0) pair
258 * will be used.
260 * The algorithm used is adapted from:
261 * "Replacing Square Roots by Pythagorean Sums"
262 * by Clave Moler and Donald Morrison (1983)
263 * IBM Journal of Research and Development 27 (6): 577–581
264 * http://www.research.ibm.com/journal/rd/276/ibmrd2706P.pdf
266 * Return value: the distance
268 double
269 cpml_pair_distance(const CpmlPair *from, const CpmlPair *to)
271 double x, y;
272 double p, q, r, s;
274 if (from == NULL)
275 from = &fallback_pair;
276 if (to == NULL)
277 to = &fallback_pair;
279 x = to->x - from->x;
280 y = to->y - from->y;
282 if (x < 0)
283 x = -x;
284 if (y < 0)
285 y = -y;
287 if (x > y) {
288 p = x;
289 q = y;
290 } else {
291 p = y;
292 q = x;
295 if (p > 0) {
296 for (;;) {
297 r = q/p;
298 r *= r;
299 if (r == 0)
300 break;
302 s = r / (4+r);
303 p += 2*s*p;
304 q *= s;
308 return p;
312 * cpml_pair_to_cairo:
313 * @pair: the destination #CpmlPair
314 * @path_data: the original path data point
316 * Sets a #cairo_path_data_t struct to @pair. This is exactly the reverse
317 * operation of cpml_pair_from_cairo().
319 void
320 cpml_pair_to_cairo(const CpmlPair *pair, cairo_path_data_t *path_data)
322 path_data->point.x = pair->x;
323 path_data->point.y = pair->y;
328 * cpml_vector_from_angle:
329 * @vector: the destination #CpmlVector
330 * @angle: angle of direction, in radians
332 * Calculates the coordinates of the point far %1 from the origin
333 * in the @angle direction. The result is stored in @vector.
335 * Return value: @vector
337 CpmlVector *
338 cpml_vector_from_angle(CpmlVector *vector, double angle)
340 /* Check for common conditions */
341 if (angle == -M_PI_2) {
342 vector->x = 0;
343 vector->y = -1;
344 return vector;
346 if (angle == M_PI_2) {
347 vector->x = 0;
348 vector->y = +1;
349 return vector;
351 if (angle == M_PI || angle == -M_PI) {
352 vector->x = -1;
353 vector->y = 0;
354 return vector;
356 if (angle == 0) {
357 vector->x = +1;
358 vector->y = 0;
359 return vector;
362 vector->x = cos(angle);
363 vector->y = sin(angle);
365 return vector;
369 * cpml_vector_set_length:
370 * @vector: a #CpmlVector
371 * @length: the new length
373 * Imposes the specified @length to @vector. If the old length is %0
374 * (and so the direction is not known), nothing happens. If @length
375 * is %0, @vector is set to (0, 0).
377 * The @length parameter can be negative, in which case the vector
378 * is inverted.
380 void
381 cpml_vector_set_length(CpmlVector *vector, double length)
383 double divisor;
385 if (length == 0) {
386 vector->x = 0;
387 vector->y = 0;
388 return;
391 divisor = cpml_pair_distance(NULL, vector);
393 /* Check for valid length (anything other than 0) */
394 if (divisor != 0) {
395 divisor /= length;
396 vector->x /= divisor;
397 vector->y /= divisor;
402 * cpml_vector_angle:
403 * @vector: the source #CpmlVector
405 * Gets the angle of @vector, in radians. If @vector is (0, 0),
406 * 0 is returned.
408 * Return value: the angle in radians, a value between -M_PI and M_PI
410 double
411 cpml_vector_angle(const CpmlVector *vector)
413 /* Check for common conditions */
414 if (vector->y == 0)
415 return vector->x >= 0 ? 0 : M_PI;
416 if (vector->x == 0)
417 return vector->y > 0 ? M_PI_2 : -M_PI_2;
418 if (vector->x == vector->y)
419 return vector->x > 0 ? M_PI_4 : -M_PI_4 * 3;
420 if (vector->x == -vector->y)
421 return vector->x > 0 ? -M_PI_4 : M_PI_4 * 3;
423 return atan2(vector->y, vector->x);
427 * cpml_vector_normal:
428 * @vector: the subject #CpmlVector
430 * Stores in @vector a vector normal to the original @vector.
431 * The length is retained.
433 * The algorithm is really quick because no trigonometry is involved.
435 void
436 cpml_vector_normal(CpmlVector *vector)
438 double tmp = vector->x;
440 vector->x = -vector->y;
441 vector->y = tmp;
445 * cpml_vector_transform:
446 * @vector: the destination #CpmlPair struct
447 * @matrix: the transformation matrix
449 * Shortcut to apply a specific transformation matrix to @vector.
450 * It works in a similar way of cpml_pair_transform() but uses
451 * cairo_matrix_transform_distance() instead of
452 * cairo_matrix_transform_point().
454 void
455 cpml_vector_transform(CpmlPair *vector, const cairo_matrix_t *matrix)
457 cairo_matrix_transform_distance(matrix, &vector->x, &vector->y);