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.
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.
34 * @x: the x component of the pair
35 * @y: the y component of the pair
37 * A generic 2D structure.
42 * @x: the x component of the vector
43 * @y: the y component of the vector
45 * Another name for #CpmlPair. It is used to clarify when a function expects
48 * A vector represents a line starting from the origin (0,0) and ending
49 * to the given coordinates pair. Vectors are useful to define directions
53 #include "cpml-pair.h"
54 #include "cpml-macros.h"
60 static CpmlPair fallback_pair
= { 0, 0 };
64 cpml_pair_copy(CpmlPair
*pair
, const CpmlPair
*src
)
66 return memcpy(pair
, src
, sizeof(CpmlPair
));
70 cpml_pair_from_value(CpmlPair
*pair
, double value
)
79 cpml_pair_negate(CpmlPair
*pair
)
86 cpml_pair_invert(CpmlPair
*pair
)
88 if (pair
->x
== 0 || pair
->y
== 0)
91 pair
->x
= 1. / pair
->x
;
92 pair
->y
= 1. / pair
->y
;
97 cpml_pair_add(CpmlPair
*pair
, const CpmlPair
*src
)
104 cpml_pair_sub(CpmlPair
*pair
, const CpmlPair
*src
)
111 cpml_pair_mul(CpmlPair
*pair
, const CpmlPair
*src
)
118 cpml_pair_div(CpmlPair
*pair
, const CpmlPair
*src
)
120 if (src
->x
== 0 || src
->y
== 0)
129 * cpml_pair_transform:
130 * @pair: the destination #CpmlPair struct
131 * @matrix: the transformation matrix
133 * Shortcut to apply a specific transformation matrix to @pair.
136 cpml_pair_transform(CpmlPair
*pair
, const cairo_matrix_t
*matrix
)
138 cairo_matrix_transform_point(matrix
, &pair
->x
, &pair
->y
);
143 * cpml_pair_squared_distance:
144 * @from: the first #CpmlPair struct
145 * @to: the second #CpmlPair struct
147 * Gets the squared distance between @from and @to. This value is useful
148 * for comparation purpose: if you need to get the real distance, use
149 * cpml_pair_distance().
151 * @from or @to could be %NULL, in which case the fallback (0, 0) pair
154 * Return value: the squared distance
157 cpml_pair_squared_distance(const CpmlPair
*from
, const CpmlPair
*to
)
162 from
= &fallback_pair
;
169 return x
* x
+ y
* y
;
173 * cpml_pair_distance:
174 * @from: the first #CpmlPair struct
175 * @to: the second #CpmlPair struct
176 * @distance: where to store the result
178 * Gets the distance between @from and @to, storing the result in @distance.
179 * If you need this value only for comparation purpose, you could use
180 * cpm_pair_squared_distance() instead.
182 * @from or @to could be %NULL, in which case the fallback (0, 0) pair
185 * The algorithm used is adapted from:
186 * "Replacing Square Roots by Pythagorean Sums"
187 * by Clave Moler and Donald Morrison (1983)
188 * IBM Journal of Research and Development 27 (6): 577–581
189 * http://www.research.ibm.com/journal/rd/276/ibmrd2706P.pdf
191 * Return value: the distance
194 cpml_pair_distance(const CpmlPair
*from
, const CpmlPair
*to
)
200 from
= &fallback_pair
;
237 * cpml_vector_from_pair:
238 * @vector: the destination vector
239 * @pair: the source pair
240 * @length: the length of the vector
242 * Given the line L passing throught the origin and @pair, gets the
243 * coordinate of the point on this line far @length from the origin
244 * and store the result in @vector. If @pair itsself is the origin,
245 * (0, 0) is returned.
247 * @pair and @vector can be the same struct.
249 * Return value: @vector
252 cpml_vector_from_pair(CpmlVector
*vector
, const CpmlPair
*pair
, double length
)
254 double distance
= cpml_pair_distance(NULL
, pair
);
261 vector
->x
= pair
->x
/ distance
;
262 vector
->y
= pair
->y
/ distance
;
269 * cpml_vector_from_angle:
270 * @vector: the destination #CpmlVector
271 * @angle: angle of direction, in radians
272 * @length: the length of the vector
274 * Calculates the coordinates of the point far @length from the origin
275 * in the @angle direction. The result is stored in @vector.
277 * Return value: @vector
280 cpml_vector_from_angle(CpmlVector
*vector
, double angle
, double length
)
282 static double cached_angle
= 0;
283 static CpmlPair cached_vector
= { 1, 0 };
285 /* Check for cached result */
286 if (angle
== cached_angle
)
287 return cpml_pair_copy(vector
, &cached_vector
);
289 /* Check for common conditions */
290 if (angle
== CPML_DIR_UP
) {
295 if (angle
== CPML_DIR_DOWN
) {
300 if (angle
== CPML_DIR_LEFT
) {
305 if (angle
== CPML_DIR_RIGHT
) {
311 /* Computation and cache registration */
312 vector
->x
= cos(angle
);
313 vector
->y
= -sin(angle
);
314 cached_angle
= angle
;
315 cpml_pair_copy(&cached_vector
, vector
);
322 * @vector: the source #CpmlVector
324 * Gets the angle of @vector, in radians. If @vector is (0, 0),
325 * %CPML_DIR_RIGHT is returned.
327 * Return value: the angle in radians
330 cpml_vector_angle(const CpmlVector
*vector
)
332 static CpmlPair cached_vector
= { 1., 0. };
333 static double cached_angle
= 0.;
335 /* Check for cached result */
336 if (vector
->x
== cached_vector
.x
&& vector
->y
== cached_vector
.y
)
339 /* Check for common conditions */
341 return vector
->x
>= 0 ? CPML_DIR_RIGHT
: CPML_DIR_LEFT
;
343 return vector
->y
> 0 ? CPML_DIR_DOWN
: CPML_DIR_UP
;
344 if (vector
->x
== vector
->y
)
345 return vector
->x
> 0 ? M_PI_4
* 7 : M_PI_4
* 3;
346 if (vector
->x
== -vector
->y
)
347 return vector
->x
> 0 ? M_PI_4
: M_PI_4
* 5;
349 /* Computation and cache registration */
350 cached_angle
= atan(-vector
->y
/ vector
->x
);
351 cpml_pair_copy(&cached_vector
, vector
);
357 * cpml_vector_normal:
358 * @vector: the subject #CpmlVector
360 * Stores in @vector a vector normal to the original @vector.
361 * The length is retained.
363 * The algorithm is really quick because no trigonometry is involved.
366 cpml_vector_normal(CpmlVector
*vector
)
368 double tmp
= vector
->x
;
370 vector
->x
= vector
->y
;