[CPML] Implemented get_length() as a virtual method
[adg.git] / cpml / cpml-line.c
blobb2721cdd922b92ad694be7581623115abbfd3d80
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-line
23 * @Section_Id:CpmlLine
24 * @title: CpmlLine
25 * @short_description: APIs manipulating straight lines
27 * The following functions manipulate %CAIRO_PATH_LINE_TO #CpmlPrimitive.
28 * No validation is made on the input so use the following methods
29 * only when you are sure the <varname>primitive</varname> argument
30 * is effectively a straingt line.
31 **/
33 /**
34 * SECTION:cpml-close
35 * @Section_Id:CpmlClose
36 * @title: CpmlClose
37 * @short_description: Straigth line used to close cyclic segments
39 * The following functions manipulate %CAIRO_PATH_CLOSE_PATH
40 * #CpmlPrimitive. No validation is made on the input so use the
41 * following methods only when you are sure the
42 * <varname>primitive</varname> argument is effectively a close path.
44 * This primitive management is almost identical to straight lines,
45 * but taking properly start and end points.
46 **/
49 #include "cpml-internal.h"
50 #include "cpml-extents.h"
51 #include "cpml-segment.h"
52 #include "cpml-primitive.h"
53 #include "cpml-primitive-private.h"
54 #include "cpml-line.h"
55 #include <stdlib.h>
58 static double get_length (const CpmlPrimitive *line);
59 static cairo_bool_t intersection (const CpmlPair *p,
60 CpmlPair *dest,
61 double *get_factor);
64 const _CpmlPrimitiveClass *
65 _cpml_line_get_class(void)
67 static _CpmlPrimitiveClass *p_class = NULL;
69 if (p_class == NULL) {
70 static _CpmlPrimitiveClass class_data = {
71 "line", 2,
72 get_length,
73 NULL,
74 NULL,
75 NULL,
76 NULL,
77 NULL,
78 NULL,
79 NULL
81 p_class = &class_data;
84 return p_class;
87 const _CpmlPrimitiveClass *
88 _cpml_close_get_class(void)
90 static _CpmlPrimitiveClass *p_class = NULL;
92 if (p_class == NULL) {
93 static _CpmlPrimitiveClass class_data = {
94 "close", 2,
95 get_length,
96 NULL,
97 NULL,
98 NULL,
99 NULL,
100 NULL,
101 NULL,
102 NULL
104 p_class = &class_data;
107 return p_class;
112 * cpml_line_put_extents:
113 * @line: the #CpmlPrimitive line data
114 * @extents: where to store the extents
116 * Given a @line primitive, returns its boundary box in @extents.
118 void
119 cpml_line_put_extents(const CpmlPrimitive *line, CpmlExtents *extents)
121 CpmlPair p1, p2;
123 extents->is_defined = 0;
125 cpml_pair_from_cairo(&p1, cpml_primitive_get_point(line, 0));
126 cpml_pair_from_cairo(&p2, cpml_primitive_get_point(line, -1));
128 cpml_extents_pair_add(extents, &p1);
129 cpml_extents_pair_add(extents, &p2);
133 * cpml_line_put_pair_at:
134 * @line: the #CpmlPrimitive line data
135 * @pair: the destination pair
136 * @pos: the position value
138 * Given the @line line, finds the coordinates at position @pos
139 * (where 0 is the start and 1 is the end) and stores the result
140 * in @pair.
142 * @pos can be less than 0 or greater than 1, in which case the
143 * coordinates are interpolated.
145 void
146 cpml_line_put_pair_at(const CpmlPrimitive *line, double pos, CpmlPair *pair)
148 cairo_path_data_t *p1, *p2;
150 p1 = cpml_primitive_get_point(line, 0);
151 p2 = cpml_primitive_get_point(line, -1);
153 pair->x = p1->point.x + (p2->point.x - p1->point.x) * pos;
154 pair->y = p1->point.y + (p2->point.y - p1->point.y) * pos;
158 * cpml_line_put_vector_at:
159 * @line: the #CpmlPrimitive line data
160 * @vector: the destination vector
161 * @pos: the position value
163 * Gets the slope on @line at the position @pos. Being the
164 * line a straight segment, the vector is always the same, so
165 * @pos is not used. Mathematically speaking, the equation
166 * performed is:
168 * @vector = endpoint(@line) - startpoint(@line).
170 void
171 cpml_line_put_vector_at(const CpmlPrimitive *line, double pos,
172 CpmlVector *vector)
174 cairo_path_data_t *p1, *p2;
176 p1 = cpml_primitive_get_point(line, 0);
177 p2 = cpml_primitive_get_point(line, -1);
179 vector->x = p2->point.x - p1->point.x;
180 vector->y = p2->point.y - p1->point.y;
184 * cpml_line_get_closest_pos:
185 * @line: the #CpmlPrimitive line data
186 * @pair: the coordinates of the subject point
188 * Returns the pos value of the point on @line nearest to @pair.
189 * The returned value is always between 0 and 1.
191 * The point nearest to @pair is got by finding the its
192 * projection on @line, as this is when the point is closer to
193 * a line primitive.
195 * Returns: the pos value, always between 0 and 1
197 double
198 cpml_line_get_closest_pos(const CpmlPrimitive *line, const CpmlPair *pair)
200 CpmlPair p[4];
201 CpmlVector normal;
202 double pos;
204 cpml_pair_from_cairo(&p[0], cpml_primitive_get_point(line, 0));
205 cpml_pair_from_cairo(&p[1], cpml_primitive_get_point(line, -1));
207 cpml_pair_copy(&normal, &p[1]);
208 cpml_pair_sub(&normal, &p[2]);
209 cpml_vector_normal(&normal);
211 cpml_pair_copy(&p[2], pair);
212 cpml_pair_copy(&p[3], pair);
213 cpml_pair_add(&p[3], &normal);
215 /* Ensure to return 0 if intersection() fails */
216 pos = 0;
217 intersection(p, NULL, &pos);
219 /* Clamp the result to 0..1 */
220 if (pos < 0)
221 pos = 0;
222 else if (pos > 1.)
223 pos = 1.;
225 return pos;
229 * cpml_line_put_intersections:
230 * @line: the first line
231 * @line2: the second line
232 * @max: maximum number of intersections to return
233 * (that is, the size of @dest)
234 * @dest: a vector of #CpmlPair
236 * Given two lines (@line and @line2), gets their intersection point
237 * and store the result in @dest.
239 * If @max is 0, the function returns 0 immediately without any
240 * further processing. If @line and @line2 are cohincident,
241 * their intersections are not considered.
243 * Returns: the number of intersections found (max 1)
244 * or 0 if the primitives do not intersect
247 cpml_line_put_intersections(const CpmlPrimitive *line,
248 const CpmlPrimitive *line2,
249 int max, CpmlPair *dest)
251 CpmlPair p[4];
253 if (max == 0)
254 return 0;
256 cpml_pair_from_cairo(&p[0], cpml_primitive_get_point(line, 0));
257 cpml_pair_from_cairo(&p[1], cpml_primitive_get_point(line, -1));
258 cpml_pair_from_cairo(&p[2], cpml_primitive_get_point(line2, 0));
259 cpml_pair_from_cairo(&p[3], cpml_primitive_get_point(line2, -1));
261 return intersection(p, dest, NULL) ? 1 : 0;
265 * cpml_line_offset:
266 * @line: the #CpmlPrimitive line data
267 * @offset: distance for the computed parallel line
269 * Given a line segment specified by the @line primitive data,
270 * computes the parallel line distant @offset from the original one
271 * and returns the result by changing @line.
273 void
274 cpml_line_offset(CpmlPrimitive *line, double offset)
276 cairo_path_data_t *p1, *p2;
277 CpmlVector normal;
279 p1 = cpml_primitive_get_point(line, 0);
280 p2 = cpml_primitive_get_point(line, -1);
282 cpml_line_put_vector_at(line, 0, &normal);
283 cpml_vector_normal(&normal);
284 cpml_vector_set_length(&normal, offset);
286 p1->point.x += normal.x;
287 p1->point.y += normal.y;
288 p2->point.x += normal.x;
289 p2->point.y += normal.y;
294 * cpml_close_put_pair_at:
295 * @close: the #CpmlPrimitive close data
296 * @pos: the position value
297 * @pair: the destination pair
299 * Given the @close path virtual primitive, finds the coordinates
300 * at position @pos (where 0 is the start and 1 is the end) and
301 * stores the result in @pair.
303 * @pos can be less than 0 or greater than 1, in which case the
304 * coordinates are interpolated.
306 void
307 cpml_close_put_pair_at(const CpmlPrimitive *close, double pos, CpmlPair *pair)
309 cpml_line_put_pair_at(close, pos, pair);
313 * cpml_close_put_vector_at:
314 * @close: the #CpmlPrimitive close data
315 * @vector: the destination vector
316 * @pos: the position value
318 * Gets the slope on @close at the position @pos. Being the
319 * close a straight line, the vector is always the same, so
320 * @pos is not used.
322 void
323 cpml_close_put_vector_at(const CpmlPrimitive *close, double pos,
324 CpmlVector *vector)
326 cpml_line_put_vector_at(close, pos, vector);
330 * cpml_close_get_closest_pos:
331 * @close: the #CpmlPrimitive close data
332 * @pair: the coordinates of the subject point
334 * Returns the pos value of the point on @close nearest to @pair.
335 * The returned value is always between 0 and 1.
337 * Returns: the pos value, always between 0 and 1
339 double
340 cpml_close_get_closest_pos(const CpmlPrimitive *close, const CpmlPair *pair)
342 return cpml_line_get_closest_pos(close, pair);
346 * cpml_close_offset:
347 * @close: the #CpmlPrimitive close data
348 * @offset: distance for the computed parallel close
350 * Given a close segment specified by the @close primitive data,
351 * computes the parallel close distant @offset from the original one
352 * and returns the result by changing @close.
354 void
355 cpml_close_offset(CpmlPrimitive *close, double offset)
357 cpml_line_offset(close, offset);
361 static double
362 get_length(const CpmlPrimitive *line)
364 CpmlPair p1, p2;
366 cpml_pair_from_cairo(&p1, cpml_primitive_get_point(line, 0));
367 cpml_pair_from_cairo(&p2, cpml_primitive_get_point(line, -1));
369 return cpml_pair_distance(&p1, &p2);
372 static cairo_bool_t
373 intersection(const CpmlPair *p, CpmlPair *dest, double *get_factor)
375 CpmlVector v[2];
376 double factor;
378 cpml_pair_copy(&v[0], &p[1]);
379 cpml_pair_sub(&v[0], &p[0]);
380 cpml_pair_copy(&v[1], &p[3]);
381 cpml_pair_sub(&v[1], &p[2]);
382 factor = v[0].x * v[1].y - v[0].y * v[1].x;
384 /* Check for equal slopes (the lines are parallel) */
385 if (factor == 0)
386 return 0;
388 factor = ((p[0].y - p[2].y) * v[1].x -
389 (p[0].x - p[2].x) * v[1].y) / factor;
391 if (dest != NULL) {
392 dest->x = p[0].x + v[0].x * factor;
393 dest->y = p[0].y + v[0].y * factor;
396 if (get_factor != NULL)
397 *get_factor = factor;
399 return 1;