1 /* CPML - Cairo Path Manipulation Library
2 * Copyright (C) 2007-2021 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
,
44 static int intersection (const CpmlPair
*p1_4
,
49 const _CpmlPrimitiveClass
*
50 _cpml_line_get_class(void)
52 static _CpmlPrimitiveClass
*p_class
= NULL
;
54 if (p_class
== NULL
) {
55 static _CpmlPrimitiveClass class_data
= {
66 p_class
= &class_data
;
72 const _CpmlPrimitiveClass
*
73 _cpml_close_get_class(void)
75 static _CpmlPrimitiveClass
*p_class
= NULL
;
77 if (p_class
== NULL
) {
78 static _CpmlPrimitiveClass class_data
= {
89 p_class
= &class_data
;
97 get_length(const CpmlPrimitive
*line
)
101 cpml_primitive_put_point(line
, 0, &p1
);
102 cpml_primitive_put_point(line
, -1, &p2
);
104 return cpml_pair_distance(&p1
, &p2
);
108 put_extents(const CpmlPrimitive
*line
, CpmlExtents
*extents
)
112 extents
->is_defined
= 0;
114 cpml_primitive_put_point(line
, 0, &p1
);
115 cpml_primitive_put_point(line
, -1, &p2
);
117 cpml_extents_pair_add(extents
, &p1
);
118 cpml_extents_pair_add(extents
, &p2
);
122 put_pair_at(const CpmlPrimitive
*line
, double pos
, CpmlPair
*pair
)
126 cpml_primitive_put_point(line
, 0, &p1
);
127 cpml_primitive_put_point(line
, -1, &p2
);
129 pair
->x
= p1
.x
+ (p2
.x
- p1
.x
) * pos
;
130 pair
->y
= p1
.y
+ (p2
.y
- p1
.y
) * pos
;
134 put_vector_at(const CpmlPrimitive
*line
, double pos
, CpmlVector
*vector
)
138 cpml_primitive_put_point(line
, 0, &p1
);
139 cpml_primitive_put_point(line
, -1, &p2
);
141 vector
->x
= p2
.x
- p1
.x
;
142 vector
->y
= p2
.y
- p1
.y
;
146 get_closest_pos(const CpmlPrimitive
*line
, const CpmlPair
*pair
)
153 cpml_primitive_put_point(line
, 0, &p1_4
[0]);
154 cpml_primitive_put_point(line
, -1, &p1_4
[1]);
156 normal
.x
= p1_4
[1].x
- p1_4
[0].x
;
157 normal
.y
= p1_4
[1].y
- p1_4
[0].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 /* The destination pair cannot be NULL to avoid crashes */
168 intersection(p1_4
, &dummy
, &pos
);
170 /* Clamp the result to 0..1 */
180 put_intersections(const CpmlPrimitive
*line
, const CpmlPrimitive
*primitive
,
181 size_t n_dest
, CpmlPair
*dest
)
185 cpml_primitive_put_point(line
, 0, &p1_4
[0]);
186 cpml_primitive_put_point(line
, -1, &p1_4
[1]);
187 cpml_primitive_put_point(primitive
, 0, &p1_4
[2]);
188 cpml_primitive_put_point(primitive
, -1, &p1_4
[3]);
190 return intersection(p1_4
, dest
, NULL
) ? 1 : 0;
194 offset(CpmlPrimitive
*line
, double offset
)
199 cpml_primitive_put_point(line
, 0, &p1
);
200 cpml_primitive_put_point(line
, -1, &p2
);
202 put_vector_at(line
, 0, &normal
);
203 cpml_vector_normal(&normal
);
204 cpml_vector_set_length(&normal
, offset
);
211 cpml_primitive_set_point(line
, 0, &p1
);
212 cpml_primitive_set_point(line
, -1, &p2
);
216 intersection(const CpmlPair
*p1_4
, CpmlPair
*dest
, double *get_factor
)
221 v
[0].x
= p1_4
[1].x
- p1_4
[0].x
;
222 v
[0].y
= p1_4
[1].y
- p1_4
[0].y
;
223 v
[1].x
= p1_4
[3].x
- p1_4
[2].x
;
224 v
[1].y
= p1_4
[3].y
- p1_4
[2].y
;
225 factor
= v
[0].x
* v
[1].y
- v
[0].y
* v
[1].x
;
227 /* Check for equal slopes (the lines are parallel) */
231 factor
= ((p1_4
[0].y
- p1_4
[2].y
) * v
[1].x
-
232 (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
;
237 if (get_factor
!= NULL
)
238 *get_factor
= factor
;