[CPML] s/cpml_(.*?)_extents/cpml_\1_put_extents/
[adg.git] / cpml / cpml-line.c
blob19a7a54debea001d0c1eb1112322f70b3bc00a82
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 * Returns: 2
50 **/
51 int
52 cpml_line_type_get_npoints(void)
54 return 2;
57 /**
58 * cpml_line_get_length:
59 * @line: the #CpmlPrimitive line data
61 * Given the @line primitive, returns the distance between its
62 * start and end points.
64 * Returns: the requested distance, that is the @line length
65 **/
66 double
67 cpml_line_get_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_put_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_put_extents(const CpmlPrimitive *line, CpmlExtents *extents)
87 CpmlPair p1, p2;
89 extents->is_defined = 0;
91 cpml_pair_from_cairo(&p1, cpml_primitive_get_point(line, 0));
92 cpml_pair_from_cairo(&p2, cpml_primitive_get_point(line, -1));
94 cpml_extents_pair_add(extents, &p1);
95 cpml_extents_pair_add(extents, &p2);
98 /**
99 * cpml_line_pair_at:
100 * @line: the #CpmlPrimitive line data
101 * @pair: the destination pair
102 * @pos: the position value
104 * Given the @line line, finds the coordinates at position @pos
105 * (where 0 is the start and 1 is the end) and stores the result
106 * in @pair.
108 * @pos can be less than 0 or greater than 1, in which case the
109 * coordinates are interpolated.
111 void
112 cpml_line_pair_at(const CpmlPrimitive *line, CpmlPair *pair, double pos)
114 cairo_path_data_t *p1, *p2;
116 p1 = cpml_primitive_get_point(line, 0);
117 p2 = cpml_primitive_get_point(line, -1);
119 pair->x = p1->point.x + (p2->point.x - p1->point.x) * pos;
120 pair->y = p1->point.y + (p2->point.y - p1->point.y) * pos;
124 * cpml_line_vector_at:
125 * @line: the #CpmlPrimitive line data
126 * @vector: the destination vector
127 * @pos: the position value
129 * Gets the slope on @line at the position @pos. Being the
130 * line a straight segment, the vector is always the same, so
131 * @pos is not used. Mathematically speaking, the equation
132 * performed is:
134 * @vector = endpoint(@line) - startpoint(@line).
136 void
137 cpml_line_vector_at(const CpmlPrimitive *line, CpmlVector *vector, double pos)
139 cairo_path_data_t *p1, *p2;
141 p1 = cpml_primitive_get_point(line, 0);
142 p2 = cpml_primitive_get_point(line, -1);
144 vector->x = p2->point.x - p1->point.x;
145 vector->y = p2->point.y - p1->point.y;
149 * cpml_line_near_pos:
150 * @line: the #CpmlPrimitive line data
151 * @pair: the coordinates of the subject point
153 * Returns the pos value of the point on @line nearest to @pair.
154 * The returned value is always between 0 and 1.
156 * The point nearest to @pair is got by finding the its
157 * projection on @line, as this is when the point is closer to
158 * a line primitive.
160 * Returns: the pos value, always between 0 and 1
162 double
163 cpml_line_near_pos(const CpmlPrimitive *line, const CpmlPair *pair)
165 CpmlPair p[4];
166 CpmlVector normal;
167 double pos;
169 cpml_pair_from_cairo(&p[0], cpml_primitive_get_point(line, 0));
170 cpml_pair_from_cairo(&p[1], cpml_primitive_get_point(line, -1));
172 cpml_pair_copy(&normal, &p[1]);
173 cpml_pair_sub(&normal, &p[2]);
174 cpml_vector_normal(&normal);
176 cpml_pair_copy(&p[2], pair);
177 cpml_pair_copy(&p[3], pair);
178 cpml_pair_add(&p[3], &normal);
180 /* Ensure to return 0 if intersection() fails */
181 pos = 0;
182 intersection(p, NULL, &pos);
184 /* Clamp the result to 0..1 */
185 if (pos < 0)
186 pos = 0;
187 else if (pos > 1.)
188 pos = 1.;
190 return pos;
194 * cpml_line_intersection:
195 * @line: the first line
196 * @line2: the second line
197 * @dest: a vector of #CpmlPair
198 * @max: maximum number of intersections to return
199 * (that is, the size of @dest)
201 * Given two lines (@line and @line2), gets their intersection point
202 * and store the result in @dest.
204 * If @max is 0, the function returns 0 immediately without any
205 * further processing. If @line and @line2 are cohincident,
206 * their intersections are not considered.
208 * Returns: the number of intersections found (max 1)
209 * or 0 if the primitives do not intersect
212 cpml_line_intersection(const CpmlPrimitive *line, const CpmlPrimitive *line2,
213 CpmlPair *dest, int max)
215 CpmlPair p[4];
217 if (max == 0)
218 return 0;
220 cpml_pair_from_cairo(&p[0], cpml_primitive_get_point(line, 0));
221 cpml_pair_from_cairo(&p[1], cpml_primitive_get_point(line, -1));
222 cpml_pair_from_cairo(&p[2], cpml_primitive_get_point(line2, 0));
223 cpml_pair_from_cairo(&p[3], cpml_primitive_get_point(line2, -1));
225 return intersection(p, dest, NULL) ? 1 : 0;
229 * cpml_line_offset:
230 * @line: the #CpmlPrimitive line data
231 * @offset: distance for the computed parallel line
233 * Given a line segment specified by the @line primitive data,
234 * computes the parallel line distant @offset from the original one
235 * and returns the result by changing @line.
237 void
238 cpml_line_offset(CpmlPrimitive *line, double offset)
240 cairo_path_data_t *p1, *p2;
241 CpmlVector normal;
243 p1 = cpml_primitive_get_point(line, 0);
244 p2 = cpml_primitive_get_point(line, -1);
246 cpml_line_vector_at(line, &normal, 0.);
247 cpml_vector_normal(&normal);
248 cpml_vector_set_length(&normal, offset);
250 p1->point.x += normal.x;
251 p1->point.y += normal.y;
252 p2->point.x += normal.x;
253 p2->point.y += normal.y;
257 static cairo_bool_t
258 intersection(const CpmlPair *p, CpmlPair *dest, double *get_factor)
260 CpmlVector v[2];
261 double factor;
263 cpml_pair_copy(&v[0], &p[1]);
264 cpml_pair_sub(&v[0], &p[0]);
265 cpml_pair_copy(&v[1], &p[3]);
266 cpml_pair_sub(&v[1], &p[2]);
267 factor = v[0].x * v[1].y - v[0].y * v[1].x;
269 /* Check for equal slopes (the lines are parallel) */
270 if (factor == 0)
271 return 0;
273 factor = ((p[0].y - p[2].y) * v[1].x -
274 (p[0].x - p[2].x) * v[1].y) / factor;
276 if (dest != NULL) {
277 dest->x = p[0].x + v[0].x * factor;
278 dest->y = p[0].y + v[0].y * factor;
281 if (get_factor != NULL)
282 *get_factor = factor;
284 return 1;