[build] Compile with the new cpml-segment.[ch] files
[adg.git] / cpml / cpml-segment.c
blob5aa12f5449570c4f268a1f738d3111b01ace2896
1 /* CPML - Cairo Path Manipulation Library
2 * Copyright (C) 2008, 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 #include "cpml-segment.h"
22 #include "cpml-alloca.h"
24 #include <stdio.h>
25 #include <string.h>
27 static cairo_bool_t strip_leadings (CpmlPath *path);
28 static cairo_bool_t path_to_segment (CpmlPath *segment,
29 const CpmlPath *path);
30 static cairo_bool_t path_to_primitive (CpmlPath *primitive,
31 const CpmlPath *path);
33 /**
34 * cpml_path_from_cairo:
35 * @path: the destination #CpmlPath structure
36 * @src: the source cairo_path_t
37 * @cr: a cairo context
39 * Builds a CpmlPath from a cairo_path_t structure. This operations involves
40 * stripping the leading %MOVE_TO primitives and setting the @path->org
41 * coordinates. If not needed, @cr could be %NULL.
43 * The origin is got from the prepending %MOVE_TO coordinates on @src.
44 * If not found, the @cr current point is used. If @cr is %NULL, the
45 * (0,0) fallback pair is used.
47 * @path and @src can be the same object (a #CpmlPath structure).
49 * Return value: 1 on success, 0 on errors
50 **/
51 cairo_bool_t
52 cpml_path_from_cairo(CpmlPath *path, const cairo_path_t *src, cairo_t *cr)
54 CpmlPair org = { 0., 0. };
56 if (cr && cairo_has_current_point(cr))
57 cairo_get_current_point(cr, &org.x, &org.y);
59 return cpml_path_from_cairo_explicit(path, src, &org);
62 /**
63 * cpml_path_from_cairo_explicit:
64 * @path: an allocated #CpmlPath structure
65 * @src: the source cairo_path_t
66 * @org: a specific origin
68 * Similar to cpml_path_from_cairo() but using an explicit origin.
69 * @path and @src can be the same object (a #CpmlPath structure).
71 * @org must be defined. If not needed consider using cpml_path_from_cairo()
72 * with a %NULL cr argument.
74 * Return value: 1 on success, 0 on errors
75 **/
76 cairo_bool_t
77 cpml_path_from_cairo_explicit(CpmlPath *path, const cairo_path_t *src,
78 const CpmlPair *org)
80 if (path == NULL || src == NULL || org == NULL || src->data == NULL)
81 return 0;
83 if (path != (CpmlPath *) src)
84 memcpy(&path->cairo_path, src, sizeof(cairo_path_t));
86 if (strip_leadings(path)) {
87 /* org taken from leadings MOVE_TO */
88 } else if (path->cairo_path.status != CAIRO_STATUS_SUCCESS) {
89 /* Error: probably an empty path provided */
90 return 0;
91 } else if (org) {
92 /* Use the provided org */
93 cpml_pair_copy(&path->org, org);
96 return 1;
99 /**
100 * cpml_path_to_cairo:
101 * @path: a #CpmlPath
102 * @cr: a cairo context
104 * Appends @path to the specified cairo context.
106 void
107 cpml_path_to_cairo(const CpmlPath *path, cairo_t *cr)
109 cairo_move_to(cr, path->org.x, path->org.y);
110 cairo_append_path(cr, (cairo_path_t *) path);
114 * cpml_path_copy:
115 * @path: an allocated #CpmlPath
116 * @src: the source path to copy
118 * Strips the leading CAIRO_PATH_MOVE_TO primitives, updating the CpmlPath
119 * structure accordling. Also the path org is update.
121 * Return value: @path or %NULL on errors
123 CpmlPath *
124 cpml_path_copy(CpmlPath *path, const CpmlPath *src)
126 if (path == NULL || src == NULL)
127 return NULL;
129 return memcpy(path, src, sizeof(CpmlPath));
133 * cpml_path_dump:
134 * @path: an allocated #CpmlPath
136 * Dumps the specified @path to stdout. Useful for debug purposes.
138 * Return value: 1 on success, 0 on errors
140 cairo_bool_t
141 cpml_path_dump(CpmlPath *path)
143 cairo_path_t *cairo_path;
144 cairo_path_data_t *data;
145 int n_data, n_point;
147 if (path == NULL)
148 return 0;
150 printf("Origin in (%lf, %lf)\n", path->org.x, path->org.y);
152 cairo_path = &path->cairo_path;
153 for (n_data = 0; n_data < cairo_path->num_data; ++n_data) {
154 data = cairo_path->data + n_data;
156 switch (data->header.type) {
157 case CAIRO_PATH_MOVE_TO:
158 printf("Move to ");
159 break;
160 case CAIRO_PATH_LINE_TO:
161 printf("Line to ");
162 break;
163 case CAIRO_PATH_CURVE_TO:
164 printf("Curve to ");
165 break;
166 case CAIRO_PATH_CLOSE_PATH:
167 printf("Path close");
168 break;
169 default:
170 printf("Unknown entity (%d)", data->header.type);
171 break;
174 for (n_point = 1; n_point < data->header.length; ++n_point)
175 printf("(%lf, %lf) ", data[n_point].point.x,
176 data[n_point].point.y);
178 n_data += n_point - 1;
179 printf("\n");
182 return 1;
186 * cpml_segment_from_path:
187 * @segment: an allocated #CpmlPath struct
188 * @path: the source path
189 * @index: the segment to retrieve (starting from 1);
190 * %CPML_FIRST or %CPML_LAST can be used
192 * Gets a specific segment from a path.
194 * Return value: 1 if a valid segment was found, 0 on errors
196 cairo_bool_t
197 cpml_segment_from_path(CpmlPath *segment, const CpmlPath *path, int index)
199 CpmlPath residue, result;
200 int i;
202 if (!cpml_path_copy(&residue, path))
203 return 0;
205 i = 0;
207 do {
208 if (!path_to_segment(&result, &residue))
209 return index == CPML_LAST && i > 0;
211 residue.cairo_path.data += result.cairo_path.num_data;
212 residue.cairo_path.num_data -= result.cairo_path.num_data;
213 ++i;
215 if (index == CPML_LAST) {
216 cpml_path_copy(segment, &result);
217 continue;
219 } while (i < index);
221 cpml_path_copy(segment, &result);
222 return 1;
226 * cpml_segment_reverse:
227 * @segment: a #CpmlPath
228 * @src: the source segment
230 * Reverses @src and stores the result in @segment. @src and @segment
231 * can be the same structure.
233 * Return value: 1 on success, 0 on errors
235 cairo_bool_t
236 cpml_segment_reverse(CpmlPath *segment, const CpmlPath *src)
238 cairo_path_data_t *data, *dst_data;
239 size_t data_size;
240 CpmlPair end;
241 int num_data, n_data;
242 int num_points, n_point;
243 const cairo_path_data_t *src_data;
245 num_data = src->cairo_path.num_data;
246 data_size = sizeof(cairo_path_data_t) * num_data;
247 data = cpml_alloca(data_size);
248 cpml_pair_copy(&end, &src->org);
250 for (n_data = 0; n_data < num_data; ++n_data) {
251 src_data = src->cairo_path.data + n_data;
252 num_points = src_data->header.length;
254 dst_data = data + num_data - n_data - num_points;
255 dst_data->header.type = src_data->header.type;
256 dst_data->header.length = num_points;
258 for (n_point = 1; n_point < num_points; ++n_point) {
259 dst_data[num_points - n_point].point.x = end.x;
260 dst_data[num_points - n_point].point.y = end.y;
261 end.x = src_data[n_point].point.x;
262 end.y = src_data[n_point].point.y;
265 n_data += n_point - 1;
268 cpml_pair_copy(&segment->org, &end);
269 memcpy(segment->cairo_path.data, data, data_size);
271 return 1;
275 * cpml_primitive_from_path:
276 * @primitive: an allocated #CpmlPath struct
277 * @path: the source path
278 * @index: the primitive to retrieve (starting from 1);
279 * %CPML_FIRST or %CPML_LAST can be used
281 * Gets a specific primitive from a path.
283 * Return value: 1 if a valid primitive was found, 0 on errors
285 cairo_bool_t
286 cpml_primitive_from_path(CpmlPath *primitive, const CpmlPath *path, int index)
288 CpmlPath residue, result;
289 int i;
291 if (!cpml_path_copy(&residue, path))
292 return 0;
294 i = 0;
296 do {
297 if (!path_to_primitive(&result, &residue))
298 return index == CPML_LAST && i > 0;
300 residue.cairo_path.data += result.cairo_path.num_data;
301 residue.cairo_path.num_data -= result.cairo_path.num_data;
302 ++i;
304 if (index == CPML_LAST) {
305 cpml_path_copy(primitive, &result);
306 continue;
308 } while (i < index);
310 cpml_path_copy(primitive, &result);
311 return 1;
315 * cpml_primitive_get_pair:
316 * @primitive: the source primitive
317 * @pair: the allocated CpmlPair destination
318 * @index: index of the pair to retrieve, starting from 1
320 * Shortcut to get a pair from a primitive.
322 * Return value: 1 on success, 0 on errors
324 cairo_bool_t
325 cpml_primitive_get_pair(const CpmlPath *primitive, CpmlPair *pair, int index)
327 cairo_path_data_t *data = primitive->cairo_path.data;
329 if (index == 0 || index > data[0].header.length)
330 return 0;
332 pair->x = data[index].point.x;
333 pair->y = data[index].point.y;
334 return 1;
338 * cpml_primitive_set_pair:
339 * @primitive: an allocated CpmlPath primitive
340 * @pair: the source pair
341 * @index: index of the pair to change, starting from 1
343 * Shortcut to set a pair on a primitive.
345 * Return value: 1 on success, 0 on errors
347 cairo_bool_t
348 cpml_primitive_set_pair(CpmlPath *primitive, const CpmlPair *pair, int index)
350 cairo_path_data_t *data = primitive->cairo_path.data;
352 if (index == 0 || index > data[0].header.length)
353 return 0;
355 data[index].point.x = pair->x;
356 data[index].point.y = pair->y;
357 return 1;
361 * cpml_primitive_get_point:
362 * @primitive: the source primitive
363 * @point: the allocated CpmlPair destination
364 * @pos: the position factor, being 0 the starting and 1 the ending point
366 * Gets a point lying on @primitive at a specific percentual position.
368 * Return value: 1 on success, 0 on errors
370 cairo_bool_t
371 cpml_primitive_get_point(const CpmlPath *primitive, CpmlPair *point, double pos)
373 int type = primitive->cairo_path.data[0].header.type;
375 if (type != CAIRO_PATH_CLOSE_PATH && type != CAIRO_PATH_LINE_TO &&
376 type != CAIRO_PATH_CURVE_TO)
377 return 0;
379 /* Common cases */
380 if (type == CAIRO_PATH_CLOSE_PATH || pos == 0.) {
381 return cpml_pair_copy(point, &primitive->org);
382 } else if (pos == 1.0) {
383 int n = type == CAIRO_PATH_LINE_TO ? 1 : 3;
384 return cpml_primitive_get_pair(primitive, point, n);
387 /* TODO */
388 return 0;
392 * cpml_primitive_reverse:
393 * @primitive: an allocated #CpmlPath struct
395 * Reverses a primitive.
397 * Return value: 1 on success, 0 on errors
399 cairo_bool_t
400 cpml_primitive_reverse(CpmlPath *primitive)
402 CpmlPair tmp;
404 switch (primitive->cairo_path.data[0].header.type) {
405 case CAIRO_PATH_LINE_TO:
406 cpml_pair_copy(&tmp, &primitive->org);
407 cpml_primitive_get_pair(primitive, &primitive->org, 1);
408 cpml_primitive_set_pair(primitive, &tmp, 1);
409 break;
410 case CAIRO_PATH_CURVE_TO:
411 cpml_pair_copy(&tmp, &primitive->org);
412 cpml_primitive_get_pair(primitive, &primitive->org, 3);
413 cpml_primitive_set_pair(primitive, &tmp, 3);
415 cpml_primitive_get_pair(primitive, &tmp, 2);
416 primitive->cairo_path.data[2].point.x =
417 primitive->cairo_path.data[3].point.x;
418 primitive->cairo_path.data[2].point.y =
419 primitive->cairo_path.data[3].point.y;
420 cpml_primitive_set_pair(primitive, &tmp, 3);
421 break;
422 default:
423 return 0;
426 return 1;
430 * strip_leadings:
431 * @path: a #CpmlPath
433 * Strips the leading CAIRO_PATH_MOVE_TO primitives, updating the CpmlPath
434 * structure accordling. Also the path org is update.
436 * Return value: 1 on success, 0 on no leading MOVE_TOs or on errors
437 * (check for path->cairo_path.status == CAIRO_STATUS_SUCCESS)
439 static cairo_bool_t
440 strip_leadings(CpmlPath *path)
442 if (path->cairo_path.data[0].header.type != CAIRO_PATH_MOVE_TO)
443 return 0;
445 do {
446 ++path->cairo_path.data;
447 path->org.x = path->cairo_path.data->point.x;
448 path->org.y = path->cairo_path.data->point.y;
449 ++path->cairo_path.data;
450 path->cairo_path.num_data -= 2;
451 if (path->cairo_path.num_data <= 0) {
452 path->cairo_path.status = CAIRO_STATUS_INVALID_PATH_DATA;
453 return 0;
455 } while (path->cairo_path.data->header.type == CAIRO_PATH_MOVE_TO);
457 return 1;
461 * path_to_segment:
462 * @segment: an allocated #CpmlPath struct
463 * @path: the source path
465 * Converts a path to a segment. @segment and @path can be the same struct.
467 * Return value: 1 if a valid segment is found, 0 on errors
469 static cairo_bool_t
470 path_to_segment(CpmlPath *segment, const CpmlPath *path)
472 cairo_path_data_t *path_data;
473 int i;
475 if (segment != path)
476 cpml_path_copy(segment, path);
478 if (!strip_leadings(segment) &&
479 segment->cairo_path.status != CAIRO_STATUS_SUCCESS)
480 return 0;
482 path_data = segment->cairo_path.data;
483 i = 0;
485 do {
486 if (path_data->header.type == CAIRO_PATH_MOVE_TO) {
487 --i;
488 break;
489 } else if (path_data->header.type == CAIRO_PATH_CLOSE_PATH) {
490 break;
492 i += path_data->header.length;
493 path_data += path_data->header.length;
494 } while (i < segment->cairo_path.num_data);
496 segment->cairo_path.num_data = i;
497 return 1;
501 * path_to_primitive:
502 * @primitive: an allocated #CpmlPath struct
503 * @path: the source path
505 * Converts a path to a primitive. @primitive and @path can be the same struct.
507 * Return value: 1 if a valid primitive is found, 0 on errors
509 static cairo_bool_t
510 path_to_primitive(CpmlPath *primitive, const CpmlPath *path)
512 cairo_path_data_t *path_data;
514 if (primitive != path)
515 cpml_path_copy(primitive, path);
517 if (!strip_leadings(primitive) &&
518 primitive->cairo_path.status != CAIRO_STATUS_SUCCESS)
519 return 0;
521 primitive->cairo_path.num_data = 1;
522 return 1;