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.
23 * @Section_Id: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.
35 * @Section_Id: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.
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"
58 static double get_length (const CpmlPrimitive
*line
);
59 static void put_extents (const CpmlPrimitive
*line
,
60 CpmlExtents
*extents
);
61 static cairo_bool_t
intersection (const CpmlPair
*p
,
66 const _CpmlPrimitiveClass
*
67 _cpml_line_get_class(void)
69 static _CpmlPrimitiveClass
*p_class
= NULL
;
71 if (p_class
== NULL
) {
72 static _CpmlPrimitiveClass class_data
= {
83 p_class
= &class_data
;
89 const _CpmlPrimitiveClass
*
90 _cpml_close_get_class(void)
92 static _CpmlPrimitiveClass
*p_class
= NULL
;
94 if (p_class
== NULL
) {
95 static _CpmlPrimitiveClass class_data
= {
106 p_class
= &class_data
;
114 * cpml_line_put_pair_at:
115 * @line: the #CpmlPrimitive line data
116 * @pair: the destination pair
117 * @pos: the position value
119 * Given the @line line, finds the coordinates at position @pos
120 * (where 0 is the start and 1 is the end) and stores the result
123 * @pos can be less than 0 or greater than 1, in which case the
124 * coordinates are interpolated.
127 cpml_line_put_pair_at(const CpmlPrimitive
*line
, double pos
, CpmlPair
*pair
)
129 cairo_path_data_t
*p1
, *p2
;
131 p1
= cpml_primitive_get_point(line
, 0);
132 p2
= cpml_primitive_get_point(line
, -1);
134 pair
->x
= p1
->point
.x
+ (p2
->point
.x
- p1
->point
.x
) * pos
;
135 pair
->y
= p1
->point
.y
+ (p2
->point
.y
- p1
->point
.y
) * pos
;
139 * cpml_line_put_vector_at:
140 * @line: the #CpmlPrimitive line data
141 * @vector: the destination vector
142 * @pos: the position value
144 * Gets the slope on @line at the position @pos. Being the
145 * line a straight segment, the vector is always the same, so
146 * @pos is not used. Mathematically speaking, the equation
149 * @vector = endpoint(@line) - startpoint(@line).
152 cpml_line_put_vector_at(const CpmlPrimitive
*line
, double pos
,
155 cairo_path_data_t
*p1
, *p2
;
157 p1
= cpml_primitive_get_point(line
, 0);
158 p2
= cpml_primitive_get_point(line
, -1);
160 vector
->x
= p2
->point
.x
- p1
->point
.x
;
161 vector
->y
= p2
->point
.y
- p1
->point
.y
;
165 * cpml_line_get_closest_pos:
166 * @line: the #CpmlPrimitive line data
167 * @pair: the coordinates of the subject point
169 * Returns the pos value of the point on @line nearest to @pair.
170 * The returned value is always between 0 and 1.
172 * The point nearest to @pair is got by finding the its
173 * projection on @line, as this is when the point is closer to
176 * Returns: the pos value, always between 0 and 1
179 cpml_line_get_closest_pos(const CpmlPrimitive
*line
, const CpmlPair
*pair
)
185 cpml_pair_from_cairo(&p
[0], cpml_primitive_get_point(line
, 0));
186 cpml_pair_from_cairo(&p
[1], cpml_primitive_get_point(line
, -1));
188 cpml_pair_copy(&normal
, &p
[1]);
189 cpml_pair_sub(&normal
, &p
[2]);
190 cpml_vector_normal(&normal
);
192 cpml_pair_copy(&p
[2], pair
);
193 cpml_pair_copy(&p
[3], pair
);
194 cpml_pair_add(&p
[3], &normal
);
196 /* Ensure to return 0 if intersection() fails */
198 intersection(p
, NULL
, &pos
);
200 /* Clamp the result to 0..1 */
210 * cpml_line_put_intersections:
211 * @line: the first line
212 * @line2: the second line
213 * @max: maximum number of intersections to return
214 * (that is, the size of @dest)
215 * @dest: a vector of #CpmlPair
217 * Given two lines (@line and @line2), gets their intersection point
218 * and store the result in @dest.
220 * If @max is 0, the function returns 0 immediately without any
221 * further processing. If @line and @line2 are cohincident,
222 * their intersections are not considered.
224 * Returns: the number of intersections found (max 1)
225 * or 0 if the primitives do not intersect
228 cpml_line_put_intersections(const CpmlPrimitive
*line
,
229 const CpmlPrimitive
*line2
,
230 int max
, CpmlPair
*dest
)
237 cpml_pair_from_cairo(&p
[0], cpml_primitive_get_point(line
, 0));
238 cpml_pair_from_cairo(&p
[1], cpml_primitive_get_point(line
, -1));
239 cpml_pair_from_cairo(&p
[2], cpml_primitive_get_point(line2
, 0));
240 cpml_pair_from_cairo(&p
[3], cpml_primitive_get_point(line2
, -1));
242 return intersection(p
, dest
, NULL
) ? 1 : 0;
247 * @line: the #CpmlPrimitive line data
248 * @offset: distance for the computed parallel line
250 * Given a line segment specified by the @line primitive data,
251 * computes the parallel line distant @offset from the original one
252 * and returns the result by changing @line.
255 cpml_line_offset(CpmlPrimitive
*line
, double offset
)
257 cairo_path_data_t
*p1
, *p2
;
260 p1
= cpml_primitive_get_point(line
, 0);
261 p2
= cpml_primitive_get_point(line
, -1);
263 cpml_line_put_vector_at(line
, 0, &normal
);
264 cpml_vector_normal(&normal
);
265 cpml_vector_set_length(&normal
, offset
);
267 p1
->point
.x
+= normal
.x
;
268 p1
->point
.y
+= normal
.y
;
269 p2
->point
.x
+= normal
.x
;
270 p2
->point
.y
+= normal
.y
;
275 * cpml_close_put_pair_at:
276 * @close: the #CpmlPrimitive close data
277 * @pos: the position value
278 * @pair: the destination pair
280 * Given the @close path virtual primitive, finds the coordinates
281 * at position @pos (where 0 is the start and 1 is the end) and
282 * stores the result in @pair.
284 * @pos can be less than 0 or greater than 1, in which case the
285 * coordinates are interpolated.
288 cpml_close_put_pair_at(const CpmlPrimitive
*close
, double pos
, CpmlPair
*pair
)
290 cpml_line_put_pair_at(close
, pos
, pair
);
294 * cpml_close_put_vector_at:
295 * @close: the #CpmlPrimitive close data
296 * @vector: the destination vector
297 * @pos: the position value
299 * Gets the slope on @close at the position @pos. Being the
300 * close a straight line, the vector is always the same, so
304 cpml_close_put_vector_at(const CpmlPrimitive
*close
, double pos
,
307 cpml_line_put_vector_at(close
, pos
, vector
);
311 * cpml_close_get_closest_pos:
312 * @close: the #CpmlPrimitive close data
313 * @pair: the coordinates of the subject point
315 * Returns the pos value of the point on @close nearest to @pair.
316 * The returned value is always between 0 and 1.
318 * Returns: the pos value, always between 0 and 1
321 cpml_close_get_closest_pos(const CpmlPrimitive
*close
, const CpmlPair
*pair
)
323 return cpml_line_get_closest_pos(close
, pair
);
328 * @close: the #CpmlPrimitive close data
329 * @offset: distance for the computed parallel close
331 * Given a close segment specified by the @close primitive data,
332 * computes the parallel close distant @offset from the original one
333 * and returns the result by changing @close.
336 cpml_close_offset(CpmlPrimitive
*close
, double offset
)
338 cpml_line_offset(close
, offset
);
343 get_length(const CpmlPrimitive
*line
)
347 cpml_pair_from_cairo(&p1
, cpml_primitive_get_point(line
, 0));
348 cpml_pair_from_cairo(&p2
, cpml_primitive_get_point(line
, -1));
350 return cpml_pair_distance(&p1
, &p2
);
354 put_extents(const CpmlPrimitive
*line
, CpmlExtents
*extents
)
358 extents
->is_defined
= 0;
360 cpml_pair_from_cairo(&p1
, cpml_primitive_get_point(line
, 0));
361 cpml_pair_from_cairo(&p2
, cpml_primitive_get_point(line
, -1));
363 cpml_extents_pair_add(extents
, &p1
);
364 cpml_extents_pair_add(extents
, &p2
);
368 intersection(const CpmlPair
*p
, CpmlPair
*dest
, double *get_factor
)
373 cpml_pair_copy(&v
[0], &p
[1]);
374 cpml_pair_sub(&v
[0], &p
[0]);
375 cpml_pair_copy(&v
[1], &p
[3]);
376 cpml_pair_sub(&v
[1], &p
[2]);
377 factor
= v
[0].x
* v
[1].y
- v
[0].y
* v
[1].x
;
379 /* Check for equal slopes (the lines are parallel) */
383 factor
= ((p
[0].y
- p
[2].y
) * v
[1].x
-
384 (p
[0].x
- p
[2].x
) * v
[1].y
) / factor
;
387 dest
->x
= p
[0].x
+ v
[0].x
* factor
;
388 dest
->y
= p
[0].y
+ v
[0].y
* factor
;
391 if (get_factor
!= NULL
)
392 *get_factor
= factor
;