// InterpolateAtDistance returns the point X along the line segment AB whose // distance from A is the angle ax. func InterpolateAtDistance(ax s1.Angle, a, b Point) Point { aRad := ax.Radians() // Use PointCross to compute the tangent vector at A towards B. The // result is always perpendicular to A, even if A=B or A=-B, but it is not // necessarily unit length. (We effectively normalize it below.) normal := a.PointCross(b) tangent := normal.Vector.Cross(a.Vector) // Now compute the appropriate linear combination of A and "tangent". With // infinite precision the result would always be unit length, but we // normalize it anyway to ensure that the error is within acceptable bounds. // (Otherwise errors can build up when the result of one interpolation is // fed into another interpolation.) return Point{(a.Mul(math.Cos(aRad)).Add(tangent.Mul(math.Sin(aRad) / tangent.Norm()))).Normalize()} }
// radiusToHeight converts an s1.Angle into the height of the cap. func radiusToHeight(r s1.Angle) float64 { if r.Radians() < 0 { return emptyHeight } if r.Radians() >= math.Pi { return fullHeight } // The height of the cap can be computed as 1 - cos(r), but this isn't very // accurate for angles close to zero (where cos(r) is almost 1). The // formula below has much better precision. d := math.Sin(0.5 * r.Radians()) return 2 * d * d }
// EarthDistance converts an angle to distance on earth in meters. func EarthDistance(angle s1.Angle) Length { return Length(angle.Radians() * EarthRadiusMeters) }