Skip to content

Commit 644846b

Browse files
rsneddsymonds
authored andcommitted
s2: Add Polyline.Uninterpolate.
Signed-off-by: David Symonds <dsymonds@golang.org>
1 parent 4a14792 commit 644846b

File tree

3 files changed

+69
-4
lines changed

3 files changed

+69
-4
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ listing of the incomplete methods are documented at the end of each file.
150150
* ContainsPointQuery - missing visit edges
151151
* laxPolygon
152152
* Loop - Loop is mostly complete now. Missing Project, Distance, Union, etc.
153-
* Polyline - Missing Interpolate, etc.
153+
* Polyline - Missing InitTo... methods, NearlyCoversPolyline
154154
* Rect (AKA s2latlngrect in C++) - Missing Centroid, InteriorContains.
155155
* RegionCoverer - canonicalize
156156
* s2_test.go (AKA s2testing and s2textformat in C++) - Missing Fractal test

s2/polyline.go

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -556,11 +556,34 @@ func (p *Polyline) Interpolate(fraction float64) (Point, int) {
556556
return (*p)[len(*p)-1], len(*p)
557557
}
558558

559+
// Uninterpolate is the inverse operation of Interpolate. Given a point on the
560+
// polyline, it returns the ratio of the distance to the point from the
561+
// beginning of the polyline over the length of the polyline. The return
562+
// value is always betwen 0 and 1 inclusive.
563+
//
564+
// The polyline should not be empty. If it has fewer than 2 vertices, the
565+
// return value is zero.
566+
func (p *Polyline) Uninterpolate(point Point, nextVertex int) float64 {
567+
if len(*p) < 2 {
568+
return 0
569+
}
570+
571+
var sum s1.Angle
572+
for i := 1; i < nextVertex; i++ {
573+
sum += (*p)[i-1].Distance((*p)[i])
574+
}
575+
lengthToPoint := sum + (*p)[nextVertex-1].Distance(point)
576+
for i := nextVertex; i < len(*p); i++ {
577+
sum += (*p)[i-1].Distance((*p)[i])
578+
}
579+
// The ratio can be greater than 1.0 due to rounding errors or because the
580+
// point is not exactly on the polyline.
581+
return minFloat64(1.0, float64(lengthToPoint/sum))
582+
}
583+
559584
// TODO(roberts): Differences from C++.
560-
// UnInterpolate
561585
// NearlyCoversPolyline
562586
// InitToSnapped
563587
// InitToSimplified
564-
// IsValid
565588
// SnapLevel
566589
// encode/decode compressed

s2/polyline_test.go

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -584,8 +584,50 @@ func TestPolylineInterpolate(t *testing.T) {
584584
}
585585
}
586586

587+
func TestPolylineUninterpolate(t *testing.T) {
588+
vertices := []Point{PointFromCoords(1, 0, 0)}
589+
line := Polyline(vertices)
590+
if got, want := line.Uninterpolate(PointFromCoords(0, 1, 0), 1), 0.0; !float64Eq(got, want) {
591+
t.Errorf("Uninterpolate on a polyline with 2 or fewer vertices should return 0, got %v", got)
592+
}
593+
594+
vertices = append(vertices,
595+
PointFromCoords(0, 1, 0),
596+
PointFromCoords(0, 1, 1),
597+
PointFromCoords(0, 0, 1),
598+
)
599+
line = Polyline(vertices)
600+
601+
interpolated, nextVertex := line.Interpolate(-0.1)
602+
if got, want := line.Uninterpolate(interpolated, nextVertex), 0.0; !float64Eq(got, want) {
603+
t.Errorf("line.Uninterpolate(%v, %d) = %v, want %v", interpolated, nextVertex, got, want)
604+
}
605+
interpolated, nextVertex = line.Interpolate(0.0)
606+
if got, want := line.Uninterpolate(interpolated, nextVertex), 0.0; !float64Eq(got, want) {
607+
t.Errorf("line.Uninterpolate(%v, %d) = %v, want %v", interpolated, nextVertex, got, want)
608+
}
609+
interpolated, nextVertex = line.Interpolate(0.5)
610+
if got, want := line.Uninterpolate(interpolated, nextVertex), 0.5; !float64Eq(got, want) {
611+
t.Errorf("line.Uninterpolate(%v, %d) = %v, want %v", interpolated, nextVertex, got, want)
612+
}
613+
interpolated, nextVertex = line.Interpolate(0.75)
614+
if got, want := line.Uninterpolate(interpolated, nextVertex), 0.75; !float64Eq(got, want) {
615+
t.Errorf("line.Uninterpolate(%v, %d) = %v, want %v", interpolated, nextVertex, got, want)
616+
}
617+
interpolated, nextVertex = line.Interpolate(1.1)
618+
if got, want := line.Uninterpolate(interpolated, nextVertex), 1.0; !float64Eq(got, want) {
619+
t.Errorf("line.Uninterpolate(%v, %d) = %v, want %v", interpolated, nextVertex, got, want)
620+
}
621+
622+
// Check that the return value is clamped to 1.0.
623+
if got, want := line.Uninterpolate(PointFromCoords(0, 1, 0), len(line)), 1.0; !float64Eq(got, want) {
624+
t.Errorf("line.Uninterpolate(%v, %d) = %v, want %v", PointFromCoords(0, 1, 0), len(line), got, want)
625+
}
626+
}
627+
587628
// TODO(roberts): Test differences from C++:
588-
// UnInterpolate
629+
// InitToSnapped
630+
// InitToSimplified
589631
//
590632
// PolylineCoveringTest
591633
// PolylineOverlapsSelf

0 commit comments

Comments
 (0)