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

# SCM Repository

[sml3d] View of /trunk/sml3d/src/base/common/matrix2d.sml
 [sml3d] / trunk / sml3d / src / base / common / matrix2d.sml

# View of /trunk/sml3d/src/base/common/matrix2d.sml

Fri Jan 22 02:37:06 2010 UTC (9 years, 3 months ago) by jhr
File size: 5215 byte(s)
```  Migrating 4D vector modules to use VEC4 signature
```
```(* matrix2d.sml
*
* COPYRIGHT (c) 2010 John Reppy (http://cs.uchicago.edu/~jhr)
*
* Double-precision 2x2 matrix types and operations.
*)

structure Matrix2d : MATRIX2 where type flt = Double.flt
= struct

structure V = Vec2d

type flt = V.flt
type vec2 = V.vec2

val epsilon = Double.epsilon

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

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

fun new {m11 : flt, m12 : flt, m21 : flt, m22 : flt} =
M(Vector.fromList[m11, m21, m12, m22])

val mat = new

(* convert 4-element vector to matrix in column-major order *)
fun fromVector v = if (Vector.length v = 4) then M v else raise Size
(* convert 4-element vector to matrix in row-major order *)
fun fromVectorT v = if (Vector.length v = 4)
then M(Vector.fromList [
v!(1,1), v!(1,2),	(* column 1 *)
v!(2,1), v!(2,2)	(* column 2 *)
])
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!(2,1), v!(2,2)
]

(* create a matrix from two column vectors *)
fun fromCols (c1 : vec2, c2 : vec2) = new {
m11 = #x c1, m12 = #x c2,
m21 = #y c1, m22 = #y c2
}
(* create a matrix from two row vectors *)
fun fromRows (r1 : vec2, r2 : vec2) = new {
m11 = #x r1, m12 = #y r1,
m21 = #x r2, m22 = #y r2
}

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

(* project specific columns/rows *)
fun col1 (M v) = {x = v!(1,1), y = v!(2,1)}
fun col2 (M v) = {x = v!(1,2), y = v!(2,2)}
fun row1 (M v) = {x = v!(1,1), y = v!(1,2)}
fun row2 (M v) = {x = v!(2,1), y = v!(2,2)}

(* standard matrices *)
val identity = new {
m11 = 1.0, m12 = 0.0,
m21 = 0.0, m22 = 1.0
}

fun isoscale s = new {
m11 = s,   m12 = 0.0,
m21 = 0.0, m22 = s
}

fun scale {x, y} = new {
m11 = x,   m12 = 0.0,
m21 = 0.0, m22 = y
}

fun rotate angle = let
val s = Double.sin angle
val c = Double.cos angle
in
new {
m11 = c, m12 = ~s,
m21 = s, m22 = c
}
end

val reflectX = new {
m11 = 1.0, m12 = 0.0,
m21 = 0.0, m22 = ~1.0
}

val reflectY = new {
m11 = ~1.0, m12 = 0.0,
m21 = 0.0, m22 = 1.0
}

(* reflect points around the given axis.  The transform matrix has the effect
* of mapping a point p to p + 2*perp_a(p), where "a" is the normalized axis
* vector and perp_a(p) is the component of p that is perpendicular to a.
*)
fun reflect axis = let
val {x, y} = V.normalize axis
val xy = ~2.0*x*y
in
new {
m11 = 3.0 - 2.0*x*x, m12 = xy,
m21 = xy, m22 = 3.0 - 2.0*y*y
}
end

val perp = new {
m11 = 0.0, m12 = ~1.0,
m21 = 1.0, m22 = 0.0
}

(* arithmetic *)
fun add (M v1, M v2) =
M(Vector.tabulate(4, fn i => usub(v1, i) + usub(v2, i)))
fun adds (M v1, s, M v2) =
M(Vector.tabulate(4, fn i => usub(v1, i) + s*usub(v2, i)))
fun sub (M v1, M v2) =
M(Vector.tabulate(4, 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}) = let
fun m arg = mat ! arg
in {
x = m(1,1) * x + m(1,2) * y,
y = m(2,1) * x + m(2,2) * y
} end

(* multiply a row vector times a matrix *)
fun vxm ({x, y}, M mat) = let
fun m arg = mat ! arg
in {
x = m(1,1) * x + m(2,1) * y,
y = m(1,2) * x + m(2,2) * y
} 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),
m12 = a(1,1) * b(1,2) + a(1,2) * b(2,2),
m21 = a(2,1) * b(1,1) + a(2,2) * b(2,1),
m22 = a(2,1) * b(1,2) + a(2,2) * b(2,2)
}
end

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

fun det (M v) = v!(1,1) * v!(2,2) - v!(2,1) * v!(1,2)

fun trace (M v) = v!(1, 1) + v!(2, 2)

fun inverse (M mat) = let
fun m arg = mat ! arg
val a = m(1,1)
val b = m(1,2)
val c = m(2,1)
val d = m(2,2)
val det = a*d - b*c
in
if (Double.abs det <= epsilon)
then NONE
else let
val invDet = 1.0 / det
in
SOME(new{
m11 = invDet * d, m12 = ~invDet * b,
m21 = ~invDet * c, m22 = invDet * a
})
end
end

end
```