From b0bda995cebf5befd80a735796661fb670eca179 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 5 May 2006 14:22:41 +0000 Subject: Various snapping cleanups and bug fixes. (bzr r734) --- src/snap.cpp | 146 +++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 96 insertions(+), 50 deletions(-) (limited to 'src/snap.cpp') diff --git a/src/snap.cpp b/src/snap.cpp index 452a1e496..ca7efde73 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -21,7 +21,7 @@ #include #include -SnapManager::SnapManager(SPNamedView* v) : grid(v, 0), guide(v, 0), object(v, 0) +SnapManager::SnapManager(SPNamedView const *v) : grid(v, 0), guide(v, 0), object(v, 0) { } @@ -85,7 +85,7 @@ Inkscape::SnappedPoint SnapManager::freeSnap(Inkscape::Snapper::PointType t, Inkscape::SnappedPoint SnapManager::constrainedSnap(Inkscape::Snapper::PointType t, NR::Point const &p, - NR::Point const &c, + Inkscape::Snapper::ConstraintLine const &c, SPItem const *it) const { std::list lit; @@ -96,7 +96,7 @@ Inkscape::SnappedPoint SnapManager::constrainedSnap(Inkscape::Snapper::PointType Inkscape::SnappedPoint SnapManager::constrainedSnap(Inkscape::Snapper::PointType t, NR::Point const &p, - NR::Point const &c, + Inkscape::Snapper::ConstraintLine const &c, std::list const &it) const { Inkscape::SnappedPoint r(p, NR_HUGE); @@ -113,74 +113,120 @@ Inkscape::SnappedPoint SnapManager::constrainedSnap(Inkscape::Snapper::PointType } -std::pair SnapManager::freeSnapTranslation(Inkscape::Snapper::PointType t, - std::vector const &p, - std::list const &it, - NR::Point const &tr) const +std::pair SnapManager::_snapTransformed(Inkscape::Snapper::PointType type, + std::vector const &points, + std::list const &ignore, + bool constrained, + Inkscape::Snapper::ConstraintLine const &constraint, + Transformation transformation_type, + NR::Point const &transformation, + NR::Point const &origin) const { + /* We have a list of points, which we are proposing to transform in some way. We need to see + ** if any of these points, when transformed, snap to anything. If they do, we return the + ** appropriate transformation with `true'; otherwise we return the original scale with `false'. + */ + + /* Quick check to see if we have any snappers that are enabled */ if (willSnapSomething() == false) { - return std::make_pair(tr, false); + return std::make_pair(transformation, false); } - NR::Point best_translation = tr; - NR::Coord best_distance = NR_HUGE; - - for (std::vector::const_iterator i = p.begin(); i != p.end(); i++) { - /* Translated version of this point */ - NR::Point const q = *i + tr; + /* The current best transformation */ + NR::Point best_transformation = transformation; + /* The current best metric for the best transformation; lower is better, NR_HUGE + ** means that we haven't snapped anything. + */ + NR::Coord best_metric = NR_HUGE; + + for (std::vector::const_iterator i = points.begin(); i != points.end(); i++) { + + /* Work out the transformed version of this point */ + NR::Point transformed; + switch (transformation_type) { + case TRANSLATION: + transformed = *i + transformation; + break; + case SCALE: + transformed = ((*i - origin) * NR::scale(transformation[NR::X], transformation[NR::Y])) + origin; + break; + default: + g_assert_not_reached(); + } + /* Snap it */ - Inkscape::SnappedPoint s = freeSnap(t, q, it); - if (s.getDistance() < NR_HUGE) { - /* Resulting translation */ - NR::Point const r = s.getPoint() - *i; - NR::Coord const d = NR::L2(r); - if (d < best_distance) { - best_distance = d; - best_translation = r; + Inkscape::SnappedPoint const snapped = constrained ? + constrainedSnap(type, transformed, constraint, ignore) : freeSnap(type, transformed, ignore); + + if (snapped.getDistance() < NR_HUGE) { + /* We snapped. Find the transformation that describes where the snapped point has + ** ended up, and also the metric for this transformation. + */ + NR::Point result; + NR::Coord metric; + switch (transformation_type) { + case TRANSLATION: + result = snapped.getPoint() - *i; + metric = NR::L2(result); + break; + case SCALE: + NR::Point const a = (snapped.getPoint() - origin); + NR::Point const b = (*i - origin); + result = NR::Point(a[NR::X] / b[NR::X], a[NR::Y] / b[NR::Y]); + metric = std::abs(NR::L2(result) - NR::L2(transformation)); + break; + } + + /* Note it if it's the best so far */ + if (metric < best_metric && metric != 0) { + best_transformation = result; + best_metric = metric; } } } + + return std::make_pair(best_transformation, best_metric < NR_HUGE); +} + - return std::make_pair(best_translation, best_distance < NR_HUGE); +std::pair SnapManager::freeSnapTranslation(Inkscape::Snapper::PointType t, + std::vector const &p, + std::list const &it, + NR::Point const &tr) const +{ + return _snapTransformed(t, p, it, false, NR::Point(), TRANSLATION, tr, NR::Point(0, 0)); } std::pair SnapManager::constrainedSnapTranslation(Inkscape::Snapper::PointType t, std::vector const &p, - NR::Point const &c, std::list const &it, + Inkscape::Snapper::ConstraintLine const &c, NR::Point const &tr) const { - if (willSnapSomething() == false) { - return std::make_pair(tr, false); - } - - NR::Point best_translation = tr; - NR::Coord best_distance = NR_HUGE; - - for (std::vector::const_iterator i = p.begin(); i != p.end(); i++) { - /* Translated version of this point */ - NR::Point const q = *i + tr; - /* Snap it */ - Inkscape::SnappedPoint s = constrainedSnap(t, q, c, it); - if (s.getDistance() < NR_HUGE) { - /* Resulting translation */ - NR::Point const r = s.getPoint() - *i; - NR::Coord const d = NR::L2(r); - if (d < best_distance) { - best_distance = d; - best_translation = r; - } - } - } - - return std::make_pair(best_translation, best_distance < NR_HUGE); + return _snapTransformed(t, p, it, true, c, TRANSLATION, tr, NR::Point(0, 0)); } +std::pair SnapManager::freeSnapScale(Inkscape::Snapper::PointType t, + std::vector const &p, + std::list const &it, + NR::scale const &s, + NR::Point const &o) const +{ + return _snapTransformed(t, p, it, false, NR::Point(0, 0), SCALE, NR::Point(s[NR::X], s[NR::Y]), o); +} - +std::pair SnapManager::constrainedSnapScale(Inkscape::Snapper::PointType t, + std::vector const &p, + std::list const &it, + Inkscape::Snapper::ConstraintLine const &c, + NR::scale const &s, + NR::Point const &o) const +{ + return _snapTransformed(t, p, it, true, c, SCALE, NR::Point(s[NR::X], s[NR::Y]), o); +} /// Minimal distance to norm before point is considered for snap. @@ -292,7 +338,7 @@ std::pair namedview_vector_snap_list(SPNamedView const *nv, Inksca return std::make_pair(ratio, dist < NR_HUGE); } - + /** * Try to snap points in \a p after they have been scaled by \a sx with respect to -- cgit v1.2.3