Add some other ideas to geom.
This commit is contained in:
parent
010c0a662c
commit
41cffbec5b
2 changed files with 214 additions and 0 deletions
105
geom/intfloat.go
Normal file
105
geom/intfloat.go
Normal file
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
Copyright 2021 Josh Deprez
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package geom
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
// IntFloat represents a number as an integer part plus a fractional part.
|
||||
// This can represent reals in the int range with decent precision.
|
||||
type IntFloat struct {
|
||||
I int
|
||||
F float64
|
||||
}
|
||||
|
||||
// ToIntFloat converts a float64 directly into an IntFloat.
|
||||
func ToIntFloat(f float64) IntFloat {
|
||||
return IntFloat{I: 0, F: f}.Canon()
|
||||
}
|
||||
|
||||
// Canon returns a value equal to x, in canonical form (0 ≤ F < 1).
|
||||
// Each possible value only has one canonical form.
|
||||
func (x IntFloat) Canon() IntFloat {
|
||||
i, f := math.Modf(x.F)
|
||||
if f < 0 {
|
||||
i--
|
||||
f = 1 + f
|
||||
}
|
||||
return IntFloat{I: x.I + int(i), F: f}
|
||||
}
|
||||
|
||||
// Float converts the value into a float64.
|
||||
func (x IntFloat) Float() float64 {
|
||||
return float64(x.I) + x.F
|
||||
}
|
||||
|
||||
func (x IntFloat) String() string {
|
||||
return fmt.Sprintf("%d + %f", x.I, x.F)
|
||||
}
|
||||
|
||||
// Lt reports x < y. x and y must be in canonical form for the
|
||||
// comparison to be meaningful.
|
||||
func (x IntFloat) Lt(y IntFloat) bool {
|
||||
if x.I == y.I {
|
||||
return x.F < y.F
|
||||
}
|
||||
return x.I < y.I
|
||||
}
|
||||
|
||||
// Gt reports x > y. x and y must be in canonical form for the
|
||||
// comparison to be meaningful.
|
||||
func (x IntFloat) Gt(y IntFloat) bool {
|
||||
if x.I == y.I {
|
||||
return x.F > y.F
|
||||
}
|
||||
return x.I > y.I
|
||||
}
|
||||
|
||||
// Add returns x+y (not canonicalised).
|
||||
func (x IntFloat) Add(y IntFloat) IntFloat {
|
||||
return IntFloat{I: x.I + y.I, F: x.F + y.F}
|
||||
}
|
||||
|
||||
// Neg returns -x (not canonicalised).
|
||||
func (x IntFloat) Neg() IntFloat {
|
||||
return IntFloat{I: -x.I, F: -x.F}
|
||||
}
|
||||
|
||||
// Sub returns x-y (not canonicalised).
|
||||
func (x IntFloat) Sub(y IntFloat) IntFloat {
|
||||
return IntFloat{I: x.I - y.I, F: x.F - y.F}
|
||||
}
|
||||
|
||||
// Mul returns x*y, canonicalised.
|
||||
func (x IntFloat) Mul(y IntFloat) IntFloat {
|
||||
return IntFloat{
|
||||
I: x.I * y.I,
|
||||
F: float64(x.I)*y.F + x.F*float64(y.I) + x.F*y.F,
|
||||
}.Canon()
|
||||
}
|
||||
|
||||
// Inv returns 1/x, canonicalised.
|
||||
func (x IntFloat) Inv() IntFloat {
|
||||
return ToIntFloat(1 / x.Float())
|
||||
}
|
||||
|
||||
// Div returns x/y, canonicalised.
|
||||
func (x IntFloat) Div(y IntFloat) IntFloat {
|
||||
return ToIntFloat(x.Float() / y.Float())
|
||||
}
|
109
geom/matrix.go
109
geom/matrix.go
|
@ -181,3 +181,112 @@ func (a RatMatrix3) Concat(b RatMatrix3) RatMatrix3 {
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Matrix3x4 implements a 3x4 matrix with floating-point values.
|
||||
type Matrix3x4 [3][4]float64
|
||||
|
||||
// IdentityMatrix3x4 is the identity matrix for Matrix3x4.
|
||||
var IdentityMatrix3x4 = Matrix3x4{
|
||||
0: [4]float64{0: 1},
|
||||
1: [4]float64{1: 1},
|
||||
2: [4]float64{2: 1},
|
||||
}
|
||||
|
||||
// Apply applies the matrix to the vector v.
|
||||
func (a Matrix3x4) Apply(v Float3) Float3 {
|
||||
return Float3{
|
||||
X: a[0][0]*v.X + a[0][1]*v.Y + a[0][2]*v.Z + a[0][3],
|
||||
Y: a[1][0]*v.X + a[1][1]*v.Y + a[1][2]*v.Z + a[1][3],
|
||||
Z: a[2][0]*v.X + a[2][1]*v.Y + a[2][2]*v.Z + a[2][3],
|
||||
}
|
||||
}
|
||||
|
||||
// Mul multiplies the whole matrix by a scalar.
|
||||
func (a Matrix3x4) Mul(r float64) Matrix3x4 {
|
||||
a[0][0] *= r
|
||||
a[0][1] *= r
|
||||
a[0][2] *= r
|
||||
a[0][3] *= r
|
||||
a[1][0] *= r
|
||||
a[1][1] *= r
|
||||
a[1][2] *= r
|
||||
a[1][3] *= r
|
||||
a[2][0] *= r
|
||||
a[2][1] *= r
|
||||
a[2][2] *= r
|
||||
a[2][3] *= r
|
||||
return a
|
||||
}
|
||||
|
||||
// Translation returns the translation component of the matrix (last column)
|
||||
// i.e. what you get if you Apply the matrix to the zero vector.
|
||||
func (a Matrix3x4) Translation() Float3 {
|
||||
return Float3{X: a[0][3], Y: a[1][3], Z: a[2][3]}
|
||||
}
|
||||
|
||||
// Adjugate returns the adjugate of the 3x3 submatrix.
|
||||
func (a Matrix3x4) Adjugate() Matrix3x4 {
|
||||
return Matrix3x4{
|
||||
0: [4]float64{
|
||||
0: a[1][1]*a[2][2] - a[1][2]*a[2][1],
|
||||
1: a[0][2]*a[2][1] - a[0][1]*a[2][2],
|
||||
2: a[0][1]*a[1][2] - a[0][2]*a[1][1],
|
||||
},
|
||||
1: [4]float64{
|
||||
0: a[1][2]*a[2][0] - a[1][0]*a[2][2],
|
||||
1: a[0][0]*a[2][2] - a[0][2]*a[2][0],
|
||||
2: a[0][2]*a[1][0] - a[0][0]*a[1][2],
|
||||
},
|
||||
2: [4]float64{
|
||||
0: a[1][0]*a[2][1] - a[1][1]*a[2][0],
|
||||
1: a[0][1]*a[2][0] - a[0][0]*a[2][1],
|
||||
2: a[0][0]*a[1][1] - a[0][1]*a[1][0],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Inverse returns the inverse of the matrix.
|
||||
func (a Matrix3x4) Inverse() (Matrix3x4, error) {
|
||||
adj := a.Adjugate()
|
||||
det := a[0][0]*adj[0][0] + a[0][1]*adj[1][0] + a[0][2]*adj[2][0]
|
||||
if det == 0 {
|
||||
return Matrix3x4{}, errSingularMatrix
|
||||
}
|
||||
inv := adj.Mul(1 / det) // the inverse of the 3x3 submatrix.
|
||||
// The affine transformation T consists of a square 3x3 submatrix A and
|
||||
// a translation vector b. We now have A^{-1} (inv).
|
||||
// T(x) = Ax + b
|
||||
// ⇒ T(x) - b = Ax
|
||||
// ⇒ A^{-1}(T(x) - b)) = x
|
||||
// ⇒ A^{-1}T(x) - A^{-1}b = x (by linearity of A^{-1})
|
||||
// ∴ T^{-1}(y) = A^{-1}y - A^{-1}b.
|
||||
ainvb := inv.Apply(a.Translation())
|
||||
a[0][3] -= ainvb.X
|
||||
a[1][3] -= ainvb.Y
|
||||
a[2][3] -= ainvb.Z
|
||||
return inv, nil
|
||||
}
|
||||
|
||||
// Concat returns the matrix equivalent to applying matrix a and then b.
|
||||
func (a Matrix3x4) Concat(b Matrix3x4) Matrix3x4 {
|
||||
return Matrix3x4{
|
||||
0: [4]float64{
|
||||
a[0][0]*b[0][0] + a[0][1]*b[1][0] + a[0][2]*b[2][0],
|
||||
a[0][0]*b[0][1] + a[0][1]*b[1][1] + a[0][2]*b[2][1],
|
||||
a[0][0]*b[0][2] + a[0][1]*b[1][2] + a[0][2]*b[2][2],
|
||||
a[0][0]*b[0][3] + a[0][1]*b[1][3] + a[0][3]*b[2][3],
|
||||
},
|
||||
1: [4]float64{
|
||||
a[1][0]*b[0][0] + a[1][1]*b[1][0] + a[1][2]*b[2][0],
|
||||
a[1][0]*b[0][1] + a[1][1]*b[1][1] + a[1][2]*b[2][1],
|
||||
a[1][0]*b[0][2] + a[1][1]*b[1][2] + a[1][2]*b[2][2],
|
||||
a[1][0]*b[0][3] + a[1][1]*b[1][3] + a[1][3]*b[2][3],
|
||||
},
|
||||
2: [4]float64{
|
||||
a[2][0]*b[0][0] + a[2][1]*b[1][0] + a[2][2]*b[2][0],
|
||||
a[2][0]*b[0][1] + a[2][1]*b[1][1] + a[2][2]*b[2][1],
|
||||
a[2][0]*b[0][2] + a[2][1]*b[1][2] + a[2][2]*b[2][2],
|
||||
a[2][0]*b[0][3] + a[2][1]*b[1][3] + a[2][3]*b[2][3],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue