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
ViewVC logotype

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 726 - (download) (annotate)
Fri Jan 22 02:37:06 2010 UTC (8 years, 10 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)
 * All rights reserved.
 *
 * 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 angle = Double.toRadians angle
	  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

root@smlnj-gforge.cs.uchicago.edu
ViewVC Help
Powered by ViewVC 1.0.0