From 35300c9822f9f84c8a011913235fd4e5dc2c5ac8 Mon Sep 17 00:00:00 2001 From: Diederik van Lierop Date: Mon, 12 Jul 2010 07:51:13 +0200 Subject: - Snap while rotating an object using the selector tool - Rename the ConstraintLine class to SnapConstraint - Move some duplicated code to 2geom (bzr r9607) --- src/ui/tool/node.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/ui/tool/node.cpp') diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp index 9c9c58ff1..886ddd1be 100644 --- a/src/ui/tool/node.cpp +++ b/src/ui/tool/node.cpp @@ -266,7 +266,7 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event) Node *node_away = (this == &_parent->_front ? _parent->_prev() : _parent->_next()); if (_parent->type() == NODE_SMOOTH && Node::_is_line_segment(_parent, node_away)) { - Inkscape::Snapper::ConstraintLine cl(_parent->position(), + Inkscape::Snapper::SnapConstraint cl(_parent->position(), _parent->position() - node_away->position()); Inkscape::SnappedPoint p; p = sm.constrainedSnap(Inkscape::SnapCandidatePoint(new_pos, SNAPSOURCE_NODE_HANDLE), cl); @@ -974,7 +974,7 @@ void Node::dragged(Geom::Point &new_pos, GdkEventMotion *event) // with Ctrl+Alt, constrain to handle lines // project the new position onto a handle line that is closer boost::optional front_point, back_point; - boost::optional line_front, line_back; + boost::optional line_front, line_back; if (_front.isDegenerate()) { if (_is_line_segment(this, _next())) front_point = _next()->position() - origin; @@ -988,9 +988,9 @@ void Node::dragged(Geom::Point &new_pos, GdkEventMotion *event) back_point = _back.relativePos(); } if (front_point) - line_front = Inkscape::Snapper::ConstraintLine(origin, *front_point); + line_front = Inkscape::Snapper::SnapConstraint(origin, *front_point); if (back_point) - line_back = Inkscape::Snapper::ConstraintLine(origin, *back_point); + line_back = Inkscape::Snapper::SnapConstraint(origin, *back_point); // TODO: combine the snap and non-snap branches by modifying snap.h / snap.cpp if (snap) { @@ -1029,8 +1029,8 @@ void Node::dragged(Geom::Point &new_pos, GdkEventMotion *event) // with Ctrl, constrain to axes // TODO combine the two branches if (snap) { - Inkscape::Snapper::ConstraintLine line_x(origin, Geom::Point(1, 0)); - Inkscape::Snapper::ConstraintLine line_y(origin, Geom::Point(0, 1)); + Inkscape::Snapper::SnapConstraint line_x(origin, Geom::Point(1, 0)); + Inkscape::Snapper::SnapConstraint line_y(origin, Geom::Point(0, 1)); fp = sm.constrainedSnap(Inkscape::SnapCandidatePoint(new_pos, _snapSourceType()), line_x); bp = sm.constrainedSnap(Inkscape::SnapCandidatePoint(new_pos, _snapSourceType()), line_y); } -- cgit v1.2.3 From fc337f39ebcfa544acbd2be2fdc6943d7d584d78 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Wed, 21 Jul 2010 02:17:34 +0200 Subject: When snapping to handle lines (Ctrl+Alt node drag), snap to perpendiculars of those lines as well (bzr r9636) --- src/ui/tool/node.cpp | 71 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 64 insertions(+), 7 deletions(-) (limited to 'src/ui/tool/node.cpp') 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 front_point, back_point; - boost::optional 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 front_point, back_point, fperp_point, bperp_point; + boost::optional 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 { -- cgit v1.2.3 From a83da58db0ad8e9a0b559a9fd5a55f40e247f38e Mon Sep 17 00:00:00 2001 From: Diederik van Lierop Date: Sat, 7 Aug 2010 10:15:18 +0200 Subject: Add a constrained snap method that takes multiple constraints. This reduces the code repetitiveness in the node tool (bzr r9692) --- src/ui/tool/node.cpp | 117 +++++++-------------------------------------------- 1 file changed, 16 insertions(+), 101 deletions(-) (limited to 'src/ui/tool/node.cpp') diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp index 69c09602e..a8582ccc5 100644 --- a/src/ui/tool/node.cpp +++ b/src/ui/tool/node.cpp @@ -270,9 +270,7 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event) _parent->position() - node_away->position()); Inkscape::SnappedPoint p; p = sm.constrainedSnap(Inkscape::SnapCandidatePoint(new_pos, SNAPSOURCE_NODE_HANDLE), cl); - if (p.getSnapped()) { - p.getPoint(new_pos); - } + new_pos = p.getPoint(); } else { sm.freeSnapReturnByRef(new_pos, SNAPSOURCE_NODE_HANDLE); } @@ -945,7 +943,7 @@ void Node::dragged(Geom::Point &new_pos, GdkEventMotion *event) // For a note on how snapping is implemented in Inkscape, see snap.h. SnapManager &sm = _desktop->namedview->snap_manager; bool snap = sm.someSnapperMightSnap(); - std::vector unselected; + Inkscape::SnappedPoint sp; if (snap) { /* setup * TODO We are doing this every time a snap happens. It should once be done only once @@ -955,6 +953,7 @@ void Node::dragged(Geom::Point &new_pos, GdkEventMotion *event) * TODO Snapping to unselected segments of selected paths doesn't work yet. */ // Build the list of unselected nodes. + std::vector unselected; typedef ControlPointSelection::Set Set; Set &nodes = _selection.allPoints(); for (Set::iterator i = nodes.begin(); i != nodes.end(); ++i) { @@ -964,32 +963,22 @@ void Node::dragged(Geom::Point &new_pos, GdkEventMotion *event) unselected.push_back(p); } } - sm.setupIgnoreSelection(_desktop, false, &unselected); + sm.setupIgnoreSelection(_desktop, true, &unselected); } if (held_control(*event)) { Geom::Point origin = _last_drag_origin(); - Inkscape::SnappedPoint fp, bp, fpp, bpp; + std::vector constraints; if (held_alt(*event)) { // with Ctrl+Alt, constrain to handle lines // 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 front_point, back_point, fperp_point, bperp_point; - boost::optional line_front, line_back, line_fperp, line_bperp; if (_front.isDegenerate()) { if (_is_line_segment(this, _next())) front_point = _next()->position() - origin; @@ -1003,11 +992,11 @@ void Node::dragged(Geom::Point &new_pos, GdkEventMotion *event) back_point = _back.relativePos(); } if (front_point) { - line_front = Inkscape::Snapper::SnapConstraint(origin, *front_point); + constraints.push_back(Inkscape::Snapper::SnapConstraint(origin, *front_point)); fperp_point = Geom::rot90(*front_point); } if (back_point) { - line_back = Inkscape::Snapper::SnapConstraint(origin, *back_point); + constraints.push_back(Inkscape::Snapper::SnapConstraint(origin, *back_point)); bperp_point = Geom::rot90(*back_point); } // perpendiculars only snap when they are further than snap increment away @@ -1016,100 +1005,26 @@ void Node::dragged(Geom::Point &new_pos, GdkEventMotion *event) (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); + constraints.push_back(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); + constraints.push_back(Inkscape::Snapper::SnapConstraint(origin, *bperp_point)); } - // TODO: combine the snap and non-snap branches by modifying snap.h / snap.cpp - if (snap) { - if (line_front) { - fp = sm.constrainedSnap(Inkscape::SnapCandidatePoint(new_pos, - _snapSourceType()), *line_front); - } - if (line_back) { - 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() || 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 { - boost::optional pos; - if (line_front) { - pos = line_front->projection(new_pos); - } - if (line_back) { - Geom::Point pos2 = line_back->projection(new_pos); - 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 { - new_pos = origin; - } - } + sp = sm.multipleConstrainedSnaps(Inkscape::SnapCandidatePoint(new_pos, _snapSourceType()), constraints); } else { // with Ctrl, constrain to axes - // TODO combine the two branches - if (snap) { - Inkscape::Snapper::SnapConstraint line_x(origin, Geom::Point(1, 0)); - Inkscape::Snapper::SnapConstraint line_y(origin, Geom::Point(0, 1)); - fp = sm.constrainedSnap(Inkscape::SnapCandidatePoint(new_pos, _snapSourceType()), line_x); - bp = sm.constrainedSnap(Inkscape::SnapCandidatePoint(new_pos, _snapSourceType()), line_y); - } - if (fp.getSnapped() || bp.getSnapped()) { - if (fp.isOtherSnapBetter(bp, false)) { - fp = bp; - } - fp.getPoint(new_pos); - _desktop->snapindicator->set_new_snaptarget(fp); - } else { - Geom::Point origin = _last_drag_origin(); - Geom::Point delta = new_pos - origin; - Geom::Dim2 d = (fabs(delta[Geom::X]) < fabs(delta[Geom::Y])) ? Geom::X : Geom::Y; - new_pos[d] = origin[d]; - } + constraints.push_back(Inkscape::Snapper::SnapConstraint(origin, Geom::Point(1, 0))); + constraints.push_back(Inkscape::Snapper::SnapConstraint(origin, Geom::Point(0, 1))); + sp = sm.multipleConstrainedSnaps(Inkscape::SnapCandidatePoint(new_pos, _snapSourceType()), constraints); } + new_pos = sp.getPoint(); } else if (snap) { - Inkscape::SnappedPoint p = sm.freeSnap(Inkscape::SnapCandidatePoint(new_pos, _snapSourceType())); - if (p.getSnapped()) { - p.getPoint(new_pos); - _desktop->snapindicator->set_new_snaptarget(p); - } + sp = sm.freeSnap(Inkscape::SnapCandidatePoint(new_pos, _snapSourceType())); + new_pos = sp.getPoint(); } SelectableControlPoint::dragged(new_pos, event); -- cgit v1.2.3