From: dvlierop2 Date: Wed, 10 Dec 2008 21:51:33 +0000 (+0000) Subject: - Fix bug #304405 (snapping to an intersection of lines at infinity is wrong) X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=71c8857afc501c5e737bce6022fd9ac810d94c05;p=inkscape.git - Fix bug #304405 (snapping to an intersection of lines at infinity is wrong) - Replace tabs by spaces --- diff --git a/src/snap.cpp b/src/snap.cpp index e13809256..ac2f1321c 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -48,14 +48,14 @@ SnapManager::SnapManager(SPNamedView const *v) : guide(this, 0), object(this, 0), snapprefs(), - _named_view(v) -{ + _named_view(v) +{ } /** * \return List of snappers that we use. */ -SnapManager::SnapperList +SnapManager::SnapperList SnapManager::getSnappers() const { SnapManager::SnapperList s; @@ -71,7 +71,7 @@ SnapManager::getSnappers() const /** * \return List of gridsnappers that we use. */ -SnapManager::SnapperList +SnapManager::SnapperList SnapManager::getGridSnappers() const { SnapperList s; @@ -97,13 +97,13 @@ bool SnapManager::someSnapperMightSnap() const if ( !snapprefs.getSnapEnabledGlobally() || snapprefs.getSnapPostponedGlobally() ) { return false; } - + SnapperList const s = getSnappers(); SnapperList::const_iterator i = s.begin(); while (i != s.end() && (*i)->ThisSnapperMightSnap() == false) { i++; } - + return (i != s.end()); } @@ -112,8 +112,8 @@ bool SnapManager::someSnapperMightSnap() const * * \param point_type 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 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 snappers List of snappers to try to snap to * \return Snapped point. */ @@ -123,7 +123,7 @@ void SnapManager::freeSnapReturnByRef(Inkscape::SnapPreferences::PointType point bool first_point, Geom::OptRect const &bbox_to_snap) const { - Inkscape::SnappedPoint const s = freeSnap(point_type, p, first_point, bbox_to_snap); + Inkscape::SnappedPoint const s = freeSnap(point_type, p, first_point, bbox_to_snap); s.getPoint(p); } @@ -132,8 +132,8 @@ void SnapManager::freeSnapReturnByRef(Inkscape::SnapPreferences::PointType point * * \param point_type 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 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 snappers List of snappers to try to snap to * \return Snapped point. */ @@ -146,28 +146,28 @@ Inkscape::SnappedPoint SnapManager::freeSnap(Inkscape::SnapPreferences::PointTyp if (!someSnapperMightSnap()) { return Inkscape::SnappedPoint(p, Inkscape::SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false); } - + std::vector *items_to_ignore; - if (_item_to_ignore) { // If we have only a single item to ignore - // then build a list containing this single item; + if (_item_to_ignore) { // If we have only a single item to ignore + // then build a list containing this single item; // This single-item list will prevail over any other _items_to_ignore list, should that exist items_to_ignore = new std::vector; items_to_ignore->push_back(_item_to_ignore); } else { items_to_ignore = _items_to_ignore; } - + SnappedConstraints sc; SnapperList const snappers = getSnappers(); - + for (SnapperList::const_iterator i = snappers.begin(); i != snappers.end(); i++) { (*i)->freeSnap(sc, point_type, p, first_point, bbox_to_snap, items_to_ignore, _unselected_nodes); } - + if (_item_to_ignore) { - delete items_to_ignore; + delete items_to_ignore; } - + return findBestSnap(p, sc, false); } @@ -179,51 +179,51 @@ Inkscape::SnappedPoint SnapManager::freeSnap(Inkscape::SnapPreferences::PointTyp // PS: Wether we really find a multiple also depends on the snapping range! Geom::Point SnapManager::multipleOfGridPitch(Geom::Point const &t) const { - if (!snapprefs.getSnapEnabledGlobally()) // No need to check for snapprefs.getSnapPostponedGlobally() here + if (!snapprefs.getSnapEnabledGlobally()) // No need to check for snapprefs.getSnapPostponedGlobally() here return t; - + //FIXME: this code should actually do this: add new grid snappers that are active for this desktop. now it just adds all gridsnappers SPDesktop* desktop = SP_ACTIVE_DESKTOP; - + if (desktop && desktop->gridsEnabled()) { bool success = false; - Geom::Point nearest_multiple; + Geom::Point nearest_multiple; Geom::Coord nearest_distance = NR_HUGE; - + // It will snap to the grid for which we find the closest snap. This might be a different - // grid than to which the objects were initially aligned. I don't see an easy way to fix - // this, so when using multiple grids one can get unexpected results - + // grid than to which the objects were initially aligned. I don't see an easy way to fix + // this, so when using multiple grids one can get unexpected results + // Cannot use getGridSnappers() because we need both the grids AND their snappers - // Therefor we iterate through all grids manually + // Therefor we iterate through all grids manually for (GSList const *l = _named_view->grids; l != NULL; l = l->next) { Inkscape::CanvasGrid *grid = (Inkscape::CanvasGrid*) l->data; - const Inkscape::Snapper* snapper = grid->snapper; + const Inkscape::Snapper* snapper = grid->snapper; if (snapper && snapper->ThisSnapperMightSnap()) { - // To find the nearest multiple of the grid pitch for a given translation t, we + // To find the nearest multiple of the grid pitch for a given translation t, we // will use the grid snapper. Simply snapping the value t to the grid will do, but // only if the origin of the grid is at (0,0). If it's not then compensate for this // in the translation t Geom::Point const t_offset = from_2geom(t) + grid->origin; - SnappedConstraints sc; + SnappedConstraints sc; // Only the first three parameters are being used for grid snappers snapper->freeSnap(sc, Inkscape::SnapPreferences::SNAPPOINT_NODE, t_offset, TRUE, Geom::OptRect(), NULL, NULL); // Find the best snap for this grid, including intersections of the grid-lines Inkscape::SnappedPoint s = findBestSnap(t_offset, sc, false); - if (s.getSnapped() && (s.getSnapDistance() < nearest_distance)) { - // use getSnapDistance() instead of getWeightedDistance() here because the pointer's position - // doesn't tell us anything about which node to snap - success = true; + if (s.getSnapped() && (s.getSnapDistance() < nearest_distance)) { + // use getSnapDistance() instead of getWeightedDistance() here because the pointer's position + // doesn't tell us anything about which node to snap + success = true; nearest_multiple = s.getPoint() - to_2geom(grid->origin); nearest_distance = s.getSnapDistance(); } } } - - if (success) + + if (success) return nearest_multiple; } - + return t; } @@ -233,8 +233,8 @@ Geom::Point SnapManager::multipleOfGridPitch(Geom::Point const &t) const * * \param point_type 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 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 constraint Constraint line. * \return Snapped point. */ @@ -245,7 +245,7 @@ void SnapManager::constrainedSnapReturnByRef(Inkscape::SnapPreferences::PointTyp bool first_point, Geom::OptRect const &bbox_to_snap) const { - Inkscape::SnappedPoint const s = constrainedSnap(point_type, p, constraint, first_point, bbox_to_snap); + Inkscape::SnappedPoint const s = constrainedSnap(point_type, p, constraint, first_point, bbox_to_snap); s.getPoint(p); } @@ -255,8 +255,8 @@ void SnapManager::constrainedSnapReturnByRef(Inkscape::SnapPreferences::PointTyp * * \param point_type 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 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 constraint Constraint line. * \return Snapped point. */ @@ -270,41 +270,41 @@ Inkscape::SnappedPoint SnapManager::constrainedSnap(Inkscape::SnapPreferences::P if (!someSnapperMightSnap()) { return Inkscape::SnappedPoint(p, Inkscape::SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false); } - + std::vector *items_to_ignore; - if (_item_to_ignore) { // If we have only a single item to ignore - // then build a list containing this single item; + if (_item_to_ignore) { // If we have only a single item to ignore + // then build a list containing this single item; // This single-item list will prevail over any other _items_to_ignore list, should that exist items_to_ignore = new std::vector; items_to_ignore->push_back(_item_to_ignore); } else { items_to_ignore = _items_to_ignore; } - - SnappedConstraints sc; + + SnappedConstraints sc; SnapperList const snappers = getSnappers(); for (SnapperList::const_iterator i = snappers.begin(); i != snappers.end(); i++) { (*i)->constrainedSnap(sc, point_type, p, first_point, bbox_to_snap, constraint, items_to_ignore); } - + if (_item_to_ignore) { - delete items_to_ignore; + delete items_to_ignore; } - + return findBestSnap(p, sc, true); } void SnapManager::guideSnap(Geom::Point &p, Geom::Point const &guide_normal) const { // This method is used to snap a guide to nodes, while dragging the guide around - + if ( !(object.GuidesMightSnap() && snapprefs.getSnapEnabledGlobally()) || snapprefs.getSnapPostponedGlobally() ) { - return; + return; } - + SnappedConstraints sc; object.guideSnap(sc, p, guide_normal); - + Inkscape::SnappedPoint const s = findBestSnap(p, sc, false); s.getPoint(p); } @@ -345,30 +345,30 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( */ /* Quick check to see if we have any snappers that are enabled - ** Also used to globally disable all snapping + ** Also used to globally disable all snapping */ if (someSnapperMightSnap() == false) { return Inkscape::SnappedPoint(); } - + std::vector transformed_points; Geom::Rect bbox; - + for (std::vector::const_iterator i = points.begin(); i != points.end(); i++) { /* Work out the transformed version of this point */ Geom::Point transformed = _transformPoint(*i, transformation_type, transformation, origin, dim, uniform); - + // add the current transformed point to the box hulling all transformed points if (i == points.begin()) { - bbox = Geom::Rect(transformed, transformed); + bbox = Geom::Rect(transformed, transformed); } else { bbox.expandTo(transformed); } - + transformed_points.push_back(transformed); - } - + } + /* The current best transformation */ Geom::Point best_transformation = transformation; @@ -384,17 +384,17 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( // std::cout << std::endl; for (std::vector::const_iterator i = points.begin(); i != points.end(); i++) { - - /* Snap it */ + + /* Snap it */ Inkscape::SnappedPoint snapped_point; Inkscape::Snapper::ConstraintLine dedicated_constraint = constraint; Geom::Point const b = (*i - origin); // vector to original point - - if (constrained) { + + if (constrained) { if ((transformation_type == SCALE || transformation_type == STRETCH) && uniform) { // When uniformly scaling, each point will have its own unique constraint line, // running from the scaling origin to the original untransformed point. We will - // calculate that line here + // calculate that line here dedicated_constraint = Inkscape::Snapper::ConstraintLine(origin, b); } else if (transformation_type == STRETCH) { // when non-uniform stretching { dedicated_constraint = Inkscape::Snapper::ConstraintLine((*i), component_vectors[dim]); @@ -402,24 +402,24 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( // When doing a constrained translation, all points will move in the same direction, i.e. // either horizontally or vertically. The lines along which they move are therefore all // parallel, but might not be colinear. Therefore we will have to set the point through - // which the constraint-line runs here, for each point individually. + // which the constraint-line runs here, for each point individually. dedicated_constraint.setPoint(*i); - } // else: leave the original constraint, e.g. for skewing + } // else: leave the original constraint, e.g. for skewing if (transformation_type == SCALE && !uniform) { - g_warning("Non-uniform constrained scaling is not supported!"); + g_warning("Non-uniform constrained scaling is not supported!"); } snapped_point = constrainedSnap(type, *j, dedicated_constraint, i == points.begin(), bbox); } else { bool const c1 = fabs(b[Geom::X]) < 1e-6; bool const c2 = fabs(b[Geom::Y]) < 1e-6; - if (transformation_type == SCALE && (c1 || c2) && !(c1 && c2)) { - // When scaling, a point aligned either horizontally or vertically with the origin can only - // move in that specific direction; therefore it should only snap in that direction, otherwise - // we will get snapped points with an invalid transformation - dedicated_constraint = Inkscape::Snapper::ConstraintLine(origin, component_vectors[c1]); - snapped_point = constrainedSnap(type, *j, dedicated_constraint, i == points.begin(), bbox); + if (transformation_type == SCALE && (c1 || c2) && !(c1 && c2)) { + // When scaling, a point aligned either horizontally or vertically with the origin can only + // move in that specific direction; therefore it should only snap in that direction, otherwise + // we will get snapped points with an invalid transformation + dedicated_constraint = Inkscape::Snapper::ConstraintLine(origin, component_vectors[c1]); + snapped_point = constrainedSnap(type, *j, dedicated_constraint, i == points.begin(), bbox); } else { - snapped_point = freeSnap(type, *j, i == points.begin(), bbox); + snapped_point = freeSnap(type, *j, i == points.begin(), bbox); } } // std::cout << "dist = " << snapped_point.getSnapDistance() << std::endl; @@ -427,25 +427,25 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( Geom::Point result; Geom::Point scale_metric(NR_HUGE, NR_HUGE); - + if (snapped_point.getSnapped()) { /* We snapped. Find the transformation that describes where the snapped point has ** ended up, and also the metric for this transformation. */ Geom::Point const a = (snapped_point.getPoint() - origin); // vector to snapped point //Geom::Point const b = (*i - origin); // vector to original point - + switch (transformation_type) { case TRANSLATION: result = snapped_point.getPoint() - *i; - /* Consider the case in which a box is almost aligned with a grid in both + /* 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 + * line. If we prefer snapping to an intersection instead of to a single * grid line, then we cannot use "metric = Geom::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! + * and not to the intersection itself! */ // Only for translations, the relevant metric will be the real snapped distance, // so we don't have to do anything special here @@ -454,7 +454,7 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( { result = Geom::Point(NR_HUGE, NR_HUGE); // If this point *i is horizontally or vertically aligned with - // the origin of the scaling, then it will scale purely in X or Y + // the origin of the scaling, then it will scale purely in X or Y // We can therefore only calculate the scaling in this direction // and the scaling factor for the other direction should remain // untouched (unless scaling is uniform ofcourse) @@ -490,13 +490,13 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( result[0] = (snapped_point.getPoint()[dim] - (*i)[dim]) / ((*i)[1 - dim] - origin[1 - dim]); // skew factor result[1] = transformation[1]; // scale factor // Store the metric for this transformation as a virtual distance - snapped_point.setSnapDistance(std::abs(result[0] - transformation[0])); + snapped_point.setSnapDistance(std::abs(result[0] - transformation[0])); snapped_point.setSecondSnapDistance(NR_HUGE); break; default: g_assert_not_reached(); } - + // When scaling, we're considering the best transformation in each direction separately. We will have a metric in each // direction, whereas for all other transformation we only a single one-dimensional metric. That's why we need to handle // the scaling metric differently @@ -507,7 +507,7 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( best_scale_metric[index] = fabs(scale_metric[index]); // When scaling, we're considering the best transformation in each direction separately // Therefore two different snapped points might together make a single best transformation - // We will however return only a single snapped point (e.g. to display the snapping indicator) + // We will however return only a single snapped point (e.g. to display the snapping indicator) best_snapped_point = snapped_point; // std::cout << "SEL "; } // else { std::cout << " ";} @@ -515,7 +515,7 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( if (uniform) { if (best_scale_metric[0] < best_scale_metric[1]) { best_transformation[1] = best_transformation[0]; - best_scale_metric[1] = best_scale_metric[0]; + best_scale_metric[1] = best_scale_metric[0]; } else { best_transformation[0] = best_transformation[1]; best_scale_metric[0] = best_scale_metric[1]; @@ -523,15 +523,15 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( } } else { // For all transformations other than scaling if (best_snapped_point.isOtherSnapBetter(snapped_point, true)) { - best_transformation = result; - best_snapped_point = snapped_point; + best_transformation = result; + best_snapped_point = snapped_point; } } } - + j++; } - + Geom::Coord best_metric; if (transformation_type == SCALE) { // When scaling, don't ever exit with one of scaling components set to NR_HUGE @@ -540,18 +540,18 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( if (uniform && best_transformation[1-index] < NR_HUGE) { best_transformation[index] = best_transformation[1-index]; } else { - best_transformation[index] = transformation[index]; + best_transformation[index] = transformation[index]; } } } best_metric = std::min(best_scale_metric[0], best_scale_metric[1]); } else { // For all transformations other than scaling - best_metric = best_snapped_point.getSnapDistance(); + best_metric = best_snapped_point.getSnapDistance(); } - + best_snapped_point.setTransformation(best_transformation); // Using " < 1e6" instead of " < NR_HUGE" for catching some rounding errors - // These rounding errors might be caused by NRRects, see bug #1584301 + // These rounding errors might be caused by NRRects, see bug #1584301 best_snapped_point.setSnapDistance(best_metric < 1e6 ? best_metric : NR_HUGE); return best_snapped_point; } @@ -572,11 +572,11 @@ Inkscape::SnappedPoint SnapManager::freeSnapTranslation(Inkscape::SnapPreference Geom::Point const &pointer, Geom::Point const &tr) const { - if (p.size() == 1) { - _displaySnapsource(point_type, _transformPoint(p.at(0), TRANSLATION, tr, Geom::Point(0,0), Geom::X, false)); - } - - return _snapTransformed(point_type, p, pointer, false, Geom::Point(0,0), TRANSLATION, tr, Geom::Point(0,0), Geom::X, false); + if (p.size() == 1) { + _displaySnapsource(point_type, _transformPoint(p.at(0), TRANSLATION, tr, Geom::Point(0,0), Geom::X, false)); + } + + return _snapTransformed(point_type, p, pointer, false, Geom::Point(0,0), TRANSLATION, tr, Geom::Point(0,0), Geom::X, false); } @@ -598,11 +598,11 @@ Inkscape::SnappedPoint SnapManager::constrainedSnapTranslation(Inkscape::SnapPre Inkscape::Snapper::ConstraintLine const &constraint, Geom::Point const &tr) const { - if (p.size() == 1) { - _displaySnapsource(point_type, _transformPoint(p.at(0), TRANSLATION, tr, Geom::Point(0,0), Geom::X, false)); - } - - return _snapTransformed(point_type, p, pointer, true, constraint, TRANSLATION, tr, Geom::Point(0,0), Geom::X, false); + if (p.size() == 1) { + _displaySnapsource(point_type, _transformPoint(p.at(0), TRANSLATION, tr, Geom::Point(0,0), Geom::X, false)); + } + + return _snapTransformed(point_type, p, pointer, true, constraint, TRANSLATION, tr, Geom::Point(0,0), Geom::X, false); } @@ -623,11 +623,11 @@ Inkscape::SnappedPoint SnapManager::freeSnapScale(Inkscape::SnapPreferences::Poi Geom::Scale const &s, Geom::Point const &o) const { - if (p.size() == 1) { - _displaySnapsource(point_type, _transformPoint(p.at(0), SCALE, Geom::Point(s[Geom::X], s[Geom::Y]), o, Geom::X, false)); - } - - return _snapTransformed(point_type, p, pointer, false, Geom::Point(0,0), SCALE, Geom::Point(s[Geom::X], s[Geom::Y]), o, Geom::X, false); + if (p.size() == 1) { + _displaySnapsource(point_type, _transformPoint(p.at(0), SCALE, Geom::Point(s[Geom::X], s[Geom::Y]), o, Geom::X, false)); + } + + return _snapTransformed(point_type, p, pointer, false, Geom::Point(0,0), SCALE, Geom::Point(s[Geom::X], s[Geom::Y]), o, Geom::X, false); } @@ -650,11 +650,11 @@ Inkscape::SnappedPoint SnapManager::constrainedSnapScale(Inkscape::SnapPreferenc Geom::Point const &o) const { // When constrained scaling, only uniform scaling is supported. - if (p.size() == 1) { - _displaySnapsource(point_type, _transformPoint(p.at(0), SCALE, Geom::Point(s[Geom::X], s[Geom::Y]), o, Geom::X, true)); - } - - return _snapTransformed(point_type, p, pointer, true, Geom::Point(0,0), SCALE, Geom::Point(s[Geom::X], s[Geom::Y]), o, Geom::X, true); + if (p.size() == 1) { + _displaySnapsource(point_type, _transformPoint(p.at(0), SCALE, Geom::Point(s[Geom::X], s[Geom::Y]), o, Geom::X, true)); + } + + return _snapTransformed(point_type, p, pointer, true, Geom::Point(0,0), SCALE, Geom::Point(s[Geom::X], s[Geom::Y]), o, Geom::X, true); } @@ -679,11 +679,11 @@ Inkscape::SnappedPoint SnapManager::constrainedSnapStretch(Inkscape::SnapPrefere Geom::Dim2 d, bool u) const { - if (p.size() == 1) { - _displaySnapsource(point_type, _transformPoint(p.at(0), STRETCH, Geom::Point(s, s), o, d, u)); - } - - return _snapTransformed(point_type, p, pointer, true, Geom::Point(0,0), STRETCH, Geom::Point(s, s), o, d, u); + if (p.size() == 1) { + _displaySnapsource(point_type, _transformPoint(p.at(0), STRETCH, Geom::Point(s, s), o, d, u)); + } + + return _snapTransformed(point_type, p, pointer, true, Geom::Point(0,0), STRETCH, Geom::Point(s, s), o, d, u); } @@ -703,29 +703,29 @@ Inkscape::SnappedPoint SnapManager::constrainedSnapSkew(Inkscape::SnapPreference std::vector const &p, Geom::Point const &pointer, Inkscape::Snapper::ConstraintLine const &constraint, - Geom::Point const &s, + Geom::Point const &s, Geom::Point const &o, Geom::Dim2 d) const { - // "s" contains skew factor in s[0], and scale factor in s[1] - - // Snapping the nodes of the boundingbox of a selection that is being transformed, will only work if - // the transformation of the bounding box is equal to the transformation of the individual nodes. This is - // NOT the case for example when rotating or skewing. The bounding box itself cannot possibly rotate or skew, - // so it's corners have a different transformation. The snappers cannot handle this, therefore snapping - // of bounding boxes is not allowed here. - g_assert(!(point_type & Inkscape::SnapPreferences::SNAPPOINT_BBOX)); - - if (p.size() == 1) { - _displaySnapsource(point_type, _transformPoint(p.at(0), SKEW, s, o, d, false)); - } - - return _snapTransformed(point_type, p, pointer, true, constraint, SKEW, s, o, d, false); + // "s" contains skew factor in s[0], and scale factor in s[1] + + // Snapping the nodes of the boundingbox of a selection that is being transformed, will only work if + // the transformation of the bounding box is equal to the transformation of the individual nodes. This is + // NOT the case for example when rotating or skewing. The bounding box itself cannot possibly rotate or skew, + // so it's corners have a different transformation. The snappers cannot handle this, therefore snapping + // of bounding boxes is not allowed here. + g_assert(!(point_type & Inkscape::SnapPreferences::SNAPPOINT_BBOX)); + + if (p.size() == 1) { + _displaySnapsource(point_type, _transformPoint(p.at(0), SKEW, s, o, d, false)); + } + + return _snapTransformed(point_type, p, pointer, true, constraint, SKEW, s, o, d, false); } Inkscape::SnappedPoint SnapManager::findBestSnap(Geom::Point const &p, SnappedConstraints &sc, bool constrained) const { - + /* std::cout << "Type and number of snapped constraints: " << std::endl; std::cout << " Points : " << sc.points.size() << std::endl; @@ -734,47 +734,47 @@ Inkscape::SnappedPoint SnapManager::findBestSnap(Geom::Point const &p, SnappedCo std::cout << " Guide lines : " << sc.guide_lines.size()<< std::endl; std::cout << " Curves : " << sc.curves.size()<< std::endl; */ - + // Store all snappoints std::list sp_list; - + // search for the closest snapped point Inkscape::SnappedPoint closestPoint; if (getClosestSP(sc.points, closestPoint)) { sp_list.push_back(closestPoint); - } - + } + // search for the closest snapped curve Inkscape::SnappedCurve closestCurve; - if (getClosestCurve(sc.curves, closestCurve)) { + if (getClosestCurve(sc.curves, closestCurve)) { sp_list.push_back(Inkscape::SnappedPoint(closestCurve)); } - + if (snapprefs.getSnapIntersectionCS()) { // search for the closest snapped intersection of curves Inkscape::SnappedPoint closestCurvesIntersection; if (getClosestIntersectionCS(sc.curves, p, closestCurvesIntersection)) { sp_list.push_back(closestCurvesIntersection); } - } + } // search for the closest snapped grid line Inkscape::SnappedLine closestGridLine; - if (getClosestSL(sc.grid_lines, closestGridLine)) { + if (getClosestSL(sc.grid_lines, closestGridLine)) { closestGridLine.setTarget(Inkscape::SNAPTARGET_GRID); sp_list.push_back(Inkscape::SnappedPoint(closestGridLine)); } - + // search for the closest snapped guide line Inkscape::SnappedLine closestGuideLine; if (getClosestSL(sc.guide_lines, closestGuideLine)) { closestGuideLine.setTarget(Inkscape::SNAPTARGET_GUIDE); sp_list.push_back(Inkscape::SnappedPoint(closestGuideLine)); } - + // When freely snapping to a grid/guide/path, only one degree of freedom is eliminated - // Therefore we will try get fully constrained by finding an intersection with another grid/guide/path - + // Therefore we will try get fully constrained by finding an intersection with another grid/guide/path + // When doing a constrained snap however, we're already at an intersection of the constrained line and // the grid/guide/path we're snapping to. This snappoint is therefore fully constrained, so there's // no need to look for additional intersections @@ -785,14 +785,14 @@ Inkscape::SnappedPoint SnapManager::findBestSnap(Geom::Point const &p, SnappedCo closestGridPoint.setTarget(Inkscape::SNAPTARGET_GRID_INTERSECTION); sp_list.push_back(closestGridPoint); } - + // search for the closest snapped intersection of guide lines Inkscape::SnappedPoint closestGuidePoint; if (getClosestIntersectionSL(sc.guide_lines, closestGuidePoint)) { closestGuidePoint.setTarget(Inkscape::SNAPTARGET_GUIDE_INTERSECTION); sp_list.push_back(closestGuidePoint); } - + // search for the closest snapped intersection of grid with guide lines if (snapprefs.getSnapIntersectionGG()) { Inkscape::SnappedPoint closestGridGuidePoint; @@ -802,23 +802,23 @@ Inkscape::SnappedPoint SnapManager::findBestSnap(Geom::Point const &p, SnappedCo } } } - + // now let's see which snapped point gets a thumbs up Inkscape::SnappedPoint bestSnappedPoint = Inkscape::SnappedPoint(p, Inkscape::SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false); // std::cout << "Finding the best snap..." << std::endl; for (std::list::const_iterator i = sp_list.begin(); i != sp_list.end(); i++) { // first find out if this snapped point is within snapping range - // std::cout << "sp = " << from_2geom((*i).getPoint()); + // std::cout << "sp = " << from_2geom((*i).getPoint()); if ((*i).getSnapDistance() <= (*i).getTolerance()) { // if it's the first point, or if it is closer than the best snapped point so far - if (i == sp_list.begin() || bestSnappedPoint.isOtherSnapBetter(*i, false)) { + if (i == sp_list.begin() || bestSnappedPoint.isOtherSnapBetter(*i, false)) { // then prefer this point over the previous one bestSnappedPoint = *i; } } // std::cout << std::endl; - } - + } + // Update the snap indicator, if requested if (_snapindicator) { if (bestSnappedPoint.getSnapped()) { @@ -827,9 +827,9 @@ Inkscape::SnappedPoint SnapManager::findBestSnap(Geom::Point const &p, SnappedCo _desktop->snapindicator->remove_snaptarget(); } } - + // std::cout << "findBestSnap = " << bestSnappedPoint.getPoint() << " | dist = " << bestSnappedPoint.getSnapDistance() << std::endl; - return bestSnappedPoint; + return bestSnappedPoint; } void SnapManager::setup(SPDesktop const *desktop, bool snapindicator, SPItem const *item_to_ignore, std::vector *unselected_nodes) @@ -849,7 +849,7 @@ void SnapManager::setup(SPDesktop const *desktop, bool snapindicator, std::vecto _items_to_ignore = &items_to_ignore; _desktop = desktop; _snapindicator = snapindicator; - _unselected_nodes = unselected_nodes; + _unselected_nodes = unselected_nodes; } SPDocument *SnapManager::getDocument() const @@ -857,14 +857,14 @@ SPDocument *SnapManager::getDocument() const return _named_view->document; } -Geom::Point SnapManager::_transformPoint(Geom::Point const &p, - Transformation const transformation_type, - Geom::Point const &transformation, - Geom::Point const &origin, - Geom::Dim2 const dim, - bool const uniform) const +Geom::Point SnapManager::_transformPoint(Geom::Point const &p, + Transformation const transformation_type, + Geom::Point const &transformation, + Geom::Point const &origin, + Geom::Dim2 const dim, + bool const uniform) const { - /* Work out the transformed version of this point */ + /* Work out the transformed version of this point */ Geom::Point transformed; switch (transformation_type) { case TRANSLATION: @@ -895,22 +895,22 @@ Geom::Point SnapManager::_transformPoint(Geom::Point const &p, default: g_assert_not_reached(); } - + return transformed; } void SnapManager::_displaySnapsource(Inkscape::SnapPreferences::PointType point_type, Geom::Point const &p) const { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if (prefs->getBool("/options/snapclosestonly/value")) { - bool p_is_a_node = point_type & Inkscape::SnapPreferences::SNAPPOINT_NODE; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (prefs->getBool("/options/snapclosestonly/value")) { + bool p_is_a_node = point_type & Inkscape::SnapPreferences::SNAPPOINT_NODE; bool p_is_a_bbox = point_type & Inkscape::SnapPreferences::SNAPPOINT_BBOX; - if ((p_is_a_node && snapprefs.getSnapModeNode()) || (p_is_a_bbox && snapprefs.getSnapModeBBox())) { - _desktop->snapindicator->set_new_snapsource(p); - } else { - _desktop->snapindicator->remove_snapsource(); - } - } + if ((p_is_a_node && snapprefs.getSnapModeNode()) || (p_is_a_bbox && snapprefs.getSnapModeBBox())) { + _desktop->snapindicator->set_new_snapsource(p); + } else { + _desktop->snapindicator->remove_snapsource(); + } + } } /* diff --git a/src/snapped-curve.cpp b/src/snapped-curve.cpp index b566bfe34..7b65c5c65 100644 --- a/src/snapped-curve.cpp +++ b/src/snapped-curve.cpp @@ -20,7 +20,7 @@ Inkscape::SnappedCurve::SnappedCurve(Geom::Point const &snapped_point, Geom::Coord const &snapped_distance, Geom::Coord const &snapped_tolerance, bool const &always_snap, bool const &fully_constrained, Geom::Curve const *curve) { - _distance = snapped_distance; + _distance = snapped_distance; _tolerance = std::max(snapped_tolerance, 1.0); _always_snap = always_snap; _curve = curve; @@ -32,7 +32,7 @@ Inkscape::SnappedCurve::SnappedCurve(Geom::Point const &snapped_point, Geom::Coo _fully_constrained = fully_constrained; } -Inkscape::SnappedCurve::SnappedCurve() +Inkscape::SnappedCurve::SnappedCurve() { _distance = NR_HUGE; _tolerance = 1; @@ -50,7 +50,7 @@ Inkscape::SnappedCurve::~SnappedCurve() { } -Inkscape::SnappedPoint Inkscape::SnappedCurve::intersect(SnappedCurve const &curve, Geom::Point const &p) const +Inkscape::SnappedPoint Inkscape::SnappedCurve::intersect(SnappedCurve const &curve, Geom::Point const &p) const { // Calculate the intersections of two curves, which are both within snapping range, and // return only the closest intersection @@ -58,7 +58,7 @@ Inkscape::SnappedPoint Inkscape::SnappedCurve::intersect(SnappedCurve const &cur // PS: We need p (the location of the mouse pointer) for find out which intersection is the // closest, as there might be multiple intersections of two curves Geom::Crossings cs = crossings(*(this->_curve), *(curve._curve)); - + if (cs.size() > 0) { // There might be multiple intersections: find the closest Geom::Coord best_dist = NR_HUGE; @@ -71,8 +71,8 @@ Inkscape::SnappedPoint Inkscape::SnappedCurve::intersect(SnappedCurve const &cur best_p = p_ix; } } - - // Now we've found the closests intersection, return it as a SnappedPoint + + // Now we've found the closest intersection, return it as a SnappedPoint bool const use_this_as_primary = _distance < curve.getSnapDistance(); Inkscape::SnappedCurve const *primaryC = use_this_as_primary ? this : &curve; Inkscape::SnappedCurve const *secondaryC = use_this_as_primary ? &curve : this; @@ -80,37 +80,40 @@ Inkscape::SnappedPoint Inkscape::SnappedCurve::intersect(SnappedCurve const &cur // we need a desktop: this is a dirty hack SPDesktop const *desktop = SP_ACTIVE_DESKTOP; best_p = desktop->dt2doc(best_p); + + Geom::Coord primaryDist = use_this_as_primary ? Geom::L2(best_p - this->getPoint()) : Geom::L2(best_p - curve.getPoint()); + Geom::Coord secondaryDist = use_this_as_primary ? Geom::L2(best_p - curve.getPoint()) : Geom::L2(best_p - this->getPoint()); // TODO: Investigate whether it is possible to use document coordinates everywhere // in the snapper code. Only the mouse position should be in desktop coordinates, I guess. // All paths are already in document coords and we are certainly not going to change THAT. - return SnappedPoint(from_2geom(best_p), Inkscape::SNAPTARGET_PATH_INTERSECTION, primaryC->getSnapDistance(), primaryC->getTolerance(), primaryC->getAlwaysSnap(), true, true, - secondaryC->getSnapDistance(), secondaryC->getTolerance(), secondaryC->getAlwaysSnap()); + return SnappedPoint(from_2geom(best_p), Inkscape::SNAPTARGET_PATH_INTERSECTION, primaryDist, primaryC->getTolerance(), primaryC->getAlwaysSnap(), true, true, + secondaryDist, secondaryC->getTolerance(), secondaryC->getAlwaysSnap()); } - + // No intersection return SnappedPoint(Geom::Point(NR_HUGE, NR_HUGE), SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, false, NR_HUGE, 0, false); } // search for the closest snapped line -bool getClosestCurve(std::list const &list, Inkscape::SnappedCurve &result) +bool getClosestCurve(std::list const &list, Inkscape::SnappedCurve &result) { bool success = false; - + for (std::list::const_iterator i = list.begin(); i != list.end(); i++) { if ((i == list.begin()) || (*i).getSnapDistance() < result.getSnapDistance()) { result = *i; success = true; - } + } } - - return success; + + return success; } // search for the closest intersection of two snapped curves, which are both member of the same collection bool getClosestIntersectionCS(std::list const &list, Geom::Point const &p, Inkscape::SnappedPoint &result) { bool success = false; - + for (std::list::const_iterator i = list.begin(); i != list.end(); i++) { std::list::const_iterator j = i; j++; @@ -119,21 +122,21 @@ bool getClosestIntersectionCS(std::list const &list, Geo if (sp.getAtIntersection()) { // if it's the first point bool const c1 = !success; - // or, if it's closer + // or, if it's closer bool const c2 = sp.getSnapDistance() < result.getSnapDistance(); - // or, if it's just as close then look at the other distance + // or, if it's just as close then look at the other distance // (only relevant for snapped points which are at an intersection) - bool const c3 = (sp.getSnapDistance() == result.getSnapDistance()) && (sp.getSecondSnapDistance() < result.getSecondSnapDistance()); + bool const c3 = (sp.getSnapDistance() == result.getSnapDistance()) && (sp.getSecondSnapDistance() < result.getSecondSnapDistance()); // then prefer this point over the previous one - if (c1 || c2 || c3) { + if (c1 || c2 || c3) { result = sp; success = true; } - } + } } } - - return success; + + return success; } /* Local Variables: diff --git a/src/snapped-line.cpp b/src/snapped-line.cpp index 48fc82051..5f7d5407b 100644 --- a/src/snapped-line.cpp +++ b/src/snapped-line.cpp @@ -13,28 +13,28 @@ #include "libnr/nr-values.h" Inkscape::SnappedLineSegment::SnappedLineSegment(Geom::Point const &snapped_point, Geom::Coord const &snapped_distance, Geom::Coord const &snapped_tolerance, bool const &always_snap, Geom::Point const &start_point_of_line, Geom::Point const &end_point_of_line) - : _start_point_of_line(start_point_of_line), _end_point_of_line(end_point_of_line) + : _start_point_of_line(start_point_of_line), _end_point_of_line(end_point_of_line) { - _point = snapped_point; + _point = snapped_point; _distance = snapped_distance; - _tolerance = std::max(snapped_tolerance, 1.0); + _tolerance = std::max(snapped_tolerance, 1.0); _always_snap = always_snap; - _at_intersection = false; - _second_distance = NR_HUGE; + _at_intersection = false; + _second_distance = NR_HUGE; _second_tolerance = 1; _second_always_snap = false; } -Inkscape::SnappedLineSegment::SnappedLineSegment() +Inkscape::SnappedLineSegment::SnappedLineSegment() { - _start_point_of_line = Geom::Point(0,0); - _end_point_of_line = Geom::Point(0,0); - _point = Geom::Point(0,0); + _start_point_of_line = Geom::Point(0,0); + _end_point_of_line = Geom::Point(0,0); + _point = Geom::Point(0,0); _distance = NR_HUGE; - _tolerance = 1; + _tolerance = 1; _always_snap = false; - _at_intersection = false; - _second_distance = NR_HUGE; + _at_intersection = false; + _second_distance = NR_HUGE; _second_tolerance = 1; _second_always_snap = false; } @@ -44,33 +44,35 @@ Inkscape::SnappedLineSegment::~SnappedLineSegment() { } -Inkscape::SnappedPoint Inkscape::SnappedLineSegment::intersect(SnappedLineSegment const &line) const +Inkscape::SnappedPoint Inkscape::SnappedLineSegment::intersect(SnappedLineSegment const &line) const { - Geom::Point intersection_2geom(NR_HUGE, NR_HUGE); - Geom::IntersectorKind result = segment_intersect(_start_point_of_line, _end_point_of_line, - line._start_point_of_line, line._end_point_of_line, - intersection_2geom); - Geom::Point intersection(intersection_2geom); - - if (result == Geom::intersects) { - /* If a snapper has been told to "always snap", then this one should be preferred + Geom::Point intersection_2geom(NR_HUGE, NR_HUGE); + Geom::IntersectorKind result = segment_intersect(_start_point_of_line, _end_point_of_line, + line._start_point_of_line, line._end_point_of_line, + intersection_2geom); + Geom::Point intersection(intersection_2geom); + + if (result == Geom::intersects) { + /* If a snapper has been told to "always snap", then this one should be preferred * over the other, if that other one has not been told so. (The preferred snapper * will be labelled "primary" below) */ bool const c1 = this->getAlwaysSnap() && !line.getAlwaysSnap(); //do not use _tolerance directly! /* If neither or both have been told to "always snap", then cast a vote based on * the snapped distance. For this we should consider the distance to the snapped - * line, not the distance to the intersection. + * line, not the distance to the intersection. * See the comment in Inkscape::SnappedLine::intersect - */ + */ bool const c2 = _distance < line.getSnapDistance(); bool const use_this_as_primary = c1 || c2; Inkscape::SnappedLineSegment const *primarySLS = use_this_as_primary ? this : &line; Inkscape::SnappedLineSegment const *secondarySLS = use_this_as_primary ? &line : this; - return SnappedPoint(intersection, SNAPTARGET_PATH_INTERSECTION, primarySLS->getSnapDistance(), primarySLS->getTolerance(), primarySLS->getAlwaysSnap(), true, true, - secondarySLS->getSnapDistance(), secondarySLS->getTolerance(), secondarySLS->getAlwaysSnap()); - } - + Geom::Coord primaryDist = use_this_as_primary ? Geom::L2(intersection_2geom - this->getPoint()) : Geom::L2(intersection_2geom - line.getPoint()); + Geom::Coord secondaryDist = use_this_as_primary ? Geom::L2(intersection_2geom - line.getPoint()) : Geom::L2(intersection_2geom - this->getPoint()); + return SnappedPoint(intersection, SNAPTARGET_PATH_INTERSECTION, primaryDist, primarySLS->getTolerance(), primarySLS->getAlwaysSnap(), true, true, + secondaryDist, secondarySLS->getTolerance(), secondarySLS->getAlwaysSnap()); + } + // No intersection return SnappedPoint(intersection, SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, false, NR_HUGE, 0, false); }; @@ -80,46 +82,46 @@ Inkscape::SnappedPoint Inkscape::SnappedLineSegment::intersect(SnappedLineSegmen Inkscape::SnappedLine::SnappedLine(Geom::Point const &snapped_point, Geom::Coord const &snapped_distance, Geom::Coord const &snapped_tolerance, bool const &always_snap, Geom::Point const &normal_to_line, Geom::Point const &point_on_line) : _normal_to_line(normal_to_line), _point_on_line(point_on_line) { - _distance = snapped_distance; + _distance = snapped_distance; _tolerance = std::max(snapped_tolerance, 1.0); _always_snap = always_snap; - _second_distance = NR_HUGE; + _second_distance = NR_HUGE; _second_tolerance = 1; _second_always_snap = false; - _point = snapped_point; - _at_intersection = false; + _point = snapped_point; + _at_intersection = false; } -Inkscape::SnappedLine::SnappedLine() +Inkscape::SnappedLine::SnappedLine() { - _normal_to_line = Geom::Point(0,0); - _point_on_line = Geom::Point(0,0); - _distance = NR_HUGE; + _normal_to_line = Geom::Point(0,0); + _point_on_line = Geom::Point(0,0); + _distance = NR_HUGE; _tolerance = 1; _always_snap = false; - _second_distance = NR_HUGE; + _second_distance = NR_HUGE; _second_tolerance = 1; _second_always_snap = false; - _point = Geom::Point(0,0); - _at_intersection = false; + _point = Geom::Point(0,0); + _at_intersection = false; } Inkscape::SnappedLine::~SnappedLine() { } -Inkscape::SnappedPoint Inkscape::SnappedLine::intersect(SnappedLine const &line) const +Inkscape::SnappedPoint Inkscape::SnappedLine::intersect(SnappedLine const &line) const { - // Calculate the intersection of two lines, which are both within snapping range + // Calculate the intersection of two lines, which are both within snapping range // One could be a grid line, whereas the other could be a guide line - // The point of intersection should be considered for snapping, but might be outside the snapping range - - Geom::Point intersection_2geom(NR_HUGE, NR_HUGE); - Geom::IntersectorKind result = Geom::line_intersection(getNormal(), getConstTerm(), + // The point of intersection should be considered for snapping, but might be outside the snapping range + + Geom::Point intersection_2geom(NR_HUGE, NR_HUGE); + Geom::IntersectorKind result = Geom::line_intersection(getNormal(), getConstTerm(), line.getNormal(), line.getConstTerm(), intersection_2geom); - Geom::Point intersection(intersection_2geom); - - if (result == Geom::intersects) { + Geom::Point intersection(intersection_2geom); + + if (result == Geom::intersects) { /* If a snapper has been told to "always snap", then this one should be preferred * over the other, if that other one has not been told so. (The preferred snapper * will be labelled "primary" below) @@ -127,147 +129,140 @@ Inkscape::SnappedPoint Inkscape::SnappedLine::intersect(SnappedLine const &line) bool const c1 = this->getAlwaysSnap() && !line.getAlwaysSnap(); /* If neither or both have been told to "always snap", then cast a vote based on * the snapped distance. For this we should consider the distance to the snapped - * line, not the distance to the intersection. - * - * The relevant snapped distance is the distance to the closest snapped line, not the - * distance to the intersection. For example, when 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 grid line. We will be snapping - * to the closest snapped point however, so if we ever want to snap to the intersection - * then the distance to it should at least be equal to the other distance, not greater - * than it, as that would rule the intersection out when comparing it with regular snappoint, - * as the latter will always be closer - */ + * line or to the intersection + */ bool const c2 = _distance < line.getSnapDistance(); bool const use_this_as_primary = c1 || c2; Inkscape::SnappedLine const *primarySL = use_this_as_primary ? this : &line; Inkscape::SnappedLine const *secondarySL = use_this_as_primary ? &line : this; - return SnappedPoint(intersection, Inkscape::SNAPTARGET_UNDEFINED, primarySL->getSnapDistance(), primarySL->getTolerance(), primarySL->getAlwaysSnap(), true, true, - secondarySL->getSnapDistance(), secondarySL->getTolerance(), secondarySL->getAlwaysSnap()); - // The type of the snap target is yet undefined, as we cannot tell whether - // we're snapping to grid or the guide lines; must be set by on a higher level + Geom::Coord primaryDist = use_this_as_primary ? Geom::L2(intersection_2geom - this->getPoint()) : Geom::L2(intersection_2geom - line.getPoint()); + Geom::Coord secondaryDist = use_this_as_primary ? Geom::L2(intersection_2geom - line.getPoint()) : Geom::L2(intersection_2geom - this->getPoint()); + return SnappedPoint(intersection, Inkscape::SNAPTARGET_UNDEFINED, primaryDist, primarySL->getTolerance(), primarySL->getAlwaysSnap(), true, true, + secondaryDist, secondarySL->getTolerance(), secondarySL->getAlwaysSnap()); + // The type of the snap target is yet undefined, as we cannot tell whether + // we're snapping to grid or the guide lines; must be set by on a higher level } - + // No intersection return SnappedPoint(intersection, SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, false, NR_HUGE, 0, false); } // search for the closest snapped line segment -bool getClosestSLS(std::list const &list, Inkscape::SnappedLineSegment &result) +bool getClosestSLS(std::list const &list, Inkscape::SnappedLineSegment &result) { - bool success = false; - - for (std::list::const_iterator i = list.begin(); i != list.end(); i++) { - if ((i == list.begin()) || (*i).getSnapDistance() < result.getSnapDistance()) { - result = *i; - success = true; - } - } - - return success; + bool success = false; + + for (std::list::const_iterator i = list.begin(); i != list.end(); i++) { + if ((i == list.begin()) || (*i).getSnapDistance() < result.getSnapDistance()) { + result = *i; + success = true; + } + } + + return success; } // search for the closest intersection of two snapped line segments, which are both member of the same collection bool getClosestIntersectionSLS(std::list const &list, Inkscape::SnappedPoint &result) { - bool success = false; - - for (std::list::const_iterator i = list.begin(); i != list.end(); i++) { - std::list::const_iterator j = i; - j++; - for (; j != list.end(); j++) { - Inkscape::SnappedPoint sp = (*i).intersect(*j); - if (sp.getAtIntersection()) { - // if it's the first point - bool const c1 = !success; - // or, if it's closer - bool const c2 = sp.getSnapDistance() < result.getSnapDistance(); - // or, if it's just then look at the other distance - // (only relevant for snapped points which are at an intersection - bool const c3 = (sp.getSnapDistance() == result.getSnapDistance()) && (sp.getSecondSnapDistance() < result.getSecondSnapDistance()); - // then prefer this point over the previous one - if (c1 || c2 || c3) { - result = sp; - success = true; - } - } - } - } - - return success; + bool success = false; + + for (std::list::const_iterator i = list.begin(); i != list.end(); i++) { + std::list::const_iterator j = i; + j++; + for (; j != list.end(); j++) { + Inkscape::SnappedPoint sp = (*i).intersect(*j); + if (sp.getAtIntersection()) { + // if it's the first point + bool const c1 = !success; + // or, if it's closer + bool const c2 = sp.getSnapDistance() < result.getSnapDistance(); + // or, if it's just then look at the other distance + // (only relevant for snapped points which are at an intersection + bool const c3 = (sp.getSnapDistance() == result.getSnapDistance()) && (sp.getSecondSnapDistance() < result.getSecondSnapDistance()); + // then prefer this point over the previous one + if (c1 || c2 || c3) { + result = sp; + success = true; + } + } + } + } + + return success; } // search for the closest snapped line -bool getClosestSL(std::list const &list, Inkscape::SnappedLine &result) +bool getClosestSL(std::list const &list, Inkscape::SnappedLine &result) { - bool success = false; - - for (std::list::const_iterator i = list.begin(); i != list.end(); i++) { - if ((i == list.begin()) || (*i).getSnapDistance() < result.getSnapDistance()) { - result = *i; - success = true; - } - } - - return success; + bool success = false; + + for (std::list::const_iterator i = list.begin(); i != list.end(); i++) { + if ((i == list.begin()) || (*i).getSnapDistance() < result.getSnapDistance()) { + result = *i; + success = true; + } + } + + return success; } // search for the closest intersection of two snapped lines, which are both member of the same collection bool getClosestIntersectionSL(std::list const &list, Inkscape::SnappedPoint &result) { - bool success = false; - - for (std::list::const_iterator i = list.begin(); i != list.end(); i++) { - std::list::const_iterator j = i; - j++; - for (; j != list.end(); j++) { - Inkscape::SnappedPoint sp = (*i).intersect(*j); - if (sp.getAtIntersection()) { - // if it's the first point - bool const c1 = !success; - // or, if it's closer - bool const c2 = sp.getSnapDistance() < result.getSnapDistance(); - // or, if it's just then look at the other distance - // (only relevant for snapped points which are at an intersection - bool const c3 = (sp.getSnapDistance() == result.getSnapDistance()) && (sp.getSecondSnapDistance() < result.getSecondSnapDistance()); - // then prefer this point over the previous one - if (c1 || c2 || c3) { - result = sp; - success = true; - } - } - } - } - - return success; + bool success = false; + + for (std::list::const_iterator i = list.begin(); i != list.end(); i++) { + std::list::const_iterator j = i; + j++; + for (; j != list.end(); j++) { + Inkscape::SnappedPoint sp = (*i).intersect(*j); + if (sp.getAtIntersection()) { + // if it's the first point + bool const c1 = !success; + // or, if it's closer + bool const c2 = sp.getSnapDistance() < result.getSnapDistance(); + // or, if it's just then look at the other distance + // (only relevant for snapped points which are at an intersection + bool const c3 = (sp.getSnapDistance() == result.getSnapDistance()) && (sp.getSecondSnapDistance() < result.getSecondSnapDistance()); + // then prefer this point over the previous one + if (c1 || c2 || c3) { + result = sp; + success = true; + } + } + } + } + + return success; } // search for the closest intersection of two snapped lines, which are in two different collections bool getClosestIntersectionSL(std::list const &list1, std::list const &list2, Inkscape::SnappedPoint &result) { - bool success = false; - - for (std::list::const_iterator i = list1.begin(); i != list1.end(); i++) { - for (std::list::const_iterator j = list2.begin(); j != list2.end(); j++) { - Inkscape::SnappedPoint sp = (*i).intersect(*j); - if (sp.getAtIntersection()) { - // if it's the first point - bool const c1 = !success; - // or, if it's closer - bool const c2 = sp.getSnapDistance() < result.getSnapDistance(); - // or, if it's just then look at the other distance - // (only relevant for snapped points which are at an intersection - bool const c3 = (sp.getSnapDistance() == result.getSnapDistance()) && (sp.getSecondSnapDistance() < result.getSecondSnapDistance()); - // then prefer this point over the previous one - if (c1 || c2 || c3) { - result = sp; - success = true; - } - } - } - } - - return success; + bool success = false; + + for (std::list::const_iterator i = list1.begin(); i != list1.end(); i++) { + for (std::list::const_iterator j = list2.begin(); j != list2.end(); j++) { + Inkscape::SnappedPoint sp = (*i).intersect(*j); + if (sp.getAtIntersection()) { + // if it's the first point + bool const c1 = !success; + // or, if it's closer + bool const c2 = sp.getSnapDistance() < result.getSnapDistance(); + // or, if it's just then look at the other distance + // (only relevant for snapped points which are at an intersection + bool const c3 = (sp.getSnapDistance() == result.getSnapDistance()) && (sp.getSecondSnapDistance() < result.getSecondSnapDistance()); + // then prefer this point over the previous one + if (c1 || c2 || c3) { + result = sp; + success = true; + } + } + } + } + + return success; } /* diff --git a/src/snapped-point.cpp b/src/snapped-point.cpp index c5eaba749..fc6e5e87f 100644 --- a/src/snapped-point.cpp +++ b/src/snapped-point.cpp @@ -17,7 +17,7 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &fully_constrained) : _point(p), _target(target), _distance(d), _tolerance(std::max(t,1.0)), _always_snap(a) { - // tolerance should never be smaller than 1 px, as it is used for normalization in isOtherSnapBetter. We don't want a division by zero. + // tolerance should never be smaller than 1 px, as it is used for normalization in isOtherSnapBetter. We don't want a division by zero. _fully_constrained = fully_constrained; _second_distance = NR_HUGE; _second_tolerance = 1; @@ -30,7 +30,7 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapTargetType const : _point(p), _target(target), _at_intersection(at_intersection), _fully_constrained(fully_constrained), _distance(d), _tolerance(std::max(t,1.0)), _always_snap(a), _second_distance(d2), _second_tolerance(std::max(t2,1.0)), _second_always_snap(a2) { - // tolerance should never be smaller than 1 px, as it is used for normalization in + // tolerance should never be smaller than 1 px, as it is used for normalization in // isOtherSnapBetter. We don't want a division by zero. _transformation = Geom::Point(1,1); _pointer_distance = NR_HUGE; @@ -39,7 +39,7 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapTargetType const Inkscape::SnappedPoint::SnappedPoint() { _point = Geom::Point(0,0); - _target = SNAPTARGET_UNDEFINED, + _target = SNAPTARGET_UNDEFINED, _distance = NR_HUGE; _tolerance = 1; _always_snap = false; @@ -58,7 +58,7 @@ Inkscape::SnappedPoint::~SnappedPoint() void Inkscape::SnappedPoint::getPoint(Geom::Point &p) const { // When we have snapped - if (getSnapped()) { + if (getSnapped()) { // then return the snapped point by overwriting p p = _point; } //otherwise p will be left untouched; this way the caller doesn't have to check wether we've snapped @@ -81,55 +81,54 @@ bool getClosestSP(std::list &list, Inkscape::SnappedPoin bool Inkscape::SnappedPoint::isOtherSnapBetter(Inkscape::SnappedPoint const &other_one, bool weighted) const { - - double dist_other = other_one.getSnapDistance(); - double dist_this = getSnapDistance(); - - // The distance to the pointer should only be taken into account when finding the best snapped source node (when + + double dist_other = other_one.getSnapDistance(); + double dist_this = getSnapDistance(); + + // The distance to the pointer should only be taken into account when finding the best snapped source node (when // there's more than one). It is not useful when trying to find the best snapped target point. // (both the snap distance and the pointer distance are measured in document pixels, not in screen pixels) if (weighted) { - // weigth factor: controls which node should be preferrerd for snapping, which is either - // the node with the closest snap (w = 0), or the node closest to the mousepointer (w = 1) - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - double w = prefs->getDoubleLimited("/options/snapweight/value", 0.5, 0, 1); - if (prefs->getBool("/options/snapclosestonly/value", false)) { - w = 1; - } - if (w > 0) { - // When accounting for the distance to the mouse pointer, then at least one of the snapped points should - // have that distance set. If not, then this is a bug. Either "weighted" must be set to false, or the - // mouse pointer distance must be set. - g_assert(getPointerDistance() != NR_HUGE || other_one.getPointerDistance() != NR_HUGE); - // The snap distance will always be smaller than the tolerance set for the snapper. The pointer distance can - // however be very large. To compare these in a fair way, we will have to normalize these metrics first - // The closest pointer distance will be normalized to 1.0; the other one will be > 1.0 - // The snap distance will be normalized to 1.0 if it's equal to the snapper tolerance - double const norm_p = std::min(getPointerDistance(), other_one.getPointerDistance()); - double const norm_t_other = std::min(50.0, other_one.getTolerance()); - double const norm_t_this = std::min(50.0, getTolerance()); - dist_other = w * other_one.getPointerDistance() / norm_p + (1-w) * dist_other / norm_t_other; - dist_this = w * getPointerDistance() / norm_p + (1-w) * dist_this / norm_t_this; - } - } - + // weigth factor: controls which node should be preferrerd for snapping, which is either + // the node with the closest snap (w = 0), or the node closest to the mousepointer (w = 1) + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + double w = prefs->getDoubleLimited("/options/snapweight/value", 0.5, 0, 1); + if (prefs->getBool("/options/snapclosestonly/value", false)) { + w = 1; + } + if (w > 0) { + // When accounting for the distance to the mouse pointer, then at least one of the snapped points should + // have that distance set. If not, then this is a bug. Either "weighted" must be set to false, or the + // mouse pointer distance must be set. + g_assert(getPointerDistance() != NR_HUGE || other_one.getPointerDistance() != NR_HUGE); + // The snap distance will always be smaller than the tolerance set for the snapper. The pointer distance can + // however be very large. To compare these in a fair way, we will have to normalize these metrics first + // The closest pointer distance will be normalized to 1.0; the other one will be > 1.0 + // The snap distance will be normalized to 1.0 if it's equal to the snapper tolerance + double const norm_p = std::min(getPointerDistance(), other_one.getPointerDistance()); + double const norm_t_other = std::min(50.0, other_one.getTolerance()); + double const norm_t_this = std::min(50.0, getTolerance()); + dist_other = w * other_one.getPointerDistance() / norm_p + (1-w) * dist_other / norm_t_other; + dist_this = w * getPointerDistance() / norm_p + (1-w) * dist_this / norm_t_this; + } + } + // If it's closer bool c1 = dist_other < dist_this; // or, if it's for a snapper with "always snap" turned on, and the previous wasn't bool c2 = other_one.getAlwaysSnap() && !getAlwaysSnap(); // But in no case fall back from a snapper with "always snap" on to one with "always snap" off bool c2n = !other_one.getAlwaysSnap() && getAlwaysSnap(); - // or, if we have a fully constrained snappoint (e.g. to a node), while the previous one was only partly constrained (e.g. to a line) + // or, if we have a fully constrained snappoint (e.g. to a node or an intersection), while the previous one was only partly constrained (e.g. to a line) bool c3 = other_one.getFullyConstrained() && !getFullyConstrained(); - // But in no case fall back; (has less priority than c3n, so it is allowed to fall back when c3 is true, see below) - bool c3n = !other_one.getFullyConstrained() && getFullyConstrained(); + // But in no case fall back; (has less priority than c3n, so it is allowed to fall back when c3 is true, see below) + bool c3n = !other_one.getFullyConstrained() && getFullyConstrained(); // or, if it's just as close then consider the second distance - // (which is only relevant for points at an intersection) - bool c4a = (dist_other == dist_this); + bool c4a = (dist_other == dist_this); bool c4b = other_one.getSecondSnapDistance() < getSecondSnapDistance(); - + // std::cout << "c1 = " << c1 << " | c2 = " << c2 << " | c2n = " << c2n << " | c3 = " << c3 << " | c3n = " << c3n << " | c4a = " << c4a << " | c4b = " << c4b << std::endl; - return (c1 || c2 || c3 || (c4a && c4b)) && !c2n && (!c3n || c2); + return (c1 || c2 || c3 || (c4a && c4b)) && !c2n && (!c3n || c2); } /*