diff options
author | zmiao <miao.zhao@mapbox.com> | 2020-04-20 16:03:06 +0300 |
---|---|---|
committer | zmiao <miao.zhao@mapbox.com> | 2020-04-22 15:53:08 +0300 |
commit | b4b27627d6da053574485ca2b80b395d37ebaffd (patch) | |
tree | 1c6eede0f9738c31492ac917c677682087d20e4b /src/mbgl | |
parent | 8dac8f1150910dfc62759330c7e3dcdd7e5b53a2 (diff) | |
download | qtlocation-mapboxgl-b4b27627d6da053574485ca2b80b395d37ebaffd.tar.gz |
[core] Distance expression: Change template class into template function in geometry_util, add range assertion for distance contaniner IndexRange
Change distance units to small letters, update tests accordingly
Diffstat (limited to 'src/mbgl')
-rw-r--r-- | src/mbgl/geometry/feature_index.cpp | 6 | ||||
-rw-r--r-- | src/mbgl/style/expression/distance.cpp | 104 | ||||
-rw-r--r-- | src/mbgl/style/expression/within.cpp | 36 | ||||
-rw-r--r-- | src/mbgl/util/geometry_util.cpp | 62 | ||||
-rw-r--r-- | src/mbgl/util/geometry_util.hpp | 59 |
5 files changed, 153 insertions, 114 deletions
diff --git a/src/mbgl/geometry/feature_index.cpp b/src/mbgl/geometry/feature_index.cpp index 85a116bc2f..afe8bb0f23 100644 --- a/src/mbgl/geometry/feature_index.cpp +++ b/src/mbgl/geometry/feature_index.cpp @@ -8,7 +8,7 @@ #include <mbgl/text/collision_index.hpp> #include <mbgl/tile/tile_id.hpp> #include <mbgl/util/constants.hpp> -#include <mbgl/util/geometry_within.hpp> +#include <mbgl/util/geometry_util.hpp> #include <mbgl/util/math.hpp> #include <mbgl/util/projection.hpp> @@ -216,7 +216,7 @@ void DynamicFeatureIndex::query(std::unordered_map<std::string, std::vector<Feat const mbgl::ScreenLineString& queryGeometry, const TransformState& state) const { if (features.empty()) return; - mbgl::WithinBBox queryBox = DefaultBBox; + mbgl::GeometryBBox<int64_t> queryBox = DefaultWithinBBox; for (const auto& p : queryGeometry) { const LatLng c = screenCoordinateToLatLng(p, state); const Point<double> pm = project(c, state); @@ -225,7 +225,7 @@ void DynamicFeatureIndex::query(std::unordered_map<std::string, std::vector<Feat } for (const auto& f : features) { // hit testing - mbgl::WithinBBox featureBox = DefaultBBox; + mbgl::GeometryBBox<int64_t> featureBox = DefaultWithinBBox; for (const auto& p : f.envelope->front()) mbgl::updateBBox(featureBox, p); const bool hit = mbgl::boxWithinBox(featureBox, queryBox) || mbgl::boxWithinBox(queryBox, featureBox); diff --git a/src/mbgl/style/expression/distance.cpp b/src/mbgl/style/expression/distance.cpp index c4d0c7b56d..d42cfa39ea 100644 --- a/src/mbgl/style/expression/distance.cpp +++ b/src/mbgl/style/expression/distance.cpp @@ -24,20 +24,6 @@ namespace { const std::size_t MinPointsSize = 100; const std::size_t MinLinePointsSize = 50; -using BBox = std::array<double, 4>; -const BBox DefaultBBox = BBox{std::numeric_limits<double>::infinity(), - std::numeric_limits<double>::infinity(), - -std::numeric_limits<double>::infinity(), - -std::numeric_limits<double>::infinity()}; - -// bbox[minX, minY, maxX, maxY] -void updateBBox(BBox& bbox, const mapbox::geometry::point<double>& p) { - bbox[0] = std::min(p.x, bbox[0]); - bbox[1] = std::min(p.y, bbox[1]); - bbox[2] = std::max(p.x, bbox[2]); - bbox[3] = std::max(p.y, bbox[3]); -} - // Inclusive index range for multipoint or linestring container using IndexRange = std::pair<std::size_t, std::size_t>; @@ -45,16 +31,20 @@ std::size_t getRangeSize(const IndexRange& range) { return range.second - range.first + 1; } -BBox getBBox(const mapbox::geometry::multi_point<double>& points, const IndexRange& range) { - BBox bbox = DefaultBBox; +using DistanceBBox = GeometryBBox<double>; + +DistanceBBox getBBox(const mapbox::geometry::multi_point<double>& points, const IndexRange& range) { + assert(range.second >= range.first && range.second < points.size()); + DistanceBBox bbox = DefaultDistanceBBox; for (std::size_t i = range.first; i <= range.second; ++i) { updateBBox(bbox, points[i]); } return bbox; } -BBox getBBox(const mapbox::geometry::line_string<double>& line, const IndexRange& range) { - BBox bbox = DefaultBBox; +DistanceBBox getBBox(const mapbox::geometry::line_string<double>& line, const IndexRange& range) { + assert(range.second >= range.first && range.second < line.size()); + DistanceBBox bbox = DefaultDistanceBBox; for (std::size_t i = range.first; i <= range.second; ++i) { updateBBox(bbox, line[i]); } @@ -62,11 +52,13 @@ BBox getBBox(const mapbox::geometry::line_string<double>& line, const IndexRange } // Calculate the distance between two bounding boxes. -// Calculate the delta in x and y direction, and use two fake points {0, 0} and {dx, dy} to calculate the distance. -// Distance will be 0 if bounding box are overlapping. -double bboxToBBoxDistance(const BBox& bbox1, const BBox& bbox2, mapbox::cheap_ruler::CheapRuler& ruler) { - double dx = 0.; - double dy = 0.; +// Calculate the delta in x and y direction, and use two fake points {0.0, 0.0} and {dx, dy} to calculate the distance. +// Distance will be 0.0 if bounding box are overlapping. +double bboxToBBoxDistance(const DistanceBBox& bbox1, + const DistanceBBox& bbox2, + mapbox::cheap_ruler::CheapRuler& ruler) { + double dx = 0.0; + double dy = 0.0; // bbox1 in left side if (bbox1[2] < bbox2[0]) { dx = bbox2[0] - bbox1[2]; @@ -83,7 +75,7 @@ double bboxToBBoxDistance(const BBox& bbox1, const BBox& bbox2, mapbox::cheap_ru if (bbox1[3] < bbox2[1]) { dy = bbox2[1] - bbox1[3]; } - return ruler.distance(mapbox::geometry::point<double>{0., 0.}, mapbox::geometry::point<double>{dx, dy}); + return ruler.distance(mapbox::geometry::point<double>{0.0, 0.0}, mapbox::geometry::point<double>{dx, dy}); } double pointToLineDistance(const mapbox::geometry::point<double>& point, @@ -98,6 +90,8 @@ double lineToLineDistance(const mapbox::geometry::line_string<double>& line1, const mapbox::geometry::line_string<double>& line2, IndexRange& range2, mapbox::cheap_ruler::CheapRuler& ruler) { + assert(range1.second >= range1.first && range1.second < line1.size()); + assert(range2.second >= range2.first && range2.second < line2.size()); double dist = std::numeric_limits<double>::infinity(); for (std::size_t i = range1.first; i < range1.second; ++i) { const auto& p1 = line1[i]; @@ -105,7 +99,7 @@ double lineToLineDistance(const mapbox::geometry::line_string<double>& line1, for (std::size_t j = range2.first; j < range2.second; ++j) { const auto& q1 = line2[j]; const auto& q2 = line2[j + 1]; - if (GeometryUtil<double>::segmentIntersectSegment(p1, p2, q1, q2)) return 0.; + if (segmentIntersectSegment(p1, p2, q1, q2)) return 0.0; auto dist1 = std::min(pointToLineDistance(p1, mapbox::geometry::line_string<double>{q1, q2}, ruler), pointToLineDistance(p2, mapbox::geometry::line_string<double>{q1, q2}, ruler)); auto dist2 = std::min(pointToLineDistance(q1, mapbox::geometry::line_string<double>{p1, p2}, ruler), @@ -121,11 +115,13 @@ double pointsToPointsDistance(const mapbox::geometry::multi_point<double>& point const mapbox::geometry::multi_point<double>& points2, IndexRange& range2, mapbox::cheap_ruler::CheapRuler& ruler) { + assert(range1.second >= range1.first && range1.second < points1.size()); + assert(range2.second >= range2.first && range2.second < points2.size()); double dist = std::numeric_limits<double>::infinity(); for (std::size_t i = range1.first; i <= range1.second; ++i) { for (std::size_t j = range2.first; j <= range2.second; ++j) { dist = std::min(dist, ruler.distance(points1[i], points2[j])); - if (dist == 0.) return dist; + if (dist == 0.0) return dist; } } return dist; @@ -154,8 +150,7 @@ std::pair<mbgl::optional<IndexRange>, mbgl::optional<IndexRange>> splitRange(con // <distance, range1, range2> using DistPair = std::tuple<double, IndexRange, IndexRange>; -class Comparator { -public: +struct Comparator { bool operator()(DistPair& left, DistPair& right) { return std::get<0>(left) < std::get<0>(right); } }; // The priority queue will ensure the top element would always be the pair that has the biggest distance @@ -180,7 +175,7 @@ double lineToLineDistance(const mapbox::geometry::line_string<double>& line1, // In case the set size are relatively small, we could use brute-force directly if (getRangeSize(rangeA) <= MinLinePointsSize && getRangeSize(rangeB) <= MinLinePointsSize) { miniDist = std::min(miniDist, lineToLineDistance(line1, rangeA, line2, rangeB, ruler)); - if (miniDist == 0.) return 0.; + if (miniDist == 0.0) return 0.0; } else { auto newRangesA = splitRange(rangeA, true /*isLine*/); auto newRangesB = splitRange(rangeB, true /*isLine*/); @@ -223,7 +218,7 @@ double pointsToPointsDistance(const mapbox::geometry::multi_point<double>& point // In case the set size are relatively small, we could use brute-force directly if (getRangeSize(rangeA) <= MinPointsSize && getRangeSize(rangeB) <= MinPointsSize) { miniDist = std::min(miniDist, pointsToPointsDistance(pointSet1, rangeA, pointSet2, rangeB, ruler)); - if (miniDist == 0.) return 0.; + if (miniDist == 0.0) return 0.0; } else { auto newRangesA = splitRange(rangeA, false /*isLine*/); auto newRangesB = splitRange(rangeB, false /*isLine*/); @@ -263,11 +258,13 @@ double pointsToLineDistance(const mapbox::geometry::multi_point<double>& points, // In case the set size are relatively small, we could use brute-force directly if (getRangeSize(rangeA) <= MinPointsSize && getRangeSize(rangeB) <= MinLinePointsSize) { + assert(rangeA.second >= rangeA.first && rangeA.second < points.size()); + assert(rangeB.second >= rangeB.first && rangeB.second < line.size()); auto subLine = mapbox::geometry::multi_point<double>(line.begin() + rangeB.first, line.begin() + rangeB.second + 1); for (std::size_t i = rangeA.first; i <= rangeA.second; ++i) { miniDist = std::min(miniDist, pointToLineDistance(points[i], subLine, ruler)); - if (miniDist == 0.) return 0.; + if (miniDist == 0.0) return 0.0; } } else { auto newRangesA = splitRange(rangeA, false /*isLine*/); @@ -296,7 +293,7 @@ double pointsToLinesDistance(const mapbox::geometry::multi_point<double>& points double dist = std::numeric_limits<double>::infinity(); for (const auto& line : lines) { dist = std::min(dist, pointsToLineDistance(points, line, ruler)); - if (dist == 0.) return dist; + if (dist == 0.0) return 0.0; } return dist; } @@ -307,7 +304,7 @@ double lineToLinesDistance(const mapbox::geometry::line_string<double>& line, double dist = std::numeric_limits<double>::infinity(); for (const auto& l : lines) { dist = std::min(dist, lineToLineDistance(line, l, ruler)); - if (dist == 0.) return dist; + if (dist == 0.0) return 0.0; } return dist; } @@ -372,7 +369,7 @@ double calculateDistance(const GeometryTileFeature& feature, double dist = std::numeric_limits<double>::infinity(); for (const auto& line : lines) { dist = std::min(dist, lineToGeometryDistance(line, geoSet, unit)); - if (dist == 0.) return dist; + if (dist == 0.0) return dist; } return dist; }, @@ -405,24 +402,24 @@ optional<Arguments> parseValue(const style::conversion::Convertible& value, styl ctx.error("Failed to parse unit argument from 'distance' expression"); return nullopt; } - if (*input == "Meters" || *input == "Metres") { + if (*input == "meters" || *input == "metres") { unit = mapbox::cheap_ruler::CheapRuler::Unit::Meters; - } else if (*input == "Kilometers") { + } else if (*input == "kilometers") { unit = mapbox::cheap_ruler::CheapRuler::Unit::Kilometers; - } else if (*input == "Miles") { + } else if (*input == "miles") { unit = mapbox::cheap_ruler::CheapRuler::Unit::Miles; - } else if (*input == "NauticalMiles") { + } else if (*input == "nauticalmiles") { unit = mapbox::cheap_ruler::CheapRuler::Unit::NauticalMiles; - } else if (*input == "Yards") { + } else if (*input == "yards") { unit = mapbox::cheap_ruler::CheapRuler::Unit::Yards; - } else if (*input == "Feet") { + } else if (*input == "feet") { unit = mapbox::cheap_ruler::CheapRuler::Unit::Feet; - } else if (*input == "Inches") { + } else if (*input == "inches") { unit = mapbox::cheap_ruler::CheapRuler::Unit::Inches; } else { ctx.error( - "'distance' expression only accepts following Units: 'Kilometers', 'Miles', 'NauticalMiles', " - "'Meters', 'Metres', 'Yards', 'Feet', 'Inches'."); + "'distance' expression only accepts following units: kilometers, miles, nauticalmiles, " + "meters, metres, yards, feet, inches."); return nullopt; } } @@ -438,8 +435,8 @@ optional<Arguments> parseValue(const style::conversion::Convertible& value, styl } } ctx.error( - "'distance' expression needs to be an array with format [\"Distance\", GeoJSONObj, \"unit(optional, Meters by " - "default)\"]."); + "'distance' expression needs to be an array with format [\"Distance\", GeoJSONObj, \"units\"(\"units\" is an " + "optional argument, 'meters' will be used by default)]."); return nullopt; } @@ -474,6 +471,7 @@ EvaluationResult Distance::evaluate(const EvaluationContext& params) const { if (geometryType == FeatureType::Point || geometryType == FeatureType::LineString) { auto distance = calculateDistance(*params.feature, *params.canonical, geometries, unit); if (!std::isnan(distance)) { + assert(distance >= 0.0); return distance; } } @@ -547,21 +545,21 @@ Value convertValue(const mapbox::geojson::rapidjson_value& v) { std::string getUnits(const mapbox::cheap_ruler::CheapRuler::Unit& unit) { switch (unit) { case mapbox::cheap_ruler::CheapRuler::Kilometers: - return "Kilometers"; + return "kilometers"; case mapbox::cheap_ruler::CheapRuler::Miles: - return "Miles"; + return "miles"; case mapbox::cheap_ruler::CheapRuler::NauticalMiles: - return "NauticalMiles"; + return "nauticalmiles"; case mapbox::cheap_ruler::CheapRuler::Meters: - return "Meters"; + return "meters"; case mapbox::cheap_ruler::CheapRuler::Yards: - return "Yards"; + return "yards"; case mapbox::cheap_ruler::CheapRuler::Feet: - return "Feet"; + return "feet"; case mapbox::cheap_ruler::CheapRuler::Inches: - return "Inches"; + return "inches"; default: - return "Error"; + return "error"; } } diff --git a/src/mbgl/style/expression/within.cpp b/src/mbgl/style/expression/within.cpp index a3e2500319..3fd2bf8f92 100644 --- a/src/mbgl/style/expression/within.cpp +++ b/src/mbgl/style/expression/within.cpp @@ -15,29 +15,6 @@ namespace mbgl { namespace { -// contains minX, minY, maxX, maxY -using WithinBBox = std::array<int64_t, 4>; -const WithinBBox DefaultBBox = WithinBBox{std::numeric_limits<int64_t>::max(), - std::numeric_limits<int64_t>::max(), - std::numeric_limits<int64_t>::min(), - std::numeric_limits<int64_t>::min()}; - -// check if bbox1 is within bbox2 -void updateBBox(WithinBBox& bbox, const Point<int64_t>& p) { - bbox[0] = std::min(p.x, bbox[0]); - bbox[1] = std::min(p.y, bbox[1]); - bbox[2] = std::max(p.x, bbox[2]); - bbox[3] = std::max(p.y, bbox[3]); -} - -bool boxWithinBox(const WithinBBox& bbox1, const WithinBBox& bbox2) { - if (bbox1[0] <= bbox2[0]) return false; - if (bbox1[2] >= bbox2[2]) return false; - if (bbox1[1] <= bbox2[1]) return false; - if (bbox1[3] >= bbox2[3]) return false; - return true; -} - Point<int64_t> latLonToTileCoodinates(const Point<double>& point, const mbgl::CanonicalTileID& canonical) { const double size = util::EXTENT * std::pow(2, canonical.z); @@ -53,6 +30,7 @@ Point<int64_t> latLonToTileCoodinates(const Point<double>& point, const mbgl::Ca return p; }; +using WithinBBox = GeometryBBox<int64_t>; Polygon<int64_t> getTilePolygon(const Polygon<double>& polygon, const mbgl::CanonicalTileID& canonical, WithinBBox& bbox) { @@ -149,7 +127,7 @@ MultiLineString<int64_t> getTileLines(const GeometryCollection& lines, const auto worldSize = util::EXTENT * std::pow(2, canonical.z); if (bbox[2] - bbox[0] <= worldSize / 2) { - bbox = DefaultBBox; + bbox = DefaultWithinBBox; for (auto& line : results) { for (auto& p : line) { updatePoint(p, bbox, polyBBox, worldSize); @@ -162,28 +140,28 @@ MultiLineString<int64_t> getTileLines(const GeometryCollection& lines, bool featureWithinPolygons(const GeometryTileFeature& feature, const CanonicalTileID& canonical, const Feature::geometry_type& polygonGeoSet) { - WithinBBox polyBBox = DefaultBBox; + WithinBBox polyBBox = DefaultWithinBBox; const auto polygons = getTilePolygons(polygonGeoSet, canonical, polyBBox); assert(!polygons.empty()); const GeometryCollection& geometries = feature.getGeometries(); switch (feature.getType()) { case FeatureType::Point: { assert(!geometries.empty()); - WithinBBox pointBBox = DefaultBBox; + WithinBBox pointBBox = DefaultWithinBBox; MultiPoint<int64_t> points = getTilePoints(geometries.at(0), canonical, pointBBox, polyBBox); if (!boxWithinBox(pointBBox, polyBBox)) return false; return std::all_of(points.begin(), points.end(), [&polygons](const auto& p) { - return GeometryUtil<int64_t>::pointWithinPolygons(p, polygons); + return pointWithinPolygons<int64_t>(p, polygons); }); } case FeatureType::LineString: { - WithinBBox lineBBox = DefaultBBox; + WithinBBox lineBBox = DefaultWithinBBox; MultiLineString<int64_t> multiLineString = getTileLines(geometries, canonical, lineBBox, polyBBox); if (!boxWithinBox(lineBBox, polyBBox)) return false; return std::all_of(multiLineString.begin(), multiLineString.end(), [&polygons](const auto& line) { - return GeometryUtil<int64_t>::lineStringWithinPolygons(line, polygons); + return lineStringWithinPolygons<int64_t>(line, polygons); }); } default: diff --git a/src/mbgl/util/geometry_util.cpp b/src/mbgl/util/geometry_util.cpp index df4119ce6a..4a90c75582 100644 --- a/src/mbgl/util/geometry_util.cpp +++ b/src/mbgl/util/geometry_util.cpp @@ -5,13 +5,31 @@ namespace mbgl { template <typename T> -bool GeometryUtil<T>::rayIntersect(const Point<T>& p, const Point<T>& p1, const Point<T>& p2) { +void updateBBox(GeometryBBox<T>& bbox, const Point<T>& p) { + bbox[0] = std::min(p.x, bbox[0]); + bbox[1] = std::min(p.y, bbox[1]); + bbox[2] = std::max(p.x, bbox[2]); + bbox[3] = std::max(p.y, bbox[3]); +} + +// check if bbox1 is within bbox2 +template <typename T> +bool boxWithinBox(const GeometryBBox<T>& bbox1, const GeometryBBox<T>& bbox2) { + if (bbox1[0] <= bbox2[0]) return false; + if (bbox1[2] >= bbox2[2]) return false; + if (bbox1[1] <= bbox2[1]) return false; + if (bbox1[3] >= bbox2[3]) return false; + return true; +} + +template <typename T> +bool rayIntersect(const Point<T>& p, const Point<T>& p1, const Point<T>& p2) { return ((p1.y > p.y) != (p2.y > p.y)) && (p.x < (p2.x - p1.x) * (p.y - p1.y) / (p2.y - p1.y) + p1.x); } // check if point p is on line segment with end points p1 and p2 template <typename T> -bool GeometryUtil<T>::pointOnBoundary(const Point<T>& p, const Point<T>& p1, const Point<T>& p2) { +bool pointOnBoundary(const Point<T>& p, const Point<T>& p1, const Point<T>& p2) { // requirements of point p on line segment: // 1. colinear: cross product of vector p->p1(x1, y1) and vector p->p2(x2, y2) equals to 0 // 2. p is between p1 and p2 @@ -23,10 +41,7 @@ bool GeometryUtil<T>::pointOnBoundary(const Point<T>& p, const Point<T>& p1, con } template <typename T> -bool GeometryUtil<T>::segmentIntersectSegment(const Point<T>& a, - const Point<T>& b, - const Point<T>& c, - const Point<T>& d) { +bool segmentIntersectSegment(const Point<T>& a, const Point<T>& b, const Point<T>& c, const Point<T>& d) { // a, b are end points for line segment1, c and d are end points for line segment2 const auto perp = [](const Point<T>& v1, const Point<T>& v2) { return (v1.x * v2.y - v1.y * v2.x); }; @@ -58,7 +73,7 @@ bool GeometryUtil<T>::segmentIntersectSegment(const Point<T>& a, } template <typename T> -bool GeometryUtil<T>::lineIntersectPolygon(const Point<T>& p1, const Point<T>& p2, const Polygon<T>& polygon) { +bool lineIntersectPolygon(const Point<T>& p1, const Point<T>& p2, const Polygon<T>& polygon) { for (auto ring : polygon) { auto length = ring.size(); // loop through every edge of the ring @@ -73,7 +88,7 @@ bool GeometryUtil<T>::lineIntersectPolygon(const Point<T>& p1, const Point<T>& p // ray casting algorithm for detecting if point is in polygon template <typename T> -bool GeometryUtil<T>::pointWithinPolygon(const Point<T>& point, const Polygon<T>& polygon, bool trueOnBoundary) { +bool pointWithinPolygon(const Point<T>& point, const Polygon<T>& polygon, bool trueOnBoundary) { bool within = false; for (const auto& ring : polygon) { const auto length = ring.size(); @@ -89,7 +104,7 @@ bool GeometryUtil<T>::pointWithinPolygon(const Point<T>& point, const Polygon<T> } template <typename T> -bool GeometryUtil<T>::pointWithinPolygons(const Point<T>& point, const MultiPolygon<T>& polygons, bool trueOnBoundary) { +bool pointWithinPolygons(const Point<T>& point, const MultiPolygon<T>& polygons, bool trueOnBoundary) { for (const auto& polygon : polygons) { if (pointWithinPolygon(point, polygon, trueOnBoundary)) return true; } @@ -97,7 +112,7 @@ bool GeometryUtil<T>::pointWithinPolygons(const Point<T>& point, const MultiPoly } template <typename T> -bool GeometryUtil<T>::lineStringWithinPolygon(const LineString<T>& line, const Polygon<T>& polygon) { +bool lineStringWithinPolygon(const LineString<T>& line, const Polygon<T>& polygon) { const auto length = line.size(); // First, check if geometry points of line segments are all inside polygon for (std::size_t i = 0; i < length; ++i) { @@ -116,14 +131,35 @@ bool GeometryUtil<T>::lineStringWithinPolygon(const LineString<T>& line, const P } template <typename T> -bool GeometryUtil<T>::lineStringWithinPolygons(const LineString<T>& line, const MultiPolygon<T>& polygons) { +bool lineStringWithinPolygons(const LineString<T>& line, const MultiPolygon<T>& polygons) { for (const auto& polygon : polygons) { if (lineStringWithinPolygon(line, polygon)) return true; } return false; } -template struct GeometryUtil<double>; -template struct GeometryUtil<int64_t>; +template void updateBBox(GeometryBBox<int64_t>& bbox, const Point<int64_t>& p); +template bool boxWithinBox(const GeometryBBox<int64_t>& bbox1, const GeometryBBox<int64_t>& bbox2); +template bool segmentIntersectSegment(const Point<int64_t>& a, + const Point<int64_t>& b, + const Point<int64_t>& c, + const Point<int64_t>& d); +template bool rayIntersect(const Point<int64_t>& p, const Point<int64_t>& p1, const Point<int64_t>& p2); +template bool pointOnBoundary(const Point<int64_t>& p, const Point<int64_t>& p1, const Point<int64_t>& p2); +template bool lineIntersectPolygon(const Point<int64_t>& p1, const Point<int64_t>& p2, const Polygon<int64_t>& polygon); +template bool pointWithinPolygon(const Point<int64_t>& point, + const Polygon<int64_t>& polygon, + bool trueOnBoundary = false); +template bool pointWithinPolygons(const Point<int64_t>& point, + const MultiPolygon<int64_t>& polygons, + bool trueOnBoundary = false); +template bool lineStringWithinPolygon(const LineString<int64_t>& line, const Polygon<int64_t>& polygon); +template bool lineStringWithinPolygons(const LineString<int64_t>& line, const MultiPolygon<int64_t>& polygons); + +template void updateBBox(GeometryBBox<double>& bbox, const Point<double>& p); +template bool segmentIntersectSegment(const Point<double>& a, + const Point<double>& b, + const Point<double>& c, + const Point<double>& d); } // namespace mbgl diff --git a/src/mbgl/util/geometry_util.hpp b/src/mbgl/util/geometry_util.hpp index ccf7bfc504..3bdef9f357 100644 --- a/src/mbgl/util/geometry_util.hpp +++ b/src/mbgl/util/geometry_util.hpp @@ -1,25 +1,52 @@ #pragma once +#include <array> #include <mbgl/util/geometry.hpp> namespace mbgl { +// contains minX, minY, maxX, maxY template <typename T> -struct GeometryUtil { - using type = T; - static bool segmentIntersectSegment(const Point<type>& a, - const Point<type>& b, - const Point<type>& c, - const Point<type>& d); - static bool rayIntersect(const Point<type>& p, const Point<type>& p1, const Point<type>& p2); - static bool pointOnBoundary(const Point<type>& p, const Point<type>& p1, const Point<type>& p2); - static bool lineIntersectPolygon(const Point<type>& p1, const Point<type>& p2, const Polygon<type>& polygon); - static bool pointWithinPolygon(const Point<type>& point, const Polygon<type>& polygon, bool trueOnBoundary = false); - static bool pointWithinPolygons(const Point<type>& point, - const MultiPolygon<type>& polygons, - bool trueOnBoundary = false); - static bool lineStringWithinPolygon(const LineString<type>& line, const Polygon<type>& polygon); - static bool lineStringWithinPolygons(const LineString<type>& line, const MultiPolygon<type>& polygons); -}; +using GeometryBBox = std::array<T, 4>; +const GeometryBBox<int64_t> DefaultWithinBBox = std::array<int64_t, 4>{std::numeric_limits<int64_t>::max(), + std::numeric_limits<int64_t>::max(), + std::numeric_limits<int64_t>::min(), + std::numeric_limits<int64_t>::min()}; + +const GeometryBBox<double> DefaultDistanceBBox = std::array<double, 4>{std::numeric_limits<double>::infinity(), + std::numeric_limits<double>::infinity(), + -std::numeric_limits<double>::infinity(), + -std::numeric_limits<double>::infinity()}; + +template <typename T> +void updateBBox(GeometryBBox<T>& bbox, const Point<T>& p); + +// check if bbox1 is within bbox2 +template <typename T> +bool boxWithinBox(const GeometryBBox<T>& bbox1, const GeometryBBox<T>& bbox2); + +template <typename T> +bool segmentIntersectSegment(const Point<T>& a, const Point<T>& b, const Point<T>& c, const Point<T>& d); + +template <typename T> +bool rayIntersect(const Point<T>& p, const Point<T>& p1, const Point<T>& p2); + +template <typename T> +bool pointOnBoundary(const Point<T>& p, const Point<T>& p1, const Point<T>& p2); + +template <typename T> +bool lineIntersectPolygon(const Point<T>& p1, const Point<T>& p2, const Polygon<T>& polygon); + +template <typename T> +bool pointWithinPolygon(const Point<T>& point, const Polygon<T>& polygon, bool trueOnBoundary = false); + +template <typename T> +bool pointWithinPolygons(const Point<T>& point, const MultiPolygon<T>& polygons, bool trueOnBoundary = false); + +template <typename T> +bool lineStringWithinPolygon(const LineString<T>& line, const Polygon<T>& polygon); + +template <typename T> +bool lineStringWithinPolygons(const LineString<T>& line, const MultiPolygon<T>& polygons); } // namespace mbgl |