func updateEdgePairMinDistance(a0, a1, b0, b1 Point, minDist s1.ChordAngle) (s1.ChordAngle, bool) {
	if minDist == 0 {
		return 0, false
	}
	if CrossingSign(a0, a1, b0, b1) == Cross {
		minDist = 0
		return 0, true
	}
	var ok1, ok2, ok3, ok4 bool
	minDist, ok1 = UpdateMinDistance(a0, b0, b1, minDist)
	minDist, ok2 = UpdateMinDistance(a1, b0, b1, minDist)
	minDist, ok3 = UpdateMinDistance(b0, a0, a1, minDist)
	minDist, ok4 = UpdateMinDistance(b1, a0, a1, minDist)
	return minDist, ok1 || ok2 || ok3 || ok4
}
updateEdgePairMinDistance computes the minimum distance between the given
pair of edges. If the two edges cross, the distance is zero. The cases
a0 == a1 and b0 == b1 are handled correctly.
package s2
import (
	"math"
	"github.com/golang/geo/s1"
)
func DistanceFromSegment(x, a, b Point) s1.Angle {
	var minDist s1.ChordAngle
	minDist, _ = updateMinDistance(x, a, b, minDist, true)
	return minDist.Angle()
}
func IsDistanceLess(x, a, b Point, limit s1.ChordAngle) bool {
	_, less := UpdateMinDistance(x, a, b, limit)
	return less
}
func UpdateMinDistance(x, a, b Point, minDist s1.ChordAngle) (s1.ChordAngle, bool) {
	return updateMinDistance(x, a, b, minDist, false)
}
func UpdateMaxDistance(x, a, b Point, maxDist s1.ChordAngle) (s1.ChordAngle, bool) {
	dist := maxChordAngle(ChordAngleBetweenPoints(x, a), ChordAngleBetweenPoints(x, b))
	if dist > s1.RightChordAngle {
		dist, _ = updateMinDistance(Point{x.Mul(-1)}, a, b, dist, true)
		dist = s1.StraightChordAngle - dist
	}
	if maxDist < dist {
		return dist, true
	}
	return maxDist, false
}
func IsInteriorDistanceLess(x, a, b Point, limit s1.ChordAngle) bool {
	_, less := UpdateMinInteriorDistance(x, a, b, limit)
	return less
}
func UpdateMinInteriorDistance(x, a, b Point, minDist s1.ChordAngle) (s1.ChordAngle, bool) {
	return interiorDist(x, a, b, minDist, false)
}
func Project(x, a, b Point) Point {
	aXb := a.PointCross(b)
	p := x.Sub(aXb.Mul(x.Dot(aXb.Vector) / aXb.Vector.Norm2()))
	if Sign(aXb, a, Point{p}) && Sign(Point{p}, b, aXb) {
		return Point{p.Normalize()}
	}
	if x.Sub(a.Vector).Norm2() <= x.Sub(b.Vector).Norm2() {
		return a
	}
	return b
}
func DistanceFraction(x, a, b Point) float64 {
	d0 := x.Angle(a.Vector)
	d1 := x.Angle(b.Vector)
	return float64(d0 / (d0 + d1))
}
func Interpolate(t float64, a, b Point) Point {
	if t == 0 {
		return a
	}
	if t == 1 {
		return b
	}
	ab := a.Angle(b.Vector)
	return InterpolateAtDistance(s1.Angle(t)*ab, a, b)
}
func InterpolateAtDistance(ax s1.Angle, a, b Point) Point {
	aRad := ax.Radians()
	normal := a.PointCross(b)
	tangent := normal.Vector.Cross(a.Vector)
	return Point{(a.Mul(math.Cos(aRad)).Add(tangent.Mul(math.Sin(aRad) / tangent.Norm()))).Normalize()}
}
func minUpdateDistanceMaxError(dist s1.ChordAngle) float64 {
	return math.Max(minUpdateInteriorDistanceMaxError(dist), dist.MaxPointError())
}
func minUpdateInteriorDistanceMaxError(dist s1.ChordAngle) float64 {
	if dist >= s1.RightChordAngle {
		return 0.0
	}
	b := math.Min(1.0, 0.5*float64(dist))
	a := math.Sqrt(b * (2 - b))
	return ((2.5+2*math.Sqrt(3)+8.5*a)*a +
		(2+2*math.Sqrt(3)/3+6.5*(1-b))*b +
		(23+16/math.Sqrt(3))*dblEpsilon) * dblEpsilon
}
func updateMinDistance(x, a, b Point, minDist s1.ChordAngle, alwaysUpdate bool) (s1.ChordAngle, bool) {
	if d, ok := interiorDist(x, a, b, minDist, alwaysUpdate); ok {
		return d, true
	}
	xa2, xb2 := (x.Sub(a.Vector)).Norm2(), x.Sub(b.Vector).Norm2()
	dist := s1.ChordAngle(math.Min(xa2, xb2))
	if !alwaysUpdate && dist >= minDist {
		return minDist, false
	}
	return dist, true
}
func interiorDist(x, a, b Point, minDist s1.ChordAngle, alwaysUpdate bool) (s1.ChordAngle, bool) {
	xa2, xb2 := (x.Sub(a.Vector)).Norm2(), x.Sub(b.Vector).Norm2()
	ab2 := a.Sub(b.Vector).Norm2()
	maxError := (4.75*dblEpsilon*(xa2+xb2+ab2) + 8*dblEpsilon*dblEpsilon)
	if math.Abs(xa2-xb2) >= ab2+maxError {
		return minDist, false
	}
	c := a.PointCross(b)
	c2 := c.Norm2()
	xDotC := x.Dot(c.Vector)
	xDotC2 := xDotC * xDotC
	if !alwaysUpdate && xDotC2 > c2*float64(minDist) {
		return minDist, false
	}
	cx := c.Cross(x.Vector)
	if a.Sub(x.Vector).Dot(cx) >= 0 || b.Sub(x.Vector).Dot(cx) <= 0 {
		return minDist, false
	}
	qr := 1 - math.Sqrt(cx.Norm2()/c2)
	dist := s1.ChordAngle((xDotC2 / c2) + (qr * qr))
	if !alwaysUpdate && dist >= minDist {
		return minDist, false
	}
	return dist, true
}