Code

Node tool: snap while scaling a selection of nodes. Consider this as experimental...
authorDiederik van Lierop <mailat-signdiedenrezidotnl>
Mon, 27 Dec 2010 21:18:34 +0000 (22:18 +0100)
committerDiederik van Lierop <mailat-signdiedenrezidotnl>
Mon, 27 Dec 2010 21:18:34 +0000 (22:18 +0100)
src/seltrans.cpp
src/seltrans.h
src/snap.cpp
src/snap.h
src/ui/tool/control-point-selection.cpp
src/ui/tool/control-point-selection.h
src/ui/tool/transform-handle-set.cpp

index b0e19e60c5d9747835c2a9ea498c8621bded7c74..b1d184986da06c3d2b7248c8a211beea641b5bcc 100644 (file)
@@ -299,7 +299,7 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s
         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 */
         if (prefs->getBool("/options/snapclosestonly/value", false)) {
-            _keepClosestPointOnly(_snap_points, p);
+            m.keepClosestPointOnly(_snap_points, p);
         } else {
             _snap_points = snap_points_hull;
         }
@@ -360,14 +360,14 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s
 
     if (prefs->getBool("/options/snapclosestonly/value", false)) {
         if (m.snapprefs.getSnapModeNode()) {
-            _keepClosestPointOnly(_snap_points, p);
+            m.keepClosestPointOnly(_snap_points, p);
         } else {
             _snap_points.clear(); // don't keep any point
         }
 
         if (m.snapprefs.getSnapModeBBox()) {
-            _keepClosestPointOnly(_bbox_points, p);
-            _keepClosestPointOnly(_bbox_points_for_translating, p);
+            m.keepClosestPointOnly(_bbox_points, p);
+            m.keepClosestPointOnly(_bbox_points_for_translating, p);
         } else {
             _bbox_points.clear(); // don't keep any point
             _bbox_points_for_translating.clear();
@@ -1632,26 +1632,6 @@ Geom::Point Inkscape::SelTrans::_calcAbsAffineGeom(Geom::Scale const geom_scale)
     return _calcAbsAffineDefault(geom_scale); // this is bogus, but we must return _something_
 }
 
-void Inkscape::SelTrans::_keepClosestPointOnly(std::vector<Inkscape::SnapCandidatePoint> &points, const Geom::Point &reference)
-{
-    if (points.size() < 2) return;
-
-    Inkscape::SnapCandidatePoint closest_point = Inkscape::SnapCandidatePoint(Geom::Point(NR_HUGE, NR_HUGE), SNAPSOURCE_UNDEFINED, SNAPTARGET_UNDEFINED);
-    Geom::Coord closest_dist = NR_HUGE;
-
-    for(std::vector<Inkscape::SnapCandidatePoint>::const_iterator i = points.begin(); i != points.end(); i++) {
-        Geom::Coord dist = Geom::L2((*i).getPoint() - reference);
-        if (i == points.begin() || dist < closest_dist) {
-            closest_point = *i;
-            closest_dist = dist;
-        }
-    }
-
-    closest_point.setSourceNum(-1);
-    points.clear();
-    points.push_back(closest_point);
-}
-
 /*
   Local Variables:
   mode:c++
index 0183683ffe028026dd0bbdd525a0c4e4cd04d5ba..bb26aa2cbae7d5de0179b28343b76dfa72c01840 100644 (file)
@@ -103,7 +103,6 @@ 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<Inkscape::SnapCandidatePoint> &points, const Geom::Point &reference);
     void _display_snapsource();
 
     enum State {
index 79f398cc54f77df6f4bea68633d4f4f17af384c5..85d2fd5afbac5bfe129b400bc04214b23813f1fd 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "sp-namedview.h"
 #include "snap.h"
+#include "snap-enums.h"
 #include "snapped-line.h"
 #include "snapped-curve.h"
 
@@ -682,7 +683,7 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed(
     Geom::Point const &transformation,
     Geom::Point const &origin,
     Geom::Dim2 dim,
-    bool uniform) const
+    bool uniform)
 {
     /* We have a list of points, which we are proposing to transform in some way.  We need to see
     ** if any of these points, when transformed, snap to anything.  If they do, we return the
@@ -734,6 +735,12 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed(
         g_warning("Unconstrained rotation is not supported!");
     }
 
+    // We will try to snap a set of points, but we don't want to have a snap indicator displayed
+    // for each of them. That's why it's temporarily disabled here, and re-enabled again after we
+    // have finished calling the freeSnap() and constrainedSnap() methods
+    bool _orig_snapindicator_status = _snapindicator;
+    _snapindicator = false;
+
     std::vector<Inkscape::SnapCandidatePoint>::iterator j = transformed_points.begin();
 
     // std::cout << std::endl;
@@ -802,6 +809,9 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed(
         // std::cout << "dist = " << snapped_point.getSnapDistance() << std::endl;
         snapped_point.setPointerDistance(Geom::L2(pointer - (*i).getPoint()));
 
+        // Allow the snapindicator to be displayed again
+        _snapindicator = _orig_snapindicator_status;
+
         Geom::Point result;
 
         /*Find the transformation that describes where the snapped point has
@@ -891,6 +901,7 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed(
 
         if (snapped_point.getSnapped()) {
             // We snapped; keep track of the best snap
+            // TODO: Compare the transformations instead of the snap points; we should be looking for the closest transformation
             if (best_snapped_point.isOtherSnapBetter(snapped_point, true)) {
                 best_transformation = result;
                 best_snapped_point = snapped_point;
@@ -932,6 +943,15 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed(
     // Using " < 1e6" instead of " < NR_HUGE" for catching some rounding errors
     // These rounding errors might be caused by NRRects, see bug #1584301
     best_snapped_point.setSnapDistance(best_metric < 1e6 ? best_metric : NR_HUGE);
+
+    if (_snapindicator) {
+        if (best_snapped_point.getSnapped()) {
+            _desktop->snapindicator->set_new_snaptarget(best_snapped_point);
+        } else {
+            _desktop->snapindicator->remove_snaptarget();
+        }
+    }
+
     return best_snapped_point;
 }
 
@@ -947,7 +967,7 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed(
 
 Inkscape::SnappedPoint SnapManager::freeSnapTranslate(std::vector<Inkscape::SnapCandidatePoint> const &p,
                                                         Geom::Point const &pointer,
-                                                        Geom::Point const &tr) const
+                                                        Geom::Point const &tr)
 {
     Inkscape::SnappedPoint result = _snapTransformed(p, pointer, false, Geom::Point(0,0), TRANSLATE, tr, Geom::Point(0,0), Geom::X, false);
 
@@ -971,7 +991,7 @@ Inkscape::SnappedPoint SnapManager::freeSnapTranslate(std::vector<Inkscape::Snap
 Inkscape::SnappedPoint SnapManager::constrainedSnapTranslate(std::vector<Inkscape::SnapCandidatePoint> const &p,
                                                                Geom::Point const &pointer,
                                                                Inkscape::Snapper::SnapConstraint const &constraint,
-                                                               Geom::Point const &tr) const
+                                                               Geom::Point const &tr)
 {
     Inkscape::SnappedPoint result = _snapTransformed(p, pointer, true, constraint, TRANSLATE, tr, Geom::Point(0,0), Geom::X, false);
 
@@ -996,7 +1016,7 @@ Inkscape::SnappedPoint SnapManager::constrainedSnapTranslate(std::vector<Inkscap
 Inkscape::SnappedPoint SnapManager::freeSnapScale(std::vector<Inkscape::SnapCandidatePoint> const &p,
                                                   Geom::Point const &pointer,
                                                   Geom::Scale const &s,
-                                                  Geom::Point const &o) const
+                                                  Geom::Point const &o)
 {
     Inkscape::SnappedPoint result = _snapTransformed(p, pointer, false, Geom::Point(0,0), SCALE, Geom::Point(s[Geom::X], s[Geom::Y]), o, Geom::X, false);
 
@@ -1021,7 +1041,7 @@ Inkscape::SnappedPoint SnapManager::freeSnapScale(std::vector<Inkscape::SnapCand
 Inkscape::SnappedPoint SnapManager::constrainedSnapScale(std::vector<Inkscape::SnapCandidatePoint> const &p,
                                                          Geom::Point const &pointer,
                                                          Geom::Scale const &s,
-                                                         Geom::Point const &o) const
+                                                         Geom::Point const &o)
 {
     // When constrained scaling, only uniform scaling is supported.
     Inkscape::SnappedPoint result = _snapTransformed(p, pointer, true, Geom::Point(0,0), SCALE, Geom::Point(s[Geom::X], s[Geom::Y]), o, Geom::X, true);
@@ -1050,7 +1070,7 @@ Inkscape::SnappedPoint SnapManager::constrainedSnapStretch(std::vector<Inkscape:
                                                             Geom::Coord const &s,
                                                             Geom::Point const &o,
                                                             Geom::Dim2 d,
-                                                            bool u) const
+                                                            bool u)
 {
     Inkscape::SnappedPoint result = _snapTransformed(p, pointer, true, Geom::Point(0,0), STRETCH, Geom::Point(s, s), o, d, u);
 
@@ -1078,7 +1098,7 @@ Inkscape::SnappedPoint SnapManager::constrainedSnapSkew(std::vector<Inkscape::Sn
                                                  Inkscape::Snapper::SnapConstraint const &constraint,
                                                  Geom::Point const &s,
                                                  Geom::Point const &o,
-                                                 Geom::Dim2 d) const
+                                                 Geom::Dim2 d)
 {
     // "s" contains skew factor in s[0], and scale factor in s[1]
 
@@ -1113,7 +1133,7 @@ Inkscape::SnappedPoint SnapManager::constrainedSnapSkew(std::vector<Inkscape::Sn
 Inkscape::SnappedPoint SnapManager::constrainedSnapRotate(std::vector<Inkscape::SnapCandidatePoint> const &p,
                                                     Geom::Point const &pointer,
                                                     Geom::Coord const &angle,
-                                                    Geom::Point const &o) const
+                                                    Geom::Point const &o)
 {
     // Snapping the nodes of the bounding box of a selection that is being transformed, will only work if
     // the transformation of the bounding box is equal to the transformation of the individual nodes. This is
@@ -1429,6 +1449,26 @@ void SnapManager::_displaySnapsource(Inkscape::SnapCandidatePoint const &p) cons
     }
 }
 
+void SnapManager::keepClosestPointOnly(std::vector<Inkscape::SnapCandidatePoint> &points, const Geom::Point &reference) const
+{
+    if (points.size() < 2) return;
+
+    Inkscape::SnapCandidatePoint closest_point = Inkscape::SnapCandidatePoint(Geom::Point(NR_HUGE, NR_HUGE), Inkscape::SNAPSOURCE_UNDEFINED, Inkscape::SNAPTARGET_UNDEFINED);
+    Geom::Coord closest_dist = NR_HUGE;
+
+    for(std::vector<Inkscape::SnapCandidatePoint>::const_iterator i = points.begin(); i != points.end(); i++) {
+        Geom::Coord dist = Geom::L2((*i).getPoint() - reference);
+        if (i == points.begin() || dist < closest_dist) {
+            closest_point = *i;
+            closest_dist = dist;
+        }
+    }
+
+    closest_point.setSourceNum(-1);
+    points.clear();
+    points.push_back(closest_point);
+}
+
 /*
   Local Variables:
   mode:c++
index c79bd308a5e2bc1bc9f11337804d1cdad9fa416a..8f8416ee5ad0c2216efb32bfedb3739dab372739 100644 (file)
@@ -149,41 +149,41 @@ public:
 
     Inkscape::SnappedPoint freeSnapTranslate(std::vector<Inkscape::SnapCandidatePoint> const &p,
                                                Geom::Point const &pointer,
-                                               Geom::Point const &tr) const;
+                                               Geom::Point const &tr);
 
     Inkscape::SnappedPoint constrainedSnapTranslate(std::vector<Inkscape::SnapCandidatePoint> const &p,
                                                       Geom::Point const &pointer,
                                                       Inkscape::Snapper::SnapConstraint const &constraint,
-                                                      Geom::Point const &tr) const;
+                                                      Geom::Point const &tr);
 
     Inkscape::SnappedPoint freeSnapScale(std::vector<Inkscape::SnapCandidatePoint> const &p,
                                          Geom::Point const &pointer,
                                          Geom::Scale const &s,
-                                         Geom::Point const &o) const;
+                                         Geom::Point const &o);
 
     Inkscape::SnappedPoint constrainedSnapScale(std::vector<Inkscape::SnapCandidatePoint> const &p,
                                                 Geom::Point const &pointer,
                                                 Geom::Scale const &s,
-                                                Geom::Point const &o) const;
+                                                Geom::Point const &o);
 
     Inkscape::SnappedPoint constrainedSnapStretch(std::vector<Inkscape::SnapCandidatePoint> const &p,
                                                   Geom::Point const &pointer,
                                                   Geom::Coord const &s,
                                                   Geom::Point const &o,
                                                   Geom::Dim2 d,
-                                                  bool uniform) const;
+                                                  bool uniform);
 
     Inkscape::SnappedPoint constrainedSnapSkew(std::vector<Inkscape::SnapCandidatePoint> const &p,
                                                Geom::Point const &pointer,
                                                Inkscape::Snapper::SnapConstraint const &constraint,
                                                Geom::Point const &s, // s[0] = skew factor, s[1] = scale factor
                                                Geom::Point const &o,
-                                               Geom::Dim2 d) const;
+                                               Geom::Dim2 d);
 
     Inkscape::SnappedPoint constrainedSnapRotate(std::vector<Inkscape::SnapCandidatePoint> const &p,
                                                     Geom::Point const &pointer,
                                                     Geom::Coord const &angle,
-                                                    Geom::Point const &o) const;
+                                                    Geom::Point const &o);
 
     Inkscape::GuideSnapper guide;      ///< guide snapper
     Inkscape::ObjectSnapper object;    ///< snapper to other objects
@@ -200,6 +200,7 @@ public:
     bool getSnapIndicator() const {return _snapindicator;}
 
     Inkscape::SnappedPoint findBestSnap(Inkscape::SnapCandidatePoint const &p, SnappedConstraints const &sc, bool constrained, bool noCurves = false, bool allowOffScreen = false) const;
+    void keepClosestPointOnly(std::vector<Inkscape::SnapCandidatePoint> &points, const Geom::Point &reference) const;
 
 protected:
     SPNamedView const *_named_view;
@@ -220,7 +221,7 @@ private:
                                             Geom::Point const &transformation,
                                             Geom::Point const &origin,
                                             Geom::Dim2 dim,
-                                            bool uniform) const;
+                                            bool uniform);
 
     Geom::Point _transformPoint(Inkscape::SnapCandidatePoint const &p,
                                             Transformation const transformation_type,
index baa53f76ea920b8e4d208393b25184e4f11e679b..517e90da22d5e6a6e5bcaca6c6237e7011c1f227 100644 (file)
@@ -642,6 +642,24 @@ bool ControlPointSelection::event(GdkEvent *event)
     return false;
 }
 
+std::vector<Inkscape::SnapCandidatePoint> ControlPointSelection::getOriginalPoints()
+{
+    std::vector<Inkscape::SnapCandidatePoint> points;
+    for (iterator i = _points.begin(); i != _points.end(); ++i) {
+        points.push_back(Inkscape::SnapCandidatePoint(_original_positions[*i], SNAPSOURCE_NODE_HANDLE));
+    }
+    return points;
+}
+
+void ControlPointSelection::setOriginalPoints()
+{
+    _original_positions.clear();
+    for (iterator i = _points.begin(); i != _points.end(); ++i) {
+        _original_positions.insert(std::make_pair(*i, (*i)->position()));
+    }
+}
+
+
 } // namespace UI
 } // namespace Inkscape
 
index 6a5b05e853592dbcde34c3f94f6a337c43c552bd..0e5acf6c5cc84e05151f5f8de19915117a02f20a 100644 (file)
@@ -22,6 +22,7 @@
 #include "util/unordered-containers.h"
 #include "ui/tool/commit-events.h"
 #include "ui/tool/manipulator.h"
+#include "snap-candidate.h"
 
 class SPDesktop;
 struct SPCanvasGroup;
@@ -108,6 +109,10 @@ public:
     sigc::signal<void> signal_update;
     sigc::signal<void, SelectableControlPoint *, bool> signal_point_changed;
     sigc::signal<void, CommitEvent> signal_commit;
+
+    std::vector<Inkscape::SnapCandidatePoint> getOriginalPoints();
+    void setOriginalPoints();
+
 private:
     // The functions below are invoked from SelectableControlPoint.
     // Previously they were connected to handlers when selecting, but this
index cafd592a3622017f42f62fafdd7253bd1b17f461..209b7fe98f7587c5690a868507bfc9067a346a91 100644 (file)
 #include "display/sodipodi-ctrlrect.h"
 #include "preferences.h"
 #include "snap.h"
+#include "snap-candidate.h"
 #include "sp-namedview.h"
 #include "ui/tool/commit-events.h"
 #include "ui/tool/control-point.h"
+#include "ui/tool/control-point-selection.h"
+#include "ui/tool/selectable-control-point.h"
 #include "ui/tool/event-utils.h"
 #include "ui/tool/transform-handle-set.h"
+#include "ui/tool/node-tool.h"
 
 // FIXME BRAIN DAMAGE WARNING: this is a global variable in select-context.cpp
 // It should be moved to a header
@@ -96,6 +100,8 @@ protected:
     Geom::Matrix _last_transform;
     Geom::Point _origin;
     TransformHandleSet &_th;
+    std::vector<Inkscape::SnapCandidatePoint> _snap_points;
+
 private:
     virtual bool grabbed(GdkEventMotion *) {
         _origin = position();
@@ -105,6 +111,20 @@ private:
         _th._setActiveHandle(this);
         _cset = &invisible_cset;
         _setState(_state);
+
+        // Collect the snap-candidates, one for each selected node. These will be stored in the _snap_points vector.
+        SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+        SnapManager &m = desktop->namedview->snap_manager;
+        InkNodeTool *nt = INK_NODE_TOOL(_desktop->event_context);
+        ControlPointSelection *selection = nt->_selected_nodes.get();
+
+        _snap_points = selection->getOriginalPoints();
+
+        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+        if (prefs->getBool("/options/snapclosestonly/value", false)) {
+            m.keepClosestPointOnly(_snap_points, _origin);
+        }
+
         return false;
     }
     virtual void dragged(Geom::Point &new_pos, GdkEventMotion *event)
@@ -118,6 +138,7 @@ private:
         _last_transform = t;
     }
     virtual void ungrabbed(GdkEventButton *) {
+        _snap_points.clear();
         _th._clearActiveHandle();
         _cset = &thandle_cset;
         _setState(_state);
@@ -177,23 +198,64 @@ protected:
         _sc_center = _th.rotationCenter();
         _sc_opposite = _th.bounds().corner(_corner + 2);
         _last_scale_x = _last_scale_y = 1.0;
+        InkNodeTool *nt = INK_NODE_TOOL(_desktop->event_context);
+        ControlPointSelection *selection = nt->_selected_nodes.get();
+        std::cout << "startTransform()" << std::endl;
+        selection->setOriginalPoints();
     }
     virtual Geom::Matrix computeTransform(Geom::Point const &new_pos, GdkEventMotion *event) {
         Geom::Point scc = held_shift(*event) ? _sc_center : _sc_opposite;
         Geom::Point vold = _origin - scc, vnew = new_pos - scc;
+
         // avoid exploding the selection
         if (Geom::are_near(vold[Geom::X], 0) || Geom::are_near(vold[Geom::Y], 0))
             return Geom::identity();
 
         double scale[2] = { vnew[Geom::X] / vold[Geom::X], vnew[Geom::Y] / vold[Geom::Y] };
+
         if (held_alt(*event)) {
             for (unsigned i = 0; i < 2; ++i) {
                 if (scale[i] >= 1.0) scale[i] = round(scale[i]);
                 else scale[i] = 1.0 / round(1.0 / scale[i]);
             }
-        } else if (held_control(*event)) {
-            scale[0] = scale[1] = std::min(scale[0], scale[1]);
+        } else {
+            //SPDesktop *desktop = _th._desktop; // Won't work as _desktop is protected
+            SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+            SnapManager &m = desktop->namedview->snap_manager;
+
+            // The lines below have been copied from Handle::dragged() in node.cpp, and need to be
+            // activated if we want to snap to unselected (i.e. stationary) nodes and stationary pieces of paths of the
+            // path that's currently being edited
+            /*
+            std::vector<Inkscape::SnapCandidatePoint> unselected;
+            typedef ControlPointSelection::Set Set;
+            Set &nodes = _parent->_selection.allPoints();
+            for (Set::iterator i = nodes.begin(); i != nodes.end(); ++i) {
+                Node *n = static_cast<Node*>(*i);
+                Inkscape::SnapCandidatePoint p(n->position(), n->_snapSourceType(), n->_snapTargetType());
+                unselected.push_back(p);
+            }
+            m.setupIgnoreSelection(_desktop, true, &unselected);
+            */
+
+            m.setupIgnoreSelection(_desktop);
+
+            Inkscape::SnappedPoint sp;
+            if (held_control(*event)) {
+                scale[0] = scale[1] = std::min(scale[0], scale[1]);
+                sp = m.constrainedSnapScale(_snap_points, _origin, Geom::Scale(scale[0], scale[1]), scc);
+            } else {
+                sp = m.freeSnapScale(_snap_points, _origin, Geom::Scale(scale[0], scale[1]), scc);
+            }
+            m.unSetup();
+
+            if (sp.getSnapped()) {
+                Geom::Point result = sp.getTransformation();
+                scale[0] = result[0];
+                scale[1] = result[1];
+            }
         }
+
         _last_scale_x = scale[0];
         _last_scale_y = scale[1];
         Geom::Matrix t = Geom::Translate(-scc)