-
Notifications
You must be signed in to change notification settings - Fork 0
/
Matrixd.scala
92 lines (77 loc) · 2.47 KB
/
Matrixd.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package planck
/** A matrix made of column vectors.
*/
case class Matrixd(entries: Seq[Vecd]) {
val sizeX = entries.size
val sizeY = if(entries.isEmpty) 0 else entries.head.size
def apply(i: Int): Vecd = entries(i)
def apply(x: Int, y: Int): Double = entries(x)(y)
def ~=(that: Any) = that match {
case t: Matrixd if sizeX == t.sizeX && sizeY == t.sizeY =>
t.entries.zip(entries).forall{case(x, y) => x ~= y}
case _ => false
}
private def singleVecMult(vec: Vecd) = {
Seq.tabulate(sizeY){i =>
Seq.tabulate(sizeX){k => entries(k)(i) * vec(k) }.fold(0.0){_+_}
}
}
def *(m: Matrixd) = {
if(sizeX != m.sizeY)
throw new SizeMismatchException
val cols = m.entries.map(singleVecMult)
Matrixd(cols.map{Vecd(_)})
}
def *(vec: Vecd) = {
if(sizeX != vec.size)
throw new SizeMismatchException
Vecd(singleVecMult(vec))
}
/** Apply self, a transformation matrix, to vec.
*
* @param vec The vector to apply the transformation to. This should be a
* 3d vector.
*/
def transform(vec: Vecd) = {
if(sizeX != 4 || sizeY != 4 || vec.size != 3)
throw new SizeMismatchException
val vec4d = Vecd(vec.entries :+ 1.0)
val transformed4d = this * vec4d
Vecd.n(
transformed4d(0) / transformed4d(3),
transformed4d(1) / transformed4d(3),
transformed4d(2) / transformed4d(3)
)
}
}
object Matrixd {
def fill(x: Int, y: Int, v: Double = 0.0) = Matrixd(Seq.fill(x){Vecd.fill(y, v)})
def id(n: Int) = Matrixd(Seq.tabulate(n){x => Vecd(Seq.tabulate(n){y => if(x == y) 1 else 0})})
def n(e: Vecd*) = Matrixd(e)
def perspectiveFOV(fov: Double, aspectRatio: Double, near: Double, far: Double) = {
// based on https://msdn.microsoft.com/bb281728
val h = 1.0 / Math.tan(fov / 2)
val w = h / aspectRatio
val nearMinusFarInverse = 1 / (near - far)
val farDist = (far + near) * nearMinusFarInverse
val farDist2 = 2 * far * near * nearMinusFarInverse
val c1 = Vecd.n(w, 0, 0, 0)
val c2 = Vecd.n(0, h, 0, 0)
val c3 = Vecd.n(0, 0, farDist, -1)
val c4 = Vecd.n(0, 0, farDist2, 0)
Matrixd.n(c1, c2, c3, c4)
}
def translation(x: Double, y: Double, z: Double) = Matrixd.n(
Vecd.n(1,0,0,0),
Vecd.n(0,1,0,0),
Vecd.n(0,0,1,0),
Vecd.n(x,y,z,1)
)
def scale(x: Double, y: Double, z: Double) = Matrixd.n(
Vecd.n(x,0,0,0),
Vecd.n(0,y,0,0),
Vecd.n(0,0,z,0),
Vecd.n(0,0,0,1)
)
def scaleAll(s: Double) = scale(s, s, s)
}