diff options
Diffstat (limited to 'src/snapped-curve.cpp')
| -rw-r--r-- | src/snapped-curve.cpp | 93 |
1 files changed, 91 insertions, 2 deletions
diff --git a/src/snapped-curve.cpp b/src/snapped-curve.cpp index 4876b896d..25b03428a 100644 --- a/src/snapped-curve.cpp +++ b/src/snapped-curve.cpp @@ -61,7 +61,7 @@ Inkscape::SnappedPoint Inkscape::SnappedCurve::intersect(SnappedCurve const &cur // Calculate the intersections of two curves, which are both within snapping range, and // return only the closest intersection // The point of intersection should be considered for snapping, but might be outside the snapping range - // PS: We need p (the location of the mouse pointer) for find out which intersection is the + // PS: We need p (the location of the mouse pointer) to find out which intersection is the // closest, as there might be multiple intersections of two curves Geom::Crossings cs = crossings(*(this->_curve), *(curve._curve)); @@ -109,12 +109,67 @@ Inkscape::SnappedPoint Inkscape::SnappedCurve::intersect(SnappedCurve const &cur return SnappedPoint(Geom::Point(Geom::infinity(), Geom::infinity()), SNAPSOURCE_UNDEFINED, 0, SNAPTARGET_UNDEFINED, Geom::infinity(), 0, false, false, false, false, Geom::infinity(), 0, false); } +Inkscape::SnappedPoint Inkscape::SnappedCurve::intersect(SnappedLine const &line, Geom::Point const &p, Geom::Affine dt2doc) const +{ + // Calculate the intersections of a curve with a line, which are both within snapping range, and + // return only the closest intersection + // The point of intersection should be considered for snapping, but might be outside the snapping range + // PS: We need p (the location of the mouse pointer) to find out which intersection is the + // closest, as there might be multiple intersections of a single curve with a line + + // 1) get a Geom::Line object from the SnappedLine + // 2) convert to document coordinates (line and p are in desktop coordinates, but the curves are in document coordinate) + // 3) create a Geom::LineSegment (i.e. a curve), because we cannot use a Geom::Line for calculating intersections + // (for this we will create a 2e6 pixels long linesegment, with t running from -1e6 to 1e6; this should be long + // enough for any practical purpose) + Geom::LineSegment line_segm = line.getLine().transformed(dt2doc).segment(-1e6, 1e6); // + Geom::Curve *line_as_curve = dynamic_cast<Geom::Curve const*>(&line_segm); + Geom::Crossings cs = crossings(*(this->_curve), *line_as_curve); + + if (cs.size() > 0) { + // There might be multiple intersections: find the closest + Geom::Coord best_dist = Geom::infinity(); + Geom::Point best_p = Geom::Point(Geom::infinity(), Geom::infinity()); + 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); + + if (dist < best_dist) { + best_dist = dist; + best_p = p_ix; + } + } + + // The intersection should in fact be returned in desktop coordinates + best_p = best_p * dt2doc; + + // Now we've found the closest intersection, return it as a SnappedPoint + if (_distance < line.getSnapDistance()) { + // curve is the closest, so this is our primary snap target + return SnappedPoint(best_p, Inkscape::SNAPSOURCE_UNDEFINED, this->getSourceNum(), Inkscape::SNAPTARGET_PATH_GUIDE_INTERSECTION, + Geom::L2(best_p - this->getPoint()), this->getTolerance(), this->getAlwaysSnap(), true, false, true, + Geom::L2(best_p - line.getPoint()), line.getTolerance(), line.getAlwaysSnap()); + } else { + return SnappedPoint(best_p, Inkscape::SNAPSOURCE_UNDEFINED, line.getSourceNum(), Inkscape::SNAPTARGET_PATH_GUIDE_INTERSECTION, + Geom::L2(best_p - line.getPoint()), line.getTolerance(), line.getAlwaysSnap(), true, false, true, + Geom::L2(best_p - this->getPoint()), this->getTolerance(), this->getAlwaysSnap()); + } + } + + // No intersection + return SnappedPoint(Geom::Point(Geom::infinity(), Geom::infinity()), SNAPSOURCE_UNDEFINED, 0, SNAPTARGET_UNDEFINED, Geom::infinity(), 0, false, false, false, false, Geom::infinity(), 0, false); +} + + // search for the closest snapped line -bool getClosestCurve(std::list<Inkscape::SnappedCurve> const &list, Inkscape::SnappedCurve &result) +bool getClosestCurve(std::list<Inkscape::SnappedCurve> const &list, Inkscape::SnappedCurve &result, bool exclude_paths) { bool success = false; for (std::list<Inkscape::SnappedCurve>::const_iterator i = list.begin(); i != list.end(); i++) { + if (exclude_paths && ((*i).getTarget() == Inkscape::SNAPTARGET_PATH)) { + continue; + } if ((i == list.begin()) || (*i).getSnapDistance() < result.getSnapDistance()) { result = *i; success = true; @@ -158,6 +213,40 @@ bool getClosestIntersectionCS(std::list<Inkscape::SnappedCurve> const &list, Geo return success; } + +// search for the closest intersection of two snapped curves, which are member of two different collections +bool getClosestIntersectionCL(std::list<Inkscape::SnappedCurve> const &curve_list, std::list<Inkscape::SnappedLine> const &line_list, Geom::Point const &p, Inkscape::SnappedPoint &result, Geom::Affine dt2doc) +{ + bool success = false; + + for (std::list<Inkscape::SnappedCurve>::const_iterator i = curve_list.begin(); i != curve_list.end(); i++) { + 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 + for (std::list<Inkscape::SnappedLine>::const_iterator j = line_list.begin(); j != line_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; + } + } + } + } + } + } + + return success; +} + /* Local Variables: mode:c++ |
