diff options
| -rw-r--r-- | src/display/canvas-axonomgrid.cpp | 7 | ||||
| -rw-r--r-- | src/display/canvas-axonomgrid.h | 3 | ||||
| -rw-r--r-- | src/display/canvas-grid.cpp | 5 | ||||
| -rw-r--r-- | src/display/canvas-grid.h | 2 | ||||
| -rw-r--r-- | src/geom.cpp | 2 | ||||
| -rw-r--r-- | src/geom.h | 5 | ||||
| -rw-r--r-- | src/guide-snapper.cpp | 6 | ||||
| -rw-r--r-- | src/guide-snapper.h | 6 | ||||
| -rw-r--r-- | src/line-snapper.cpp | 53 | ||||
| -rw-r--r-- | src/line-snapper.h | 8 | ||||
| -rw-r--r-- | src/object-snapper.cpp | 54 | ||||
| -rw-r--r-- | src/object-snapper.h | 11 | ||||
| -rw-r--r-- | src/snap.cpp | 164 | ||||
| -rw-r--r-- | src/snap.h | 14 | ||||
| -rw-r--r-- | src/snapped-line.cpp | 180 | ||||
| -rw-r--r-- | src/snapped-line.h | 76 | ||||
| -rw-r--r-- | src/snapped-point.cpp | 35 | ||||
| -rw-r--r-- | src/snapped-point.h | 32 | ||||
| -rw-r--r-- | src/snapper.cpp | 28 | ||||
| -rw-r--r-- | src/snapper.h | 30 |
20 files changed, 545 insertions, 176 deletions
diff --git a/src/display/canvas-axonomgrid.cpp b/src/display/canvas-axonomgrid.cpp index c00e2ea8f..66c9cc1fa 100644 --- a/src/display/canvas-axonomgrid.cpp +++ b/src/display/canvas-axonomgrid.cpp @@ -650,6 +650,13 @@ CanvasAxonomGridSnapper::_getSnapLines(NR::Point const &p) const return s; } +void CanvasAxonomGridSnapper::_addSnappedLine(SnappedConstraints &sc, NR::Point const snapped_point, NR::Coord const snapped_distance, NR::Point const normal_to_line, NR::Point const point_on_line) const +{ + SnappedInfiniteLine dummy = SnappedInfiniteLine(snapped_point, snapped_distance, normal_to_line, point_on_line); + sc.grid_lines.push_back(dummy); +} + + }; // namespace Inkscape diff --git a/src/display/canvas-axonomgrid.h b/src/display/canvas-axonomgrid.h index 157982416..68c011d30 100644 --- a/src/display/canvas-axonomgrid.h +++ b/src/display/canvas-axonomgrid.h @@ -92,7 +92,8 @@ public: private: LineList _getSnapLines(NR::Point const &p) const; - + void _addSnappedLine(SnappedConstraints &sc, NR::Point const snapped_point, NR::Coord const snapped_distance, NR::Point const normal_to_line, const NR::Point point_on_line) const; + CanvasAxonomGrid *grid; }; diff --git a/src/display/canvas-grid.cpp b/src/display/canvas-grid.cpp index e9eabad10..d3cbf9153 100644 --- a/src/display/canvas-grid.cpp +++ b/src/display/canvas-grid.cpp @@ -850,6 +850,11 @@ CanvasXYGridSnapper::_getSnapLines(NR::Point const &p) const return s; } +void CanvasXYGridSnapper::_addSnappedLine(SnappedConstraints &sc, NR::Point const snapped_point, NR::Coord const snapped_distance, NR::Point const normal_to_line, NR::Point const point_on_line) const +{ + SnappedInfiniteLine dummy = SnappedInfiniteLine(snapped_point, snapped_distance, normal_to_line, point_on_line); + sc.grid_lines.push_back(dummy); +} diff --git a/src/display/canvas-grid.h b/src/display/canvas-grid.h index 40e37c44f..ec5e52c90 100644 --- a/src/display/canvas-grid.h +++ b/src/display/canvas-grid.h @@ -162,7 +162,7 @@ public: private: LineList _getSnapLines(NR::Point const &p) const; - + void _addSnappedLine(SnappedConstraints &sc, NR::Point const snapped_point, NR::Coord const snapped_distance, NR::Point const normal_to_line, const NR::Point point_on_line) const; CanvasXYGrid *grid; }; diff --git a/src/geom.cpp b/src/geom.cpp index e59b0f302..5072b0c0e 100644 --- a/src/geom.cpp +++ b/src/geom.cpp @@ -17,7 +17,7 @@ * intersection; otherwise, \a result remains unchanged. * * This function finds the intersection of the two lines (infinite) - * defined by n0.X = d0 and x1.X = d1. The algorithm is as follows: + * defined by n0.X = d0 and n1.X = d1. The algorithm is as follows: * To compute the intersection point use Cramer's rule: * (see http://en.wikipedia.org/wiki/Cramer%27s_rule) * \verbatim diff --git a/src/geom.h b/src/geom.h index d00a4e37c..27e2533a2 100644 --- a/src/geom.h +++ b/src/geom.h @@ -1,3 +1,6 @@ +#ifndef SEEN_GEOM_H +#define SEEN_GEOM_H + /** * \file geom.h * \brief Various geometrical calculations @@ -28,3 +31,5 @@ enum IntersectorKind { IntersectorKind intersector_line_intersection(NR::Point const &n0, double const d0, NR::Point const &n1, double const d1, NR::Point &result); + +#endif /* !SEEN_GEOM_H */ diff --git a/src/guide-snapper.cpp b/src/guide-snapper.cpp index decfaf3cf..51b5e7680 100644 --- a/src/guide-snapper.cpp +++ b/src/guide-snapper.cpp @@ -52,6 +52,12 @@ bool Inkscape::GuideSnapper::ThisSnapperMightSnap() const return _named_view == NULL ? false : (_enabled && _snap_from != 0 && _named_view->showguides); } +void Inkscape::GuideSnapper::_addSnappedLine(SnappedConstraints &sc, NR::Point const snapped_point, NR::Coord const snapped_distance, NR::Point const normal_to_line, NR::Point const point_on_line) const +{ + SnappedInfiniteLine dummy = SnappedInfiniteLine(snapped_point, snapped_distance, normal_to_line, point_on_line); + sc.guide_lines.push_back(dummy); +} + /* Local Variables: mode:c++ diff --git a/src/guide-snapper.h b/src/guide-snapper.h index 15f484711..0605bdb97 100644 --- a/src/guide-snapper.h +++ b/src/guide-snapper.h @@ -28,12 +28,12 @@ namespace Inkscape class GuideSnapper : public LineSnapper { public: - GuideSnapper(SPNamedView const *nv, NR::Coord const d); - + GuideSnapper(SPNamedView const *nv, NR::Coord const d); bool ThisSnapperMightSnap() const; private: - LineList _getSnapLines(NR::Point const &p) const; + LineList _getSnapLines(NR::Point const &p) const; + void _addSnappedLine(SnappedConstraints &sc, NR::Point const snapped_point, NR::Coord const snapped_distance, NR::Point const normal_to_line, NR::Point const point_on_line) const; }; } diff --git a/src/line-snapper.cpp b/src/line-snapper.cpp index cf46671c8..3b91fb015 100644 --- a/src/line-snapper.cpp +++ b/src/line-snapper.cpp @@ -2,74 +2,65 @@ #include "libnr/nr-point-fns.h" #include "geom.h" #include "line-snapper.h" +#include "snapped-line.cpp" Inkscape::LineSnapper::LineSnapper(SPNamedView const *nv, NR::Coord const d) : Snapper(nv, d) { } -Inkscape::SnappedPoint Inkscape::LineSnapper::_doFreeSnap(Inkscape::Snapper::PointType const &t, +void Inkscape::LineSnapper::_doFreeSnap(SnappedConstraints &sc, + Inkscape::Snapper::PointType const &t, NR::Point const &p, bool const &f, std::vector<NR::Point> &points_to_snap, std::list<SPItem const *> const &it) const { - /* Snap along x (ie to vertical lines) */ - Inkscape::SnappedPoint const v = _doConstrainedSnap(t, p, f, points_to_snap, component_vectors[NR::X], it); - /* Snap along y (ie to horizontal lines) */ - Inkscape::SnappedPoint const h = _doConstrainedSnap(t, p, f, points_to_snap, component_vectors[NR::Y], it); + /* Snap along x (i.e. to vertical lines) */ + _doConstrainedSnap(sc, t, p, f, points_to_snap, component_vectors[NR::X], it); + /* Snap along y (i.e. to horizontal lines) */ + _doConstrainedSnap(sc, t, p, f, points_to_snap, component_vectors[NR::Y], it); - /* If we snapped to both, combine the two results. This is so that, for example, - ** we snap nicely to the intersection of two guidelines. - */ - if (v.getDistance() < NR_HUGE && h.getDistance() < NR_HUGE) { - return SnappedPoint(NR::Point(v.getPoint()[NR::X], h.getPoint()[NR::Y]), hypot(v.getDistance(), h.getDistance())); - } - - /* If we snapped to a vertical line, return that */ - if (v.getDistance() < NR_HUGE) { - return v; - } - - /* Otherwise just return any horizontal snap; if we didn't snap to that either - ** we haven't snapped to anything. - */ - return h; } -Inkscape::SnappedPoint Inkscape::LineSnapper::_doConstrainedSnap(Inkscape::Snapper::PointType const &t, +void Inkscape::LineSnapper::_doConstrainedSnap(SnappedConstraints &sc, + Inkscape::Snapper::PointType const &t, NR::Point const &p, bool const &f, std::vector<NR::Point> &points_to_snap, ConstraintLine const &c, std::list<SPItem const *> const &it) const + { Inkscape::SnappedPoint s = SnappedPoint(p, NR_HUGE); /* Get the lines that we will try to snap to */ const LineList lines = _getSnapLines(p); - + for (LineList::const_iterator i = lines.begin(); i != lines.end(); i++) { /* Normal to the line we're trying to snap along */ NR::Point const n(NR::rot90(NR::unit_vector(c.getDirection()))); - /* Constant term of the line we're trying to snap along */ - NR::Coord const q = dot(n, c.hasPoint() ? c.getPoint() : p); + NR::Point const point_on_line = c.hasPoint() ? c.getPoint() : p; + + /* Constant term of the line we're trying to snap along */ + NR::Coord const q = dot(n, point_on_line); /* Try to intersect this line with the target line */ - NR::Point t = p; + NR::Point t = NR::Point(NR_HUGE, NR_HUGE); IntersectorKind const k = intersector_line_intersection(n, q, component_vectors[i->first], i->second, t); - + if (k == INTERSECTS) { const NR::Coord dist = L2(t - p); - if (dist < getDistance() && dist < s.getDistance() ) { - s = SnappedPoint(t, dist); + //Store any line that's within snapping range + if (dist < getDistance()) { + _addSnappedLine(sc, t, dist, c.getDirection(), t); + //SnappedInfiniteLine dummy = SnappedInfiniteLine(t, dist, c.getDirection(), t); + //sc.infinite_lines.push_back(dummy); } } } - - return s; } /* diff --git a/src/line-snapper.h b/src/line-snapper.h index 5d93c858e..a15e6ae2d 100644 --- a/src/line-snapper.h +++ b/src/line-snapper.h @@ -25,13 +25,15 @@ protected: typedef std::list<std::pair<NR::Dim2, NR::Coord> > LineList; private: - SnappedPoint _doFreeSnap(Inkscape::Snapper::PointType const &t, + void _doFreeSnap(SnappedConstraints &sc, + Inkscape::Snapper::PointType const &t, NR::Point const &p, bool const &first_point, std::vector<NR::Point> &points_to_snap, std::list<SPItem const *> const &it) const; - SnappedPoint _doConstrainedSnap(Inkscape::Snapper::PointType const &t, + void _doConstrainedSnap(SnappedConstraints &sc, + Inkscape::Snapper::PointType const &t, NR::Point const &p, bool const &first_point, std::vector<NR::Point> &points_to_snap, @@ -43,6 +45,8 @@ private: * \return List of lines that we should try snapping to. */ virtual LineList _getSnapLines(NR::Point const &p) const = 0; + + virtual void _addSnappedLine(SnappedConstraints &sc, NR::Point const snapped_point, NR::Coord const snapped_distance, NR::Point const normal_to_line, NR::Point const point_on_line) const = 0; }; } diff --git a/src/object-snapper.cpp b/src/object-snapper.cpp index 53f04f8c4..10f75e5c4 100644 --- a/src/object-snapper.cpp +++ b/src/object-snapper.cpp @@ -113,16 +113,13 @@ void Inkscape::ObjectSnapper::_findCandidates(SPObject* r, } -void Inkscape::ObjectSnapper::_snapNodes(Inkscape::Snapper::PointType const &t, +bool Inkscape::ObjectSnapper::_snapNodes(Inkscape::Snapper::PointType const &t, Inkscape::SnappedPoint &s, NR::Point const &p, bool const &first_point, DimensionToSnap const snap_dim) const { - /* FIXME: this seems like a hack. Perhaps Snappers should be - ** in SPDesktop rather than SPNamedView? - */ - SPDesktop const *desktop = SP_ACTIVE_DESKTOP; + bool success = false; // Determine the type of bounding box we should snap to SPItem::BBoxType bbox_type = SPItem::GEOMETRIC_BBOX; @@ -194,16 +191,20 @@ void Inkscape::ObjectSnapper::_snapNodes(Inkscape::Snapper::PointType const &t, if (dist < getDistance() && dist < s.getDistance()) { s = SnappedPoint(snapped_point, dist); + success = true; } } + + return success; } -void Inkscape::ObjectSnapper::_snapPaths(Inkscape::Snapper::PointType const &t, +bool Inkscape::ObjectSnapper::_snapPaths(Inkscape::Snapper::PointType const &t, Inkscape::SnappedPoint &s, NR::Point const &p, bool const &first_point) const { + bool success = false; /* FIXME: this seems like a hack. Perhaps Snappers should be ** in SPDesktop rather than SPNamedView? */ @@ -314,21 +315,25 @@ void Inkscape::ObjectSnapper::_snapPaths(Inkscape::Snapper::PointType const &t, NR::Coord const dist = NR::L2(o_dt - p); if (dist < getDistance() && dist < s.getDistance()) { s = SnappedPoint(o_dt, dist); + success = true; } } } } + + return success; } -Inkscape::SnappedPoint Inkscape::ObjectSnapper::_doFreeSnap(Inkscape::Snapper::PointType const &t, - NR::Point const &p, - bool const &first_point, - std::vector<NR::Point> &points_to_snap, - std::list<SPItem const *> const &it) const +void Inkscape::ObjectSnapper::_doFreeSnap(SnappedConstraints &sc, + Inkscape::Snapper::PointType const &t, + NR::Point const &p, + bool const &first_point, + std::vector<NR::Point> &points_to_snap, + std::list<SPItem const *> const &it) const { if ( NULL == _named_view ) { - return SnappedPoint(p, NR_HUGE); + return; } /* Get a list of all the SPItems that we will try to snap to */ @@ -337,30 +342,35 @@ Inkscape::SnappedPoint Inkscape::ObjectSnapper::_doFreeSnap(Inkscape::Snapper::P } SnappedPoint s(p, NR_HUGE); + bool snapped_to_node = false; + bool snapped_to_path = false; if (_snap_to_itemnode || _snap_to_bboxnode) { - _snapNodes(t, s, p, first_point, SNAP_XY); + snapped_to_node = _snapNodes(t, s, p, first_point, SNAP_XY); } if (_snap_to_itempath || _snap_to_bboxpath) { - _snapPaths(t, s, p, first_point); + snapped_to_path = _snapPaths(t, s, p, first_point); } - return s; + if (snapped_to_node || snapped_to_path) { + sc.points.push_back(s); + } } -Inkscape::SnappedPoint Inkscape::ObjectSnapper::_doConstrainedSnap(Inkscape::Snapper::PointType const &t, - NR::Point const &p, - bool const &first_point, - std::vector<NR::Point> &points_to_snap, - ConstraintLine const &c, - std::list<SPItem const *> const &it) const +void Inkscape::ObjectSnapper::_doConstrainedSnap(SnappedConstraints &sc, + Inkscape::Snapper::PointType const &t, + NR::Point const &p, + bool const &first_point, + std::vector<NR::Point> &points_to_snap, + ConstraintLine const &c, + std::list<SPItem const *> const &it) const { /* FIXME: this needs implementing properly; I think we have to do the ** intersection of c with the objects. */ - return _doFreeSnap(t, p, first_point, points_to_snap, it); + _doFreeSnap(sc, t, p, first_point, points_to_snap, it); } diff --git a/src/object-snapper.h b/src/object-snapper.h index e473e3fe9..5b2e6f37d 100644 --- a/src/object-snapper.h +++ b/src/object-snapper.h @@ -17,7 +17,6 @@ #include "sp-path.h" #include "splivarot.h" - struct SPNamedView; struct SPItem; struct SPObject; @@ -88,13 +87,15 @@ private: std::vector<SPItem*> *_candidates; std::vector<NR::Point> *_points_to_snap_to; std::vector<Path*> *_paths_to_snap_to; - SnappedPoint _doFreeSnap(Inkscape::Snapper::PointType const &t, + void _doFreeSnap(SnappedConstraints &sc, + Inkscape::Snapper::PointType const &t, NR::Point const &p, bool const &first_point, std::vector<NR::Point> &points_to_snap, std::list<SPItem const *> const &it) const; - SnappedPoint _doConstrainedSnap(Inkscape::Snapper::PointType const &t, + void _doConstrainedSnap(SnappedConstraints &sc, + Inkscape::Snapper::PointType const &t, NR::Point const &p, bool const &first_point, std::vector<NR::Point> &points_to_snap, @@ -107,13 +108,13 @@ private: std::vector<NR::Point> &points_to_snap, DimensionToSnap const snap_dim) const; - void _snapNodes(Inkscape::Snapper::PointType const &t, + bool _snapNodes(Inkscape::Snapper::PointType const &t, Inkscape::SnappedPoint &s, NR::Point const &p, bool const &first_point, DimensionToSnap const snap_dim) const; - void _snapPaths(Inkscape::Snapper::PointType const &t, + bool _snapPaths(Inkscape::Snapper::PointType const &t, Inkscape::SnappedPoint &s, NR::Point const &p, bool const &first_point) const; diff --git a/src/snap.cpp b/src/snap.cpp index 1529dc40d..486507ce6 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -17,8 +17,11 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include <utility> + #include "sp-namedview.h" #include "snap.h" +#include "snapped-line.h" #include <libnr/nr-point-fns.h> #include <libnr/nr-scale-ops.h> @@ -182,29 +185,6 @@ Inkscape::SnappedPoint SnapManager::freeSnap(Inkscape::Snapper::PointType t, return freeSnap(t, p, true, points_to_snap, lit); } - -/** - * Try to snap a point to any interested snappers. - * - * \param t Type of point. - * \param p Point. - * \param first_point If true then this point is the first one from a whole bunch of points - * \param points_to_snap The whole bunch of points, all from the same selection and having the same transformation - * \param it List of items to ignore when snapping. - * \return Snapped point. - */ - - Inkscape::SnappedPoint SnapManager::freeSnap(Inkscape::Snapper::PointType t, - NR::Point const &p, - bool const &first_point, - std::vector<NR::Point> &points_to_snap, - std::list<SPItem const *> const &it) const -{ - SnapperList const snappers = getSnappers(); - - return freeSnap(t, p, first_point, points_to_snap, it, snappers); -} - /** * Try to snap a point to any of the specified snappers. * @@ -221,19 +201,18 @@ Inkscape::SnappedPoint SnapManager::freeSnap(Inkscape::Snapper::PointType t, NR::Point const &p, bool const &first_point, std::vector<NR::Point> &points_to_snap, - std::list<SPItem const *> const &it, - SnapperList const &snappers) const + std::list<SPItem const *> const &it) const { - Inkscape::SnappedPoint r(p, NR_HUGE); + + SnappedConstraints sc; + + SnapperList const snappers = getSnappers(); for (SnapperList::const_iterator i = snappers.begin(); i != snappers.end(); i++) { - Inkscape::SnappedPoint const s = (*i)->freeSnap(t, p, first_point, points_to_snap, it); - if (s.getDistance() < r.getDistance()) { - r = s; - } + (*i)->freeSnap(sc, t, p, first_point, points_to_snap, it); } - return r; + return findBestSnap(p, sc); } /** @@ -273,22 +252,19 @@ SnapManager::freeSnapAlways( Inkscape::Snapper::PointType t, std::list<SPItem const *> const &it, SnapperList &snappers ) { - Inkscape::SnappedPoint r(p, NR_HUGE); + + SnappedConstraints sc; for (SnapperList::iterator i = snappers.begin(); i != snappers.end(); i++) { gdouble const curr_gridsnap = (*i)->getDistance(); const_cast<Inkscape::Snapper*> (*i)->setDistance(NR_HUGE); std::vector<NR::Point> points_to_snap; points_to_snap.push_back(p); - Inkscape::SnappedPoint const s = (*i)->freeSnap(t, p, true, points_to_snap, it); + (*i)->freeSnap(sc, t, p, true, points_to_snap, it); const_cast<Inkscape::Snapper*> (*i)->setDistance(curr_gridsnap); - - if (s.getDistance() < r.getDistance()) { - r = s; - } } - return r; + return findBestSnap(p, sc); } @@ -340,17 +316,15 @@ Inkscape::SnappedPoint SnapManager::constrainedSnap(Inkscape::Snapper::PointType Inkscape::Snapper::ConstraintLine const &c, std::list<SPItem const *> const &it) const { - Inkscape::SnappedPoint r(p, NR_HUGE); - + + SnappedConstraints sc; + SnapperList const snappers = getSnappers(); for (SnapperList::const_iterator i = snappers.begin(); i != snappers.end(); i++) { - Inkscape::SnappedPoint const s = (*i)->constrainedSnap(t, p, first_point, points_to_snap, c, it); - if (s.getDistance() < r.getDistance()) { - r = s; - } + (*i)->constrainedSnap(sc, t, p, first_point, points_to_snap, c, it); } - return r; + return findBestSnap(p, sc); } Inkscape::SnappedPoint SnapManager::guideSnap(NR::Point const &p, @@ -456,7 +430,7 @@ std::pair<NR::Point, bool> SnapManager::_snapTransformed( std::vector<NR::Point>::const_iterator j = transformed_points.begin(); - for (std::vector<NR::Point>::const_iterator i = points.begin(); i != points.end(); i++) { + for (std::vector<NR::Point>::const_iterator i = points.begin(); i != points.end(); i++) { /* Snap it */ Inkscape::SnappedPoint const snapped = constrained ? @@ -471,7 +445,16 @@ std::pair<NR::Point, bool> SnapManager::_snapTransformed( switch (transformation_type) { case TRANSLATION: result = snapped.getPoint() - *i; - metric = NR::L2(result); + /* Consider the case in which a box is almost aligned with a grid in both + * horizontal and vertical directions. The distance to the intersection of + * the grid lines will always be larger then the distance to a single grid + * line. If we prefer snapping to an intersection instead of to a single + * grid line, then we cannot use "metric = NR::L2(result)". Therefore the + * snapped distance will be used as a metric. Please note that the snapped + * distance is defined as the distance to the nearest line of the intersection, + * and not to the intersection itself! + */ + metric = snapped.getDistance(); //used to be: metric = NR::L2(result); break; case SCALE: { @@ -483,11 +466,11 @@ std::pair<NR::Point, bool> SnapManager::_snapTransformed( } case STRETCH: { - for (int j = 0; j < 2; j++) { - if (uniform || j == dim) { - result[j] = (snapped.getPoint()[dim] - origin[dim]) / ((*i)[dim] - origin[dim]); + for (int a = 0; a < 2; a++) { + if (uniform || a == dim) { + result[a] = (snapped.getPoint()[dim] - origin[dim]) / ((*i)[dim] - origin[dim]); } else { - result[j] = 1; + result[a] = 1; } } metric = std::abs(result[dim] - transformation[dim]); @@ -502,7 +485,7 @@ std::pair<NR::Point, bool> SnapManager::_snapTransformed( } /* Note it if it's the best so far */ - if (metric < best_metric) { + if ((metric < best_metric) || ((metric == best_metric) && snapped.getAtIntersection() == true)) { best_transformation = result; best_metric = metric; } @@ -510,7 +493,7 @@ std::pair<NR::Point, bool> SnapManager::_snapTransformed( j++; } - + // Using " < 1e6" instead of " < NR::HUGE" for catching some rounding errors // These rounding errors might be caused by NRRects, see bug #1584301 return std::make_pair(best_transformation, best_metric < 1e6); @@ -671,6 +654,81 @@ std::pair<NR::Coord, bool> SnapManager::freeSnapSkew(Inkscape::Snapper::PointTyp return std::make_pair(r.first[d], r.second); } +Inkscape::SnappedPoint SnapManager::findBestSnap(NR::Point const &p, SnappedConstraints &sc) const +{ + NR::Coord const guide_sens = guide.getDistance(); + NR::Coord grid_sens = 0; + + SnapManager::SnapperList const gs = getGridSnappers(); + SnapperList::const_iterator i = gs.begin(); + if (i != gs.end()) { + grid_sens = (*i)->getDistance(); + } + + // Store all snappoints, optionally together with their specific snapping range + std::list<std::pair<Inkscape::SnappedPoint, NR::Coord> > sp_list; + // Most of these snapped points are already within the snapping range, because + // they have already been filtered by their respective snappers. In that case + // we can set the snapping range to NR_HUGE here. If however we're looking at + // intersections of e.g. a grid and guide line, then we'll have to determine + // once again whether we're within snapping range. In this case we will set + // the snapping range to e.g. min(guide_sens, grid_sens) + + // search for the closest snapped point + Inkscape::SnappedPoint closestPoint; + if (getClosestSP(sc.points, closestPoint)) { + sp_list.push_back(std::make_pair(closestPoint, NR_HUGE)); + } + + // search for the closest snapped grid line + Inkscape::SnappedInfiniteLine closestGridLine; + if (getClosestSIL(sc.grid_lines, closestGridLine)) { + sp_list.push_back(std::make_pair(Inkscape::SnappedPoint(closestGridLine), NR_HUGE)); + } + + // search for the closest snapped guide line + Inkscape::SnappedInfiniteLine closestGuideLine; + if (getClosestSIL(sc.guide_lines, closestGuideLine)) { + sp_list.push_back(std::make_pair(Inkscape::SnappedPoint(closestGuideLine), NR_HUGE)); + } + + // search for the closest snapped intersection of grid lines + Inkscape::SnappedPoint closestGridPoint; + if (getClosestIntersectionSIL(sc.grid_lines, closestGridPoint)) { + sp_list.push_back(std::make_pair(closestGridPoint, NR_HUGE)); + } + + // search for the closest snapped intersection of guide lines + Inkscape::SnappedPoint closestGuidePoint; + if (getClosestIntersectionSIL(sc.guide_lines, closestGuidePoint)) { + sp_list.push_back(std::make_pair(closestGuidePoint, NR_HUGE)); + } + + // search for the closest snapped intersection of grid with guide lines + Inkscape::SnappedPoint closestGridGuidePoint; + if (getClosestIntersectionSIL(sc.grid_lines, sc.guide_lines, closestGridGuidePoint)) { + sp_list.push_back(std::make_pair(closestGridGuidePoint, std::min(guide_sens, grid_sens))); + } + + // now let's see which snapped point gets a thumbs up + Inkscape::SnappedPoint bestPoint(p, NR_HUGE); + for (std::list<std::pair<Inkscape::SnappedPoint, NR::Coord> >::const_iterator i = sp_list.begin(); i != sp_list.end(); i++) { + // first find out if this snapped point is within snapping range + if ((*i).first.getDistance() <= (*i).second) { + // if it's the first point + bool c1 = (i == sp_list.begin()); + // or, if it's closer + bool c2 = (*i).first.getDistance() < bestPoint.getDistance(); + // or, if it's just as close but at an intersection + bool c3 = ((*i).first.getDistance() == bestPoint.getDistance()) && (*i).first.getAtIntersection(); + // then prefer this point over the previous one + if (c1 || c2 || c3) { + bestPoint = (*i).first; + } + } + } + return bestPoint; +} /* Local Variables: mode:c++ diff --git a/src/snap.h b/src/snap.h index f44df8923..29d22a1cd 100644 --- a/src/snap.h +++ b/src/snap.h @@ -22,6 +22,7 @@ #include <libnr/nr-dim2.h> #include <libnr/nr-forward.h> #include <libnr/nr-scale.h> + #include "guide-snapper.h" #include "object-snapper.h" @@ -48,18 +49,11 @@ public: NR::Point const &p, SPItem const *it) const; - Inkscape::SnappedPoint freeSnap(Inkscape::Snapper::PointType t, - NR::Point const &p, - bool const &first_point, - std::vector<NR::Point> &points_to_snap, - std::list<SPItem const *> const &it) const; - - Inkscape::SnappedPoint freeSnap( Inkscape::Snapper::PointType t, + Inkscape::SnappedPoint freeSnap( Inkscape::Snapper::PointType t, NR::Point const &p, bool const &first_point, std::vector<NR::Point> &points_to_snap, - std::list<SPItem const *> const &it, - SnapperList const &snappers ) const; + std::list<SPItem const *> const &it) const; Inkscape::SnappedPoint freeSnapAlways( Inkscape::Snapper::PointType t, NR::Point const &p, @@ -172,6 +166,8 @@ private: NR::Point const &origin, NR::Dim2 dim, bool uniform) const; + + Inkscape::SnappedPoint findBestSnap(NR::Point const &p, SnappedConstraints &sc) const; }; #endif /* !SEEN_SNAP_H */ diff --git a/src/snapped-line.cpp b/src/snapped-line.cpp new file mode 100644 index 000000000..5e31fc1dd --- /dev/null +++ b/src/snapped-line.cpp @@ -0,0 +1,180 @@ +/** + * \file src/snapped-line.cpp + * \brief SnappedInfiniteLine class. + * + * Authors: + * Diederik van Lierop <mail@diedenrezi.nl> + * + * Released under GNU GPL, read the file 'COPYING' for more information. + */ + +#include "snapped-line.h" +#include "geom.h" + +Inkscape::SnappedLine::SnappedLine(NR::Point snapped_point, NR::Coord snapped_distance, NR::Point start_point_of_line, NR::Point end_point_of_line) + : _start_point_of_line(start_point_of_line), _end_point_of_line(end_point_of_line) +{ + _distance = snapped_distance; + _point = snapped_point; + _at_intersection = false; +} + +Inkscape::SnappedLine::SnappedLine() +{ + _start_point_of_line = NR::Point(0,0); + _end_point_of_line = NR::Point(0,0); + _distance = NR_HUGE; + _point = NR::Point(0,0); + _at_intersection = false; +} + + +Inkscape::SnappedLine::~SnappedLine() +{ +} + +Inkscape::SnappedPoint Inkscape::SnappedLine::intersect(SnappedLine const &line) const +{ + //TODO: Diederik, implement the intersection + NR::Point const intersection = NR::Point(NR_HUGE, NR_HUGE); + + //if (result == INTERSECTS) { + /* The relevant snapped distance is the distance to the closest snapped line, not the + distance to the intersection. For example, when a box is almost aligned with a grid + in both horizontal and vertical directions, the distance to the intersection of the + grid lines will always be larger then the distance to a grid line. We will be snapping + to the closest snapped point however, so if we ever want to snap to the intersection + then the distance to it should at least be equal to the other distance, not greater + than it, as that would rule the intersection out + */ + NR::Coord distance = std::min(_distance, line.getDistance()); + //} + return SnappedPoint(intersection, distance); +}; + + + +Inkscape::SnappedInfiniteLine::SnappedInfiniteLine(NR::Point snapped_point, NR::Coord snapped_distance, NR::Point normal_to_line, NR::Point point_on_line) + : _normal_to_line(normal_to_line), _point_on_line(point_on_line) +{ + _distance = snapped_distance; + _point = snapped_point; + _at_intersection = false; +} + +Inkscape::SnappedInfiniteLine::SnappedInfiniteLine() +{ + _normal_to_line = NR::Point(0,0); + _point_on_line = NR::Point(0,0); + _distance = NR_HUGE; + _point = NR::Point(0,0); + _at_intersection = false; +} + +Inkscape::SnappedInfiniteLine::~SnappedInfiniteLine() +{ +} + +Inkscape::SnappedPoint Inkscape::SnappedInfiniteLine::intersect(SnappedInfiniteLine const &line) const +{ + // Calculate the intersection of to infinite lines, which are both within snapping range + // The point of intersection should be considered for snapping, but might be outside the snapping range + + NR::Point intersection = NR::Point(NR_HUGE, NR_HUGE); + NR::Coord distance = NR_HUGE; + + IntersectorKind result = intersector_line_intersection(getNormal(), getConstTerm(), + line.getNormal(), line.getConstTerm(), intersection); + + /*std::cout << "n0 = " << getNormal() << std::endl; + std::cout << "n1 = " << line.getNormal() << std::endl; + std::cout << "c0 = " << getConstTerm() << std::endl; + std::cout << "c1 = " << line.getConstTerm() << std::endl;*/ + + if (result == INTERSECTS) { + /* The relevant snapped distance is the distance to the closest snapped line, not the + distance to the intersection. For example, when a box is almost aligned with a grid + in both horizontal and vertical directions, the distance to the intersection of the + grid lines will always be larger then the distance to a grid line. We will be snapping + to the closest snapped point however, so if we ever want to snap to the intersection + then the distance to it should at least be equal to the other distance, not greater + than it, as that would rule the intersection out + */ + distance = std::min(_distance, line.getDistance()); + //std::cout << "Intersected nicely, now getSIL distance = " << distance << std::endl; + } + + //std::cout << "getSIL distance = " << distance << std::endl; + + return SnappedPoint(intersection, distance, result == INTERSECTS); +} + +// search for the closest snapped infinite line +bool getClosestSIL(std::list<Inkscape::SnappedInfiniteLine> &list, Inkscape::SnappedInfiniteLine &result) +{ + bool success = false; + + for (std::list<Inkscape::SnappedInfiniteLine>::const_iterator i = list.begin(); i != list.end(); i++) { + if ((i == list.begin()) || (*i).getDistance() < result.getDistance()) { + result = *i; + success = true; + } + } + + return success; +} + +// search for the closest intersection of two snapped infinite lines, which are both member of the same collection +bool getClosestIntersectionSIL(std::list<Inkscape::SnappedInfiniteLine> &list, Inkscape::SnappedPoint &result) +{ + bool success = false; + + for (std::list<Inkscape::SnappedInfiniteLine>::const_iterator i = list.begin(); i != list.end(); i++) { + std::list<Inkscape::SnappedInfiniteLine>::const_iterator j = i; + j++; + for (; j != list.end(); j++) { + Inkscape::SnappedPoint sp = (*i).intersect(*j); + if (sp.getAtIntersection()) { + if (!success || sp.getDistance() < result.getDistance()) { + // !success because the first intersection cannot be compared to a previous one + result = sp; + success = true; + } + } + } + } + + return success; +} + +// search for the closest intersection of two snapped infinite lines, which are in two different collections +bool getClosestIntersectionSIL(std::list<Inkscape::SnappedInfiniteLine> &list1, std::list<Inkscape::SnappedInfiniteLine> &list2, Inkscape::SnappedPoint &result) +{ + bool success = false; + + for (std::list<Inkscape::SnappedInfiniteLine>::const_iterator i = list1.begin(); i != list1.end(); i++) { + for (std::list<Inkscape::SnappedInfiniteLine>::const_iterator j = list2.begin(); j != list2.end(); j++) { + Inkscape::SnappedPoint sp = (*i).intersect(*j); + if (sp.getAtIntersection()) { + if (!success || sp.getDistance() < result.getDistance()) { + // !success because the first intersection cannot be compared to a previous one + result = sp; + success = true; + } + } + } + } + + return success; +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/snapped-line.h b/src/snapped-line.h new file mode 100644 index 000000000..0b8c9053f --- /dev/null +++ b/src/snapped-line.h @@ -0,0 +1,76 @@ +#ifndef SEEN_SNAPPEDLINE_H +#define SEEN_SNAPPEDLINE_H + +/** + * \file src/snapped-line.h + * \brief SnappedInfiniteLine class. + * + * Authors: + * Diederik van Lierop <mail@diedenrezi.nl> + * + * Released under GNU GPL, read the file 'COPYING' for more information. + */ + +#include <vector> +#include <list> +#include "libnr/nr-coord.h" +#include "libnr/nr-point.h" +#include <libnr/nr-point-fns.h> +#include "snapped-point.h" + +namespace Inkscape +{ + +/// Class describing the result of an attempt to snap to a line segment. +class SnappedLine : public SnappedPoint +{ +public: + SnappedLine(); + SnappedLine(NR::Point snapped_point, NR::Coord snapped_distance, NR::Point start_point_of_line, NR::Point end_point_of_line); + ~SnappedLine(); + Inkscape::SnappedPoint intersect(SnappedLine const &line) const; //intersect with another SnappedLine + +private: + NR::Point _start_point_of_line; + NR::Point _end_point_of_line; +}; + + +/// Class describing the result of an attempt to snap to an infinite line. +class SnappedInfiniteLine : public SnappedPoint +{ +public: + SnappedInfiniteLine(); + SnappedInfiniteLine(NR::Point snapped_point, NR::Coord snapped_distance, NR::Point normal_to_line, NR::Point point_on_line); + ~SnappedInfiniteLine(); + Inkscape::SnappedPoint intersect(SnappedInfiniteLine const &line) const; //intersect with another SnappedInfiniteLine + // This line is described by this equation: + // a*x + b*y = c <-> nx*px + ny+py = c <-> n.p = c + NR::Point getNormal() const {return _normal_to_line;} // n = (nx, ny) + NR::Point getPointOnLine() const {return _point_on_line;} // p = (px, py) + NR::Coord getConstTerm() const {return dot(_normal_to_line, _point_on_line);} // c = n.p = nx*px + ny*py; + +private: + NR::Point _normal_to_line; + NR::Point _point_on_line; +}; + +} + +bool getClosestSIL(std::list<Inkscape::SnappedInfiniteLine> &list, Inkscape::SnappedInfiniteLine &result); +bool getClosestIntersectionSIL(std::list<Inkscape::SnappedInfiniteLine> &list, Inkscape::SnappedPoint &result); +bool getClosestIntersectionSIL(std::list<Inkscape::SnappedInfiniteLine> &list1, std::list<Inkscape::SnappedInfiniteLine> &list2, Inkscape::SnappedPoint &result); + + +#endif /* !SEEN_SNAPPEDLINE_H */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/snapped-point.cpp b/src/snapped-point.cpp index 5d0d242dd..9df76b704 100644 --- a/src/snapped-point.cpp +++ b/src/snapped-point.cpp @@ -9,28 +9,24 @@ */ #include "snapped-point.h" +#include <libnr/nr-values.h> -Inkscape::SnappedPoint::SnappedPoint(NR::Point p, NR::Coord d) - : _distance(d), _point(p) +Inkscape::SnappedPoint::SnappedPoint(NR::Point p, NR::Coord d, bool at_intersection) + : _distance(d), _point(p), _at_intersection(at_intersection) { - } -Inkscape::SnappedPoint::~SnappedPoint() +Inkscape::SnappedPoint::SnappedPoint() { - /// TODO : empty the _hightlight_groups vector and destroy the - /// HighlightGroup items it holds + _distance = NR_HUGE; + _point = NR::Point(0,0); + _at_intersection = false; } -void Inkscape::SnappedPoint::addHighlightGroup(HighlightGroup *group) -{ - /// TODO -} -void Inkscape::SnappedPoint::addHighlightGroups(std::vector<HighlightGroup*> *groups) +Inkscape::SnappedPoint::~SnappedPoint() { - /// TODO } NR::Coord Inkscape::SnappedPoint::getDistance() const @@ -43,12 +39,21 @@ NR::Point Inkscape::SnappedPoint::getPoint() const return _point; } -std::vector<Inkscape::HighlightGroup*> Inkscape::SnappedPoint::getHighlightGroups() const +// search for the closest snapped point +bool getClosestSP(std::list<Inkscape::SnappedPoint> &list, Inkscape::SnappedPoint &result) { - return _hightlight_groups; + bool success = false; + + for (std::list<Inkscape::SnappedPoint>::const_iterator i = list.begin(); i != list.end(); i++) { + if ((i == list.begin()) || (*i).getDistance() < result.getDistance()) { + result = *i; + success = true; + } + } + + return success; } - /* Local Variables: mode:c++ diff --git a/src/snapped-point.h b/src/snapped-point.h index 0669ddd21..147922b2f 100644 --- a/src/snapped-point.h +++ b/src/snapped-point.h @@ -12,36 +12,36 @@ */ #include <vector> +#include <list> #include "libnr/nr-coord.h" #include "libnr/nr-point.h" namespace Inkscape { - -class HighlightGroup; - + /// Class describing the result of an attempt to snap. class SnappedPoint { public: - SnappedPoint() {} - SnappedPoint(::NR::Point p, ::NR::Coord d); + SnappedPoint(); + SnappedPoint(::NR::Point p, ::NR::Coord d, bool at_intersection = false); ~SnappedPoint(); - void addHighlightGroup(HighlightGroup *group); - void addHighlightGroups(std::vector<HighlightGroup*> *groups); - - ::NR::Coord getDistance() const; + NR::Coord getDistance() const; NR::Point getPoint() const; - std::vector<HighlightGroup*> getHighlightGroups() const; - -private: - ::NR::Coord _distance; - ::NR::Point _point; - std::vector<HighlightGroup*> _hightlight_groups; -}; + bool getAtIntersection() const {return _at_intersection;} + +protected: + NR::Coord _distance; + NR::Point _point; + bool _at_intersection; +}; } + +bool getClosestSP(std::list<Inkscape::SnappedPoint> &list, Inkscape::SnappedPoint &result); + + #endif /* !SEEN_SNAPPEDPOINT_H */ /* diff --git a/src/snapper.cpp b/src/snapper.cpp index 17d7b7137..5edde2405 100644 --- a/src/snapper.cpp +++ b/src/snapper.cpp @@ -91,7 +91,9 @@ void Inkscape::Snapper::setEnabled(bool s) * \return Snapped point. */ -Inkscape::SnappedPoint Inkscape::Snapper::freeSnap(PointType const &t, +void Inkscape::Snapper::freeSnap(SnappedConstraints &sc, + + PointType const &t, NR::Point const &p, bool const &first_point, std::vector<NR::Point> &points_to_snap, @@ -99,7 +101,7 @@ Inkscape::SnappedPoint Inkscape::Snapper::freeSnap(PointType const &t, { std::list<SPItem const *> lit; lit.push_back(it); - return freeSnap(t, p, first_point, points_to_snap, lit); + freeSnap(sc, t, p, first_point, points_to_snap, lit); } @@ -114,17 +116,19 @@ Inkscape::SnappedPoint Inkscape::Snapper::freeSnap(PointType const &t, * \return Snapped point. */ -Inkscape::SnappedPoint Inkscape::Snapper::freeSnap(PointType const &t, +void Inkscape::Snapper::freeSnap(SnappedConstraints &sc, + + PointType const &t, NR::Point const &p, bool const &first_point, std::vector<NR::Point> &points_to_snap, std::list<SPItem const *> const &it) const { if (_enabled == false || getSnapFrom(t) == false) { - return SnappedPoint(p, NR_HUGE); + return; } - return _doFreeSnap(t, p, first_point, points_to_snap, it); + _doFreeSnap(sc, t, p, first_point, points_to_snap, it); } @@ -141,7 +145,9 @@ Inkscape::SnappedPoint Inkscape::Snapper::freeSnap(PointType const &t, * \return Snapped point. */ -Inkscape::SnappedPoint Inkscape::Snapper::constrainedSnap(PointType const &t, +void Inkscape::Snapper::constrainedSnap(SnappedConstraints &sc, + + PointType const &t, NR::Point const &p, bool const &first_point, std::vector<NR::Point> &points_to_snap, @@ -150,7 +156,7 @@ Inkscape::SnappedPoint Inkscape::Snapper::constrainedSnap(PointType const &t, { std::list<SPItem const *> lit; lit.push_back(it); - return constrainedSnap(t, p, first_point, points_to_snap, c, lit); + constrainedSnap(sc, t, p, first_point, points_to_snap, c, lit); } @@ -165,7 +171,9 @@ Inkscape::SnappedPoint Inkscape::Snapper::constrainedSnap(PointType const &t, * \return Snapped point. */ -Inkscape::SnappedPoint Inkscape::Snapper::constrainedSnap(PointType const &t, +void Inkscape::Snapper::constrainedSnap(SnappedConstraints &sc, + + PointType const &t, NR::Point const &p, bool const &first_point, std::vector<NR::Point> &points_to_snap, @@ -173,10 +181,10 @@ Inkscape::SnappedPoint Inkscape::Snapper::constrainedSnap(PointType const &t, std::list<SPItem const *> const &it) const { if (_enabled == false || getSnapFrom(t) == false) { - return SnappedPoint(p, NR_HUGE); + return; } - return _doConstrainedSnap(t, p, first_point, points_to_snap, c, it); + _doConstrainedSnap(sc, t, p, first_point, points_to_snap, c, it); } /* diff --git a/src/snapper.h b/src/snapper.h index 5b6b4a258..a122db72f 100644 --- a/src/snapper.h +++ b/src/snapper.h @@ -15,7 +15,16 @@ #include <list> #include "libnr/nr-coord.h" #include "libnr/nr-point.h" + #include "snapped-point.h" +#include "snapped-line.h" + +struct SnappedConstraints { + std::list<Inkscape::SnappedPoint> points; + std::list<Inkscape::SnappedLine> lines; + std::list<Inkscape::SnappedInfiniteLine> grid_lines; + std::list<Inkscape::SnappedInfiniteLine> guide_lines; +}; struct SPNamedView; struct SPItem; @@ -50,13 +59,15 @@ public: void setEnabled(bool s); - SnappedPoint freeSnap(PointType const &t, + void freeSnap(SnappedConstraints &sc, + PointType const &t, NR::Point const &p, bool const &first_point, std::vector<NR::Point> &points_to_snap, SPItem const *it) const; - SnappedPoint freeSnap(PointType const &t, + void freeSnap(SnappedConstraints &sc, + PointType const &t, NR::Point const &p, bool const &first_point, std::vector<NR::Point> &points_to_snap, @@ -87,19 +98,22 @@ public: NR::Point _direction; }; - SnappedPoint constrainedSnap(PointType const &t, + void constrainedSnap(SnappedConstraints &sc, + PointType const &t, NR::Point const &p, bool const &first_point, std::vector<NR::Point> &points_to_snap, ConstraintLine const &c, SPItem const *it) const; - SnappedPoint constrainedSnap(PointType const &t, + void constrainedSnap(SnappedConstraints &sc, + PointType const &t, NR::Point const &p, bool const &first_point, std::vector<NR::Point> &points_to_snap, ConstraintLine const &c, std::list<SPItem const *> const &it) const; + protected: SPNamedView const *_named_view; int _snap_from; ///< bitmap of point types that we will snap from @@ -116,7 +130,8 @@ private: * \param it Items that should not be snapped to. * \return Snapped point. */ - virtual SnappedPoint _doFreeSnap(PointType const &t, + virtual void _doFreeSnap(SnappedConstraints &sc, + PointType const &t, NR::Point const &p, bool const &first_point, std::vector<NR::Point> &points_to_snap, @@ -132,14 +147,15 @@ private: * \param it Items that should not be snapped to. * \return Snapped point. */ - virtual SnappedPoint _doConstrainedSnap(PointType const &t, + virtual void _doConstrainedSnap(SnappedConstraints &sc, + PointType const &t, NR::Point const &p, bool const &first_point, std::vector<NR::Point> &points_to_snap, ConstraintLine const &c, std::list<SPItem const *> const &it) const = 0; - ::NR::Coord _distance; ///< snap distance (desktop coordinates) + NR::Coord _distance; ///< snap distance (desktop coordinates) }; } |
