in s2/rect.go [519:601]
func directedHausdorffDistance(lngDiff s1.Angle, a, b r1.Interval) s1.Angle {
// By symmetry, we can assume a's longitude is 0 and b's longitude is
// lngDiff. Call b's two endpoints bLo and bHi. Let H be the hemisphere
// containing a and delimited by the longitude line of b. The Voronoi diagram
// of b on H has three edges (portions of great circles) all orthogonal to b
// and meeting at bLo cross bHi.
// E1: (bLo, bLo cross bHi)
// E2: (bHi, bLo cross bHi)
// E3: (-bMid, bLo cross bHi), where bMid is the midpoint of b
//
// They subdivide H into three Voronoi regions. Depending on how longitude 0
// (which contains edge a) intersects these regions, we distinguish two cases:
// Case 1: it intersects three regions. This occurs when lngDiff <= π/2.
// Case 2: it intersects only two regions. This occurs when lngDiff > π/2.
//
// In the first case, the directed Hausdorff distance to edge b can only be
// realized by the following points on a:
// A1: two endpoints of a.
// A2: intersection of a with the equator, if b also intersects the equator.
//
// In the second case, the directed Hausdorff distance to edge b can only be
// realized by the following points on a:
// B1: two endpoints of a.
// B2: intersection of a with E3
// B3: farthest point from bLo to the interior of D, and farthest point from
// bHi to the interior of U, if any, where D (resp. U) is the portion
// of edge a below (resp. above) the intersection point from B2.
if lngDiff < 0 {
panic("impossible: negative lngDiff")
}
if lngDiff > math.Pi {
panic("impossible: lngDiff > Pi")
}
if lngDiff == 0 {
return s1.Angle(a.DirectedHausdorffDistance(b))
}
// Assumed longitude of b.
bLng := lngDiff
// Two endpoints of b.
bLo := PointFromLatLng(LatLng{s1.Angle(b.Lo), bLng})
bHi := PointFromLatLng(LatLng{s1.Angle(b.Hi), bLng})
// Cases A1 and B1.
aLo := PointFromLatLng(LatLng{s1.Angle(a.Lo), 0})
aHi := PointFromLatLng(LatLng{s1.Angle(a.Hi), 0})
maxDistance := maxAngle(
DistanceFromSegment(aLo, bLo, bHi),
DistanceFromSegment(aHi, bLo, bHi))
if lngDiff <= math.Pi/2 {
// Case A2.
if a.Contains(0) && b.Contains(0) {
maxDistance = maxAngle(maxDistance, lngDiff)
}
return maxDistance
}
// Case B2.
p := bisectorIntersection(b, bLng)
pLat := LatLngFromPoint(p).Lat
if a.Contains(float64(pLat)) {
maxDistance = maxAngle(maxDistance, p.Angle(bLo.Vector))
}
// Case B3.
if pLat > s1.Angle(a.Lo) {
intDist, ok := interiorMaxDistance(r1.Interval{a.Lo, math.Min(float64(pLat), a.Hi)}, bLo)
if ok {
maxDistance = maxAngle(maxDistance, intDist)
}
}
if pLat < s1.Angle(a.Hi) {
intDist, ok := interiorMaxDistance(r1.Interval{math.Max(float64(pLat), a.Lo), a.Hi}, bHi)
if ok {
maxDistance = maxAngle(maxDistance, intDist)
}
}
return maxDistance
}