Home My Page Projects Code Snippets Project Openings 3D graphics for Standard ML
 Summary Activity SCM

# SCM Repository

[sml3d] View of /trunk/sml3d/src/sml3d/base/matrix3f.sml
 [sml3d] / trunk / sml3d / src / sml3d / base / matrix3f.sml

# View of /trunk/sml3d/src/sml3d/base/matrix3f.sml

Wed Jan 18 02:21:03 2012 UTC (7 years ago) by jhr
File size: 8035 byte(s)
```  Working on new SML3d core libraries
```
```(* matrix3f.sml
*
* COPYRIGHT (c) 2012 The SML3d Project (http://sml3d.cs.uchicago.edu)
*
* Single-precision 3x3 matrices
*)

structure Matrix3f :> MATRIX3 where type flt = SML3dTypes.float
= struct

type flt = SML3dTypes.float
type vec3 = SML3dTypes.vec3f

val epsilon = Double.epsilon

(* represented in column-major order, since that is what OpenGL LoadMatrix
* expects.
*)
datatype mat3 = M of flt Vector.vector

(* index = 3*(c-1) + r - 1 = 3*c + r - 4 *)
val usub = Unsafe.Vector.sub
fun ! (a : flt Vector.vector, (r, c)) = usub(a, 3*c + r - 4)
infix 8 !

fun new {m11, m12, m13, m21, m22, m23, m31, m32, m33} =
M(Vector.fromList [m11, m21, m31, m12, m22, m32,  m13, m23, m33])

val mat = new

(* convert 9-element vector to matrix in column-major order *)
fun fromVector v = if (Vector.length v = 9) then M v else raise Size
(* convert 9-element vector to matrix in row-major order *)
fun fromVectorT v = if (Vector.length v = 9)
then M(Vector.fromList [
v!(1,1), v!(1,2), v!(1,3),	(* column 1 *)
v!(2,1), v!(2,2), v!(2,3),	(* column 2 *)
v!(3,1), v!(3,2), v!(3,3)		(* column 3 *)
])
else raise Size

(* returns matrix as flat vector in column-major order *)
fun toVector (M v) = v
(* returns matrix as flat vector in row-major order *)
fun toVectorT (M v) = Vector.fromList [
v!(1,1), v!(1,2), v!(1,3),
v!(2,1), v!(2,2), v!(2,3),
v!(3,1), v!(3,2), v!(3,3)
]

(* create a matrix from three column vectors *)
fun fromCols (c1 : vec3, c2 : vec3, c3 : vec3) = new {
m11 = #1 c1, m12 = #1 c2, m13 = #1 c3,
m21 = #2 c1, m22 = #2 c2, m23 = #2 c3,
m31 = #3 c1, m32 = #3 c2, m33 = #3 c3
}
(* create a matrix from three row vectors *)
fun fromRows (r1 : vec3, r2 : vec3, r3 : vec3) = new {
m11 = #1 r1, m12 = #2 r1, m13 = #3 r1,
m21 = #1 r2, m22 = #2 r2, m23 = #3 r2,
m31 = #1 r3, m32 = #2 r3, m33 = #3 r3
}

(* return the columns of the matrix *)
fun toCols (M v) = (
(v!(1,1), v!(2,1), v!(3,1)),	(* column 1 *)
(v!(1,2), v!(2,2), v!(3,2)),	(* column 2 *)
(v!(1,3), v!(2,3), v!(3,3))		(* column 3 *)
)
(* return the rows of the matrix *)
fun toRows (M v) = (
(v!(1,1), v!(1,2), v!(1,3)),	(* row 1 *)
(v!(2,1), v!(2,2), v!(2,3)),	(* row 2 *)
(v!(3,1), v!(3,2), v!(3,3))		(* row 3 *)
)

(* project specific columns/rows *)
fun col1 (M v) = (v!(1,1), v!(2,1), v!(3,1))
fun col2 (M v) = (v!(1,2), v!(2,2), v!(3,2))
fun col3 (M v) = (v!(1,3), v!(2,3), v!(3,3))
fun row1 (M v) = (v!(1,1), v!(1,2), v!(1,3))
fun row2 (M v) = (v!(2,1), v!(2,2), v!(2,3))
fun row3 (M v) = (v!(3,1), v!(3,2), v!(3,3))

val identity = new {
m11 = 1.0, m12 = 0.0, m13 = 0.0,
m21 = 0.0, m22 = 1.0, m23 = 0.0,
m31 = 0.0, m32 = 0.0, m33 = 1.0
}

fun isoscale s = new {
m11 = s,   m12 = 0.0, m13 = 0.0,
m21 = 0.0, m22 = s,   m23 = 0.0,
m31 = 0.0, m32 = 0.0, m33 = s
}

fun scale (x, y, z) = new {
m11 = x,   m12 = 0.0, m13 = 0.0,
m21 = 0.0, m22 = y,   m23 = 0.0,
m31 = 0.0, m32 = 0.0, m33 = z
}

(* rotation around X axis (in degrees) *)
fun rotateX angle = let
val s = Float.sin angle
val c = Float.cos angle
in
new {
m11 = 1.0, m12 = 0.0, m13 = 0.0,
m21 = 0.0, m22 = c,   m23 = ~s,
m31 = 0.0, m32 = s,   m33 = c
}
end

(* rotation around Y axis (in degrees) *)
fun rotateY angle = let
val s = Float.sin angle
val c = Float.cos angle
in
new {
m11 = c,   m12 = 0.0, m13 = s,
m21 = 0.0, m22 = 1.0, m23 = 0.0,
m31 = ~s,  m32 = 0.0, m33 = c
}
end

(* rotation around Z axis (in degrees) *)
fun rotateZ angle = let
val s = Float.sin angle
val c = Float.cos angle
in
new {
m11 = c,   m12 = ~s,  m13 = 0.0,
m21 = s,   m22 = c,   m23 = 0.0,
m31 = 0.0, m32 = 0.0, m33 = 1.0
}
end

(* rotation around an axis (in degrees) *)
fun rotate (angle, (x, y, z)) = let
val s = Float.sin angle
val c = Float.cos angle
val c' = 1.0 - c
in
new {
m11 = x*x*c'+c,   m12 = x*y*c'-z*s, m13 = x*z*c'+y*s,
m21 = y*x*c'+z*s, m22 = y*y*c'+c,   m23 = y*z*c'-x*s,
m31 = x*z*c'-y*s, m32 = y*z*c'+x*s, m33 = z*z*c'+c
}
end

(* arithmetic *)
fun add (M v1, M v2) =
M(Vector.tabulate(9, fn i => usub(v1, i) + usub(v2, i)))
fun adds (M v1, s, M v2) =
M(Vector.tabulate(9, fn i => usub(v1, i) + s*usub(v2, i)))
fun sub (M v1, M v2) =
M(Vector.tabulate(9, fn i => usub(v1, i) - usub(v2, i)))
fun negate (M v) = M(Vector.map ~ v)

(* multiply a scalar times a matrix *)
fun sxm (s, M v) = M(Vector.map (fn x => s*x) v)

(* multiply a matrix times a column vector *)
fun mxv (M mat, (x, y, z)) = let
fun m arg = mat ! arg
in (
m(1,1) * x + m(1,2) * y + m(1,3) * z,
m(2,1) * x + m(2,2) * y + m(2,3) * z,
m(3,1) * x + m(3,2) * y + m(3,3) * z
) end

(* multiply a row vector times a matrix *)
fun vxm ((x, y, z), M mat) = let
fun m arg = mat ! arg
in (
m(1,1) * x + m(2,1) * y + m(3,1) * z,
m(1,2) * x + m(2,2) * y + m(3,2) * z,
m(1,3) * x + m(2,3) * y + m(3,3) * z
) end

(* matrix transpose *)
fun transpose (M mat) = let
fun m arg = mat ! arg
in
new {
m11 = m(1,1), m12 = m(2,1), m13 = m(3,1),
m21 = m(1,2), m22 = m(2,2), m23 = m(3,2),
m31 = m(1,3), m32 = m(2,3), m33 = m(3,3)
}
end

(* matrix multiplication *)
fun mxm (M aMat, M bMat) = let
fun a arg = aMat ! arg
fun b arg = bMat ! arg
in
new {
m11 = a(1,1) * b(1,1) + a(1,2) * b(2,1) + a(1,3) * b(3,1),
m12 = a(1,1) * b(1,2) + a(1,2) * b(2,2) + a(1,3) * b(3,2),
m13 = a(1,1) * b(1,3) + a(1,2) * b(2,3) + a(1,3) * b(3,3),
m21 = a(2,1) * b(1,1) + a(2,2) * b(2,1) + a(2,3) * b(3,1),
m22 = a(2,1) * b(1,2) + a(2,2) * b(2,2) + a(2,3) * b(3,2),
m23 = a(2,1) * b(1,3) + a(2,2) * b(2,3) + a(2,3) * b(3,3),
m31 = a(3,1) * b(1,1) + a(3,2) * b(2,1) + a(3,3) * b(3,1),
m32 = a(3,1) * b(1,2) + a(3,2) * b(2,2) + a(3,3) * b(3,2),
m33 = a(3,1) * b(1,3) + a(3,2) * b(2,3) + a(3,3) * b(3,3)
}
end

(* matrix transpose *)
fun transpose (M mat) = let
fun m arg = mat ! arg
in
new {
m11 = m(1,1), m12 = m(2,1), m13 = m(3,1),
m21 = m(1,2), m22 = m(2,2), m23 = m(3,2),
m31 = m(1,3), m32 = m(2,3), m33 = m(3,3)
}
end

fun det (M mat) = let
fun m arg = mat ! arg
fun t (i,j,k) = m(1,i)*m(2,j)*m(3,k)
in
t(1,2,3) - t(1,3,2) - t(2,1,3) + t(2,3,1) + t(3,1,2) - t(3,2,1)
end

fun trace (M mat) = mat!(1,1) + mat!(2,2) + mat!(3,3)

fun inverse (M mat) = let
fun m arg = FP.ftod(mat ! arg)
(* 2x2 determinant *)
fun det2 (a, b, c, d) = a*d - b*c
(* 2x2 subdeterminants *)
val sd11 = det2 (m(2,2), m(2,3), m(3,2), m(3,3))
val sd12 = det2 (m(1,3), m(1,2), m(3,3), m(3,2))
val sd13 = det2 (m(1,2), m(1,3), m(2,2), m(2,3))
val sd21 = det2 (m(2,3), m(2,1), m(3,3), m(3,1))
val sd22 = det2 (m(1,1), m(1,3), m(3,1), m(3,3))
val sd23 = det2 (m(1,3), m(1,1), m(2,3), m(2,1))
val sd31 = det2 (m(2,1), m(2,2), m(3,1), m(3,2))
val sd32 = det2 (m(1,2), m(1,1), m(3,2), m(3,1))
val sd33 = det2 (m(1,1), m(1,2), m(2,1), m(2,2))
(* determinant *)
val det = m(1,1)*sd11 - m(1,2)*sd12 + m(1,3)*sd13
in
if ((det > ~epsilon) andalso (det < epsilon))
then NONE
else let
val detInv = 1.0 / det
in
SOME(new {
m11 = FP.dtof(sd11*detInv),
m21 = FP.dtof(sd12*detInv),
m31 = FP.dtof(sd13*detInv),
m12 = FP.dtof(sd21*detInv),
m22 = FP.dtof(sd22*detInv),
m32 = FP.dtof(sd23*detInv),
m13 = FP.dtof(sd31*detInv),
m23 = FP.dtof(sd32*detInv),
m33 = FP.dtof(sd33*detInv)
})
end
end

end
```