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.cpp117
1 files changed, 103 insertions, 14 deletions
diff --git a/src/snapped-curve.cpp b/src/snapped-curve.cpp
index 25bde8105..8fdf1d46f 100644
--- a/src/snapped-curve.cpp
+++ b/src/snapped-curve.cpp
@@ -1,6 +1,6 @@
/**
* \file src/snapped-curve.cpp
- * \brief SnappedCurve class.
+ * SnappedCurve class.
*
* Authors:
* Diederik van Lierop <mail@diedenrezi.nl>
@@ -20,7 +20,7 @@ Inkscape::SnappedCurve::SnappedCurve(Geom::Point const &snapped_point, int num_p
_tolerance = std::max(snapped_tolerance, 1.0);
_always_snap = always_snap;
_curve = curve;
- _second_distance = NR_HUGE;
+ _second_distance = Geom::infinity();
_second_tolerance = 1;
_second_always_snap = false;
_point = snapped_point;
@@ -36,11 +36,11 @@ Inkscape::SnappedCurve::SnappedCurve()
{
_num_path = 0;
_num_segm = 0;
- _distance = NR_HUGE;
+ _distance = Geom::infinity();
_tolerance = 1;
_always_snap = false;
_curve = NULL;
- _second_distance = NR_HUGE;
+ _second_distance = Geom::infinity();
_second_tolerance = 1;
_second_always_snap = false;
_point = Geom::Point(0,0);
@@ -61,15 +61,15 @@ 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));
if (cs.size() > 0) {
// There might be multiple intersections: find the closest
- Geom::Coord best_dist = NR_HUGE;
- Geom::Point best_p = Geom::Point(NR_HUGE, NR_HUGE);
- for (Geom::Crossings::const_iterator i = cs.begin(); i != cs.end(); i++) {
+ 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);
@@ -106,15 +106,70 @@ Inkscape::SnappedPoint Inkscape::SnappedCurve::intersect(SnappedCurve const &cur
}
// No intersection
- return SnappedPoint(Geom::Point(NR_HUGE, NR_HUGE), SNAPSOURCE_UNDEFINED, 0, SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, false, false, NR_HUGE, 0, false);
+ 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); //
+ const 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++) {
+ 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;
@@ -129,12 +184,45 @@ 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++) {
+ for (std::list<Inkscape::SnappedCurve>::const_iterator i = list.begin(); i != 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
std::list<Inkscape::SnappedCurve>::const_iterator j = i;
- j++;
- for (; j != list.end(); j++) {
+ ++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;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ 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()) {
@@ -158,6 +246,7 @@ bool getClosestIntersectionCS(std::list<Inkscape::SnappedCurve> const &list, Geo
return success;
}
+
/*
Local Variables:
mode:c++