[AdgDimStyle] Added missing "adg-context.h" include to the implementation
[adg.git] / cpml / cpml-pair.c
blobe5deb2f3026a3c86e19d288f8c09b16ed05223ee
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.
50 **/
52 #include "cpml-pair.h"
53 #include "cpml-macros.h"
55 #include <stdlib.h>
56 #include <string.h>
57 #include <math.h>
60 static CpmlPair fallback_pair = { 0, 0 };
63 /**
64 * cpml_pair_copy:
65 * @pair: the destination #CpmlPair
66 * @src: the source #CpmlPair
68 * Copies @src in @pair.
70 * Return value: @pair
71 **/
72 CpmlPair *
73 cpml_pair_copy(CpmlPair *pair, const CpmlPair *src)
75 return memcpy(pair, src, sizeof(CpmlPair));
78 /**
79 * cpml_pair_from_cairo:
80 * @pair: the destination #CpmlPair
81 * @path_data: the original path data point
83 * Gets @pair from a #cairo_path_data_t struct. @path_data should contains
84 * a point data: it is up to the caller to be sure @path_data is valid.
86 * Return value: @pair
87 **/
88 CpmlPair *
89 cpml_pair_from_cairo(CpmlPair *pair, const cairo_path_data_t *path_data)
91 pair->x = path_data->point.x;
92 pair->y = path_data->point.y;
93 return pair;
97 /**
98 * cpml_pair_negate:
99 * @pair: a #CpmlPair
101 * Negates the coordinates of @pair.
103 void
104 cpml_pair_negate(CpmlPair *pair)
106 pair->x = - pair->x;
107 pair->y = - pair->y;
111 * cpml_pair_invert:
112 * @pair: a #CpmlPair
114 * Inverts (1/x) the coordinates of @pair. If @pair cannot be inverted
115 * because one coordinate is 0, 0 is returned and no transformation is
116 * performed.
118 * Return value: 1 on success, 0 on errors
120 cairo_bool_t
121 cpml_pair_invert(CpmlPair *pair)
123 if (pair->x == 0 || pair->y == 0)
124 return 0;
126 pair->x = 1. / pair->x;
127 pair->y = 1. / pair->y;
128 return 1;
132 * cpml_pair_add:
133 * @pair: the destination #CpmlPair
134 * @src: the source pair to add
136 * Adds @src to @pair and stores the result in @pair. In other words,
137 * @pair = @pair + @src.
139 void
140 cpml_pair_add(CpmlPair *pair, const CpmlPair *src)
142 pair->x += src->x;
143 pair->y += src->y;
147 * cpml_pair_sub:
148 * @pair: the destination #CpmlPair
149 * @src: the source pair to subtract
151 * Subtracts @src from @pair and stores the result in @pair. In other words,
152 * @pair = @pair - @src.
154 void
155 cpml_pair_sub(CpmlPair *pair, const CpmlPair *src)
157 pair->x -= src->x;
158 pair->y -= src->y;
162 * cpml_pair_mul:
163 * @pair: the destination #CpmlPair
164 * @src: the source pair factor
166 * Multiplies the x coordinate of @pair by the @src x factor and the
167 * y coordinate by the @src y factor.
169 void
170 cpml_pair_mul(CpmlPair *pair, const CpmlPair *src)
172 pair->x *= src->x;
173 pair->y *= src->y;
177 * cpml_pair_div:
178 * @pair: the destination #CpmlPair
179 * @src: the source pair divisor
181 * Divides the x coordinate of @pair by the @src x divisor and the
182 * y coordinate by the @src y divisor. If @pair cannot be divided
183 * because of a division by 0, 0 is returned and no transformation
184 * is performed.
186 * Return value: 1 on success, 0 on errors
188 cairo_bool_t
189 cpml_pair_div(CpmlPair *pair, const CpmlPair *src)
191 if (src->x == 0 || src->y == 0)
192 return 0;
194 pair->x /= src->x;
195 pair->y /= src->y;
196 return 1;
200 * cpml_pair_transform:
201 * @pair: the destination #CpmlPair struct
202 * @matrix: the transformation matrix
204 * Shortcut to apply a specific transformation matrix to @pair.
206 void
207 cpml_pair_transform(CpmlPair *pair, const cairo_matrix_t *matrix)
209 cairo_matrix_transform_point(matrix, &pair->x, &pair->y);
214 * cpml_pair_squared_distance:
215 * @from: the first #CpmlPair struct
216 * @to: the second #CpmlPair struct
218 * Gets the squared distance between @from and @to. This value is useful
219 * for comparation purpose: if you need to get the real distance, use
220 * cpml_pair_distance().
222 * @from or @to could be %NULL, in which case the fallback (0, 0) pair
223 * will be used.
225 * Return value: the squared distance
227 double
228 cpml_pair_squared_distance(const CpmlPair *from, const CpmlPair *to)
230 double x, y;
232 if (from == NULL)
233 from = &fallback_pair;
234 if (to == NULL)
235 to = &fallback_pair;
237 x = to->x - from->x;
238 y = to->y - from->y;
240 return x * x + y * y;
244 * cpml_pair_distance:
245 * @from: the first #CpmlPair struct
246 * @to: the second #CpmlPair struct
247 * @distance: where to store the result
249 * Gets the distance between @from and @to, storing the result in @distance.
250 * If you need this value only for comparation purpose, you could use
251 * cpm_pair_squared_distance() instead.
253 * @from or @to could be %NULL, in which case the fallback (0, 0) pair
254 * will be used.
256 * The algorithm used is adapted from:
257 * "Replacing Square Roots by Pythagorean Sums"
258 * by Clave Moler and Donald Morrison (1983)
259 * IBM Journal of Research and Development 27 (6): 577–581
260 * http://www.research.ibm.com/journal/rd/276/ibmrd2706P.pdf
262 * Return value: the distance
264 double
265 cpml_pair_distance(const CpmlPair *from, const CpmlPair *to)
267 double x, y;
268 double p, q, r, s;
270 if (from == NULL)
271 from = &fallback_pair;
272 if (to == NULL)
273 to = &fallback_pair;
275 x = to->x - from->x;
276 y = to->y - from->y;
278 if (x < 0)
279 x = -x;
280 if (y < 0)
281 y = -y;
283 if (x > y) {
284 p = x;
285 q = y;
286 } else {
287 p = y;
288 q = x;
291 if (p > 0) {
292 for (;;) {
293 r = q/p;
294 r *= r;
295 if (r == 0)
296 break;
298 s = r / (4+r);
299 p += 2*s*p;
300 q *= s;
304 return p;
308 * cpml_vector_from_angle:
309 * @vector: the destination #CpmlVector
310 * @angle: angle of direction, in radians
311 * @length: the length of the vector
313 * Calculates the coordinates of the point far @length from the origin
314 * in the @angle direction. The result is stored in @vector.
316 * Return value: @vector
318 CpmlVector *
319 cpml_vector_from_angle(CpmlVector *vector, double angle, double length)
321 static double cached_angle = 0;
322 static CpmlPair cached_vector = { 1, 0 };
324 /* Check for cached result */
325 if (angle == cached_angle)
326 return cpml_pair_copy(vector, &cached_vector);
328 /* Check for common conditions */
329 if (angle == M_PI_2 * 3.) {
330 vector->x = 0;
331 vector->y = -1;
332 return vector;
334 if (angle == M_PI_2) {
335 vector->x = 0;
336 vector->y = +1;
337 return vector;
339 if (angle == M_PI) {
340 vector->x = -1;
341 vector->y = 0;
342 return vector;
344 if (angle == 0.) {
345 vector->x = +1;
346 vector->y = 0;
347 return vector;
350 /* Computation and cache registration */
351 vector->x = cos(angle);
352 vector->y = -sin(angle);
353 cached_angle = angle;
354 cpml_pair_copy(&cached_vector, vector);
356 return vector;
360 * cpml_vector_set_length:
361 * @vector: a #CpmlVector
362 * @length: the new length
364 * Imposes the specified @length to @vector. If the old length is 0
365 * (and so the direction is not known), nothing happens.
367 void
368 cpml_vector_set_length(CpmlVector *vector, double length)
370 double divisor = cpml_pair_distance(NULL, vector);
372 /* Check for valid length (anything other than 0) */
373 if (divisor <= 0)
374 return;
376 divisor /= length;
377 vector->x /= divisor;
378 vector->y /= divisor;
382 * cpml_vector_angle:
383 * @vector: the source #CpmlVector
385 * Gets the angle of @vector, in radians. If @vector is (0, 0),
386 * 0 is returned.
388 * Return value: the angle in radians
390 double
391 cpml_vector_angle(const CpmlVector *vector)
393 static CpmlPair cached_vector = { 1., 0. };
394 static double cached_angle = 0.;
396 /* Check for cached result */
397 if (vector->x == cached_vector.x && vector->y == cached_vector.y)
398 return cached_angle;
400 /* Check for common conditions */
401 if (vector->y == 0)
402 return vector->x >= 0 ? 0. : M_PI;
403 if (vector->x == 0)
404 return vector->y > 0 ? M_PI_2 : M_PI_2 * 3.;
405 if (vector->x == vector->y)
406 return vector->x > 0 ? M_PI_4 * 7 : M_PI_4 * 3;
407 if (vector->x == -vector->y)
408 return vector->x > 0 ? M_PI_4 : M_PI_4 * 5;
410 /* Computation and cache registration */
411 cached_angle = atan(-vector->y / vector->x);
412 cpml_pair_copy(&cached_vector, vector);
414 return cached_angle;
418 * cpml_vector_normal:
419 * @vector: the subject #CpmlVector
421 * Stores in @vector a vector normal to the original @vector.
422 * The length is retained.
424 * The algorithm is really quick because no trigonometry is involved.
426 void
427 cpml_vector_normal(CpmlVector *vector)
429 double tmp = vector->x;
431 vector->x = -vector->y;
432 vector->y = tmp;
436 * cpml_pair_to_cairo:
437 * @pair: the destination #CpmlPair
438 * @path_data: the original path data point
440 * Sets a #cairo_path_data_t struct to @pair. This is exactly the reverse
441 * operation of cpml_pair_from_cairo().
443 void
444 cpml_pair_to_cairo(const CpmlPair *pair, cairo_path_data_t *path_data)
446 path_data->point.x = pair->x;
447 path_data->point.y = pair->y;