1 /* CPML - Cairo Path Manipulation Library
2 * Copyright (C) 2008,2009,2010,2011 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.
20 #include "cpml-internal.h"
21 #include "cpml-extents.h"
22 #include "cpml-segment.h"
23 #include "cpml-primitive.h"
24 #include "cpml-primitive-private.h"
27 static double get_length (const CpmlPrimitive
*line
);
28 static void put_extents (const CpmlPrimitive
*line
,
29 CpmlExtents
*extents
);
30 static void put_pair_at (const CpmlPrimitive
*line
,
33 static void put_vector_at (const CpmlPrimitive
*line
,
36 static double get_closest_pos (const CpmlPrimitive
*line
,
37 const CpmlPair
*pair
);
38 static size_t put_intersections (const CpmlPrimitive
*line
,
39 const CpmlPrimitive
*primitive
,
42 static void offset (CpmlPrimitive
*line
,
45 intersection (const CpmlPair
*p1_4
,
50 const _CpmlPrimitiveClass
*
51 _cpml_line_get_class(void)
53 static _CpmlPrimitiveClass
*p_class
= NULL
;
55 if (p_class
== NULL
) {
56 static _CpmlPrimitiveClass class_data
= {
67 p_class
= &class_data
;
73 const _CpmlPrimitiveClass
*
74 _cpml_close_get_class(void)
76 static _CpmlPrimitiveClass
*p_class
= NULL
;
78 if (p_class
== NULL
) {
79 static _CpmlPrimitiveClass class_data
= {
90 p_class
= &class_data
;
98 get_length(const CpmlPrimitive
*line
)
102 cpml_pair_from_cairo(&p1
, cpml_primitive_get_point(line
, 0));
103 cpml_pair_from_cairo(&p2
, cpml_primitive_get_point(line
, -1));
105 return cpml_pair_distance(&p1
, &p2
);
109 put_extents(const CpmlPrimitive
*line
, CpmlExtents
*extents
)
113 extents
->is_defined
= 0;
115 cpml_pair_from_cairo(&p1
, cpml_primitive_get_point(line
, 0));
116 cpml_pair_from_cairo(&p2
, cpml_primitive_get_point(line
, -1));
118 cpml_extents_pair_add(extents
, &p1
);
119 cpml_extents_pair_add(extents
, &p2
);
123 put_pair_at(const CpmlPrimitive
*line
, double pos
, CpmlPair
*pair
)
125 cairo_path_data_t
*p1
, *p2
;
127 p1
= cpml_primitive_get_point(line
, 0);
128 p2
= cpml_primitive_get_point(line
, -1);
130 pair
->x
= p1
->point
.x
+ (p2
->point
.x
- p1
->point
.x
) * pos
;
131 pair
->y
= p1
->point
.y
+ (p2
->point
.y
- p1
->point
.y
) * pos
;
135 put_vector_at(const CpmlPrimitive
*line
, double pos
, CpmlVector
*vector
)
137 cairo_path_data_t
*p1
, *p2
;
139 p1
= cpml_primitive_get_point(line
, 0);
140 p2
= cpml_primitive_get_point(line
, -1);
142 vector
->x
= p2
->point
.x
- p1
->point
.x
;
143 vector
->y
= p2
->point
.y
- p1
->point
.y
;
147 get_closest_pos(const CpmlPrimitive
*line
, const CpmlPair
*pair
)
153 cpml_pair_from_cairo(&p1_4
[0], cpml_primitive_get_point(line
, 0));
154 cpml_pair_from_cairo(&p1_4
[1], cpml_primitive_get_point(line
, -1));
156 normal
.x
= p1_4
[1].x
- p1_4
[2].x
;
157 normal
.y
= p1_4
[1].y
- p1_4
[2].y
;
158 cpml_vector_normal(&normal
);
160 cpml_pair_copy(&p1_4
[2], pair
);
162 p1_4
[3].x
= pair
->x
+ normal
.x
;
163 p1_4
[3].y
= pair
->y
+ normal
.y
;
165 /* Ensure to return 0 if intersection() fails */
167 intersection(p1_4
, NULL
, &pos
);
169 /* Clamp the result to 0..1 */
179 put_intersections(const CpmlPrimitive
*line
, const CpmlPrimitive
*primitive
,
180 size_t n_dest
, CpmlPair
*dest
)
187 cpml_pair_from_cairo(&p1_4
[0], cpml_primitive_get_point(line
, 0));
188 cpml_pair_from_cairo(&p1_4
[1], cpml_primitive_get_point(line
, -1));
189 cpml_pair_from_cairo(&p1_4
[2], cpml_primitive_get_point(primitive
, 0));
190 cpml_pair_from_cairo(&p1_4
[3], cpml_primitive_get_point(primitive
, -1));
192 return intersection(p1_4
, dest
, NULL
) ? 1 : 0;
196 offset(CpmlPrimitive
*line
, double offset
)
198 cairo_path_data_t
*p1
, *p2
;
201 p1
= cpml_primitive_get_point(line
, 0);
202 p2
= cpml_primitive_get_point(line
, -1);
204 put_vector_at(line
, 0, &normal
);
205 cpml_vector_normal(&normal
);
206 cpml_vector_set_length(&normal
, offset
);
208 p1
->point
.x
+= normal
.x
;
209 p1
->point
.y
+= normal
.y
;
210 p2
->point
.x
+= normal
.x
;
211 p2
->point
.y
+= normal
.y
;
215 intersection(const CpmlPair
*p1_4
, CpmlPair
*dest
, double *get_factor
)
220 v
[0].x
= p1_4
[1].x
- p1_4
[0].x
;
221 v
[0].y
= p1_4
[1].y
- p1_4
[0].y
;
222 v
[1].x
= p1_4
[3].x
- p1_4
[2].x
;
223 v
[1].y
= p1_4
[3].y
- p1_4
[2].y
;
224 factor
= v
[0].x
* v
[1].y
- v
[0].y
* v
[1].x
;
226 /* Check for equal slopes (the lines are parallel) */
230 factor
= ((p1_4
[0].y
- p1_4
[2].y
) * v
[1].x
-
231 (p1_4
[0].x
- p1_4
[2].x
) * v
[1].y
) / factor
;
234 dest
->x
= p1_4
[0].x
+ v
[0].x
* factor
;
235 dest
->y
= p1_4
[0].y
+ v
[0].y
* factor
;
238 if (get_factor
!= NULL
)
239 *get_factor
= factor
;