[AdgArrowStyle] Hidden private struct
[adg.git] / cpml / cpml-line.c
blob62b71255760635c067e8399770dc73b80e9b44e2
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.
20 /**
21 * SECTION:line
22 * @title: Straight lines
23 * @short_description: Line primitive management
25 * The following functions manipulate %CAIRO_PATH_LINE_TO #CpmlPrimitive.
26 * No check is made on the primitive struct, so be sure the
27 * <structname>CpmlPrimitive</structname> is effectively a line before
28 * calling these APIs.
29 **/
31 #include "cpml-line.h"
32 #include "cpml-pair.h"
34 #include <stdlib.h>
37 static cairo_bool_t intersection (const CpmlPair *p,
38 CpmlPair *dest,
39 double *get_factor);
42 /**
43 * cpml_line_type_get_npoints:
45 * Returns the number of point needed to properly specify a line primitive.
47 * Return value: 2
48 **/
49 int
50 cpml_line_type_get_npoints(void)
52 return 2;
55 /**
56 * cpml_line_length:
57 * @line: the #CpmlPrimitive line data
59 * Given the @line primitive, returns the distance between its
60 * start and end points.
62 * Return value: the requested distance, that is the @line length
63 **/
64 double
65 cpml_line_length(const CpmlPrimitive *line)
67 CpmlPair p1, p2;
69 cpml_pair_from_cairo(&p1, cpml_primitive_get_point(line, 0));
70 cpml_pair_from_cairo(&p2, cpml_primitive_get_point(line, -1));
72 return cpml_pair_distance(&p1, &p2);
75 /**
76 * cpml_line_pair_at:
77 * @line: the #CpmlPrimitive line data
78 * @pair: the destination pair
79 * @pos: the position value
81 * Given the @line line, finds the coordinates at position @pos
82 * (where 0 is the start and 1 is the end) and stores the result
83 * in @pair.
85 * @pos can be less than 0 or greater than 1, in which case the
86 * coordinates are interpolated.
87 **/
88 void
89 cpml_line_pair_at(const CpmlPrimitive *line, CpmlPair *pair, double pos)
91 cairo_path_data_t *p1, *p2;
93 p1 = cpml_primitive_get_point(line, 0);
94 p2 = cpml_primitive_get_point(line, -1);
96 pair->x = p1->point.x + (p2->point.x - p1->point.x) * pos;
97 pair->y = p1->point.y + (p2->point.y - p1->point.y) * pos;
101 * cpml_line_vector_at:
102 * @line: the #CpmlPrimitive line data
103 * @vector: the destination vector
104 * @pos: the position value
106 * Gets the slope on @line at the position @pos. Being the
107 * line a straight segment, the vector is always the same, so
108 * @pos is not used. Mathematically speaking, the equation
109 * performed is:
111 * @vector = endpoint(@line) - startpoint(@line).
113 void
114 cpml_line_vector_at(const CpmlPrimitive *line, CpmlVector *vector, double pos)
116 cairo_path_data_t *p1, *p2;
118 p1 = cpml_primitive_get_point(line, 0);
119 p2 = cpml_primitive_get_point(line, -1);
121 vector->x = p2->point.x - p1->point.x;
122 vector->y = p2->point.y - p1->point.y;
126 * cpml_line_near_pos:
127 * @line: the #CpmlPrimitive line data
128 * @pair: the coordinates of the subject point
130 * Returns the pos value of the point on @line nearest to @pair.
131 * The returned value is always between 0 and 1.
133 * The point nearest to @pair is got by finding the its
134 * projection on @line, as this is when the point is closer to
135 * a line primitive.
137 * Return value: the pos value, always between 0 and 1
139 double
140 cpml_line_near_pos(const CpmlPrimitive *line, const CpmlPair *pair)
142 CpmlPair p[4];
143 CpmlVector normal;
144 double pos;
146 cpml_pair_from_cairo(&p[0], cpml_primitive_get_point(line, 0));
147 cpml_pair_from_cairo(&p[1], cpml_primitive_get_point(line, -1));
149 cpml_pair_sub(cpml_pair_copy(&normal, &p[1]), &p[2]);
150 cpml_vector_normal(&normal);
152 cpml_pair_copy(&p[2], pair);
153 cpml_pair_add(cpml_pair_copy(&p[3], pair), &normal);
155 /* Ensure to return 0 if intersection() fails */
156 pos = 0;
157 intersection(p, NULL, &pos);
159 /* Clamp the result to 0..1 */
160 if (pos < 0)
161 pos = 0;
162 else if (pos > 1.)
163 pos = 1.;
165 return pos;
169 * cpml_line_intersection:
170 * @line: the first line
171 * @line2: the second line
172 * @dest: a vector of #CpmlPair
173 * @max: maximum number of intersections to return
174 * (that is, the size of @dest)
176 * Given two lines (@line and @line2), gets their intersection point
177 * and store the result in @dest.
179 * If @max is 0, the function returns 0 immediately without any
180 * further processing. If @line and @line2 are cohincident,
181 * their intersections are not considered.
183 * Return value: the number of intersections found (max 1)
184 * or 0 if the primitives do not intersect
187 cpml_line_intersection(const CpmlPrimitive *line, const CpmlPrimitive *line2,
188 CpmlPair *dest, int max)
190 CpmlPair p[4];
192 if (max == 0)
193 return 0;
195 cpml_pair_from_cairo(&p[0], cpml_primitive_get_point(line, 0));
196 cpml_pair_from_cairo(&p[1], cpml_primitive_get_point(line, -1));
197 cpml_pair_from_cairo(&p[2], cpml_primitive_get_point(line2, 0));
198 cpml_pair_from_cairo(&p[3], cpml_primitive_get_point(line2, -1));
200 return intersection(p, dest, NULL) ? 1 : 0;
204 * cpml_line_offset:
205 * @line: the #CpmlPrimitive line data
206 * @offset: distance for the computed parallel line
208 * Given a line segment specified by the @line primitive data,
209 * computes the parallel line distant @offset from the original one
210 * and returns the result by changing @line.
212 void
213 cpml_line_offset(CpmlPrimitive *line, double offset)
215 cairo_path_data_t *p1, *p2;
216 CpmlVector normal;
218 p1 = cpml_primitive_get_point(line, 0);
219 p2 = cpml_primitive_get_point(line, -1);
221 cpml_line_vector_at(line, &normal, 0.);
222 cpml_vector_normal(&normal);
223 cpml_vector_set_length(&normal, offset);
225 p1->point.x += normal.x;
226 p1->point.y += normal.y;
227 p2->point.x += normal.x;
228 p2->point.y += normal.y;
232 static cairo_bool_t
233 intersection(const CpmlPair *p, CpmlPair *dest, double *get_factor)
235 CpmlVector v[2];
236 double factor;
238 cpml_pair_sub(cpml_pair_copy(&v[0], &p[1]), &p[0]);
239 cpml_pair_sub(cpml_pair_copy(&v[1], &p[3]), &p[2]);
240 factor = v[0].x * v[1].y - v[0].y * v[1].x;
242 /* Check for equal slopes (the lines are parallel) */
243 if (factor == 0)
244 return 0;
246 factor = ((p[0].y - p[2].y) * v[1].x -
247 (p[0].x - p[2].x) * v[1].y) / factor;
249 if (dest != NULL) {
250 dest->x = p[0].x + v[0].x * factor;
251 dest->y = p[0].y + v[0].y * factor;
254 if (get_factor != NULL)
255 *get_factor = factor;
257 return 1;