1 /* CPML - Cairo Path Manipulation Library
2 * Copyright (C) 2008,2009,2010 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 #CPML_LINE #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 straight line.
36 * The type code used to identify "line-to" primitives.
37 * It is equivalent to the %CAIRO_PATH_LINE_TO cairo constant.
43 * @Section_Id:CpmlClose
45 * @short_description: Straigth line used to close cyclic segments
47 * The following functions manipulate #CPML_CLOSE #CpmlPrimitive.
48 * No validation is made on the input so use the following methods
49 * only when you are sure the <varname>primitive</varname> argument
50 * is effectively a close path.
52 * This primitive management is almost identical to straight lines,
53 * but taking properly start and end points.
59 * The type code used to identify "close" primitives.
60 * It is equivalent to the %CAIRO_PATH_CLOSE_PATH cairo constant.
64 #include "cpml-internal.h"
65 #include "cpml-extents.h"
66 #include "cpml-segment.h"
67 #include "cpml-primitive.h"
68 #include "cpml-primitive-private.h"
69 #include "cpml-line.h"
72 static double get_length (const CpmlPrimitive
*line
);
73 static void put_extents (const CpmlPrimitive
*line
,
74 CpmlExtents
*extents
);
75 static void put_pair_at (const CpmlPrimitive
*line
,
78 static void put_vector_at (const CpmlPrimitive
*line
,
81 static double get_closest_pos (const CpmlPrimitive
*line
,
82 const CpmlPair
*pair
);
83 static size_t put_intersections (const CpmlPrimitive
*line
,
84 const CpmlPrimitive
*primitive
,
87 static void offset (CpmlPrimitive
*line
,
90 intersection (const CpmlPair
*p1_4
,
95 const _CpmlPrimitiveClass
*
96 _cpml_line_get_class(void)
98 static _CpmlPrimitiveClass
*p_class
= NULL
;
100 if (p_class
== NULL
) {
101 static _CpmlPrimitiveClass class_data
= {
112 p_class
= &class_data
;
118 const _CpmlPrimitiveClass
*
119 _cpml_close_get_class(void)
121 static _CpmlPrimitiveClass
*p_class
= NULL
;
123 if (p_class
== NULL
) {
124 static _CpmlPrimitiveClass class_data
= {
135 p_class
= &class_data
;
143 get_length(const CpmlPrimitive
*line
)
147 cpml_pair_from_cairo(&p1
, cpml_primitive_get_point(line
, 0));
148 cpml_pair_from_cairo(&p2
, cpml_primitive_get_point(line
, -1));
150 return cpml_pair_distance(&p1
, &p2
);
154 put_extents(const CpmlPrimitive
*line
, CpmlExtents
*extents
)
158 extents
->is_defined
= 0;
160 cpml_pair_from_cairo(&p1
, cpml_primitive_get_point(line
, 0));
161 cpml_pair_from_cairo(&p2
, cpml_primitive_get_point(line
, -1));
163 cpml_extents_pair_add(extents
, &p1
);
164 cpml_extents_pair_add(extents
, &p2
);
168 put_pair_at(const CpmlPrimitive
*line
, double pos
, CpmlPair
*pair
)
170 cairo_path_data_t
*p1
, *p2
;
172 p1
= cpml_primitive_get_point(line
, 0);
173 p2
= cpml_primitive_get_point(line
, -1);
175 pair
->x
= p1
->point
.x
+ (p2
->point
.x
- p1
->point
.x
) * pos
;
176 pair
->y
= p1
->point
.y
+ (p2
->point
.y
- p1
->point
.y
) * pos
;
180 put_vector_at(const CpmlPrimitive
*line
, double pos
, CpmlVector
*vector
)
182 cairo_path_data_t
*p1
, *p2
;
184 p1
= cpml_primitive_get_point(line
, 0);
185 p2
= cpml_primitive_get_point(line
, -1);
187 vector
->x
= p2
->point
.x
- p1
->point
.x
;
188 vector
->y
= p2
->point
.y
- p1
->point
.y
;
192 get_closest_pos(const CpmlPrimitive
*line
, const CpmlPair
*pair
)
198 cpml_pair_from_cairo(&p1_4
[0], cpml_primitive_get_point(line
, 0));
199 cpml_pair_from_cairo(&p1_4
[1], cpml_primitive_get_point(line
, -1));
201 normal
.x
= p1_4
[1].x
- p1_4
[2].x
;
202 normal
.y
= p1_4
[1].y
- p1_4
[2].y
;
203 cpml_vector_normal(&normal
);
205 cpml_pair_copy(&p1_4
[2], pair
);
207 p1_4
[3].x
= pair
->x
+ normal
.x
;
208 p1_4
[3].y
= pair
->y
+ normal
.y
;
210 /* Ensure to return 0 if intersection() fails */
212 intersection(p1_4
, NULL
, &pos
);
214 /* Clamp the result to 0..1 */
224 put_intersections(const CpmlPrimitive
*line
, const CpmlPrimitive
*primitive
,
225 size_t n_dest
, CpmlPair
*dest
)
232 cpml_pair_from_cairo(&p1_4
[0], cpml_primitive_get_point(line
, 0));
233 cpml_pair_from_cairo(&p1_4
[1], cpml_primitive_get_point(line
, -1));
234 cpml_pair_from_cairo(&p1_4
[2], cpml_primitive_get_point(primitive
, 0));
235 cpml_pair_from_cairo(&p1_4
[3], cpml_primitive_get_point(primitive
, -1));
237 return intersection(p1_4
, dest
, NULL
) ? 1 : 0;
241 offset(CpmlPrimitive
*line
, double offset
)
243 cairo_path_data_t
*p1
, *p2
;
246 p1
= cpml_primitive_get_point(line
, 0);
247 p2
= cpml_primitive_get_point(line
, -1);
249 put_vector_at(line
, 0, &normal
);
250 cpml_vector_normal(&normal
);
251 cpml_vector_set_length(&normal
, offset
);
253 p1
->point
.x
+= normal
.x
;
254 p1
->point
.y
+= normal
.y
;
255 p2
->point
.x
+= normal
.x
;
256 p2
->point
.y
+= normal
.y
;
260 intersection(const CpmlPair
*p1_4
, CpmlPair
*dest
, double *get_factor
)
265 v
[0].x
= p1_4
[1].x
- p1_4
[0].x
;
266 v
[0].y
= p1_4
[1].y
- p1_4
[0].y
;
267 v
[1].x
= p1_4
[3].x
- p1_4
[2].x
;
268 v
[1].y
= p1_4
[3].y
- p1_4
[2].y
;
269 factor
= v
[0].x
* v
[1].y
- v
[0].y
* v
[1].x
;
271 /* Check for equal slopes (the lines are parallel) */
275 factor
= ((p1_4
[0].y
- p1_4
[2].y
) * v
[1].x
-
276 (p1_4
[0].x
- p1_4
[2].x
) * v
[1].y
) / factor
;
279 dest
->x
= p1_4
[0].x
+ v
[0].x
* factor
;
280 dest
->y
= p1_4
[0].y
+ v
[0].y
* factor
;
283 if (get_factor
!= NULL
)
284 *get_factor
= factor
;