in s2/cell.go [487:547]
func (c Cell) distanceInternal(targetXYZ Point, toInterior bool) s1.ChordAngle {
// All calculations are done in the (u,v,w) coordinates of this cell's face.
target := faceXYZtoUVW(int(c.face), targetXYZ)
// Compute dot products with all four upward or rightward-facing edge
// normals. dirIJ is the dot product for the edge corresponding to axis
// I, endpoint J. For example, dir01 is the right edge of the Cell
// (corresponding to the upper endpoint of the u-axis).
dir00 := target.X - target.Z*c.uv.X.Lo
dir01 := target.X - target.Z*c.uv.X.Hi
dir10 := target.Y - target.Z*c.uv.Y.Lo
dir11 := target.Y - target.Z*c.uv.Y.Hi
inside := true
if dir00 < 0 {
inside = false // Target is to the left of the cell
if c.vEdgeIsClosest(target, false) {
return edgeDistance(-dir00, c.uv.X.Lo)
}
}
if dir01 > 0 {
inside = false // Target is to the right of the cell
if c.vEdgeIsClosest(target, true) {
return edgeDistance(dir01, c.uv.X.Hi)
}
}
if dir10 < 0 {
inside = false // Target is below the cell
if c.uEdgeIsClosest(target, false) {
return edgeDistance(-dir10, c.uv.Y.Lo)
}
}
if dir11 > 0 {
inside = false // Target is above the cell
if c.uEdgeIsClosest(target, true) {
return edgeDistance(dir11, c.uv.Y.Hi)
}
}
if inside {
if toInterior {
return s1.ChordAngle(0)
}
// Although you might think of Cells as rectangles, they are actually
// arbitrary quadrilaterals after they are projected onto the sphere.
// Therefore the simplest approach is just to find the minimum distance to
// any of the four edges.
return minChordAngle(edgeDistance(-dir00, c.uv.X.Lo),
edgeDistance(dir01, c.uv.X.Hi),
edgeDistance(-dir10, c.uv.Y.Lo),
edgeDistance(dir11, c.uv.Y.Hi))
}
// Otherwise, the closest point is one of the four cell vertices. Note that
// it is *not* trivial to narrow down the candidates based on the edge sign
// tests above, because (1) the edges don't meet at right angles and (2)
// there are points on the far side of the sphere that are both above *and*
// below the cell, etc.
return minChordAngle(c.vertexChordDist2(target, false, false),
c.vertexChordDist2(target, true, false),
c.vertexChordDist2(target, false, true),
c.vertexChordDist2(target, true, true))
}