Documentation ¶
Overview ¶
Package geom provides geometric primitives: vectors, matrices and transformations.
Index ¶
- Constants
- Variables
- type AffineTransform
- func ComposeLR(t ...*AffineTransform) *AffineTransform
- func MapBaseTo(o, x, y, z Vec) *AffineTransform
- func Pitch(angle float64) *AffineTransform
- func Roll(angle float64) *AffineTransform
- func Rotate(origin Vec, axis Vec, angle float64) *AffineTransform
- func Scale(origin Vec, s float64) *AffineTransform
- func Translate(delta Vec) *AffineTransform
- func UnitTransform() *AffineTransform
- func Yaw(angle float64) *AffineTransform
- func YawPitchRoll(yaw, pitch, roll float64) *AffineTransform
- func (t *AffineTransform) After(s *AffineTransform) *AffineTransform
- func (t *AffineTransform) Before(s *AffineTransform) *AffineTransform
- func (t *AffineTransform) Inverse() *AffineTransform
- func (t *AffineTransform) TransformDir(dir Vec) Vec
- func (t *AffineTransform) TransformPoint(x Vec) Vec
- func (t *AffineTransform) WithOrigin(o Vec) *AffineTransform
- type Matrix
- type Vec
- func (a Vec) Add(b Vec) Vec
- func (a Vec) Cross(b Vec) Vec
- func (a Vec) Dot(b Vec) float64
- func (a Vec) IsNaN() bool
- func (a Vec) Len() float64
- func (a Vec) Len2() float64
- func (a Vec) MAdd(s float64, b Vec) Vec
- func (a Vec) Mul(s float64) Vec
- func (a *Vec) Normalize()
- func (a Vec) Normalized() Vec
- func (a Vec) Sub(b Vec) Vec
- type Vec2
Examples ¶
Constants ¶
const ( // Deg is one degree in radians. Useful for conversions, e.g.: 90*Deg. Deg = Pi / 180 // Pi is shorthand for math.Pi. Pi = math.Pi )
const ( X = 0 Y = 1 Z = 2 )
Vector components.
Variables ¶
var Ex = Vec{1, 0, 0}
Ex is shorthand for the basis vector [1 0 0].
var Ey = Vec{0, 1, 0}
Ey is shorthand for the basis vector [0 1 0].
var Ez = Vec{0, 0, 1}
Ez is shorthand for the basis vector [0 0 1].
var Inf = math.Inf(1)
var O = Vec{0, 0, 0}
O is shorthand for the zero vector [0 0 0].
Functions ¶
This section is empty.
Types ¶
type AffineTransform ¶
AffineTransform represents an 3D affine transformation
y = A x + b
func ComposeLR ¶
func ComposeLR(t ...*AffineTransform) *AffineTransform
ComposeLR composes affine transformations left-to-right. I.e., the leftmost argument is applied first.
func MapBaseTo ¶
func MapBaseTo(o, x, y, z Vec) *AffineTransform
func Pitch ¶
func Pitch(angle float64) *AffineTransform
Pitch tilts the camera upwards by the given angle (in radians). E.g.:
camera.Pitch( 0*Deg) // look horizontally camera.Pitch(-90*Deg) // look at your feet camera.Pitch(+90*Deg) // look at the zenith
Yaw, Pitch and Roll are not commutative. Use YawPitchRoll to apply them in canonical order.
func Roll ¶
func Roll(angle float64) *AffineTransform
Roll rotates the camera counterclockwise around the line of sight. E.g.:
camera.Roll( 0*Deg) // horizon runs straight camera.Roll(45*Deg) // horizon runs diagonally, from top left to bottom right.
Yaw, Pitch and Roll are not commutative. Use YawPitchRoll to apply them in canonical order.
func Rotate ¶
func Rotate(origin Vec, axis Vec, angle float64) *AffineTransform
Rotate returns a Transform that rotates around an arbitrary axis, with origin as the fixed point. The rotation is counterclockwise in a right-handed space.
Example ¶
angle := 30 * Deg inputs := [3]Vec{Ex, Ey, Ez} Rx := Rotate(O, Vec{1, 0, 0}, angle) for _, v := range inputs { fmt.Printf("Rx: % .2f -> % .2f\n", v, Rx.TransformPoint(v)) } fmt.Println() Ry := Rotate(O, Vec{0, 1, 0}, angle) for _, v := range inputs { fmt.Printf("Ry: % .2f -> % .2f\n", v, Ry.TransformPoint(v)) } fmt.Println() Rz := Rotate(O, Vec{0, 0, 1}, angle) for _, v := range inputs { fmt.Printf("Rz: % .2f -> % .2f\n", v, Rz.TransformPoint(v)) } fmt.Println()
Output: Rx: [ 1.00 0.00 0.00] -> [ 1.00 0.00 0.00] Rx: [ 0.00 1.00 0.00] -> [ 0.00 0.87 0.50] Rx: [ 0.00 0.00 1.00] -> [ 0.00 -0.50 0.87] Ry: [ 1.00 0.00 0.00] -> [ 0.87 0.00 -0.50] Ry: [ 0.00 1.00 0.00] -> [ 0.00 1.00 0.00] Ry: [ 0.00 0.00 1.00] -> [ 0.50 0.00 0.87] Rz: [ 1.00 0.00 0.00] -> [ 0.87 0.50 0.00] Rz: [ 0.00 1.00 0.00] -> [-0.50 0.87 0.00] Rz: [ 0.00 0.00 1.00] -> [ 0.00 0.00 1.00]
func Scale ¶
func Scale(origin Vec, s float64) *AffineTransform
Scale returns a transform that scales by factor s, with origin as the fixed point.
Example ¶
tf := Scale(O, 2) v := Vec{1, 2, 3} fmt.Printf("point: % g -> % g\n", v, tf.TransformPoint(v)) fmt.Printf("dir: % g -> % g\n", v, tf.TransformDir(v))
Output: point: [ 1 2 3] -> [ 2 4 6] dir: [ 1 2 3] -> [ 2 4 6]
func Translate ¶
func Translate(delta Vec) *AffineTransform
Translate returns a Transform that translates by delta. Translation affects points (TransformPoint), but not directions (TransformDir).
Example ¶
tf := Translate(Vec{1, 0, 0}) v := Vec{1, 2, 3} fmt.Printf("point: % g -> % g\n", v, tf.TransformPoint(v)) fmt.Printf("dir: % g -> % g\n", v, tf.TransformDir(v))
Output: point: [ 1 2 3] -> [ 2 2 3] dir: [ 1 2 3] -> [ 1 2 3]
func UnitTransform ¶
func UnitTransform() *AffineTransform
func Yaw ¶
func Yaw(angle float64) *AffineTransform
Yaw rotates the camera counterclockwise by the given angle (in radians), while keeping it horizontal. E.g.:
camera.Yaw( 0*Deg) // look North camera.Yaw(+90*Deg) // look West camera.Yaw(-90*Deg) // look East camera.Yaw(180*Deg) // look South
Yaw, Pitch and Roll are not commutative. Use YawPitchRoll to apply them in canonical order.
func YawPitchRoll ¶
func YawPitchRoll(yaw, pitch, roll float64) *AffineTransform
func (*AffineTransform) After ¶
func (t *AffineTransform) After(s *AffineTransform) *AffineTransform
After returns a composite transform that applies s first, followed by t.
Example ¶
R := Rotate(O, Ez, 90*Deg) S := Scale(O, 2) T := Translate(Vec{1, 0, 0}) ST := S.After(T) TR := T.After(R) RS := R.After(S) TS := T.After(S) RT := R.After(T) SR := S.After(R) RST := R.After(S).After(T) STR := S.After(T).After(R) TRS := T.After(R).After(S) x := Vec{1, 0, 0} fmt.Printf("R : % g -> % g\n", x, R.TransformPoint(x)) fmt.Printf("S : % g -> % g\n", x, S.TransformPoint(x)) fmt.Printf("T : % g -> % g\n", x, T.TransformPoint(x)) fmt.Printf("ST : % g -> % g\n", x, ST.TransformPoint(x)) fmt.Printf("S(T) : % g -> % g\n", x, S.TransformPoint(T.TransformPoint(x))) fmt.Printf("TR : % g -> % g\n", x, TR.TransformPoint(x)) fmt.Printf("T(R) : % g -> % g\n", x, T.TransformPoint(R.TransformPoint(x))) fmt.Printf("RS : % g -> % g\n", x, RS.TransformPoint(x)) fmt.Printf("R(S) : % g -> % g\n", x, R.TransformPoint(S.TransformPoint(x))) fmt.Printf("TS : % g -> % g\n", x, TS.TransformPoint(x)) fmt.Printf("T(S) : % g -> % g\n", x, T.TransformPoint(S.TransformPoint(x))) fmt.Printf("RT : % g -> % g\n", x, RT.TransformPoint(x)) fmt.Printf("R(T) : % g -> % g\n", x, R.TransformPoint(T.TransformPoint(x))) fmt.Printf("SR : % g -> % g\n", x, SR.TransformPoint(x)) fmt.Printf("S(R) : % g -> % g\n", x, S.TransformPoint(R.TransformPoint(x))) fmt.Printf("RST : % g -> % g\n", x, RST.TransformPoint(x)) fmt.Printf("R(S(T)) : % g -> % g\n", x, R.TransformPoint(S.TransformDir(T.TransformPoint(x)))) fmt.Printf("ComposeLR(T,S,R): % g -> % g\n", x, ComposeLR(T, S, R).TransformPoint(x)) fmt.Printf("STR : % g -> % g\n", x, STR.TransformPoint(x)) fmt.Printf("S(T(R)) : % g -> % g\n", x, S.TransformPoint(T.TransformPoint(R.TransformPoint(x)))) fmt.Printf("ComposeLR(R,T,S): % g -> % g\n", x, ComposeLR(R, T, S).TransformPoint(x)) fmt.Printf("TRS : % g -> % g\n", x, TRS.TransformPoint(x)) fmt.Printf("T(R(S)) : % g -> % g\n", x, T.TransformPoint(R.TransformPoint(S.TransformPoint(x)))) fmt.Printf("ComposeLR(S,R,T): % g -> % g\n", x, ComposeLR(S, R, T).TransformPoint(x))
Output: R : [ 1 0 0] -> [ 0 1 0] S : [ 1 0 0] -> [ 2 0 0] T : [ 1 0 0] -> [ 2 0 0] ST : [ 1 0 0] -> [ 4 0 0] S(T) : [ 1 0 0] -> [ 4 0 0] TR : [ 1 0 0] -> [ 1 1 0] T(R) : [ 1 0 0] -> [ 1 1 0] RS : [ 1 0 0] -> [ 0 2 0] R(S) : [ 1 0 0] -> [ 0 2 0] TS : [ 1 0 0] -> [ 3 0 0] T(S) : [ 1 0 0] -> [ 3 0 0] RT : [ 1 0 0] -> [ 0 2 0] R(T) : [ 1 0 0] -> [ 0 2 0] SR : [ 1 0 0] -> [ 0 2 0] S(R) : [ 1 0 0] -> [ 0 2 0] RST : [ 1 0 0] -> [ 0 4 0] R(S(T)) : [ 1 0 0] -> [ 0 4 0] ComposeLR(T,S,R): [ 1 0 0] -> [ 0 4 0] STR : [ 1 0 0] -> [ 2 2 0] S(T(R)) : [ 1 0 0] -> [ 2 2 0] ComposeLR(R,T,S): [ 1 0 0] -> [ 2 2 0] TRS : [ 1 0 0] -> [ 1 2 0] T(R(S)) : [ 1 0 0] -> [ 1 2 0] ComposeLR(S,R,T): [ 1 0 0] -> [ 1 2 0]
func (*AffineTransform) Before ¶
func (t *AffineTransform) Before(s *AffineTransform) *AffineTransform
Before returns a composite transform that applies t first, followed by s.
func (*AffineTransform) Inverse ¶
func (t *AffineTransform) Inverse() *AffineTransform
Inverse returns the inverse affine transformation.
func (*AffineTransform) TransformDir ¶
func (t *AffineTransform) TransformDir(dir Vec) Vec
TransformDir applies affine transformation t to vector dir, returning
A x
Directions are invariant against the the translation part of the transform. Use TransformPoint to transform a point, which does undergo translation.
func (*AffineTransform) TransformPoint ¶
func (t *AffineTransform) TransformPoint(x Vec) Vec
TransformPoint applies affine transformation t to point x, returning
A x + b
Use TransformDir to transform a direction (vector).
func (*AffineTransform) WithOrigin ¶
func (t *AffineTransform) WithOrigin(o Vec) *AffineTransform
WithOrigin returns a translated version of t so that o is the new origin (fixed point). E.g.:
Rotate(Vec{}, Ez, θ).WithOrigin(Vec{1,2,0})
rotates around [1, 2, 0] rather than [0, 0, 0]
type Matrix ¶
type Matrix [3]Vec
Matrix is a 3x3 matrix intended for linear transformations.
func UnitMatrix ¶
func UnitMatrix() Matrix
func (*Matrix) Inverse ¶
Inverse returns the inverse matrix.
Example ¶
m := Matrix{{1, 2, 3}, {3, -1, 2}, {2, 3, -1}} inv := m.Inverse() check := inv.Mul(&m) for i := range check { for j, v := range check[i] { if math.Abs(v) < 1e-9 { check[i][j] = 0 } } } fmt.Printf("% 4.3f", check)
Output: [[ 1.000 0.000 0.000] [ 0.000 1.000 0.000] [ 0.000 0.000 1.000]]
func (*Matrix) Mul ¶
Mul performs a Matrix-Matrix multiplication
Example ¶
theta := 45 * math.Pi / 180 c := math.Cos(theta) s := math.Sin(theta) a := Matrix{{c, s, 0}, {-s, c, 0}, {0, 0, 1}} fmt.Printf("% 4.1f", a.Mul(&a))
Output: [[ 0.0 1.0 0.0] [-1.0 0.0 0.0] [ 0.0 0.0 1.0]]
func (*Matrix) MulVec ¶
MulVec performs a Matrix-Vector multiplication
m . vT
Example ¶
theta := 30 * math.Pi / 180 c := math.Cos(theta) s := math.Sin(theta) m := Matrix{{c, s, 0}, {-s, c, 0}, {0, 0, 1}} fmt.Printf("% 3f\n", m.MulVec(Vec{1, 0, 0})) fmt.Printf("% 3f\n", m.MulVec(Vec{0, 1, 0})) fmt.Printf("% 3f\n", m.MulVec(Vec{0, 0, 1}))
Output: [ 0.866025 0.500000 0.000000] [-0.500000 0.866025 0.000000] [ 0.000000 0.000000 1.000000]
type Vec ¶
type Vec [3]float64
Vec is a 3-component vector. Used to represent either points in space or vectors.
Example ¶
a := Vec{1, 2, 3} b := Vec{0, 1, -2} fmt.Printf("% g.Add(% g) = % g\n", a, b, a.Add(b)) fmt.Printf("% g.Cross(% g) = % g\n", a, b, a.Cross(b)) fmt.Printf("% g.Dot(% g) = % g\n", a, b, a.Dot(b)) fmt.Printf("% g.MAdd(2, % g) = % g\n", a, b, a.MAdd(2, b)) fmt.Printf("% g.Sub(% g) = % g\n", a, b, a.Sub(b)) fmt.Printf("% g.IsNaN() = %v\n", a, a.IsNaN()) fmt.Printf("% g.Mul(2) = % g\n", a, a.Mul(2)) fmt.Printf("% g.Len() = % g\n", a, a.Len()) fmt.Printf("% g.Len2() = % 3g\n", a, a.Len2()) fmt.Printf("% g.Normalized()= % g\n", a, a.Normalized())
Output: [ 1 2 3].Add([ 0 1 -2]) = [ 1 3 1] [ 1 2 3].Cross([ 0 1 -2]) = [-7 2 1] [ 1 2 3].Dot([ 0 1 -2]) = -4 [ 1 2 3].MAdd(2, [ 0 1 -2]) = [ 1 4 -1] [ 1 2 3].Sub([ 0 1 -2]) = [ 1 1 5] [ 1 2 3].IsNaN() = false [ 1 2 3].Mul(2) = [ 2 4 6] [ 1 2 3].Len() = 3.7416573867739413 [ 1 2 3].Len2() = 14 [ 1 2 3].Normalized()= [ 0.2672612419124244 0.5345224838248488 0.8017837257372732]
func MakeBasis ¶
MakeBasis constructs an orthonormal basis. I.e. returns y and z so that x, y, and z are mutually orthogonal.
func TriangleNormal ¶
TriangleNormal returns the normal vector of the triangle with vertices a, b, c.
Example ¶
a := Vec{1, 0, 0} b := Vec{2, 0, 0} c := Vec{1, 1, 0} fmt.Println(TriangleNormal(a, b, c))
Output: [0 0 1]
func (Vec) Cross ¶
Cross returns the cross product of a and b, assuming a right-handed space. See https://en.wikipedia.org/wiki/Cross_product#Matrix_notation
func (*Vec) Normalize ¶
func (a *Vec) Normalize()
Normalize scales a to unit length, overwriting the original.
Example ¶
a := Vec{3, 4, 0} a.Normalize() fmt.Printf("% .1f\n", a)
Output: [ 0.6 0.8 0.0]
func (Vec) Normalized ¶
Normalized returns a copy of a that is scaled to unit length.