func uvwFace(face, axis, direction int) int {
	return faceUVWFaces[face][axis][direction]
}
uvwFaces returns the face in the (u,v,w) coordinate system on the given axis
in the given direction.
package s2
import (
	"math"
	"github.com/golang/geo/r3"
)
const (
	maxSiTi = maxSize << 1
)
func siTiToST(si uint32) float64 {
	if si > maxSiTi {
		return 1.0
	}
	return float64(si) / float64(maxSiTi)
}
func stToSiTi(s float64) uint32 {
	if s < 0 {
		return uint32(s*maxSiTi - 0.5)
	}
	return uint32(s*maxSiTi + 0.5)
}
func stToUV(s float64) float64 {
	if s >= 0.5 {
		return (1 / 3.) * (4*s*s - 1)
	}
	return (1 / 3.) * (1 - 4*(1-s)*(1-s))
}
func uvToST(u float64) float64 {
	if u >= 0 {
		return 0.5 * math.Sqrt(1+3*u)
	}
	return 1 - 0.5*math.Sqrt(1-3*u)
}
func face(r r3.Vector) int {
	f := r.LargestComponent()
	switch {
	case f == r3.XAxis && r.X < 0:
		f += 3
	case f == r3.YAxis && r.Y < 0:
		f += 3
	case f == r3.ZAxis && r.Z < 0:
		f += 3
	}
	return int(f)
}
func validFaceXYZToUV(face int, r r3.Vector) (float64, float64) {
	switch face {
	case 0:
		return r.Y / r.X, r.Z / r.X
	case 1:
		return -r.X / r.Y, r.Z / r.Y
	case 2:
		return -r.X / r.Z, -r.Y / r.Z
	case 3:
		return r.Z / r.X, r.Y / r.X
	case 4:
		return r.Z / r.Y, -r.X / r.Y
	}
	return -r.Y / r.Z, -r.X / r.Z
}
func xyzToFaceUV(r r3.Vector) (f int, u, v float64) {
	f = face(r)
	u, v = validFaceXYZToUV(f, r)
	return f, u, v
}
func faceUVToXYZ(face int, u, v float64) r3.Vector {
	switch face {
	case 0:
		return r3.Vector{1, u, v}
	case 1:
		return r3.Vector{-u, 1, v}
	case 2:
		return r3.Vector{-u, -v, 1}
	case 3:
		return r3.Vector{-1, -v, -u}
	case 4:
		return r3.Vector{v, -1, -u}
	default:
		return r3.Vector{v, u, -1}
	}
}
func faceXYZToUV(face int, p Point) (u, v float64, ok bool) {
	switch face {
	case 0:
		if p.X <= 0 {
			return 0, 0, false
		}
	case 1:
		if p.Y <= 0 {
			return 0, 0, false
		}
	case 2:
		if p.Z <= 0 {
			return 0, 0, false
		}
	case 3:
		if p.X >= 0 {
			return 0, 0, false
		}
	case 4:
		if p.Y >= 0 {
			return 0, 0, false
		}
	default:
		if p.Z >= 0 {
			return 0, 0, false
		}
	}
	u, v = validFaceXYZToUV(face, p.Vector)
	return u, v, true
}
func faceXYZtoUVW(face int, p Point) Point {
	switch face {
	case 0:
		return Point{r3.Vector{p.Y, p.Z, p.X}}
	case 1:
		return Point{r3.Vector{-p.X, p.Z, p.Y}}
	case 2:
		return Point{r3.Vector{-p.X, -p.Y, p.Z}}
	case 3:
		return Point{r3.Vector{-p.Z, -p.Y, -p.X}}
	case 4:
		return Point{r3.Vector{-p.Z, p.X, -p.Y}}
	default:
		return Point{r3.Vector{p.Y, p.X, -p.Z}}
	}
}
func faceSiTiToXYZ(face int, si, ti uint32) Point {
	return Point{faceUVToXYZ(face, stToUV(siTiToST(si)), stToUV(siTiToST(ti)))}
}
func xyzToFaceSiTi(p Point) (face int, si, ti uint32, level int) {
	face, u, v := xyzToFaceUV(p.Vector)
	si = stToSiTi(uvToST(u))
	ti = stToSiTi(uvToST(v))
	level = maxLevel - findLSBSetNonZero64(uint64(si|maxSiTi))
	if level < 0 || level != maxLevel-findLSBSetNonZero64(uint64(ti|maxSiTi)) {
		return face, si, ti, -1
	}
	if p.Vector == faceSiTiToXYZ(face, si, ti).Normalize() {
		return face, si, ti, level
	}
	return face, si, ti, -1
}
func uNorm(face int, u float64) r3.Vector {
	switch face {
	case 0:
		return r3.Vector{u, -1, 0}
	case 1:
		return r3.Vector{1, u, 0}
	case 2:
		return r3.Vector{1, 0, u}
	case 3:
		return r3.Vector{-u, 0, 1}
	case 4:
		return r3.Vector{0, -u, 1}
	default:
		return r3.Vector{0, -1, -u}
	}
}
func vNorm(face int, v float64) r3.Vector {
	switch face {
	case 0:
		return r3.Vector{-v, 0, 1}
	case 1:
		return r3.Vector{0, -v, 1}
	case 2:
		return r3.Vector{0, -1, -v}
	case 3:
		return r3.Vector{v, -1, 0}
	case 4:
		return r3.Vector{1, v, 0}
	default:
		return r3.Vector{1, 0, v}
	}
}
var faceUVWAxes = [6][3]Point{
	{Point{r3.Vector{0, 1, 0}}, Point{r3.Vector{0, 0, 1}}, Point{r3.Vector{1, 0, 0}}},
	{Point{r3.Vector{-1, 0, 0}}, Point{r3.Vector{0, 0, 1}}, Point{r3.Vector{0, 1, 0}}},
	{Point{r3.Vector{-1, 0, 0}}, Point{r3.Vector{0, -1, 0}}, Point{r3.Vector{0, 0, 1}}},
	{Point{r3.Vector{0, 0, -1}}, Point{r3.Vector{0, -1, 0}}, Point{r3.Vector{-1, 0, 0}}},
	{Point{r3.Vector{0, 0, -1}}, Point{r3.Vector{1, 0, 0}}, Point{r3.Vector{0, -1, 0}}},
	{Point{r3.Vector{0, 1, 0}}, Point{r3.Vector{1, 0, 0}}, Point{r3.Vector{0, 0, -1}}},
}
var faceUVWFaces = [6][3][2]int{
	{{4, 1}, {5, 2}, {3, 0}},
	{{0, 3}, {5, 2}, {4, 1}},
	{{0, 3}, {1, 4}, {5, 2}},
	{{2, 5}, {1, 4}, {0, 3}},
	{{2, 5}, {3, 0}, {1, 4}},
	{{4, 1}, {3, 0}, {2, 5}},
}
func uvwAxis(face, axis int) Point {
	return faceUVWAxes[face][axis]
}