[AdgTableStyle] Using different line style for frame and grid
[adg.git] / src / cpml / cpml-line.c
blob5c23e59db8119dd49e2634fa5b9b6dd0fa4f3f88
1 /* CPML - Cairo Path Manipulation Library
2 * Copyright (C) 2008,2009,2010 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 #CPML_LINE #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 straight line.
31 **/
33 /**
34 * CPML_LINE:
36 * The type code used to identify "line-to" primitives.
37 * It is equivalent to the %CAIRO_PATH_LINE_TO cairo constant.
38 **/
41 /**
42 * SECTION:cpml-close
43 * @Section_Id:CpmlClose
44 * @title: CpmlClose
45 * @short_description: Straigth line used to close cyclic segments
47 * The following functions manipulate #CPML_CLOSE #CpmlPrimitive.
48 * No validation is made on the input so use the following methods
49 * only when you are sure the <varname>primitive</varname> argument
50 * is effectively a close path.
52 * This primitive management is almost identical to straight lines,
53 * but taking properly start and end points.
54 **/
56 /**
57 * CPML_CLOSE:
59 * The type code used to identify "close" primitives.
60 * It is equivalent to the %CAIRO_PATH_CLOSE_PATH cairo constant.
61 **/
64 #include "cpml-internal.h"
65 #include "cpml-extents.h"
66 #include "cpml-segment.h"
67 #include "cpml-primitive.h"
68 #include "cpml-primitive-private.h"
69 #include "cpml-line.h"
72 static double get_length (const CpmlPrimitive *line);
73 static void put_extents (const CpmlPrimitive *line,
74 CpmlExtents *extents);
75 static void put_pair_at (const CpmlPrimitive *line,
76 double pos,
77 CpmlPair *pair);
78 static void put_vector_at (const CpmlPrimitive *line,
79 double pos,
80 CpmlVector *vector);
81 static double get_closest_pos (const CpmlPrimitive *line,
82 const CpmlPair *pair);
83 static size_t put_intersections (const CpmlPrimitive *line,
84 const CpmlPrimitive *primitive,
85 size_t n_dest,
86 CpmlPair *dest);
87 static void offset (CpmlPrimitive *line,
88 double offset);
89 static cairo_bool_t
90 intersection (const CpmlPair *p1_4,
91 CpmlPair *dest,
92 double *get_factor);
95 const _CpmlPrimitiveClass *
96 _cpml_line_get_class(void)
98 static _CpmlPrimitiveClass *p_class = NULL;
100 if (p_class == NULL) {
101 static _CpmlPrimitiveClass class_data = {
102 "line to", 2,
103 get_length,
104 put_extents,
105 put_pair_at,
106 put_vector_at,
107 get_closest_pos,
108 put_intersections,
109 offset,
110 NULL
112 p_class = &class_data;
115 return p_class;
118 const _CpmlPrimitiveClass *
119 _cpml_close_get_class(void)
121 static _CpmlPrimitiveClass *p_class = NULL;
123 if (p_class == NULL) {
124 static _CpmlPrimitiveClass class_data = {
125 "close", 2,
126 get_length,
127 put_extents,
128 put_pair_at,
129 put_vector_at,
130 get_closest_pos,
131 put_intersections,
132 offset,
133 NULL
135 p_class = &class_data;
138 return p_class;
142 static double
143 get_length(const CpmlPrimitive *line)
145 CpmlPair p1, p2;
147 cpml_pair_from_cairo(&p1, cpml_primitive_get_point(line, 0));
148 cpml_pair_from_cairo(&p2, cpml_primitive_get_point(line, -1));
150 return cpml_pair_distance(&p1, &p2);
153 static void
154 put_extents(const CpmlPrimitive *line, CpmlExtents *extents)
156 CpmlPair p1, p2;
158 extents->is_defined = 0;
160 cpml_pair_from_cairo(&p1, cpml_primitive_get_point(line, 0));
161 cpml_pair_from_cairo(&p2, cpml_primitive_get_point(line, -1));
163 cpml_extents_pair_add(extents, &p1);
164 cpml_extents_pair_add(extents, &p2);
167 static void
168 put_pair_at(const CpmlPrimitive *line, double pos, CpmlPair *pair)
170 cairo_path_data_t *p1, *p2;
172 p1 = cpml_primitive_get_point(line, 0);
173 p2 = cpml_primitive_get_point(line, -1);
175 pair->x = p1->point.x + (p2->point.x - p1->point.x) * pos;
176 pair->y = p1->point.y + (p2->point.y - p1->point.y) * pos;
179 static void
180 put_vector_at(const CpmlPrimitive *line, double pos, CpmlVector *vector)
182 cairo_path_data_t *p1, *p2;
184 p1 = cpml_primitive_get_point(line, 0);
185 p2 = cpml_primitive_get_point(line, -1);
187 vector->x = p2->point.x - p1->point.x;
188 vector->y = p2->point.y - p1->point.y;
191 static double
192 get_closest_pos(const CpmlPrimitive *line, const CpmlPair *pair)
194 CpmlPair p1_4[4];
195 CpmlVector normal;
196 double pos;
198 cpml_pair_from_cairo(&p1_4[0], cpml_primitive_get_point(line, 0));
199 cpml_pair_from_cairo(&p1_4[1], cpml_primitive_get_point(line, -1));
201 normal.x = p1_4[1].x - p1_4[2].x;
202 normal.y = p1_4[1].y - p1_4[2].y;
203 cpml_vector_normal(&normal);
205 cpml_pair_copy(&p1_4[2], pair);
207 p1_4[3].x = pair->x + normal.x;
208 p1_4[3].y = pair->y + normal.y;
210 /* Ensure to return 0 if intersection() fails */
211 pos = 0;
212 intersection(p1_4, NULL, &pos);
214 /* Clamp the result to 0..1 */
215 if (pos < 0)
216 pos = 0;
217 else if (pos > 1.)
218 pos = 1.;
220 return pos;
223 static size_t
224 put_intersections(const CpmlPrimitive *line, const CpmlPrimitive *primitive,
225 size_t n_dest, CpmlPair *dest)
227 CpmlPair p1_4[4];
229 if (n_dest == 0)
230 return 0;
232 cpml_pair_from_cairo(&p1_4[0], cpml_primitive_get_point(line, 0));
233 cpml_pair_from_cairo(&p1_4[1], cpml_primitive_get_point(line, -1));
234 cpml_pair_from_cairo(&p1_4[2], cpml_primitive_get_point(primitive, 0));
235 cpml_pair_from_cairo(&p1_4[3], cpml_primitive_get_point(primitive, -1));
237 return intersection(p1_4, dest, NULL) ? 1 : 0;
240 static void
241 offset(CpmlPrimitive *line, double offset)
243 cairo_path_data_t *p1, *p2;
244 CpmlVector normal;
246 p1 = cpml_primitive_get_point(line, 0);
247 p2 = cpml_primitive_get_point(line, -1);
249 put_vector_at(line, 0, &normal);
250 cpml_vector_normal(&normal);
251 cpml_vector_set_length(&normal, offset);
253 p1->point.x += normal.x;
254 p1->point.y += normal.y;
255 p2->point.x += normal.x;
256 p2->point.y += normal.y;
259 static cairo_bool_t
260 intersection(const CpmlPair *p1_4, CpmlPair *dest, double *get_factor)
262 CpmlVector v[2];
263 double factor;
265 v[0].x = p1_4[1].x - p1_4[0].x;
266 v[0].y = p1_4[1].y - p1_4[0].y;
267 v[1].x = p1_4[3].x - p1_4[2].x;
268 v[1].y = p1_4[3].y - p1_4[2].y;
269 factor = v[0].x * v[1].y - v[0].y * v[1].x;
271 /* Check for equal slopes (the lines are parallel) */
272 if (factor == 0)
273 return 0;
275 factor = ((p1_4[0].y - p1_4[2].y) * v[1].x -
276 (p1_4[0].x - p1_4[2].x) * v[1].y) / factor;
278 if (dest != NULL) {
279 dest->x = p1_4[0].x + v[0].x * factor;
280 dest->y = p1_4[0].y + v[0].y * factor;
283 if (get_factor != NULL)
284 *get_factor = factor;
286 return 1;