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

commonMain.Vec2.kt Maven / Gradle / Ivy

The newest version!
package org.openrndr.kartifex

import org.openrndr.utils.Hashes
import kotlin.jvm.JvmRecord
import kotlin.math.PI
import kotlin.math.atan2
import kotlin.math.cos
import kotlin.math.sin

@JvmRecord
data class Vec2(val x: Double, val y: Double) : Vec {


    override fun map(f: DoubleUnaryOperator): Vec2 {
        return Vec2(f(x), f(y))
    }

    override fun reduce(f: DoubleBinaryOperator, init: Double): Double {
        return f(f(x, y), init)
    }

    override fun reduce(f: DoubleBinaryOperator): Double {
        return f(x, y)
    }

    override fun zip(v: Vec2, f: DoubleBinaryOperator): Vec2 {
        return Vec2(f(x, v.x), f(y, v.y))
    }

    override fun every(f: DoublePredicate): Boolean {
        return f(x) && f(y)
    }

    override fun any(f: DoublePredicate): Boolean {
        return f(x) || f(y)
    }

    override fun nth(idx: Int): Double {
        return when (idx) {
            0 -> x
            1 -> y
            else -> throw IndexOutOfBoundsException()
        }
    }

    override fun dim(): Int {
        return 2
    }

    override fun array(): DoubleArray {
        return doubleArrayOf(x, y)
    }

    fun add(x: Double, y: Double): Vec2 {
        return Vec2(this.x + x, this.y + y)
    }

    fun sub(x: Double, y: Double): Vec2 {
        return Vec2(this.x - x, this.y - y)
    }

    fun swap(): Vec2 {
        return Vec2(y, x)
    }

    fun vec3(z: Double): Vec3 {
        return Vec3(x, y, z)
    }

    fun vec4(z: Double, w: Double): Vec4 {
        return Vec4(x, y, z, w)
    }

    fun vec4(v: Vec2): Vec4 {
        return Vec4(x, y, v.x, v.y)
    }

    fun transform(m: Matrix3): Vec2 {
        return m.transform(this)
    }

    /**
     * @return a rotated vector
     */
    fun rotate(radians: Double): Vec2 {
        val s: Double = sin(radians)
        val c: Double = cos(radians)
        return Vec2(c * x + -s * y, s * x + c * y)
    }

    fun polar2(): Polar2 {
        return Polar2(atan2(y, x), length())
    }

    override fun hashCode(): Int {
        return Hashes.hash(x, y)
    }

    override fun equals(other: Any?): Boolean {
        if (other is Vec2) {
            val v = other
            return v.x == x && v.y == y
        }
        return false
    }

    override operator fun compareTo(other: Vec2): Int {
        return COMPARATOR.compare(this, other)
    }

    override fun add(v: Vec2): Vec2 {
        return Vec2(x + v.x, y + v.y)
    }

    override fun add(n: Double): Vec2 {
        return Vec2(x + n, y + n)
    }

    override fun negate(): Vec2 {
        return Vec2(-x, -y)
    }

    override fun sub(v: Vec2): Vec2 {
        return Vec2(x - v.x, y - v.y)
    }

    override fun sub(n: Double): Vec2 {
        return Vec2(x - n, y - n)
    }

    override fun mul(v: Vec2): Vec2 {
        return Vec2(x * v.x, y * v.y)
    }

    override fun mul(k: Double): Vec2 {
        return Vec2(x * k, y * k)
    }

    override operator fun div(v: Vec2): Vec2 {
        return Vec2(x / v.x, y / v.y)
    }

    override fun toString(): String {
        return "Vec2(x=$x, y=$y)"
    }

    companion object {
        val COMPARATOR = compareBy({ v -> v.x }, { v -> v.y })

        val ORIGIN = Vec2(0.0, 0.0)
        val X_AXIS = Vec2(1.0, 0.0)
        val Y_AXIS = Vec2(0.0, 1.0)

        fun cross(a: Vec2, b: Vec2): Double {
            return a.x * b.y - a.y * b.x
        }

        /**
         * @return the clockwise angle between the two vectors
         */
        fun angleBetween(oa: Vec2, ob: Vec2): Double {

            val a = oa.pseudoNorm()
            val b = ob.pseudoNorm()

            // from section 12 of https://people.eecs.berkeley.edu/~wkahan/Mindless.pdf
            var theta: Double = atan2(cross(a, b), Vec.dot(a, b))
            if (theta > 0) {
                theta -= PI * 2
            }
            return theta
        }

        /**
         * @return whether `b` sits between the vectors `a` and `b`
         */
        fun between(a: Vec2, b: Vec2, c: Vec2): Boolean {
            return cross(a, b) * cross(c, b) < 0
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy