commonMain.ru.casperix.math.quad_matrix.float64.Matrix4d.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of math Show documentation
Show all versions of math Show documentation
Simple set of geometric and other types
package ru.casperix.math.quad_matrix.float64
import ru.casperix.math.quad_matrix.QuadMatrix
import ru.casperix.math.quad_matrix.QuadMatrixBuilder
import ru.casperix.math.quad_matrix.float32.Matrix4f
import ru.casperix.math.quaternion.float64.QuaternionDouble
import ru.casperix.math.vector.float64.Vector3d
import ru.casperix.misc.toFloatArray
import kotlinx.serialization.Serializable
@Serializable
data class Matrix4d(val data: DoubleArray) : QuadMatrix {
// constructor(vararg data: Double) : this(doubleArrayOf(*data))
init {
if (data.size != 16) throw Error("Source expected 16 elements, but actual ${data.size}")
}
operator fun get(x: Int, y: Int): Double {
return data[x + y * 4]
}
operator fun get(index: Int): Double {
return data[index]
}
fun transform(value: Vector3d): Vector3d {
val m = data
val rx = value.x * m[0] + value.y * m[4] + value.z * m[8] + m[12]
val ry = value.x * m[1] + value.y * m[5] + value.z * m[9] + m[13]
val rz = value.x * m[2] + value.y * m[6] + value.z * m[10] + m[14]
val rw = 1 / (value.x * m[3] + value.y * m[7] + value.z * m[11] + m[15])
return Vector3d(rx * rw, ry * rw, rz * rw)
}
override operator fun times(other: Matrix4d): Matrix4d {
val otherM = other.data
return Matrix4d(
doubleArrayOf(
data[0] * otherM[0] + data[1] * otherM[4] + data[2] * otherM[8] + data[3] * otherM[12],
data[0] * otherM[1] + data[1] * otherM[5] + data[2] * otherM[9] + data[3] * otherM[13],
data[0] * otherM[2] + data[1] * otherM[6] + data[2] * otherM[10] + data[3] * otherM[14],
data[0] * otherM[3] + data[1] * otherM[7] + data[2] * otherM[11] + data[3] * otherM[15],
data[4] * otherM[0] + data[5] * otherM[4] + data[6] * otherM[8] + data[7] * otherM[12],
data[4] * otherM[1] + data[5] * otherM[5] + data[6] * otherM[9] + data[7] * otherM[13],
data[4] * otherM[2] + data[5] * otherM[6] + data[6] * otherM[10] + data[7] * otherM[14],
data[4] * otherM[3] + data[5] * otherM[7] + data[6] * otherM[11] + data[7] * otherM[15],
data[8] * otherM[0] + data[9] * otherM[4] + data[10] * otherM[8] + data[11] * otherM[12],
data[8] * otherM[1] + data[9] * otherM[5] + data[10] * otherM[9] + data[11] * otherM[13],
data[8] * otherM[2] + data[9] * otherM[6] + data[10] * otherM[10] + data[11] * otherM[14],
data[8] * otherM[3] + data[9] * otherM[7] + data[10] * otherM[11] + data[11] * otherM[15],
data[12] * otherM[0] + data[13] * otherM[4] + data[14] * otherM[8] + data[15] * otherM[12],
data[12] * otherM[1] + data[13] * otherM[5] + data[14] * otherM[9] + data[15] * otherM[13],
data[12] * otherM[2] + data[13] * otherM[6] + data[14] * otherM[10] + data[15] * otherM[14],
data[12] * otherM[3] + data[13] * otherM[7] + data[14] * otherM[11] + data[15] * otherM[15],
)
)
}
fun toMatrix4f(): Matrix4f {
return Matrix4f(data.toFloatArray())
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false
other as Matrix4d
if (!data.contentEquals(other.data)) return false
return true
}
override fun hashCode(): Int {
return data.hashCode()
}
override fun determinant(): Double {
return data[i30] * data[i21] * data[i12] * data[i03] - data[i20] * data[i31] * data[i12] * data[i03] - data[i30] * data[i11] * data[i22] * data[i03] + data[i10] * data[i31] * data[i22] * data[i03] + data[i20] * data[i11] * data[i32] * data[i03] - data[i10] * data[i21] * data[i32] * data[i03] - data[i30] * data[i21] * data[i02] * data[i13] + data[i20] * data[i31] * data[i02] * data[i13] + data[i30] * data[i01] * data[i22] * data[i13] - data[i00] * data[i31] * data[i22] * data[i13] - data[i20] * data[i01] * data[i32] * data[i13] + data[i00] * data[i21] * data[i32] * data[i13] + data[i30] * data[i11] * data[i02] * data[i23] - data[i10] * data[i31] * data[i02] * data[i23] - data[i30] * data[i01] * data[i12] * data[i23] + data[i00] * data[i31] * data[i12] * data[i23] + data[i10] * data[i01] * data[i32] * data[i23] - data[i00] * data[i11] * data[i32] * data[i23] - data[i20] * data[i11] * data[i02] * data[i33] + data[i10] * data[i21] * data[i02] * data[i33] + data[i20] * data[i01] * data[i12] * data[i33] - data[i00] * data[i21] * data[i12] * data[i33] - data[i10] * data[i01] * data[i22] * data[i33] + data[i00] * data[i11] * data[i22] * data[i33]
}
override fun inverse(): Matrix4d {
val l_det = data[3] * data[6] * data[9] * data[12] -
data[2] * data[7] * data[9] * data[12] -
data[3] * data[5] * data[10] * data[12] +
data[1] * data[7] * data[10] * data[12] +
data[2] * data[5] * data[11] * data[12] -
data[1] * data[6] * data[11] * data[12] -
data[3] * data[6] * data[8] * data[13] +
data[2] * data[7] * data[8] * data[13] +
data[3] * data[4] * data[10] * data[13] -
data[0] * data[7] * data[10] * data[13] -
data[2] * data[4] * data[11] * data[13] +
data[0] * data[6] * data[11] * data[13] +
data[3] * data[5] * data[8] * data[14] -
data[1] * data[7] * data[8] * data[14] -
data[3] * data[4] * data[9] * data[14] +
data[0] * data[7] * data[9] * data[14] +
data[1] * data[4] * data[11] * data[14] -
data[0] * data[5] * data[11] * data[14] -
data[2] * data[5] * data[8] * data[15] +
data[1] * data[6] * data[8] * data[15] +
data[2] * data[4] * data[9] * data[15] -
data[0] * data[6] * data[9] * data[15] -
data[1] * data[4] * data[10] * data[15] +
data[0] * data[5] * data[10] * data[15]
if (l_det == 0.0) throw RuntimeException("non-indataertible matrix");
val m0 =
data[9] * data[14] * data[7] - data[13] * data[10] * data[7] + data[13] * data[6] * data[11] - data[5] * data[14] * data[11] - data[9] * data[6] * data[15] + data[5] * data[10] * data[15]
val m4 =
data[12] * data[10] * data[7] - data[8] * data[14] * data[7] - data[12] * data[6] * data[11] + data[4] * data[14] * data[11] + data[8] * data[6] * data[15] - data[4] * data[10] * data[15]
val m8 =
data[8] * data[13] * data[7] - data[12] * data[9] * data[7] + data[12] * data[5] * data[11] - data[4] * data[13] * data[11] - data[8] * data[5] * data[15] + data[4] * data[9] * data[15]
val m12 =
data[12] * data[9] * data[6] - data[8] * data[13] * data[6] - data[12] * data[5] * data[10] + data[4] * data[13] * data[10] + data[8] * data[5] * data[14] - data[4] * data[9] * data[14]
val m1 =
data[13] * data[10] * data[3] - data[9] * data[14] * data[3] - data[13] * data[2] * data[11] + data[1] * data[14] * data[11] + data[9] * data[2] * data[15] - data[1] * data[10] * data[15]
val m5 =
data[8] * data[14] * data[3] - data[12] * data[10] * data[3] + data[12] * data[2] * data[11] - data[0] * data[14] * data[11] - data[8] * data[2] * data[15] + data[0] * data[10] * data[15]
val m9 =
data[12] * data[9] * data[3] - data[8] * data[13] * data[3] - data[12] * data[1] * data[11] + data[0] * data[13] * data[11] + data[8] * data[1] * data[15] - data[0] * data[9] * data[15]
val m13 =
data[8] * data[13] * data[2] - data[12] * data[9] * data[2] + data[12] * data[1] * data[10] - data[0] * data[13] * data[10] - data[8] * data[1] * data[14] + data[0] * data[9] * data[14]
val m2 =
data[5] * data[14] * data[3] - data[13] * data[6] * data[3] + data[13] * data[2] * data[7] - data[1] * data[14] * data[7] - data[5] * data[2] * data[15] + data[1] * data[6] * data[15]
val m6 =
data[12] * data[6] * data[3] - data[4] * data[14] * data[3] - data[12] * data[2] * data[7] + data[0] * data[14] * data[7] + data[4] * data[2] * data[15] - data[0] * data[6] * data[15]
val m10 =
data[4] * data[13] * data[3] - data[12] * data[5] * data[3] + data[12] * data[1] * data[7] - data[0] * data[13] * data[7] - data[4] * data[1] * data[15] + data[0] * data[5] * data[15]
val m14 =
data[12] * data[5] * data[2] - data[4] * data[13] * data[2] - data[12] * data[1] * data[6] + data[0] * data[13] * data[6] + data[4] * data[1] * data[14] - data[0] * data[5] * data[14]
val m3 =
data[9] * data[6] * data[3] - data[5] * data[10] * data[3] - data[9] * data[2] * data[7] + data[1] * data[10] * data[7] + data[5] * data[2] * data[11] - data[1] * data[6] * data[11]
val m7 =
data[4] * data[10] * data[3] - data[8] * data[6] * data[3] + data[8] * data[2] * data[7] - data[0] * data[10] * data[7] - data[4] * data[2] * data[11] + data[0] * data[6] * data[11]
val m11 =
data[8] * data[5] * data[3] - data[4] * data[9] * data[3] - data[8] * data[1] * data[7] + data[0] * data[9] * data[7] + data[4] * data[1] * data[11] - data[0] * data[5] * data[11]
val m15 =
data[4] * data[9] * data[2] - data[8] * data[5] * data[2] + data[8] * data[1] * data[6] - data[0] * data[9] * data[6] - data[4] * data[1] * data[10] + data[0] * data[5] * data[10]
val inv_det = 1.0 / l_det;
return Matrix4d(
doubleArrayOf(
m0 * inv_det,
m1 * inv_det,
m2 * inv_det,
m3 * inv_det,
m4 * inv_det,
m5 * inv_det,
m6 * inv_det,
m7 * inv_det,
m8 * inv_det,
m9 * inv_det,
m10 * inv_det,
m11 * inv_det,
m12 * inv_det,
m13 * inv_det,
m14 * inv_det,
m15 * inv_det,
)
)
}
override fun transpose(): Matrix4d {
return Matrix4d(
doubleArrayOf(
data[i00], data[i01], data[i02], data[i03],
data[i10], data[i11], data[i12], data[i13],
data[i20], data[i21], data[i22], data[i23],
data[i30], data[i31], data[i32], data[i33],
)
)
}
companion object : QuadMatrixBuilder {
private val i00 = 0
private val i10 = 1
private val i20 = 2
private val i30 = 3
private val i01 = 4
private val i11 = 5
private val i21 = 6
private val i31 = 7
private val i02 = 8
private val i12 = 9
private val i22 = 10
private val i32 = 11
private val i03 = 12
private val i13 = 13
private val i23 = 14
private val i33 = 15
fun byIndex(factory: (Int) -> Double): Matrix4d {
return Matrix4d(DoubleArray(16) { factory(it) })
}
fun fromValues(vararg values: Double): Matrix4d {
return byIndex { values.getOrNull(it) ?: 0.0 }
}
val IDENTITY = byIndex { if (it % 5 == 0) 1.0 else 0.0 }
override fun translate(value: Vector3d): Matrix4d {
return fromValues(
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
value.x, value.y, value.z, 1.0
)
}
override fun scale(value: Vector3d): Matrix4d {
return fromValues(
value.x, 0.0, 0.0, 0.0,
0.0, value.y, 0.0, 0.0,
0.0, 0.0, value.z, 0.0,
0.0, 0.0, 0.0, 1.0
)
}
override fun rotate(value: QuaternionDouble): Matrix4d {
val xx = value.x * value.x
val yy = value.y * value.y
val zz = value.z * value.z
val xy = value.x * value.y
val zw = value.z * value.w
val zx = value.z * value.x
val yw = value.y * value.w
val yz = value.y * value.z
val xw = value.x * value.w
return Matrix4d(
doubleArrayOf(
/*0*/ (1.0 - (2.0 * (yy + zz))),
/*1*/ 2.0 * (xy + zw),
/*2*/ 2.0 * (zx - yw),
/*3*/ 0.0,
/*4*/ 2.0 * (xy - zw),
/*5*/ (1.0 - (2.0 * (zz + xx))),
/*6*/ 2.0 * (yz + xw),
/*7*/ 0.0,
/*8*/ 2.0 * (zx + yw),
/*9*/ 2.0 * (yz - xw),
/*10*/ (1.0 - (2.0 * (yy + xx))),
/*11*/ 0.0,
/*12*/ 0.0,
/*13*/ 0.0,
/*14*/ 0.0,
/*15*/ 1.0
)
)
}
fun compose(translate: Vector3d, scale: Vector3d, rotation: QuaternionDouble): Matrix4d {
val xx = rotation.x * rotation.x
val yy = rotation.y * rotation.y
val zz = rotation.z * rotation.z
val xy = rotation.x * rotation.y
val zw = rotation.z * rotation.w
val zx = rotation.z * rotation.x
val yw = rotation.y * rotation.w
val yz = rotation.y * rotation.z
val xw = rotation.x * rotation.w
return Matrix4d(
doubleArrayOf(
/*0*/ (1.0 - (2.0 * (yy + zz))) * scale.x,
/*1*/ 2.0 * (xy + zw) * scale.x,
/*2*/ 2.0 * (zx - yw) * scale.x,
/*3*/ 0.0,
/*4*/ 2.0 * (xy - zw) * scale.y,
/*5*/ (1.0 - (2.0 * (zz + xx))) * scale.y,
/*6*/ 2.0 * (yz + xw) * scale.y,
/*7*/ 0.0,
/*8*/ 2.0 * (zx + yw) * scale.z,
/*9*/ 2.0 * (yz - xw) * scale.z,
/*10*/ (1.0 - (2.0 * (yy + xx))) * scale.z,
/*11*/ 0.0,
/*12*/ translate.x,
/*13*/ translate.y,
/*14*/ translate.z,
/*15*/ 1.0
)
)
}
fun createByAxis(xAxis: Vector3d, yAxis: Vector3d, zAxis: Vector3d): Matrix4d {
return fromValues(
xAxis.x, yAxis.x, zAxis.x, 0.0,
xAxis.y, yAxis.y, zAxis.y, 0.0,
xAxis.z, yAxis.z, zAxis.z, 0.0,
0.0, 0.0, 0.0, 1.0
)
}
fun fromQuaternion(quaternion: QuaternionDouble): Matrix4d {
val xx = quaternion.x * quaternion.x
val yy = quaternion.y * quaternion.y
val zz = quaternion.z * quaternion.z
val xy = quaternion.x * quaternion.y
val zw = quaternion.z * quaternion.w
val zx = quaternion.z * quaternion.x
val yw = quaternion.y * quaternion.w
val yz = quaternion.y * quaternion.z
val xw = quaternion.x * quaternion.w
return fromValues(
/*0*/ 1.0 - (2.0 * (yy + zz)),
/*1*/ 2.0 * (xy + zw),
/*2*/ 2.0 * (zx - yw),
/*3*/ 0.0,
/*4*/ 2.0 * (xy - zw),
/*5*/ 1.0 - (2.0 * (zz + xx)),
/*6*/ 2.0 * (yz + xw),
/*7*/ 0.0,
/*8*/ 2.0 * (zx + yw),
/*9*/ 2.0 * (yz - xw),
/*10*/ 1.0 - (2.0 * (yy + xx)),
/*11*/ 0.0,
/*12*/ 0.0,
/*13*/ 0.0,
/*14*/ 0.0,
/*15*/ 1.0
)
}
fun orthographic(
left: Double,
right: Double,
bottom: Double,
top: Double,
near: Double,
far: Double
): Matrix4d {
val tx = -(right + left) / (right - left)
val ty = -(top + bottom) / (top - bottom)
val tz = -(far + near) / (far - near)
return Matrix4d(
doubleArrayOf(
2.0 / (right - left), 0.0, 0.0, 0.0,
0.0, 2.0 / (top - bottom), 0.0, 0.0,
0.0, 0.0, -2.0 / (far - near), 0.0,
tx, ty, tz, 0.0,
)
)
}
}
}