Code

This is the first c++ification commit from me. It handles sp-line, sp-polyline, sp...
[inkscape.git] / src / sp-shape.cpp
index de564813720785f7671fb1a8b66885bfc7b07a3a..4de6aeb800b58137e9f975d1deadb72121777310 100644 (file)
@@ -50,6 +50,8 @@
 
 #include "util/mathfns.h" // for triangle_area()
 
+#include "splivarot.h" // for bounding box calculation
+
 #define noSHAPE_VERBOSE
 
 static void sp_shape_class_init (SPShapeClass *klass);
@@ -295,7 +297,7 @@ sp_shape_update (SPObject *object, SPCtx *ctx, unsigned int flags)
         /* Dimension marker views */
         for (SPItemView *v = item->display; v != NULL; v = v->next) {
             if (!v->arenaitem->key) {
-                NR_ARENA_ITEM_SET_KEY (v->arenaitem, sp_item_display_key_new (SP_MARKER_LOC_QTY));
+                NR_ARENA_ITEM_SET_KEY (v->arenaitem, SPItem::display_key_new (SP_MARKER_LOC_QTY));
             }
             for (int i = 0 ; i < SP_MARKER_LOC_QTY ; i++) {
                 if (shape->marker[i]) {
@@ -541,166 +543,193 @@ static void sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &
             cbbox.x1 = (*geombbox)[0][1];
             cbbox.y1 = (*geombbox)[1][1];
 
-            if ((SPItem::BBoxType) flags != SPItem::GEOMETRIC_BBOX) {
-
-                SPStyle* style=SP_OBJECT_STYLE (item);
-                if (!style->stroke.isNone()) {
-                    double const scale = transform.descrim();
-                    if ( fabs(style->stroke_width.computed * scale) > 0.01 ) { // sinon c'est 0=oon veut pas de bord
-                        double const width = MAX(0.125, style->stroke_width.computed * scale);
-                        if ( fabs(cbbox.x1-cbbox.x0) > -0.00001 && fabs(cbbox.y1-cbbox.y0) > -0.00001 ) {
-                            cbbox.x0-=0.5*width;
-                            cbbox.x1+=0.5*width;
-                            cbbox.y0-=0.5*width;
-                            cbbox.y1+=0.5*width;
+            switch ((SPItem::BBoxType) flags) {
+                case SPItem::GEOMETRIC_BBOX: {
+                    // do nothing
+                    break;
+                }
+                case SPItem::RENDERING_BBOX: {
+                    // convert the stroke to a path and calculate that path's geometric bbox
+                    SPStyle* style=SP_OBJECT_STYLE (item);
+                    if (!style->stroke.isNone()) {
+                        Geom::PathVector *pathv = item_outline(item);
+                        if (pathv) {
+                            Geom::OptRect geomstrokebbox = bounds_exact_transformed(*pathv, transform);
+                            if (geomstrokebbox) {
+                                NRRect  strokebbox;
+                                strokebbox.x0 = (*geomstrokebbox)[0][0];
+                                strokebbox.y0 = (*geomstrokebbox)[1][0];
+                                strokebbox.x1 = (*geomstrokebbox)[0][1];
+                                strokebbox.y1 = (*geomstrokebbox)[1][1];
+                                nr_rect_d_union (&cbbox, &cbbox, &strokebbox);
+                            }
+                            delete pathv;
                         }
                     }
+                    break;
                 }
-
-                // Union with bboxes of the markers, if any
-                if (sp_shape_has_markers (shape)) {
-                    /** \todo make code prettier! */
-                    Geom::PathVector const & pathv = shape->curve->get_pathvector();
-                    // START marker
-                    for (unsigned i = 0; i < 2; i++) { // SP_MARKER_LOC and SP_MARKER_LOC_START
-                        if ( shape->marker[i] ) {
-                            SPMarker* marker = SP_MARKER (shape->marker[i]);
-                            SPItem* marker_item = sp_item_first_item_child (SP_OBJECT (marker));
-
-                            if (marker_item) {
-                                Geom::Matrix tr(sp_shape_marker_get_transform_at_start(pathv.begin()->front()));
-                                if (!marker->orient_auto) {
-                                    Geom::Point transl = tr.translation();
-                                    tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(transl);
-                                }
-                                if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) {
-                                    tr = Geom::Scale(style->stroke_width.computed) * tr;
-                                }
-
-                                // total marker transform
-                                tr = marker_item->transform * marker->c2p * tr * transform;
-
-                                // get bbox of the marker with that transform
-                                NRRect marker_bbox;
-                                sp_item_invoke_bbox (marker_item, &marker_bbox, from_2geom(tr), true);
-                                // union it with the shape bbox
-                                nr_rect_d_union (&cbbox, &cbbox, &marker_bbox);
+                default:
+                case SPItem::APPROXIMATE_BBOX: {
+                    SPStyle* style=SP_OBJECT_STYLE (item);
+                    if (!style->stroke.isNone()) {
+                        double const scale = transform.descrim();
+                        if ( fabs(style->stroke_width.computed * scale) > 0.01 ) { // sinon c'est 0=oon veut pas de bord
+                            double const width = MAX(0.125, style->stroke_width.computed * scale);
+                            if ( fabs(cbbox.x1-cbbox.x0) > -0.00001 && fabs(cbbox.y1-cbbox.y0) > -0.00001 ) {
+                                cbbox.x0-=0.5*width;
+                                cbbox.x1+=0.5*width;
+                                cbbox.y0-=0.5*width;
+                                cbbox.y1+=0.5*width;
                             }
                         }
                     }
-                    // MID marker
-                    for (unsigned i = 0; i < 3; i += 2) { // SP_MARKER_LOC and SP_MARKER_LOC_MID
-                        SPMarker* marker = SP_MARKER (shape->marker[i]);
-                        if ( !shape->marker[i] ) continue;
-                        SPItem* marker_item = sp_item_first_item_child (SP_OBJECT (marker));
-                        if ( !marker_item ) continue;
-
-                        for(Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
-                            // START position
-                            if ( path_it != pathv.begin() 
-                                 && ! ((path_it == (pathv.end()-1)) && (path_it->size_default() == 0)) ) // if this is the last path and it is a moveto-only, there is no mid marker there
-                            {
-                                Geom::Matrix tr(sp_shape_marker_get_transform_at_start(path_it->front()));
-                                if (!marker->orient_auto) {
-                                    Geom::Point transl = tr.translation();
-                                    tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(transl);
-                                }
-                                if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) {
-                                    tr = Geom::Scale(style->stroke_width.computed) * tr;
-                                }
-                                tr = marker_item->transform * marker->c2p * tr * transform;
-                                NRRect marker_bbox;
-                                sp_item_invoke_bbox (marker_item, &marker_bbox, from_2geom(tr), true);
-                                nr_rect_d_union (&cbbox, &cbbox, &marker_bbox);
-                            }
-                            // MID position
-                            if ( path_it->size_default() > 1) {
-                                Geom::Path::const_iterator curve_it1 = path_it->begin();      // incoming curve
-                                Geom::Path::const_iterator curve_it2 = ++(path_it->begin());  // outgoing curve
-                                while (curve_it2 != path_it->end_default())
-                                {
-                                    /* Put marker between curve_it1 and curve_it2.
-                                     * Loop to end_default (so including closing segment), because when a path is closed,
-                                     * there should be a midpoint marker between last segment and closing straight line segment */
-
-                                    SPMarker* marker = SP_MARKER (shape->marker[i]);
-                                    SPItem* marker_item = sp_item_first_item_child (SP_OBJECT (marker));
-
-                                    if (marker_item) {
-                                        Geom::Matrix tr(sp_shape_marker_get_transform(*curve_it1, *curve_it2));
-                                        if (!marker->orient_auto) {
-                                            Geom::Point transl = tr.translation();
-                                            tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(transl);
-                                        }
-                                        if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) {
-                                            tr = Geom::Scale(style->stroke_width.computed) * tr;
-                                        }
-                                        tr = marker_item->transform * marker->c2p * tr * transform;
-                                        NRRect marker_bbox;
-                                        sp_item_invoke_bbox (marker_item, &marker_bbox, from_2geom(tr), true);
-                                        nr_rect_d_union (&cbbox, &cbbox, &marker_bbox);
+
+                    // Union with bboxes of the markers, if any
+                    if (sp_shape_has_markers (shape)) {
+                        /** \todo make code prettier! */
+                        Geom::PathVector const & pathv = shape->curve->get_pathvector();
+                        // START marker
+                        for (unsigned i = 0; i < 2; i++) { // SP_MARKER_LOC and SP_MARKER_LOC_START
+                            if ( shape->marker[i] ) {
+                                SPMarker* marker = SP_MARKER (shape->marker[i]);
+                                SPItem* marker_item = sp_item_first_item_child (SP_OBJECT (marker));
+
+                                if (marker_item) {
+                                    Geom::Matrix tr(sp_shape_marker_get_transform_at_start(pathv.begin()->front()));
+                                    if (!marker->orient_auto) {
+                                        Geom::Point transl = tr.translation();
+                                        tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(transl);
+                                    }
+                                    if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) {
+                                        tr = Geom::Scale(style->stroke_width.computed) * tr;
                                     }
 
-                                    ++curve_it1;
-                                    ++curve_it2;
-                                }
-                            }
-                            // END position
-                            if ( path_it != (pathv.end()-1) && !path_it->empty()) {
-                                Geom::Curve const &lastcurve = path_it->back_default();
-                                Geom::Matrix tr = sp_shape_marker_get_transform_at_end(lastcurve);
-                                if (!marker->orient_auto) {
-                                    Geom::Point transl = tr.translation();
-                                    tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(transl);
-                                }
-                                if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) {
-                                    tr = Geom::Scale(style->stroke_width.computed) * tr;
+                                    // total marker transform
+                                    tr = marker_item->transform * marker->c2p * tr * transform;
+
+                                    // get bbox of the marker with that transform
+                                    NRRect marker_bbox;
+                                    marker_item->invoke_bbox ( &marker_bbox, from_2geom(tr), true);
+                                    // union it with the shape bbox
+                                    nr_rect_d_union (&cbbox, &cbbox, &marker_bbox);
                                 }
-                                tr = marker_item->transform * marker->c2p * tr * transform;
-                                NRRect marker_bbox;
-                                sp_item_invoke_bbox (marker_item, &marker_bbox, tr, true);
-                                nr_rect_d_union (&cbbox, &cbbox, &marker_bbox);
                             }
                         }
-                    }
-                    // END marker
-                    for (unsigned i = 0; i < 4; i += 3) { // SP_MARKER_LOC and SP_MARKER_LOC_END
-                        if ( shape->marker[i] ) {
+                        // MID marker
+                        for (unsigned i = 0; i < 3; i += 2) { // SP_MARKER_LOC and SP_MARKER_LOC_MID
                             SPMarker* marker = SP_MARKER (shape->marker[i]);
+                            if ( !shape->marker[i] ) continue;
                             SPItem* marker_item = sp_item_first_item_child (SP_OBJECT (marker));
+                            if ( !marker_item ) continue;
 
-                            if (marker_item) {
-                                /* Get reference to last curve in the path.
-                                 * For moveto-only path, this returns the "closing line segment". */
-                                Geom::Path const &path_last = pathv.back();
-                                unsigned int index = path_last.size_default();
-                                if (index > 0) {
-                                    index--;
+                            for(Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
+                                // START position
+                                if ( path_it != pathv.begin() 
+                                     && ! ((path_it == (pathv.end()-1)) && (path_it->size_default() == 0)) ) // if this is the last path and it is a moveto-only, there is no mid marker there
+                                {
+                                    Geom::Matrix tr(sp_shape_marker_get_transform_at_start(path_it->front()));
+                                    if (!marker->orient_auto) {
+                                        Geom::Point transl = tr.translation();
+                                        tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(transl);
+                                    }
+                                    if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) {
+                                        tr = Geom::Scale(style->stroke_width.computed) * tr;
+                                    }
+                                    tr = marker_item->transform * marker->c2p * tr * transform;
+                                    NRRect marker_bbox;
+                                    marker_item->invoke_bbox ( &marker_bbox, from_2geom(tr), true);
+                                    nr_rect_d_union (&cbbox, &cbbox, &marker_bbox);
                                 }
-                                Geom::Curve const &lastcurve = path_last[index];
+                                // MID position
+                                if ( path_it->size_default() > 1) {
+                                    Geom::Path::const_iterator curve_it1 = path_it->begin();      // incoming curve
+                                    Geom::Path::const_iterator curve_it2 = ++(path_it->begin());  // outgoing curve
+                                    while (curve_it2 != path_it->end_default())
+                                    {
+                                        /* Put marker between curve_it1 and curve_it2.
+                                         * Loop to end_default (so including closing segment), because when a path is closed,
+                                         * there should be a midpoint marker between last segment and closing straight line segment */
+
+                                        SPMarker* marker = SP_MARKER (shape->marker[i]);
+                                        SPItem* marker_item = sp_item_first_item_child (SP_OBJECT (marker));
+
+                                        if (marker_item) {
+                                            Geom::Matrix tr(sp_shape_marker_get_transform(*curve_it1, *curve_it2));
+                                            if (!marker->orient_auto) {
+                                                Geom::Point transl = tr.translation();
+                                                tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(transl);
+                                            }
+                                            if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) {
+                                                tr = Geom::Scale(style->stroke_width.computed) * tr;
+                                            }
+                                            tr = marker_item->transform * marker->c2p * tr * transform;
+                                            NRRect marker_bbox;
+                                            marker_item->invoke_bbox ( &marker_bbox, from_2geom(tr), true);
+                                            nr_rect_d_union (&cbbox, &cbbox, &marker_bbox);
+                                        }
 
-                                Geom::Matrix tr = sp_shape_marker_get_transform_at_end(lastcurve);
-                                if (!marker->orient_auto) {
-                                    Geom::Point transl = tr.translation();
-                                    tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(transl);
+                                        ++curve_it1;
+                                        ++curve_it2;
+                                    }
                                 }
-                                if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) {
-                                    tr = Geom::Scale(style->stroke_width.computed) * tr;
+                                // END position
+                                if ( path_it != (pathv.end()-1) && !path_it->empty()) {
+                                    Geom::Curve const &lastcurve = path_it->back_default();
+                                    Geom::Matrix tr = sp_shape_marker_get_transform_at_end(lastcurve);
+                                    if (!marker->orient_auto) {
+                                        Geom::Point transl = tr.translation();
+                                        tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(transl);
+                                    }
+                                    if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) {
+                                        tr = Geom::Scale(style->stroke_width.computed) * tr;
+                                    }
+                                    tr = marker_item->transform * marker->c2p * tr * transform;
+                                    NRRect marker_bbox;
+                                    marker_item->invoke_bbox ( &marker_bbox, tr, true);
+                                    nr_rect_d_union (&cbbox, &cbbox, &marker_bbox);
                                 }
+                            }
+                        }
+                        // END marker
+                        for (unsigned i = 0; i < 4; i += 3) { // SP_MARKER_LOC and SP_MARKER_LOC_END
+                            if ( shape->marker[i] ) {
+                                SPMarker* marker = SP_MARKER (shape->marker[i]);
+                                SPItem* marker_item = sp_item_first_item_child (SP_OBJECT (marker));
+
+                                if (marker_item) {
+                                    /* Get reference to last curve in the path.
+                                     * For moveto-only path, this returns the "closing line segment". */
+                                    Geom::Path const &path_last = pathv.back();
+                                    unsigned int index = path_last.size_default();
+                                    if (index > 0) {
+                                        index--;
+                                    }
+                                    Geom::Curve const &lastcurve = path_last[index];
+
+                                    Geom::Matrix tr = sp_shape_marker_get_transform_at_end(lastcurve);
+                                    if (!marker->orient_auto) {
+                                        Geom::Point transl = tr.translation();
+                                        tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(transl);
+                                    }
+                                    if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) {
+                                        tr = Geom::Scale(style->stroke_width.computed) * tr;
+                                    }
 
-                                // total marker transform
-                                tr = marker_item->transform * marker->c2p * tr * transform;
+                                    // total marker transform
+                                    tr = marker_item->transform * marker->c2p * tr * transform;
 
-                                // get bbox of the marker with that transform
-                                NRRect marker_bbox;
-                                sp_item_invoke_bbox (marker_item, &marker_bbox, tr, true);
-                                // union it with the shape bbox
-                                nr_rect_d_union (&cbbox, &cbbox, &marker_bbox);
+                                    // get bbox of the marker with that transform
+                                    NRRect marker_bbox;
+                                    marker_item->invoke_bbox ( &marker_bbox, tr, true);
+                                    // union it with the shape bbox
+                                    nr_rect_d_union (&cbbox, &cbbox, &marker_bbox);
+                                }
                             }
                         }
                     }
-                }
-            }
+                    break;
+                } // end case approximate bbox type 
+            }  // end switch bboxtype
 
             // copy our bbox to the variable we're given
             *bbox = cbbox;
@@ -720,7 +749,7 @@ sp_shape_print_invoke_marker_printing(SPObject* obj, Geom::Matrix tr, SPStyle* s
 
     Geom::Matrix old_tr = marker_item->transform;
     marker_item->transform = tr;
-    sp_item_invoke_print (marker_item, ctx);
+    marker_item->invoke_print (ctx);
     marker_item->transform = old_tr;
 }
 /**
@@ -748,13 +777,13 @@ sp_shape_print (SPItem *item, SPPrintContext *ctx)
         }
 
     /* fixme: Think (Lauris) */
-    sp_item_invoke_bbox(item, &pbox, Geom::identity(), TRUE);
+    item->invoke_bbox( &pbox, Geom::identity(), TRUE);
     dbox.x0 = 0.0;
     dbox.y0 = 0.0;
     dbox.x1 = sp_document_width (SP_OBJECT_DOCUMENT (item));
     dbox.y1 = sp_document_height (SP_OBJECT_DOCUMENT (item));
-    sp_item_bbox_desktop (item, &bbox);
-    Geom::Matrix const i2d(sp_item_i2d_affine(item));
+    item->getBboxDesktop (&bbox);
+    Geom::Matrix const i2d(item->i2d_affine());
 
     SPStyle* style = SP_OBJECT_STYLE (item);
 
@@ -870,7 +899,7 @@ sp_shape_show (SPItem *item, NRArena *arena, unsigned int /*key*/, unsigned int
 
         /* provide key and dimension the marker views */
         if (!arenaitem->key) {
-            NR_ARENA_ITEM_SET_KEY (arenaitem, sp_item_display_key_new (SP_MARKER_LOC_QTY));
+            NR_ARENA_ITEM_SET_KEY (arenaitem, SPItem::display_key_new (SP_MARKER_LOC_QTY));
         }
 
         for (int i = 0; i < SP_MARKER_LOC_QTY; i++) {
@@ -1168,10 +1197,10 @@ static void sp_shape_snappoints(SPItem const *item, std::vector<Inkscape::SnapCa
     if (pathv.empty())
         return;
 
-    Geom::Matrix const i2d (sp_item_i2d_affine (item));
+    Geom::Matrix const i2d (item->i2d_affine ());
 
     if (snapprefs->getSnapObjectMidpoints()) {
-        Geom::OptRect bbox = item->getBounds(sp_item_i2d_affine(item));
+        Geom::OptRect bbox = item->getBounds(item->i2d_affine());
         if (bbox) {
             p.push_back(Inkscape::SnapCandidatePoint(bbox->midpoint(), Inkscape::SNAPSOURCE_OBJECT_MIDPOINT, Inkscape::SNAPTARGET_OBJECT_MIDPOINT));
         }
@@ -1198,7 +1227,24 @@ static void sp_shape_snappoints(SPItem const *item, std::vector<Inkscape::SnapCa
             bool c2 = snapprefs->getSnapSmoothNodes() && (nodetype == Geom::NODE_SMOOTH || nodetype == Geom::NODE_SYMM);
 
             if (c1 || c2) {
-                p.push_back(Inkscape::SnapCandidatePoint(curve_it1->finalPoint() * i2d, Inkscape::SNAPSOURCE_NODE_CUSP, Inkscape::SNAPTARGET_NODE_CUSP));
+                Inkscape::SnapSourceType sst;
+                Inkscape::SnapTargetType stt;
+                switch (nodetype) {
+                case Geom::NODE_CUSP:
+                    sst = Inkscape::SNAPSOURCE_NODE_CUSP;
+                    stt = Inkscape::SNAPTARGET_NODE_CUSP;
+                    break;
+                case Geom::NODE_SMOOTH:
+                case Geom::NODE_SYMM:
+                    sst = Inkscape::SNAPSOURCE_NODE_SMOOTH;
+                    stt = Inkscape::SNAPTARGET_NODE_SMOOTH;
+                    break;
+                default:
+                    sst = Inkscape::SNAPSOURCE_UNDEFINED;
+                    stt = Inkscape::SNAPTARGET_UNDEFINED;
+                    break;
+                }
+                p.push_back(Inkscape::SnapCandidatePoint(curve_it1->finalPoint() * i2d, sst, stt));
             }
 
             // Consider midpoints of line segments for snapping