summaryrefslogtreecommitdiffstats
path: root/src/ui/tool
diff options
context:
space:
mode:
authorKrzysztof Kosi??ski <tweenk.pl@gmail.com>2010-07-21 00:17:34 +0000
committerKrzysztof KosiƄski <tweenk.pl@gmail.com>2010-07-21 00:17:34 +0000
commitfc337f39ebcfa544acbd2be2fdc6943d7d584d78 (patch)
tree3cad8b210744e1605676938bdf74875dc6c72f58 /src/ui/tool
parentfix Bug 308204, add Visual bbox option (diff)
downloadinkscape-fc337f39ebcfa544acbd2be2fdc6943d7d584d78.tar.gz
inkscape-fc337f39ebcfa544acbd2be2fdc6943d7d584d78.zip
When snapping to handle lines (Ctrl+Alt node drag), snap
to perpendiculars of those lines as well (bzr r9636)
Diffstat (limited to 'src/ui/tool')
-rw-r--r--src/ui/tool/node.cpp71
1 files changed, 64 insertions, 7 deletions
diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp
index 886ddd1be..69c09602e 100644
--- a/src/ui/tool/node.cpp
+++ b/src/ui/tool/node.cpp
@@ -969,12 +969,27 @@ void Node::dragged(Geom::Point &new_pos, GdkEventMotion *event)
if (held_control(*event)) {
Geom::Point origin = _last_drag_origin();
- Inkscape::SnappedPoint fp, bp;
+ Inkscape::SnappedPoint fp, bp, fpp, bpp;
if (held_alt(*event)) {
// with Ctrl+Alt, constrain to handle lines
- // project the new position onto a handle line that is closer
- boost::optional<Geom::Point> front_point, back_point;
- boost::optional<Inkscape::Snapper::SnapConstraint> line_front, line_back;
+ // project the new position onto a handle line that is closer;
+ // also snap to perpendiculars of handle lines
+
+ // TODO: this code is repetitive to the point of sillyness. Find a way
+ // to express this concisely by modifying the semantics of snapping calls.
+ // During a non-snap invocation, we should call constrainedSnap()
+ // anyway, but it should just return the closest point matching the constraint
+ // rather than snapping to an object. There should be comparison
+ // operators defined for snap results, to simplify determining the best one,
+ // or the snapping calls should take a reference to a snapping result and
+ // replace it with the current result if it's better.
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ int snaps = prefs->getIntLimited("/options/rotationsnapsperpi/value", 12, 1, 1000);
+ double min_angle = M_PI / snaps;
+
+ boost::optional<Geom::Point> front_point, back_point, fperp_point, bperp_point;
+ boost::optional<Inkscape::Snapper::SnapConstraint> line_front, line_back, line_fperp, line_bperp;
if (_front.isDegenerate()) {
if (_is_line_segment(this, _next()))
front_point = _next()->position() - origin;
@@ -987,10 +1002,28 @@ void Node::dragged(Geom::Point &new_pos, GdkEventMotion *event)
} else {
back_point = _back.relativePos();
}
- if (front_point)
+ if (front_point) {
line_front = Inkscape::Snapper::SnapConstraint(origin, *front_point);
- if (back_point)
+ fperp_point = Geom::rot90(*front_point);
+ }
+ if (back_point) {
line_back = Inkscape::Snapper::SnapConstraint(origin, *back_point);
+ bperp_point = Geom::rot90(*back_point);
+ }
+ // perpendiculars only snap when they are further than snap increment away
+ // from the second handle constraint
+ if (fperp_point && (!back_point ||
+ (fabs(Geom::angle_between(*fperp_point, *back_point)) > min_angle &&
+ fabs(Geom::angle_between(*fperp_point, *back_point)) < M_PI - min_angle)))
+ {
+ line_fperp = Inkscape::Snapper::SnapConstraint(origin, *fperp_point);
+ }
+ if (bperp_point && (!front_point ||
+ (fabs(Geom::angle_between(*bperp_point, *front_point)) > min_angle &&
+ fabs(Geom::angle_between(*bperp_point, *front_point)) < M_PI - min_angle)))
+ {
+ line_bperp = Inkscape::Snapper::SnapConstraint(origin, *bperp_point);
+ }
// TODO: combine the snap and non-snap branches by modifying snap.h / snap.cpp
if (snap) {
@@ -1002,11 +1035,25 @@ void Node::dragged(Geom::Point &new_pos, GdkEventMotion *event)
bp = sm.constrainedSnap(Inkscape::SnapCandidatePoint(new_pos,
_snapSourceType()), *line_back);
}
+ if (line_fperp) {
+ fpp = sm.constrainedSnap(Inkscape::SnapCandidatePoint(new_pos,
+ _snapSourceType()), *line_fperp);
+ }
+ if (line_bperp) {
+ bpp = sm.constrainedSnap(Inkscape::SnapCandidatePoint(new_pos,
+ _snapSourceType()), *line_bperp);
+ }
}
- if (fp.getSnapped() || bp.getSnapped()) {
+ if (fp.getSnapped() || bp.getSnapped() || fpp.getSnapped() || bpp.getSnapped()) {
if (fp.isOtherSnapBetter(bp, false)) {
fp = bp;
}
+ if (fp.isOtherSnapBetter(fpp, false)) {
+ fp = fpp;
+ }
+ if (fp.isOtherSnapBetter(bpp, false)) {
+ fp = bpp;
+ }
fp.getPoint(new_pos);
_desktop->snapindicator->set_new_snaptarget(fp);
} else {
@@ -1019,6 +1066,16 @@ void Node::dragged(Geom::Point &new_pos, GdkEventMotion *event)
if (!pos || (pos && Geom::distance(new_pos, *pos) > Geom::distance(new_pos, pos2)))
pos = pos2;
}
+ if (line_fperp) {
+ Geom::Point pos2 = line_fperp->projection(new_pos);
+ if (!pos || (pos && Geom::distance(new_pos, *pos) > Geom::distance(new_pos, pos2)))
+ pos = pos2;
+ }
+ if (line_bperp) {
+ Geom::Point pos2 = line_bperp->projection(new_pos);
+ if (!pos || (pos && Geom::distance(new_pos, *pos) > Geom::distance(new_pos, pos2)))
+ pos = pos2;
+ }
if (pos) {
new_pos = *pos;
} else {