doc: update copyright line for 2021
[adg.git] / src / cpml / cpml-line.c
blobccb1a75437ab7b9cae925f400ef3ef370d618d07
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,
31 double pos,
32 CpmlPair *pair);
33 static void put_vector_at (const CpmlPrimitive *line,
34 double pos,
35 CpmlVector *vector);
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,
40 size_t n_dest,
41 CpmlPair *dest);
42 static void offset (CpmlPrimitive *line,
43 double offset);
44 static int intersection (const CpmlPair *p1_4,
45 CpmlPair *dest,
46 double *get_factor);
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 = {
56 "line to", 2,
57 get_length,
58 put_extents,
59 put_pair_at,
60 put_vector_at,
61 get_closest_pos,
62 put_intersections,
63 offset,
64 NULL
66 p_class = &class_data;
69 return p_class;
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 = {
79 "close", 2,
80 get_length,
81 put_extents,
82 put_pair_at,
83 put_vector_at,
84 get_closest_pos,
85 put_intersections,
86 offset,
87 NULL
89 p_class = &class_data;
92 return p_class;
96 static double
97 get_length(const CpmlPrimitive *line)
99 CpmlPair p1, p2;
101 cpml_primitive_put_point(line, 0, &p1);
102 cpml_primitive_put_point(line, -1, &p2);
104 return cpml_pair_distance(&p1, &p2);
107 static void
108 put_extents(const CpmlPrimitive *line, CpmlExtents *extents)
110 CpmlPair p1, p2;
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);
121 static void
122 put_pair_at(const CpmlPrimitive *line, double pos, CpmlPair *pair)
124 CpmlPair p1, p2;
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;
133 static void
134 put_vector_at(const CpmlPrimitive *line, double pos, CpmlVector *vector)
136 CpmlPair p1, p2;
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;
145 static double
146 get_closest_pos(const CpmlPrimitive *line, const CpmlPair *pair)
148 CpmlPair p1_4[4];
149 CpmlVector normal;
150 CpmlPair dummy;
151 double pos;
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 */
166 pos = 0;
167 /* The destination pair cannot be NULL to avoid crashes */
168 intersection(p1_4, &dummy, &pos);
170 /* Clamp the result to 0..1 */
171 if (pos < 0)
172 pos = 0;
173 else if (pos > 1.)
174 pos = 1.;
176 return pos;
179 static size_t
180 put_intersections(const CpmlPrimitive *line, const CpmlPrimitive *primitive,
181 size_t n_dest, CpmlPair *dest)
183 CpmlPair p1_4[4];
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;
193 static void
194 offset(CpmlPrimitive *line, double offset)
196 CpmlPair p1, p2;
197 CpmlVector normal;
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);
206 p1.x += normal.x;
207 p1.y += normal.y;
208 p2.x += normal.x;
209 p2.y += normal.y;
211 cpml_primitive_set_point(line, 0, &p1);
212 cpml_primitive_set_point(line, -1, &p2);
215 static int
216 intersection(const CpmlPair *p1_4, CpmlPair *dest, double *get_factor)
218 CpmlVector v[2];
219 double 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) */
228 if (factor == 0)
229 return 0;
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;
240 return 1;