Skip to content

Commit af0013a

Browse files
rsneddsymonds
authored andcommitted
s2: Fix ConvexHullQuery handling of antipodal points.
Signed-off-by: David Symonds <dsymonds@golang.org>
1 parent a7649ee commit af0013a

File tree

2 files changed

+30
-1
lines changed

2 files changed

+30
-1
lines changed

s2/convex_hull_query.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ package s2
1616

1717
import (
1818
"sort"
19+
20+
"github.com/golang/geo/r3"
1921
)
2022

2123
// ConvexHullQuery builds the convex hull of any collection of points,
@@ -231,7 +233,24 @@ func singlePointLoop(p Point) *Loop {
231233

232234
// singleEdgeLoop constructs a loop consisting of the two vertices and their midpoint.
233235
func singleEdgeLoop(a, b Point) *Loop {
234-
vertices := []Point{a, b, {a.Add(b.Vector).Normalize()}}
236+
// If the points are exactly antipodal we return the full loop.
237+
//
238+
// Note that we could use the code below even in this case (which would
239+
// return a zero-area loop that follows the edge AB), except that (1) the
240+
// direction of AB is defined using symbolic perturbations and therefore is
241+
// not predictable by ordinary users, and (2) Loop disallows anitpodal
242+
// adjacent vertices and so we would need to use 4 vertices to define the
243+
// degenerate loop. (Note that the Loop antipodal vertex restriction is
244+
// historical and now could easily be removed, however it would still have
245+
// the problem that the edge direction is not easily predictable.)
246+
if a.Add(b.Vector) == (r3.Vector{}) {
247+
return FullLoop()
248+
}
249+
250+
// Construct a loop consisting of the two vertices and their midpoint. We
251+
// use Interpolate() to ensure that the midpoint is very close to
252+
// the edge even when its endpoints nearly antipodal.
253+
vertices := []Point{a, b, Interpolate(0.5, a, b)}
235254
loop := LoopFromPoints(vertices)
236255
// The resulting loop may be clockwise, so invert it if necessary.
237256
loop.Normalize()

s2/convex_hull_query_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,16 @@ func TestConvexHullQueryTwoPoints(t *testing.T) {
8484
}
8585
}
8686

87+
func TestConvexHullAntipodalPoints(t *testing.T) {
88+
query := NewConvexHullQuery()
89+
query.AddPoint(PointFromCoords(0, 0, 1))
90+
query.AddPoint(PointFromCoords(0, 0, -1))
91+
result := query.ConvexHull()
92+
if !result.IsFull() {
93+
t.Errorf("antipodal points should return a Full Polygon, got: %v", result)
94+
}
95+
}
96+
8797
func loopHasVertex(l *Loop, p Point) bool {
8898
for _, v := range l.vertices {
8999
if v == p {

0 commit comments

Comments
 (0)