X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fsnapped-line.cpp;h=b6a5c2f9f5986f5b71692a808fad6a525cf26a80;hb=b03899b976eaea0d850429cae78aca08f64245c6;hp=7ae94e4f4b79181834cc5d0a36e8f4b5aa6af8e8;hpb=4e33f020dd832c0fa662afd97a40d6eba7f1fade;p=inkscape.git diff --git a/src/snapped-line.cpp b/src/snapped-line.cpp index 7ae94e4f4..b6a5c2f9f 100644 --- a/src/snapped-line.cpp +++ b/src/snapped-line.cpp @@ -12,21 +12,31 @@ #include <2geom/geom.h> #include "libnr/nr-values.h" -Inkscape::SnappedLineSegment::SnappedLineSegment(NR::Point snapped_point, NR::Coord snapped_distance, NR::Point start_point_of_line, NR::Point end_point_of_line) +Inkscape::SnappedLineSegment::SnappedLineSegment(NR::Point snapped_point, NR::Coord snapped_distance, NR::Coord snapped_tolerance, bool always_snap, NR::Point start_point_of_line, NR::Point end_point_of_line) : _start_point_of_line(start_point_of_line), _end_point_of_line(end_point_of_line) { - _distance = snapped_distance; _point = snapped_point; + _distance = snapped_distance; + _tolerance = snapped_tolerance; + _always_snap = always_snap; _at_intersection = false; + _second_distance = NR_HUGE; + _second_tolerance = 0; + _second_always_snap = false; } Inkscape::SnappedLineSegment::SnappedLineSegment() { _start_point_of_line = NR::Point(0,0); _end_point_of_line = NR::Point(0,0); - _distance = NR_HUGE; _point = NR::Point(0,0); + _distance = NR_HUGE; + _tolerance = 0; + _always_snap = false; _at_intersection = false; + _second_distance = NR_HUGE; + _second_tolerance = 0; + _second_always_snap = false; } @@ -37,28 +47,45 @@ Inkscape::SnappedLineSegment::~SnappedLineSegment() Inkscape::SnappedPoint Inkscape::SnappedLineSegment::intersect(SnappedLineSegment const &line) const { Geom::Point intersection_2geom(NR_HUGE, NR_HUGE); - NR::Coord distance = NR_HUGE; - Geom::IntersectorKind result = segment_intersect(_start_point_of_line.to_2geom(), _end_point_of_line.to_2geom(), line._start_point_of_line.to_2geom(), line._end_point_of_line.to_2geom(), intersection_2geom); NR::Point intersection(intersection_2geom); if (result == Geom::intersects) { - /* The relevant snapped distance is the distance to the closest snapped line, not the - distance to the intersection. See the comment in Inkscape::SnappedLine::intersect + /* 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. + * See the comment in Inkscape::SnappedLine::intersect */ - distance = std::min(_distance, line.getDistance()); + bool const c2 = _distance < line.getDistance(); + 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, primarySLS->getDistance(), primarySLS->getTolerance(), primarySLS->getAlwaysSnap(), true, + secondarySLS->getDistance(), secondarySLS->getTolerance(), secondarySLS->getAlwaysSnap()); } - return SnappedPoint(intersection, distance, result == Geom::intersects); + + // No intersection + return SnappedPoint(intersection, NR_HUGE, 0, false, false, NR_HUGE, 0, false); }; -Inkscape::SnappedLine::SnappedLine(NR::Point snapped_point, NR::Coord snapped_distance, NR::Point normal_to_line, NR::Point point_on_line) +Inkscape::SnappedLine::SnappedLine(NR::Point snapped_point, NR::Coord snapped_distance, NR::Coord snapped_tolerance, bool always_snap, NR::Point normal_to_line, NR::Point point_on_line) : _normal_to_line(normal_to_line), _point_on_line(point_on_line) { _distance = snapped_distance; + _tolerance = snapped_tolerance; + _always_snap = always_snap; + _second_distance = NR_HUGE; + _second_tolerance = 0; + _second_always_snap = false; _point = snapped_point; _at_intersection = false; } @@ -68,6 +95,11 @@ Inkscape::SnappedLine::SnappedLine() _normal_to_line = NR::Point(0,0); _point_on_line = NR::Point(0,0); _distance = NR_HUGE; + _tolerance = 0; + _always_snap = false; + _second_distance = NR_HUGE; + _second_tolerance = 0; + _second_always_snap = false; _point = NR::Point(0,0); _at_intersection = false; } @@ -78,29 +110,44 @@ Inkscape::SnappedLine::~SnappedLine() Inkscape::SnappedPoint Inkscape::SnappedLine::intersect(SnappedLine const &line) const { - // Calculate the intersection of to 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); - NR::Coord distance = NR_HUGE; - - Geom::IntersectorKind result = Geom::line_intersection(getNormal().to_2geom(), getConstTerm(), + Geom::IntersectorKind result = Geom::line_intersection(getNormal().to_2geom(), getConstTerm(), line.getNormal().to_2geom(), line.getConstTerm(), intersection_2geom); NR::Point intersection(intersection_2geom); if (result == Geom::intersects) { - /* 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 - */ - distance = std::min(_distance, line.getDistance()); - } - - return SnappedPoint(intersection, distance, 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(); + /* 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 + */ + bool const c2 = _distance < line.getDistance(); + 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, primarySL->getDistance(), primarySL->getTolerance(), primarySL->getAlwaysSnap(), true, + secondarySL->getDistance(), secondarySL->getTolerance(), secondarySL->getAlwaysSnap()); + } + + // No intersection + return SnappedPoint(intersection, NR_HUGE, 0, false, false, NR_HUGE, 0, false); } // search for the closest snapped line segment @@ -129,8 +176,15 @@ bool getClosestIntersectionSLS(std::list &list, In for (; j != list.end(); j++) { Inkscape::SnappedPoint sp = (*i).intersect(*j); if (sp.getAtIntersection()) { - if (!success || sp.getDistance() < result.getDistance()) { - // !success because the first intersection cannot be compared to a previous one + // if it's the first point + bool const c1 = !success; + // or, if it's closer + bool const c2 = sp.getDistance() < result.getDistance(); + // 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.getDistance() == result.getDistance()) && (sp.getSecondDistance() < result.getSecondDistance()); + // then prefer this point over the previous one + if (c1 || c2 || c3) { result = sp; success = true; } @@ -167,8 +221,15 @@ bool getClosestIntersectionSL(std::list &list, Inkscape:: for (; j != list.end(); j++) { Inkscape::SnappedPoint sp = (*i).intersect(*j); if (sp.getAtIntersection()) { - if (!success || sp.getDistance() < result.getDistance()) { - // !success because the first intersection cannot be compared to a previous one + // if it's the first point + bool const c1 = !success; + // or, if it's closer + bool const c2 = sp.getDistance() < result.getDistance(); + // 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.getDistance() == result.getDistance()) && (sp.getSecondDistance() < result.getSecondDistance()); + // then prefer this point over the previous one + if (c1 || c2 || c3) { result = sp; success = true; } @@ -188,8 +249,15 @@ bool getClosestIntersectionSL(std::list &list1, std::list for (std::list::const_iterator j = list2.begin(); j != list2.end(); j++) { Inkscape::SnappedPoint sp = (*i).intersect(*j); if (sp.getAtIntersection()) { - if (!success || sp.getDistance() < result.getDistance()) { - // !success because the first intersection cannot be compared to a previous one + // if it's the first point + bool const c1 = !success; + // or, if it's closer + bool const c2 = sp.getDistance() < result.getDistance(); + // 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.getDistance() == result.getDistance()) && (sp.getSecondDistance() < result.getSecondDistance()); + // then prefer this point over the previous one + if (c1 || c2 || c3) { result = sp; success = true; }