[AdgArrowStyle] Updated and cleaned sources
[adg.git] / cpml / cpml-segment.c
blobc52307d4d340de990bf96484533fbf2e29407646
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 normalize_segment (CpmlSegment *segment);
30 /**
31 * cpml_segment_init:
32 * @segment: a #CpmlSegment
33 * @src: the source cairo_path_t
35 * Builds a CpmlSegment from a cairo_path_t structure. This operation
36 * involves stripping the leading %MOVE_TO primitives and setting the
37 * internal segment structure accordling. A pointer to the source
38 * path segment is kept.
40 * Return value: 1 on success, 0 on errors
41 **/
42 cairo_bool_t
43 cpml_segment_init(CpmlSegment *segment, cairo_path_t *src)
45 /* The cairo path should be defined and in perfect state */
46 if (src == NULL || src->num_data == 0 ||
47 src->status != CAIRO_STATUS_SUCCESS)
48 return 0;
50 segment->original = src;
51 memcpy(&segment->path, src, sizeof(cairo_path_t));
53 return normalize_segment(segment);
56 /**
57 * cpml_segment_copy:
58 * @segment: a #CpmlSegment
59 * @src: the source segment to copy
61 * Makes a shallow copy of @src into @segment.
63 * Return value: @segment or %NULL on errors
64 **/
65 CpmlSegment *
66 cpml_segment_copy(CpmlSegment *segment, const CpmlSegment *src)
68 if (segment == NULL || src == NULL)
69 return NULL;
71 return memcpy(segment, src, sizeof(CpmlSegment));
74 /**
75 * cpml_segment_dump:
76 * @segment: a #CpmlSegment
78 * Dumps the specified @segment to stdout. Useful for debugging purposes.
79 **/
80 void
81 cpml_segment_dump(const CpmlSegment *segment)
83 const cairo_path_t *path;
84 cairo_path_data_t *data;
85 int n_data, n_point;
87 if (segment == NULL) {
88 printf("Trying to dump a NULL segment!\n");
89 return;
92 path = &segment->path;
93 for (n_data = 0; n_data < path->num_data; ++n_data) {
94 data = path->data + n_data;
96 switch (data->header.type) {
97 case CAIRO_PATH_MOVE_TO:
98 printf("Move to ");
99 break;
100 case CAIRO_PATH_LINE_TO:
101 printf("Line to ");
102 break;
103 case CAIRO_PATH_CURVE_TO:
104 printf("Curve to ");
105 break;
106 case CAIRO_PATH_CLOSE_PATH:
107 printf("Path close");
108 break;
109 default:
110 printf("Unknown entity (%d)", data->header.type);
111 break;
114 for (n_point = 1; n_point < data->header.length; ++n_point)
115 printf("(%lf, %lf) ", data[n_point].point.x,
116 data[n_point].point.y);
118 n_data += n_point - 1;
119 printf("\n");
124 * cpml_segment_reset:
125 * @segment: a #CpmlSegment
127 * Modifies @segment to point to the first segment of the original path.
129 void
130 cpml_segment_reset(CpmlSegment *segment)
132 memcpy(&segment->path, segment->original, sizeof(cairo_path_t));
133 normalize_segment(segment);
137 * cpml_segment_next:
138 * @segment: a #CpmlSegment
140 * Modifies @segment to point to the next segment of the original path.
142 * Return value: 1 on success, 0 if no next segment found or errors
144 cairo_bool_t
145 cpml_segment_next(CpmlSegment *segment)
147 int num_data = segment->path.num_data;
148 int offset = segment->path.data - segment->original->data;
150 segment->path.num_data = segment->original->num_data - num_data - offset;
151 segment->path.data += num_data;
153 return normalize_segment(segment);
157 * cpml_segment_reverse:
158 * @segment: a #CpmlSegment
160 * Reverses @segment in-place. The resulting rendering will be the same,
161 * but with the primitives generated in reverse order.
163 void
164 cpml_segment_reverse(CpmlSegment *segment)
166 cairo_path_data_t *data, *dst_data;
167 size_t data_size;
168 double end_x, end_y;
169 int num_data, n_data;
170 int num_points, n_point;
171 const cairo_path_data_t *src_data;
173 num_data = segment->path.num_data;
174 data_size = sizeof(cairo_path_data_t) * num_data;
175 data = cpml_alloca(data_size);
176 end_x = segment->path.data[1].point.x;
177 end_y = segment->path.data[1].point.y;
179 for (n_data = 2; n_data < num_data; ++n_data) {
180 src_data = segment->path.data + n_data;
181 num_points = src_data->header.length;
183 dst_data = data + num_data - n_data - num_points + 2;
184 dst_data->header.type = src_data->header.type;
185 dst_data->header.length = num_points;
187 for (n_point = 1; n_point < num_points; ++n_point) {
188 dst_data[num_points - n_point].point.x = end_x;
189 dst_data[num_points - n_point].point.y = end_y;
190 end_x = src_data[n_point].point.x;
191 end_y = src_data[n_point].point.y;
194 n_data += n_point - 1;
197 data[0].header.type = CAIRO_PATH_MOVE_TO;
198 data[0].header.length = 2;
199 data[1].point.x = end_x;
200 data[1].point.y = end_y;
201 memcpy(segment->path.data, data, data_size);
205 * cpml_segment_transform:
206 * @segment: a #CpmlSegment
207 * @matrix: the matrix to be applied
209 * Applies @matrix on all the points of @segment.
211 void
212 cpml_segment_transform(CpmlSegment *segment, const cairo_matrix_t *matrix)
214 cairo_path_data_t *data;
215 int n_data, num_data;
216 int n_point, num_points;
218 data = segment->path.data;
219 num_data = segment->path.num_data;
221 for (n_data = 0; n_data < num_data; n_data += num_points) {
222 num_points = data->header.length;
223 ++data;
224 for (n_point = 1; n_point < num_points; ++n_point) {
225 cairo_matrix_transform_point(matrix, &data->point.x, &data->point.y);
226 ++data;
232 * normalize_segment:
233 * @segment: a #CpmlSegment
235 * Strips the leading CAIRO_PATH_MOVE_TO primitives, updating the CpmlSegment
236 * structure accordling. One, and only once, MOVE_TO primitive is left.
238 * Return value: 1 on success, 0 on no leading MOVE_TOs or on errors
240 static cairo_bool_t
241 normalize_segment(CpmlSegment *segment)
243 cairo_path_data_t *data;
245 if (segment == NULL || segment->path.num_data <= 0)
246 return 0;
248 data = segment->path.data;
249 if (data->header.type != CAIRO_PATH_MOVE_TO) {
250 segment->path.status = CAIRO_STATUS_INVALID_PATH_DATA;
251 return 0;
254 while (segment->path.num_data >= 0) {
255 data += 2;
256 if (data->header.type != CAIRO_PATH_MOVE_TO)
257 return 1;
259 segment->path.data = data;
260 segment->path.num_data -= 2;
263 return 0;