diff options
Diffstat (limited to 'src/object-snapper.cpp')
| -rw-r--r-- | src/object-snapper.cpp | 83 |
1 files changed, 56 insertions, 27 deletions
diff --git a/src/object-snapper.cpp b/src/object-snapper.cpp index 536affb82..f96335c4a 100644 --- a/src/object-snapper.cpp +++ b/src/object-snapper.cpp @@ -16,6 +16,7 @@ #include <2geom/point.h> #include <2geom/rect.h> #include <2geom/line.h> +#include <2geom/circle.h> #include "document.h" #include "sp-namedview.h" #include "sp-image.h" @@ -91,6 +92,12 @@ void Inkscape::ObjectSnapper::_findCandidates(SPObject* parent, return; } + if (_snapmanager->getDesktop() == NULL) { + g_warning("desktop == NULL, so we cannot snap; please inform the developpers of this bug"); + // Apparently the etup() method from the SnapManager class hasn't been called before trying to snap. + } + + if (first_point) { _candidates->clear(); } @@ -99,7 +106,6 @@ void Inkscape::ObjectSnapper::_findCandidates(SPObject* parent, bbox_to_snap_incl.expandBy(getSnapperTolerance()); // see? for (SPObject* o = sp_object_first_child(parent); o != NULL; o = SP_OBJECT_NEXT(o)) { - g_assert(_snapmanager->getDesktop() != NULL); if (SP_IS_ITEM(o) && !(_snapmanager->getDesktop()->itemIsHidden(SP_ITEM(o)) && !clip_or_mask)) { // Snapping to items in a locked layer is allowed // Don't snap to hidden objects, unless they're a clipped path or a mask @@ -441,6 +447,9 @@ void Inkscape::ObjectSnapper::_snapPaths(SnappedConstraints &sc, } } + int num_path = 0; + int num_segm = 0; + for (std::vector<Inkscape::SnapCandidatePath >::const_iterator it_p = _paths_to_snap_to->begin(); it_p != _paths_to_snap_to->end(); it_p++) { bool const being_edited = node_tool_active && (*it_p).currently_being_edited; //if true then this pathvector it_pv is currently being edited in the node tool @@ -482,11 +491,13 @@ void Inkscape::ObjectSnapper::_snapPaths(SnappedConstraints &sc, if (!being_edited || (c1 && c2)) { Geom::Coord const dist = Geom::distance(sp_doc, p_doc); if (dist < getSnapperTolerance()) { - sc.curves.push_back(Inkscape::SnappedCurve(sp_dt, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, curve, p.getSourceType(), p.getSourceNum(), it_p->target_type, it_p->target_bbox)); + sc.curves.push_back(Inkscape::SnappedCurve(sp_dt, num_path, num_segm, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, curve, p.getSourceType(), p.getSourceNum(), it_p->target_type, it_p->target_bbox)); } } } + num_segm++; } // End of: for (Geom::PathVector::iterator ....) + num_path++; } } @@ -512,7 +523,7 @@ bool Inkscape::ObjectSnapper::isUnselectedNode(Geom::Point const &point, std::ve void Inkscape::ObjectSnapper::_snapPathsConstrained(SnappedConstraints &sc, Inkscape::SnapCandidatePoint const &p, - ConstraintLine const &c) const + SnapConstraint const &c) const { _collectPaths(p, p.getSourceNum() == 0); @@ -527,36 +538,54 @@ void Inkscape::ObjectSnapper::_snapPathsConstrained(SnappedConstraints &sc, direction_vector = Geom::unit_vector(direction_vector); } - // The intersection point of the constraint line with any path, - // must lie within two points on the constraintline: p_min_on_cl and p_max_on_cl - // The distance between those points is twice the snapping tolerance + // The intersection point of the constraint line with any path, must lie within two points on the + // SnapConstraint: p_min_on_cl and p_max_on_cl. The distance between those points is twice the snapping tolerance Geom::Point const p_proj_on_cl = p.getPoint(); // projection has already been taken care of in constrainedSnap in the snapmanager; Geom::Point const p_min_on_cl = _snapmanager->getDesktop()->dt2doc(p_proj_on_cl - getSnapperTolerance() * direction_vector); Geom::Point const p_max_on_cl = _snapmanager->getDesktop()->dt2doc(p_proj_on_cl + getSnapperTolerance() * direction_vector); + Geom::Coord tolerance = getSnapperTolerance(); + + // PS: Because the paths we're about to snap to are all expressed relative to document coordinate system, we will have + // to convert the snapper coordinates from the desktop coordinates to document coordinates - Geom::Path cl; - std::vector<Geom::Path> clv; - cl.start(p_min_on_cl); - cl.appendNew<Geom::LineSegment>(p_max_on_cl); - clv.push_back(cl); + std::vector<Geom::Path> constraint_path; + if (c.isCircular()) { + Geom::Circle constraint_circle(_snapmanager->getDesktop()->dt2doc(c.getPoint()), c.getRadius()); + constraint_circle.getPath(constraint_path); + } else { + Geom::Path constraint_line; + constraint_line.start(p_min_on_cl); + constraint_line.appendNew<Geom::LineSegment>(p_max_on_cl); + constraint_path.push_back(constraint_line); + } for (std::vector<Inkscape::SnapCandidatePath >::const_iterator k = _paths_to_snap_to->begin(); k != _paths_to_snap_to->end(); k++) { if (k->path_vector) { - Geom::CrossingSet cs = Geom::crossings(clv, *(k->path_vector)); - if (cs.size() > 0) { - // We need only the first element of cs, because cl is only a single straight linesegment - // This first element contains a vector filled with crossings of cl with k->first - for (std::vector<Geom::Crossing>::const_iterator m = cs[0].begin(); m != cs[0].end(); m++) { - if ((*m).ta >= 0 && (*m).ta <= 1 ) { - // Reconstruct the point of intersection - Geom::Point p_inters = p_min_on_cl + ((*m).ta) * (p_max_on_cl - p_min_on_cl); - // When it's within snapping range, then return it - // (within snapping range == between p_min_on_cl and p_max_on_cl == 0 < ta < 1) - Geom::Coord dist = Geom::L2(_snapmanager->getDesktop()->dt2doc(p_proj_on_cl) - p_inters); - SnappedPoint s(_snapmanager->getDesktop()->doc2dt(p_inters), p.getSourceType(), p.getSourceNum(), k->target_type, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true, k->target_bbox); + Geom::CrossingSet cs = Geom::crossings(constraint_path, *(k->path_vector)); + unsigned int index = 0; + for (Geom::CrossingSet::const_iterator i = cs.begin(); i != cs.end(); i++) { + if (index >= constraint_path.size()) { + break; + } + for (Geom::Crossings::const_iterator m = (*i).begin(); m != (*i).end(); m++) { + //std::cout << "ta = " << (*m).ta << " | tb = " << (*m).tb << std::endl; + // Reconstruct the point of intersection + Geom::Point p_inters = constraint_path[index].pointAt((*m).ta); + // .. and convert it to desktop coordinates + p_inters = _snapmanager->getDesktop()->doc2dt(p_inters); + Geom::Coord dist = Geom::L2(p_proj_on_cl - p_inters); + SnappedPoint s = SnappedPoint(p_inters, p.getSourceType(), p.getSourceNum(), k->target_type, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true, k->target_bbox);; + if (dist <= tolerance) { // If the intersection is within snapping range, then we might snap to it + if (c.isCircular()) { + Geom::Point v_orig = c.getDirection(); // vector from the origin to the original (untransformed) point + Geom::Point v_inters = p_inters - c.getPoint(); + Geom::Coord radians = atan2(Geom::dot(Geom::rot90(v_orig), v_inters), Geom::dot(v_orig, v_inters)); + s.setTransformation(Geom::Point(radians, radians)); + } sc.points.push_back(s); } } + index++; } } } @@ -612,7 +641,7 @@ void Inkscape::ObjectSnapper::freeSnap(SnappedConstraints &sc, void Inkscape::ObjectSnapper::constrainedSnap( SnappedConstraints &sc, Inkscape::SnapCandidatePoint const &p, Geom::OptRect const &bbox_to_snap, - ConstraintLine const &c, + SnapConstraint const &c, std::vector<SPItem const *> const *it) const { if (_snap_enabled == false || _snapmanager->snapprefs.getSnapFrom(p.getSourceType()) == false) { @@ -667,7 +696,7 @@ void Inkscape::ObjectSnapper::guideFreeSnap(SnappedConstraints &sc, void Inkscape::ObjectSnapper::guideConstrainedSnap(SnappedConstraints &sc, Geom::Point const &p, Geom::Point const &guide_normal, - ConstraintLine const &/*c*/) const + SnapConstraint const &/*c*/) const { /* Get a list of all the SPItems that we will try to snap to */ std::vector<SPItem*> cand; @@ -693,7 +722,7 @@ void Inkscape::ObjectSnapper::guideConstrainedSnap(SnappedConstraints &sc, bool Inkscape::ObjectSnapper::ThisSnapperMightSnap() const { bool snap_to_something = _snapmanager->snapprefs.getSnapToItemPath() - || _snapmanager->snapprefs.getSnapToItemNode() + || _snapmanager->snapprefs.getSnapToItemNode() || _snapmanager->snapprefs.getSnapSmoothNodes() || _snapmanager->snapprefs.getSnapToBBoxPath() || _snapmanager->snapprefs.getSnapToBBoxNode() || _snapmanager->snapprefs.getSnapToPageBorder() @@ -706,7 +735,7 @@ bool Inkscape::ObjectSnapper::ThisSnapperMightSnap() const bool Inkscape::ObjectSnapper::GuidesMightSnap() const // almost the same as ThisSnapperMightSnap above, but only looking at points (and not paths) { - bool snap_to_something = _snapmanager->snapprefs.getSnapToItemNode() + bool snap_to_something = _snapmanager->snapprefs.getSnapToItemNode() || _snapmanager->snapprefs.getSnapSmoothNodes() || _snapmanager->snapprefs.getSnapToPageBorder() || (_snapmanager->snapprefs.getSnapModeBBox() && _snapmanager->snapprefs.getSnapToBBoxNode()) || (_snapmanager->snapprefs.getSnapModeBBox() && (_snapmanager->snapprefs.getSnapBBoxEdgeMidpoints() || _snapmanager->snapprefs.getSnapBBoxMidpoints())) |
