summaryrefslogtreecommitdiffstats
path: root/src/snap.cpp
diff options
context:
space:
mode:
authorDiederik van Lierop <mail@diedenrezi.nl>2007-11-03 14:48:50 +0000
committerdvlierop2 <dvlierop2@users.sourceforge.net>2007-11-03 14:48:50 +0000
commit84504bd815a6ef3c5b7b5958ce46429cbab56a66 (patch)
treed74ae924d96f98b07658dcb67d46b64c486d1beb /src/snap.cpp
parentAdded an icons file with a cleaned up current icon set (prefix "ink_" in thei... (diff)
downloadinkscape-84504bd815a6ef3c5b7b5958ce46429cbab56a66.tar.gz
inkscape-84504bd815a6ef3c5b7b5958ce46429cbab56a66.zip
Groundwork to snap to intersections, e.g. intersections of gridlines with guidelines, and of objects with other objects. The snappers used to return only SnappedPoints, but now also SnappedLines and SnappedInfiniteLines can be returned. SnappedPaths will be implemented later.
(bzr r4016)
Diffstat (limited to 'src/snap.cpp')
-rw-r--r--src/snap.cpp164
1 files changed, 111 insertions, 53 deletions
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++