From 484ca6397408146e58884063e54cd4f92ad5c79f Mon Sep 17 00:00:00 2001 From: dvlierop2 Date: Sun, 8 Apr 2007 21:07:29 +0000 Subject: [PATCH] Changes to the selector tool, e.g. option to choose either APPROXIMATE_BBOX or GEOMETRIC_BBOX --- src/selection.cpp | 18 ++--- src/selection.h | 9 ++- src/seltrans.cpp | 201 +++++++++++++++++++++++++++++----------------- src/seltrans.h | 9 ++- src/sp-item.cpp | 12 +-- src/sp-item.h | 6 +- src/sp-shape.cpp | 1 + 7 files changed, 159 insertions(+), 97 deletions(-) diff --git a/src/selection.cpp b/src/selection.cpp index 05bd8d030..44f601362 100644 --- a/src/selection.cpp +++ b/src/selection.cpp @@ -304,25 +304,25 @@ Inkscape::XML::Node *Selection::singleRepr() { return obj ? SP_OBJECT_REPR(obj) : NULL; } -NRRect *Selection::bounds(NRRect *bbox) const +NRRect *Selection::bounds(NRRect *bbox, SPItem::BBoxType type) const { g_return_val_if_fail (bbox != NULL, NULL); - *bbox = NRRect(bounds()); + *bbox = NRRect(bounds(type)); return bbox; } -NR::Maybe Selection::bounds() const +NR::Maybe Selection::bounds(SPItem::BBoxType type) const { GSList const *items = const_cast(this)->itemList(); NR::Maybe bbox = NR::Nothing(); for ( GSList const *i = items ; i != NULL ; i = i->next ) { - bbox = NR::union_bounds(bbox, sp_item_bbox_desktop(SP_ITEM(i->data))); + bbox = NR::union_bounds(bbox, sp_item_bbox_desktop(SP_ITEM(i->data), type)); } return bbox; } -NRRect *Selection::boundsInDocument(NRRect *bbox) const { +NRRect *Selection::boundsInDocument(NRRect *bbox, SPItem::BBoxType type) const { g_return_val_if_fail (bbox != NULL, NULL); GSList const *items=const_cast(this)->itemList(); @@ -336,16 +336,16 @@ NRRect *Selection::boundsInDocument(NRRect *bbox) const { for ( GSList const *iter=items ; iter != NULL ; iter = iter->next ) { SPItem *item=SP_ITEM(iter->data); - NR::Matrix const i2doc(sp_item_i2doc_affine(item)); - sp_item_invoke_bbox(item, bbox, i2doc, FALSE); + NR::Matrix i2doc(sp_item_i2doc_affine(item)); + sp_item_invoke_bbox(item, bbox, i2doc, FALSE, type); } return bbox; } -NR::Maybe Selection::boundsInDocument() const { +NR::Maybe Selection::boundsInDocument(SPItem::BBoxType type) const { NRRect r; - return boundsInDocument(&r)->upgrade(); + return boundsInDocument(&r, type)->upgrade(); } /** Extract the position of the center from the first selected object */ diff --git a/src/selection.h b/src/selection.h index 34de82c7c..d8427108f 100644 --- a/src/selection.h +++ b/src/selection.h @@ -28,6 +28,7 @@ #include "gc-anchored.h" #include "gc-soft-ptr.h" #include "util/list.h" +#include "sp-item.h" class SPItem; @@ -231,23 +232,23 @@ public: guint numberOfParents(); /** @brief Returns the bounding rectangle of the selection */ - NRRect *bounds(NRRect *dest) const; + NRRect *bounds(NRRect *dest, SPItem::BBoxType type = SPItem::APPROXIMATE_BBOX) const; /** @brief Returns the bounding rectangle of the selection */ - NR::Maybe bounds() const; + NR::Maybe bounds(SPItem::BBoxType type = SPItem::APPROXIMATE_BBOX) const; /** * @brief Returns the bounding rectangle of the selection * * \todo how is this different from bounds()? */ - NRRect *boundsInDocument(NRRect *dest) const; + NRRect *boundsInDocument(NRRect *dest, SPItem::BBoxType type = SPItem::APPROXIMATE_BBOX) const; /** * @brief Returns the bounding rectangle of the selection * * \todo how is this different from bounds()? */ - NR::Maybe boundsInDocument() const; + NR::Maybe boundsInDocument(SPItem::BBoxType type = SPItem::APPROXIMATE_BBOX) const; /** * @brief Returns the rotation/skew center of the selection diff --git a/src/seltrans.cpp b/src/seltrans.cpp index f62e18ac2..52afc0e14 100644 --- a/src/seltrans.cpp +++ b/src/seltrans.cpp @@ -88,11 +88,15 @@ Inkscape::SelTrans::SelTrans(SPDesktop *desktop) : _show(SHOW_CONTENT), _grabbed(false), _show_handles(true), - _box(NR::Nothing()), + _bbox(NR::Nothing()), + _approximate_bbox(NR::Nothing()), _chandle(NULL), _stamp_cache(NULL), _message_context(desktop->messageStack()) { + //_snap_bbox_type = SPItem::GEOMETRIC_BBOX; //TODO: Get this parameter from UI; hardcoded for the time being + _snap_bbox_type = SPItem::APPROXIMATE_BBOX; + g_return_if_fail(desktop != NULL); for (int i = 0; i < 8; i++) { @@ -108,6 +112,8 @@ Inkscape::SelTrans::SelTrans(SPDesktop *desktop) : _updateHandles(); _selection = sp_desktop_selection(desktop); + + _norm = sp_canvas_item_new(sp_desktop_controls(desktop), SP_TYPE_CTRL, @@ -254,56 +260,70 @@ void Inkscape::SelTrans::grab(NR::Point const &p, gdouble x, gdouble y, bool sho _current.set_identity(); _point = p; + + // The selector tool should snap the bbox and the special snappoints, but not path nodes + // (The special points are the handles, center, rotation axis, font baseline, ends of spiral, etc.) - _snap_points = selection->getSnapPoints(); + // First, get all special points for snapping + _snap_points = selection->getSnapPoints(); // Excludes path nodes + std::vector snap_points_hull = selection->getSnapPointsConvexHull(); // Includes path nodes if (_snap_points.size() > 100) { /* Snapping a huge number of nodes will take way too long, so limit the number of snappable nodes An average user would rarely ever try to snap such a large number of nodes anyway, because (s)he could hardly discern which node would be snapping */ - _snap_points = selection->getSnapPointsConvexHull(); + _snap_points = snap_points_hull; // Unfortunately, by now we will have lost the font-baseline snappoints :-( } - _box = selection->bounds(); - _bbox_points.clear(); - if (_box) { - for ( unsigned i = 0 ; i < 4 ; i++ ) { - _bbox_points.push_back(_box->corner(i)); + + // Find bbox hulling all special points, which excludes stroke width. Here we need to include the + // path nodes, for example because a rectangle which has been converted to a path doesn't have + // any other special points + NR::Rect snap_points_bbox; + if ( snap_points_hull.empty() == false ) { + std::vector::iterator i = snap_points_hull.begin(); + snap_points_bbox = NR::Rect(*i, *i); + i++; + while (i != snap_points_hull.end()) { + snap_points_bbox.expandTo(*i); + i++; } } - - gchar const *scale_origin = prefs_get_string_attribute("tools.select", "scale_origin"); - bool const origin_on_bbox = (scale_origin == NULL || !strcmp(scale_origin, "bbox")); - - /*Snapping will be to either nodes or to boundingbox-cornes; each will require its own origin, which - is only slightly different from the other. When we would use an origin at one of the nodes while - trying to snap the boundingbox, all four points of the boundingbox would be moving (e.g. during stretching), - and would therefore also be snapping (which is bad). This leads to bugs similar to #1540195, in which - a box is caught between to guides. To solve this, we need two different points: _opposite_for_snappoints and - _opposite_for_boundingbox - */ + // Next, determine the bounding box for snapping ... + _bbox = selection->bounds(_snap_bbox_type); - if (_box) { - _opposite_for_bboxpoints = _box->min() + _box->dimensions() * NR::scale(1-x, 1-y); - - NR::Rect op_box = *_box; - // FIXME: should be using ConvexHull here - if ( _snap_points.empty() == false) { - std::vector::iterator i = _snap_points.begin(); - op_box = NR::Rect(*i, *i); - i++; - while (i != _snap_points.end()) { - op_box.expandTo(*i); - i++; - } + _approximate_bbox = selection->bounds(SPItem::APPROXIMATE_BBOX); // Used for correctly scaling the strokewidth + + _bbox_points.clear(); + if (_bbox) { + // ... and add the bbox corners to _bbox_points + for ( unsigned i = 0 ; i < 4 ; i++ ) { + _bbox_points.push_back(_bbox->corner(i)); } - _opposite_for_snappoints = ( op_box.min() + ( op_box.dimensions() * NR::scale(1-x, 1-y) ) ); - //until we can kick out the old _opposite, and use _opposite_for_bboxpoints or _opposite_for_snappoints everywhere - //keep the old behavior for _opposite: - _opposite = origin_on_bbox ? _opposite_for_bboxpoints : _opposite_for_snappoints; - //FIXME: get rid of _opposite. Requires different handling of preferences, see Bulia Byak's comment for bug #1540195 + // There are two separate "opposites" (i.e. opposite w.r.t. the handle being dragged): + // - one for snapping the boundingbox, which can be either visual or geometric + // - one for snapping the special points + // The "opposite" in case of a geometric boundingbox always coincides with the "opposite" for the special points + // These distinct "opposites" are needed in the snapmanager to avoid bugs such as #1540195 (in which + // a box is caught between to guides) + _opposite_for_bboxpoints = _bbox->min() + _bbox->dimensions() * NR::scale(1-x, 1-y); + _opposite_for_specpoints = (snap_points_bbox.min() + (snap_points_bbox.dimensions() * NR::scale(1-x, 1-y) ) ); + // Only a single "opposite" can be used in calculating transformations. + _opposite = _opposite_for_bboxpoints; } + /*std::cout << "Number of snap points: " << _snap_points.size() << std::endl; + for (std::vector::const_iterator i = _snap_points.begin(); i != _snap_points.end(); i++) + { + std::cout << " " << *i << std::endl; + } + + std::cout << "Number of bbox points: " << _bbox_points.size() << std::endl; + for (std::vector::const_iterator i = _bbox_points.begin(); i != _bbox_points.end(); i++) + { + std::cout << " " << *i << std::endl; + }*/ + if ((x != -1) && (y != -1)) { sp_canvas_item_show(_norm); sp_canvas_item_show(_grip); @@ -333,11 +353,11 @@ void Inkscape::SelTrans::transform(NR::Matrix const &rel_affine, NR::Point const sp_item_set_i2d_affine(&item, prev_transform * affine); } } else { - if (_box) { + if (_bbox) { NR::Point p[4]; /* update the outline */ for (unsigned i = 0 ; i < 4 ; i++) { - p[i] = _box->corner(i) * affine; + p[i] = _bbox->corner(i) * affine; } for (unsigned i = 0 ; i < 4 ; i++) { sp_ctrlline_set_coords(SP_CTRLLINE(_l[i]), p[i], p[(i+1)%4]); @@ -577,8 +597,31 @@ void Inkscape::SelTrans::_updateVolatileState() return; } - _box = selection->bounds(); - if (!_box) { + // First, get all special points for snapping + std::vector snap_points_hull = selection->getSnapPointsConvexHull(); // Includes path nodes + // Find bbox hulling all special points, which excludes stroke width. Here we need to include the + // path nodes, for example because a rectangle which has been converted to a path doesn't have + // any other special points + NR::Rect snap_points_bbox; + if ( snap_points_hull.empty() == false ) { + std::vector::iterator i = snap_points_hull.begin(); + snap_points_bbox = NR::Rect(*i, *i); + i++; + while (i != snap_points_hull.end()) { + snap_points_bbox.expandTo(*i); + i++; + } + } + + // Next, determine the bounding box for snapping ... + _bbox = selection->bounds(_snap_bbox_type); + _approximate_bbox = selection->bounds(SPItem::APPROXIMATE_BBOX); + + /*std::cout << "Approximate BBox: " << _approximate_bbox->min() << " - " << _approximate_bbox->max() << std::endl; + std::cout << "Geometric BBox: " << selection->bounds(SPItem::GEOMETRIC_BBOX)->min() << " - " << selection->bounds(SPItem::GEOMETRIC_BBOX)->max() << std::endl; + */ + + if (!_bbox) { _empty = true; return; } @@ -627,9 +670,9 @@ void Inkscape::SelTrans::_showHandles(SPKnot *knot[], SPSelTransHandle const han NR::Point const handle_pt(handle[i].x, handle[i].y); // shouldn't have nullary bbox, but knots - g_assert(_box); - NR::Point p( _box->min() - + ( _box->dimensions() + g_assert(_bbox); + NR::Point p( _bbox->min() + + ( _bbox->dimensions() * NR::scale(handle_pt) ) ); sp_knot_moveto(knot[i], &p); @@ -749,11 +792,11 @@ gboolean Inkscape::SelTrans::handleRequest(SPKnot *knot, NR::Point *position, gu if ((!(state & GDK_SHIFT_MASK) == !(_state == STATE_ROTATE)) && (&handle != &handle_center)) { _origin = _opposite; _origin_for_bboxpoints = _opposite_for_bboxpoints; - _origin_for_snappoints = _opposite_for_snappoints; + _origin_for_specpoints = _opposite_for_specpoints; } else if (_center) { _origin = *_center; _origin_for_bboxpoints = *_center; - _origin_for_snappoints = *_center; + _origin_for_specpoints = *_center; } else { // FIXME return TRUE; @@ -876,7 +919,7 @@ gboolean Inkscape::SelTrans::scaleRequest(NR::Point &pt, guint state) // Snap along a suitable constraint vector from the origin. // The inclination of the constraint vector is calculated from the aspect ratio - NR::Point bbox_dim = _box->dimensions(); + NR::Point bbox_dim = _bbox->dimensions(); double const aspect_ratio = bbox_dim[1] / bbox_dim[0]; // = height / width // Determine direction of the constraint vector @@ -895,9 +938,9 @@ gboolean Inkscape::SelTrans::scaleRequest(NR::Point &pt, guint state) std::pair sn = m.constrainedSnapScale(Snapper::SNAP_POINT, _snap_points, it, - Snapper::ConstraintLine(_origin_for_snappoints, cv), + Snapper::ConstraintLine(_origin_for_specpoints, cv), s, - _origin_for_snappoints); + _origin_for_specpoints); if (bb.second == false && sn.second == false) { /* We didn't snap, so just keep the locked aspect ratio */ @@ -922,7 +965,7 @@ gboolean Inkscape::SelTrans::scaleRequest(NR::Point &pt, guint state) _snap_points, it, s, - _origin_for_snappoints); + _origin_for_specpoints); /* Pick the snap that puts us closest to the original scale */ NR::Coord bd = bb.second ? @@ -1009,7 +1052,7 @@ gboolean Inkscape::SelTrans::stretchRequest(SPSelTransHandle const &handle, NR:: _snap_points, it, s[axis], - _origin_for_snappoints, + _origin_for_specpoints, axis, true); @@ -1035,7 +1078,7 @@ gboolean Inkscape::SelTrans::stretchRequest(SPSelTransHandle const &handle, NR:: _snap_points, it, s[axis], - _origin_for_snappoints, + _origin_for_specpoints, axis, false); @@ -1122,7 +1165,7 @@ gboolean Inkscape::SelTrans::skewRequest(SPSelTransHandle const &handle, NR::Poi _snap_points, std::list(), skew[dim_a], - _origin_for_snappoints, + _origin_for_specpoints, dim_b); if (bb.second || sn.second) { @@ -1214,21 +1257,21 @@ gboolean Inkscape::SelTrans::centerRequest(NR::Point &pt, guint state) } } - if ( !(state & GDK_SHIFT_MASK) && _box ) { + if ( !(state & GDK_SHIFT_MASK) && _bbox ) { // screen pixels to snap center to bbox #define SNAP_DIST 5 // FIXME: take from prefs double snap_dist = SNAP_DIST / _desktop->current_zoom(); for (int i = 0; i < 2; i++) { - if (fabs(pt[i] - _box->min()[i]) < snap_dist) { - pt[i] = _box->min()[i]; + if (fabs(pt[i] - _bbox->min()[i]) < snap_dist) { + pt[i] = _bbox->min()[i]; } - if (fabs(pt[i] - _box->midpoint()[i]) < snap_dist) { - pt[i] = _box->midpoint()[i]; + if (fabs(pt[i] - _bbox->midpoint()[i]) < snap_dist) { + pt[i] = _bbox->midpoint()[i]; } - if (fabs(pt[i] - _box->max()[i]) < snap_dist) { - pt[i] = _box->max()[i]; + if (fabs(pt[i] - _bbox->max()[i]) < snap_dist) { + pt[i] = _bbox->max()[i]; } } } @@ -1308,23 +1351,30 @@ void Inkscape::SelTrans::stretch(SPSelTransHandle const &handle, NR::Point &pt, s[!dim] = fabs(s[dim]); } - if (!_box) { + if (!_bbox) { return; } - NR::Point new_bbox_min = _box->min() * (NR::translate(-scale_origin) * NR::Matrix(s) * NR::translate(scale_origin)); - NR::Point new_bbox_max = _box->max() * (NR::translate(-scale_origin) * NR::Matrix(s) * NR::translate(scale_origin)); + NR::Point new_bbox_min = _approximate_bbox->min() * (NR::translate(-scale_origin) * NR::Matrix(s) * NR::translate(scale_origin)); + NR::Point new_bbox_max = _approximate_bbox->max() * (NR::translate(-scale_origin) * NR::Matrix(s) * NR::translate(scale_origin)); - int transform_stroke = prefs_get_int_attribute ("options.transform", "stroke", 1); - NR::Matrix scaler = get_scale_transform_with_stroke (*_box, _strokewidth, transform_stroke, - new_bbox_min[NR::X], new_bbox_min[NR::Y], new_bbox_max[NR::X], new_bbox_max[NR::Y]); + int transform_stroke = false; + gdouble strokewidth = 0; + + if ( _snap_bbox_type != SPItem::GEOMETRIC_BBOX) { + transform_stroke = prefs_get_int_attribute ("options.transform", "stroke", 1); + strokewidth = _strokewidth; + } + + NR::Matrix scaler = get_scale_transform_with_stroke (*_approximate_bbox, strokewidth, transform_stroke, + new_bbox_min[NR::X], new_bbox_min[NR::Y], new_bbox_max[NR::X], new_bbox_max[NR::Y]); transform(scaler, NR::Point(0, 0)); // we have already accounted for origin, so pass 0,0 } void Inkscape::SelTrans::scale(NR::Point &pt, guint state) { - if (!_box) { + if (!_bbox) { return; } @@ -1337,13 +1387,20 @@ void Inkscape::SelTrans::scale(NR::Point &pt, guint state) if (fabs(s[i]) < 1e-9) s[i] = 1e-9; } - NR::Point new_bbox_min = _box->min() * (NR::translate(-_origin) * NR::Matrix(s) * NR::translate(_origin)); - NR::Point new_bbox_max = _box->max() * (NR::translate(-_origin) * NR::Matrix(s) * NR::translate(_origin)); + NR::Point new_bbox_min = _approximate_bbox->min() * (NR::translate(-_origin) * NR::Matrix(s) * NR::translate(_origin)); + NR::Point new_bbox_max = _approximate_bbox->max() * (NR::translate(-_origin) * NR::Matrix(s) * NR::translate(_origin)); - int transform_stroke = prefs_get_int_attribute ("options.transform", "stroke", 1); - NR::Matrix scaler = get_scale_transform_with_stroke (*_box, _strokewidth, transform_stroke, - new_bbox_min[NR::X], new_bbox_min[NR::Y], new_bbox_max[NR::X], new_bbox_max[NR::Y]); + int transform_stroke = false; + gdouble strokewidth = 0; + if ( _snap_bbox_type != SPItem::GEOMETRIC_BBOX) { + transform_stroke = prefs_get_int_attribute ("options.transform", "stroke", 1); + strokewidth = _strokewidth; + } + + NR::Matrix scaler = get_scale_transform_with_stroke (*_approximate_bbox, strokewidth, transform_stroke, + new_bbox_min[NR::X], new_bbox_min[NR::Y], new_bbox_max[NR::X], new_bbox_max[NR::Y]); + transform(scaler, NR::Point(0, 0)); // we have already accounted for origin, so pass 0,0 } diff --git a/src/seltrans.h b/src/seltrans.h index df4b4d77b..74734cdd8 100644 --- a/src/seltrans.h +++ b/src/seltrans.h @@ -117,14 +117,17 @@ private: bool _empty; bool _changed; - NR::Maybe _box; + SPItem::BBoxType _snap_bbox_type; + + NR::Maybe _bbox; + NR::Maybe _approximate_bbox; gdouble _strokewidth; NR::Matrix _current; NR::Point _opposite; ///< opposite point to where a scale is taking place - NR::Point _opposite_for_snappoints; + NR::Point _opposite_for_specpoints; NR::Point _opposite_for_bboxpoints; - NR::Point _origin_for_snappoints; + NR::Point _origin_for_specpoints; NR::Point _origin_for_bboxpoints; NR::Maybe _center; diff --git a/src/sp-item.cpp b/src/sp-item.cpp index ab1f6e242..5858f5d4e 100644 --- a/src/sp-item.cpp +++ b/src/sp-item.cpp @@ -674,9 +674,9 @@ NR::Maybe SPItem::getBounds(NR::Matrix const &transform, } void -sp_item_invoke_bbox(SPItem const *item, NRRect *bbox, NR::Matrix const &transform, unsigned const clear) +sp_item_invoke_bbox(SPItem const *item, NRRect *bbox, NR::Matrix const &transform, unsigned const clear, SPItem::BBoxType type) { - sp_item_invoke_bbox_full(item, bbox, transform, 0, clear); + sp_item_invoke_bbox_full(item, bbox, transform, type, clear); } /** Calls \a item's subclass' bounding box method; clips it by the bbox of clippath, if any; and @@ -743,19 +743,19 @@ unsigned sp_item_pos_in_parent(SPItem *item) } void -sp_item_bbox_desktop(SPItem *item, NRRect *bbox) +sp_item_bbox_desktop(SPItem *item, NRRect *bbox, SPItem::BBoxType type) { g_assert(item != NULL); g_assert(SP_IS_ITEM(item)); g_assert(bbox != NULL); - sp_item_invoke_bbox(item, bbox, sp_item_i2d_affine(item), TRUE); + sp_item_invoke_bbox(item, bbox, sp_item_i2d_affine(item), TRUE, type); } -NR::Maybe sp_item_bbox_desktop(SPItem *item) +NR::Maybe sp_item_bbox_desktop(SPItem *item, SPItem::BBoxType type) { NRRect ret; - sp_item_invoke_bbox(item, &ret, sp_item_i2d_affine(item), TRUE); + sp_item_invoke_bbox(item, &ret, sp_item_i2d_affine(item), TRUE, type); return ret.upgrade(); } diff --git a/src/sp-item.h b/src/sp-item.h index 9359763b5..89a74ceaf 100644 --- a/src/sp-item.h +++ b/src/sp-item.h @@ -207,7 +207,7 @@ struct SPItemClass { /* Methods */ -void sp_item_invoke_bbox(SPItem const *item, NRRect *bbox, NR::Matrix const &transform, unsigned const clear); +void sp_item_invoke_bbox(SPItem const *item, NRRect *bbox, NR::Matrix const &transform, unsigned const clear, SPItem::BBoxType type = SPItem::APPROXIMATE_BBOX); void sp_item_invoke_bbox_full(SPItem const *item, NRRect *bbox, NR::Matrix const &transform, unsigned const flags, unsigned const clear); unsigned sp_item_pos_in_parent(SPItem *item); @@ -239,8 +239,8 @@ gint sp_item_event (SPItem *item, SPEvent *event); NRArenaItem *sp_item_get_arenaitem(SPItem *item, unsigned int key); -void sp_item_bbox_desktop(SPItem *item, NRRect *bbox) __attribute__ ((deprecated)); -NR::Maybe sp_item_bbox_desktop(SPItem *item); +void sp_item_bbox_desktop(SPItem *item, NRRect *bbox, SPItem::BBoxType type = SPItem::APPROXIMATE_BBOX) __attribute__ ((deprecated)); +NR::Maybe sp_item_bbox_desktop(SPItem *item, SPItem::BBoxType type = SPItem::APPROXIMATE_BBOX); NR::Matrix i2anc_affine(SPObject const *item, SPObject const *ancestor); NR::Matrix i2i_affine(SPObject const *src, SPObject const *dest); diff --git a/src/sp-shape.cpp b/src/sp-shape.cpp index 55dfe6549..8d9b2296a 100644 --- a/src/sp-shape.cpp +++ b/src/sp-shape.cpp @@ -619,6 +619,7 @@ static void sp_shape_bbox(SPItem const *item, NRRect *bbox, NR::Matrix const &tr nr_path_matrix_bbox_union(&bp, transform, &cbbox); if ((SPItem::BBoxType) flags != SPItem::GEOMETRIC_BBOX) { + SPStyle* style=SP_OBJECT_STYLE (item); if (style->stroke.type != SP_PAINT_TYPE_NONE) { double const scale = expansion(transform); -- 2.30.2