作図ソフト dia の改良版
Révision | 3ec25448ae14f38c59b2ec504d45f02836b74ab9 (tree) |
---|---|
l'heure | 2014-04-26 22:31:46 |
Auteur | Hans Breuer <hans@breu...> |
Commiter | Hans Breuer |
[substitute] improve Convert to Path
'Convert to Path' based on the DiaPathRenderer was not producing the
desired effect for some standard objects. Filled objects were not
necessarily filled anymore after conversion. Even simple objects were
producing a group of objects rather than a single path object. Now:
Also included a test/demo file convert-to-path.dia.
@@ -27,6 +27,11 @@ | ||
27 | 27 | |
28 | 28 | #include "attributes.h" /* attributes_get_foreground() */ |
29 | 29 | |
30 | +typedef enum { | |
31 | + PATH_STROKE = (1<<0), | |
32 | + PATH_FILL = (1<<1) | |
33 | +} PathLastOp; | |
34 | + | |
30 | 35 | /*! |
31 | 36 | * \brief Renderer which turns everything into a path (or a list thereof) |
32 | 37 | * |
@@ -44,6 +49,8 @@ struct _DiaPathRenderer | ||
44 | 49 | |
45 | 50 | Color stroke; |
46 | 51 | Color fill; |
52 | + | |
53 | + PathLastOp last_op; | |
47 | 54 | }; |
48 | 55 | |
49 | 56 | struct _DiaPathRendererClass |
@@ -94,7 +101,7 @@ dia_path_renderer_finalize (GObject *object) | ||
94 | 101 | * @param self explicit this pointer |
95 | 102 | * @param stroke line color or NULL |
96 | 103 | * @param fill fill color or NULL |
97 | - * \private \memeberof _DiaPathRenderer | |
104 | + * \private \memberof _DiaPathRenderer | |
98 | 105 | */ |
99 | 106 | static GArray * |
100 | 107 | _get_current_path (DiaPathRenderer *self, |
@@ -113,6 +120,11 @@ _get_current_path (DiaPathRenderer *self, | ||
113 | 120 | memcpy (&self->fill, fill, sizeof(*fill)); |
114 | 121 | new_path = TRUE; |
115 | 122 | } |
123 | + /* also create a new path if the last op was a fill and we now stroke */ | |
124 | + if ( stroke && self->last_op == PATH_FILL | |
125 | + || fill && self->last_op == PATH_STROKE) | |
126 | + new_path = TRUE; | |
127 | + self->last_op = stroke ? PATH_STROKE : PATH_FILL; | |
116 | 128 | |
117 | 129 | if (!self->pathes || new_path) { |
118 | 130 | if (!self->pathes) |
@@ -123,6 +135,40 @@ _get_current_path (DiaPathRenderer *self, | ||
123 | 135 | return path; |
124 | 136 | } |
125 | 137 | /*! |
138 | + * \brief Optimize away potential duplicated path | |
139 | + * Dia's object rendering often consists of identical consecutive fill and stroke | |
140 | + * operations. This function check if two identical pathes are at the end of our | |
141 | + * list and just removes the second one. | |
142 | + * \private \memberof _DiaPathRenderer | |
143 | + */ | |
144 | +static void | |
145 | +_remove_duplicated_path (DiaPathRenderer *self) | |
146 | +{ | |
147 | + if (self->pathes && self->pathes->len >= 2) { | |
148 | + GArray *p1 = g_ptr_array_index (self->pathes, self->pathes->len - 2); | |
149 | + GArray *p2 = g_ptr_array_index (self->pathes, self->pathes->len - 1); | |
150 | + if (p1->len == p2->len) { | |
151 | + gboolean same = TRUE; | |
152 | + guint i; | |
153 | + for (i = 0; i < p1->len; ++i) { | |
154 | + const BezPoint *bp1 = &g_array_index (p1, BezPoint, i); | |
155 | + const BezPoint *bp2 = &g_array_index (p2, BezPoint, i); | |
156 | + | |
157 | + same &= (bp1->type == bp2->type); | |
158 | + same &= (memcmp (&bp1->p1, &bp2->p1, sizeof(Point)) == 0); | |
159 | + if (bp1->type == BEZ_CURVE_TO) { | |
160 | + same &= (memcmp (&bp1->p2, &bp2->p2, sizeof(Point)) == 0); | |
161 | + same &= (memcmp (&bp1->p3, &bp2->p3, sizeof(Point)) == 0); | |
162 | + } | |
163 | + } | |
164 | + if (same) { | |
165 | + g_array_free (p2, TRUE); | |
166 | + g_ptr_array_set_size (self->pathes, self->pathes->len - 1); | |
167 | + } | |
168 | + } | |
169 | + } | |
170 | +} | |
171 | +/*! | |
126 | 172 | * \brief Starting a new rendering run |
127 | 173 | * Could be used to clean the path leftovers from a previous run. |
128 | 174 | * Typical export renderers flush here. |
@@ -188,7 +234,7 @@ _path_append (GArray *points, const Point *pt) | ||
188 | 234 | const BezPoint *prev = (points->len > 0) ? &g_array_index (points, BezPoint, points->len - 1) : NULL; |
189 | 235 | const Point *last = prev ? (prev->type == BEZ_CURVE_TO ? &prev->p3 : &prev->p1) : NULL; |
190 | 236 | |
191 | - if (!last || last->x != pt->x || last->y != pt->y) { | |
237 | + if (!last || distance_point_point(last, pt) > 0.001) { | |
192 | 238 | BezPoint bp; |
193 | 239 | bp.type = BEZ_MOVE_TO; |
194 | 240 | bp.p1 = *pt; |
@@ -282,6 +328,7 @@ draw_polyline(DiaRenderer *self, | ||
282 | 328 | Color *line_colour) |
283 | 329 | { |
284 | 330 | _polyline (self, points, num_points, line_colour, NULL); |
331 | + _remove_duplicated_path (DIA_PATH_RENDERER (self)); | |
285 | 332 | } |
286 | 333 | static void |
287 | 334 | draw_polygon(DiaRenderer *self, |
@@ -294,6 +341,7 @@ draw_polygon(DiaRenderer *self, | ||
294 | 341 | /* FIXME: can't be that simple ;) */ |
295 | 342 | _polyline (self, points, num_points, line_colour, NULL); |
296 | 343 | _path_lineto (path, &points[0]); |
344 | + _remove_duplicated_path (renderer); | |
297 | 345 | } |
298 | 346 | static void |
299 | 347 | fill_polygon(DiaRenderer *self, |
@@ -336,6 +384,7 @@ draw_rect (DiaRenderer *self, | ||
336 | 384 | Color *color) |
337 | 385 | { |
338 | 386 | _rect (self, ul_corner, lr_corner, color, NULL); |
387 | + _remove_duplicated_path (DIA_PATH_RENDERER (self)); | |
339 | 388 | } |
340 | 389 | static void |
341 | 390 | fill_rect (DiaRenderer *self, |
@@ -423,6 +472,7 @@ draw_arc (DiaRenderer *self, | ||
423 | 472 | Color *color) |
424 | 473 | { |
425 | 474 | _arc (self, center, width, height, angle1, angle2, color, NULL); |
475 | + _remove_duplicated_path (DIA_PATH_RENDERER (self)); | |
426 | 476 | } |
427 | 477 | static void |
428 | 478 | fill_arc (DiaRenderer *self, |
@@ -508,6 +558,7 @@ draw_ellipse (DiaRenderer *self, | ||
508 | 558 | Color *color) |
509 | 559 | { |
510 | 560 | _ellipse (self, center, width, height, color, NULL); |
561 | + _remove_duplicated_path (DIA_PATH_RENDERER (self)); | |
511 | 562 | } |
512 | 563 | static void |
513 | 564 | fill_ellipse (DiaRenderer *self, |
@@ -545,6 +596,7 @@ draw_bezier (DiaRenderer *self, | ||
545 | 596 | Color *color) |
546 | 597 | { |
547 | 598 | _bezier(self, points, numpoints, color, NULL); |
599 | + _remove_duplicated_path (DIA_PATH_RENDERER (self)); | |
548 | 600 | } |
549 | 601 | static void |
550 | 602 | fill_bezier(DiaRenderer *self, |