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.
34 #include "cpml-line.h"
35 #include "cpml-pair.h"
39 static cairo_bool_t
intersection (const CpmlPair
*p
,
45 * cpml_line_type_get_npoints:
47 * Returns the number of point needed to properly specify a line primitive.
52 cpml_line_type_get_npoints(void)
59 * @line: the #CpmlPrimitive line data
61 * Given the @line primitive, returns the distance between its
62 * start and end points.
64 * Returns: the requested distance, that is the @line length
67 cpml_line_length(const CpmlPrimitive
*line
)
71 cpml_pair_from_cairo(&p1
, cpml_primitive_get_point(line
, 0));
72 cpml_pair_from_cairo(&p2
, cpml_primitive_get_point(line
, -1));
74 return cpml_pair_distance(&p1
, &p2
);
79 * @line: the #CpmlPrimitive line data
80 * @extents: where to store the extents
82 * Given a @line primitive, returns its boundary box in @extents.
85 cpml_line_extents(const CpmlPrimitive
*line
, CpmlExtents
*extents
)
89 extents
->is_defined
= 0;
91 cpml_pair_from_cairo(&p1
, cpml_primitive_get_point(line
, 0));
92 cpml_pair_from_cairo(&p2
, cpml_primitive_get_point(line
, -1));
94 cpml_extents_pair_add(extents
, &p1
);
95 cpml_extents_pair_add(extents
, &p2
);
100 * @line: the #CpmlPrimitive line data
101 * @pair: the destination pair
102 * @pos: the position value
104 * Given the @line line, finds the coordinates at position @pos
105 * (where 0 is the start and 1 is the end) and stores the result
108 * @pos can be less than 0 or greater than 1, in which case the
109 * coordinates are interpolated.
112 cpml_line_pair_at(const CpmlPrimitive
*line
, CpmlPair
*pair
, double pos
)
114 cairo_path_data_t
*p1
, *p2
;
116 p1
= cpml_primitive_get_point(line
, 0);
117 p2
= cpml_primitive_get_point(line
, -1);
119 pair
->x
= p1
->point
.x
+ (p2
->point
.x
- p1
->point
.x
) * pos
;
120 pair
->y
= p1
->point
.y
+ (p2
->point
.y
- p1
->point
.y
) * pos
;
124 * cpml_line_vector_at:
125 * @line: the #CpmlPrimitive line data
126 * @vector: the destination vector
127 * @pos: the position value
129 * Gets the slope on @line at the position @pos. Being the
130 * line a straight segment, the vector is always the same, so
131 * @pos is not used. Mathematically speaking, the equation
134 * @vector = endpoint(@line) - startpoint(@line).
137 cpml_line_vector_at(const CpmlPrimitive
*line
, CpmlVector
*vector
, double pos
)
139 cairo_path_data_t
*p1
, *p2
;
141 p1
= cpml_primitive_get_point(line
, 0);
142 p2
= cpml_primitive_get_point(line
, -1);
144 vector
->x
= p2
->point
.x
- p1
->point
.x
;
145 vector
->y
= p2
->point
.y
- p1
->point
.y
;
149 * cpml_line_near_pos:
150 * @line: the #CpmlPrimitive line data
151 * @pair: the coordinates of the subject point
153 * Returns the pos value of the point on @line nearest to @pair.
154 * The returned value is always between 0 and 1.
156 * The point nearest to @pair is got by finding the its
157 * projection on @line, as this is when the point is closer to
160 * Returns: the pos value, always between 0 and 1
163 cpml_line_near_pos(const CpmlPrimitive
*line
, const CpmlPair
*pair
)
169 cpml_pair_from_cairo(&p
[0], cpml_primitive_get_point(line
, 0));
170 cpml_pair_from_cairo(&p
[1], cpml_primitive_get_point(line
, -1));
172 cpml_pair_copy(&normal
, &p
[1]);
173 cpml_pair_sub(&normal
, &p
[2]);
174 cpml_vector_normal(&normal
);
176 cpml_pair_copy(&p
[2], pair
);
177 cpml_pair_copy(&p
[3], pair
);
178 cpml_pair_add(&p
[3], &normal
);
180 /* Ensure to return 0 if intersection() fails */
182 intersection(p
, NULL
, &pos
);
184 /* Clamp the result to 0..1 */
194 * cpml_line_intersection:
195 * @line: the first line
196 * @line2: the second line
197 * @dest: a vector of #CpmlPair
198 * @max: maximum number of intersections to return
199 * (that is, the size of @dest)
201 * Given two lines (@line and @line2), gets their intersection point
202 * and store the result in @dest.
204 * If @max is 0, the function returns 0 immediately without any
205 * further processing. If @line and @line2 are cohincident,
206 * their intersections are not considered.
208 * Returns: the number of intersections found (max 1)
209 * or 0 if the primitives do not intersect
212 cpml_line_intersection(const CpmlPrimitive
*line
, const CpmlPrimitive
*line2
,
213 CpmlPair
*dest
, int max
)
220 cpml_pair_from_cairo(&p
[0], cpml_primitive_get_point(line
, 0));
221 cpml_pair_from_cairo(&p
[1], cpml_primitive_get_point(line
, -1));
222 cpml_pair_from_cairo(&p
[2], cpml_primitive_get_point(line2
, 0));
223 cpml_pair_from_cairo(&p
[3], cpml_primitive_get_point(line2
, -1));
225 return intersection(p
, dest
, NULL
) ? 1 : 0;
230 * @line: the #CpmlPrimitive line data
231 * @offset: distance for the computed parallel line
233 * Given a line segment specified by the @line primitive data,
234 * computes the parallel line distant @offset from the original one
235 * and returns the result by changing @line.
238 cpml_line_offset(CpmlPrimitive
*line
, double offset
)
240 cairo_path_data_t
*p1
, *p2
;
243 p1
= cpml_primitive_get_point(line
, 0);
244 p2
= cpml_primitive_get_point(line
, -1);
246 cpml_line_vector_at(line
, &normal
, 0.);
247 cpml_vector_normal(&normal
);
248 cpml_vector_set_length(&normal
, offset
);
250 p1
->point
.x
+= normal
.x
;
251 p1
->point
.y
+= normal
.y
;
252 p2
->point
.x
+= normal
.x
;
253 p2
->point
.y
+= normal
.y
;
258 intersection(const CpmlPair
*p
, CpmlPair
*dest
, double *get_factor
)
263 cpml_pair_copy(&v
[0], &p
[1]);
264 cpml_pair_sub(&v
[0], &p
[0]);
265 cpml_pair_copy(&v
[1], &p
[3]);
266 cpml_pair_sub(&v
[1], &p
[2]);
267 factor
= v
[0].x
* v
[1].y
- v
[0].y
* v
[1].x
;
269 /* Check for equal slopes (the lines are parallel) */
273 factor
= ((p
[0].y
- p
[2].y
) * v
[1].x
-
274 (p
[0].x
- p
[2].x
) * v
[1].y
) / factor
;
277 dest
->x
= p
[0].x
+ v
[0].x
* factor
;
278 dest
->y
= p
[0].y
+ v
[0].y
* factor
;
281 if (get_factor
!= NULL
)
282 *get_factor
= factor
;