build: depends on cairo-gobject if introspection is enabled
[adg.git] / src / cpml / cpml-line.c
blob960023bc7d3468e83aec9a9d972f0d2d18dc88e8
1 /* CPML - Cairo Path Manipulation Library
2 * Copyright (C) 2007,2008,2009,2010,2011,2012,2013 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
45 intersection (const CpmlPair *p1_4,
46 CpmlPair *dest,
47 double *get_factor);
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 = {
57 "line to", 2,
58 get_length,
59 put_extents,
60 put_pair_at,
61 put_vector_at,
62 get_closest_pos,
63 put_intersections,
64 offset,
65 NULL
67 p_class = &class_data;
70 return p_class;
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 = {
80 "close", 2,
81 get_length,
82 put_extents,
83 put_pair_at,
84 put_vector_at,
85 get_closest_pos,
86 put_intersections,
87 offset,
88 NULL
90 p_class = &class_data;
93 return p_class;
97 static double
98 get_length(const CpmlPrimitive *line)
100 CpmlPair p1, p2;
102 cpml_primitive_put_point(line, 0, &p1);
103 cpml_primitive_put_point(line, -1, &p2);
105 return cpml_pair_distance(&p1, &p2);
108 static void
109 put_extents(const CpmlPrimitive *line, CpmlExtents *extents)
111 CpmlPair p1, p2;
113 extents->is_defined = 0;
115 cpml_primitive_put_point(line, 0, &p1);
116 cpml_primitive_put_point(line, -1, &p2);
118 cpml_extents_pair_add(extents, &p1);
119 cpml_extents_pair_add(extents, &p2);
122 static void
123 put_pair_at(const CpmlPrimitive *line, double pos, CpmlPair *pair)
125 CpmlPair p1, p2;
127 cpml_primitive_put_point(line, 0, &p1);
128 cpml_primitive_put_point(line, -1, &p2);
130 pair->x = p1.x + (p2.x - p1.x) * pos;
131 pair->y = p1.y + (p2.y - p1.y) * pos;
134 static void
135 put_vector_at(const CpmlPrimitive *line, double pos, CpmlVector *vector)
137 CpmlPair p1, p2;
139 cpml_primitive_put_point(line, 0, &p1);
140 cpml_primitive_put_point(line, -1, &p2);
142 vector->x = p2.x - p1.x;
143 vector->y = p2.y - p1.y;
146 static double
147 get_closest_pos(const CpmlPrimitive *line, const CpmlPair *pair)
149 CpmlPair p1_4[4];
150 CpmlVector normal;
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[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 */
166 pos = 0;
167 intersection(p1_4, NULL, &pos);
169 /* Clamp the result to 0..1 */
170 if (pos < 0)
171 pos = 0;
172 else if (pos > 1.)
173 pos = 1.;
175 return pos;
178 static size_t
179 put_intersections(const CpmlPrimitive *line, const CpmlPrimitive *primitive,
180 size_t n_dest, CpmlPair *dest)
182 CpmlPair p1_4[4];
184 if (n_dest == 0)
185 return 0;
187 cpml_primitive_put_point(line, 0, &p1_4[0]);
188 cpml_primitive_put_point(line, -1, &p1_4[1]);
189 cpml_primitive_put_point(primitive, 0, &p1_4[2]);
190 cpml_primitive_put_point(primitive, -1, &p1_4[3]);
192 return intersection(p1_4, dest, NULL) ? 1 : 0;
195 static void
196 offset(CpmlPrimitive *line, double offset)
198 CpmlPair p1, p2;
199 CpmlVector normal;
201 cpml_primitive_put_point(line, 0, &p1);
202 cpml_primitive_put_point(line, -1, &p2);
204 put_vector_at(line, 0, &normal);
205 cpml_vector_normal(&normal);
206 cpml_vector_set_length(&normal, offset);
208 p1.x += normal.x;
209 p1.y += normal.y;
210 p2.x += normal.x;
211 p2.y += normal.y;
213 cpml_primitive_set_point(line, 0, &p1);
214 cpml_primitive_set_point(line, -1, &p2);
217 static int
218 intersection(const CpmlPair *p1_4, CpmlPair *dest, double *get_factor)
220 CpmlVector v[2];
221 double factor;
223 v[0].x = p1_4[1].x - p1_4[0].x;
224 v[0].y = p1_4[1].y - p1_4[0].y;
225 v[1].x = p1_4[3].x - p1_4[2].x;
226 v[1].y = p1_4[3].y - p1_4[2].y;
227 factor = v[0].x * v[1].y - v[0].y * v[1].x;
229 /* Check for equal slopes (the lines are parallel) */
230 if (factor == 0)
231 return 0;
233 factor = ((p1_4[0].y - p1_4[2].y) * v[1].x -
234 (p1_4[0].x - p1_4[2].x) * v[1].y) / factor;
236 if (dest != NULL) {
237 dest->x = p1_4[0].x + v[0].x * factor;
238 dest->y = p1_4[0].y + v[0].y * factor;
241 if (get_factor != NULL)
242 *get_factor = factor;
244 return 1;