summaryrefslogtreecommitdiffstats
path: root/src/snapped-curve.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/snapped-curve.cpp')
-rw-r--r--src/snapped-curve.cpp93
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++