docs: updated copyright to 2012
[adg.git] / src / cpml / cpml-pair.c
blob8c994c5d809e305b60fd8abfba33d12191d8a877
1 /* CPML - Cairo Path Manipulation Library
2 * Copyright (C) 2008,2009,2010,2011,2012 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.
32 * Since: 1.0
33 **/
35 /**
36 * CpmlPair:
37 * @x: the x component of the pair
38 * @y: the y component of the pair
40 * A generic 2D structure.
42 * Since: 1.0
43 **/
45 /**
46 * CpmlVector:
47 * @x: the x component of the vector
48 * @y: the y component of the vector
50 * Another name for #CpmlPair. It is used to clarify when a function
51 * expects a generic pair (usually coordinates) or a vector.
53 * A vector represents a line starting from the origin (0,0) and ending
54 * to the given coordinates pair. Vectors are useful to define direction
55 * and length at once. Keep in mind the cairo default coordinates system
56 * is not problably what you expect: the x axis increases at right
57 * (as usual) but the y axis increases at down (the reverse of a usual
58 * cartesian plan). An angle of 0 is at V=(1; 0) (middle right).
60 * Since: 1.0
61 **/
64 #include "cpml-internal.h"
65 #include <string.h>
66 #include <math.h>
69 static CpmlPair fallback_pair = { 0, 0 };
72 /**
73 * cpml_pair_from_cairo:
74 * @pair: (out): the destination #CpmlPair
75 * @path_data: (in) (type gpointer): the original path data point
77 * Sets @pair from a #cairo_path_data_t struct. @path_data should contains
78 * a point data: it is up to the caller to be sure @path_data is valid.
80 * Since: 1.0
81 **/
82 void
83 cpml_pair_from_cairo(CpmlPair *pair, const cairo_path_data_t *path_data)
85 pair->x = path_data->point.x;
86 pair->y = path_data->point.y;
89 /**
90 * cpml_pair_copy:
91 * @pair: (out): the destination #CpmlPair
92 * @src: (in): the source #CpmlPair
94 * Copies @src in @pair.
96 * Since: 1.0
97 **/
98 void
99 cpml_pair_copy(CpmlPair *pair, const CpmlPair *src)
101 memcpy(pair, src, sizeof(CpmlPair));
105 * cpml_pair_equal:
106 * @pair: the first pair to compare
107 * @src: the second pair to compare
109 * Compares @pair to @src and returns 1 if the pairs are equals.
110 * Two %NULL pairs are considered equal.
112 * Returns: (type gboolean): %1 if @pair is equal to @src,
113 * %0 otherwise
115 * Since: 1.0
118 cpml_pair_equal(const CpmlPair *pair, const CpmlPair *src)
120 if (pair == NULL && src == NULL)
121 return 1;
123 if (pair == NULL || src == NULL)
124 return 0;
126 return pair->x == src->x && pair->y == src->y ? 1 : 0;
130 * cpml_pair_transform:
131 * @pair: (inout): the destination #CpmlPair struct
132 * @matrix: (in): the transformation matrix
134 * Shortcut to apply a specific transformation matrix to @pair.
136 * Since: 1.0
138 void
139 cpml_pair_transform(CpmlPair *pair, const cairo_matrix_t *matrix)
141 cairo_matrix_transform_point(matrix, &pair->x, &pair->y);
145 * cpml_pair_squared_distance:
146 * @from: the first #CpmlPair struct
147 * @to: the second #CpmlPair struct
149 * Gets the squared distance between @from and @to. This value is useful
150 * for comparation purpose: if you need to get the real distance, use
151 * cpml_pair_distance().
153 * @from or @to could be %NULL, in which case the fallback (0, 0) pair
154 * will be used.
156 * Returns: the squared distance
158 * Since: 1.0
160 double
161 cpml_pair_squared_distance(const CpmlPair *from, const CpmlPair *to)
163 double x, y;
165 if (from == NULL)
166 from = &fallback_pair;
167 if (to == NULL)
168 to = &fallback_pair;
170 x = to->x - from->x;
171 y = to->y - from->y;
173 return x * x + y * y;
177 * cpml_pair_distance:
178 * @from: the first #CpmlPair struct
179 * @to: the second #CpmlPair struct
181 * Gets the distance between @from and @to. If you need this value only
182 * for comparation purpose, you could use cpm_pair_squared_distance()
183 * instead.
185 * @from or @to could be %NULL, in which case the fallback (0, 0) pair
186 * will be used.
188 * The algorithm used is adapted from:
189 * "Replacing Square Roots by Pythagorean Sums"
190 * by Clave Moler and Donald Morrison (1983)
191 * IBM Journal of Research and Development 27 (6): 577–581
192 * http://www.research.ibm.com/journal/rd/276/ibmrd2706P.pdf
194 * Returns: the distance
196 * Since: 1.0
198 double
199 cpml_pair_distance(const CpmlPair *from, const CpmlPair *to)
201 double x, y;
202 double p, q, r, s;
204 if (from == NULL)
205 from = &fallback_pair;
206 if (to == NULL)
207 to = &fallback_pair;
209 x = to->x - from->x;
210 y = to->y - from->y;
212 if (x < 0)
213 x = -x;
214 if (y < 0)
215 y = -y;
217 if (x > y) {
218 p = x;
219 q = y;
220 } else {
221 p = y;
222 q = x;
225 if (p > 0) {
226 for (;;) {
227 r = q/p;
228 r *= r;
229 if (r == 0)
230 break;
232 s = r / (4+r);
233 p += 2*s*p;
234 q *= s;
238 return p;
242 * cpml_pair_to_cairo:
243 * @pair: (in): the source #CpmlPair
244 * @path_data: (out) (type gpointer): the path data point to modify
246 * Sets a #cairo_path_data_t struct to @pair. This is exactly the reverse
247 * operation of cpml_pair_from_cairo().
249 * Since: 1.0
251 void
252 cpml_pair_to_cairo(const CpmlPair *pair, cairo_path_data_t *path_data)
254 path_data->point.x = pair->x;
255 path_data->point.y = pair->y;
260 * cpml_vector_from_angle:
261 * @vector: (out): the destination #CpmlVector
262 * @angle: (in): angle of direction, in radians
264 * Calculates the coordinates of the point far %1 from the origin
265 * in the @angle direction. The result is stored in @vector.
267 * Since: 1.0
269 void
270 cpml_vector_from_angle(CpmlVector *vector, double angle)
272 /* Check for common conditions */
273 if (angle == -M_PI_2) {
274 vector->x = 0;
275 vector->y = -1;
276 } else if (angle == M_PI_2) {
277 vector->x = 0;
278 vector->y = +1;
279 } else if (angle == M_PI || angle == -M_PI) {
280 vector->x = -1;
281 vector->y = 0;
282 } else if (angle == 0) {
283 vector->x = +1;
284 vector->y = 0;
285 } else {
286 vector->x = cos(angle);
287 vector->y = sin(angle);
292 * cpml_vector_set_length:
293 * @vector: (inout): a #CpmlVector
294 * @length: (in): the new length
296 * Imposes the specified @length to @vector. If the old length is %0
297 * (and so the direction is not known), nothing happens. If @length
298 * is %0, @vector is set to (0, 0).
300 * The @length parameter can be negative, in which case the vector
301 * is inverted.
303 * Since: 1.0
305 void
306 cpml_vector_set_length(CpmlVector *vector, double length)
308 double divisor;
310 if (length == 0) {
311 vector->x = 0;
312 vector->y = 0;
313 return;
316 divisor = cpml_pair_distance(NULL, vector);
318 /* Check for valid length (anything other than 0) */
319 if (divisor != 0) {
320 divisor /= length;
321 vector->x /= divisor;
322 vector->y /= divisor;
327 * cpml_vector_angle:
328 * @vector: the source #CpmlVector
330 * Gets the angle of @vector, in radians. If @vector is (0, 0),
331 * 0 is returned.
333 * Returns: the angle in radians, a value between -M_PI and M_PI
335 * Since: 1.0
337 double
338 cpml_vector_angle(const CpmlVector *vector)
340 /* Check for common conditions */
341 if (vector->y == 0)
342 return vector->x >= 0 ? 0 : M_PI;
343 if (vector->x == 0)
344 return vector->y > 0 ? M_PI_2 : -M_PI_2;
345 if (vector->x == vector->y)
346 return vector->x > 0 ? M_PI_4 : -M_PI_4 * 3;
347 if (vector->x == -vector->y)
348 return vector->x > 0 ? -M_PI_4 : M_PI_4 * 3;
350 return atan2(vector->y, vector->x);
354 * cpml_vector_normal:
355 * @vector: (inout): the subject #CpmlVector
357 * Stores in @vector a vector normal to the original @vector.
358 * The length is retained.
360 * The algorithm is really quick because no trigonometry is involved.
362 * Since: 1.0
364 void
365 cpml_vector_normal(CpmlVector *vector)
367 double tmp = vector->x;
369 vector->x = -vector->y;
370 vector->y = tmp;
374 * cpml_vector_transform:
375 * @vector: (inout): the destination #CpmlPair struct
376 * @matrix: (in): the transformation matrix
378 * Shortcut to apply a specific transformation matrix to @vector.
379 * It works in a similar way of cpml_pair_transform() but uses
380 * cairo_matrix_transform_distance() instead of
381 * cairo_matrix_transform_point().
383 * Since: 1.0
385 void
386 cpml_vector_transform(CpmlPair *vector, const cairo_matrix_t *matrix)
388 cairo_matrix_transform_distance(matrix, &vector->x, &vector->y);