diff options
| author | Diederik van Lierop <mail@diedenrezi.nl> | 2011-09-18 17:09:29 +0000 |
|---|---|---|
| committer | Diederik van Lierop <mail@diedenrezi.nl> | 2011-09-18 17:09:29 +0000 |
| commit | 344d9e8077c05b86e7d423b5db163b3e3e541032 (patch) | |
| tree | 1734ecbec437e8d5d381989dc499d49fc656f859 /src | |
| parent | German translation update (diff) | |
| download | inkscape-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.cpp | 3 | ||||
| -rw-r--r-- | src/snap-enums.h | 1 | ||||
| -rw-r--r-- | src/snap-preferences.cpp | 2 | ||||
| -rw-r--r-- | src/snap.cpp | 32 | ||||
| -rw-r--r-- | src/snapped-curve.cpp | 93 | ||||
| -rw-r--r-- | src/snapped-curve.h | 5 |
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 */ |
