55
55
using namespace arangodb ;
56
56
using namespace arangodb ::geo;
57
57
58
+ namespace {
59
+
60
+ S2Polygon latLngRectToPolygon (S2LatLngRect const * rect) {
61
+ // Construct polygon from rect:
62
+ std::vector<S2Point> v;
63
+ v.reserve (5 );
64
+ v.emplace_back (rect->GetVertex (0 ).ToPoint ());
65
+ v.emplace_back (rect->GetVertex (1 ).ToPoint ());
66
+ v.emplace_back (rect->GetVertex (2 ).ToPoint ());
67
+ v.emplace_back (rect->GetVertex (3 ).ToPoint ());
68
+ v.emplace_back (rect->GetVertex (0 ).ToPoint ());
69
+ std::unique_ptr<S2Loop> loop;
70
+ loop = std::make_unique<S2Loop>(std::move (v), S2Debug::DISABLE);
71
+ return S2Polygon{std::move (loop), S2Debug::DISABLE};
72
+ }
73
+
74
+ }
75
+
58
76
Result ShapeContainer::parseCoordinates (VPackSlice const & json, bool geoJson) {
59
77
if (!json.isArray () || json.length () < 2 ) {
60
78
return Result (TRI_ERROR_BAD_PARAMETER, " Invalid coordinate pair" );
@@ -557,41 +575,57 @@ bool ShapeContainer::equals(ShapeContainer const* cc) const {
557
575
bool ShapeContainer::intersects (S2Polyline const * other) const {
558
576
switch (_type) {
559
577
case ShapeContainer::Type::S2_POINT: {
560
- S2Point const & p = static_cast <S2PointRegion*>(_data)->point ();
561
- // containment is only numerically defined on the endpoints
562
- for (int k = 0 ; k < other->num_vertices (); k++) {
563
- if (other->vertex (k) == p) {
564
- return true ;
565
- }
566
- }
567
- return false ;
578
+ THROW_ARANGO_EXCEPTION_MESSAGE (TRI_ERROR_NOT_IMPLEMENTED,
579
+ " The case GEO_INTERSECTS(<point>, <polyline>) is numerically instable and thus not supported." );
568
580
}
569
581
case ShapeContainer::Type::S2_POLYLINE: {
570
582
S2Polyline const * ll = static_cast <S2Polyline const *>(_data);
571
583
return ll->Intersects (other);
572
584
}
573
585
case ShapeContainer::Type::S2_LATLNGRECT: {
574
- S2LatLngRect const * rect = static_cast <S2LatLngRect const *>(_data);
575
- for (int k = 0 ; k < other->num_vertices (); k++) {
576
- if (rect->Contains (other->vertex (k))) {
577
- return true ;
578
- }
579
- }
580
- return false ;
586
+ auto rectPoly = ::latLngRectToPolygon (static_cast <S2LatLngRect const *>(_data));
587
+ auto cuts = rectPoly.IntersectWithPolyline (*other);
588
+ return !cuts.empty ();
581
589
}
582
590
case ShapeContainer::Type::S2_POLYGON: {
583
591
S2Polygon const * poly = static_cast <S2Polygon const *>(_data);
584
592
auto cuts = poly->IntersectWithPolyline (*other);
585
593
return !cuts.empty ();
586
594
}
587
595
case ShapeContainer::Type::S2_MULTIPOINT:
588
- case ShapeContainer::Type::S2_MULTIPOLYLINE:
596
+ case ShapeContainer::Type::S2_MULTIPOLYLINE: {
597
+ THROW_ARANGO_EXCEPTION_MESSAGE (TRI_ERROR_NOT_IMPLEMENTED,
598
+ " The case GEO_INTERSECTS(<multipoint or multipolyline>, <polyline>) is not yet implemented." );
599
+ }
589
600
case ShapeContainer::Type::EMPTY:
590
601
TRI_ASSERT (false );
591
602
}
592
603
return false ;
593
604
}
594
605
606
+ namespace {
607
+ bool intersectRectPolygon (S2LatLngRect const * rect, S2Polygon const * poly) {
608
+ if (rect->is_full ()) {
609
+ return true ; // rectangle spans entire sphere
610
+ } else if (rect->is_point ()) {
611
+ return poly->Contains (rect->lo ().ToPoint ()); // easy case
612
+ } else if (!rect->Intersects (poly->GetRectBound ())) {
613
+ return false ; // cheap rejection
614
+ }
615
+ auto rectPoly = ::latLngRectToPolygon (rect);
616
+ return poly->Intersects (&rectPoly);
617
+ }
618
+
619
+ bool insersectMultiPointsRegion (S2MultiPointRegion const * points, S2Region const * region) {
620
+ for (int i = 0 ; i < points->num_points (); ++i) {
621
+ if (region->Contains (points->point (i))) {
622
+ return true ;
623
+ }
624
+ }
625
+ return false ;
626
+ }
627
+ }
628
+
595
629
bool ShapeContainer::intersects (S2LatLngRect const * other) const {
596
630
switch (_type) {
597
631
case ShapeContainer::Type::S2_POINT: {
@@ -600,7 +634,10 @@ bool ShapeContainer::intersects(S2LatLngRect const* other) const {
600
634
}
601
635
602
636
case ShapeContainer::Type::S2_POLYLINE: {
603
- return contains (other);
637
+ auto rectPoly = ::latLngRectToPolygon (static_cast <S2LatLngRect const *>(other));
638
+ S2Polyline const * self = static_cast <S2Polyline const *>(_data);
639
+ auto cuts = rectPoly.IntersectWithPolyline (*self);
640
+ return !cuts.empty ();
604
641
}
605
642
606
643
case ShapeContainer::Type::S2_LATLNGRECT: {
@@ -610,22 +647,17 @@ bool ShapeContainer::intersects(S2LatLngRect const* other) const {
610
647
611
648
case ShapeContainer::Type::S2_POLYGON: {
612
649
S2Polygon const * self = static_cast <S2Polygon const *>(_data);
613
- if (other->is_full ()) {
614
- return true ; // rectangle spans entire sphere
615
- } else if (other->is_point ()) {
616
- return self->Contains (other->lo ().ToPoint ()); // easy case
617
- } else if (!other->Intersects (self->GetRectBound ())) {
618
- return false ; // cheap rejection
619
- }
620
- // construct bounding polyline of rect
621
- S2Polyline rectBound ({other->GetVertex (0 ), other->GetVertex (1 ),
622
- other->GetVertex (2 ), other->GetVertex (3 )});
623
- return self->Intersects (rectBound);
650
+ return intersectRectPolygon (other, self);
651
+ }
652
+
653
+ case ShapeContainer::Type::S2_MULTIPOINT: {
654
+ S2MultiPointRegion* self = static_cast <S2MultiPointRegion*>(_data);
655
+ return insersectMultiPointsRegion (self, other);
624
656
}
625
657
626
- case ShapeContainer::Type::S2_MULTIPOINT:
627
658
case ShapeContainer::Type::S2_MULTIPOLYLINE: {
628
- return contains (other); // same
659
+ THROW_ARANGO_EXCEPTION_MESSAGE (TRI_ERROR_NOT_IMPLEMENTED,
660
+ " The case GEO_INTERSECTS(<multiline>, <latlngrect>) is not yet implemented." );
629
661
}
630
662
631
663
case ShapeContainer::Type::EMPTY:
@@ -641,31 +673,24 @@ bool ShapeContainer::intersects(S2Polygon const* other) const {
641
673
return other->Contains (p);
642
674
}
643
675
case ShapeContainer::Type::S2_POLYLINE: {
644
- LOG_TOPIC ( " 2cb3c " , ERR, Logger::FIXME)
645
- << " intersection with polyline is not well defined " ;
646
- return false ; // numerically not well defined
676
+ S2Polyline* line = static_cast <S2Polyline*>(_data);
677
+ auto cuts = other-> IntersectWithPolyline (*line) ;
678
+ return !cuts. empty ();
647
679
}
648
680
case ShapeContainer::Type::S2_LATLNGRECT: {
649
681
S2LatLngRect const * self = static_cast <S2LatLngRect const *>(_data);
650
- if (self->is_full ()) {
651
- return true ; // rectangle spans entire sphere
652
- } else if (self->is_point ()) {
653
- return other->Contains (self->lo ().ToPoint ()); // easy case
654
- } else if (!self->Intersects (other->GetRectBound ())) {
655
- return false ; // cheap rejection
656
- }
657
- // construct bounding polyline of rect
658
- S2Polyline rectBound ({self->GetVertex (0 ), self->GetVertex (1 ),
659
- self->GetVertex (2 ), self->GetVertex (3 )});
660
- return other->Intersects (rectBound);
682
+ return intersectRectPolygon (self, other);
661
683
}
662
684
case ShapeContainer::Type::S2_POLYGON: {
663
685
S2Polygon const * self = static_cast <S2Polygon const *>(_data);
664
686
return self->Intersects (other);
665
687
}
666
- case ShapeContainer::Type::EMPTY:
667
688
case ShapeContainer::Type::S2_MULTIPOINT:
668
- case ShapeContainer::Type::S2_MULTIPOLYLINE:
689
+ case ShapeContainer::Type::S2_MULTIPOLYLINE: {
690
+ THROW_ARANGO_EXCEPTION_MESSAGE (TRI_ERROR_NOT_IMPLEMENTED,
691
+ " The case GEO_INTERSECTS(<multipoint or multipolyline>, <polygon>) is not yet implemented." );
692
+ }
693
+ case ShapeContainer::Type::EMPTY:
669
694
TRI_ASSERT (false );
670
695
}
671
696
return false ;
@@ -674,6 +699,11 @@ bool ShapeContainer::intersects(S2Polygon const* other) const {
674
699
bool ShapeContainer::intersects (ShapeContainer const * cc) const {
675
700
switch (cc->_type ) {
676
701
case ShapeContainer::Type::S2_POINT: {
702
+ if (_type == ShapeContainer::Type::S2_POLYLINE ||
703
+ _type == ShapeContainer::Type::S2_MULTIPOLYLINE) {
704
+ THROW_ARANGO_EXCEPTION_MESSAGE (TRI_ERROR_NOT_IMPLEMENTED,
705
+ " The case GEO_INTERSECTS(<polyline>, <point>) is numerically instable and thus not supported." );
706
+ }
677
707
S2Point const & p = static_cast <S2PointRegion*>(cc->_data )->point ();
678
708
return _data->Contains (p); // same
679
709
}
@@ -687,13 +717,13 @@ bool ShapeContainer::intersects(ShapeContainer const* cc) const {
687
717
return intersects (static_cast <S2LatLngRect const *>(cc->_data ));
688
718
}
689
719
case ShapeContainer::Type::S2_MULTIPOINT: {
690
- auto pts = static_cast <S2MultiPointRegion const *>(cc->_data );
691
- for (int k = 0 ; k < pts->num_points (); k++) {
692
- if (_data->Contains (pts->point (k))) {
693
- return true ;
694
- }
720
+ if (_type == ShapeContainer::Type::S2_POLYLINE ||
721
+ _type == ShapeContainer::Type::S2_MULTIPOLYLINE) {
722
+ THROW_ARANGO_EXCEPTION_MESSAGE (TRI_ERROR_NOT_IMPLEMENTED,
723
+ " The case GEO_INTERSECTS(<polyline>, <multipoint>) is numerically instable and thus not supported." );
695
724
}
696
- return false ;
725
+ auto pts = static_cast <S2MultiPointRegion const *>(cc->_data );
726
+ return insersectMultiPointsRegion (pts, _data);
697
727
}
698
728
case ShapeContainer::Type::S2_MULTIPOLYLINE: {
699
729
auto lines = static_cast <S2MultiPolyline const *>(cc->_data );
0 commit comments