summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/draw-context.cpp2
-rw-r--r--src/line-snapper.cpp3
-rw-r--r--src/line-snapper.h3
-rw-r--r--src/object-snapper.cpp53
-rw-r--r--src/object-snapper.h6
-rw-r--r--src/snap.cpp8
-rw-r--r--src/snapper.h17
7 files changed, 65 insertions, 27 deletions
diff --git a/src/draw-context.cpp b/src/draw-context.cpp
index a531b88d1..c0ae626d5 100644
--- a/src/draw-context.cpp
+++ b/src/draw-context.cpp
@@ -511,7 +511,7 @@ void spdc_endpoint_snap_rotation(SPEventContext const *const ec, Geom::Point &p,
/* Snap it along best vector */
SnapManager &m = SP_EVENT_CONTEXT_DESKTOP(ec)->namedview->snap_manager;
m.setup(SP_EVENT_CONTEXT_DESKTOP(ec));
- m.constrainedSnapReturnByRef(p, Inkscape::SNAPSOURCE_NODE_HANDLE, Inkscape::Snapper::SnapConstraint(best));
+ m.constrainedSnapReturnByRef(p, Inkscape::SNAPSOURCE_NODE_HANDLE, Inkscape::Snapper::SnapConstraint(o, best));
}
}
}
diff --git a/src/line-snapper.cpp b/src/line-snapper.cpp
index 19e6c0fe6..0a1567a47 100644
--- a/src/line-snapper.cpp
+++ b/src/line-snapper.cpp
@@ -64,7 +64,8 @@ void Inkscape::LineSnapper::constrainedSnap(SnappedConstraints &sc,
Inkscape::SnapCandidatePoint const &p,
Geom::OptRect const &/*bbox_to_snap*/,
SnapConstraint const &c,
- std::vector<SPItem const *> const */*it*/) const
+ std::vector<SPItem const *> const */*it*/,
+ std::vector<SnapCandidatePoint> */*unselected_nodes*/) const
{
if (_snap_enabled == false || _snapmanager->snapprefs.getSnapFrom(p.getSourceType()) == false) {
diff --git a/src/line-snapper.h b/src/line-snapper.h
index 4f3d17998..cdc45c286 100644
--- a/src/line-snapper.h
+++ b/src/line-snapper.h
@@ -35,7 +35,8 @@ public:
Inkscape::SnapCandidatePoint const &p,
Geom::OptRect const &bbox_to_snap,
SnapConstraint const &c,
- std::vector<SPItem const *> const *it) const;
+ std::vector<SPItem const *> const *it,
+ std::vector<SnapCandidatePoint> *unselected_nodes) const;
protected:
typedef std::list<std::pair<Geom::Point, Geom::Point> > LineList;
diff --git a/src/object-snapper.cpp b/src/object-snapper.cpp
index d84ee9c4f..23af26d47 100644
--- a/src/object-snapper.cpp
+++ b/src/object-snapper.cpp
@@ -257,7 +257,8 @@ void Inkscape::ObjectSnapper::_collectNodes(Inkscape::SnapSourceType const &t,
void Inkscape::ObjectSnapper::_snapNodes(SnappedConstraints &sc,
Inkscape::SnapCandidatePoint const &p,
- std::vector<SnapCandidatePoint> *unselected_nodes) const
+ std::vector<SnapCandidatePoint> *unselected_nodes,
+ SnapConstraint const &c) const
{
// Iterate through all nodes, find out which one is the closest to p, and snap to it!
@@ -271,9 +272,20 @@ void Inkscape::ObjectSnapper::_snapNodes(SnappedConstraints &sc,
bool success = false;
for (std::vector<SnapCandidatePoint>::const_iterator k = _points_to_snap_to->begin(); k != _points_to_snap_to->end(); k++) {
- Geom::Coord dist = Geom::L2((*k).getPoint() - p.getPoint());
+ Geom::Point target_pt = (*k).getPoint();
+ if (!c.isUndefined()) {
+ // We're snapping to nodes along a constraint only, so find out if this node
+ // is at the constraint, while allowing for a small margin
+ if (Geom::L2(target_pt - c.projection(target_pt)) > 1e-9) {
+ // The distance from the target point to its projection on the constraint
+ // is too large, so this point is not on the constraint. Skip it!
+ continue;
+ }
+ }
+
+ Geom::Coord dist = Geom::L2(target_pt - p.getPoint());
if (dist < getSnapperTolerance() && dist < s.getSnapDistance()) {
- s = SnappedPoint((*k).getPoint(), p.getSourceType(), p.getSourceNum(), (*k).getTargetType(), dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true, (*k).getTargetBBox());
+ s = SnappedPoint(target_pt, p.getSourceType(), p.getSourceNum(), (*k).getTargetType(), dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true, (*k).getTargetBBox());
success = true;
}
}
@@ -300,13 +312,13 @@ void Inkscape::ObjectSnapper::_snapTranslatingGuide(SnappedConstraints &sc,
Geom::Coord tol = getSnapperTolerance();
for (std::vector<SnapCandidatePoint>::const_iterator k = _points_to_snap_to->begin(); k != _points_to_snap_to->end(); k++) {
-
+ Geom::Point target_pt = (*k).getPoint();
// Project each node (*k) on the guide line (running through point p)
- Geom::Point p_proj = Geom::projection((*k).getPoint(), Geom::Line(p, p + Geom::rot90(guide_normal)));
- Geom::Coord dist = Geom::L2((*k).getPoint() - p_proj); // distance from node to the guide
+ Geom::Point p_proj = Geom::projection(target_pt, Geom::Line(p, p + Geom::rot90(guide_normal)));
+ Geom::Coord dist = Geom::L2(target_pt - p_proj); // distance from node to the guide
Geom::Coord dist2 = Geom::L2(p - p_proj); // distance from projection of node on the guide, to the mouse location
if ((dist < tol && dist2 < tol) || getSnapperAlwaysSnap()) {
- s = SnappedPoint((*k).getPoint(), SNAPSOURCE_GUIDE, 0, (*k).getTargetType(), dist, tol, getSnapperAlwaysSnap(), false, true, (*k).getTargetBBox());
+ s = SnappedPoint(target_pt, SNAPSOURCE_GUIDE, 0, (*k).getTargetType(), dist, tol, getSnapperAlwaysSnap(), false, true, (*k).getTargetBBox());
sc.points.push_back(s);
}
}
@@ -608,7 +620,7 @@ void Inkscape::ObjectSnapper::freeSnap(SnappedConstraints &sc,
_findCandidates(sp_document_root(_snapmanager->getDocument()), it, p.getSourceNum() == 0, local_bbox_to_snap, false, Geom::identity());
}
-
+ // TODO: Argh, UGLY! Get rid of this here, move this logic to the snap manager
bool snap_nodes = (_snapmanager->snapprefs.getSnapModeNode() && (
_snapmanager->snapprefs.getSnapToItemNode() ||
_snapmanager->snapprefs.getSnapSmoothNodes() ||
@@ -655,7 +667,8 @@ void Inkscape::ObjectSnapper::constrainedSnap( SnappedConstraints &sc,
Inkscape::SnapCandidatePoint const &p,
Geom::OptRect const &bbox_to_snap,
SnapConstraint const &c,
- std::vector<SPItem const *> const *it) const
+ std::vector<SPItem const *> const *it,
+ std::vector<SnapCandidatePoint> *unselected_nodes) const
{
if (_snap_enabled == false || _snapmanager->snapprefs.getSnapFrom(p.getSourceType()) == false) {
return;
@@ -671,10 +684,24 @@ void Inkscape::ObjectSnapper::constrainedSnap( SnappedConstraints &sc,
// This is useful for example when scaling an object while maintaining a fixed aspect ratio. It's
// nodes are only allowed to move in one direction (i.e. in one degree of freedom).
- // When snapping to objects, we either snap to their nodes or their paths. It is however very
- // unlikely that any node will be exactly at the constrained line, so for a constrained snap
- // to objects we will only consider the object's paths. Beside, the nodes will be at these paths,
- // so we will more or less snap to them anyhow.
+ // TODO: Argh, UGLY! Get rid of this here, move this logic to the snap manager
+ bool snap_nodes = (_snapmanager->snapprefs.getSnapModeNode() && (
+ _snapmanager->snapprefs.getSnapToItemNode() ||
+ _snapmanager->snapprefs.getSnapSmoothNodes() ||
+ _snapmanager->snapprefs.getSnapLineMidpoints() ||
+ _snapmanager->snapprefs.getSnapObjectMidpoints()
+ )) || (_snapmanager->snapprefs.getSnapModeBBox() && (
+ _snapmanager->snapprefs.getSnapToBBoxNode() ||
+ _snapmanager->snapprefs.getSnapBBoxEdgeMidpoints() ||
+ _snapmanager->snapprefs.getSnapBBoxMidpoints()
+ )) || (_snapmanager->snapprefs.getSnapModeBBoxOrNodes() && (
+ _snapmanager->snapprefs.getIncludeItemCenter() ||
+ _snapmanager->snapprefs.getSnapToPageBorder()
+ ));
+
+ if (snap_nodes) {
+ _snapNodes(sc, p, unselected_nodes, c);
+ }
if (_snapmanager->snapprefs.getSnapToItemPath() || _snapmanager->snapprefs.getSnapToBBoxPath() || _snapmanager->snapprefs.getSnapToPageBorder()) {
_snapPathsConstrained(sc, p, c);
diff --git a/src/object-snapper.h b/src/object-snapper.h
index 99c8a077e..4933d8459 100644
--- a/src/object-snapper.h
+++ b/src/object-snapper.h
@@ -57,7 +57,8 @@ public:
Inkscape::SnapCandidatePoint const &p,
Geom::OptRect const &bbox_to_snap,
SnapConstraint const &c,
- std::vector<SPItem const *> const *it) const;
+ std::vector<SPItem const *> const *it,
+ std::vector<SnapCandidatePoint> *unselected_nodes) const;
private:
//store some lists of candidates, points and paths, so we don't have to rebuild them for each point we want to snap
@@ -74,7 +75,8 @@ private:
void _snapNodes(SnappedConstraints &sc,
Inkscape::SnapCandidatePoint const &p,
- std::vector<SnapCandidatePoint> *unselected_nodes) const; // in desktop coordinates
+ std::vector<SnapCandidatePoint> *unselected_nodes,
+ SnapConstraint const &c = SnapConstraint()) const; // in desktop coordinates
void _snapTranslatingGuide(SnappedConstraints &sc,
Geom::Point const &p,
diff --git a/src/snap.cpp b/src/snap.cpp
index bcacb81e2..7ba85a9aa 100644
--- a/src/snap.cpp
+++ b/src/snap.cpp
@@ -374,7 +374,7 @@ Inkscape::SnappedPoint SnapManager::constrainedSnap(Inkscape::SnapCandidatePoint
SnappedConstraints sc;
SnapperList const snappers = getSnappers();
for (SnapperList::const_iterator i = snappers.begin(); i != snappers.end(); i++) {
- (*i)->constrainedSnap(sc, p, bbox_to_snap, constraint, &_items_to_ignore);
+ (*i)->constrainedSnap(sc, p, bbox_to_snap, constraint, &_items_to_ignore, _unselected_nodes);
}
Inkscape::SnappedPoint result = findBestSnap(p, sc, true);
@@ -422,7 +422,7 @@ Inkscape::SnappedPoint SnapManager::multipleConstrainedSnaps(Inkscape::SnapCandi
// Try to snap to the constraint
if (!snapping_is_futile) {
for (SnapperList::const_iterator i = snappers.begin(); i != snappers.end(); i++) {
- (*i)->constrainedSnap(sc, p, bbox_to_snap, *c, &_items_to_ignore);
+ (*i)->constrainedSnap(sc, p, bbox_to_snap, *c, &_items_to_ignore,_unselected_nodes);
}
}
}
@@ -526,14 +526,14 @@ void SnapManager::guideConstrainedSnap(Geom::Point &p, SPGuide const &guideline)
SnappedConstraints sc;
Inkscape::Snapper::SnapConstraint cl(guideline.point_on_line, Geom::rot90(guideline.normal_to_line));
if (object.ThisSnapperMightSnap()) {
- object.constrainedSnap(sc, candidate, Geom::OptRect(), cl, NULL);
+ object.constrainedSnap(sc, candidate, Geom::OptRect(), cl, NULL, NULL);
}
// Snap to guides & grid lines
SnapperList snappers = getGridSnappers();
snappers.push_back(&guide);
for (SnapperList::const_iterator i = snappers.begin(); i != snappers.end(); i++) {
- (*i)->constrainedSnap(sc, candidate, Geom::OptRect(), cl, NULL);
+ (*i)->constrainedSnap(sc, candidate, Geom::OptRect(), cl, NULL, NULL);
}
Inkscape::SnappedPoint const s = findBestSnap(candidate, sc, false);
diff --git a/src/snapper.h b/src/snapper.h
index d8214db80..91784d3ae 100644
--- a/src/snapper.h
+++ b/src/snapper.h
@@ -72,7 +72,7 @@ public:
class SnapConstraint
{
private:
- enum SnapConstraintType {LINE, DIRECTION, CIRCLE};
+ enum SnapConstraintType {LINE, DIRECTION, CIRCLE, UNDEFINED};
public:
// Constructs a direction constraint, e.g. horizontal or vertical but without a specified point
@@ -82,11 +82,13 @@ public:
SnapConstraint(Geom::Line const &l) : _point(l.origin()), _direction(l.versor()), _type(LINE) {}
// Constructs a circular constraint
SnapConstraint(Geom::Point const &p, Geom::Point const &d, Geom::Coord const &r) : _point(p), _direction(d), _radius(r), _type(CIRCLE) {}
+ // Undefined, or empty constraint
+ SnapConstraint() : _type(UNDEFINED) {}
- bool hasPoint() const {return _type != DIRECTION;}
+ bool hasPoint() const {return _type != DIRECTION && _type != UNDEFINED;}
Geom::Point getPoint() const {
- g_assert(_type != DIRECTION);
+ g_assert(_type != DIRECTION && _type != UNDEFINED);
return _point;
}
@@ -102,6 +104,7 @@ public:
bool isCircular() const { return _type == CIRCLE; }
bool isLinear() const { return _type == LINE; }
bool isDirection() const { return _type == DIRECTION; }
+ bool isUndefined() const { return _type == UNDEFINED; }
Geom::Point projection(Geom::Point const &p) const { // returns the projection of p on this constraint
if (_type == CIRCLE) {
@@ -114,11 +117,14 @@ public:
// point to be projected is exactly at the center of the circle, so any point on the circle is a projection
return _point + Geom::Point(_radius, 0);
}
- } else {
+ } else if (_type != UNDEFINED){
// project on to a linear constraint
Geom::Point const p1_on_cl = (_type == LINE) ? _point : p;
Geom::Point const p2_on_cl = p1_on_cl + _direction;
return Geom::projection(p, Geom::Line(p1_on_cl, p2_on_cl));
+ } else {
+ g_warning("Bug: trying to find the projection onto an undefined constraint");
+ return Geom::Point();
}
}
@@ -133,7 +139,8 @@ public:
Inkscape::SnapCandidatePoint const &/*p*/,
Geom::OptRect const &/*bbox_to_snap*/,
SnapConstraint const &/*c*/,
- std::vector<SPItem const *> const */*it*/) const {};
+ std::vector<SPItem const *> const */*it*/,
+ std::vector<SnapCandidatePoint> */*unselected_nodes*/) const {};
protected:
SnapManager *_snapmanager;