From 4737cdf2ce045c40c7af9f35a41b20c733e583c0 Mon Sep 17 00:00:00 2001 From: Lev Dragunov Date: Mon, 19 Oct 2015 15:58:43 +0300 Subject: [PATCH 1/3] [routing] Cross section geometry generation fix. --- generator/routing_generator.cpp | 10 +++++++--- geometry/region2d.hpp | 32 ++++++++++++++++++++++---------- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/generator/routing_generator.cpp b/generator/routing_generator.cpp index d680ad1259..053fe02aaa 100644 --- a/generator/routing_generator.cpp +++ b/generator/routing_generator.cpp @@ -119,10 +119,14 @@ void FindCrossNodes(osrm::NodeDataVectorT const & nodeData, gen::OsmID2FeatureID if (outStart == outEnd) continue; - border.FindIntersection(MercatorBounds::FromLatLon(segment.lat1, segment.lon1), - MercatorBounds::FromLatLon(segment.lat2, segment.lon2), - intersection); + if (!border.FindIntersection(MercatorBounds::FromLatLon(segment.lat1, segment.lon1), + MercatorBounds::FromLatLon(segment.lat2, segment.lon2), + intersection)) + { + ASSERT(false, ("Can't determine a intersection point with a border!")); + continue; + } // for old format compatibility intersection = m2::PointD(MercatorBounds::XToLon(intersection.x), MercatorBounds::YToLat(intersection.y)); if (!outStart && outEnd) diff --git a/geometry/region2d.hpp b/geometry/region2d.hpp index 078c215445..7cf90d8560 100644 --- a/geometry/region2d.hpp +++ b/geometry/region2d.hpp @@ -29,11 +29,16 @@ namespace m2 my::AlmostEqualAbs(p1.y, p2.y, static_cast(kPrecision)); } template - bool EqualZero(TCoord val, TCoord) const + bool EqualZeroSquarePrecision(TCoord val) const { static_assert(std::is_floating_point::value, ""); - return my::AlmostEqualAbs(val, 0.0, static_cast(kPrecision)); + return my::AlmostEqualAbs(val, 0.0, kPrecision * kPrecision); + } + inline bool IsAlmostBetween(double val, double left, double right) const + { + return ((val >= left - kPrecision) && (val <= right + kPrecision)) || + ((val <= left + kPrecision) && (val >= right - kPrecision)); } }; @@ -45,10 +50,15 @@ namespace m2 return p1 == p2; } template - bool EqualZero(TCoord val, TCoord) const + bool EqualZeroSquarePrecision(TCoord val) const { return val == 0; } + inline bool IsAlmostBetween(double val, double left, double right) const + { + return ((val >= left) && (val <= right)) || + ((val <= left) && (val >= right)); + } }; template struct TraitsType; @@ -145,21 +155,23 @@ namespace m2 ContainerT Data() const { return m_points; } + template inline bool IsIntersect(CoordT const & x11, CoordT const & y11, CoordT const & x12, CoordT const & y12, - CoordT const & x21, CoordT const & y21, CoordT const & x22, CoordT const & y22, PointT & pt) const + CoordT const & x21, CoordT const & y21, CoordT const & x22, CoordT const & y22, + EqualF equalF, PointT & pt) const { if (!((y12 - y11) * (x22 - x21) - (x12 - x11) * (y22-y21))) return false; double v = ((x12 - x11) * (y21 - y11) + (y12 - y11) * (x11 - x21)) / ((y12 - y11) * (x22 - x21) - (x12 - x11) * (y22 - y21)); PointT p(x21 + (x22 - x21) * v, y21 + (y22 - y21) * v); - if (!(((p.x >= x11) && (p.x <= x12)) || ((p.x <= x11) && (p.x >= x12)))) + if (!equalF.IsAlmostBetween(p.x, x11, x12)) return false; - if (!(((p.x >= x21) && (p.x <= x22)) || ((p.x <= x21) && (p.x >= x22)))) + if (!equalF.IsAlmostBetween(p.x, x21, x22)) return false; - if (!(((p.y >= y11) && (p.y <= y12)) || ((p.y <= y11) && (p.y >= y12)))) + if (!equalF.IsAlmostBetween(p.y, y11, y12)) return false; - if (!(((p.y >= y21) && (p.y <= y22)) || ((p.y <= y21) && (p.y >= y22)))) + if (!equalF.IsAlmostBetween(p.y, y21, y22)) return false; pt = p; @@ -168,7 +180,7 @@ namespace m2 inline bool IsIntersect(PointT const & p1, PointT const & p2, PointT const & p3, PointT const & p4 , PointT & pt) const { - return IsIntersect(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, pt); + return IsIntersect(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, typename TraitsT::EqualType(), pt); } public: @@ -206,7 +218,7 @@ namespace m2 BigCoordT const delta = prev.y - curr.y; BigCoordT const cp = CrossProduct(curr, prev); - if (!equalF.EqualZero(cp, delta)) + if (!equalF.EqualZeroSquarePrecision(cp)) { bool const PrevGreaterCurr = delta > 0.0; From ecc78cfba7c33bcc070391d989e7ef0c2467bd85 Mon Sep 17 00:00:00 2001 From: Lev Dragunov Date: Tue, 20 Oct 2015 17:29:01 +0300 Subject: [PATCH 2/3] Geometry unit test. --- geometry/geometry_tests/region_test.cpp | 9 +++++++++ geometry/region2d.hpp | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/geometry/geometry_tests/region_test.cpp b/geometry/geometry_tests/region_test.cpp index 1076631d34..8c9899d3b3 100644 --- a/geometry/geometry_tests/region_test.cpp +++ b/geometry/geometry_tests/region_test.cpp @@ -134,6 +134,15 @@ UNIT_TEST(Region) region.AddPoint(P(34.4, 33.2)); TEST(region.IsValid(), ()); + { + // equality case + { + P const data[] = { P(1, 1), P(0, 4.995), P(1, 4.999996), P(1.000003, 5.000001), P(0.5, 10), P(10, 10), P(10, 1) }; + region.Assign(data, data + ARRAY_SIZE(data)); + } + TEST(!region.Contains(P(0.9999987, 0.9999938)), ()); + TEST(!region.Contains(P(0.999998, 4.9999987)), ()); + } } UNIT_TEST(Region_Contains_int32) diff --git a/geometry/region2d.hpp b/geometry/region2d.hpp index 7cf90d8560..10bd47f377 100644 --- a/geometry/region2d.hpp +++ b/geometry/region2d.hpp @@ -218,6 +218,10 @@ namespace m2 BigCoordT const delta = prev.y - curr.y; BigCoordT const cp = CrossProduct(curr, prev); + // Squared precision is needed here because of comparison between cross product of two + // vectors and zero. It's impossible to compare them relatively, so they're compared + // absolutely, and, as cross product is proportional to product of lengths of both + // operands precision must be squared too. if (!equalF.EqualZeroSquarePrecision(cp)) { bool const PrevGreaterCurr = delta > 0.0; From b56749e893238d270721678320e93e6288a0a42e Mon Sep 17 00:00:00 2001 From: Lev Dragunov Date: Tue, 20 Oct 2015 18:54:15 +0300 Subject: [PATCH 3/3] PR fix. --- geometry/region2d.hpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/geometry/region2d.hpp b/geometry/region2d.hpp index 10bd47f377..934a45c945 100644 --- a/geometry/region2d.hpp +++ b/geometry/region2d.hpp @@ -35,10 +35,11 @@ namespace m2 return my::AlmostEqualAbs(val, 0.0, kPrecision * kPrecision); } - inline bool IsAlmostBetween(double val, double left, double right) const + // Determines if value of a val lays between a p1 and a p2 values with some precision. + inline bool IsAlmostBetween(double val, double p1, double p2) const { - return ((val >= left - kPrecision) && (val <= right + kPrecision)) || - ((val <= left + kPrecision) && (val >= right - kPrecision)); + return (val >= p1 - kPrecision && val <= p2 + kPrecision) || + (val <= p1 + kPrecision && val >= p2 - kPrecision); } }; @@ -56,8 +57,8 @@ namespace m2 } inline bool IsAlmostBetween(double val, double left, double right) const { - return ((val >= left) && (val <= right)) || - ((val <= left) && (val >= right)); + return (val >= left && val <= right) || + (val <= left && val >= right); } }; @@ -155,14 +156,15 @@ namespace m2 ContainerT Data() const { return m_points; } - template + template inline bool IsIntersect(CoordT const & x11, CoordT const & y11, CoordT const & x12, CoordT const & y12, CoordT const & x21, CoordT const & y21, CoordT const & x22, CoordT const & y22, - EqualF equalF, PointT & pt) const + TEqualF equalF, PointT & pt) const { - if (!((y12 - y11) * (x22 - x21) - (x12 - x11) * (y22-y21))) + double const divider = ((y12 - y11) * (x22 - x21) - (x12 - x11) * (y22-y21)); + if (equalF.EqualZeroSquarePrecision(divider)) return false; - double v = ((x12 - x11) * (y21 - y11) + (y12 - y11) * (x11 - x21)) / ((y12 - y11) * (x22 - x21) - (x12 - x11) * (y22 - y21)); + double v = ((x12 - x11) * (y21 - y11) + (y12 - y11) * (x11 - x21)) / divider; PointT p(x21 + (x22 - x21) * v, y21 + (y22 - y21) * v); if (!equalF.IsAlmostBetween(p.x, x11, x12)) @@ -186,8 +188,8 @@ namespace m2 public: /// Taken from Computational Geometry in C and modified - template - bool Contains(PointT const & pt, EqualF equalF) const + template + bool Contains(PointT const & pt, TEqualF equalF) const { if (!m_rect.IsPointInside(pt)) return false; @@ -266,8 +268,8 @@ namespace m2 } /// Slow check that point lies at the border. - template - bool AtBorder(PointT const & pt, double const delta, EqualF equalF) const + template + bool AtBorder(PointT const & pt, double const delta, TEqualF equalF) const { if (!m_rect.IsPointInside(pt)) return false;