From: dvlierop2 Date: Mon, 24 Nov 2008 19:45:10 +0000 (+0000) Subject: Add an option to the preferences to _only_ snap the node closest to the mouse pointer X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=fd4f8ef876a2d6f7e0a81596857787d05c67778b;p=inkscape.git Add an option to the preferences to _only_ snap the node closest to the mouse pointer --- diff --git a/src/nodepath.cpp b/src/nodepath.cpp index 234aba4cc..7165dab98 100644 --- a/src/nodepath.cpp +++ b/src/nodepath.cpp @@ -1360,25 +1360,46 @@ static void sp_nodepath_selected_nodes_move(Inkscape::NodePath::Path *nodepath, SnapManager &m = nodepath->desktop->namedview->snap_manager; - for (GList *l = nodepath->selected; l != NULL; l = l->next) { + // When only the node closest to the mouse pointer is to be snapped + // then we will not even try to snap to other points and discard those immediately + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + bool closest_only = prefs->getBool("/options/snapclosestonly/value", false); + + Inkscape::NodePath::Node *closest_node = NULL; + Geom::Coord closest_dist = NR_HUGE; + + if (closest_only) { + for (GList *l = nodepath->selected; l != NULL; l = l->next) { + Inkscape::NodePath::Node *n = (Inkscape::NodePath::Node *) l->data; + Geom::Coord dist = Geom::L2(nodepath->drag_origin_mouse - n->origin); + if (dist < closest_dist) { + closest_node = n; + closest_dist = dist; + } + } + } + + // Iterate through all selected nodes + m.setup(nodepath->desktop, false, SP_PATH(nodepath->item), &unselected_nodes); + for (GList *l = nodepath->selected; l != NULL; l = l->next) { Inkscape::NodePath::Node *n = (Inkscape::NodePath::Node *) l->data; - m.setup(nodepath->desktop, false, SP_PATH(n->subpath->nodepath->item), &unselected_nodes); - Inkscape::SnappedPoint s; - - if (constrained) { - Inkscape::Snapper::ConstraintLine dedicated_constraint = constraint; - dedicated_constraint.setPoint(n->pos); - s = m.constrainedSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, to_2geom(n->pos + delta), dedicated_constraint); - } else { - s = m.freeSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, to_2geom(n->pos + delta)); - } - - if (s.getSnapped()) { - s.setPointerDistance(Geom::L2(nodepath->drag_origin_mouse - n->origin)); - if (!s.isOtherOneBetter(best, true)) { - best = s; - best_pt = from_2geom(s.getPoint()) - n->pos; - } + if (!closest_only || n == closest_node) { //try to snap either all selected nodes or only the closest one + Inkscape::SnappedPoint s; + if (constrained) { + Inkscape::Snapper::ConstraintLine dedicated_constraint = constraint; + dedicated_constraint.setPoint(n->pos); + s = m.constrainedSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, to_2geom(n->pos + delta), dedicated_constraint); + } else { + s = m.freeSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, to_2geom(n->pos + delta)); + } + + if (s.getSnapped()) { + s.setPointerDistance(Geom::L2(nodepath->drag_origin_mouse - n->origin)); + if (!s.isOtherSnapBetter(best, true)) { + best = s; + best_pt = from_2geom(s.getPoint()) - n->pos; + } + } } } diff --git a/src/preferences-skeleton.h b/src/preferences-skeleton.h index 1868b9c88..68df4e730 100644 --- a/src/preferences-skeleton.h +++ b/src/preferences-skeleton.h @@ -250,6 +250,7 @@ static char const preferences_skeleton[] = " \n" " \n" " \n" +" \n" " \n" " \n" " \n" diff --git a/src/seltrans.cpp b/src/seltrans.cpp index 34ea17a64..4bb1b3d2b 100644 --- a/src/seltrans.cpp +++ b/src/seltrans.cpp @@ -295,7 +295,7 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s _snap_points = snap_points_hull; // Unfortunately, by now we will have lost the font-baseline snappoints :-( } - + // 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 @@ -326,6 +326,23 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s _opposite_for_specpoints = snap_points_bbox.min() + snap_points_bbox.dimensions() * Geom::Scale(1-x, 1-y); _opposite = _opposite_for_bboxpoints; } + + // When snapping the node closest to the mouse pointer is absolutely preferred over the closest snap + // (i.e. when weight == 1), then we will not even try to snap to other points and discard those other + // points immediately. + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (prefs->getBool("/options/snapclosestonly/value", false)) { + _keepClosestPointOnly(_snap_points, p); + _keepClosestPointOnly(_bbox_points, p); + if (_snap_points.size() == 1 && _bbox_points.size() == 1) { //both vectors can only have either one or zero elements + // So we have exactly one bbox corner and one node left; now find out which is closest and delete the other one + if (Geom::L2(_snap_points.at(0) - p) < Geom::L2(_bbox_points.at(0) - p)) { + _bbox_points.clear(); + } else { + _snap_points.clear(); + } + } + } // The lines below are usefull for debugging any snapping issues, as they'll spit out all points that are considered for snapping @@ -1415,7 +1432,7 @@ void Inkscape::SelTrans::moveTo(Geom::Point const &xy, guint state) Inkscape::SnappedPoint best_snapped_point; for (std::list::const_iterator i = s.begin(); i != s.end(); i++) { if (i->getSnapped()) { - if (best_snapped_point.isOtherOneBetter(*i, true)) { + if (best_snapped_point.isOtherSnapBetter(*i, true)) { best_snapped_point = *i; dxy = i->getTransformation(); } @@ -1544,6 +1561,25 @@ Geom::Point Inkscape::SelTrans::_calcAbsAffineGeom(Geom::Scale const geom_scale) return visual_bbox.min() + visual_bbox.dimensions() * Geom::Scale(_handle_x, _handle_y); } +void Inkscape::SelTrans::_keepClosestPointOnly(std::vector &points, const Geom::Point &reference) +{ + if (points.size() < 2) return; + + Geom::Point closest_point = Geom::Point(NR_HUGE, NR_HUGE); + Geom::Coord closest_dist = NR_HUGE; + + for(std::vector::const_iterator i = points.begin(); i != points.end(); i++) { + Geom::Coord dist = Geom::L2(*i - reference); + if (i == points.begin() || dist < closest_dist) { + closest_point = *i; + closest_dist = dist; + } + } + + points.clear(); + points.push_back(closest_point); +} + /* Local Variables: mode:c++ diff --git a/src/seltrans.h b/src/seltrans.h index 9fafb5a76..a472f3366 100644 --- a/src/seltrans.h +++ b/src/seltrans.h @@ -102,6 +102,7 @@ private: Geom::Point _getGeomHandlePos(Geom::Point const &visual_handle_pos); Geom::Point _calcAbsAffineDefault(Geom::Scale const default_scale); Geom::Point _calcAbsAffineGeom(Geom::Scale const geom_scale); + void _keepClosestPointOnly(std::vector &points, const Geom::Point &reference); enum State { STATE_SCALE, //scale or stretch diff --git a/src/snap.cpp b/src/snap.cpp index f6504efe3..e89063b43 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -347,7 +347,6 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( ** Also used to globally disable all snapping */ if (someSnapperMightSnap() == false) { - g_assert(points.size() > 0); return Inkscape::SnappedPoint(); } @@ -551,7 +550,7 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( } } } else { // For all transformations other than scaling - if (best_snapped_point.isOtherOneBetter(snapped_point, true)) { + if (best_snapped_point.isOtherSnapBetter(snapped_point, true)) { best_transformation = result; best_snapped_point = snapped_point; } @@ -815,7 +814,7 @@ Inkscape::SnappedPoint SnapManager::findBestSnap(Geom::Point const &p, SnappedCo // std::cout << "sp = " << from_2geom((*i).getPoint()); if ((*i).getSnapDistance() <= (*i).getTolerance()) { // if it's the first point, or if it is closer than the best snapped point so far - if (i == sp_list.begin() || bestSnappedPoint.isOtherOneBetter(*i, false)) { + if (i == sp_list.begin() || bestSnappedPoint.isOtherSnapBetter(*i, false)) { // then prefer this point over the previous one bestSnappedPoint = *i; } diff --git a/src/snapped-curve.cpp b/src/snapped-curve.cpp index 327de90bd..b566bfe34 100644 --- a/src/snapped-curve.cpp +++ b/src/snapped-curve.cpp @@ -121,8 +121,8 @@ bool getClosestIntersectionCS(std::list const &list, Geo bool const c1 = !success; // or, if it's closer bool const c2 = sp.getSnapDistance() < result.getSnapDistance(); - // or, if it's just then look at the other distance - // (only relevant for snapped points which are at an intersection + // or, if it's just as close then look at the other distance + // (only relevant for snapped points which are at an intersection) bool const c3 = (sp.getSnapDistance() == result.getSnapDistance()) && (sp.getSecondSnapDistance() < result.getSecondSnapDistance()); // then prefer this point over the previous one if (c1 || c2 || c3) { diff --git a/src/snapped-point.cpp b/src/snapped-point.cpp index d03968a94..c5eaba749 100644 --- a/src/snapped-point.cpp +++ b/src/snapped-point.cpp @@ -17,7 +17,7 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &fully_constrained) : _point(p), _target(target), _distance(d), _tolerance(std::max(t,1.0)), _always_snap(a) { - // tolerance should never be smaller than 1 px, as it is used for normalization in isOtherOneBetter. We don't want a division by zero. + // tolerance should never be smaller than 1 px, as it is used for normalization in isOtherSnapBetter. We don't want a division by zero. _fully_constrained = fully_constrained; _second_distance = NR_HUGE; _second_tolerance = 1; @@ -31,7 +31,7 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapTargetType const _second_distance(d2), _second_tolerance(std::max(t2,1.0)), _second_always_snap(a2) { // tolerance should never be smaller than 1 px, as it is used for normalization in - // isOtherOneBetter. We don't want a division by zero. + // isOtherSnapBetter. We don't want a division by zero. _transformation = Geom::Point(1,1); _pointer_distance = NR_HUGE; } @@ -79,7 +79,7 @@ bool getClosestSP(std::list &list, Inkscape::SnappedPoin return success; } -bool Inkscape::SnappedPoint::isOtherOneBetter(Inkscape::SnappedPoint const &other_one, bool weighted) const +bool Inkscape::SnappedPoint::isOtherSnapBetter(Inkscape::SnappedPoint const &other_one, bool weighted) const { double dist_other = other_one.getSnapDistance(); @@ -92,7 +92,10 @@ bool Inkscape::SnappedPoint::isOtherOneBetter(Inkscape::SnappedPoint const &othe // weigth factor: controls which node should be preferrerd for snapping, which is either // the node with the closest snap (w = 0), or the node closest to the mousepointer (w = 1) Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - double const w = prefs->getDoubleLimited("/options/snapweight/value", 0.5, 0, 1); + double w = prefs->getDoubleLimited("/options/snapweight/value", 0.5, 0, 1); + if (prefs->getBool("/options/snapclosestonly/value", false)) { + w = 1; + } if (w > 0) { // When accounting for the distance to the mouse pointer, then at least one of the snapped points should // have that distance set. If not, then this is a bug. Either "weighted" must be set to false, or the diff --git a/src/snapped-point.h b/src/snapped-point.h index bc5b2d39e..b50207429 100644 --- a/src/snapped-point.h +++ b/src/snapped-point.h @@ -79,7 +79,7 @@ public: void setTarget(SnapTargetType const target) {_target = target;} SnapTargetType getTarget() {return _target;} - bool isOtherOneBetter(SnappedPoint const &other_one, bool weighted) const; + bool isOtherSnapBetter(SnappedPoint const &other_one, bool weighted) const; protected: Geom::Point _point; // Location of the snapped point diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp index e78d51af4..e680115fe 100644 --- a/src/ui/dialog/inkscape-preferences.cpp +++ b/src/ui/dialog/inkscape-preferences.cpp @@ -210,11 +210,14 @@ void InkscapePreferences::initPageSnapping() _page_snapping.add_line( false, _("Delay (in msec):"), _snap_delay, "", _("Postpone snapping as long as the mouse is moving, and then wait an additional fraction of a second. This additional delay is specified here. When set to zero or to a very small number, snapping will be immediate"), true); + _snap_closest_only.init( _("Only snap the node closest to the pointer"), "/options/snapclosestonly/value", false); + _page_snapping.add_line( false, "", _snap_closest_only, "", + _("Only try to snap the node that is initialy closest to the mouse pointer")); + _snap_weight.init("/options/snapweight/value", 0, 1, 0.1, 0.2, 0.5, 1); _page_snapping.add_line( false, _("Weight factor:"), _snap_weight, "", _("When multiple snap solutions are found, then Inkscape can either prefer the closest transformation (when set to 0), or prefer the node that was initially the closest to the pointer (when set to 1)"), true); - - + this->AddPage(_page_snapping, _("Snapping"), PREFS_PAGE_SNAPPING); } diff --git a/src/ui/dialog/inkscape-preferences.h b/src/ui/dialog/inkscape-preferences.h index c62919c45..b439f25dd 100644 --- a/src/ui/dialog/inkscape-preferences.h +++ b/src/ui/dialog/inkscape-preferences.h @@ -128,7 +128,7 @@ protected: PrefCheckButton _wheel_zoom; Gtk::HScale *_slider_snapping_delay; - PrefCheckButton _snap_indicator; + PrefCheckButton _snap_indicator, _snap_closest_only; PrefCombo _steps_rot_snap; PrefCheckButton _steps_compass;