[AdgMatrix] Corrected adg_matrix_normalize()
[adg.git] / cpml / cpml-line.c
blobbca309cabd6eb2c78c18cdc9e5b656c9cce4a40d
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 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 * Return value: 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_sub(cpml_pair_copy(&normal, &p[1]), &p[2]);
173 cpml_vector_normal(&normal);
175 cpml_pair_copy(&p[2], pair);
176 cpml_pair_add(cpml_pair_copy(&p[3], pair), &normal);
178 /* Ensure to return 0 if intersection() fails */
179 pos = 0;
180 intersection(p, NULL, &pos);
182 /* Clamp the result to 0..1 */
183 if (pos < 0)
184 pos = 0;
185 else if (pos > 1.)
186 pos = 1.;
188 return pos;
192 * cpml_line_intersection:
193 * @line: the first line
194 * @line2: the second line
195 * @dest: a vector of #CpmlPair
196 * @max: maximum number of intersections to return
197 * (that is, the size of @dest)
199 * Given two lines (@line and @line2), gets their intersection point
200 * and store the result in @dest.
202 * If @max is 0, the function returns 0 immediately without any
203 * further processing. If @line and @line2 are cohincident,
204 * their intersections are not considered.
206 * Return value: the number of intersections found (max 1)
207 * or 0 if the primitives do not intersect
210 cpml_line_intersection(const CpmlPrimitive *line, const CpmlPrimitive *line2,
211 CpmlPair *dest, int max)
213 CpmlPair p[4];
215 if (max == 0)
216 return 0;
218 cpml_pair_from_cairo(&p[0], cpml_primitive_get_point(line, 0));
219 cpml_pair_from_cairo(&p[1], cpml_primitive_get_point(line, -1));
220 cpml_pair_from_cairo(&p[2], cpml_primitive_get_point(line2, 0));
221 cpml_pair_from_cairo(&p[3], cpml_primitive_get_point(line2, -1));
223 return intersection(p, dest, NULL) ? 1 : 0;
227 * cpml_line_offset:
228 * @line: the #CpmlPrimitive line data
229 * @offset: distance for the computed parallel line
231 * Given a line segment specified by the @line primitive data,
232 * computes the parallel line distant @offset from the original one
233 * and returns the result by changing @line.
235 void
236 cpml_line_offset(CpmlPrimitive *line, double offset)
238 cairo_path_data_t *p1, *p2;
239 CpmlVector normal;
241 p1 = cpml_primitive_get_point(line, 0);
242 p2 = cpml_primitive_get_point(line, -1);
244 cpml_line_vector_at(line, &normal, 0.);
245 cpml_vector_normal(&normal);
246 cpml_vector_set_length(&normal, offset);
248 p1->point.x += normal.x;
249 p1->point.y += normal.y;
250 p2->point.x += normal.x;
251 p2->point.y += normal.y;
255 static cairo_bool_t
256 intersection(const CpmlPair *p, CpmlPair *dest, double *get_factor)
258 CpmlVector v[2];
259 double factor;
261 cpml_pair_sub(cpml_pair_copy(&v[0], &p[1]), &p[0]);
262 cpml_pair_sub(cpml_pair_copy(&v[1], &p[3]), &p[2]);
263 factor = v[0].x * v[1].y - v[0].y * v[1].x;
265 /* Check for equal slopes (the lines are parallel) */
266 if (factor == 0)
267 return 0;
269 factor = ((p[0].y - p[2].y) * v[1].x -
270 (p[0].x - p[2].x) * v[1].y) / factor;
272 if (dest != NULL) {
273 dest->x = p[0].x + v[0].x * factor;
274 dest->y = p[0].y + v[0].y * factor;
277 if (get_factor != NULL)
278 *get_factor = factor;
280 return 1;