Code

1) Improve the way the distance to the pointer is taken into account when finding...
authordvlierop2 <dvlierop2@users.sourceforge.net>
Sun, 23 Nov 2008 13:55:26 +0000 (13:55 +0000)
committerdvlierop2 <dvlierop2@users.sourceforge.net>
Sun, 23 Nov 2008 13:55:26 +0000 (13:55 +0000)
2) Use this distance also when snapping nodes in the path editor
3) Add a slider in the preferences dialog to control the weighing of this distance

14 files changed:
src/context-fns.cpp
src/nodepath.cpp
src/nodepath.h
src/object-snapper.cpp
src/preferences-skeleton.h
src/seltrans.cpp
src/snap.cpp
src/snapped-curve.cpp
src/snapped-line.cpp
src/snapped-point.cpp
src/snapped-point.h
src/snapper.cpp
src/ui/dialog/inkscape-preferences.cpp
src/ui/dialog/inkscape-preferences.h

index c80def78786f2dee63ad867379ada857d1db749d..c394e38ca7b62f826b64f7d7107bed5e52d166d2 100644 (file)
@@ -140,7 +140,7 @@ Geom::Rect Inkscape::snap_rectangular_box(SPDesktop const *desktop, SPItem *item
                                      Inkscape::Snapper::ConstraintLine(p[1] - p[0]));
 
             /* Choose the best snap and update points accordingly */
-            if (s[0].getDistance() < s[1].getDistance()) {
+            if (s[0].getSnapDistance() < s[1].getSnapDistance()) {
                 if (s[0].getSnapped()) {
                     p[0] = s[0].getPoint();
                     p[1] = 2 * center - s[0].getPoint();
@@ -178,7 +178,7 @@ Geom::Rect Inkscape::snap_rectangular_box(SPDesktop const *desktop, SPItem *item
         s[0] = m.freeSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, to_2geom(p[0]));
         s[1] = m.freeSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, to_2geom(p[1]));
 
-        if (s[0].getDistance() < s[1].getDistance()) {
+        if (s[0].getSnapDistance() < s[1].getSnapDistance()) {
             if (s[0].getSnapped()) {
                 p[0] = s[0].getPoint();
                 p[1] = 2 * center - s[0].getPoint();
index 34c850d086099b87a8bf33c85226ebc46ef18de8..234aba4cc6675e223544937b67f00981d93a1f3f 100644 (file)
@@ -314,6 +314,8 @@ Inkscape::NodePath::Path *sp_nodepath_new(SPDesktop *desktop, SPObject *object,
     } else {
         np->item = SP_ITEM(object);
     }
+    
+    np->drag_origin_mouse = Geom::Point(NR_HUGE, NR_HUGE);
 
     // we need to update item's transform from the repr here,
     // because they may be out of sync when we respond
@@ -1335,10 +1337,9 @@ static void sp_nodepath_selected_nodes_move(Inkscape::NodePath::Path *nodepath,
                                             bool const snap, bool constrained = false, 
                                             Inkscape::Snapper::ConstraintLine const &constraint = Geom::Point())
 {
-    Geom::Coord best = NR_HUGE;
     Geom::Point delta(dx, dy);
     Geom::Point best_pt = delta;
-    Inkscape::SnappedPoint best_abs;
+    Inkscape::SnappedPoint best;
     
     if (snap) {    
         /* When dragging a (selected) node, it should only snap to other nodes (i.e. unselected nodes), and
@@ -1363,6 +1364,7 @@ static void sp_nodepath_selected_nodes_move(Inkscape::NodePath::Path *nodepath,
             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);
@@ -1370,15 +1372,18 @@ static void sp_nodepath_selected_nodes_move(Inkscape::NodePath::Path *nodepath,
             } else {
                 s = m.freeSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, to_2geom(n->pos + delta));
             }            
-            if (s.getSnapped() && (s.getDistance() < best)) {
-                best = s.getDistance();
-                best_abs = s;
-                best_pt = from_2geom(s.getPoint()) - n->pos;
+            
+            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 (best_abs.getSnapped()) {
-            nodepath->desktop->snapindicator->set_new_snappoint(best_abs);
+        if (best.getSnapped()) {
+            nodepath->desktop->snapindicator->set_new_snappoint(best);
         } else {
             nodepath->desktop->snapindicator->remove_snappoint();    
         }
@@ -3546,7 +3551,7 @@ static void node_clicked(SPKnot */*knot*/, guint state, gpointer data)
 /**
  * Mouse grabbed node callback.
  */
-static void node_grabbed(SPKnot */*knot*/, guint state, gpointer data)
+static void node_grabbed(SPKnot *knot, guint state, gpointer data)
 {
    Inkscape::NodePath::Node *n = (Inkscape::NodePath::Node *) data;
 
@@ -3555,6 +3560,9 @@ static void node_grabbed(SPKnot */*knot*/, guint state, gpointer data)
     }
 
     n->is_dragging = true;
+    // Reconstruct and store the location of the mouse pointer at the time when we started dragging (needed for snapping)
+    n->subpath->nodepath->drag_origin_mouse = knot->grabbed_rel_pos + knot->drag_origin;  
+    
     sp_canvas_force_full_redraw_after_interruptions(n->subpath->nodepath->desktop->canvas, 5);
 
     sp_nodepath_remember_origins (n->subpath->nodepath);
@@ -3569,6 +3577,7 @@ static void node_ungrabbed(SPKnot */*knot*/, guint /*state*/, gpointer data)
 
    n->dragging_out = NULL;
    n->is_dragging = false;
+   n->subpath->nodepath->drag_origin_mouse = Geom::Point(NR_HUGE, NR_HUGE);
    sp_canvas_end_forced_full_redraws(n->subpath->nodepath->desktop->canvas);
 
    sp_nodepath_update_repr(n->subpath->nodepath, _("Move nodes"));
@@ -4579,7 +4588,7 @@ sp_nodepath_node_new(Inkscape::NodePath::SubPath *sp, Inkscape::NodePath::Node *
     n->pos      = *pos;
     n->p.pos    = *ppos;
     n->n.pos    = *npos;
-
+    
     n->dragging_out = NULL;
 
     Inkscape::NodePath::Node *prev;
index 262b93d0434fe53a9dbe63841055ad0cd362a8be..8c3d2744221f749e0edd4af1862595e349360672 100644 (file)
@@ -276,6 +276,10 @@ class Path {
     /// there isn't any); we also consider the node mouseovered if it is covered
     /// by one of its handles and the latter is mouseovered
     static Node *active_node;
+    
+    /// Location of mouse pointer when we started dragging, needed for snapping
+       Geom::Point drag_origin_mouse;
+
 };
 
 }  // namespace NodePath
index 1fd566c8235aa3c478ff6bf5b13007450eea74c7..06f24c47fa1129d28623bfbedea13f6710a82116 100644 (file)
@@ -247,7 +247,7 @@ void Inkscape::ObjectSnapper::_snapNodes(SnappedConstraints &sc,
     
     for (std::vector<Geom::Point>::const_iterator k = _points_to_snap_to->begin(); k != _points_to_snap_to->end(); k++) {
         Geom::Coord dist = Geom::L2(*k - p);        
-        if (dist < getSnapperTolerance() && dist < s.getDistance()) {
+        if (dist < getSnapperTolerance() && dist < s.getSnapDistance()) {
             s = SnappedPoint(*k, SNAPTARGET_NODE, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true);
             success = true;
         }
@@ -276,7 +276,7 @@ void Inkscape::ObjectSnapper::_snapTranslatingGuideToNodes(SnappedConstraints &s
         Geom::Point p_proj = project_on_linesegment(*k, p, p + Geom::rot90(guide_normal));
         Geom::Coord dist = Geom::L2(*k - 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() && dist < s.getDistance())) {
+        if ((dist < tol && dist2 < tol) || (getSnapperAlwaysSnap() && dist < s.getSnapDistance())) {
             s = SnappedPoint(*k, SNAPTARGET_NODE, dist, tol, getSnapperAlwaysSnap(), true);
             success = true;
         }
index 0b860174891b64fe64e464387082cf2116cb04c1..1868b9c888dfa58b9ecc8881c6f8a72a7a05e90c 100644 (file)
@@ -249,6 +249,7 @@ static char const preferences_skeleton[] =
 "    <group id=\"transientpolicy\" value=\"1\"/>\n"
 "    <group id=\"scrollingacceleration\" value=\"0.4\"/>\n"
 "    <group id=\"snapdelay\" value=\"150\"/>\n"        
+"    <group id=\"snapweight\" value=\"0.5\"/>\n"
 "    <group id=\"snapindicator\" value=\"1\"/>\n"
 "    <group id=\"autoscrollspeed\" value=\"0.7\"/>\n"
 "    <group id=\"autoscrolldistance\" value=\"-10\"/>\n"
index 614ce7584f7d4c0de05bd3ec9e5f151f36afe512..34ea17a649ef356e10abdb5a067efc97d705aade 100644 (file)
@@ -1413,10 +1413,9 @@ void Inkscape::SelTrans::moveTo(Geom::Point const &xy, guint state)
 
         /* Pick one */
         Inkscape::SnappedPoint best_snapped_point;
-        g_assert(best_snapped_point.getDistance() == NR_HUGE);
         for (std::list<Inkscape::SnappedPoint>::const_iterator i = s.begin(); i != s.end(); i++) {
             if (i->getSnapped()) {
-                if (i->getDistance() < best_snapped_point.getDistance()) {
+                if (best_snapped_point.isOtherOneBetter(*i, true)) {
                     best_snapped_point = *i;
                     dxy = i->getTransformation();
                 }
index ebce87c98fa40018ff20acf1736702b6091579e0..f6504efe3b16934965afe2d12d84c73060cc9890 100644 (file)
@@ -209,10 +209,12 @@ Geom::Point SnapManager::multipleOfGridPitch(Geom::Point const &t) const
                 snapper->freeSnap(sc, Inkscape::SnapPreferences::SNAPPOINT_NODE, t_offset, TRUE, Geom::OptRect(), NULL, NULL);
                 // Find the best snap for this grid, including intersections of the grid-lines
                 Inkscape::SnappedPoint s = findBestSnap(t_offset, sc, false);
-                if (s.getSnapped() && (s.getDistance() < nearest_distance)) {
-                    success = true;
+                if (s.getSnapped() && (s.getSnapDistance() < nearest_distance)) { 
+                    // use getSnapDistance() instead of getWeightedDistance() here because the pointer's position 
+                       // doesn't tell us anything about which node to snap
+                       success = true;
                     nearest_multiple = s.getPoint() - to_2geom(grid->origin);
-                    nearest_distance = s.getDistance();
+                    nearest_distance = s.getSnapDistance();
                 }
             }
         }
@@ -448,8 +450,9 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed(
             } else {
                snapped_point = freeSnap(type, *j, i == points.begin(), bbox);
             }
-               snapped_point.setPointerDistance(Geom::L2(pointer - *i));
         }
+        // std::cout << "dist = " << snapped_point.getSnapDistance() << std::endl;
+        snapped_point.setPointerDistance(Geom::L2(pointer - *i));
 
         Geom::Point result;
         Geom::Point scale_metric(NR_HUGE, NR_HUGE);
@@ -509,15 +512,15 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed(
                         }
                     }
                     // Store the metric for this transformation as a virtual distance
-                    snapped_point.setDistance(std::abs(result[dim] - transformation[dim]));
-                    snapped_point.setSecondDistance(NR_HUGE);
+                    snapped_point.setSnapDistance(std::abs(result[dim] - transformation[dim]));
+                    snapped_point.setSecondSnapDistance(NR_HUGE);
                     break;
                 case SKEW:
                     result[0] = (snapped_point.getPoint()[dim] - (*i)[dim]) / ((*i)[1 - dim] - origin[1 - dim]); // skew factor
                     result[1] = transformation[1]; // scale factor
                     // Store the metric for this transformation as a virtual distance
-                    snapped_point.setDistance(std::abs(result[0] - transformation[0])); 
-                    snapped_point.setSecondDistance(NR_HUGE);
+                    snapped_point.setSnapDistance(std::abs(result[0] - transformation[0])); 
+                    snapped_point.setSecondSnapDistance(NR_HUGE);
                     break;
                 default:
                     g_assert_not_reached();
@@ -548,10 +551,10 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed(
                     }
                 }
             } else { // For all transformations other than scaling
-                if (best_snapped_point.isOtherOneBetter(snapped_point)) {
-                    best_transformation = result;
+                if (best_snapped_point.isOtherOneBetter(snapped_point, true)) {
+                       best_transformation = result;
                     best_snapped_point = snapped_point;                    
-                }                
+                }
             }
         }
         
@@ -572,13 +575,13 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed(
         }
         best_metric = std::min(best_scale_metric[0], best_scale_metric[1]);
     } else { // For all transformations other than scaling
-        best_metric = best_snapped_point.getDistance();        
+        best_metric = best_snapped_point.getSnapDistance();        
     }
     
     best_snapped_point.setTransformation(best_transformation);
     // 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.setDistance(best_metric < 1e6 ? best_metric : NR_HUGE);
+    best_snapped_point.setSnapDistance(best_metric < 1e6 ? best_metric : NR_HUGE);
     return best_snapped_point;
 }
 
@@ -810,9 +813,9 @@ Inkscape::SnappedPoint SnapManager::findBestSnap(Geom::Point const &p, SnappedCo
     for (std::list<Inkscape::SnappedPoint>::const_iterator i = sp_list.begin(); i != sp_list.end(); i++) {
         // first find out if this snapped point is within snapping range
        // std::cout << "sp = " << from_2geom((*i).getPoint());
-        if ((*i).getDistance() <= (*i).getTolerance()) {
+        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)) { 
+            if (i == sp_list.begin() || bestSnappedPoint.isOtherOneBetter(*i, false)) { 
                 // then prefer this point over the previous one
                 bestSnappedPoint = *i;
             }
@@ -829,7 +832,7 @@ Inkscape::SnappedPoint SnapManager::findBestSnap(Geom::Point const &p, SnappedCo
         }
     }
     
-    // std::cout << "findBestSnap = " << bestSnappedPoint.getPoint() << std::endl;
+    // std::cout << "findBestSnap = " << bestSnappedPoint.getPoint() << " | dist = " << bestSnappedPoint.getSnapDistance() << std::endl;
     return bestSnappedPoint;         
 }
 
index 3a6512e5e0522097316d175d864565ed23aa5119..327de90bd215c99c1def2bc9c7292cafb970fd64 100644 (file)
 Inkscape::SnappedCurve::SnappedCurve(Geom::Point const &snapped_point, Geom::Coord const &snapped_distance, Geom::Coord const &snapped_tolerance, bool const &always_snap, bool const &fully_constrained, Geom::Curve const *curve)
 {
        _distance = snapped_distance;
-    _tolerance = snapped_tolerance;
+    _tolerance = std::max(snapped_tolerance, 1.0);
     _always_snap = always_snap;
     _curve = curve;
     _second_distance = NR_HUGE;
-    _second_tolerance = 0;
+    _second_tolerance = 1;
     _second_always_snap = false;
     _point = snapped_point;
     _at_intersection = false;
@@ -35,11 +35,11 @@ Inkscape::SnappedCurve::SnappedCurve(Geom::Point const &snapped_point, Geom::Coo
 Inkscape::SnappedCurve::SnappedCurve() 
 {
     _distance = NR_HUGE;
-    _tolerance = 0;
+    _tolerance = 1;
     _always_snap = false;
     _curve = NULL;
     _second_distance = NR_HUGE;
-    _second_tolerance = 0;
+    _second_tolerance = 1;
     _second_always_snap = false;
     _point = Geom::Point(0,0);
     _at_intersection = false;
@@ -73,7 +73,7 @@ Inkscape::SnappedPoint Inkscape::SnappedCurve::intersect(SnappedCurve const &cur
         }
         
         // Now we've found the closests intersection, return it as a SnappedPoint
-        bool const use_this_as_primary = _distance < curve.getDistance();
+        bool const use_this_as_primary = _distance < curve.getSnapDistance();
         Inkscape::SnappedCurve const *primaryC = use_this_as_primary ? this : &curve;
         Inkscape::SnappedCurve const *secondaryC = use_this_as_primary ? &curve : this;
         // The intersection should in fact be returned in desktop coordinates, but for this
@@ -83,8 +83,8 @@ 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(from_2geom(best_p), Inkscape::SNAPTARGET_PATH_INTERSECTION, primaryC->getDistance(), primaryC->getTolerance(), primaryC->getAlwaysSnap(), true, true,
-                                          secondaryC->getDistance(), secondaryC->getTolerance(), secondaryC->getAlwaysSnap());
+        return SnappedPoint(from_2geom(best_p), Inkscape::SNAPTARGET_PATH_INTERSECTION, primaryC->getSnapDistance(), primaryC->getTolerance(), primaryC->getAlwaysSnap(), true, true,
+                                          secondaryC->getSnapDistance(), secondaryC->getTolerance(), secondaryC->getAlwaysSnap());
     }
     
     // No intersection
@@ -97,7 +97,7 @@ bool getClosestCurve(std::list<Inkscape::SnappedCurve> const &list, Inkscape::Sn
     bool success = false;
     
     for (std::list<Inkscape::SnappedCurve>::const_iterator i = list.begin(); i != list.end(); i++) {
-        if ((i == list.begin()) || (*i).getDistance() < result.getDistance()) {
+        if ((i == list.begin()) || (*i).getSnapDistance() < result.getSnapDistance()) {
             result = *i;
             success = true;
         }   
@@ -120,10 +120,10 @@ bool getClosestIntersectionCS(std::list<Inkscape::SnappedCurve> const &list, Geo
                 // if it's the first point
                 bool const c1 = !success;
                 // or, if it's closer             
-                bool const c2 = sp.getDistance() < result.getDistance();
+                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
-                bool const c3 = (sp.getDistance() == result.getDistance()) && (sp.getSecondDistance() < result.getSecondDistance()); 
+                bool const c3 = (sp.getSnapDistance() == result.getSnapDistance()) && (sp.getSecondSnapDistance() < result.getSecondSnapDistance()); 
                 // then prefer this point over the previous one
                 if (c1 || c2 || c3) {  
                     result = sp;
index fc2d059dca4c82e81529344d8a22346b9f0f8056..48fc8205132161ee44f7c174487e632d2586b965 100644 (file)
@@ -17,11 +17,11 @@ Inkscape::SnappedLineSegment::SnappedLineSegment(Geom::Point const &snapped_poin
 {
        _point = snapped_point;
     _distance = snapped_distance;
-       _tolerance = snapped_tolerance;
+       _tolerance = std::max(snapped_tolerance, 1.0);
     _always_snap = always_snap;
        _at_intersection = false;
        _second_distance = NR_HUGE;
-    _second_tolerance = 0;
+    _second_tolerance = 1;
     _second_always_snap = false;
 }
 
@@ -31,11 +31,11 @@ Inkscape::SnappedLineSegment::SnappedLineSegment()
        _end_point_of_line = Geom::Point(0,0);
        _point = Geom::Point(0,0);
     _distance = NR_HUGE;
-       _tolerance = 0;
+       _tolerance = 1;
     _always_snap = false;
        _at_intersection = false;
        _second_distance = NR_HUGE;
-    _second_tolerance = 0;
+    _second_tolerance = 1;
     _second_always_snap = false;
 }
 
@@ -63,12 +63,12 @@ Inkscape::SnappedPoint Inkscape::SnappedLineSegment::intersect(SnappedLineSegmen
          * line, not the distance to the intersection. 
          * See the comment in Inkscape::SnappedLine::intersect
                */
-        bool const c2 = _distance < line.getDistance();
+        bool const c2 = _distance < line.getSnapDistance();
         bool const use_this_as_primary = c1 || c2;
         Inkscape::SnappedLineSegment const *primarySLS = use_this_as_primary ? this : &line;
         Inkscape::SnappedLineSegment const *secondarySLS = use_this_as_primary ? &line : this;
-        return SnappedPoint(intersection, SNAPTARGET_PATH_INTERSECTION, primarySLS->getDistance(), primarySLS->getTolerance(), primarySLS->getAlwaysSnap(), true, true,
-                                          secondarySLS->getDistance(), secondarySLS->getTolerance(), secondarySLS->getAlwaysSnap());
+        return SnappedPoint(intersection, SNAPTARGET_PATH_INTERSECTION, primarySLS->getSnapDistance(), primarySLS->getTolerance(), primarySLS->getAlwaysSnap(), true, true,
+                                          secondarySLS->getSnapDistance(), secondarySLS->getTolerance(), secondarySLS->getAlwaysSnap());
        }
     
     // No intersection
@@ -81,10 +81,10 @@ Inkscape::SnappedLine::SnappedLine(Geom::Point const &snapped_point, Geom::Coord
     : _normal_to_line(normal_to_line), _point_on_line(point_on_line)
 {
        _distance = snapped_distance;
-    _tolerance = snapped_tolerance;
+    _tolerance = std::max(snapped_tolerance, 1.0);
     _always_snap = always_snap;
        _second_distance = NR_HUGE;
-    _second_tolerance = 0;
+    _second_tolerance = 1;
     _second_always_snap = false;
        _point = snapped_point;
        _at_intersection = false;
@@ -95,10 +95,10 @@ Inkscape::SnappedLine::SnappedLine()
        _normal_to_line = Geom::Point(0,0);
        _point_on_line = Geom::Point(0,0);
        _distance = NR_HUGE;
-    _tolerance = 0;
+    _tolerance = 1;
     _always_snap = false;
        _second_distance = NR_HUGE;
-    _second_tolerance = 0;
+    _second_tolerance = 1;
     _second_always_snap = false;
        _point = Geom::Point(0,0);
        _at_intersection = false;
@@ -138,12 +138,12 @@ Inkscape::SnappedPoint Inkscape::SnappedLine::intersect(SnappedLine const &line)
          * than it, as that would rule the intersection out when comparing it with regular snappoint,
          * as the latter will always be closer
         */
-        bool const c2 = _distance < line.getDistance();
+        bool const c2 = _distance < line.getSnapDistance();
         bool const use_this_as_primary = c1 || c2;
         Inkscape::SnappedLine const *primarySL = use_this_as_primary ? this : &line;
         Inkscape::SnappedLine const *secondarySL = use_this_as_primary ? &line : this;
-        return SnappedPoint(intersection, Inkscape::SNAPTARGET_UNDEFINED, primarySL->getDistance(), primarySL->getTolerance(), primarySL->getAlwaysSnap(), true, true,
-                                          secondarySL->getDistance(), secondarySL->getTolerance(), secondarySL->getAlwaysSnap());
+        return SnappedPoint(intersection, Inkscape::SNAPTARGET_UNDEFINED, primarySL->getSnapDistance(), primarySL->getTolerance(), primarySL->getAlwaysSnap(), true, true,
+                                          secondarySL->getSnapDistance(), 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                                          
     }
@@ -158,7 +158,7 @@ bool getClosestSLS(std::list<Inkscape::SnappedLineSegment> const &list, Inkscape
        bool success = false;
        
        for (std::list<Inkscape::SnappedLineSegment>::const_iterator i = list.begin(); i != list.end(); i++) {
-               if ((i == list.begin()) || (*i).getDistance() < result.getDistance()) {
+               if ((i == list.begin()) || (*i).getSnapDistance() < result.getSnapDistance()) {
                        result = *i;
                        success = true;
                }       
@@ -181,10 +181,10 @@ bool getClosestIntersectionSLS(std::list<Inkscape::SnappedLineSegment> const &li
                                // if it's the first point
                bool const c1 = !success;
                                // or, if it's closer             
-                               bool const c2 = sp.getDistance() < result.getDistance();
+                               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
-                               bool const c3 = (sp.getDistance() == result.getDistance()) && (sp.getSecondDistance() < result.getSecondDistance()); 
+                               bool const c3 = (sp.getSnapDistance() == result.getSnapDistance()) && (sp.getSecondSnapDistance() < result.getSecondSnapDistance()); 
                                // then prefer this point over the previous one
                                if (c1 || c2 || c3) {  
                                        result = sp;
@@ -203,7 +203,7 @@ bool getClosestSL(std::list<Inkscape::SnappedLine> const &list, Inkscape::Snappe
        bool success = false;
        
        for (std::list<Inkscape::SnappedLine>::const_iterator i = list.begin(); i != list.end(); i++) {
-               if ((i == list.begin()) || (*i).getDistance() < result.getDistance()) {
+               if ((i == list.begin()) || (*i).getSnapDistance() < result.getSnapDistance()) {
                        result = *i;
                        success = true;
                }       
@@ -226,10 +226,10 @@ bool getClosestIntersectionSL(std::list<Inkscape::SnappedLine> const &list, Inks
                                // if it's the first point
                bool const c1 = !success;
                                // or, if it's closer             
-                               bool const c2 = sp.getDistance() < result.getDistance();
+                               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
-                               bool const c3 = (sp.getDistance() == result.getDistance()) && (sp.getSecondDistance() < result.getSecondDistance()); 
+                               bool const c3 = (sp.getSnapDistance() == result.getSnapDistance()) && (sp.getSecondSnapDistance() < result.getSecondSnapDistance()); 
                                // then prefer this point over the previous one
                                if (c1 || c2 || c3) {  
                                        result = sp;
@@ -254,10 +254,10 @@ bool getClosestIntersectionSL(std::list<Inkscape::SnappedLine> const &list1, std
                                // if it's the first point
                bool const c1 = !success;
                                // or, if it's closer             
-                               bool const c2 = sp.getDistance() < result.getDistance();
+                               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
-                               bool const c3 = (sp.getDistance() == result.getDistance()) && (sp.getSecondDistance() < result.getSecondDistance()); 
+                               bool const c3 = (sp.getSnapDistance() == result.getSnapDistance()) && (sp.getSecondSnapDistance() < result.getSecondSnapDistance()); 
                                // then prefer this point over the previous one
                                if (c1 || c2 || c3) {  
                                        result = sp;
index 1177e5f141c8720812b21dd2b539021b13b3c203..d03968a9444261e305ae948bf0b3c07303d45806 100644 (file)
@@ -9,27 +9,31 @@
  *  Released under GNU GPL, read the file 'COPYING' for more information.
  */
 
+#include <gtk/gtk.h>
 #include "snapped-point.h"
+#include "preferences.h"
 
 // overloaded constructor
 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(t), _always_snap(a)
+    : _point(p), _target(target), _distance(d), _tolerance(std::max(t,1.0)), _always_snap(a)
 {
-    _at_intersection = false;
+       // tolerance should never be smaller than 1 px, as it is used for normalization in isOtherOneBetter. We don't want a division by zero.
     _fully_constrained = fully_constrained;
     _second_distance = NR_HUGE;
-    _second_tolerance = 0;
+    _second_tolerance = 1;
     _second_always_snap = false;
     _transformation = Geom::Point(1,1);
-    _pointer_distance = 0;
+    _pointer_distance = NR_HUGE;
 }
 
 Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, 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), _target(target), _at_intersection(at_intersection), _fully_constrained(fully_constrained), _distance(d), _tolerance(t), _always_snap(a),
-    _second_distance(d2), _second_tolerance(t2), _second_always_snap(a2)
+    : _point(p), _target(target), _at_intersection(at_intersection), _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 
+    // isOtherOneBetter. We don't want a division by zero.
     _transformation = Geom::Point(1,1);
-    _pointer_distance = 0;
+    _pointer_distance = NR_HUGE;
 }
 
 Inkscape::SnappedPoint::SnappedPoint()
@@ -37,14 +41,14 @@ Inkscape::SnappedPoint::SnappedPoint()
     _point = Geom::Point(0,0);
     _target = SNAPTARGET_UNDEFINED, 
     _distance = NR_HUGE;
-    _tolerance = 0;
+    _tolerance = 1;
     _always_snap = false;
     _at_intersection = false;
     _second_distance = NR_HUGE;
-    _second_tolerance = 0;
+    _second_tolerance = 1;
     _second_always_snap = false;
     _transformation = Geom::Point(1,1);
-    _pointer_distance = 0;
+    _pointer_distance = NR_HUGE;
 }
 
 Inkscape::SnappedPoint::~SnappedPoint()
@@ -66,7 +70,7 @@ bool getClosestSP(std::list<Inkscape::SnappedPoint> &list, Inkscape::SnappedPoin
     bool success = false;
 
     for (std::list<Inkscape::SnappedPoint>::const_iterator i = list.begin(); i != list.end(); i++) {
-        if ((i == list.begin()) || (*i).getDistance() < result.getDistance()) {
+        if ((i == list.begin()) || (*i).getSnapDistance() < result.getSnapDistance()) {
             result = *i;
             success = true;
         }
@@ -75,13 +79,39 @@ bool getClosestSP(std::list<Inkscape::SnappedPoint> &list, Inkscape::SnappedPoin
     return success;
 }
 
-bool Inkscape::SnappedPoint::isOtherOneBetter(Inkscape::SnappedPoint const &other_one) const
+bool Inkscape::SnappedPoint::isOtherOneBetter(Inkscape::SnappedPoint const &other_one, bool weighted) const
 {
-    double const w = 0.25; // 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)
     
-       // If it's closer
-    bool c1 = (w * other_one.getPointerDistance() + (1-w) * other_one.getDistance()) < (w * getPointerDistance() + (1-w) * getDistance());
+       double dist_other = other_one.getSnapDistance();
+       double dist_this = getSnapDistance();    
+               
+       // The distance to the pointer should only be taken into account when finding the best snapped source node (when
+    // there's more than one). It is not useful when trying to find the best snapped target point.
+    // (both the snap distance and the pointer distance are measured in document pixels, not in screen pixels)
+    if (weighted) {
+               // 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);
+               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
+                       // mouse pointer distance must be set. 
+                       g_assert(getPointerDistance() != NR_HUGE || other_one.getPointerDistance() != NR_HUGE);
+                       // The snap distance will always be smaller than the tolerance set for the snapper. The pointer distance can
+                       // 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(getPointerDistance(), other_one.getPointerDistance());
+                       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 * other_one.getPointerDistance() / norm_p + (1-w) * dist_other / norm_t_other;
+                       dist_this = w * getPointerDistance() / norm_p + (1-w) * dist_this / norm_t_this;
+               }
+       }
+       
+    // If it's closer
+    bool c1 =  dist_other < dist_this;
     // or, if it's for a snapper with "always snap" turned on, and the previous wasn't
     bool c2 = other_one.getAlwaysSnap() && !getAlwaysSnap();
     // But in no case fall back from a snapper with "always snap" on to one with "always snap" off
@@ -92,10 +122,10 @@ bool Inkscape::SnappedPoint::isOtherOneBetter(Inkscape::SnappedPoint const &othe
     bool c3n = !other_one.getFullyConstrained() && getFullyConstrained(); 
     // or, if it's just as close then consider the second distance
     // (which is only relevant for points at an intersection)
-    bool c4a = (other_one.getDistance() == getDistance()); 
-    bool c4b = other_one.getSecondDistance() < getSecondDistance();
+    bool c4a = (dist_other == dist_this); 
+    bool c4b = other_one.getSecondSnapDistance() < getSecondSnapDistance();
     
-    // std::cout << "c1 = " << c1 << " | c2 = " << c2 << " | c2n = " << c2n << " | c3 = " << c3 << " | c3n = " << c3n << " | c4a = " << c4a << " | c4b = " << c4b;
+    // std::cout << "c1 = " << c1 << " | c2 = " << c2 << " | c2n = " << c2n << " | c3 = " << c3 << " | c3n = " << c3n << " | c4a = " << c4a << " | c4b = " << c4b << std::endl;
     return (c1 || c2 || c3 || (c4a && c4b)) && !c2n && (!c3n || c2);       
 }
 
index 254e464217bdfe5d8612978e98c454659b3c7506..bc5b2d39ee702d97753c9b9b9ec221b105039820 100644 (file)
@@ -46,12 +46,12 @@ public:
     SnappedPoint(Geom::Point const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &fully_constrained);
     ~SnappedPoint();
 
-    Geom::Coord getDistance() const {return _distance;}
-    void setDistance(Geom::Coord const d) {_distance = d;}
+    Geom::Coord getSnapDistance() const {return _distance;}
+    void setSnapDistance(Geom::Coord const d) {_distance = d;}
     Geom::Coord getTolerance() const {return _tolerance;}
     bool getAlwaysSnap() const {return _always_snap;}
-    Geom::Coord getSecondDistance() const {return _second_distance;}
-    void setSecondDistance(Geom::Coord const d) {_second_distance = d;}
+    Geom::Coord getSecondSnapDistance() const {return _second_distance;}
+    void setSecondSnapDistance(Geom::Coord const d) {_second_distance = d;}
     Geom::Coord getSecondTolerance() const {return _second_tolerance;}
     bool getSecondAlwaysSnap() const {return _second_always_snap;}
     Geom::Coord getPointerDistance() const {return _pointer_distance;}
@@ -79,7 +79,7 @@ public:
     void setTarget(SnapTargetType const target) {_target = target;}
     SnapTargetType getTarget() {return _target;}
     
-    bool isOtherOneBetter(SnappedPoint const &other_one) const;
+    bool isOtherOneBetter(SnappedPoint const &other_one, bool weighted) const;
     
 protected:
     Geom::Point _point; // Location of the snapped point
index 7e45681602f293e19f8774a5b234f8913014ece1..79f30fa3ce4eb7bea27517b97f6eab8e2b5c66e6 100644 (file)
@@ -22,7 +22,7 @@
 Inkscape::Snapper::Snapper(SnapManager const *sm, Geom::Coord const t) : 
        _snapmanager(sm), 
        _snap_enabled(true),
-       _snapper_tolerance(t)
+       _snapper_tolerance(std::max(t, 1.0))
 {
     g_assert(_snapmanager != NULL);
 }
@@ -33,7 +33,7 @@ Inkscape::Snapper::Snapper(SnapManager const *sm, Geom::Coord const t) :
  */
 void Inkscape::Snapper::setSnapperTolerance(Geom::Coord const d)
 {
-    _snapper_tolerance = d;
+    _snapper_tolerance = std::max(d, 1.0);
 }
 
 /**
index a436ce867e4a9d316df930ad4f05a7676b459779..e78d51af41f6ec1819e958da9c39c6bd5a5d49b5 100644 (file)
@@ -208,7 +208,12 @@ void InkscapePreferences::initPageSnapping()
            
        _snap_delay.init("/options/snapdelay/value", 0, 1000, 50, 100, 300, 0);
        _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);
+                       _("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_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);
 }
index a957ce6579a8343aedaa0e1e701040bc27ac3391..c62919c45eeafa1ebe2f9cbacd7fa3d1e8c6c098 100644 (file)
@@ -176,7 +176,7 @@ protected:
 
     PrefSpinButton  _importexport_export, _misc_recent, _misc_simpl;
     ZoomCorrRulerSlider _ui_zoom_correction;
-    PrefSlider         _snap_delay;
+    PrefSlider         _snap_delay, _snap_weight;
     PrefSpinButton  _misc_latency_skew;
     PrefCheckButton _misc_comment, _misc_forkvectors, _misc_scripts, _misc_namedicon_delay;
     PrefCombo       _misc_small_toolbar;