Code

Revert recent refactoring changes by johnce because they break the build, which canno...
[inkscape.git] / src / sp-shape.cpp
1 /*
2  * Base class for shapes, including <path> element
3  *
4  * Author:
5  *   Lauris Kaplinski <lauris@kaplinski.com>
6  *
7  * Copyright (C) 1999-2002 Lauris Kaplinski
8  * Copyright (C) 2000-2001 Ximian, Inc.
9  * Copyright (C) 2004 John Cliff
10  * Copyright (C) 2007-2008 Johan Engelen
11  *
12  * Released under GNU GPL, read the file 'COPYING' for more information
13  */
15 #ifdef HAVE_CONFIG_H
16 # include "config.h"
17 #endif
19 #include <libnr/nr-matrix-fns.h>
20 #include <libnr/nr-matrix-ops.h>
21 #include <libnr/nr-matrix-translate-ops.h>
22 #include <libnr/nr-scale-matrix-ops.h>
23 #include <2geom/rect.h>
24 #include <2geom/transforms.h>
25 #include <2geom/pathvector.h>
26 #include <2geom/path-intersection.h>
27 #include "helper/geom.h"
28 #include "helper/geom-nodetype.h"
30 #include <sigc++/functors/ptr_fun.h>
31 #include <sigc++/adaptors/bind.h>
33 #include "macros.h"
34 #include "display/nr-arena-shape.h"
35 #include "display/curve.h"
36 #include "print.h"
37 #include "document.h"
38 #include "style.h"
39 #include "marker.h"
40 #include "sp-path.h"
41 #include "preferences.h"
42 #include "attributes.h"
44 #include "live_effects/lpeobject.h"
45 #include "uri.h"
46 #include "extract-uri.h"
47 #include "uri-references.h"
48 #include "bad-uri-exception.h"
49 #include "xml/repr.h"
51 #include "util/mathfns.h" // for triangle_area()
53 #define noSHAPE_VERBOSE
55 static void sp_shape_class_init (SPShapeClass *klass);
56 static void sp_shape_init (SPShape *shape);
57 static void sp_shape_finalize (GObject *object);
59 static void sp_shape_build (SPObject * object, SPDocument * document, Inkscape::XML::Node * repr);
60 static void sp_shape_release (SPObject *object);
62 static void sp_shape_set(SPObject *object, unsigned key, gchar const *value);
63 static void sp_shape_update (SPObject *object, SPCtx *ctx, unsigned int flags);
64 static void sp_shape_modified (SPObject *object, unsigned int flags);
65 static Inkscape::XML::Node *sp_shape_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
67 static void sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const flags);
68 void sp_shape_print (SPItem * item, SPPrintContext * ctx);
69 static NRArenaItem *sp_shape_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags);
70 static void sp_shape_hide (SPItem *item, unsigned int key);
71 static void sp_shape_snappoints (SPItem const *item, bool const target, SnapPointsWithType &p, Inkscape::SnapPreferences const *snapprefs);
73 static void sp_shape_update_marker_view (SPShape *shape, NRArenaItem *ai);
75 static SPLPEItemClass *parent_class;
77 /**
78  * Registers the SPShape class with Gdk and returns its type number.
79  */
80 GType
81 sp_shape_get_type (void)
82 {
83     static GType type = 0;
84     if (!type) {
85         GTypeInfo info = {
86             sizeof (SPShapeClass),
87             NULL, NULL,
88             (GClassInitFunc) sp_shape_class_init,
89             NULL, NULL,
90             sizeof (SPShape),
91             16,
92             (GInstanceInitFunc) sp_shape_init,
93             NULL,    /* value_table */
94         };
95         type = g_type_register_static (SP_TYPE_LPE_ITEM, "SPShape", &info, (GTypeFlags)0);
96     }
97     return type;
98 }
100 /**
101  * Initializes a SPShapeClass object.  Establishes the function pointers to the class'
102  * member routines in the class vtable, and sets pointers to parent classes.
103  */
104 static void
105 sp_shape_class_init (SPShapeClass *klass)
107     GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
108     SPObjectClass *sp_object_class = SP_OBJECT_CLASS(klass);
109     SPItemClass * item_class = SP_ITEM_CLASS(klass);
110     SPLPEItemClass * lpe_item_class = SP_LPE_ITEM_CLASS(klass);
112     parent_class = (SPLPEItemClass *)g_type_class_peek_parent (klass);
114     gobject_class->finalize = sp_shape_finalize;
116     sp_object_class->build = sp_shape_build;
117     sp_object_class->release = sp_shape_release;
118     sp_object_class->set = sp_shape_set;
119     sp_object_class->update = sp_shape_update;
120     sp_object_class->modified = sp_shape_modified;
121     sp_object_class->write = sp_shape_write;
123     item_class->bbox = sp_shape_bbox;
124     item_class->print = sp_shape_print;
125     item_class->show = sp_shape_show;
126     item_class->hide = sp_shape_hide;
127     item_class->snappoints = sp_shape_snappoints;
128     lpe_item_class->update_patheffect = NULL;
130     klass->set_shape = NULL;
133 /**
134  * Initializes an SPShape object.
135  */
136 static void
137 sp_shape_init (SPShape *shape)
139     for ( int i = 0 ; i < SP_MARKER_LOC_QTY ; i++ ) {
140         new (&shape->release_connect[i]) sigc::connection();
141         new (&shape->modified_connect[i]) sigc::connection();
142         shape->marker[i] = NULL;
143     }
144     shape->curve = NULL;
147 static void
148 sp_shape_finalize (GObject *object)
150     SPShape *shape=(SPShape *)object;
152     for ( int i = 0 ; i < SP_MARKER_LOC_QTY ; i++ ) {
153         shape->release_connect[i].disconnect();
154         shape->release_connect[i].~connection();
155         shape->modified_connect[i].disconnect();
156         shape->modified_connect[i].~connection();
157     }
159     if (((GObjectClass *) (parent_class))->finalize) {
160         (* ((GObjectClass *) (parent_class))->finalize)(object);
161     }
164 /**
165  * Virtual build callback for SPMarker.
166  *
167  * This is to be invoked immediately after creation of an SPShape.
168  *
169  * \see sp_object_build()
170  */
171 static void
172 sp_shape_build (SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
174     if (((SPObjectClass *) (parent_class))->build) {
175        (*((SPObjectClass *) (parent_class))->build) (object, document, repr);
176     }
178     for (int i = 0 ; i < SP_MARKER_LOC_QTY ; i++) {
179         sp_shape_set_marker (object, i, object->style->marker[i].value);
180       }
183 /**
184  * Removes, releases and unrefs all children of object
185  *
186  * This is the inverse of sp_shape_build().  It must be invoked as soon
187  * as the shape is removed from the tree, even if it is still referenced
188  * by other objects.  This routine also disconnects/unrefs markers and
189  * curves attached to it.
190  *
191  * \see sp_object_release()
192  */
193 static void
194 sp_shape_release (SPObject *object)
196     SPItem *item;
197     SPShape *shape;
198     SPItemView *v;
199     int i;
201     item = (SPItem *) object;
202     shape = (SPShape *) object;
204     for (i = 0; i < SP_MARKER_LOC_QTY; i++) {
205         if (shape->marker[i]) {
206             for (v = item->display; v != NULL; v = v->next) {
207               sp_marker_hide ((SPMarker *) shape->marker[i], NR_ARENA_ITEM_GET_KEY (v->arenaitem) + i);
208             }
209             shape->release_connect[i].disconnect();
210             shape->modified_connect[i].disconnect();
211             shape->marker[i] = sp_object_hunref (shape->marker[i], object);
212         }
213     }
214     if (shape->curve) {
215         shape->curve = shape->curve->unref();
216     }
218     if (((SPObjectClass *) parent_class)->release) {
219       ((SPObjectClass *) parent_class)->release (object);
220     }
225 static void
226 sp_shape_set(SPObject *object, unsigned int key, gchar const *value)
228     if (((SPObjectClass *) parent_class)->set) {
229         ((SPObjectClass *) parent_class)->set(object, key, value);
230     }
233 static Inkscape::XML::Node *
234 sp_shape_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags)
236     if (((SPObjectClass *)(parent_class))->write) {
237         ((SPObjectClass *)(parent_class))->write(object, doc, repr, flags);
238     }
240     return repr;
243 /**
244  * Updates the shape when its attributes have changed.  Also establishes
245  * marker objects to match the style settings.
246  */
247 static void
248 sp_shape_update (SPObject *object, SPCtx *ctx, unsigned int flags)
250     SPItem *item = (SPItem *) object;
251     SPShape *shape = (SPShape *) object;
253     if (((SPObjectClass *) (parent_class))->update) {
254         (* ((SPObjectClass *) (parent_class))->update) (object, ctx, flags);
255     }
257     /* This stanza checks that an object's marker style agrees with
258      * the marker objects it has allocated.  sp_shape_set_marker ensures
259      * that the appropriate marker objects are present (or absent) to
260      * match the style.
261      */
262     for (int i = 0 ; i < SP_MARKER_LOC_QTY ; i++) {
263         sp_shape_set_marker (object, i, object->style->marker[i].value);
264       }
266     if (flags & (SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
267         SPStyle *style;
268         style = SP_OBJECT_STYLE (object);
269         if (style->stroke_width.unit == SP_CSS_UNIT_PERCENT) {
270             SPItemCtx *ictx = (SPItemCtx *) ctx;
271             double const aw = 1.0 / NR::expansion(ictx->i2vp);
272             style->stroke_width.computed = style->stroke_width.value * aw;
273             for (SPItemView *v = ((SPItem *) (shape))->display; v != NULL; v = v->next) {
274                 nr_arena_shape_set_style ((NRArenaShape *) v->arenaitem, style);
275             }
276         }
277     }
279     if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_PARENT_MODIFIED_FLAG)) {
280         /* This is suboptimal, because changing parent style schedules recalculation */
281         /* But on the other hand - how can we know that parent does not tie style and transform */
282         Geom::OptRect paintbox = SP_ITEM(object)->getBounds(Geom::identity(), SPItem::GEOMETRIC_BBOX);
283         for (SPItemView *v = SP_ITEM (shape)->display; v != NULL; v = v->next) {
284             NRArenaShape * const s = NR_ARENA_SHAPE(v->arenaitem);
285             if (flags & SP_OBJECT_MODIFIED_FLAG) {
286                 nr_arena_shape_set_path(s, shape->curve, (flags & SP_OBJECT_USER_MODIFIED_FLAG_B));
287             }
288             if (paintbox) {
289                 s->setPaintBox(*paintbox);
290             }
291         }
292     }
294     if (sp_shape_has_markers (shape)) {
295         /* Dimension marker views */
296         for (SPItemView *v = item->display; v != NULL; v = v->next) {
297             if (!v->arenaitem->key) {
298                 NR_ARENA_ITEM_SET_KEY (v->arenaitem, sp_item_display_key_new (SP_MARKER_LOC_QTY));
299             }
300             for (int i = 0 ; i < SP_MARKER_LOC_QTY ; i++) {
301                 if (shape->marker[i]) {
302                     sp_marker_show_dimension ((SPMarker *) shape->marker[i],
303                                               NR_ARENA_ITEM_GET_KEY (v->arenaitem) + i,
304                                               sp_shape_number_of_markers (shape, i));
305                 }
306             }
307         }
309         /* Update marker views */
310         for (SPItemView *v = item->display; v != NULL; v = v->next) {
311             sp_shape_update_marker_view (shape, v->arenaitem);
312         }
313     }
316 /**
317  * Calculate the transform required to get a marker's path object in the
318  * right place for particular path segment on a shape.
319  *
320  * \see sp_shape_marker_update_marker_view.
321  *
322  * From SVG spec:
323  * The axes of the temporary new user coordinate system are aligned according to the orient attribute on the 'marker'
324  * element and the slope of the curve at the given vertex. (Note: if there is a discontinuity at a vertex, the slope
325  * is the average of the slopes of the two segments of the curve that join at the given vertex. If a slope cannot be
326  * determined, the slope is assumed to be zero.)
327  *
328  * Reference: http://www.w3.org/TR/SVG11/painting.html#MarkerElement, the `orient' attribute.
329  * Reference for behaviour of zero-length segments:
330  * http://www.w3.org/TR/SVG11/implnote.html#PathElementImplementationNotes
331  */
332 Geom::Matrix
333 sp_shape_marker_get_transform(Geom::Curve const & c1, Geom::Curve const & c2)
335     Geom::Point p = c1.pointAt(1);
336     Geom::Curve * c1_reverse = c1.reverse();
337     Geom::Point tang1 = - c1_reverse->unitTangentAt(0);
338     delete c1_reverse;
339     Geom::Point tang2 = c2.unitTangentAt(0);
341     double const angle1 = Geom::atan2(tang1);
342     double const angle2 = Geom::atan2(tang2);
344     double ret_angle;
345     ret_angle = .5 * (angle1 + angle2);
347     if ( fabs( angle2 - angle1 ) > M_PI ) {
348         /* ret_angle is in the middle of the larger of the two sectors between angle1 and
349          * angle2, so flip it by 180degrees to force it to the middle of the smaller sector.
350          *
351          * (Imagine a circle with rays drawn at angle1 and angle2 from the centre of the
352          * circle.  Those two rays divide the circle into two sectors.)
353          */
354         ret_angle += M_PI;
355     }
357     return Geom::Rotate(ret_angle) * Geom::Translate(p);
359 Geom::Matrix
360 sp_shape_marker_get_transform_at_start(Geom::Curve const & c)
362     Geom::Point p = c.pointAt(0);
363     Geom::Matrix ret = Geom::Translate(p);
365     if ( !c.isDegenerate() ) {
366         Geom::Point tang = c.unitTangentAt(0);
367         double const angle = Geom::atan2(tang);
368         ret = Geom::Rotate(angle) * Geom::Translate(p);
369     } else {
370         /* FIXME: the svg spec says to search for a better alternative than zero angle directionality:
371          * http://www.w3.org/TR/SVG11/implnote.html#PathElementImplementationNotes */
372     }
374     return ret;
376 Geom::Matrix
377 sp_shape_marker_get_transform_at_end(Geom::Curve const & c)
379     Geom::Point p = c.pointAt(1);
380     Geom::Matrix ret = Geom::Translate(p);
382     if ( !c.isDegenerate() ) {
383         Geom::Curve * c_reverse = c.reverse();
384         Geom::Point tang = - c_reverse->unitTangentAt(0);
385         delete c_reverse;
386         double const angle = Geom::atan2(tang);
387         ret = Geom::Rotate(angle) * Geom::Translate(p);
388     } else {
389         /* FIXME: the svg spec says to search for a better alternative than zero angle directionality:
390          * http://www.w3.org/TR/SVG11/implnote.html#PathElementImplementationNotes */
391     }
393     return ret;
396 /**
397  * Updates the instances (views) of a given marker in a shape.
398  * Marker views have to be scaled already.  The transformation
399  * is retrieved and then shown by calling sp_marker_show_instance.
400  *
401  * @todo figure out what to do when both 'marker' and for instance 'marker-end' are set.
402  */
403 static void
404 sp_shape_update_marker_view (SPShape *shape, NRArenaItem *ai)
406     SPStyle *style = ((SPObject *) shape)->style;
408     // position arguments to sp_marker_show_instance, basically counts the amount of markers.
409     int counter[4] = {0};
411     Geom::PathVector const & pathv = shape->curve->get_pathvector();
412     for(Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
413       // START position
414         Geom::Matrix const m (sp_shape_marker_get_transform_at_start(path_it->front()));
415         for (int i = 0; i < 2; i++) {  // SP_MARKER_LOC and SP_MARKER_LOC_START
416             if ( shape->marker[i] ) {
417                 sp_marker_show_instance ((SPMarker* ) shape->marker[i], ai,
418                                          NR_ARENA_ITEM_GET_KEY(ai) + i, counter[i], m,
419                                          style->stroke_width.computed);
420                  counter[i]++;
421             }
422         }
424       // MID position
425         if ( (shape->marker[SP_MARKER_LOC_MID] || shape->marker[SP_MARKER_LOC]) && (path_it->size_default() > 1) ) {
426             Geom::Path::const_iterator curve_it1 = path_it->begin();      // incoming curve
427             Geom::Path::const_iterator curve_it2 = ++(path_it->begin());  // outgoing curve
428             while (curve_it2 != path_it->end_default())
429             {
430                 /* Put marker between curve_it1 and curve_it2.
431                  * Loop to end_default (so including closing segment), because when a path is closed,
432                  * there should be a midpoint marker between last segment and closing straight line segment
433                  */
434                 Geom::Matrix const m (sp_shape_marker_get_transform(*curve_it1, *curve_it2));
435                 for (int i = 0; i < 3; i += 2) {  // SP_MARKER_LOC and SP_MARKER_LOC_MID
436                     if (shape->marker[i]) {
437                         sp_marker_show_instance ((SPMarker* ) shape->marker[i], ai,
438                                                  NR_ARENA_ITEM_GET_KEY(ai) + i, counter[i], m,
439                                                  style->stroke_width.computed);
440                         counter[i]++;
441                     }
442                 }
444                 ++curve_it1;
445                 ++curve_it2;
446             }
447         }
449       // END position
450         if ( shape->marker[SP_MARKER_LOC_END] || shape->marker[SP_MARKER_LOC] ) {
451             /* Get reference to last curve in the path.
452              * For moveto-only path, this returns the "closing line segment". */
453             unsigned int index = path_it->size_default();
454             if (index > 0) {
455                 index--;
456             }
457             Geom::Curve const &lastcurve = (*path_it)[index];
458             Geom::Matrix const m = sp_shape_marker_get_transform_at_end(lastcurve);
460             for (int i = 0; i < 4; i += 3) {  // SP_MARKER_LOC and SP_MARKER_LOC_END
461                 if (shape->marker[i]) {
462                     sp_marker_show_instance ((SPMarker* ) shape->marker[i], ai,
463                                              NR_ARENA_ITEM_GET_KEY(ai) + i, counter[i], m,
464                                              style->stroke_width.computed);
465                     counter[i]++;
466                 }
467             }
468         }
469     }
472 /**
473  * Sets modified flag for all sub-item views.
474  */
475 static void
476 sp_shape_modified (SPObject *object, unsigned int flags)
478     SPShape *shape = SP_SHAPE (object);
480     if (((SPObjectClass *) (parent_class))->modified) {
481       (* ((SPObjectClass *) (parent_class))->modified) (object, flags);
482     }
484     if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) {
485         for (SPItemView *v = SP_ITEM (shape)->display; v != NULL; v = v->next) {
486             nr_arena_shape_set_style (NR_ARENA_SHAPE (v->arenaitem), object->style);
487         }
488     }
491 /**
492  * Calculates the bounding box for item, storing it into bbox.
493  * This also includes the bounding boxes of any markers included in the shape.
494  */
495 static void sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const flags)
497     SPShape const *shape = SP_SHAPE (item);
498     if (shape->curve) {
499         Geom::OptRect geombbox = bounds_exact_transformed(shape->curve->get_pathvector(), transform);
500         if (geombbox) {
501             NRRect  cbbox;
502             cbbox.x0 = (*geombbox)[0][0];
503             cbbox.y0 = (*geombbox)[1][0];
504             cbbox.x1 = (*geombbox)[0][1];
505             cbbox.y1 = (*geombbox)[1][1];
507             if ((SPItem::BBoxType) flags != SPItem::GEOMETRIC_BBOX) {
509                 SPStyle* style=SP_OBJECT_STYLE (item);
510                 if (!style->stroke.isNone()) {
511                     double const scale = transform.descrim();
512                     if ( fabs(style->stroke_width.computed * scale) > 0.01 ) { // sinon c'est 0=oon veut pas de bord
513                         double const width = MAX(0.125, style->stroke_width.computed * scale);
514                         if ( fabs(cbbox.x1-cbbox.x0) > -0.00001 && fabs(cbbox.y1-cbbox.y0) > -0.00001 ) {
515                             cbbox.x0-=0.5*width;
516                             cbbox.x1+=0.5*width;
517                             cbbox.y0-=0.5*width;
518                             cbbox.y1+=0.5*width;
519                         }
520                     }
521                 }
523                 // Union with bboxes of the markers, if any
524                 if (sp_shape_has_markers (shape)) {
525                     /* TODO: make code prettier: lots of variables can be taken out of the loop! */
526                     Geom::PathVector const & pathv = shape->curve->get_pathvector();
527                     for(Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
528                         for (unsigned i = 0; i < 2; i++) { // SP_MARKER_LOC and SP_MARKER_LOC_START
529                             if ( shape->marker[i] ) {
530                                 SPMarker* marker = SP_MARKER (shape->marker[i]);
531                                 SPItem* marker_item = sp_item_first_item_child (SP_OBJECT (marker));
533                                 if (marker_item) {
534                                                                         Geom::Matrix tr(sp_shape_marker_get_transform_at_start(path_it->front()));
535                                                                         if (!marker->orient_auto) {
536                                                                                 Geom::Point transl = tr.translation();
537                                                                                 tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(transl);
538                                                                         }
539                                                                         if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) {
540                                                                                 tr = Geom::Scale(style->stroke_width.computed) * tr;
541                                                                         }
543                                                                         // total marker transform
544                                                                         tr = marker_item->transform * marker->c2p * tr * transform;
546                                                                         // get bbox of the marker with that transform
547                                                                         NRRect marker_bbox;
548                                                                         sp_item_invoke_bbox (marker_item, &marker_bbox, from_2geom(tr), true);
549                                                                         // union it with the shape bbox
550                                                                         nr_rect_d_union (&cbbox, &cbbox, &marker_bbox);
551                                 }
552                             }
553                         }
555                         for (unsigned i = 0; i < 3; i += 2) { // SP_MARKER_LOC and SP_MARKER_LOC_MID
556                             if ( shape->marker[i] && (path_it->size_default() > 1) ) {
557                                 Geom::Path::const_iterator curve_it1 = path_it->begin();      // incoming curve
558                                 Geom::Path::const_iterator curve_it2 = ++(path_it->begin());  // outgoing curve
559                                 while (curve_it2 != path_it->end_default())
560                                 {
561                                     /* Put marker between curve_it1 and curve_it2.
562                                      * Loop to end_default (so including closing segment), because when a path is closed,
563                                      * there should be a midpoint marker between last segment and closing straight line segment */
565                                     SPMarker* marker = SP_MARKER (shape->marker[i]);
566                                     SPItem* marker_item = sp_item_first_item_child (SP_OBJECT (marker));
568                                     if (marker_item) {
569                                         Geom::Matrix tr(sp_shape_marker_get_transform(*curve_it1, *curve_it2));
570                                                                                 if (!marker->orient_auto) {
571                                                                                         Geom::Point transl = tr.translation();
572                                                                                         tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(transl);
573                                                                                 }
574                                                                                 if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) {
575                                                                                         tr = Geom::Scale(style->stroke_width.computed) * tr;
576                                                                                 }
578                                                                                 // total marker transform
579                                                                                 tr = marker_item->transform * marker->c2p * tr * transform;
581                                                                                 // get bbox of the marker with that transform
582                                                                                 NRRect marker_bbox;
583                                                                                 sp_item_invoke_bbox (marker_item, &marker_bbox, from_2geom(tr), true);
584                                                                                 // union it with the shape bbox
585                                                                                 nr_rect_d_union (&cbbox, &cbbox, &marker_bbox);
586                                     }
588                                     ++curve_it1;
589                                     ++curve_it2;
590                                 }
591                             }
592                         }
594                         for (unsigned i = 0; i < 4; i += 3) { // SP_MARKER_LOC and SP_MARKER_LOC_END
595                             if ( shape->marker[i] ) {
596                                 SPMarker* marker = SP_MARKER (shape->marker[i]);
597                                 SPItem* marker_item = sp_item_first_item_child (SP_OBJECT (marker));
599                                 if (marker_item) {
600                                                                         /* Get reference to last curve in the path.
601                                                                          * For moveto-only path, this returns the "closing line segment". */
602                                                                         unsigned int index = path_it->size_default();
603                                                                         if (index > 0) {
604                                                                                 index--;
605                                                                         }
606                                                                         Geom::Curve const &lastcurve = (*path_it)[index];
608                                                                         Geom::Matrix tr = sp_shape_marker_get_transform_at_end(lastcurve);
609                                                                         if (!marker->orient_auto) {
610                                                                                 Geom::Point transl = tr.translation();
611                                                                                 tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(transl);
612                                                                         }
613                                                                         if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) {
614                                                                                 tr = Geom::Scale(style->stroke_width.computed) * tr;
615                                                                         }
617                                                                         // total marker transform
618                                                                         tr = marker_item->transform * marker->c2p * tr * transform;
620                                                                         // get bbox of the marker with that transform
621                                                                         NRRect marker_bbox;
622                                                                         sp_item_invoke_bbox (marker_item, &marker_bbox, tr, true);
623                                                                         // union it with the shape bbox
624                                                                         nr_rect_d_union (&cbbox, &cbbox, &marker_bbox);
625                                 }
626                             }
627                         }
628                     }
629                 }
630             }
632             // copy our bbox to the variable we're given
633             *bbox = cbbox;
634         }
635     }
638 static void
639 sp_shape_print_invoke_marker_printing(SPObject* obj, Geom::Matrix tr, SPStyle* style, SPPrintContext *ctx) {
640     SPMarker *marker = SP_MARKER(obj);
641     if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) {
642         tr = Geom::Scale(style->stroke_width.computed) * tr;
643     }
645     SPItem* marker_item = sp_item_first_item_child (SP_OBJECT (marker));
646     tr = marker_item->transform * marker->c2p * tr;
648     Geom::Matrix old_tr = marker_item->transform;
649     marker_item->transform = tr;
650     sp_item_invoke_print (marker_item, ctx);
651     marker_item->transform = old_tr;
653 /**
654  * Prepares shape for printing.  Handles printing of comments for printing
655  * debugging, sizes the item to fit into the document width/height,
656  * applies print fill/stroke, sets transforms for markers, and adds
657  * comment labels.
658  */
659 void
660 sp_shape_print (SPItem *item, SPPrintContext *ctx)
662     NRRect pbox, dbox, bbox;
664     SPShape *shape = SP_SHAPE(item);
666     if (!shape->curve) return;
668         Inkscape::Preferences *prefs = Inkscape::Preferences::get();
669         gint add_comments = prefs->getBool("/printing/debug/add-label-comments");
670         if (add_comments) {
671             gchar * comment = g_strdup_printf("begin '%s'",
672                                               SP_OBJECT(item)->defaultLabel());
673             sp_print_comment(ctx, comment);
674             g_free(comment);
675         }
677     /* fixme: Think (Lauris) */
678     sp_item_invoke_bbox(item, &pbox, Geom::identity(), TRUE);
679     dbox.x0 = 0.0;
680     dbox.y0 = 0.0;
681     dbox.x1 = sp_document_width (SP_OBJECT_DOCUMENT (item));
682     dbox.y1 = sp_document_height (SP_OBJECT_DOCUMENT (item));
683     sp_item_bbox_desktop (item, &bbox);
684     Geom::Matrix const i2d(sp_item_i2d_affine(item));
686     SPStyle* style = SP_OBJECT_STYLE (item);
688     if (!style->fill.isNone()) {
689         sp_print_fill (ctx, shape->curve->get_pathvector(), &i2d, style, &pbox, &dbox, &bbox);
690     }
692     if (!style->stroke.isNone()) {
693         sp_print_stroke (ctx, shape->curve->get_pathvector(), &i2d, style, &pbox, &dbox, &bbox);
694     }
696     /* TODO: make code prettier: lots of variables can be taken out of the loop! */
697     Geom::PathVector const & pathv = shape->curve->get_pathvector();
698     for(Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
699         if ( shape->marker[SP_MARKER_LOC_START] || shape->marker[SP_MARKER_LOC]) {
700             Geom::Matrix tr(sp_shape_marker_get_transform_at_start(path_it->front()));
701             if (shape->marker[SP_MARKER_LOC_START]) {
702                 sp_shape_print_invoke_marker_printing(shape->marker[SP_MARKER_LOC_START], tr, style, ctx);
703             }
704             if (shape->marker[SP_MARKER_LOC]) {
705                 sp_shape_print_invoke_marker_printing(shape->marker[SP_MARKER_LOC], tr, style, ctx);
706             }
707         }
709         if ( (shape->marker[SP_MARKER_LOC_MID] || shape->marker[SP_MARKER_LOC]) && (path_it->size_default() > 1) ) {
710             Geom::Path::const_iterator curve_it1 = path_it->begin();      // incoming curve
711             Geom::Path::const_iterator curve_it2 = ++(path_it->begin());  // outgoing curve
712             while (curve_it2 != path_it->end_default())
713             {
714                 /* Put marker between curve_it1 and curve_it2.
715                  * Loop to end_default (so including closing segment), because when a path is closed,
716                  * there should be a midpoint marker between last segment and closing straight line segment */
717                 Geom::Matrix tr(sp_shape_marker_get_transform(*curve_it1, *curve_it2));
719                 if (shape->marker[SP_MARKER_LOC_MID]) {
720                     sp_shape_print_invoke_marker_printing(shape->marker[SP_MARKER_LOC_MID], tr, style, ctx);
721                 }
722                 if (shape->marker[SP_MARKER_LOC]) {
723                     sp_shape_print_invoke_marker_printing(shape->marker[SP_MARKER_LOC], tr, style, ctx);
724                 }
726                 ++curve_it1;
727                 ++curve_it2;
728             }
729         }
731         if ( shape->marker[SP_MARKER_LOC_END] || shape->marker[SP_MARKER_LOC]) {
732             /* Get reference to last curve in the path.
733              * For moveto-only path, this returns the "closing line segment". */
734             unsigned int index = path_it->size_default();
735             if (index > 0) {
736                 index--;
737             }
738             Geom::Curve const &lastcurve = (*path_it)[index];
740             Geom::Matrix tr = sp_shape_marker_get_transform_at_end(lastcurve);
742             if (shape->marker[SP_MARKER_LOC_END]) {
743                 sp_shape_print_invoke_marker_printing(shape->marker[SP_MARKER_LOC_END], tr, style, ctx);
744             }
745             if (shape->marker[SP_MARKER_LOC]) {
746                 sp_shape_print_invoke_marker_printing(shape->marker[SP_MARKER_LOC], tr, style, ctx);
747             }
748         }
749     }
751         if (add_comments) {
752             gchar * comment = g_strdup_printf("end '%s'",
753                                               SP_OBJECT(item)->defaultLabel());
754             sp_print_comment(ctx, comment);
755             g_free(comment);
756         }
759 /**
760  * Sets style, path, and paintbox.  Updates marker views, including dimensions.
761  */
762 static NRArenaItem *
763 sp_shape_show (SPItem *item, NRArena *arena, unsigned int /*key*/, unsigned int /*flags*/)
765     SPObject *object = SP_OBJECT(item);
766     SPShape *shape = SP_SHAPE(item);
768     NRArenaItem *arenaitem = NRArenaShape::create(arena);
769     NRArenaShape * const s = NR_ARENA_SHAPE(arenaitem);
770     nr_arena_shape_set_style(s, object->style);
771     nr_arena_shape_set_path(s, shape->curve, false);
772     Geom::OptRect paintbox = item->getBounds(Geom::identity());
773     if (paintbox) {
774         s->setPaintBox(*paintbox);
775     }
777     /* This stanza checks that an object's marker style agrees with
778      * the marker objects it has allocated.  sp_shape_set_marker ensures
779      * that the appropriate marker objects are present (or absent) to
780      * match the style.
781      */
782     for (int i = 0 ; i < SP_MARKER_LOC_QTY ; i++) {
783         sp_shape_set_marker (object, i, object->style->marker[i].value);
784       }
786     if (sp_shape_has_markers (shape)) {
788         /* provide key and dimension the marker views */
789         if (!arenaitem->key) {
790             NR_ARENA_ITEM_SET_KEY (arenaitem, sp_item_display_key_new (SP_MARKER_LOC_QTY));
791         }
793         for (int i = 0; i < SP_MARKER_LOC_QTY; i++) {
794             if (shape->marker[i]) {
795                 sp_marker_show_dimension ((SPMarker *) shape->marker[i],
796                                           NR_ARENA_ITEM_GET_KEY (arenaitem) + i,
797                                           sp_shape_number_of_markers (shape, i));
798             }
799         }
801         /* Update marker views */
802         sp_shape_update_marker_view (shape, arenaitem);
803     }
805     return arenaitem;
808 /**
809  * Hides/removes marker views from the shape.
810  */
811 static void
812 sp_shape_hide (SPItem *item, unsigned int key)
814     SPShape *shape;
815     SPItemView *v;
816     int i;
818     shape = (SPShape *) item;
820     for (i=0; i<SP_MARKER_LOC_QTY; i++) {
821       if (shape->marker[i]) {
822         for (v = item->display; v != NULL; v = v->next) {
823                 if (key == v->key) {
824           sp_marker_hide ((SPMarker *) shape->marker[i],
825                                     NR_ARENA_ITEM_GET_KEY (v->arenaitem) + i);
826                 }
827         }
828       }
829     }
831     if (((SPItemClass *) parent_class)->hide) {
832       ((SPItemClass *) parent_class)->hide (item, key);
833     }
836 /**
837 * \param shape Shape.
838 * \return TRUE if the shape has any markers, or FALSE if not.
839 */
840 int
841 sp_shape_has_markers (SPShape const *shape)
843     /* Note, we're ignoring 'marker' settings, which technically should apply for
844        all three settings.  This should be fixed later such that if 'marker' is
845        specified, then all three should appear. */
847     return (
848         shape->curve &&
849         (shape->marker[SP_MARKER_LOC] ||
850          shape->marker[SP_MARKER_LOC_START] ||
851          shape->marker[SP_MARKER_LOC_MID] ||
852          shape->marker[SP_MARKER_LOC_END])
853         );
857 /**
858 * \param shape Shape.
859 * \param type Marker type (e.g. SP_MARKER_LOC_START)
860 * \return Number of markers that the shape has of this type.
861 */
862 int
863 sp_shape_number_of_markers (SPShape *shape, int type)
865     Geom::PathVector const & pathv = shape->curve->get_pathvector();
867     switch(type) {
868         case SP_MARKER_LOC:
869         {
870             if ( shape->marker[SP_MARKER_LOC] ) {
871                 guint n = 2*pathv.size();
872                 for(Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
873                     n += path_it->size();
874                     n += path_it->closed() ? 1 : 0;
875                 }
876                 return n;
877             } else {
878                 return 0;
879             }
880         }
881         case SP_MARKER_LOC_START:
882             return shape->marker[SP_MARKER_LOC_START] ? pathv.size() : 0;
884         case SP_MARKER_LOC_MID:
885         {
886             if ( shape->marker[SP_MARKER_LOC_MID] ) {
887             guint n = 0;
888                 for(Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
889                     n += path_it->size();
890                     n += path_it->closed() ? 1 : 0;
891                 }
892                 return n;
893             } else {
894                 return 0;
895             }
896         }
898         case SP_MARKER_LOC_END:
899         {
900             return shape->marker[SP_MARKER_LOC_END] ? pathv.size() : 0;
901         }
903         default:
904             return 0;
905     }
908 /**
909  * Checks if the given marker is used in the shape, and if so, it
910  * releases it by calling sp_marker_hide.  Also detaches signals
911  * and unrefs the marker from the shape.
912  */
913 static void
914 sp_shape_marker_release (SPObject *marker, SPShape *shape)
916     SPItem *item;
917     int i;
919     item = (SPItem *) shape;
921     for (i = 0; i < SP_MARKER_LOC_QTY; i++) {
922         if (marker == shape->marker[i]) {
923             SPItemView *v;
924             /* Hide marker */
925             for (v = item->display; v != NULL; v = v->next) {
926               sp_marker_hide ((SPMarker *) (shape->marker[i]), NR_ARENA_ITEM_GET_KEY (v->arenaitem) + i);
927               /* fixme: Do we need explicit remove here? (Lauris) */
928               /* nr_arena_item_set_mask (v->arenaitem, NULL); */
929             }
930             /* Detach marker */
931             shape->release_connect[i].disconnect();
932             shape->modified_connect[i].disconnect();
933             shape->marker[i] = sp_object_hunref (shape->marker[i], item);
934         }
935     }
938 /**
939  * No-op.  Exists for handling 'modified' messages
940  */
941 static void
942 sp_shape_marker_modified (SPObject */*marker*/, guint /*flags*/, SPItem */*item*/)
944     /* I think mask does update automagically */
945     /* g_warning ("Item %s mask %s modified", SP_OBJECT_ID (item), SP_OBJECT_ID (mask)); */
948 /**
949  * Adds a new marker to shape object at the location indicated by key.  value
950  * must be a valid URI reference resolvable from the shape object (i.e., present
951  * in the document <defs>).  If the shape object already has a marker
952  * registered at the given position, it is removed first.  Then the
953  * new marker is hrefed and its signals connected.
954  */
955 void
956 sp_shape_set_marker (SPObject *object, unsigned int key, const gchar *value)
958     SPItem *item = (SPItem *) object;
959     SPShape *shape = (SPShape *) object;
961     if (key > SP_MARKER_LOC_END) {
962         return;
963     }
965     SPObject *mrk = sp_css_uri_reference_resolve (SP_OBJECT_DOCUMENT (object), value);
966     if (mrk != shape->marker[key]) {
967         if (shape->marker[key]) {
968             SPItemView *v;
970             /* Detach marker */
971             shape->release_connect[key].disconnect();
972             shape->modified_connect[key].disconnect();
974             /* Hide marker */
975             for (v = item->display; v != NULL; v = v->next) {
976                 sp_marker_hide ((SPMarker *) (shape->marker[key]),
977                                 NR_ARENA_ITEM_GET_KEY (v->arenaitem) + key);
978                 /* fixme: Do we need explicit remove here? (Lauris) */
979                 /* nr_arena_item_set_mask (v->arenaitem, NULL); */
980             }
982             /* Unref marker */
983             shape->marker[key] = sp_object_hunref (shape->marker[key], object);
984         }
985         if (SP_IS_MARKER (mrk)) {
986             shape->marker[key] = sp_object_href (mrk, object);
987             shape->release_connect[key] = mrk->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_shape_marker_release), shape));
988             shape->modified_connect[key] = mrk->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_shape_marker_modified), shape));
989         }
990     }
995 /* Shape section */
997 /**
998  * Calls any registered handlers for the set_shape action
999  */
1000 void
1001 sp_shape_set_shape (SPShape *shape)
1003     g_return_if_fail (shape != NULL);
1004     g_return_if_fail (SP_IS_SHAPE (shape));
1006     if (SP_SHAPE_CLASS (G_OBJECT_GET_CLASS (shape))->set_shape) {
1007       SP_SHAPE_CLASS (G_OBJECT_GET_CLASS (shape))->set_shape (shape);
1008     }
1011 /**
1012  * Adds a curve to the shape.  If owner is specified, a reference
1013  * will be made, otherwise the curve will be copied into the shape.
1014  * Any existing curve in the shape will be unreferenced first.
1015  * This routine also triggers a request to update the display.
1016  */
1017 void
1018 sp_shape_set_curve (SPShape *shape, SPCurve *curve, unsigned int owner)
1020     if (shape->curve) {
1021         shape->curve = shape->curve->unref();
1022     }
1023     if (curve) {
1024         if (owner) {
1025             shape->curve = curve->ref();
1026         } else {
1027             shape->curve = curve->copy();
1028         }
1029     }
1030         SP_OBJECT(shape)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
1033 /**
1034  * Return duplicate of curve (if any exists) or NULL if there is no curve
1035  */
1036 SPCurve *
1037 sp_shape_get_curve (SPShape *shape)
1039     if (shape->curve) {
1040         return shape->curve->copy();
1041     }
1042     return NULL;
1045 /**
1046  * Same as sp_shape_set_curve but without updating the display
1047  */
1048 void
1049 sp_shape_set_curve_insync (SPShape *shape, SPCurve *curve, unsigned int owner)
1051     if (shape->curve) {
1052         shape->curve = shape->curve->unref();
1053     }
1054     if (curve) {
1055         if (owner) {
1056             shape->curve = curve->ref();
1057         } else {
1058             shape->curve = curve->copy();
1059         }
1060     }
1063 /**
1064  * Return all nodes in a path that are to be considered for snapping
1065  */
1066 static void sp_shape_snappoints(SPItem const *item, bool const target, SnapPointsWithType &p, Inkscape::SnapPreferences const *snapprefs)
1068     g_assert(item != NULL);
1069     g_assert(SP_IS_SHAPE(item));
1071     SPShape const *shape = SP_SHAPE(item);
1072     if (shape->curve == NULL) {
1073         return;
1074     }
1076     // Help enforcing strict snapping, i.e. only return nodes when we're snapping nodes to nodes or a guide to nodes
1077     if (!(snapprefs->getSnapModeNode() || snapprefs->getSnapModeGuide())) {
1078         return;
1079     }
1081     Geom::PathVector const &pathv = shape->curve->get_pathvector();
1082     if (pathv.empty())
1083         return;
1085     Geom::Matrix const i2d (sp_item_i2d_affine (item));
1087     int type;
1089         if (snapprefs->getSnapObjectMidpoints()) {
1090                 Geom::OptRect bbox = item->getBounds(sp_item_i2d_affine(item));
1091                 if (bbox) {
1092                         type = target ? int(Inkscape::SNAPTARGET_OBJECT_MIDPOINT) : int(Inkscape::SNAPSOURCE_OBJECT_MIDPOINT);
1093                         p.push_back(std::make_pair(bbox->midpoint(), type));
1094                 }
1095         }
1097     for(Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
1098         if (snapprefs->getSnapToItemNode()) {
1099                 type = target ? int(Inkscape::SNAPTARGET_NODE_CUSP) : int(Inkscape::SNAPSOURCE_NODE_CUSP);
1100                 p.push_back(std::make_pair(path_it->initialPoint() * i2d, type));
1101         }
1103         Geom::Path::const_iterator curve_it1 = path_it->begin();      // incoming curve
1104         Geom::Path::const_iterator curve_it2 = ++(path_it->begin());  // outgoing curve
1105         while (curve_it2 != path_it->end_closed())
1106         {
1107             /* Test whether to add the node between curve_it1 and curve_it2.
1108              * Loop to end_closed (so always including closing segment); the last node to be added
1109              * is the node between the closing segment and the segment before that, regardless
1110              * of the path being closed or not. If the path is closed, the final point was already added by
1111              * adding the initial point. */
1113             Geom::NodeType nodetype = Geom::get_nodetype(*curve_it1, *curve_it2);
1115             bool c1 = snapprefs->getSnapToItemNode() && (nodetype == Geom::NODE_CUSP || nodetype == Geom::NODE_NONE);
1116             bool c2 = snapprefs->getSnapSmoothNodes() && (nodetype == Geom::NODE_SMOOTH || nodetype == Geom::NODE_SYMM);
1118             if (c1 || c2) {
1119                 type = target ? int(Inkscape::SNAPTARGET_NODE_CUSP) : int(Inkscape::SNAPSOURCE_NODE_CUSP);
1120                                 p.push_back(std::make_pair(curve_it1->finalPoint() * i2d, type));
1121             }
1123                         // Consider midpoints of line segments for snapping
1124                         if (snapprefs->getSnapLineMidpoints()) { // only do this when we're snapping nodes (enforce strict snapping)
1125                                 if (Geom::LineSegment const* line_segment = dynamic_cast<Geom::LineSegment const*>(&(*curve_it1))) {
1126                                         type = target ? int(Inkscape::SNAPTARGET_LINE_MIDPOINT) : int(Inkscape::SNAPSOURCE_LINE_MIDPOINT);
1127                                         p.push_back(std::make_pair(Geom::middle_point(*line_segment) * i2d, type));
1128                                 }
1129                         }
1131             ++curve_it1;
1132             ++curve_it2;
1133         }
1135         // Find the internal intersections of each path and consider these for snapping
1136         // (using "Method 1" as described in Inkscape::ObjectSnapper::_collectNodes())
1137         if (snapprefs->getSnapIntersectionCS()) {
1138             Geom::Crossings cs;
1139             cs = self_crossings(*path_it);
1140             if (cs.size() > 0) { // There might be multiple intersections...
1141                 for (Geom::Crossings::const_iterator i = cs.begin(); i != cs.end(); i++) {
1142                     Geom::Point p_ix = (*path_it).pointAt((*i).ta);
1143                     type = target ? int(Inkscape::SNAPTARGET_PATH_INTERSECTION) : int(Inkscape::SNAPSOURCE_PATH_INTERSECTION);
1144                     p.push_back(std::make_pair(p_ix * i2d, type));
1145                 }
1146             }
1147         }
1148     }
1152 /*
1153   Local Variables:
1154   mode:c++
1155   c-file-style:"stroustrup"
1156   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1157   indent-tabs-mode:nil
1158   fill-column:99
1159   End:
1160 */
1161 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :