Code

Added a new toolbar with snapping controls
[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, SnapPointsIter 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                                 Geom::Matrix tr(sp_shape_marker_get_transform_at_start(path_it->front()));
534                                 if (!marker->orient_auto) {
535                                     Geom::Point transl = tr.translation();
536                                     tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(transl);
537                                 }
538                                 if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) {
539                                     tr = Geom::Scale(style->stroke_width.computed) * tr;
540                                 }
542                                 // total marker transform
543                                 tr = marker_item->transform * marker->c2p * tr * transform;
545                                 // get bbox of the marker with that transform
546                                 NRRect marker_bbox;
547                                 sp_item_invoke_bbox (marker_item, &marker_bbox, from_2geom(tr), true);
548                                 // union it with the shape bbox
549                                 nr_rect_d_union (&cbbox, &cbbox, &marker_bbox);
550                             }
551                         }
553                         for (unsigned i = 0; i < 3; i += 2) { // SP_MARKER_LOC and SP_MARKER_LOC_MID
554                             if ( shape->marker[i] && (path_it->size_default() > 1) ) {
555                                 Geom::Path::const_iterator curve_it1 = path_it->begin();      // incoming curve
556                                 Geom::Path::const_iterator curve_it2 = ++(path_it->begin());  // outgoing curve
557                                 while (curve_it2 != path_it->end_default())
558                                 {
559                                     /* Put marker between curve_it1 and curve_it2.
560                                      * Loop to end_default (so including closing segment), because when a path is closed,
561                                      * there should be a midpoint marker between last segment and closing straight line segment */
563                                     SPMarker* marker = SP_MARKER (shape->marker[i]);
564                                     SPItem* marker_item = sp_item_first_item_child (SP_OBJECT (marker));
566                                     Geom::Matrix tr(sp_shape_marker_get_transform(*curve_it1, *curve_it2));
567                                     if (!marker->orient_auto) {
568                                         Geom::Point transl = tr.translation();
569                                         tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(transl);
570                                     }
571                                     if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) {
572                                         tr = Geom::Scale(style->stroke_width.computed) * tr;
573                                     }
575                                     // total marker transform
576                                     tr = marker_item->transform * marker->c2p * tr * transform;
578                                     // get bbox of the marker with that transform
579                                     NRRect marker_bbox;
580                                     sp_item_invoke_bbox (marker_item, &marker_bbox, from_2geom(tr), true);
581                                     // union it with the shape bbox
582                                     nr_rect_d_union (&cbbox, &cbbox, &marker_bbox);
584                                     ++curve_it1;
585                                     ++curve_it2;
586                                 }
587                             }
588                         }
590                         for (unsigned i = 0; i < 4; i += 3) { // SP_MARKER_LOC and SP_MARKER_LOC_END
591                             if ( shape->marker[i] ) {
592                                 SPMarker* marker = SP_MARKER (shape->marker[i]);
593                                 SPItem* marker_item = sp_item_first_item_child (SP_OBJECT (marker));
595                                 /* Get reference to last curve in the path.
596                                  * For moveto-only path, this returns the "closing line segment". */
597                                 unsigned int index = path_it->size_default();
598                                 if (index > 0) {
599                                     index--;
600                                 }
601                                 Geom::Curve const &lastcurve = (*path_it)[index];
603                                 Geom::Matrix tr = sp_shape_marker_get_transform_at_end(lastcurve);
604                                 if (!marker->orient_auto) {
605                                     Geom::Point transl = tr.translation();
606                                     tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(transl);
607                                 }
608                                 if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) {
609                                     tr = Geom::Scale(style->stroke_width.computed) * tr;
610                                 }
612                                 // total marker transform
613                                 tr = marker_item->transform * marker->c2p * tr * transform;
615                                 // get bbox of the marker with that transform
616                                 NRRect marker_bbox;
617                                 sp_item_invoke_bbox (marker_item, &marker_bbox, tr, true);
618                                 // union it with the shape bbox
619                                 nr_rect_d_union (&cbbox, &cbbox, &marker_bbox);
620                             }
621                         }
622                     }
623                 }
624             }
626             // copy our bbox to the variable we're given
627             *bbox = cbbox;
628         }
629     }
632 static void
633 sp_shape_print_invoke_marker_printing(SPObject* obj, Geom::Matrix tr, SPStyle* style, SPPrintContext *ctx) {
634     SPMarker *marker = SP_MARKER(obj);
635     if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) {
636         tr = Geom::Scale(style->stroke_width.computed) * tr;
637     }
639     SPItem* marker_item = sp_item_first_item_child (SP_OBJECT (marker));
640     tr = marker_item->transform * marker->c2p * tr;
642     Geom::Matrix old_tr = marker_item->transform;
643     marker_item->transform = tr;
644     sp_item_invoke_print (marker_item, ctx);
645     marker_item->transform = old_tr;
647 /**
648  * Prepares shape for printing.  Handles printing of comments for printing
649  * debugging, sizes the item to fit into the document width/height,
650  * applies print fill/stroke, sets transforms for markers, and adds
651  * comment labels.
652  */
653 void
654 sp_shape_print (SPItem *item, SPPrintContext *ctx)
656     NRRect pbox, dbox, bbox;
658     SPShape *shape = SP_SHAPE(item);
660     if (!shape->curve) return;
662         Inkscape::Preferences *prefs = Inkscape::Preferences::get();
663         gint add_comments = prefs->getBool("/printing/debug/add-label-comments");
664         if (add_comments) {
665             gchar * comment = g_strdup_printf("begin '%s'",
666                                               SP_OBJECT(item)->defaultLabel());
667             sp_print_comment(ctx, comment);
668             g_free(comment);
669         }
671     /* fixme: Think (Lauris) */
672     sp_item_invoke_bbox(item, &pbox, Geom::identity(), TRUE);
673     dbox.x0 = 0.0;
674     dbox.y0 = 0.0;
675     dbox.x1 = sp_document_width (SP_OBJECT_DOCUMENT (item));
676     dbox.y1 = sp_document_height (SP_OBJECT_DOCUMENT (item));
677     sp_item_bbox_desktop (item, &bbox);
678     Geom::Matrix const i2d(sp_item_i2d_affine(item));
680     SPStyle* style = SP_OBJECT_STYLE (item);
682     if (!style->fill.isNone()) {
683         sp_print_fill (ctx, shape->curve->get_pathvector(), &i2d, style, &pbox, &dbox, &bbox);
684     }
686     if (!style->stroke.isNone()) {
687         sp_print_stroke (ctx, shape->curve->get_pathvector(), &i2d, style, &pbox, &dbox, &bbox);
688     }
690     /* TODO: make code prettier: lots of variables can be taken out of the loop! */
691     Geom::PathVector const & pathv = shape->curve->get_pathvector();
692     for(Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
693         if ( shape->marker[SP_MARKER_LOC_START] || shape->marker[SP_MARKER_LOC]) {
694             Geom::Matrix tr(sp_shape_marker_get_transform_at_start(path_it->front()));
695             if (shape->marker[SP_MARKER_LOC_START]) {
696                 sp_shape_print_invoke_marker_printing(shape->marker[SP_MARKER_LOC_START], tr, style, ctx);
697             }
698             if (shape->marker[SP_MARKER_LOC]) {
699                 sp_shape_print_invoke_marker_printing(shape->marker[SP_MARKER_LOC], tr, style, ctx);
700             }
701         }
703         if ( (shape->marker[SP_MARKER_LOC_MID] || shape->marker[SP_MARKER_LOC]) && (path_it->size_default() > 1) ) {
704             Geom::Path::const_iterator curve_it1 = path_it->begin();      // incoming curve
705             Geom::Path::const_iterator curve_it2 = ++(path_it->begin());  // outgoing curve
706             while (curve_it2 != path_it->end_default())
707             {
708                 /* Put marker between curve_it1 and curve_it2.
709                  * Loop to end_default (so including closing segment), because when a path is closed,
710                  * there should be a midpoint marker between last segment and closing straight line segment */
711                 Geom::Matrix tr(sp_shape_marker_get_transform(*curve_it1, *curve_it2));
713                 if (shape->marker[SP_MARKER_LOC_MID]) {
714                     sp_shape_print_invoke_marker_printing(shape->marker[SP_MARKER_LOC_MID], tr, style, ctx);
715                 }
716                 if (shape->marker[SP_MARKER_LOC]) {
717                     sp_shape_print_invoke_marker_printing(shape->marker[SP_MARKER_LOC], tr, style, ctx);
718                 }
720                 ++curve_it1;
721                 ++curve_it2;
722             }
723         }
725         if ( shape->marker[SP_MARKER_LOC_END] || shape->marker[SP_MARKER_LOC]) {
726             /* Get reference to last curve in the path.
727              * For moveto-only path, this returns the "closing line segment". */
728             unsigned int index = path_it->size_default();
729             if (index > 0) {
730                 index--;
731             }
732             Geom::Curve const &lastcurve = (*path_it)[index];
734             Geom::Matrix tr = sp_shape_marker_get_transform_at_end(lastcurve);
736             if (shape->marker[SP_MARKER_LOC_END]) {
737                 sp_shape_print_invoke_marker_printing(shape->marker[SP_MARKER_LOC_END], tr, style, ctx);
738             }
739             if (shape->marker[SP_MARKER_LOC]) {
740                 sp_shape_print_invoke_marker_printing(shape->marker[SP_MARKER_LOC], tr, style, ctx);
741             }
742         }
743     }
745         if (add_comments) {
746             gchar * comment = g_strdup_printf("end '%s'",
747                                               SP_OBJECT(item)->defaultLabel());
748             sp_print_comment(ctx, comment);
749             g_free(comment);
750         }
753 /**
754  * Sets style, path, and paintbox.  Updates marker views, including dimensions.
755  */
756 static NRArenaItem *
757 sp_shape_show (SPItem *item, NRArena *arena, unsigned int /*key*/, unsigned int /*flags*/)
759     SPObject *object = SP_OBJECT(item);
760     SPShape *shape = SP_SHAPE(item);
762     NRArenaItem *arenaitem = NRArenaShape::create(arena);
763     NRArenaShape * const s = NR_ARENA_SHAPE(arenaitem);
764     nr_arena_shape_set_style(s, object->style);
765     nr_arena_shape_set_path(s, shape->curve, false);
766     Geom::OptRect paintbox = item->getBounds(Geom::identity());
767     if (paintbox) {
768         s->setPaintBox(*paintbox);
769     }
771     /* This stanza checks that an object's marker style agrees with
772      * the marker objects it has allocated.  sp_shape_set_marker ensures
773      * that the appropriate marker objects are present (or absent) to
774      * match the style.
775      */
776     for (int i = 0 ; i < SP_MARKER_LOC_QTY ; i++) {
777         sp_shape_set_marker (object, i, object->style->marker[i].value);
778       }
780     if (sp_shape_has_markers (shape)) {
782         /* provide key and dimension the marker views */
783         if (!arenaitem->key) {
784             NR_ARENA_ITEM_SET_KEY (arenaitem, sp_item_display_key_new (SP_MARKER_LOC_QTY));
785         }
787         for (int i = 0; i < SP_MARKER_LOC_QTY; i++) {
788             if (shape->marker[i]) {
789                 sp_marker_show_dimension ((SPMarker *) shape->marker[i],
790                                           NR_ARENA_ITEM_GET_KEY (arenaitem) + i,
791                                           sp_shape_number_of_markers (shape, i));
792             }
793         }
795         /* Update marker views */
796         sp_shape_update_marker_view (shape, arenaitem);
797     }
799     return arenaitem;
802 /**
803  * Hides/removes marker views from the shape.
804  */
805 static void
806 sp_shape_hide (SPItem *item, unsigned int key)
808     SPShape *shape;
809     SPItemView *v;
810     int i;
812     shape = (SPShape *) item;
814     for (i=0; i<SP_MARKER_LOC_QTY; i++) {
815       if (shape->marker[i]) {
816         for (v = item->display; v != NULL; v = v->next) {
817                 if (key == v->key) {
818           sp_marker_hide ((SPMarker *) shape->marker[i],
819                                     NR_ARENA_ITEM_GET_KEY (v->arenaitem) + i);
820                 }
821         }
822       }
823     }
825     if (((SPItemClass *) parent_class)->hide) {
826       ((SPItemClass *) parent_class)->hide (item, key);
827     }
830 /**
831 * \param shape Shape.
832 * \return TRUE if the shape has any markers, or FALSE if not.
833 */
834 int
835 sp_shape_has_markers (SPShape const *shape)
837     /* Note, we're ignoring 'marker' settings, which technically should apply for
838        all three settings.  This should be fixed later such that if 'marker' is
839        specified, then all three should appear. */
841     return (
842         shape->curve &&
843         (shape->marker[SP_MARKER_LOC] ||
844          shape->marker[SP_MARKER_LOC_START] ||
845          shape->marker[SP_MARKER_LOC_MID] ||
846          shape->marker[SP_MARKER_LOC_END])
847         );
851 /**
852 * \param shape Shape.
853 * \param type Marker type (e.g. SP_MARKER_LOC_START)
854 * \return Number of markers that the shape has of this type.
855 */
856 int
857 sp_shape_number_of_markers (SPShape *shape, int type)
859     Geom::PathVector const & pathv = shape->curve->get_pathvector();
861     switch(type) {
862         case SP_MARKER_LOC:
863         {
864             if ( shape->marker[SP_MARKER_LOC] ) {
865                 guint n = 2*pathv.size();
866                 for(Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
867                     n += path_it->size();
868                     n += path_it->closed() ? 1 : 0;
869                 }
870                 return n;
871             } else {
872                 return 0;
873             }
874         }
875         case SP_MARKER_LOC_START:
876             return shape->marker[SP_MARKER_LOC_START] ? pathv.size() : 0;
878         case SP_MARKER_LOC_MID:
879         {
880             if ( shape->marker[SP_MARKER_LOC_MID] ) {
881             guint n = 0;
882                 for(Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
883                     n += path_it->size();
884                     n += path_it->closed() ? 1 : 0;
885                 }
886                 return n;
887             } else {
888                 return 0;
889             }
890         }
892         case SP_MARKER_LOC_END:
893         {
894             return shape->marker[SP_MARKER_LOC_END] ? pathv.size() : 0;
895         }
897         default:
898             return 0;
899     }
902 /**
903  * Checks if the given marker is used in the shape, and if so, it
904  * releases it by calling sp_marker_hide.  Also detaches signals
905  * and unrefs the marker from the shape.
906  */
907 static void
908 sp_shape_marker_release (SPObject *marker, SPShape *shape)
910     SPItem *item;
911     int i;
913     item = (SPItem *) shape;
915     for (i = 0; i < SP_MARKER_LOC_QTY; i++) {
916         if (marker == shape->marker[i]) {
917             SPItemView *v;
918             /* Hide marker */
919             for (v = item->display; v != NULL; v = v->next) {
920               sp_marker_hide ((SPMarker *) (shape->marker[i]), NR_ARENA_ITEM_GET_KEY (v->arenaitem) + i);
921               /* fixme: Do we need explicit remove here? (Lauris) */
922               /* nr_arena_item_set_mask (v->arenaitem, NULL); */
923             }
924             /* Detach marker */
925             shape->release_connect[i].disconnect();
926             shape->modified_connect[i].disconnect();
927             shape->marker[i] = sp_object_hunref (shape->marker[i], item);
928         }
929     }
932 /**
933  * No-op.  Exists for handling 'modified' messages
934  */
935 static void
936 sp_shape_marker_modified (SPObject */*marker*/, guint /*flags*/, SPItem */*item*/)
938     /* I think mask does update automagically */
939     /* g_warning ("Item %s mask %s modified", SP_OBJECT_ID (item), SP_OBJECT_ID (mask)); */
942 /**
943  * Adds a new marker to shape object at the location indicated by key.  value
944  * must be a valid URI reference resolvable from the shape object (i.e., present
945  * in the document <defs>).  If the shape object already has a marker
946  * registered at the given position, it is removed first.  Then the
947  * new marker is hrefed and its signals connected.
948  */
949 void
950 sp_shape_set_marker (SPObject *object, unsigned int key, const gchar *value)
952     SPItem *item = (SPItem *) object;
953     SPShape *shape = (SPShape *) object;
955     if (key < 0 || key > SP_MARKER_LOC_END) {
956         return;
957     }
959     SPObject *mrk = sp_css_uri_reference_resolve (SP_OBJECT_DOCUMENT (object), value);
960     if (mrk != shape->marker[key]) {
961         if (shape->marker[key]) {
962             SPItemView *v;
964             /* Detach marker */
965             shape->release_connect[key].disconnect();
966             shape->modified_connect[key].disconnect();
968             /* Hide marker */
969             for (v = item->display; v != NULL; v = v->next) {
970                 sp_marker_hide ((SPMarker *) (shape->marker[key]),
971                                 NR_ARENA_ITEM_GET_KEY (v->arenaitem) + key);
972                 /* fixme: Do we need explicit remove here? (Lauris) */
973                 /* nr_arena_item_set_mask (v->arenaitem, NULL); */
974             }
976             /* Unref marker */
977             shape->marker[key] = sp_object_hunref (shape->marker[key], object);
978         }
979         if (SP_IS_MARKER (mrk)) {
980             shape->marker[key] = sp_object_href (mrk, object);
981             shape->release_connect[key] = mrk->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_shape_marker_release), shape));
982             shape->modified_connect[key] = mrk->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_shape_marker_modified), shape));
983         }
984     }
989 /* Shape section */
991 /**
992  * Calls any registered handlers for the set_shape action
993  */
994 void
995 sp_shape_set_shape (SPShape *shape)
997     g_return_if_fail (shape != NULL);
998     g_return_if_fail (SP_IS_SHAPE (shape));
1000     if (SP_SHAPE_CLASS (G_OBJECT_GET_CLASS (shape))->set_shape) {
1001       SP_SHAPE_CLASS (G_OBJECT_GET_CLASS (shape))->set_shape (shape);
1002     }
1005 /**
1006  * Adds a curve to the shape.  If owner is specified, a reference
1007  * will be made, otherwise the curve will be copied into the shape.
1008  * Any existing curve in the shape will be unreferenced first.
1009  * This routine also triggers a request to update the display.
1010  */
1011 void
1012 sp_shape_set_curve (SPShape *shape, SPCurve *curve, unsigned int owner)
1014     if (shape->curve) {
1015         shape->curve = shape->curve->unref();
1016     }
1017     if (curve) {
1018         if (owner) {
1019             shape->curve = curve->ref();
1020         } else {
1021             shape->curve = curve->copy();
1022         }
1023     }
1024         SP_OBJECT(shape)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
1027 /**
1028  * Return duplicate of curve (if any exists) or NULL if there is no curve
1029  */
1030 SPCurve *
1031 sp_shape_get_curve (SPShape *shape)
1033     if (shape->curve) {
1034         return shape->curve->copy();
1035     }
1036     return NULL;
1039 /**
1040  * Same as sp_shape_set_curve but without updating the display
1041  */
1042 void
1043 sp_shape_set_curve_insync (SPShape *shape, SPCurve *curve, unsigned int owner)
1045     if (shape->curve) {
1046         shape->curve = shape->curve->unref();
1047     }
1048     if (curve) {
1049         if (owner) {
1050             shape->curve = curve->ref();
1051         } else {
1052             shape->curve = curve->copy();
1053         }
1054     }
1057 /**
1058  * Return all nodes in a path that are to be considered for snapping
1059  */
1060 static void sp_shape_snappoints(SPItem const *item, SnapPointsIter p, Inkscape::SnapPreferences const *snapprefs)
1062     g_assert(item != NULL);
1063     g_assert(SP_IS_SHAPE(item));
1065     SPShape const *shape = SP_SHAPE(item);
1066     if (shape->curve == NULL) {
1067         return;
1068     }
1070     Geom::PathVector const &pathv = shape->curve->get_pathvector();
1071     if (pathv.empty())
1072         return;
1074     Geom::Matrix const i2d (sp_item_i2d_affine (item));
1076     for(Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
1077         *p = path_it->initialPoint() * i2d;
1079         Geom::Path::const_iterator curve_it1 = path_it->begin();      // incoming curve
1080         Geom::Path::const_iterator curve_it2 = ++(path_it->begin());  // outgoing curve
1081         while (curve_it2 != path_it->end_closed())
1082         {
1083             /* Test whether to add the node between curve_it1 and curve_it2.
1084              * Loop to end_closed (so always including closing segment); the last node to be added
1085              * is the node between the closing segment and the segment before that, regardless
1086              * of the path being closed or not. If the path is closed, the final point was already added by
1087              * adding the initial point. */
1089             Geom::NodeType nodetype = Geom::get_nodetype(*curve_it1, *curve_it2);
1091             // Depending on the snapping preferences, either add only cusp nodes, or add add both cusp and smooth nodes
1092             if (snapprefs->getSnapSmoothNodes() || nodetype == Geom::NODE_NONE || nodetype == Geom::NODE_CUSP) {
1093                 *p = curve_it1->finalPoint() * i2d;
1094             }
1096             // Consider midpoints of line segments for snapping
1097             if (snapprefs->getSnapMidpoints()) {
1098                 if (Geom::LineSegment const* line_segment = dynamic_cast<Geom::LineSegment const*>(&(*curve_it1))) {
1099                     *p = Geom::middle_point(*line_segment) * i2d;
1100                 }
1101             }
1103             ++curve_it1;
1104             ++curve_it2;
1105         }
1107         // Find the internal intersections of each path and consider these for snapping (using "Method 1" as desciribed in Inkscape::ObjectSnapper::_collectNodes())
1108         if (snapprefs->getSnapIntersectionCS()) {
1109             Geom::Crossings cs;
1110             cs = self_crossings(*path_it);
1111             if (cs.size() > 0) { // There might be multiple intersections...
1112                 for (Geom::Crossings::const_iterator i = cs.begin(); i != cs.end(); i++) {
1113                     Geom::Point p_ix = (*path_it).pointAt((*i).ta);
1114                     *p = p_ix * i2d;
1115                 }
1116             }
1117         }
1118     }
1124 /*
1125   Local Variables:
1126   mode:c++
1127   c-file-style:"stroustrup"
1128   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1129   indent-tabs-mode:nil
1130   fill-column:99
1131   End:
1132 */
1133 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :