[AdgTransformationMode] Renamed to AdgTransformMode
[adg.git] / cpml / cpml-line.c
blob40190c5134c9d98a25cca0f7e18465e88b1b9faf
1 /* CPML - Cairo Path Manipulation Library
2 * Copyright (C) 2008, 2009 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.
21 /**
22 * SECTION:cpml-line
23 * @Section_Id:CpmlLine
24 * @title: CpmlLine
25 * @short_description: APIs manipulating straight lines
27 * The following functions manipulate %CAIRO_PATH_LINE_TO #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 straingt line.
31 **/
34 #include "cpml-line.h"
35 #include "cpml-pair.h"
36 #include <stdlib.h>
39 static cairo_bool_t intersection (const CpmlPair *p,
40 CpmlPair *dest,
41 double *get_factor);
44 /**
45 * cpml_line_type_get_npoints:
47 * Returns the number of point needed to properly specify a line primitive.
49 * Return value: 2
50 **/
51 int
52 cpml_line_type_get_npoints(void)
54 return 2;
57 /**
58 * cpml_line_length:
59 * @line: the #CpmlPrimitive line data
61 * Given the @line primitive, returns the distance between its
62 * start and end points.
64 * Return value: the requested distance, that is the @line length
65 **/
66 double
67 cpml_line_length(const CpmlPrimitive *line)
69 CpmlPair p1, p2;
71 cpml_pair_from_cairo(&p1, cpml_primitive_get_point(line, 0));
72 cpml_pair_from_cairo(&p2, cpml_primitive_get_point(line, -1));
74 return cpml_pair_distance(&p1, &p2);
77 /**
78 * cpml_line_extents:
79 * @line: the #CpmlPrimitive line data
80 * @extents: where to store the extents
82 * Given a @line primitive, returns its boundary box in @extents.
83 **/
84 void
85 cpml_line_extents(const CpmlPrimitive *line, CpmlExtents *extents)
87 CpmlPair p1, p2;
89 cpml_pair_from_cairo(&p1, cpml_primitive_get_point(line, 0));
90 cpml_pair_from_cairo(&p2, cpml_primitive_get_point(line, -1));
92 cpml_extents_pair_add(extents, &p1);
93 cpml_extents_pair_add(extents, &p2);
96 /**
97 * cpml_line_pair_at:
98 * @line: the #CpmlPrimitive line data
99 * @pair: the destination pair
100 * @pos: the position value
102 * Given the @line line, finds the coordinates at position @pos
103 * (where 0 is the start and 1 is the end) and stores the result
104 * in @pair.
106 * @pos can be less than 0 or greater than 1, in which case the
107 * coordinates are interpolated.
109 void
110 cpml_line_pair_at(const CpmlPrimitive *line, CpmlPair *pair, double pos)
112 cairo_path_data_t *p1, *p2;
114 p1 = cpml_primitive_get_point(line, 0);
115 p2 = cpml_primitive_get_point(line, -1);
117 pair->x = p1->point.x + (p2->point.x - p1->point.x) * pos;
118 pair->y = p1->point.y + (p2->point.y - p1->point.y) * pos;
122 * cpml_line_vector_at:
123 * @line: the #CpmlPrimitive line data
124 * @vector: the destination vector
125 * @pos: the position value
127 * Gets the slope on @line at the position @pos. Being the
128 * line a straight segment, the vector is always the same, so
129 * @pos is not used. Mathematically speaking, the equation
130 * performed is:
132 * @vector = endpoint(@line) - startpoint(@line).
134 void
135 cpml_line_vector_at(const CpmlPrimitive *line, CpmlVector *vector, double pos)
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 * cpml_line_near_pos:
148 * @line: the #CpmlPrimitive line data
149 * @pair: the coordinates of the subject point
151 * Returns the pos value of the point on @line nearest to @pair.
152 * The returned value is always between 0 and 1.
154 * The point nearest to @pair is got by finding the its
155 * projection on @line, as this is when the point is closer to
156 * a line primitive.
158 * Return value: the pos value, always between 0 and 1
160 double
161 cpml_line_near_pos(const CpmlPrimitive *line, const CpmlPair *pair)
163 CpmlPair p[4];
164 CpmlVector normal;
165 double pos;
167 cpml_pair_from_cairo(&p[0], cpml_primitive_get_point(line, 0));
168 cpml_pair_from_cairo(&p[1], cpml_primitive_get_point(line, -1));
170 cpml_pair_sub(cpml_pair_copy(&normal, &p[1]), &p[2]);
171 cpml_vector_normal(&normal);
173 cpml_pair_copy(&p[2], pair);
174 cpml_pair_add(cpml_pair_copy(&p[3], pair), &normal);
176 /* Ensure to return 0 if intersection() fails */
177 pos = 0;
178 intersection(p, NULL, &pos);
180 /* Clamp the result to 0..1 */
181 if (pos < 0)
182 pos = 0;
183 else if (pos > 1.)
184 pos = 1.;
186 return pos;
190 * cpml_line_intersection:
191 * @line: the first line
192 * @line2: the second line
193 * @dest: a vector of #CpmlPair
194 * @max: maximum number of intersections to return
195 * (that is, the size of @dest)
197 * Given two lines (@line and @line2), gets their intersection point
198 * and store the result in @dest.
200 * If @max is 0, the function returns 0 immediately without any
201 * further processing. If @line and @line2 are cohincident,
202 * their intersections are not considered.
204 * Return value: the number of intersections found (max 1)
205 * or 0 if the primitives do not intersect
208 cpml_line_intersection(const CpmlPrimitive *line, const CpmlPrimitive *line2,
209 CpmlPair *dest, int max)
211 CpmlPair p[4];
213 if (max == 0)
214 return 0;
216 cpml_pair_from_cairo(&p[0], cpml_primitive_get_point(line, 0));
217 cpml_pair_from_cairo(&p[1], cpml_primitive_get_point(line, -1));
218 cpml_pair_from_cairo(&p[2], cpml_primitive_get_point(line2, 0));
219 cpml_pair_from_cairo(&p[3], cpml_primitive_get_point(line2, -1));
221 return intersection(p, dest, NULL) ? 1 : 0;
225 * cpml_line_offset:
226 * @line: the #CpmlPrimitive line data
227 * @offset: distance for the computed parallel line
229 * Given a line segment specified by the @line primitive data,
230 * computes the parallel line distant @offset from the original one
231 * and returns the result by changing @line.
233 void
234 cpml_line_offset(CpmlPrimitive *line, double offset)
236 cairo_path_data_t *p1, *p2;
237 CpmlVector normal;
239 p1 = cpml_primitive_get_point(line, 0);
240 p2 = cpml_primitive_get_point(line, -1);
242 cpml_line_vector_at(line, &normal, 0.);
243 cpml_vector_normal(&normal);
244 cpml_vector_set_length(&normal, offset);
246 p1->point.x += normal.x;
247 p1->point.y += normal.y;
248 p2->point.x += normal.x;
249 p2->point.y += normal.y;
253 static cairo_bool_t
254 intersection(const CpmlPair *p, CpmlPair *dest, double *get_factor)
256 CpmlVector v[2];
257 double factor;
259 cpml_pair_sub(cpml_pair_copy(&v[0], &p[1]), &p[0]);
260 cpml_pair_sub(cpml_pair_copy(&v[1], &p[3]), &p[2]);
261 factor = v[0].x * v[1].y - v[0].y * v[1].x;
263 /* Check for equal slopes (the lines are parallel) */
264 if (factor == 0)
265 return 0;
267 factor = ((p[0].y - p[2].y) * v[1].x -
268 (p[0].x - p[2].x) * v[1].y) / factor;
270 if (dest != NULL) {
271 dest->x = p[0].x + v[0].x * factor;
272 dest->y = p[0].y + v[0].y * factor;
275 if (get_factor != NULL)
276 *get_factor = factor;
278 return 1;