Code

Fix bounding box snapping (LP562205, comment 6, issue II)
authorDiederik van Lierop <mailat-signdiedenrezidotnl>
Sat, 8 May 2010 21:27:22 +0000 (23:27 +0200)
committerDiederik van Lierop <mailat-signdiedenrezidotnl>
Sat, 8 May 2010 21:27:22 +0000 (23:27 +0200)
15 files changed:
src/display/canvas-axonomgrid.cpp
src/display/canvas-axonomgrid.h
src/display/canvas-grid.cpp
src/display/canvas-grid.h
src/gradient-drag.cpp
src/guide-snapper.cpp
src/guide-snapper.h
src/line-snapper.cpp
src/line-snapper.h
src/object-snapper.cpp
src/snap.cpp
src/snapped-curve.cpp
src/snapped-line.cpp
src/snapped-point.cpp
src/snapped-point.h

index cf28831166a04d829ee84f77625fe9bd17e49785..37469fa737bdede42dd9c7a3b564ef53892ce5ea 100644 (file)
@@ -794,9 +794,9 @@ void CanvasAxonomGridSnapper::_addSnappedLine(SnappedConstraints &sc, Geom::Poin
     sc.grid_lines.push_back(dummy);
 }
 
-void CanvasAxonomGridSnapper::_addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num) const
+void CanvasAxonomGridSnapper::_addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num, bool constrained_snap) const
 {
-    SnappedPoint dummy = SnappedPoint(snapped_point, source, source_num, Inkscape::SNAPTARGET_GRID, snapped_distance, getSnapperTolerance(), getSnapperAlwaysSnap(), true);
+    SnappedPoint dummy = SnappedPoint(snapped_point, source, source_num, Inkscape::SNAPTARGET_GRID, snapped_distance, getSnapperTolerance(), getSnapperAlwaysSnap(), constrained_snap, true);
     sc.points.push_back(dummy);
 }
 
index 4b1cd48340ccec5215131c0e88084b5281283364..58185e2e6a4bbf940666689c12e049172d18b551 100644 (file)
@@ -79,7 +79,7 @@ public:
 private:
     LineList _getSnapLines(Geom::Point const &p) const;
     void _addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num, Geom::Point const normal_to_line, const Geom::Point point_on_line) const;
-    void _addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num) const;
+    void _addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num, bool constrained_snap) const;
 
     CanvasAxonomGrid *grid;
 };
index 3532c504a73954f30666174de8e3c0f033774f9c..a79a6b610c1bc947b0ede5f7bf2c6d4007d86dec 100644 (file)
@@ -1030,9 +1030,9 @@ void CanvasXYGridSnapper::_addSnappedLine(SnappedConstraints &sc, Geom::Point co
     sc.grid_lines.push_back(dummy);
 }
 
-void CanvasXYGridSnapper::_addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num) const
+void CanvasXYGridSnapper::_addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num, bool constrained_snap) const
 {
-    SnappedPoint dummy = SnappedPoint(snapped_point, source, source_num, Inkscape::SNAPTARGET_GRID, snapped_distance, getSnapperTolerance(), getSnapperAlwaysSnap(), true);
+    SnappedPoint dummy = SnappedPoint(snapped_point, source, source_num, Inkscape::SNAPTARGET_GRID, snapped_distance, getSnapperTolerance(), getSnapperAlwaysSnap(), constrained_snap, true);
     sc.points.push_back(dummy);
 }
 
index daf28c15c4fcf62e9b63a21bb1d7e984df309fb0..a11d77d1dc86d9eb5372c10e6dc50ddfad6c7426 100644 (file)
@@ -167,7 +167,7 @@ public:
 private:
     LineList _getSnapLines(Geom::Point const &p) const;
     void _addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance,  SnapSourceType const &source, long source_num, Geom::Point const normal_to_line, const Geom::Point point_on_line) const;
-    void _addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num) const;
+    void _addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num, bool constrained_snap) const;
     CanvasXYGrid *grid;
 };
 
index 9796fc5da70c974025e418397affd83f709bf676..11de93d680290f5fc9bc7a2cf3fc4c9443fc2a1e 100644 (file)
@@ -665,7 +665,7 @@ gr_knot_moved_handler(SPKnot *knot, Geom::Point const &ppointer, guint state, gp
                         s.setTransformation(s.getPoint() - p);
                         sc.points.push_back(s);
                     } else {
-                        Inkscape::SnappedPoint dummy(p + *snap_vector, Inkscape::SNAPSOURCE_OTHER_HANDLE, 0, Inkscape::SNAPTARGET_CONSTRAINED_ANGLE, Geom::L2(*snap_vector), 10000, true, false);
+                        Inkscape::SnappedPoint dummy(p + *snap_vector, Inkscape::SNAPSOURCE_OTHER_HANDLE, 0, Inkscape::SNAPTARGET_CONSTRAINED_ANGLE, Geom::L2(*snap_vector), 10000, true, true, false);
                         dummy.setTransformation(*snap_vector);
                         sc.points.push_back(dummy);
                     }
index 9121e3ee20df852d4bb0bd15242a7ddddb58064e..4f70521e0904a5fd9a4f9e3ee823be462d17266b 100644 (file)
@@ -74,16 +74,16 @@ void Inkscape::GuideSnapper::_addSnappedLine(SnappedConstraints &sc, Geom::Point
     sc.guide_lines.push_back(dummy);
 }
 
-void Inkscape::GuideSnapper::_addSnappedLinesOrigin(SnappedConstraints &sc, Geom::Point const origin, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num) const
+void Inkscape::GuideSnapper::_addSnappedLinesOrigin(SnappedConstraints &sc, Geom::Point const origin, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num, bool constrained_snap) const
 {
-    SnappedPoint dummy = SnappedPoint(origin, source, source_num, Inkscape::SNAPTARGET_GUIDE_ORIGIN, snapped_distance, getSnapperTolerance(), getSnapperAlwaysSnap(), true);
+    SnappedPoint dummy = SnappedPoint(origin, source, source_num, Inkscape::SNAPTARGET_GUIDE_ORIGIN, snapped_distance, getSnapperTolerance(), getSnapperAlwaysSnap(), constrained_snap, true);
     sc.points.push_back(dummy);
 }
 
 
-void Inkscape::GuideSnapper::_addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num) const
+void Inkscape::GuideSnapper::_addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num, bool constrained_snap) const
 {
-    SnappedPoint dummy = SnappedPoint(snapped_point, source, source_num, Inkscape::SNAPTARGET_GUIDE, snapped_distance, getSnapperTolerance(), getSnapperAlwaysSnap(), true);
+    SnappedPoint dummy = SnappedPoint(snapped_point, source, source_num, Inkscape::SNAPTARGET_GUIDE, snapped_distance, getSnapperTolerance(), getSnapperAlwaysSnap(), constrained_snap, true);
     sc.points.push_back(dummy);
 }
 
index 5adac6e2220951ef6d39d31ad27c3825002e18c7..5de1b56a4ae20474a183a8c17de683cf2bec2b35 100644 (file)
@@ -35,8 +35,8 @@ public:
 private:
     LineList _getSnapLines(Geom::Point const &p) const;
     void _addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance,  SnapSourceType const &source, long source_num, Geom::Point const normal_to_line, Geom::Point const point_on_line) const;
-    void _addSnappedLinesOrigin(SnappedConstraints &sc, Geom::Point const origin, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num) const;
-    void _addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num) const;
+    void _addSnappedLinesOrigin(SnappedConstraints &sc, Geom::Point const origin, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num, bool constrained_snap) const;
+    void _addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num, bool constrained_snap) const;
 };
 
 }
index f2f02533246a8d6b90a20fb73db4694db4ffc678..fc40643c8f135afc605cadc7c33640e8c666855b 100644 (file)
@@ -50,7 +50,7 @@ void Inkscape::LineSnapper::freeSnap(SnappedConstraints &sc,
             // discern between grids and guides here
             Geom::Coord const dist_p1 = Geom::L2(p1 - p.getPoint());
             if (dist_p1 < getSnapperTolerance()) {
-                _addSnappedLinesOrigin(sc, p1, dist_p1, p.getSourceType(), p.getSourceNum());
+                _addSnappedLinesOrigin(sc, p1, dist_p1, p.getSourceType(), p.getSourceNum(), false);
                 // Only relevant for guides; grids don't have an origin per line
                 // Therefore _addSnappedLinesOrigin() will only be implemented for guides
             }
@@ -104,13 +104,13 @@ void Inkscape::LineSnapper::constrainedSnap(SnappedConstraints &sc,
                     // This snappoint is therefore fully constrained, so there's no need
                     // to look for additional intersections; just return the snapped point
                     // and forget about the line
-                    _addSnappedPoint(sc, t, dist, p.getSourceType(), p.getSourceNum());
+                    _addSnappedPoint(sc, t, dist, p.getSourceType(), p.getSourceNum(), true);
                     // For any line that's within range, we will also look at it's "point on line" p1. For guides
                     // this point coincides with its origin; for grids this is of no use, but we cannot
                     // discern between grids and guides here
                     Geom::Coord const dist_p1 = Geom::L2(p1 - p.getPoint());
                     if (dist_p1 < getSnapperTolerance()) {
-                        _addSnappedLinesOrigin(sc, p1, dist_p1, p.getSourceType(), p.getSourceNum());
+                        _addSnappedLinesOrigin(sc, p1, dist_p1, p.getSourceType(), p.getSourceNum(), true);
                         // Only relevant for guides; grids don't have an origin per line
                         // Therefore _addSnappedLinesOrigin() will only be implemented for guides
                     }
@@ -122,7 +122,7 @@ void Inkscape::LineSnapper::constrainedSnap(SnappedConstraints &sc,
 
 // Will only be overridden in the guide-snapper class, because grid lines don't have an origin; the
 // grid-snapper classes will use this default empty method
-void Inkscape::LineSnapper::_addSnappedLinesOrigin(SnappedConstraints &/*sc*/, Geom::Point const /*origin*/, Geom::Coord const /*snapped_distance*/, SnapSourceType const &/*source_type*/, long /*source_num*/) const
+void Inkscape::LineSnapper::_addSnappedLinesOrigin(SnappedConstraints &/*sc*/, Geom::Point const /*origin*/, Geom::Coord const /*snapped_distance*/, SnapSourceType const &/*source_type*/, long /*source_num*/, bool /*constrained_snap*/) const
 {
 }
 
index 429139421dbaa9d2876f3d06fd87aa0beccc919f..1aa3526cc12f7c993fbdf94c48bc95faf8888b1a 100644 (file)
@@ -52,9 +52,9 @@ private:
   virtual void _addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num, Geom::Point const normal_to_line, Geom::Point const point_on_line) const = 0;
 
   // Will only be implemented for guide lines, because grid lines don't have an origin
-  virtual void _addSnappedLinesOrigin(SnappedConstraints &sc, Geom::Point const origin, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num) const;
+  virtual void _addSnappedLinesOrigin(SnappedConstraints &sc, Geom::Point const origin, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num, bool constrained_snap) const;
 
-  virtual void _addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num) const = 0;
+  virtual void _addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num, bool constrained_snap) const = 0;
 };
 
 }
index 77449ddc3d3092cadb4be15f06eed8180a53358e..536affb8239750f437cb8eef6e694066b40c6eec 100644 (file)
@@ -265,7 +265,7 @@ void Inkscape::ObjectSnapper::_snapNodes(SnappedConstraints &sc,
     for (std::vector<SnapCandidatePoint>::const_iterator k = _points_to_snap_to->begin(); k != _points_to_snap_to->end(); k++) {
         Geom::Coord dist = Geom::L2((*k).getPoint() - p.getPoint());
         if (dist < getSnapperTolerance() && dist < s.getSnapDistance()) {
-            s = SnappedPoint((*k).getPoint(), p.getSourceType(), p.getSourceNum(), (*k).getTargetType(), dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true, (*k).getTargetBBox());
+            s = SnappedPoint((*k).getPoint(), p.getSourceType(), p.getSourceNum(), (*k).getTargetType(), dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true, (*k).getTargetBBox());
             success = true;
         }
     }
@@ -299,7 +299,7 @@ void Inkscape::ObjectSnapper::_snapTranslatingGuideToNodes(SnappedConstraints &s
         Geom::Coord dist = Geom::L2((*k).getPoint() - p_proj); // distance from node to the guide
         Geom::Coord dist2 = Geom::L2(p - p_proj); // distance from projection of node on the guide, to the mouse location
         if ((dist < tol && dist2 < tol) || getSnapperAlwaysSnap()) {
-            s = SnappedPoint((*k).getPoint(), SNAPSOURCE_GUIDE, 0, (*k).getTargetType(), dist, tol, getSnapperAlwaysSnap(), true, (*k).getTargetBBox());
+            s = SnappedPoint((*k).getPoint(), SNAPSOURCE_GUIDE, 0, (*k).getTargetType(), dist, tol, getSnapperAlwaysSnap(), false, true, (*k).getTargetBBox());
             sc.points.push_back(s);
         }
     }
index 8704ce3bb69200752fed6dba11088f10523053dc..c47f93ff11c37a77dfcc685ae00f8ce37c458d13 100644 (file)
@@ -201,7 +201,7 @@ Inkscape::SnappedPoint SnapManager::freeSnap(Inkscape::SnapCandidatePoint const
                                              Geom::OptRect const &bbox_to_snap) const
 {
     if (!someSnapperMightSnap()) {
-        return Inkscape::SnappedPoint(p, Inkscape::SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false);
+        return Inkscape::SnappedPoint(p, Inkscape::SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, false);
     }
 
     SnappedConstraints sc;
@@ -365,7 +365,7 @@ Inkscape::SnappedPoint SnapManager::constrainedSnap(Inkscape::SnapCandidatePoint
     // First project the mouse pointer onto the constraint
     Geom::Point pp = constraint.projection(p.getPoint());
 
-    Inkscape::SnappedPoint no_snap = Inkscape::SnappedPoint(pp, p.getSourceType(), p.getSourceNum(), Inkscape::SNAPTARGET_CONSTRAINT, Geom::L2(pp - p.getPoint()), 0, false, false);
+    Inkscape::SnappedPoint no_snap = Inkscape::SnappedPoint(pp, p.getSourceType(), p.getSourceNum(), Inkscape::SNAPTARGET_CONSTRAINT, Geom::L2(pp - p.getPoint()), 0, false, true, false);
 
     if (!someSnapperMightSnap()) {
         // Always return point on constraint
@@ -648,7 +648,7 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed(
                     // the origin of the scaling, then it will scale purely in X or Y
                     // We can therefore only calculate the scaling in this direction
                     // and the scaling factor for the other direction should remain
-                    // untouched (unless scaling is uniform ofcourse)
+                    // untouched (unless scaling is uniform of course)
                     for (int index = 0; index < 2; index++) {
                         if (fabs(b[index]) > 1e-6) { // if SCALING CAN occur in this direction
                             if (fabs(fabs(a[index]/b[index]) - fabs(transformation[index])) > 1e-12) { // if SNAPPING DID occur in this direction
@@ -697,9 +697,6 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed(
                     g_assert_not_reached();
             }
 
-            // When scaling, we're considering the best transformation in each direction separately. We will have a metric in each
-            // direction, whereas for all other transformation we only a single one-dimensional metric. That's why we need to handle
-            // the scaling metric differently
             if (best_snapped_point.isOtherSnapBetter(snapped_point, true)) {
                 best_transformation = result;
                 best_snapped_point = snapped_point;
index d4ef0a83fe204c53cbb6423b4c5d23b22e241f8d..e7df3cfade8faa07661a138a4666bf3f2ae1e4c1 100644 (file)
@@ -87,12 +87,12 @@ Inkscape::SnappedPoint Inkscape::SnappedCurve::intersect(SnappedCurve const &cur
         // TODO: Investigate whether it is possible to use document coordinates everywhere
         // in the snapper code. Only the mouse position should be in desktop coordinates, I guess.
         // All paths are already in document coords and we are certainly not going to change THAT.
-        return SnappedPoint(best_p, Inkscape::SNAPSOURCE_UNDEFINED, primaryC->getSourceNum(), Inkscape::SNAPTARGET_PATH_INTERSECTION, primaryDist, primaryC->getTolerance(), primaryC->getAlwaysSnap(), true, true,
+        return SnappedPoint(best_p, Inkscape::SNAPSOURCE_UNDEFINED, primaryC->getSourceNum(), Inkscape::SNAPTARGET_PATH_INTERSECTION, primaryDist, primaryC->getTolerance(), primaryC->getAlwaysSnap(), true, false, true,
                 secondaryDist, secondaryC->getTolerance(), secondaryC->getAlwaysSnap());
     }
 
     // No intersection
-    return SnappedPoint(Geom::Point(NR_HUGE, NR_HUGE), SNAPSOURCE_UNDEFINED, 0, SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, false, NR_HUGE, 0, false);
+    return SnappedPoint(Geom::Point(NR_HUGE, NR_HUGE), SNAPSOURCE_UNDEFINED, 0, SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, false, false, NR_HUGE, 0, false);
 }
 
 // search for the closest snapped line
index 9dde22a4e1f675e25ea5a9336f01dcacc4dfdf7c..da17ff81a4017769c2e97026ddf5fb68ae7512b7 100644 (file)
@@ -80,12 +80,12 @@ Inkscape::SnappedPoint Inkscape::SnappedLineSegment::intersect(SnappedLineSegmen
         Inkscape::SnappedLineSegment const *secondarySLS = use_this_as_primary ? &line : this;
         Geom::Coord primaryDist = use_this_as_primary ? Geom::L2(inters_pt - this->getPoint()) : Geom::L2(inters_pt - line.getPoint());
         Geom::Coord secondaryDist = use_this_as_primary ? Geom::L2(inters_pt - line.getPoint()) : Geom::L2(inters_pt - this->getPoint());
-        return SnappedPoint(inters_pt, SNAPSOURCE_UNDEFINED, primarySLS->getSourceNum(), SNAPTARGET_PATH_INTERSECTION, primaryDist, primarySLS->getTolerance(), primarySLS->getAlwaysSnap(), true, true,
+        return SnappedPoint(inters_pt, SNAPSOURCE_UNDEFINED, primarySLS->getSourceNum(), SNAPTARGET_PATH_INTERSECTION, primaryDist, primarySLS->getTolerance(), primarySLS->getAlwaysSnap(), true, false, true,
                                           secondaryDist, secondarySLS->getTolerance(), secondarySLS->getAlwaysSnap());
     }
 
     // No intersection
-    return SnappedPoint(Geom::Point(NR_HUGE, NR_HUGE), SNAPSOURCE_UNDEFINED, 0, SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, false, NR_HUGE, 0, false);
+    return SnappedPoint(Geom::Point(NR_HUGE, NR_HUGE), SNAPSOURCE_UNDEFINED, 0, SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, false, false, NR_HUGE, 0, false);
 };
 
 
@@ -161,14 +161,14 @@ Inkscape::SnappedPoint Inkscape::SnappedLine::intersect(SnappedLine const &line)
         Inkscape::SnappedLine const *secondarySL = use_this_as_primary ? &line : this;
         Geom::Coord primaryDist = use_this_as_primary ? Geom::L2(inters_pt - this->getPoint()) : Geom::L2(inters_pt - line.getPoint());
         Geom::Coord secondaryDist = use_this_as_primary ? Geom::L2(inters_pt - line.getPoint()) : Geom::L2(inters_pt - this->getPoint());
-        return SnappedPoint(inters_pt, Inkscape::SNAPSOURCE_UNDEFINED, primarySL->getSourceNum(), Inkscape::SNAPTARGET_UNDEFINED, primaryDist, primarySL->getTolerance(), primarySL->getAlwaysSnap(), true, true,
+        return SnappedPoint(inters_pt, Inkscape::SNAPSOURCE_UNDEFINED, primarySL->getSourceNum(), Inkscape::SNAPTARGET_UNDEFINED, primaryDist, primarySL->getTolerance(), primarySL->getAlwaysSnap(), true, false, true,
                                           secondaryDist, secondarySL->getTolerance(), secondarySL->getAlwaysSnap());
         // The type of the snap target is yet undefined, as we cannot tell whether
         // we're snapping to grid or the guide lines; must be set by on a higher level
     }
 
     // No intersection
-    return SnappedPoint(Geom::Point(NR_HUGE, NR_HUGE), SNAPSOURCE_UNDEFINED, 0, SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, false, NR_HUGE, 0, false);
+    return SnappedPoint(Geom::Point(NR_HUGE, NR_HUGE), SNAPSOURCE_UNDEFINED, 0, SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, false, false, NR_HUGE, 0, false);
 }
 
 // search for the closest snapped line segment
index 508ec8f62c1e49aaeb7f1bb1ccf489ef32e0e388..352f2dd1e363867cc81d5bd2d6cf0231669f1190 100644 (file)
 #include "preferences.h"
 
 // overloaded constructor
-Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &fully_constrained, Geom::OptRect target_bbox)
+Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained, Geom::OptRect target_bbox)
     : _point(p), _source(source), _source_num(source_num), _target(target), _distance(d), _tolerance(std::max(t,1.0)), _always_snap(a), _target_bbox(target_bbox)
 {
     // tolerance should never be smaller than 1 px, as it is used for normalization in isOtherSnapBetter. We don't want a division by zero.
     _at_intersection = false;
+    _constrained_snap = constrained_snap;
     _fully_constrained = fully_constrained;
     _second_distance = NR_HUGE;
     _second_tolerance = 1;
@@ -27,13 +28,14 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const
     _pointer_distance = NR_HUGE;
 }
 
-Inkscape::SnappedPoint::SnappedPoint(Inkscape::SnapCandidatePoint const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &fully_constrained)
+Inkscape::SnappedPoint::SnappedPoint(Inkscape::SnapCandidatePoint const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained)
     : _target(target), _distance(d), _tolerance(std::max(t,1.0)), _always_snap(a)
 {
     _point = p.getPoint();
     _source = p.getSourceType();
     _source_num = p.getSourceNum();
     _at_intersection = false;
+    _constrained_snap = constrained_snap;
     _fully_constrained = fully_constrained;
     _second_distance = NR_HUGE;
     _second_tolerance = 1;
@@ -44,8 +46,8 @@ Inkscape::SnappedPoint::SnappedPoint(Inkscape::SnapCandidatePoint const &p, Snap
 
 }
 
-Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &at_intersection, bool const &fully_constrained, Geom::Coord const &d2, Geom::Coord const &t2, bool const &a2)
-    : _point(p), _source(source), _source_num(source_num), _target(target), _at_intersection(at_intersection), _fully_constrained(fully_constrained), _distance(d), _tolerance(std::max(t,1.0)), _always_snap(a),
+Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &at_intersection, bool const &constrained_snap, bool const &fully_constrained, Geom::Coord const &d2, Geom::Coord const &t2, bool const &a2)
+    : _point(p), _source(source), _source_num(source_num), _target(target), _at_intersection(at_intersection), _constrained_snap(constrained_snap), _fully_constrained(fully_constrained), _distance(d), _tolerance(std::max(t,1.0)), _always_snap(a),
     _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
@@ -62,6 +64,7 @@ Inkscape::SnappedPoint::SnappedPoint()
     _source_num = 0,
     _target = SNAPTARGET_UNDEFINED,
     _at_intersection = false;
+    _constrained_snap = false;
     _fully_constrained = false;
     _distance = NR_HUGE;
     _tolerance = 1;
@@ -155,7 +158,8 @@ bool Inkscape::SnappedPoint::isOtherSnapBetter(Inkscape::SnappedPoint const &oth
                 // however be very large. To compare these in a fair way, we will have to normalize these metrics first
                 // The closest pointer distance will be normalized to 1.0; the other one will be > 1.0
                 // The snap distance will be normalized to 1.0 if it's equal to the snapper tolerance
-                double const norm_p = std::min(dist_pointer_this, dist_pointer_other);
+                double const norm_p = std::min(dist_pointer_this, dist_pointer_other) + 1;
+                // make sure norm_p is never too close to zero (e.g. when snapping the bbox-corner that was grabbed), by incr. with 1
                 double const norm_t_other = std::min(50.0, other_one.getTolerance());
                 double const norm_t_this = std::min(50.0, getTolerance());
                 dist_other = w * dist_pointer_other / norm_p + (1-w) * dist_other / norm_t_other;
@@ -180,9 +184,9 @@ bool Inkscape::SnappedPoint::isOtherSnapBetter(Inkscape::SnappedPoint const &oth
     // But in no case fall back from a snapper with "always snap" on to one with "always snap" off
     bool c2n = !other_one.getAlwaysSnap() && getAlwaysSnap();
     // or, if we have a fully constrained snappoint (e.g. to a node or an intersection), while the previous one was only partly constrained (e.g. to a line)
-    bool c3 = other_one.getFullyConstrained() && !getFullyConstrained();
+    bool c3 = (other_one.getFullyConstrained() && !other_one.getConstrainedSnap()) && !getFullyConstrained(); // Do not consider constrained snaps here, because these will always be fully constrained anyway
     // But in no case fall back; (has less priority than c3n, so it is allowed to fall back when c3 is true, see below)
-    bool c3n = !other_one.getFullyConstrained() && getFullyConstrained();
+    bool c3n = !other_one.getFullyConstrained() && (getFullyConstrained() && !getConstrainedSnap());
 
     // When both are fully constrained AND coincident, then prefer nodes over intersections
     bool d = other_one.getFullyConstrained() && getFullyConstrained() && (Geom::L2(other_one.getPoint() - getPoint()) < 1e-9);
@@ -192,7 +196,7 @@ bool Inkscape::SnappedPoint::isOtherSnapBetter(Inkscape::SnappedPoint const &oth
 
     // or, if it's just as close then consider the second distance
     bool c5a = (dist_other == dist_this);
-    bool c5b = other_one.getSecondSnapDistance() < getSecondSnapDistance();
+    bool c5b = (other_one.getSecondSnapDistance() < getSecondSnapDistance()) && (getSecondSnapDistance() < NR_HUGE);
 
     // std::cout << other_one.getPoint() << " (Other one, dist = " << dist_other << ") vs. " << getPoint() << " (this one, dist = " << dist_this << ") ---> ";
     // std::cout << "c1 = " << c1 << " | c2 = " << c2 << " | c2n = " << c2n << " | c3 = " << c3 << " | c3n = " << c3n << " | c4 = " << c4 << " | c4n = " << c4n << " | c5a = " << c5a << " | c5b = " << c5b << std::endl;
index 10d36f57e33c30e7d4a24b75d7971bc51f9143c7..05e954e1e4ea6aaeb18a73ad0872f41ccb8936e9 100644 (file)
@@ -28,9 +28,9 @@ class SnappedPoint
 public:
     SnappedPoint();
     SnappedPoint(Geom::Point const &p);
-    SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &at_intersection, bool const &fully_constrained, Geom::Coord const &d2, Geom::Coord const &t2, bool const &a2);
-    SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &fully_constrained, Geom::OptRect target_bbox = Geom::OptRect());
-    SnappedPoint(SnapCandidatePoint const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &fully_constrained);
+    SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &at_intersection, bool const &constrained_snap, bool const &fully_constrained, Geom::Coord const &d2, Geom::Coord const &t2, bool const &a2);
+    SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained, Geom::OptRect target_bbox = Geom::OptRect());
+    SnappedPoint(SnapCandidatePoint const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained);
     ~SnappedPoint();
 
     Geom::Coord getSnapDistance() const {return _distance;}
@@ -61,6 +61,7 @@ public:
 
     bool getAtIntersection() const {return _at_intersection;}
     bool getFullyConstrained() const {return _fully_constrained;}
+    bool getConstrainedSnap() const {return _constrained_snap;}
     bool getSnapped() const {return _distance < NR_HUGE;}
     Geom::Point getTransformation() const {return _transformation;}
     void setTransformation(Geom::Point const t) {_transformation = t;}
@@ -97,6 +98,7 @@ protected:
     long _source_num; // Sequence number of the source point that snapped, if that point is part of a set of points. (starting at zero)
     SnapTargetType _target; // Describes to what we've snapped to
     bool _at_intersection; // If true, the snapped point is at an intersection
+    bool _constrained_snap; // If true, then the snapped point was found when looking for a constrained snap
     bool _fully_constrained; // When snapping for example to a node, then the snap will be "fully constrained".
                             // When snapping to a line however, the snap is only partly constrained (i.e. only in one dimension)