diff options
Diffstat (limited to 'src/mongo/db/geo/big_polygon.cpp')
-rw-r--r-- | src/mongo/db/geo/big_polygon.cpp | 298 |
1 files changed, 146 insertions, 152 deletions
diff --git a/src/mongo/db/geo/big_polygon.cpp b/src/mongo/db/geo/big_polygon.cpp index fb496bfa96e..f50bdf1ae37 100644 --- a/src/mongo/db/geo/big_polygon.cpp +++ b/src/mongo/db/geo/big_polygon.cpp @@ -35,197 +35,191 @@ namespace mongo { - using std::unique_ptr; - using std::vector; +using std::unique_ptr; +using std::vector; - BigSimplePolygon::BigSimplePolygon() { - } - - // Caller should ensure loop is valid. - BigSimplePolygon::BigSimplePolygon(S2Loop* loop) : - _loop(loop), _isNormalized(loop->IsNormalized()) { - } +BigSimplePolygon::BigSimplePolygon() {} - BigSimplePolygon::~BigSimplePolygon() { - } +// Caller should ensure loop is valid. +BigSimplePolygon::BigSimplePolygon(S2Loop* loop) + : _loop(loop), _isNormalized(loop->IsNormalized()) {} - void BigSimplePolygon::Init(S2Loop* loop) { - _loop.reset(loop); - _isNormalized = loop->IsNormalized(); - _borderLine.reset(); - _borderPoly.reset(); - } +BigSimplePolygon::~BigSimplePolygon() {} - double BigSimplePolygon::GetArea() const { - return _loop->GetArea(); - } +void BigSimplePolygon::Init(S2Loop* loop) { + _loop.reset(loop); + _isNormalized = loop->IsNormalized(); + _borderLine.reset(); + _borderPoly.reset(); +} - bool BigSimplePolygon::Contains(const S2Polygon& polygon) const { - const S2Polygon& polyBorder = GetPolygonBorder(); +double BigSimplePolygon::GetArea() const { + return _loop->GetArea(); +} - if (_isNormalized) { - // Polygon border is the same as the loop - return polyBorder.Contains(&polygon); - } +bool BigSimplePolygon::Contains(const S2Polygon& polygon) const { + const S2Polygon& polyBorder = GetPolygonBorder(); - // Polygon border is the complement of the loop - // - // Return true iff big polygon's complement (polyBorder) doesn't intersect with polygon. - // We don't guarantee whether the points on border are contained or not. - return !polyBorder.Intersects(&polygon); + if (_isNormalized) { + // Polygon border is the same as the loop + return polyBorder.Contains(&polygon); } - bool BigSimplePolygon::Contains(const S2Polyline& line) const { - // - // A line is contained within a loop if the result of subtracting the loop from the line is - // nothing. - // - // Also, a line is contained within a loop if the result of clipping the line to the - // complement of the loop is nothing. - // - // If we can't subtract the loop itself using S2, we clip (intersect) to the inverse. Every - // point in S2 is contained in exactly one of these loops. - // - // TODO: Polygon borders are actually kind of weird, and this is somewhat inconsistent with - // Intersects(). A point might Intersect() a boundary exactly, but not be Contain()ed - // within the Polygon. Think the right thing to do here is custom intersection functions. - // - const S2Polygon& polyBorder = GetPolygonBorder(); + // Polygon border is the complement of the loop + // + // Return true iff big polygon's complement (polyBorder) doesn't intersect with polygon. + // We don't guarantee whether the points on border are contained or not. + return !polyBorder.Intersects(&polygon); +} - OwnedPointerVector<S2Polyline> clippedOwned; - vector<S2Polyline*>& clipped = clippedOwned.mutableVector(); - - if (_isNormalized) { - // Polygon border is the same as the loop - polyBorder.SubtractFromPolyline(&line, &clipped); - return clipped.size() == 0; - } - else { - // Polygon border is the complement of the loop - polyBorder.IntersectWithPolyline(&line, &clipped); - return clipped.size() == 0; - } +bool BigSimplePolygon::Contains(const S2Polyline& line) const { + // + // A line is contained within a loop if the result of subtracting the loop from the line is + // nothing. + // + // Also, a line is contained within a loop if the result of clipping the line to the + // complement of the loop is nothing. + // + // If we can't subtract the loop itself using S2, we clip (intersect) to the inverse. Every + // point in S2 is contained in exactly one of these loops. + // + // TODO: Polygon borders are actually kind of weird, and this is somewhat inconsistent with + // Intersects(). A point might Intersect() a boundary exactly, but not be Contain()ed + // within the Polygon. Think the right thing to do here is custom intersection functions. + // + const S2Polygon& polyBorder = GetPolygonBorder(); + + OwnedPointerVector<S2Polyline> clippedOwned; + vector<S2Polyline*>& clipped = clippedOwned.mutableVector(); + + if (_isNormalized) { + // Polygon border is the same as the loop + polyBorder.SubtractFromPolyline(&line, &clipped); + return clipped.size() == 0; + } else { + // Polygon border is the complement of the loop + polyBorder.IntersectWithPolyline(&line, &clipped); + return clipped.size() == 0; } +} - bool BigSimplePolygon::Contains(S2Point const& point) const { - return _loop->Contains(point); - } +bool BigSimplePolygon::Contains(S2Point const& point) const { + return _loop->Contains(point); +} - bool BigSimplePolygon::Intersects(const S2Polygon& polygon) const { - // If the loop area is at most 2*Pi, treat it as a simple Polygon. - if (_isNormalized) { - const S2Polygon& polyBorder = GetPolygonBorder(); - return polyBorder.Intersects(&polygon); - } - - // The loop area is greater than 2*Pi, so it intersects a polygon (even with holes) if it - // intersects any of the top-level polygon loops, since any valid polygon is less than - // a hemisphere. - // - // Intersecting a polygon hole requires that the loop must have intersected the containing - // loop - topology ftw. - // - // Another approach is to check polyBorder doesn't contain polygon, but the following - // approach is cheaper. - - // Iterate over all the top-level polygon loops - for (int i = 0; i < polygon.num_loops(); i = polygon.GetLastDescendant(i) + 1) { - const S2Loop* polyLoop = polygon.loop(i); - if (_loop->Intersects(polyLoop)) - return true; - } - - return false; +bool BigSimplePolygon::Intersects(const S2Polygon& polygon) const { + // If the loop area is at most 2*Pi, treat it as a simple Polygon. + if (_isNormalized) { + const S2Polygon& polyBorder = GetPolygonBorder(); + return polyBorder.Intersects(&polygon); } - bool BigSimplePolygon::Intersects(const S2Polyline& line) const { - // - // A loop intersects a line if line intersects the loop border or, if it doesn't, either - // line is contained in the loop, or line is disjoint with the loop. So checking any - // vertex of the line is sufficient. - // - // TODO: Make a general Polygon/Line relation tester which uses S2 primitives - // - return GetLineBorder().Intersects(&line) || _loop->Contains(line.vertex(0)); - } + // The loop area is greater than 2*Pi, so it intersects a polygon (even with holes) if it + // intersects any of the top-level polygon loops, since any valid polygon is less than + // a hemisphere. + // + // Intersecting a polygon hole requires that the loop must have intersected the containing + // loop - topology ftw. + // + // Another approach is to check polyBorder doesn't contain polygon, but the following + // approach is cheaper. - bool BigSimplePolygon::Intersects(S2Point const& point) const { - return Contains(point); + // Iterate over all the top-level polygon loops + for (int i = 0; i < polygon.num_loops(); i = polygon.GetLastDescendant(i) + 1) { + const S2Loop* polyLoop = polygon.loop(i); + if (_loop->Intersects(polyLoop)) + return true; } - void BigSimplePolygon::Invert() { - _loop->Invert(); - _isNormalized = _loop->IsNormalized(); - } + return false; +} - const S2Polygon& BigSimplePolygon::GetPolygonBorder() const { - if (_borderPoly) - return *_borderPoly; +bool BigSimplePolygon::Intersects(const S2Polyline& line) const { + // + // A loop intersects a line if line intersects the loop border or, if it doesn't, either + // line is contained in the loop, or line is disjoint with the loop. So checking any + // vertex of the line is sufficient. + // + // TODO: Make a general Polygon/Line relation tester which uses S2 primitives + // + return GetLineBorder().Intersects(&line) || _loop->Contains(line.vertex(0)); +} - unique_ptr<S2Loop> cloned(_loop->Clone()); +bool BigSimplePolygon::Intersects(S2Point const& point) const { + return Contains(point); +} - // Any loop in polygon should be than a hemisphere (2*Pi). - cloned->Normalize(); +void BigSimplePolygon::Invert() { + _loop->Invert(); + _isNormalized = _loop->IsNormalized(); +} - OwnedPointerVector<S2Loop> loops; - loops.mutableVector().push_back(cloned.release()); - _borderPoly.reset(new S2Polygon(&loops.mutableVector())); +const S2Polygon& BigSimplePolygon::GetPolygonBorder() const { + if (_borderPoly) return *_borderPoly; - } - const S2Polyline& BigSimplePolygon::GetLineBorder() const { - if (_borderLine) - return *_borderLine; + unique_ptr<S2Loop> cloned(_loop->Clone()); - vector<S2Point> points; - int numVertices = _loop->num_vertices(); - for (int i = 0; i <= numVertices; ++i) { - // vertex() maps "numVertices" to 0 internally, so we don't have to deal with - // the index out of range. - points.push_back(_loop->vertex(i)); - } + // Any loop in polygon should be than a hemisphere (2*Pi). + cloned->Normalize(); - _borderLine.reset(new S2Polyline(points)); + OwnedPointerVector<S2Loop> loops; + loops.mutableVector().push_back(cloned.release()); + _borderPoly.reset(new S2Polygon(&loops.mutableVector())); + return *_borderPoly; +} +const S2Polyline& BigSimplePolygon::GetLineBorder() const { + if (_borderLine) return *_borderLine; - } - BigSimplePolygon* BigSimplePolygon::Clone() const { - return new BigSimplePolygon(_loop->Clone()); + vector<S2Point> points; + int numVertices = _loop->num_vertices(); + for (int i = 0; i <= numVertices; ++i) { + // vertex() maps "numVertices" to 0 internally, so we don't have to deal with + // the index out of range. + points.push_back(_loop->vertex(i)); } - S2Cap BigSimplePolygon::GetCapBound() const { - return _loop->GetCapBound(); - } + _borderLine.reset(new S2Polyline(points)); - S2LatLngRect BigSimplePolygon::GetRectBound() const { - return _loop->GetRectBound(); - } + return *_borderLine; +} - bool BigSimplePolygon::Contains(const S2Cell& cell) const { - return _loop->Contains(cell); - } +BigSimplePolygon* BigSimplePolygon::Clone() const { + return new BigSimplePolygon(_loop->Clone()); +} - bool BigSimplePolygon::MayIntersect(const S2Cell& cell) const { - return _loop->MayIntersect(cell); - } +S2Cap BigSimplePolygon::GetCapBound() const { + return _loop->GetCapBound(); +} - bool BigSimplePolygon::VirtualContainsPoint(const S2Point& p) const { - return _loop->VirtualContainsPoint(p); - } +S2LatLngRect BigSimplePolygon::GetRectBound() const { + return _loop->GetRectBound(); +} - void BigSimplePolygon::Encode(Encoder* const encoder) const { - invariant(false); - } +bool BigSimplePolygon::Contains(const S2Cell& cell) const { + return _loop->Contains(cell); +} - bool BigSimplePolygon::Decode(Decoder* const decoder) { - invariant(false); - } +bool BigSimplePolygon::MayIntersect(const S2Cell& cell) const { + return _loop->MayIntersect(cell); +} - bool BigSimplePolygon::DecodeWithinScope(Decoder* const decoder) { - invariant(false); - } +bool BigSimplePolygon::VirtualContainsPoint(const S2Point& p) const { + return _loop->VirtualContainsPoint(p); +} + +void BigSimplePolygon::Encode(Encoder* const encoder) const { + invariant(false); +} +bool BigSimplePolygon::Decode(Decoder* const decoder) { + invariant(false); } +bool BigSimplePolygon::DecodeWithinScope(Decoder* const decoder) { + invariant(false); +} +} |