All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.earth.worldwind.geom.Matrix3.kt Maven / Gradle / Ivy

Go to download

The WorldWind Kotlin SDK (WWK) includes the library, examples and tutorials for building multiplatform 3D virtual globe applications for Android, Web and Java.

There is a newer version: 1.5.23
Show newest version
package earth.worldwind.geom

import earth.worldwind.util.Logger.ERROR
import earth.worldwind.util.Logger.logMessage
import kotlin.math.cos
import kotlin.math.sin

/**
 * 3 x 3 matrix in row-major order.
 */
open class Matrix3 private constructor(
    /**
     * The matrix's components, stored in row-major order.
     */
    val m: DoubleArray
){
    companion object {
        /**
         * The components for the 3 x 3 identity matrix, stored in row-major order.
         */
        internal val identity = doubleArrayOf(
            1.0, 0.0, 0.0,
            0.0, 1.0, 0.0,
            0.0, 0.0, 1.0
        )
    }

    /**
     * Constructs a 3 x 3 identity matrix.
     */
    constructor(): this(identity.copyOf())

    /**
     * Constructs a 3 x 3 matrix with specified components.
     *
     * @param m11 matrix element at row 1, column 1
     * @param m12 matrix element at row 1, column 2
     * @param m13 matrix element at row 1, column 3
     * @param m21 matrix element at row 2, column 1
     * @param m22 matrix element at row 2, column 2
     * @param m23 matrix element at row 2, column 3
     * @param m31 matrix element at row 3, column 1
     * @param m32 matrix element at row 3, column 2
     * @param m33 matrix element at row 3, column 3
     */
    constructor(
        m11: Double, m12: Double, m13: Double,
        m21: Double, m22: Double, m23: Double,
        m31: Double, m32: Double, m33: Double
    ): this(doubleArrayOf(m11, m12, m13, m21, m22, m23, m31, m32, m33))

    /**
     * Constructs a 3 x 3 matrix with the components of a specified matrix.
     *
     * @param matrix the matrix specifying the new components
     */
    constructor(matrix: Matrix3): this(matrix.m.copyOf())

    /**
     * Sets this 3 x 3 matrix to specified components.
     *
     * @param m11 matrix element at row 1, column 1
     * @param m12 matrix element at row 1, column 2
     * @param m13 matrix element at row 1, column 3
     * @param m21 matrix element at row 2, column 1
     * @param m22 matrix element at row 2, column 2
     * @param m23 matrix element at row 2, column 3
     * @param m31 matrix element at row 3, column 1
     * @param m32 matrix element at row 3, column 2
     * @param m33 matrix element at row 3, column 3
     *
     * @return this matrix set to the specified components
     */
    fun set(
        m11: Double, m12: Double, m13: Double,
        m21: Double, m22: Double, m23: Double,
        m31: Double, m32: Double, m33: Double
    ) = apply {
        m[0] = m11
        m[1] = m12
        m[2] = m13
        m[3] = m21
        m[4] = m22
        m[5] = m23
        m[6] = m31
        m[7] = m32
        m[8] = m33
    }

    /**
     * Sets this 3 x 3 matrix to the components of a specified matrix.
     *
     * @param matrix the matrix specifying the new components
     *
     * @return this matrix with its components set to that of the specified matrix
     */
    fun copy(matrix: Matrix3) = apply { matrix.m.copyInto(m) }

    /**
     * Sets the translation components of this matrix to specified values.
     *
     * @param x the X translation component
     * @param y the Y translation component
     *
     * @return this matrix with its translation components set to the specified values and all other components
     * unmodified
     */
    fun setTranslation(x: Double, y: Double) = apply {
        m[2] = x
        m[5] = y
    }

    /**
     * Sets the rotation components of this matrix to a specified angle. Positive angles are interpreted as
     * counter-clockwise rotation.
     *
     * @param angle the angle of rotation
     *
     * @return this matrix with its rotation components set to the specified values and all other components unmodified
     */
    fun setRotation(angle: Angle) = apply {
        val c = cos(angle.inRadians)
        val s = sin(angle.inRadians)
        m[0] = c
        m[1] = -s
        m[3] = s
        m[4] = c
    }

    /**
     * Sets the scale components of this matrix to specified values.
     *
     * @param xScale the X scale component
     * @param yScale the Y scale component
     *
     * @return this matrix with its scale components set to the specified values and all other components unmodified
     */
    fun setScale(xScale: Double, yScale: Double) = apply {
        m[0] = xScale
        m[4] = yScale
    }

    /**
     * Sets this matrix to the 3 x 3 identity matrix.
     *
     * @return this matrix, set to the identity matrix
     */
    fun setToIdentity() = apply { identity.copyInto(m) }

    /**
     * Sets this matrix to a translation matrix with specified translation components.
     *
     * @param x the X translation component
     * @param y the Y translation component
     *
     * @return this matrix with its translation components set to those specified and all other components set to that
     * of an identity matrix
     */
    fun setToTranslation(x: Double, y: Double) = apply {
        m[0] = 1.0
        m[1] = 0.0
        m[2] = x
        m[3] = 0.0
        m[4] = 1.0
        m[5] = y
        m[6] = 0.0
        m[7] = 0.0
        m[8] = 1.0
    }

    /**
     * Sets this matrix to a rotation matrix with a specified angle. Positive angles are interpreted as
     * counter-clockwise rotation.
     *
     * @param angle the angle of rotation
     *
     * @return this matrix with its rotation components set to those specified and all other components set to that of
     * an identity matrix
     */
    fun setToRotation(angle: Angle) = apply {
        val c = cos(angle.inRadians)
        val s = sin(angle.inRadians)
        m[0] = c
        m[1] = -s
        m[2] = 0.0
        m[3] = s
        m[4] = c
        m[5] = 0.0
        m[6] = 0.0
        m[7] = 0.0
        m[8] = 1.0
    }

    /**
     * Sets this matrix to a scale matrix with specified scale components.
     *
     * @param xScale the X scale component
     * @param yScale the Y scale component
     *
     * @return this matrix with its scale components set to those specified and all other components set to that of an
     * identity matrix
     */
    fun setToScale(xScale: Double, yScale: Double) = apply {
        m[0] = xScale
        m[1] = 0.0
        m[2] = 0.0
        m[3] = 0.0
        m[4] = yScale
        m[5] = 0.0
        m[6] = 0.0
        m[7] = 0.0
        m[8] = 1.0
    }

    /**
     * Sets this matrix to one that flips and shifts the y-axis. The resultant matrix maps Y=0 to Y=1 and Y=1 to Y=0.
     * All existing values are overwritten. This matrix is usually used to change the coordinate origin from an upper
     * left coordinate origin to a lower left coordinate origin.
     * 
* This matrix is typically necessary to align the coordinate system of images (top-left origin) with that of OpenGL * (bottom-left origin). * * @return this matrix set to values described above */ fun setToVerticalFlip() = apply { m[0] = 1.0 m[1] = 0.0 m[2] = 0.0 m[3] = 0.0 m[4] = -1.0 m[5] = 1.0 m[6] = 0.0 m[7] = 0.0 m[8] = 1.0 } /** * Sets this matrix to one that transforms normalized coordinates from a source sector to a destination sector. * Normalized coordinates within a sector range from 0 to 1, with (0, 0) indicating the lower left corner and (1, 1) * indicating the upper right. The resultant matrix maps a normalized source coordinate (X, Y) to its corresponding * normalized destination coordinate (X', Y'). *
* This matrix typically necessary to transform texture coordinates from one geographic region to another. For * example, the texture coordinates for a terrain tile spanning one region must be transformed to coordinates * appropriate for an image tile spanning a potentially different region. * * @param src the source sector * @param dst the destination sector * * @return this matrix set to values described above */ fun setToTileTransform(src: Sector, dst: Sector) = apply { val srcDeltaLat = src.deltaLatitude.inDegrees val srcDeltaLon = src.deltaLongitude.inDegrees val dstDeltaLat = dst.deltaLatitude.inDegrees val dstDeltaLon = dst.deltaLongitude.inDegrees val xs = srcDeltaLon / dstDeltaLon val ys = srcDeltaLat / dstDeltaLat val xt = (src.minLongitude.inDegrees - dst.minLongitude.inDegrees) / dstDeltaLon val yt = (src.minLatitude.inDegrees - dst.minLatitude.inDegrees) / dstDeltaLat m[0] = xs m[1] = 0.0 m[2] = xt m[3] = 0.0 m[4] = ys m[5] = yt m[6] = 0.0 m[7] = 0.0 m[8] = 1.0 } /** * Sets this matrix to the matrix product of two specified matrices. * * @param a the first matrix multiplicand * @param b The second matrix multiplicand * * @return this matrix set to the product of a x b */ fun setToMultiply(a: Matrix3, b: Matrix3) = apply { val ma = a.m val mb = b.m m[0] = ma[0] * mb[0] + ma[1] * mb[3] + ma[2] * mb[6] m[1] = ma[0] * mb[1] + ma[1] * mb[4] + ma[2] * mb[7] m[2] = ma[0] * mb[2] + ma[1] * mb[5] + ma[2] * mb[8] m[3] = ma[3] * mb[0] + ma[4] * mb[3] + ma[5] * mb[6] m[4] = ma[3] * mb[1] + ma[4] * mb[4] + ma[5] * mb[7] m[5] = ma[3] * mb[2] + ma[4] * mb[5] + ma[5] * mb[8] m[6] = ma[6] * mb[0] + ma[7] * mb[3] + ma[8] * mb[6] m[7] = ma[6] * mb[1] + ma[7] * mb[4] + ma[8] * mb[7] m[8] = ma[6] * mb[2] + ma[7] * mb[5] + ma[8] * mb[8] } /** * Multiplies this matrix by a translation matrix with specified translation values. * * @param x the X translation component * @param y the Y translation component * * @return this matrix multiplied by the translation matrix implied by the specified values */ fun multiplyByTranslation(x: Double, y: Double) = apply { multiplyByMatrix(1.0, 0.0, x, 0.0, 1.0, y, 0.0, 0.0, 1.0) } /** * Multiplies this matrix by a rotation matrix about a specified axis and angle. Positive angles are interpreted as * counter-clockwise rotation. * * @param angle the angle of rotation * * @return this matrix multiplied by the rotation matrix implied by the specified values */ fun multiplyByRotation(angle: Angle) = apply { val c = cos(angle.inRadians) val s = sin(angle.inRadians) multiplyByMatrix(c, -s, 0.0, s, c, 0.0, 0.0, 0.0, 1.0) } /** * Multiplies this matrix by a scale matrix with specified values. * * @param xScale the X scale component * @param yScale the Y scale component * * @return this matrix multiplied by the scale matrix implied by the specified values */ fun multiplyByScale(xScale: Double, yScale: Double) = apply { multiplyByMatrix(xScale, 0.0, 0.0, 0.0, yScale, 0.0, 0.0, 0.0, 1.0) } /** * Multiplies this matrix by a matrix that flips and shifts the y-axis. The vertical flip matrix maps Y=0 to Y=1 and * Y=1 to Y=0. This matrix is usually used to change the coordinate origin from an upper left coordinate origin to a * lower left coordinate origin. *
* This is typically necessary to align the coordinate system of images (top-left origin) with that of OpenGL * (bottom-left origin). * * @return this matrix multiplied by a vertical flip matrix implied by values described above */ fun multiplyByVerticalFlip() = apply { m[2] += m[1] m[5] += m[4] m[8] += m[7] m[1] = -m[1] m[4] = -m[4] m[7] = -m[7] } /** * Multiplies this matrix by a matrix that transforms normalized coordinates from a source sector to a destination * sector. Normalized coordinates within a sector range from 0 to 1, with (0, 0) indicating the lower left corner * and (1, 1) indicating the upper right. The resultant matrix maps a normalized source coordinate (X, Y) to its * corresponding normalized destination coordinate (X', Y'). *
* This matrix typically necessary to transform texture coordinates from one geographic region to another. For * example, the texture coordinates for a terrain tile spanning one region must be transformed to coordinates * appropriate for an image tile spanning a potentially different region. * * @param src the source sector * @param dst the destination sector * * @return this matrix multiplied by the transform matrix implied by values described above */ fun multiplyByTileTransform(src: Sector, dst: Sector) = apply { val srcDeltaLat = src.deltaLatitude.inDegrees val srcDeltaLon = src.deltaLongitude.inDegrees val dstDeltaLat = dst.deltaLatitude.inDegrees val dstDeltaLon = dst.deltaLongitude.inDegrees val xs = srcDeltaLon / dstDeltaLon val ys = srcDeltaLat / dstDeltaLat val xt = (src.minLongitude.inDegrees - dst.minLongitude.inDegrees) / dstDeltaLon val yt = (src.minLatitude.inDegrees - dst.minLatitude.inDegrees) / dstDeltaLat m[2] += m[0] * xt + m[1] * yt m[5] += m[3] * xt + m[4] * yt m[8] += m[6] * xt + m[6] * yt m[0] *= xs m[1] *= ys m[3] *= xs m[4] *= ys m[6] *= xs m[7] *= ys } /** * Multiplies this matrix by a specified matrix. * * @param matrix the matrix to multiply with this matrix * * @return this matrix after multiplying it by the specified matrix */ fun multiplyByMatrix(matrix: Matrix3) = apply { val ma = m val mb = matrix.m var ma0 = ma[0] var ma1 = ma[1] var ma2 = ma[2] ma[0] = ma0 * mb[0] + ma1 * mb[3] + ma2 * mb[6] ma[1] = ma0 * mb[1] + ma1 * mb[4] + ma2 * mb[7] ma[2] = ma0 * mb[2] + ma1 * mb[5] + ma2 * mb[8] ma0 = ma[3] ma1 = ma[4] ma2 = ma[5] ma[3] = ma0 * mb[0] + ma1 * mb[3] + ma2 * mb[6] ma[4] = ma0 * mb[1] + ma1 * mb[4] + ma2 * mb[7] ma[5] = ma0 * mb[2] + ma1 * mb[5] + ma2 * mb[8] ma0 = ma[6] ma1 = ma[7] ma2 = ma[8] ma[6] = ma0 * mb[0] + ma1 * mb[3] + ma2 * mb[6] ma[7] = ma0 * mb[1] + ma1 * mb[4] + ma2 * mb[7] ma[8] = ma0 * mb[2] + ma1 * mb[5] + ma2 * mb[8] } /** * Multiplies this matrix by a matrix specified by individual components. * * @param m11 matrix element at row 1, column 1 * @param m12 matrix element at row 1, column 2 * @param m13 matrix element at row 1, column 3 * @param m21 matrix element at row 2, column 1 * @param m22 matrix element at row 2, column 2 * @param m23 matrix element at row 2, column 3 * @param m31 matrix element at row 3, column 1 * @param m32 matrix element at row 3, column 2 * @param m33 matrix element at row 3, column 3 * * @return this matrix with its components multiplied by the specified values */ fun multiplyByMatrix( m11: Double, m12: Double, m13: Double, m21: Double, m22: Double, m23: Double, m31: Double, m32: Double, m33: Double ) = apply { var mr1 = m[0] var mr2 = m[1] var mr3 = m[2] m[0] = mr1 * m11 + mr2 * m21 + mr3 * m31 m[1] = mr1 * m12 + mr2 * m22 + mr3 * m32 m[2] = mr1 * m13 + mr2 * m23 + mr3 * m33 mr1 = m[3] mr2 = m[4] mr3 = m[5] m[3] = mr1 * m11 + mr2 * m21 + mr3 * m31 m[4] = mr1 * m12 + mr2 * m22 + mr3 * m32 m[5] = mr1 * m13 + mr2 * m23 + mr3 * m33 mr1 = m[6] mr2 = m[7] mr3 = m[8] m[6] = mr1 * m11 + mr2 * m21 + mr3 * m31 m[7] = mr1 * m12 + mr2 * m22 + mr3 * m32 m[8] = mr1 * m13 + mr2 * m23 + mr3 * m33 } /** * Transposes this matrix in place. * * @return this matrix, transposed. */ fun transpose() = apply { var tmp = m[1] m[1] = m[3] m[3] = tmp tmp = m[2] m[2] = m[6] m[6] = tmp tmp = m[5] m[5] = m[7] m[7] = tmp } /** * Transposes the specified matrix and stores the result in this matrix. * * @param matrix the matrix whose transpose is computed * * @return this matrix set to the transpose of the specified matrix */ fun transposeMatrix(matrix: Matrix3) = apply { m[0] = matrix.m[0] m[1] = matrix.m[3] m[2] = matrix.m[6] m[3] = matrix.m[1] m[4] = matrix.m[4] m[5] = matrix.m[7] m[6] = matrix.m[2] m[7] = matrix.m[5] m[8] = matrix.m[8] } /** * Transposes this matrix, storing the result in the specified single precision array. The result is compatible with * GLSL uniform matrices, and can be passed to the function glUniformMatrix3fv. * * @param result a pre-allocated array of length 9 in which to return the transposed components * * @return the result argument set to the transposed components */ fun transposeToArray(result: FloatArray, offset: Int): FloatArray { var o = offset require(result.size - o >= 9) { logMessage(ERROR, "Matrix4", "transposeToArray", "missingArray") } result[o++] = m[0].toFloat() result[o++] = m[3].toFloat() result[o++] = m[6].toFloat() result[o++] = m[1].toFloat() result[o++] = m[4].toFloat() result[o++] = m[7].toFloat() result[o++] = m[2].toFloat() result[o++] = m[5].toFloat() result[o] = m[8].toFloat() return result } /** * Inverts this matrix in place. *
* This throws an exception if this matrix is singular. * * @return this matrix, inverted * * @throws IllegalArgumentException If this matrix cannot be inverted */ fun invert(): Matrix3 { throw UnsupportedOperationException("Matrix3.invert is not implemented") // TODO } /** * Inverts the specified matrix and stores the result in this matrix. *
* This throws an exception if the matrix is singular. *
* The result of this method is undefined if this matrix is passed in as the matrix to invert. * * @param matrix the matrix whose inverse is computed * * @return this matrix set to the inverse of the specified matrix */ @Suppress("UNUSED_PARAMETER") fun invertMatrix(matrix: Matrix3): Matrix3 { TODO("Matrix3.invertMatrix is not implemented") } override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is Matrix3) return false return m.contentEquals(other.m) } override fun hashCode() = m.contentHashCode() override fun toString() = "Matrix3([${m[0]}, ${m[1]}, ${m[2]}], [${m[3]}, ${m[4]}, ${m[5]}], [${m[6]}, ${m[7]}, ${m[8]}])" }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy