feat: polish & windviz & deploy
This commit is contained in:
parent
81b8e763bd
commit
465ad00f7b
78 changed files with 20622 additions and 2154 deletions
|
|
@ -56,31 +56,74 @@ func (a Axis) Locate(value float64) (Bracket, error) {
|
|||
return Bracket{Lo: lo, Hi: hi, Frac: pos - float64(lo)}, nil
|
||||
}
|
||||
|
||||
// EvalTrilinear samples a 3D field via f at the eight corners defined by b3
|
||||
// and returns the trilinearly interpolated value.
|
||||
// TrilinearWeights returns the eight corner weights for a (axis0, axis1,
|
||||
// axis2) bracket triple, in the canonical visiting order
|
||||
//
|
||||
// The corners are visited in the order (axis0 outer, axis2 inner), matching
|
||||
// the Cython reference. With f(i,j,k) = a*i + b*j + c*k + d this returns
|
||||
// a*pos0 + b*pos1 + c*pos2 + d exactly, modulo floating-point rounding.
|
||||
func EvalTrilinear(b3 [3]Bracket, f func(i, j, k int) float64) float64 {
|
||||
// (0,0,0) (0,0,1) (0,1,0) (0,1,1) (1,0,0) (1,0,1) (1,1,0) (1,1,1)
|
||||
//
|
||||
// where the bit triple selects Lo (0) or Hi (1) on each axis. The weights sum
|
||||
// to 1. Pair this with Dot8 over corner values fetched in the same order.
|
||||
func TrilinearWeights(b3 [3]Bracket) [8]float64 {
|
||||
wa0, wa1 := 1-b3[0].Frac, b3[0].Frac
|
||||
wb0, wb1 := 1-b3[1].Frac, b3[1].Frac
|
||||
wc0, wc1 := 1-b3[2].Frac, b3[2].Frac
|
||||
|
||||
wa0wb0 := wa0 * wb0
|
||||
wa0wb1 := wa0 * wb1
|
||||
wa1wb0 := wa1 * wb0
|
||||
wa1wb1 := wa1 * wb1
|
||||
|
||||
return [8]float64{
|
||||
wa0wb0 * wc0,
|
||||
wa0wb0 * wc1,
|
||||
wa0wb1 * wc0,
|
||||
wa0wb1 * wc1,
|
||||
wa1wb0 * wc0,
|
||||
wa1wb0 * wc1,
|
||||
wa1wb1 * wc0,
|
||||
wa1wb1 * wc1,
|
||||
}
|
||||
}
|
||||
|
||||
// Dot8 returns the multiply-accumulate sum w[0]*v[0] + ... + w[7]*v[7].
|
||||
//
|
||||
// The fixed length and straight-line accumulation are written so the Go
|
||||
// compiler can keep the values in registers and a future hand-vectorised
|
||||
// port can replace the body with a single SIMD MAC. The accumulation order
|
||||
// is fixed (ascending index) so results are reproducible.
|
||||
func Dot8(w, v *[8]float64) float64 {
|
||||
acc := w[0] * v[0]
|
||||
acc = w[1]*v[1] + acc
|
||||
acc = w[2]*v[2] + acc
|
||||
acc = w[3]*v[3] + acc
|
||||
acc = w[4]*v[4] + acc
|
||||
acc = w[5]*v[5] + acc
|
||||
acc = w[6]*v[6] + acc
|
||||
acc = w[7]*v[7] + acc
|
||||
return acc
|
||||
}
|
||||
|
||||
// EvalTrilinear samples a 3D field via f at the eight corners defined by b3
|
||||
// and returns the trilinearly interpolated value.
|
||||
//
|
||||
// Corners are visited in the canonical order documented on TrilinearWeights.
|
||||
// With f(i,j,k) = a*i + b*j + c*k + d this returns a*pos0 + b*pos1 + c*pos2
|
||||
// + d, modulo floating-point rounding. For the hot path prefer precomputing
|
||||
// weights once via TrilinearWeights and reducing with Dot8.
|
||||
func EvalTrilinear(b3 [3]Bracket, f func(i, j, k int) float64) float64 {
|
||||
w := TrilinearWeights(b3)
|
||||
a0, a1 := b3[0].Lo, b3[0].Hi
|
||||
bb0, bb1 := b3[1].Lo, b3[1].Hi
|
||||
b0, b1 := b3[1].Lo, b3[1].Hi
|
||||
c0, c1 := b3[2].Lo, b3[2].Hi
|
||||
|
||||
return wa0*wb0*wc0*f(a0, bb0, c0) +
|
||||
wa0*wb0*wc1*f(a0, bb0, c1) +
|
||||
wa0*wb1*wc0*f(a0, bb1, c0) +
|
||||
wa0*wb1*wc1*f(a0, bb1, c1) +
|
||||
wa1*wb0*wc0*f(a1, bb0, c0) +
|
||||
wa1*wb0*wc1*f(a1, bb0, c1) +
|
||||
wa1*wb1*wc0*f(a1, bb1, c0) +
|
||||
wa1*wb1*wc1*f(a1, bb1, c1)
|
||||
}
|
||||
|
||||
// Lerp returns (1-l)*a + l*b.
|
||||
func Lerp(a, b, l float64) float64 {
|
||||
return (1-l)*a + l*b
|
||||
v := [8]float64{
|
||||
f(a0, b0, c0),
|
||||
f(a0, b0, c1),
|
||||
f(a0, b1, c0),
|
||||
f(a0, b1, c1),
|
||||
f(a1, b0, c0),
|
||||
f(a1, b0, c1),
|
||||
f(a1, b1, c0),
|
||||
f(a1, b1, c1),
|
||||
}
|
||||
return Dot8(&w, &v)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue