summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDiederik van Lierop <mail@diedenrezi.nl>2011-09-18 17:09:29 +0000
committerDiederik van Lierop <mail@diedenrezi.nl>2011-09-18 17:09:29 +0000
commit344d9e8077c05b86e7d423b5db163b3e3e541032 (patch)
tree1734ecbec437e8d5d381989dc499d49fc656f859 /src
parentGerman translation update (diff)
downloadinkscape-344d9e8077c05b86e7d423b5db163b3e3e541032.tar.gz
inkscape-344d9e8077c05b86e7d423b5db163b3e3e541032.zip
Snap to guide-path intersections, and don't snap to paths when only path intersections are asked for
Fixed bugs: - https://launchpad.net/bugs/847457 - https://launchpad.net/bugs/850982 (bzr r10639)
Diffstat (limited to 'src')
-rw-r--r--src/display/snap-indicator.cpp3
-rw-r--r--src/snap-enums.h1
-rw-r--r--src/snap-preferences.cpp2
-rw-r--r--src/snap.cpp32
-rw-r--r--src/snapped-curve.cpp93
-rw-r--r--src/snapped-curve.h5
6 files changed, 123 insertions, 13 deletions
diff --git a/src/display/snap-indicator.cpp b/src/display/snap-indicator.cpp
index 5b2314d51..0f31a24b9 100644
--- a/src/display/snap-indicator.cpp
+++ b/src/display/snap-indicator.cpp
@@ -102,6 +102,9 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap
case SNAPTARGET_PATH_INTERSECTION:
target_name = _("path intersection");
break;
+ case SNAPTARGET_PATH_GUIDE_INTERSECTION:
+ target_name = _("guide-path intersection");
+ break;
case SNAPTARGET_BBOX_CORNER:
target_name = _("bounding box corner");
break;
diff --git a/src/snap-enums.h b/src/snap-enums.h
index 8a95bb2dd..5ade54354 100644
--- a/src/snap-enums.h
+++ b/src/snap-enums.h
@@ -69,6 +69,7 @@ enum SnapTargetType {
SNAPTARGET_LINE_MIDPOINT,
SNAPTARGET_PATH,
SNAPTARGET_PATH_INTERSECTION,
+ SNAPTARGET_PATH_GUIDE_INTERSECTION,
SNAPTARGET_ELLIPSE_QUADRANT_POINT, // this corner is at the center of the stroke
SNAPTARGET_RECT_CORNER, // of a rectangle, so this corner is at the center of the stroke
//-------------------------------------------------------------------
diff --git a/src/snap-preferences.cpp b/src/snap-preferences.cpp
index fa5903c37..25e00718c 100644
--- a/src/snap-preferences.cpp
+++ b/src/snap-preferences.cpp
@@ -147,6 +147,8 @@ void Inkscape::SnapPreferences::_mapTargetToArrayIndex(Inkscape::SnapTargetType
target = SNAPTARGET_NODE_CUSP;
} else if (target == SNAPTARGET_ELLIPSE_QUADRANT_POINT) {
target = SNAPTARGET_NODE_SMOOTH;
+ } else if (target == SNAPTARGET_PATH_GUIDE_INTERSECTION) {
+ target = SNAPTARGET_PATH_INTERSECTION;
}
diff --git a/src/snap.cpp b/src/snap.cpp
index 631704b5c..eeca66d74 100644
--- a/src/snap.cpp
+++ b/src/snap.cpp
@@ -1168,19 +1168,13 @@ Inkscape::SnappedPoint SnapManager::findBestSnap(Inkscape::SnapCandidatePoint co
// search for the closest snapped curve
Inkscape::SnappedCurve closestCurve;
- if (getClosestCurve(isr.curves, closestCurve)) {
+ // We might have collected the paths only to snap to their intersection, without the intention to snap to the paths themselves
+ // Therefore we explicitly check whether the paths should be considered as snap targets themselves
+ bool exclude_paths = !snapprefs.isTargetSnappable(Inkscape::SNAPTARGET_PATH);
+ if (getClosestCurve(isr.curves, closestCurve, exclude_paths)) {
sp_list.push_back(Inkscape::SnappedPoint(closestCurve));
}
- if (snapprefs.isTargetSnappable(Inkscape::SNAPTARGET_PATH_INTERSECTION)) {
- // search for the closest snapped intersection of curves
- Inkscape::SnappedPoint closestCurvesIntersection;
- if (getClosestIntersectionCS(isr.curves, p.getPoint(), closestCurvesIntersection, _desktop->dt2doc())) {
- closestCurvesIntersection.setSource(p.getSourceType());
- sp_list.push_back(closestCurvesIntersection);
- }
- }
-
// search for the closest snapped grid line
Inkscape::SnappedLine closestGridLine;
if (getClosestSL(isr.grid_lines, closestGridLine)) {
@@ -1200,6 +1194,24 @@ Inkscape::SnappedPoint SnapManager::findBestSnap(Inkscape::SnapCandidatePoint co
// the grid/guide/path we're snapping to. This snappoint is therefore fully constrained, so there's
// no need to look for additional intersections
if (!constrained) {
+ if (snapprefs.isTargetSnappable(Inkscape::SNAPTARGET_PATH_INTERSECTION)) {
+ // search for the closest snapped intersection of curves
+ Inkscape::SnappedPoint closestCurvesIntersection;
+ if (getClosestIntersectionCS(isr.curves, p.getPoint(), closestCurvesIntersection, _desktop->dt2doc())) {
+ closestCurvesIntersection.setSource(p.getSourceType());
+ sp_list.push_back(closestCurvesIntersection);
+ }
+ }
+
+ if (snapprefs.isTargetSnappable(Inkscape::SNAPTARGET_PATH_GUIDE_INTERSECTION)) {
+ // search for the closest snapped intersection of a guide with a curve
+ Inkscape::SnappedPoint closestCurveGuideIntersection;
+ if (getClosestIntersectionCL(isr.curves, isr.guide_lines, p.getPoint(), closestCurveGuideIntersection, _desktop->dt2doc())) {
+ closestCurveGuideIntersection.setSource(p.getSourceType());
+ sp_list.push_back(closestCurveGuideIntersection);
+ }
+ }
+
// search for the closest snapped intersection of grid lines
Inkscape::SnappedPoint closestGridPoint;
if (getClosestIntersectionSL(isr.grid_lines, closestGridPoint)) {
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++
diff --git a/src/snapped-curve.h b/src/snapped-curve.h
index ed04576df..8b1080dc4 100644
--- a/src/snapped-curve.h
+++ b/src/snapped-curve.h
@@ -14,6 +14,7 @@
#include <vector>
#include <list>
#include "snapped-point.h"
+#include "snapped-line.h"
#include <2geom/forward.h>
namespace Inkscape
@@ -27,6 +28,7 @@ public:
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);
~SnappedCurve();
Inkscape::SnappedPoint intersect(SnappedCurve const &curve, Geom::Point const &p, Geom::Affine dt2doc) const; //intersect with another SnappedCurve
+ Inkscape::SnappedPoint intersect(SnappedLine const &line, Geom::Point const &p, Geom::Affine dt2doc) const; //intersect with a SnappedLine
private:
Geom::Curve const *_curve;
@@ -36,8 +38,9 @@ private:
}
-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 = false);
bool getClosestIntersectionCS(std::list<Inkscape::SnappedCurve> const &list, Geom::Point const &p, Inkscape::SnappedPoint &result, Geom::Affine dt2doc);
+bool getClosestIntersectionCL(std::list<Inkscape::SnappedCurve> const &list1, std::list<Inkscape::SnappedLine> const &list2, Geom::Point const &p, Inkscape::SnappedPoint &result, Geom::Affine dt2doc);
#endif /* !SEEN_SNAPPEDCURVE_H */