Code

Node tool: special case node duplication for endnodes - select new endnode
[inkscape.git] / src / snapped-curve.cpp
index 33403863869525231c775f17e9580ed2a378190e..5deb4c449c214db0f9bd8511e67bc5e4a34bdffa 100644 (file)
 #include <2geom/crossing.h>
 #include <2geom/path-intersection.h>
 
-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, SnapSourceType source, long source_num, SnapTargetType target)
+Inkscape::SnappedCurve::SnappedCurve(Geom::Point const &snapped_point, int num_path, int num_segm, Geom::Coord const &snapped_distance, Geom::Coord const &snapped_tolerance, bool const &always_snap, bool const &fully_constrained, Geom::Curve const *curve, SnapSourceType source, long source_num, SnapTargetType target, Geom::OptRect target_bbox)
 {
+    _num_path = num_path;
+    _num_segm = num_segm;
     _distance = snapped_distance;
     _tolerance = std::max(snapped_tolerance, 1.0);
     _always_snap = always_snap;
@@ -27,10 +29,13 @@ Inkscape::SnappedCurve::SnappedCurve(Geom::Point const &snapped_point, Geom::Coo
     _source = source;
     _source_num = source_num;
     _target = target;
+    _target_bbox = target_bbox;
 }
 
 Inkscape::SnappedCurve::SnappedCurve()
 {
+    _num_path = 0;
+    _num_segm = 0;
     _distance = NR_HUGE;
     _tolerance = 1;
     _always_snap = false;
@@ -42,8 +47,9 @@ Inkscape::SnappedCurve::SnappedCurve()
     _at_intersection = false;
     _fully_constrained = false;
     _source = SNAPSOURCE_UNDEFINED;
-    _source_num = 0;
+    _source_num = -1;
     _target = SNAPTARGET_UNDEFINED;
+    _target_bbox = Geom::OptRect();
 }
 
 Inkscape::SnappedCurve::~SnappedCurve()
@@ -66,6 +72,16 @@ Inkscape::SnappedPoint Inkscape::SnappedCurve::intersect(SnappedCurve const &cur
         for (Geom::Crossings::const_iterator i = cs.begin(); i != cs.end(); i++) {
             Geom::Point p_ix = this->_curve->pointAt((*i).ta);
             Geom::Coord dist = Geom::distance(p_ix, p);
+
+            // Test if we have two segments (curves) from the same path..
+            if (this->_num_path == curve._num_path) {
+                // Never try to intersect a segment with itself
+                if (this->_num_segm == curve._num_segm) continue;
+                // Two subsequent segments (curves) in a path will have a common node; this node is not considered to be an intersection
+                if (this->_num_segm == curve._num_segm + 1 && (*i).ta == 0 && (*i).tb == 1) continue;
+                if (this->_num_segm + 1 == curve._num_segm && (*i).ta == 1 && (*i).tb == 0) continue;
+            }
+
             if (dist < best_dist) {
                 best_dist = dist;
                 best_p = p_ix;
@@ -85,12 +101,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
@@ -114,22 +130,27 @@ bool getClosestIntersectionCS(std::list<Inkscape::SnappedCurve> const &list, Geo
     bool success = false;
 
     for (std::list<Inkscape::SnappedCurve>::const_iterator i = list.begin(); i != list.end(); i++) {
-        std::list<Inkscape::SnappedCurve>::const_iterator j = i;
-        j++;
-        for (; j != list.end(); j++) {
-            Inkscape::SnappedPoint sp = (*i).intersect(*j, p, dt2doc);
-            if (sp.getAtIntersection()) {
-                // if it's the first point
-                bool const c1 = !success;
-                // or, if it's closer
-                bool const c2 = sp.getSnapDistance() < result.getSnapDistance();
-                // or, if it's just as close then look at the other distance
-                // (only relevant for snapped points which are at an intersection)
-                bool const c3 = (sp.getSnapDistance() == result.getSnapDistance()) && (sp.getSecondSnapDistance() < result.getSecondSnapDistance());
-                // then prefer this point over the previous one
-                if (c1 || c2 || c3) {
-                    result = sp;
-                    success = true;
+        if ((*i).getTarget() != Inkscape::SNAPTARGET_BBOX_EDGE) { // We don't support snapping to intersections of bboxes,
+            // as this would require two bboxes two be flashed in the snap indicator
+            std::list<Inkscape::SnappedCurve>::const_iterator j = i;
+            j++;
+            for (; j != list.end(); j++) {
+                if ((*j).getTarget() != Inkscape::SNAPTARGET_BBOX_EDGE) { // We don't support snapping to intersections of bboxes
+                    Inkscape::SnappedPoint sp = (*i).intersect(*j, p, dt2doc);
+                    if (sp.getAtIntersection()) {
+                        // if it's the first point
+                        bool const c1 = !success;
+                        // or, if it's closer
+                        bool const c2 = sp.getSnapDistance() < result.getSnapDistance();
+                        // or, if it's just as close then look at the other distance
+                        // (only relevant for snapped points which are at an intersection)
+                        bool const c3 = (sp.getSnapDistance() == result.getSnapDistance()) && (sp.getSecondSnapDistance() < result.getSecondSnapDistance());
+                        // then prefer this point over the previous one
+                        if (c1 || c2 || c3) {
+                            result = sp;
+                            success = true;
+                        }
+                    }
                 }
             }
         }