[CPML] Added cpml_angle()
[adg.git] / cpml / cpml-line.c
blob661e5cfb130a660914b34264a84707660aedb1ea
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: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_pair_at:
79 * @line: the #CpmlPrimitive line data
80 * @pair: the destination pair
81 * @pos: the position value
83 * Given the @line line, finds the coordinates at position @pos
84 * (where 0 is the start and 1 is the end) and stores the result
85 * in @pair.
87 * @pos can be less than 0 or greater than 1, in which case the
88 * coordinates are interpolated.
89 **/
90 void
91 cpml_line_pair_at(const CpmlPrimitive *line, CpmlPair *pair, double pos)
93 cairo_path_data_t *p1, *p2;
95 p1 = cpml_primitive_get_point(line, 0);
96 p2 = cpml_primitive_get_point(line, -1);
98 pair->x = p1->point.x + (p2->point.x - p1->point.x) * pos;
99 pair->y = p1->point.y + (p2->point.y - p1->point.y) * pos;
103 * cpml_line_vector_at:
104 * @line: the #CpmlPrimitive line data
105 * @vector: the destination vector
106 * @pos: the position value
108 * Gets the slope on @line at the position @pos. Being the
109 * line a straight segment, the vector is always the same, so
110 * @pos is not used. Mathematically speaking, the equation
111 * performed is:
113 * @vector = endpoint(@line) - startpoint(@line).
115 void
116 cpml_line_vector_at(const CpmlPrimitive *line, CpmlVector *vector, double pos)
118 cairo_path_data_t *p1, *p2;
120 p1 = cpml_primitive_get_point(line, 0);
121 p2 = cpml_primitive_get_point(line, -1);
123 vector->x = p2->point.x - p1->point.x;
124 vector->y = p2->point.y - p1->point.y;
128 * cpml_line_near_pos:
129 * @line: the #CpmlPrimitive line data
130 * @pair: the coordinates of the subject point
132 * Returns the pos value of the point on @line nearest to @pair.
133 * The returned value is always between 0 and 1.
135 * The point nearest to @pair is got by finding the its
136 * projection on @line, as this is when the point is closer to
137 * a line primitive.
139 * Return value: the pos value, always between 0 and 1
141 double
142 cpml_line_near_pos(const CpmlPrimitive *line, const CpmlPair *pair)
144 CpmlPair p[4];
145 CpmlVector normal;
146 double pos;
148 cpml_pair_from_cairo(&p[0], cpml_primitive_get_point(line, 0));
149 cpml_pair_from_cairo(&p[1], cpml_primitive_get_point(line, -1));
151 cpml_pair_sub(cpml_pair_copy(&normal, &p[1]), &p[2]);
152 cpml_vector_normal(&normal);
154 cpml_pair_copy(&p[2], pair);
155 cpml_pair_add(cpml_pair_copy(&p[3], pair), &normal);
157 /* Ensure to return 0 if intersection() fails */
158 pos = 0;
159 intersection(p, NULL, &pos);
161 /* Clamp the result to 0..1 */
162 if (pos < 0)
163 pos = 0;
164 else if (pos > 1.)
165 pos = 1.;
167 return pos;
171 * cpml_line_intersection:
172 * @line: the first line
173 * @line2: the second line
174 * @dest: a vector of #CpmlPair
175 * @max: maximum number of intersections to return
176 * (that is, the size of @dest)
178 * Given two lines (@line and @line2), gets their intersection point
179 * and store the result in @dest.
181 * If @max is 0, the function returns 0 immediately without any
182 * further processing. If @line and @line2 are cohincident,
183 * their intersections are not considered.
185 * Return value: the number of intersections found (max 1)
186 * or 0 if the primitives do not intersect
189 cpml_line_intersection(const CpmlPrimitive *line, const CpmlPrimitive *line2,
190 CpmlPair *dest, int max)
192 CpmlPair p[4];
194 if (max == 0)
195 return 0;
197 cpml_pair_from_cairo(&p[0], cpml_primitive_get_point(line, 0));
198 cpml_pair_from_cairo(&p[1], cpml_primitive_get_point(line, -1));
199 cpml_pair_from_cairo(&p[2], cpml_primitive_get_point(line2, 0));
200 cpml_pair_from_cairo(&p[3], cpml_primitive_get_point(line2, -1));
202 return intersection(p, dest, NULL) ? 1 : 0;
206 * cpml_line_offset:
207 * @line: the #CpmlPrimitive line data
208 * @offset: distance for the computed parallel line
210 * Given a line segment specified by the @line primitive data,
211 * computes the parallel line distant @offset from the original one
212 * and returns the result by changing @line.
214 void
215 cpml_line_offset(CpmlPrimitive *line, double offset)
217 cairo_path_data_t *p1, *p2;
218 CpmlVector normal;
220 p1 = cpml_primitive_get_point(line, 0);
221 p2 = cpml_primitive_get_point(line, -1);
223 cpml_line_vector_at(line, &normal, 0.);
224 cpml_vector_normal(&normal);
225 cpml_vector_set_length(&normal, offset);
227 p1->point.x += normal.x;
228 p1->point.y += normal.y;
229 p2->point.x += normal.x;
230 p2->point.y += normal.y;
234 static cairo_bool_t
235 intersection(const CpmlPair *p, CpmlPair *dest, double *get_factor)
237 CpmlVector v[2];
238 double factor;
240 cpml_pair_sub(cpml_pair_copy(&v[0], &p[1]), &p[0]);
241 cpml_pair_sub(cpml_pair_copy(&v[1], &p[3]), &p[2]);
242 factor = v[0].x * v[1].y - v[0].y * v[1].x;
244 /* Check for equal slopes (the lines are parallel) */
245 if (factor == 0)
246 return 0;
248 factor = ((p[0].y - p[2].y) * v[1].x -
249 (p[0].x - p[2].x) * v[1].y) / factor;
251 if (dest != NULL) {
252 dest->x = p[0].x + v[0].x * factor;
253 dest->y = p[0].y + v[0].y * factor;
256 if (get_factor != NULL)
257 *get_factor = factor;
259 return 1;