From 5656ff634ad50f80597150492ff2443d5607c30d Mon Sep 17 00:00:00 2001 From: soywiz Date: Fri, 9 Oct 2020 10:36:11 +0200 Subject: [PATCH] 2.0.0-alpha --- build.gradle.kts | 2 +- gradle.properties | 6 +- gradle/wrapper/gradle-wrapper.jar | Bin 58695 -> 58694 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- .../kotlin/com/soywiz/korma/algo/AStar.kt | 9 +- .../kotlin/com/soywiz/korma/geom/Anchor.kt | 3 - .../kotlin/com/soywiz/korma/geom/Angle.kt | 23 +- .../com/soywiz/korma/geom/BoundsBuilder.kt | 76 +-- .../com/soywiz/korma/geom/EulerRotation.kt | 42 ++ .../kotlin/com/soywiz/korma/geom/Matrix.kt | 275 +++-------- .../kotlin/com/soywiz/korma/geom/Matrix3D.kt | 437 ++++++------------ .../kotlin/com/soywiz/korma/geom/MatrixExt.kt | 12 +- .../kotlin/com/soywiz/korma/geom/Point.kt | 250 ++++------ .../com/soywiz/korma/geom/PointArrayList.kt | 96 ++-- .../korma/geom/{PointArea.kt => PointPool.kt} | 22 +- .../com/soywiz/korma/geom/Quaternion.kt | 148 ++++++ .../com/soywiz/korma/geom/QuaternionEuler.kt | 221 --------- .../kotlin/com/soywiz/korma/geom/Rectangle.kt | 78 ++-- .../kotlin/com/soywiz/korma/geom/ScaleMode.kt | 12 +- .../kotlin/com/soywiz/korma/geom/Size.kt | 45 +- .../kotlin/com/soywiz/korma/geom/Vector3D.kt | 47 +- .../soywiz/korma/geom/binpack/BinPacker.kt | 26 +- .../com/soywiz/korma/geom/shape/Shape2d.kt | 7 +- .../com/soywiz/korma/geom/vector/Edge.kt | 16 +- .../com/soywiz/korma/geom/vector/LineJoin.kt | 9 + .../korma/geom/vector/PolygonScanline.kt | 6 +- .../soywiz/korma/geom/vector/VectorBuilder.kt | 182 ++++---- .../soywiz/korma/geom/vector/VectorPath.kt | 96 ++-- .../com/soywiz/korma/internal/KormaVersion.kt | 2 +- .../com/soywiz/korma/interpolation/Easing.kt | 218 +++++---- .../korma/interpolation/Interpolation.kt | 11 - .../com/soywiz/korma/random/RandomExt.kt | 2 - .../com/soywiz/korma/geom/Matrix3DTest.kt | 24 +- .../com/soywiz/korma/geom/MatrixTest.kt | 13 +- .../{PointAreaTest.kt => PointPoolTest.kt} | 4 +- .../com/soywiz/korma/geom/Vector2Test.kt | 2 +- .../com/soywiz/korma/geom/Vector3DTest.kt | 28 +- .../korma/geom/vector/VectorPathTest.kt | 2 +- .../soywiz/korma/interpolation/EasingTest.kt | 17 + .../kotlin/com/soywiz/korma/math/MathTest.kt | 20 + 40 files changed, 1077 insertions(+), 1414 deletions(-) create mode 100644 korma/src/commonMain/kotlin/com/soywiz/korma/geom/EulerRotation.kt rename korma/src/commonMain/kotlin/com/soywiz/korma/geom/{PointArea.kt => PointPool.kt} (70%) create mode 100644 korma/src/commonMain/kotlin/com/soywiz/korma/geom/Quaternion.kt delete mode 100644 korma/src/commonMain/kotlin/com/soywiz/korma/geom/QuaternionEuler.kt rename korma/src/commonTest/kotlin/com/soywiz/korma/geom/{PointAreaTest.kt => PointPoolTest.kt} (85%) diff --git a/build.gradle.kts b/build.gradle.kts index 36f4685..71ceeeb 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -11,7 +11,7 @@ buildscript { } dependencies { - classpath("com.soywiz.korlibs:easy-kotlin-mpp-gradle-plugin:0.9.3") // Kotlin 1.3.72: https://github.com/korlibs/easy-kotlin-mpp-gradle-plugin + classpath("com.soywiz.korlibs:easy-kotlin-mpp-gradle-plugin:0.10.3") // Kotlin 1.4.10: https://github.com/korlibs/easy-kotlin-mpp-gradle-plugin } } diff --git a/gradle.properties b/gradle.properties index 4a5122f..476fbbd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,10 +3,10 @@ kotlin.code.style=official # version group=com.soywiz.korlibs.korma -version=1.11.18-SNAPSHOT +version=2.0.0-SNAPSHOT # korlibs -kdsVersion=1.10.12 +kdsVersion=2.0.0-alpha # bintray location project.bintray.org=korlibs @@ -23,4 +23,4 @@ project.license.url=https://raw.githubusercontent.com/korlibs/korma/master/LICEN # gradle org.gradle.jvmargs=-Xmx3g kotlin.incremental.multiplatform=true -kotlin.native.ignoreDisabledTargets=true \ No newline at end of file +kotlin.native.ignoreDisabledTargets=true diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index f3d88b1c2faf2fc91d853cd5d4242b5547257070..490fda8577df6c95960ba7077c43220e5bb2c0d9 100644 GIT binary patch delta 6577 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 MViXjGx&OBR0?kH%b^rhX delta 6547 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 Boolean) { companion object { @@ -24,7 +23,7 @@ class AStar(val width: Int, val height: Int, val isBlocking: (x: Int, y: Int) -> // Reset queue.clear() for (n in weights.indices) weights[n] = Int.MAX_VALUE - for (n in prev.indices) prev[n] = NULL.index + for (n in prev.indices) prev[n] = NIL.index val first = getNode(x0, y0) val dest = getNode(x1, y1) @@ -54,19 +53,19 @@ class AStar(val width: Int, val height: Int, val isBlocking: (x: Int, y: Int) -> if (findClosest || closest == dest) { var current: AStarNode = closest - while (current != NULL) { + while (current != NIL) { emit(current.posX, current.posY) current = current.prev } } } - private val NULL = AStarNode(-1) + private val NIL = AStarNode(-1) private val posX = IntArray(width * height) { it % width } private val posY = IntArray(width * height) { it / width } private val weights = IntArray(width * height) { Int.MAX_VALUE } - private val prev = IntArray(width * height) { NULL.index } + private val prev = IntArray(width * height) { NIL.index } private val queue = IntPriorityQueue { a, b -> AStarNode(a).weight - AStarNode(b).weight } private fun inside(x: Int, y: Int): Boolean = (x in 0 until width) && (y in 0 until height) diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Anchor.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Anchor.kt index 5e5998e..9826ca5 100644 --- a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Anchor.kt +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Anchor.kt @@ -8,9 +8,6 @@ data class Anchor(val sx: Double, val sy: Double) : Interpolable { operator fun invoke(sx: Int, sy: Int) = Anchor(sx.toDouble(), sy.toDouble()) operator fun invoke(sx: Float, sy: Float) = Anchor(sx.toDouble(), sy.toDouble()) - @Deprecated("Kotlin/Native boxes inline + Number") - inline operator fun invoke(sx: Number, sy: Number) = Anchor(sx.toDouble(), sy.toDouble()) - val TOP_LEFT = Anchor(0.0, 0.0) val TOP_CENTER = Anchor(0.5, 0.0) val TOP_RIGHT = Anchor(1.0, 0.0) diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Angle.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Angle.kt index 68123cc..7c09cfc 100644 --- a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Angle.kt +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Angle.kt @@ -23,11 +23,6 @@ inline class Angle(val radians: Double) : Comparable { fun fromRadians(radians: Int) = fromRadians(radians.toDouble()) fun fromDegrees(degrees: Int) = fromDegrees(degrees.toDouble()) - @Deprecated("Kotlin/Native boxes Number in inline") - inline fun fromRadians(radians: Number) = fromRadians(radians.toDouble()) - @Deprecated("Kotlin/Native boxes Number in inline") - inline fun fromDegrees(degrees: Number) = fromDegrees(degrees.toDouble()) - internal const val PI2 = PI * 2 internal const val DEG2RAD = PI / 180.0 @@ -67,8 +62,8 @@ inline class Angle(val radians: Double) : Comparable { return if (angle < 0) Angle(angle + PI2) else Angle(angle) } - @Deprecated("Kotlin/Native boxes Number in inline") - inline fun between(x0: Number, y0: Number, x1: Number, y1: Number): Angle = between(x0.toDouble(), y0.toDouble(), x1.toDouble(), y1.toDouble()) + fun between(x0: Int, y0: Int, x1: Int, y1: Int): Angle = between(x0.toDouble(), y0.toDouble(), x1.toDouble(), y1.toDouble()) + fun between(x0: Float, y0: Float, x1: Float, y1: Float): Angle = between(x0.toDouble(), y0.toDouble(), x1.toDouble(), y1.toDouble()) fun between(p0: IPoint, p1: IPoint): Angle = between(p0.x, p0.y, p1.x, p1.y) } @@ -79,6 +74,7 @@ inline class Angle(val radians: Double) : Comparable { inline fun cos(angle: Angle): Double = kotlin.math.cos(angle.radians) inline fun sin(angle: Angle): Double = kotlin.math.sin(angle.radians) inline fun tan(angle: Angle): Double = kotlin.math.tan(angle.radians) +inline fun abs(angle: Angle): Angle = Angle.fromRadians(angle.radians.absoluteValue) val Angle.cosine get() = cos(this) val Angle.sine get() = sin(this) @@ -91,15 +87,11 @@ fun Angle.longDistanceTo(other: Angle): Angle = Angle.longDistanceTo(this, other operator fun Angle.times(scale: Double): Angle = Angle(this.radians * scale) operator fun Angle.div(scale: Double): Angle = Angle(this.radians / scale) - +operator fun Angle.times(scale: Float): Angle = this * scale.toDouble() +operator fun Angle.div(scale: Float): Angle = this / scale.toDouble() operator fun Angle.times(scale: Int): Angle = this * scale.toDouble() operator fun Angle.div(scale: Int): Angle = this / scale.toDouble() -@Deprecated("Kotlin/Native boxes Number in inline") -inline operator fun Angle.times(scale: Number): Angle = this * scale.toDouble() -@Deprecated("Kotlin/Native boxes Number in inline") -inline operator fun Angle.div(scale: Number): Angle = this / scale.toDouble() - operator fun Angle.div(other: Angle): Double = this.radians / other.radians // Ratio operator fun Angle.plus(other: Angle): Angle = Angle(this.radians + other.radians) operator fun Angle.minus(other: Angle): Angle = Angle(this.radians - other.radians) @@ -134,11 +126,6 @@ val Int.radians get() = Angle.fromRadians(this) val Float.degrees get() = Angle.fromDegrees(this) val Float.radians get() = Angle.fromRadians(this) -@Deprecated("Kotlin/Native boxes Number in inline") -inline val Number.degrees get() = Angle.fromDegrees(this) -@Deprecated("Kotlin/Native boxes Number in inline") -inline val Number.radians get() = Angle.fromRadians(this) - val Angle.normalized get() = Angle(radians umod Angle.MAX_RADIANS) fun Double.interpolate(l: Angle, r: Angle): Angle = this.interpolate(l.radians, r.radians).radians diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/BoundsBuilder.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/BoundsBuilder.kt index 2738121..ab7b23c 100644 --- a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/BoundsBuilder.kt +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/BoundsBuilder.kt @@ -26,17 +26,56 @@ class BoundsBuilder { } fun add(x: Double, y: Double): BoundsBuilder { - xmin = kotlin.math.min(xmin, x) - xmax = kotlin.math.max(xmax, x) - ymin = kotlin.math.min(ymin, y) - ymax = kotlin.math.max(ymax, y) + if (x < xmin) xmin = x + if (x > xmax) xmax = x + if (y < ymin) ymin = y + if (y > ymax) ymax = y npoints++ //println("add($x, $y) -> ($xmin,$ymin)-($xmax,$ymax)") return this } - fun add(x: Double, y: Double, transform :Matrix): BoundsBuilder = - add(transform.transformX(x, y), transform.transformY(x, y)) + fun add(x: Int, y: Int): BoundsBuilder = add(x.toDouble(), y.toDouble()) + fun add(x: Float, y: Float): BoundsBuilder = add(x.toDouble(), y.toDouble()) + + fun add(x: Double, y: Double, transform: Matrix): BoundsBuilder = add(transform.transformX(x, y), transform.transformY(x, y)) + fun add(x: Int, y: Int, transform: Matrix): BoundsBuilder = add(x.toDouble(), y.toDouble(), transform) + fun add(x: Float, y: Float, transform: Matrix): BoundsBuilder = add(x.toDouble(), y.toDouble(), transform) + + fun add(point: IPoint): BoundsBuilder = add(point.x, point.y) + fun add(point: IPoint, transform: Matrix): BoundsBuilder = add(point.x, point.y, transform) + + fun add(ps: Iterable): BoundsBuilder { + for (p in ps) add(p) + return this + } + fun add(ps: IPointArrayList): BoundsBuilder { + for (n in 0 until ps.size) add(ps.getX(n), ps.getY(n)) + return this + } + fun add(rect: Rectangle): BoundsBuilder { + if (rect.isNotEmpty) { + add(rect.left, rect.top) + add(rect.right, rect.bottom) + } + return this + } + + fun add(ps: Iterable, transform: Matrix): BoundsBuilder { + for (p in ps) add(p, transform) + return this + } + fun add(ps: IPointArrayList, transform: Matrix): BoundsBuilder { + for (n in 0 until ps.size) add(ps.getX(n), ps.getY(n), transform) + return this + } + fun add(rect: Rectangle, transform: Matrix): BoundsBuilder { + if (rect.isNotEmpty) { + add(rect.left, rect.top, transform) + add(rect.right, rect.bottom, transform) + } + return this + } fun getBoundsOrNull(out: Rectangle = Rectangle()): Rectangle? = if (npoints == 0) null else out.setBounds(xmin, ymin, xmax, ymax) @@ -47,28 +86,3 @@ class BoundsBuilder { return out } } - -fun BoundsBuilder.add(x: Int, y: Int) = add(x.toDouble(), y.toDouble()) - -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun BoundsBuilder.add(x: Number, y: Number) = add(x.toDouble(), y.toDouble()) - -fun BoundsBuilder.add(p: IPoint) = add(p.x, p.y) -fun BoundsBuilder.add(ps: Iterable) = this.apply { for (p in ps) add(p) } -fun BoundsBuilder.add(ps: IPointArrayList) = run { for (n in 0 until ps.size) add(ps.getX(n), ps.getY(n)) } -fun BoundsBuilder.add(rect: Rectangle) = this.apply { - if (rect.isNotEmpty) { - add(rect.left, rect.top) - add(rect.right, rect.bottom) - } -} - -fun BoundsBuilder.add(p: IPoint, transform: Matrix) = add(p.x, p.y, transform) -fun BoundsBuilder.add(ps: Iterable, transform: Matrix) = this.apply { for (p in ps) add(p, transform) } -fun BoundsBuilder.add(ps: IPointArrayList, transform: Matrix) = run { for (n in 0 until ps.size) add(ps.getX(n), ps.getY(n), transform) } -fun BoundsBuilder.add(rect: Rectangle, transform: Matrix) = this.apply { - if (rect.isNotEmpty) { - add(rect.left, rect.top, transform) - add(rect.right, rect.bottom, transform) - } -} diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/EulerRotation.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/EulerRotation.kt new file mode 100644 index 0000000..bc67afd --- /dev/null +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/EulerRotation.kt @@ -0,0 +1,42 @@ +package com.soywiz.korma.geom + +data class EulerRotation( + var x: Angle = 0.degrees, + var y: Angle = 0.degrees, + var z: Angle = 0.degrees +) { + companion object { + fun toQuaternion(roll: Angle, pitch: Angle, yaw: Angle, out: Quaternion = Quaternion()): Quaternion { + val cr = cos(roll * 0.5) + val sr = sin(roll * 0.5) + val cp = cos(pitch * 0.5) + val sp = sin(pitch * 0.5) + val cy = cos(yaw * 0.5) + val sy = sin(yaw * 0.5) + return out.setTo( + (cy * cp * sr - sy * sp * cr), + (sy * cp * sr + cy * sp * cr), + (sy * cp * cr - cy * sp * sr), + (cy * cp * cr + sy * sp * sr) + ) + } + fun toQuaternion(euler: EulerRotation, out: Quaternion = Quaternion()): Quaternion = toQuaternion(euler.x, euler.y, euler.z, out) + } + + fun toQuaternion(out: Quaternion = Quaternion()): Quaternion = toQuaternion(this, out) + + fun setQuaternion(x: Double, y: Double, z: Double, w: Double): EulerRotation = Quaternion.toEuler(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat(), this) + fun setQuaternion(x: Int, y: Int, z: Int, w: Int): EulerRotation = Quaternion.toEuler(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat(), this) + fun setQuaternion(x: Float, y: Float, z: Float, w: Float): EulerRotation = Quaternion.toEuler(x, y, z, w, this) + + fun setQuaternion(quaternion: Quaternion): EulerRotation = Quaternion.toEuler(quaternion.x, quaternion.y, quaternion.z, quaternion.w, this) + fun setTo(x: Angle, y: Angle, z: Angle): EulerRotation = this + .apply { this.x = x } + .apply { this.y = y } + .apply { this.z = z } + + fun setTo(other: EulerRotation): EulerRotation = setTo(other.x, other.y, other.z) + + private val tempQuat: Quaternion by lazy { Quaternion() } + fun toMatrix(out: Matrix3D = Matrix3D()): Matrix3D = tempQuat.setEuler(this).toMatrix(out) +} diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Matrix.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Matrix.kt index 7b0cfd3..49b67f9 100644 --- a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Matrix.kt +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Matrix.kt @@ -7,40 +7,6 @@ import com.soywiz.korma.interpolation.MutableInterpolable import com.soywiz.korma.interpolation.interpolate import kotlin.math.* -@Deprecated("Use Matrix instead") -interface IMatrix { - val _a: Double - val _b: Double - val _c: Double - val _d: Double - val _tx: Double - val _ty: Double - companion object { - @Deprecated("Kotlin/Native boxes inline + Number") - operator fun invoke(a: Number = 1, b: Number = 0, c: Number = 0, d: Number = 1, tx: Number = 0, ty: Number = 0): IMatrix = Matrix( - a.toDouble(), - b.toDouble(), - c.toDouble(), - d.toDouble(), - tx.toDouble(), - ty.toDouble() - ) - } -} - -@Deprecated("Use Matrix instead") -val IMatrix.a get() = _a -@Deprecated("Use Matrix instead") -val IMatrix.b get() = _b -@Deprecated("Use Matrix instead") -val IMatrix.c get() = _c -@Deprecated("Use Matrix instead") -val IMatrix.d get() = _d -@Deprecated("Use Matrix instead") -val IMatrix.tx get() = _tx -@Deprecated("Use Matrix instead") -val IMatrix.ty get() = _ty - data class Matrix( var a: Double = 1.0, var b: Double = 0.0, @@ -48,15 +14,7 @@ data class Matrix( var d: Double = 1.0, var tx: Double = 0.0, var ty: Double = 0.0 -) : IMatrix, MutableInterpolable, Interpolable { - - override val _a: Double get() = a - override val _b: Double get() = b - override val _c: Double get() = c - override val _d: Double get() = d - override val _tx: Double get() = tx - override val _ty: Double get() = ty - +) : MutableInterpolable, Interpolable { companion object { inline operator fun invoke(a: Float, b: Float = 0f, c: Float = 0f, d: Float = 1f, tx: Float = 0f, ty: Float = 0f) = Matrix(a.toDouble(), b.toDouble(), c.toDouble(), d.toDouble(), tx.toDouble(), ty.toDouble()) @@ -64,10 +22,6 @@ data class Matrix( inline operator fun invoke(a: Int, b: Int = 0, c: Int = 0, d: Int = 1, tx: Int = 0, ty: Int = 0) = Matrix(a.toDouble(), b.toDouble(), c.toDouble(), d.toDouble(), tx.toDouble(), ty.toDouble()) - @Deprecated("Kotlin/Native boxes inline + Number") - inline operator fun invoke(a: Number, b: Number = 0.0, c: Number = 0.0, d: Number = 1.0, tx: Number = 0.0, ty: Number = 0.0) = - Matrix(a.toDouble(), b.toDouble(), c.toDouble(), d.toDouble(), tx.toDouble(), ty.toDouble()) - operator fun invoke(m: Matrix, out: Matrix = Matrix()): Matrix = out.copyFrom(m) } @@ -101,7 +55,6 @@ data class Matrix( this.tx = tx this.ty = ty } - fun setTo(a: Float, b: Float, c: Float, d: Float, tx: Float, ty: Float): Matrix = setTo(a.toDouble(), b.toDouble(), c.toDouble(), d.toDouble(), tx.toDouble(), ty.toDouble()) fun setTo(a: Int, b: Int, c: Int, d: Int, tx: Int, ty: Int): Matrix = setTo(a.toDouble(), b.toDouble(), c.toDouble(), d.toDouble(), tx.toDouble(), ty.toDouble()) @@ -128,7 +81,7 @@ data class Matrix( tx = tx1 } - fun skew(skewX: Double, skewY: Double): Matrix { + fun skew(skewX: Angle, skewY: Angle): Matrix { val sinX = sin(skewX) val cosX = cos(skewX) val sinY = sin(skewY) @@ -145,9 +98,20 @@ data class Matrix( } fun scale(sx: Double, sy: Double = sx) = setTo(a * sx, b * sx, c * sy, d * sy, tx * sx, ty * sy) + fun scale(sx: Float, sy: Float = sx) = scale(sx.toDouble(), sy.toDouble()) + fun scale(sx: Int, sy: Int = sx) = scale(sx.toDouble(), sy.toDouble()) + fun prescale(sx: Double, sy: Double = sx) = setTo(a * sx, b * sx, c * sy, d * sy, tx, ty) + fun prescale(sx: Float, sy: Float = sx) = prescale(sx.toDouble(), sy.toDouble()) + fun prescale(sx: Int, sy: Int = sx) = prescale(sx.toDouble(), sy.toDouble()) + fun translate(dx: Double, dy: Double) = this.apply { this.tx += dx; this.ty += dy } + fun translate(dx: Float, dy: Float) = translate(dx.toDouble(), dy.toDouble()) + fun translate(dx: Int, dy: Int) = translate(dx.toDouble(), dy.toDouble()) + fun pretranslate(dx: Double, dy: Double) = this.apply { tx += a * dx + c * dy; ty += b * dx + d * dy } + fun pretranslate(dx: Float, dy: Float) = pretranslate(dx.toDouble(), dy.toDouble()) + fun pretranslate(dx: Int, dy: Int) = pretranslate(dx.toDouble(), dy.toDouble()) fun prerotate(angle: Angle) = this.apply { val m = Matrix() @@ -155,13 +119,14 @@ data class Matrix( this.premultiply(m) } - fun preskew(skewX: Double, skewY: Double) = this.apply { + fun preskew(skewX: Angle, skewY: Angle) = this.apply { val m = Matrix() m.skew(skewX, skewY) this.premultiply(m) } fun premultiply(m: Matrix) = this.premultiply(m.a, m.b, m.c, m.d, m.tx, m.ty) + fun postmultiply(m: Matrix) = multiply(this, m) fun premultiply(la: Double, lb: Double, lc: Double, ld: Double, ltx: Double, lty: Double): Matrix = setTo( la * a + lb * c, @@ -171,6 +136,8 @@ data class Matrix( ltx * a + lty * c + tx, ltx * b + lty * d + ty ) + fun premultiply(la: Float, lb: Float, lc: Float, ld: Float, ltx: Float, lty: Float): Matrix = premultiply(la.toDouble(), lb.toDouble(), lc.toDouble(), ld.toDouble(), ltx.toDouble(), lty.toDouble()) + fun premultiply(la: Int, lb: Int, lc: Int, ld: Int, ltx: Int, lty: Int): Matrix = premultiply(la.toDouble(), lb.toDouble(), lc.toDouble(), ld.toDouble(), ltx.toDouble(), lty.toDouble()) fun multiply(l: Matrix, r: Matrix): Matrix = setTo( l.a * r.a + l.b * r.c, @@ -186,6 +153,8 @@ data class Matrix( fun identity() = setTo(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) + fun isIdentity() = getType() == Type.IDENTITY + fun invert(matrixToInvert: Matrix = this): Matrix { val src = matrixToInvert val dst = this @@ -213,10 +182,10 @@ data class Matrix( scaleX: Double, scaleY: Double, rotation: Angle, - skewX: Double, - skewY: Double + skewX: Angle, + skewY: Angle ): Matrix { - if (skewX == 0.0 && skewY == 0.0) { + if (skewX == 0.0.radians && skewY == 0.0.radians) { if (rotation == 0.radians) { this.setTo(scaleX, 0.0, 0.0, scaleY, x, y) } else { @@ -233,73 +202,45 @@ data class Matrix( } return this } + fun setTransform(x: Float, y: Float, scaleX: Float, scaleY: Float, rotation: Angle, skewX: Angle, skewY: Angle): Matrix = setTransform(x.toDouble(), y.toDouble(), scaleX.toDouble(), scaleY.toDouble(), rotation, skewX, skewY) fun clone() = Matrix(a, b, c, d, tx, ty) - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun setTo(a: Number, b: Number, c: Number, d: Number, tx: Number, ty: Number): Matrix = setTo(a.toDouble(), b.toDouble(), c.toDouble(), d.toDouble(), tx.toDouble(), ty.toDouble()) - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun scale(sx: Number, sy: Number = sx) = scale(sx.toDouble(), sy.toDouble()) - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun prescale(sx: Number, sy: Number = sx) = prescale(sx.toDouble(), sy.toDouble()) - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun translate(dx: Number, dy: Number) = translate(dx.toDouble(), dy.toDouble()) - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun pretranslate(dx: Number, dy: Number) = pretranslate(dx.toDouble(), dy.toDouble()) - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun skew(skewX: Number, skewY: Number): Matrix = skew(skewX.toDouble(), skewY.toDouble()) - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun preskew(skewX: Number, skewY: Number) = preskew(skewX.toDouble(), skewY.toDouble()) - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun premultiply(la: Number, lb: Number, lc: Number, ld: Number, ltx: Number, lty: Number): Matrix = premultiply(la.toDouble(), lb.toDouble(), lc.toDouble(), ld.toDouble(), ltx.toDouble(), lty.toDouble()) - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun rotateRadians(angle: Number) = rotate(angle.radians) - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun rotateDegrees(angle: Number) = rotate(angle.degrees) - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun prerotateRadians(angle: Number) = prerotate(angle.radians) - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun prerotateDegrees(angle: Number) = prerotate(angle.degrees) - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun setTransform(x: Number, y: Number, scaleX: Number, scaleY: Number, rotation: Angle, skewX: Number, skewY: Number): Matrix = setTransform(x.toDouble(), y.toDouble(), scaleX.toDouble(), scaleY.toDouble(), rotation, skewX.toDouble(), skewY.toDouble()) - operator fun times(that: Matrix): Matrix = Matrix().multiply(this, that) + fun toTransform(out: Transform = Transform()): Transform = out.setMatrix(this) + // Transform points - fun transformX(px: Double, py: Double): Double = this.a * px + this.c * py + this.tx - fun transformY(px: Double, py: Double): Double = this.d * py + this.b * px + this.ty - fun transform(px: Double, py: Double, out: Point = Point()): Point = out.setTo(transformX(px, py), transformY(px, py)) fun transform(p: IPoint, out: Point = Point()): Point = transform(p.x, p.y, out) + fun transform(px: Double, py: Double, out: Point = Point()): Point = out.setTo(transformX(px, py), transformY(px, py)) + fun transform(px: Float, py: Float, out: Point = Point()): Point = out.setTo(transformX(px, py), transformY(px, py)) + fun transform(px: Int, py: Int, out: Point = Point()): Point = out.setTo(transformX(px, py), transformY(px, py)) + fun transformX(p: IPoint): Double = transformX(p.x, p.y) + fun transformX(px: Double, py: Double): Double = this.a * px + this.c * py + this.tx + fun transformX(px: Float, py: Float): Double = this.a * px + this.c * py + this.tx + fun transformX(px: Int, py: Int): Double = this.a * px + this.c * py + this.tx + fun transformY(p: IPoint): Double = transformY(p.x, p.y) + fun transformY(px: Double, py: Double): Double = this.d * py + this.b * px + this.ty + fun transformY(px: Float, py: Float): Double = this.d * py + this.b * px + this.ty + fun transformY(px: Int, py: Int): Double = this.d * py + this.b * px + this.ty + fun transformXf(px: Double, py: Double): Float = transformX(px, py).toFloat() - fun transformYf(px: Double, py: Double): Float = transformY(px, py).toFloat() fun transformXf(px: Float, py: Float): Float = transformX(px.toDouble(), py.toDouble()).toFloat() - fun transformYf(px: Float, py: Float): Float = transformY(px.toDouble(), py.toDouble()).toFloat() - - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun transform(px: Number, py: Number, out: Point = Point()): Point = transform(px.toDouble(), py.toDouble(), out) - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun transformXf(px: Number, py: Number): Float = transformX(px.toDouble(), py.toDouble()).toFloat() - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun transformYf(px: Number, py: Number): Float = transformY(px.toDouble(), py.toDouble()).toFloat() - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun transformX(px: Number, py: Number): Double = transformX(px.toDouble(), py.toDouble()) - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun transformY(px: Number, py: Number): Double = transformY(px.toDouble(), py.toDouble()) + fun transformXf(px: Int, py: Int): Float = transformX(px.toDouble(), py.toDouble()).toFloat() + fun transformYf(px: Double, py: Double): Float = transformY(px, py).toFloat() + fun transformYf(px: Float, py: Float): Float = transformY(px.toDouble(), py.toDouble()).toFloat() + fun transformYf(px: Int, py: Int): Float = transformY(px.toDouble(), py.toDouble()).toFloat() data class Transform( var x: Double = 0.0, var y: Double = 0.0, var scaleX: Double = 1.0, var scaleY: Double = 1.0, - var skewX: Double = 0.0, var skewY: Double = 0.0, + var skewX: Angle = 0.radians, var skewY: Angle = 0.radians, var rotation: Angle = 0.radians ) : MutableInterpolable, Interpolable { - companion object { - @Deprecated("Kotlin/Native boxes inline + Number") - inline operator fun invoke(x: Number = 0.0, y: Number = 0.0, scaleX: Number = 1.0, scaleY: Number = 1.0, skewX: Number = 0.0, skewY: Number = 0.0, rotation: Angle = 0.radians) = - Transform(x.toDouble(), y.toDouble(), scaleX.toDouble(), scaleY.toDouble(), skewX.toDouble(), skewY.toDouble(), rotation) - } + val scaleAvg get() = (scaleX + scaleY) * 0.5 override fun interpolateWith(ratio: Double, other: Transform): Transform = Transform().setToInterpolated(ratio, this, other) @@ -318,38 +259,9 @@ data class Matrix( y = 0.0 scaleX = 1.0 scaleY = 1.0 - skewX = 0.0 - skewY = 0.0 - rotation = 0.radians - } - - @Deprecated("Use Matrix instead") - fun setMatrix(matrix: IMatrix): Transform { - val PI_4 = PI / 4.0 - this.x = matrix._tx - this.y = matrix._ty - - this.skewX = atan(-matrix._c / matrix._d) - this.skewY = atan(matrix._b / matrix._a) - - // Faster isNaN - if (this.skewX != this.skewX) this.skewX = 0.0 - if (this.skewY != this.skewY) this.skewY = 0.0 - - this.scaleY = - if (this.skewX > -PI_4 && this.skewX < PI_4) matrix._d / cos(this.skewX) else -matrix._c / sin(this.skewX) - this.scaleX = - if (this.skewY > -PI_4 && this.skewY < PI_4) matrix._a / cos(this.skewY) else matrix._b / sin(this.skewY) - - if (abs(this.skewX - this.skewY) < 0.0001) { - this.rotation = this.skewX.radians - this.skewX = 0.0 - this.skewY = 0.0 - } else { - this.rotation = 0.radians - } - - return this + skewX = 0.0.radians + skewY = 0.0.radians + rotation = 0.0.radians } fun setMatrix(matrix: Matrix): Transform { @@ -357,22 +269,22 @@ data class Matrix( this.x = matrix.tx this.y = matrix.ty - this.skewX = atan(-matrix.c / matrix.d) - this.skewY = atan(matrix.b / matrix.a) + this.skewX = atan(-matrix.c / matrix.d).radians + this.skewY = atan(matrix.b / matrix.a).radians // Faster isNaN - if (this.skewX != this.skewX) this.skewX = 0.0 - if (this.skewY != this.skewY) this.skewY = 0.0 + if (this.skewX != this.skewX) this.skewX = 0.0.radians + if (this.skewY != this.skewY) this.skewY = 0.0.radians this.scaleY = - if (this.skewX > -PI_4 && this.skewX < PI_4) matrix.d / cos(this.skewX) else -matrix.c / sin(this.skewX) + if (this.skewX > -PI_4.radians && this.skewX < PI_4.radians) matrix.d / cos(this.skewX) else -matrix.c / sin(this.skewX) this.scaleX = - if (this.skewY > -PI_4 && this.skewY < PI_4) matrix.a / cos(this.skewY) else matrix.b / sin(this.skewY) + if (this.skewY > -PI_4.radians && this.skewY < PI_4.radians) matrix.a / cos(this.skewY) else matrix.b / sin(this.skewY) - if (abs(this.skewX - this.skewY) < 0.0001) { - this.rotation = this.skewX.radians - this.skewX = 0.0 - this.skewY = 0.0 + if (abs(this.skewX - this.skewY).radians < 0.0001) { + this.rotation = this.skewX + this.skewX = 0.0.radians + this.skewY = 0.0.radians } else { this.rotation = 0.radians } @@ -383,7 +295,7 @@ data class Matrix( fun toMatrix(out: Matrix = Matrix()): Matrix = out.setTransform(x, y, scaleX, scaleY, rotation, skewX, skewY) fun copyFrom(that: Transform) = setTo(that.x, that.y, that.scaleX, that.scaleY, that.rotation, that.skewX, that.skewY) - fun setTo(x: Double, y: Double, scaleX: Double, scaleY: Double, rotation: Angle, skewX: Double, skewY: Double): Transform { + fun setTo(x: Double, y: Double, scaleX: Double, scaleY: Double, rotation: Angle, skewX: Angle, skewY: Angle): Transform { this.x = x this.y = y this.scaleX = scaleX @@ -393,10 +305,8 @@ data class Matrix( this.skewY = skewY return this } - - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun setTo(x: Number, y: Number, scaleX: Number, scaleY: Number, rotation: Angle, skewX: Number, skewY: Number): Transform = - setTo(x.toDouble(), y.toDouble(), scaleX.toDouble(), scaleY.toDouble(), rotation, skewX.toDouble(), skewY.toDouble()) + fun setTo(x: Float, y: Float, scaleX: Float, scaleY: Float, rotation: Angle, skewX: Angle, skewY: Angle): Transform = + setTo(x.toDouble(), y.toDouble(), scaleX.toDouble(), scaleY.toDouble(), rotation, skewX, skewY) fun clone() = Transform().copyFrom(this) } @@ -427,7 +337,7 @@ data class Matrix( val tx = this.tx val ty = this.ty try { - return callback() + return this.callback() } finally { this.a = a this.b = b @@ -440,68 +350,3 @@ data class Matrix( override fun toString(): String = "Matrix(a=$a, b=$b, c=$c, d=$d, tx=$tx, ty=$ty)" } - -@Deprecated("Use Matrix instead") -operator fun IMatrix.times(that: IMatrix): Matrix = Matrix().multiply(this, that) - -// Transform points -@Deprecated("Use Matrix instead") -fun IMatrix.transformX(px: Double, py: Double): Double = this._a * px + this._c * py + this._tx -@Deprecated("Use Matrix instead") -fun IMatrix.transformY(px: Double, py: Double): Double = this._d * py + this._b * px + this._ty -@Deprecated("Use Matrix instead") -fun IMatrix.transform(px: Double, py: Double, out: Point = Point()): Point = out.setTo(transformX(px, py), transformY(px, py)) -@Deprecated("Use Matrix instead") -inline fun IMatrix.transform(px: Number, py: Number, out: Point = Point()): Point = transform(px.toDouble(), py.toDouble(), out) -@Deprecated("Use Matrix instead") -inline fun IMatrix.transform(p: IPoint, out: Point = Point()): Point = transform(p.x, p.y, out) -@Deprecated("Use Matrix instead") -inline fun IMatrix.transformXf(px: Number, py: Number): Float = transformX(px.toDouble(), py.toDouble()).toFloat() -@Deprecated("Use Matrix instead") -inline fun IMatrix.transformYf(px: Number, py: Number): Float = transformY(px.toDouble(), py.toDouble()).toFloat() -@Deprecated("Use Matrix instead") -inline fun IMatrix.transformX(px: Number, py: Number): Double = transformX(px.toDouble(), py.toDouble()) -@Deprecated("Use Matrix instead") -inline fun IMatrix.transformY(px: Number, py: Number): Double = transformY(px.toDouble(), py.toDouble()) -@Deprecated("Use Matrix instead") -inline fun IMatrix.transformX(p: IPoint): Double = transformX(p.x, p.y) -@Deprecated("Use Matrix instead") -inline fun IMatrix.transformY(p: IPoint): Double = transformY(p.x, p.y) - -@Deprecated("Use Matrix instead") -fun Matrix.invert(matrixToInvert: IMatrix = this): Matrix { - val src = matrixToInvert - val dst = this - val norm = src._a * src._d - src._b * src._c - - if (norm == 0.0) { - dst.setTo(0.0, 0.0, 0.0, 0.0, -src._tx, -src._ty) - } else { - val inorm = 1.0 / norm - val d = src._a * inorm - val a = src._d * inorm - val b = src._b * -inorm - val c = src._c * -inorm - dst.setTo(a, b, c, d, -a * src._tx - c * src._ty, -b * src._tx - d * src._ty) - } - - return this -} - -@Deprecated("Use Matrix instead") -fun Matrix.multiply(l: IMatrix, r: IMatrix): Matrix = setTo( - l._a * r._a + l._b * r._c, - l._a * r._b + l._b * r._d, - l._c * r._a + l._d * r._c, - l._c * r._b + l._d * r._d, - l._tx * r._a + l._ty * r._c + r._tx, - l._tx * r._b + l._ty * r._d + r._ty -) -@Deprecated("Use Matrix instead") -fun Matrix.premultiply(m: IMatrix) = this.premultiply(m._a, m._b, m._c, m._d, m._tx, m._ty) - -@Deprecated("Use Matrix instead") -fun Matrix.copyFrom(that: IMatrix): Matrix { - setTo(that._a, that._b, that._c, that._d, that._tx, that._ty) - return this -} diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Matrix3D.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Matrix3D.kt index c5de594..43d2c99 100644 --- a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Matrix3D.kt +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Matrix3D.kt @@ -61,9 +61,6 @@ class Matrix3D { operator fun set(row: Int, column: Int, value: Double) = this.set(row, column, value.toFloat()) operator fun set(row: Int, column: Int, value: Int) = this.set(row, column, value.toFloat()) - @Deprecated("Kotlin/Native boxes Number in inline") - inline operator fun set(row: Int, column: Int, value: Number) = set(row, column, value.toFloat()) - inline var v00: Float get() = data[M00]; set(v) = run { data[M00] = v } inline var v01: Float get() = data[M01]; set(v) = run { data[M01] = v } inline var v02: Float get() = data[M02]; set(v) = run { data[M02] = v } @@ -166,6 +163,10 @@ class Matrix3D { data[columnMajorIndex(row, 3)] = d return this } + fun setRow(row: Int, a: Double, b: Double, c: Double, d: Double): Matrix3D = setRow(row, a.toFloat(), b.toFloat(), c.toFloat(), d.toFloat()) + fun setRow(row: Int, a: Int, b: Int, c: Int, d: Int): Matrix3D = setRow(row, a.toFloat(), b.toFloat(), c.toFloat(), d.toFloat()) + fun setRow(row: Int, data: FloatArray): Matrix3D = setRow(row, data[0], data[1], data[2], data[3]) + fun setRow(row: Int, data: Vector3D): Matrix3D = setRow(row, data.x, data.y, data.w, data.z) fun setColumn(column: Int, a: Float, b: Float, c: Float, d: Float): Matrix3D { data[columnMajorIndex(0, column)] = a @@ -174,6 +175,10 @@ class Matrix3D { data[columnMajorIndex(3, column)] = d return this } + fun setColumn(column: Int, a: Double, b: Double, c: Double, d: Double): Matrix3D = setColumn(column, a.toFloat(), b.toFloat(), c.toFloat(), d.toFloat()) + fun setColumn(column: Int, a: Int, b: Int, c: Int, d: Int): Matrix3D = setColumn(column, a.toFloat(), b.toFloat(), c.toFloat(), d.toFloat()) + fun setColumn(column: Int, data: FloatArray): Matrix3D = setColumn(column, data[0], data[1], data[2], data[3]) + fun setColumn(column: Int, data: Vector3D): Matrix3D = setColumn(column, data.x, data.y, data.w, data.z) fun getRow(n: Int, target: FloatArray = FloatArray(4)): FloatArray { val m = n * 4 @@ -226,23 +231,6 @@ class Matrix3D { (v01 * v10 * v22) - (v02 * v11 * v20) - fun setRow(row: Int, data: FloatArray): Matrix3D = setRow(row, data[0], data[1], data[2], data[3]) - fun setColumn(column: Int, data: FloatArray): Matrix3D = setColumn(column, data[0], data[1], data[2], data[3]) - - fun setRow(row: Int, data: Vector3D): Matrix3D = setRow(row, data.x, data.y, data.w, data.z) - fun setColumn(column: Int, data: Vector3D): Matrix3D = setColumn(column, data.x, data.y, data.w, data.z) - - fun setRow(row: Int, a: Double, b: Double, c: Double, d: Double): Matrix3D = setRow(row, a.toFloat(), b.toFloat(), c.toFloat(), d.toFloat()) - fun setRow(row: Int, a: Int, b: Int, c: Int, d: Int): Matrix3D = setRow(row, a.toFloat(), b.toFloat(), c.toFloat(), d.toFloat()) - - fun setColumn(column: Int, a: Double, b: Double, c: Double, d: Double): Matrix3D = setColumn(column, a.toFloat(), b.toFloat(), c.toFloat(), d.toFloat()) - fun setColumn(column: Int, a: Int, b: Int, c: Int, d: Int): Matrix3D = setColumn(column, a.toFloat(), b.toFloat(), c.toFloat(), d.toFloat()) - - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun setRow(row: Int, a: Number, b: Number, c: Number, d: Number): Matrix3D = setRow(row, a.toFloat(), b.toFloat(), c.toFloat(), d.toFloat()) - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun setColumn(column: Int, a: Number, b: Number, c: Number, d: Number): Matrix3D = setColumn(column, a.toFloat(), b.toFloat(), c.toFloat(), d.toFloat()) - fun identity() = this.setColumns( 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, @@ -250,83 +238,66 @@ class Matrix3D { 0f, 0f, 0f, 1f ) - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun setToTranslation(x: Number, y: Number, z: Number, w: Number = 1f) = setToTranslation(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat()) - + fun setToTranslation(x: Float, y: Float, z: Float, w: Float = 1f): Matrix3D = this.setRows( + 1f, 0f, 0f, x, + 0f, 1f, 0f, y, + 0f, 0f, 1f, z, + 0f, 0f, 0f, w + ) fun setToTranslation(x: Double, y: Double, z: Double, w: Double = 1.0) = setToTranslation(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat()) fun setToTranslation(x: Int, y: Int, z: Int, w: Int = 1) = setToTranslation(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat()) - fun setToTranslation(x: Float, y: Float, z: Float, w: Float = 1f): Matrix3D = this.setRows( - 1, 0, 0, x, - 0, 1, 0, y, - 0, 0, 1, z, - 0, 0, 0, w + fun setToScale(x: Float, y: Float, z: Float, w: Float = 1f): Matrix3D = this.setRows( + x, 0f, 0f, 0f, + 0f, y, 0f, 0f, + 0f, 0f, z, 0f, + 0f, 0f, 0f, w ) - - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun setToScale(x: Number, y: Number, z: Number, w: Number = 1f) = setToScale(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat()) fun setToScale(x: Double, y: Double, z: Double, w: Double = 1.0) = setToScale(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat()) fun setToScale(x: Int, y: Int, z: Int, w: Int = 1) = setToScale(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat()) - fun setToScale(x: Float, y: Float, z: Float, w: Float = 1f): Matrix3D = this.setRows( - x, 0, 0, 0, - 0, y, 0, 0, - 0, 0, z, 0, - 0, 0, 0, w + fun setToShear(x: Float, y: Float, z: Float): Matrix3D = this.setRows( + 1f, y, z, 0f, + x, 1f, z, 0f, + x, y, 1f, 0f, + 0f, 0f, 0f, 1f ) - - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun setToShear(x: Number, y: Number, z: Number) = setToShear(x.toFloat(), y.toFloat(), z.toFloat()) fun setToShear(x: Double, y: Double, z: Double) = setToShear(x.toFloat(), y.toFloat(), z.toFloat()) fun setToShear(x: Int, y: Int, z: Int) = setToShear(x.toFloat(), y.toFloat(), z.toFloat()) - fun setToShear(x: Float, y: Float, z: Float): Matrix3D = this.setRows( - 1, y, z, 0, - x, 1, z, 0, - x, y, 1, 0, - 0, 0, 0, 1 - ) - fun setToRotationX(angle: Angle): Matrix3D { - val c = cos(angle) - val s = sin(angle) + val c = cos(angle).toFloat() + val s = sin(angle).toFloat() return this.setRows( - 1, 0, 0, 0, - 0, c, - s, 0, - 0, s, c, 0, - 0, 0, 0, 1 + 1f, 0f, 0f, 0f, + 0f, c, - s, 0f, + 0f, s, c, 0f, + 0f, 0f, 0f, 1f ) } fun setToRotationY(angle: Angle): Matrix3D { - val c = cos(angle) - val s = sin(angle) + val c = cos(angle).toFloat() + val s = sin(angle).toFloat() return this.setRows( - c, 0, s, 0, - 0, 1, 0, 0, - - s, 0, c, 0, - 0, 0, 0, 1 + c, 0f, s, 0f, + 0f, 1f, 0f, 0f, + - s, 0f, c, 0f, + 0f, 0f, 0f, 1f ) } fun setToRotationZ(angle: Angle): Matrix3D { - val c = cos(angle) - val s = sin(angle) + val c = cos(angle).toFloat() + val s = sin(angle).toFloat() return this.setRows( - c, - s, 0, 0, - s, c, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 + c, - s, 0f, 0f, + s, c, 0f, 0f, + 0f, 0f, 1f, 0f, + 0f, 0f, 0f, 1f ) } - fun setToRotation(angle: Angle, direction: Vector3D): Matrix3D = setToRotation(angle, direction.x, direction.y, direction.z) - - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun setToRotation(angle: Angle, x: Number, y: Number, z: Number): Matrix3D = setToRotation(angle, x.toFloat(), y.toFloat(), z.toFloat()) - fun setToRotation(angle: Angle, x: Double, y: Double, z: Double): Matrix3D = setToRotation(angle, x.toFloat(), y.toFloat(), z.toFloat()) - fun setToRotation(angle: Angle, x: Int, y: Int, z: Int): Matrix3D = setToRotation(angle, x.toFloat(), y.toFloat(), z.toFloat()) - fun setToRotation(angle: Angle, x: Float, y: Float, z: Float): Matrix3D { val mag = sqrt(x * x + y * y + z * z) val norm = 1.0 / mag @@ -341,12 +312,15 @@ class Matrix3D { val ty = t * ny return this.setRows( - tx * nx + c, tx * ny - s * nz, tx * nz + s * ny, 0, - tx * ny + s * nz, ty * ny + c, ty * nz - s * nx, 0, - tx * nz - s * ny, ty * nz + s * nx, t * nz * nz + c, 0, - 0, 0, 0, 1 + tx * nx + c, tx * ny - s * nz, tx * nz + s * ny, 0.0, + tx * ny + s * nz, ty * ny + c, ty * nz - s * nx, 0.0, + tx * nz - s * ny, ty * nz + s * nx, t * nz * nz + c, 0.0, + 0.0, 0.0, 0.0, 1.0 ) } + fun setToRotation(angle: Angle, direction: Vector3D): Matrix3D = setToRotation(angle, direction.x, direction.y, direction.z) + fun setToRotation(angle: Angle, x: Double, y: Double, z: Double): Matrix3D = setToRotation(angle, x.toFloat(), y.toFloat(), z.toFloat()) + fun setToRotation(angle: Angle, x: Int, y: Int, z: Int): Matrix3D = setToRotation(angle, x.toFloat(), y.toFloat(), z.toFloat()) fun multiply(l: Matrix3D, r: Matrix3D) = this.setRows( (l.v00 * r.v00) + (l.v01 * r.v10) + (l.v02 * r.v20) + (l.v03 * r.v30), @@ -370,6 +344,59 @@ class Matrix3D { (l.v30 * r.v03) + (l.v31 * r.v13) + (l.v32 * r.v23) + (l.v33 * r.v33) ) + fun multiply( + lv00: Float, lv01: Float, lv02: Float, lv03: Float, + lv10: Float, lv11: Float, lv12: Float, lv13: Float, + lv20: Float, lv21: Float, lv22: Float, lv23: Float, + lv30: Float, lv31: Float, lv32: Float, lv33: Float, + + rv00: Float, rv01: Float, rv02: Float, rv03: Float, + rv10: Float, rv11: Float, rv12: Float, rv13: Float, + rv20: Float, rv21: Float, rv22: Float, rv23: Float, + rv30: Float, rv31: Float, rv32: Float, rv33: Float, + ) = this.setRows( + (lv00 * rv00) + (lv01 * rv10) + (lv02 * rv20) + (lv03 * rv30), + (lv00 * rv01) + (lv01 * rv11) + (lv02 * rv21) + (lv03 * rv31), + (lv00 * rv02) + (lv01 * rv12) + (lv02 * rv22) + (lv03 * rv32), + (lv00 * rv03) + (lv01 * rv13) + (lv02 * rv23) + (lv03 * rv33), + + (lv10 * rv00) + (lv11 * rv10) + (lv12 * rv20) + (lv13 * rv30), + (lv10 * rv01) + (lv11 * rv11) + (lv12 * rv21) + (lv13 * rv31), + (lv10 * rv02) + (lv11 * rv12) + (lv12 * rv22) + (lv13 * rv32), + (lv10 * rv03) + (lv11 * rv13) + (lv12 * rv23) + (lv13 * rv33), + + (lv20 * rv00) + (lv21 * rv10) + (lv22 * rv20) + (lv23 * rv30), + (lv20 * rv01) + (lv21 * rv11) + (lv22 * rv21) + (lv23 * rv31), + (lv20 * rv02) + (lv21 * rv12) + (lv22 * rv22) + (lv23 * rv32), + (lv20 * rv03) + (lv21 * rv13) + (lv22 * rv23) + (lv23 * rv33), + + (lv30 * rv00) + (lv31 * rv10) + (lv32 * rv20) + (lv33 * rv30), + (lv30 * rv01) + (lv31 * rv11) + (lv32 * rv21) + (lv33 * rv31), + (lv30 * rv02) + (lv31 * rv12) + (lv32 * rv22) + (lv33 * rv32), + (lv30 * rv03) + (lv31 * rv13) + (lv32 * rv23) + (lv33 * rv33) + ) + + fun multiply( + lv00: Double, lv01: Double, lv02: Double, lv03: Double, + lv10: Double, lv11: Double, lv12: Double, lv13: Double, + lv20: Double, lv21: Double, lv22: Double, lv23: Double, + lv30: Double, lv31: Double, lv32: Double, lv33: Double, + + rv00: Double, rv01: Double, rv02: Double, rv03: Double, + rv10: Double, rv11: Double, rv12: Double, rv13: Double, + rv20: Double, rv21: Double, rv22: Double, rv23: Double, + rv30: Double, rv31: Double, rv32: Double, rv33: Double, + ) = multiply( + lv00.toFloat(), lv01.toFloat(), lv02.toFloat(), lv03.toFloat(), + lv10.toFloat(), lv11.toFloat(), lv12.toFloat(), lv13.toFloat(), + lv20.toFloat(), lv21.toFloat(), lv22.toFloat(), lv23.toFloat(), + lv30.toFloat(), lv31.toFloat(), lv32.toFloat(), lv33.toFloat(), + rv00.toFloat(), rv01.toFloat(), rv02.toFloat(), rv03.toFloat(), + rv10.toFloat(), rv11.toFloat(), rv12.toFloat(), rv13.toFloat(), + rv20.toFloat(), rv21.toFloat(), rv22.toFloat(), rv23.toFloat(), + rv30.toFloat(), rv31.toFloat(), rv32.toFloat(), rv33.toFloat(), + ) + fun multiply(scale: Float, l: Matrix3D = this) = this.apply { for (n in 0 until 16) this.data[n] = l.data[n] * scale } @@ -393,51 +420,30 @@ class Matrix3D { fun transform(v: Vector3D, out: Vector3D = Vector3D()): Vector3D = transform(v.x, v.y, v.z, v.w, out) - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun setToOrtho(rect: Rectangle, near: Number = 0f, far: Number = 1f): Matrix3D = setToOrtho(rect.left, rect.right, rect.bottom, rect.top, near.toDouble(), far.toDouble()) - fun setToOrtho(rect: Rectangle, near: Double = 0.0, far: Double = 1.0): Matrix3D = setToOrtho(rect.left, rect.right, rect.bottom, rect.top, near, far) - fun setToOrtho(rect: Rectangle, near: Float = 0f, far: Float = 1f): Matrix3D = setToOrtho(rect.left, rect.right, rect.bottom, rect.top, near.toDouble(), far.toDouble()) - fun setToOrtho(rect: Rectangle, near: Int = 0, far: Int = 1): Matrix3D = setToOrtho(rect.left, rect.right, rect.bottom, rect.top, near.toDouble(), far.toDouble()) - - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun setToOrtho(left: Number, right: Number, bottom: Number, top: Number, near: Number, far: Number): Matrix3D = - setToOrtho(left.toFloat(), right.toFloat(), bottom.toFloat(), top.toFloat(), near.toFloat(), far.toFloat()) - - inline fun setToOrtho(left: Double, right: Double, bottom: Double, top: Double, near: Double, far: Double): Matrix3D = - setToOrtho(left.toFloat(), right.toFloat(), bottom.toFloat(), top.toFloat(), near.toFloat(), far.toFloat()) - inline fun setToOrtho(left: Int, right: Int, bottom: Int, top: Int, near: Int, far: Int): Matrix3D = - setToOrtho(left.toFloat(), right.toFloat(), bottom.toFloat(), top.toFloat(), near.toFloat(), far.toFloat()) - fun setToOrtho(left: Float, right: Float, bottom: Float, top: Float, near: Float = 0f, far: Float = 1f): Matrix3D { - val sx = 2 / (right - left) - val sy = 2 / (top - bottom) - val sz = -2 / (far - near) + val sx = 2f / (right - left) + val sy = 2f / (top - bottom) + val sz = -2f / (far - near) val tx = -(right + left) / (right - left) val ty = -(top + bottom) / (top - bottom) val tz = -(far + near) / (far - near) return setRows( - sx, 0, 0, tx, - 0, sy, 0, ty, - 0, 0, sz, tz, - 0, 0, 0, 1 + sx, 0f, 0f, tx, + 0f, sy, 0f, ty, + 0f, 0f, sz, tz, + 0f, 0f, 0f, 1f ) } - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun setToFrustum(rect: Rectangle, zNear: Number = 0f, zFar: Number = 1f): Matrix3D = setToFrustum(rect.left, rect.right, rect.bottom, rect.top, zNear.toDouble(), zFar.toDouble()) - fun setToFrustum(rect: Rectangle, zNear: Double = 0.0, zFar: Double = 1.0): Matrix3D = setToFrustum(rect.left, rect.right, rect.bottom, rect.top, zNear.toDouble(), zFar.toDouble()) - fun setToFrustum(rect: Rectangle, zNear: Float = 0f, zFar: Float = 1f): Matrix3D = setToFrustum(rect.left, rect.right, rect.bottom, rect.top, zNear.toDouble(), zFar.toDouble()) - fun setToFrustum(rect: Rectangle, zNear: Int = 0, zFar: Int = 1): Matrix3D = setToFrustum(rect.left, rect.right, rect.bottom, rect.top, zNear.toDouble(), zFar.toDouble()) - - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun setToFrustum(left: Number, right: Number, bottom: Number, top: Number, zNear: Number = 0f, zFar: Number = 1f): Matrix3D - = setToFrustum(left.toFloat(), right.toFloat(), bottom.toFloat(), top.toFloat(), zNear.toFloat(), zFar.toFloat()) - inline fun setToFrustum(left: Double, right: Double, bottom: Double, top: Double, zNear: Double = 0.0, zFar: Double = 1.0): Matrix3D - = setToFrustum(left.toFloat(), right.toFloat(), bottom.toFloat(), top.toFloat(), zNear.toFloat(), zFar.toFloat()) - inline fun setToFrustum(left: Int, right: Int, bottom: Int, top: Int, zNear: Int = 0, zFar: Int = 1): Matrix3D - = setToFrustum(left.toFloat(), right.toFloat(), bottom.toFloat(), top.toFloat(), zNear.toFloat(), zFar.toFloat()) + fun setToOrtho(rect: Rectangle, near: Double = 0.0, far: Double = 1.0): Matrix3D = setToOrtho(rect.left, rect.right, rect.bottom, rect.top, near, far) + fun setToOrtho(rect: Rectangle, near: Float = 0f, far: Float = 1f): Matrix3D = setToOrtho(rect.left, rect.right, rect.bottom, rect.top, near.toDouble(), far.toDouble()) + fun setToOrtho(rect: Rectangle, near: Int = 0, far: Int = 1): Matrix3D = setToOrtho(rect.left, rect.right, rect.bottom, rect.top, near.toDouble(), far.toDouble()) + fun setToOrtho(left: Double, right: Double, bottom: Double, top: Double, near: Double, far: Double): Matrix3D = + setToOrtho(left.toFloat(), right.toFloat(), bottom.toFloat(), top.toFloat(), near.toFloat(), far.toFloat()) + fun setToOrtho(left: Int, right: Int, bottom: Int, top: Int, near: Int, far: Int): Matrix3D = + setToOrtho(left.toFloat(), right.toFloat(), bottom.toFloat(), top.toFloat(), near.toFloat(), far.toFloat()) fun setToFrustum(left: Float, right: Float, bottom: Float, top: Float, zNear: Float = 0f, zFar: Float = 1f): Matrix3D { if (zNear <= 0.0f || zFar <= zNear) { @@ -457,18 +463,21 @@ class Matrix3D { val D = -2.0f * (zFar * zNear) / dz return setRows( - zNear2 / dx, 0, A, 0, - 0, zNear2 / dy, B, 0, - 0, 0, C, D, - 0, 0, -1, 0 + zNear2 / dx, 0f, A, 0f, + 0f, zNear2 / dy, B, 0f, + 0f, 0f, C, D, + 0f, 0f, -1f, 0f ) } + fun setToFrustum(rect: Rectangle, zNear: Double = 0.0, zFar: Double = 1.0): Matrix3D = setToFrustum(rect.left, rect.right, rect.bottom, rect.top, zNear.toDouble(), zFar.toDouble()) + fun setToFrustum(rect: Rectangle, zNear: Float = 0f, zFar: Float = 1f): Matrix3D = setToFrustum(rect.left, rect.right, rect.bottom, rect.top, zNear.toDouble(), zFar.toDouble()) + fun setToFrustum(rect: Rectangle, zNear: Int = 0, zFar: Int = 1): Matrix3D = setToFrustum(rect.left, rect.right, rect.bottom, rect.top, zNear.toDouble(), zFar.toDouble()) + + fun setToFrustum(left: Double, right: Double, bottom: Double, top: Double, zNear: Double = 0.0, zFar: Double = 1.0): Matrix3D + = setToFrustum(left.toFloat(), right.toFloat(), bottom.toFloat(), top.toFloat(), zNear.toFloat(), zFar.toFloat()) + fun setToFrustum(left: Int, right: Int, bottom: Int, top: Int, zNear: Int = 0, zFar: Int = 1): Matrix3D + = setToFrustum(left.toFloat(), right.toFloat(), bottom.toFloat(), top.toFloat(), zNear.toFloat(), zFar.toFloat()) - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun setToPerspective(fovy: Angle, aspect: Number, zNear: Number, zFar: Number): Matrix3D - = setToPerspective(fovy, aspect.toFloat(), zNear.toFloat(), zFar.toFloat()) - fun setToPerspective(fovy: Angle, aspect: Double, zNear: Double, zFar: Double): Matrix3D - = setToPerspective(fovy, aspect.toFloat(), zNear.toFloat(), zFar.toFloat()) fun setToPerspective(fovy: Angle, aspect: Float, zNear: Float, zFar: Float): Matrix3D { val top = tan(fovy.radians / 2f) * zNear @@ -477,6 +486,9 @@ class Matrix3D { val right = aspect * top return setToFrustum(left.toFloat(), right.toFloat(), bottom.toFloat(), top.toFloat(), zNear, zFar) } + fun setToPerspective(fovy: Angle, aspect: Double, zNear: Double, zFar: Double): Matrix3D + = setToPerspective(fovy, aspect.toFloat(), zNear.toFloat(), zFar.toFloat()) + override fun equals(other: Any?): Boolean = (other is Matrix3D) && this.data.contentEquals(other.data) override fun hashCode(): Int = data.contentHashCode() @@ -519,18 +531,6 @@ fun Matrix3D.copyToFloat2x2(out: FloatArray, order: MajorOrder, offset: Int) = c fun Matrix3D.copyToFloat3x3(out: FloatArray, order: MajorOrder, offset: Int) = copyToFloatWxH(out, 3, 3, order, offset) fun Matrix3D.copyToFloat4x4(out: FloatArray, order: MajorOrder, offset: Int) = copyToFloatWxH(out, 4, 4, order, offset) -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun Matrix3D.setRows( - a00: Number, a01: Number, a02: Number, a03: Number, - a10: Number, a11: Number, a12: Number, a13: Number, - a20: Number, a21: Number, a22: Number, a23: Number, - a30: Number, a31: Number, a32: Number, a33: Number -): Matrix3D = setRows( - a00.toFloat(), a01.toFloat(), a02.toFloat(), a03.toFloat(), - a10.toFloat(), a11.toFloat(), a12.toFloat(), a13.toFloat(), - a20.toFloat(), a21.toFloat(), a22.toFloat(), a23.toFloat(), - a30.toFloat(), a31.toFloat(), a32.toFloat(), a33.toFloat() -) fun Matrix3D.setRows( a00: Double, a01: Double, a02: Double, a03: Double, a10: Double, a11: Double, a12: Double, a13: Double, @@ -554,18 +554,6 @@ fun Matrix3D.setRows( a30, a31, a32, a33 ) -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun Matrix3D.setColumns( - a00: Number, a10: Number, a20: Number, a30: Number, - a01: Number, a11: Number, a21: Number, a31: Number, - a02: Number, a12: Number, a22: Number, a32: Number, - a03: Number, a13: Number, a23: Number, a33: Number -): Matrix3D = setColumns( - a00.toFloat(), a10.toFloat(), a20.toFloat(), a30.toFloat(), - a01.toFloat(), a11.toFloat(), a21.toFloat(), a31.toFloat(), - a02.toFloat(), a12.toFloat(), a22.toFloat(), a32.toFloat(), - a03.toFloat(), a13.toFloat(), a23.toFloat(), a33.toFloat() -) fun Matrix3D.setColumns( a00: Double, a10: Double, a20: Double, a30: Double, a01: Double, a11: Double, a21: Double, a31: Double, @@ -589,17 +577,6 @@ fun Matrix3D.setColumns( a03, a13, a23, a33 ) -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun Matrix3D.setRows3x3( - a00: Number, a01: Number, a02: Number, - a10: Number, a11: Number, a12: Number, - a20: Number, a21: Number, a22: Number -): Matrix3D = setRows( - a00.toFloat(), a01.toFloat(), a02.toFloat(), 0f, - a10.toFloat(), a11.toFloat(), a12.toFloat(), 0f, - a20.toFloat(), a21.toFloat(), a22.toFloat(), 0f, - 0f, 0f, 0f, 1f -) fun Matrix3D.setRows3x3( a00: Double, a01: Double, a02: Double, a10: Double, a11: Double, a12: Double, @@ -621,17 +598,6 @@ fun Matrix3D.setRows3x3( 0f, 0f, 0f, 1f ) -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun Matrix3D.setColumns3x3( - a00: Number, a10: Number, a20: Number, - a01: Number, a11: Number, a21: Number, - a02: Number, a12: Number, a22: Number -): Matrix3D = setColumns( - a00.toFloat(), a10.toFloat(), a20.toFloat(), 0f, - a01.toFloat(), a11.toFloat(), a21.toFloat(), 0f, - a02.toFloat(), a12.toFloat(), a22.toFloat(), 0f, - 0f, 0f, 0f, 1f -) fun Matrix3D.setColumns3x3( a00: Double, a10: Double, a20: Double, a01: Double, a11: Double, a21: Double, @@ -653,16 +619,6 @@ fun Matrix3D.setColumns3x3( 0f, 0f, 0f, 1f ) -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun Matrix3D.setRows2x2( - a00: Number, a01: Number, - a10: Number, a11: Number -): Matrix3D = setRows( - a00.toFloat(), a01.toFloat(), 0f, 0f, - a10.toFloat(), a11.toFloat(), 0f, 0f, - 0f, 0f, 1f, 0f, - 0f, 0f, 0f, 1f -) fun Matrix3D.setRows2x2( a00: Double, a01: Double, a10: Double, a11: Double @@ -682,18 +638,6 @@ fun Matrix3D.setRows2x2( 0f, 0f, 0f, 1f ) -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun Matrix3D.Companion.fromRows( - a00: Number, a01: Number, a02: Number, a03: Number, - a10: Number, a11: Number, a12: Number, a13: Number, - a20: Number, a21: Number, a22: Number, a23: Number, - a30: Number, a31: Number, a32: Number, a33: Number -): Matrix3D = Matrix3D().setRows( - a00.toFloat(), a01.toFloat(), a02.toFloat(), a03.toFloat(), - a10.toFloat(), a11.toFloat(), a12.toFloat(), a13.toFloat(), - a20.toFloat(), a21.toFloat(), a22.toFloat(), a23.toFloat(), - a30.toFloat(), a31.toFloat(), a32.toFloat(), a33.toFloat() -) fun Matrix3D.Companion.fromRows( a00: Double, a01: Double, a02: Double, a03: Double, a10: Double, a11: Double, a12: Double, a13: Double, @@ -717,18 +661,6 @@ fun Matrix3D.Companion.fromRows( a30, a31, a32, a33 ) -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun Matrix3D.Companion.fromColumns( - a00: Number, a10: Number, a20: Number, a30: Number, - a01: Number, a11: Number, a21: Number, a31: Number, - a02: Number, a12: Number, a22: Number, a32: Number, - a03: Number, a13: Number, a23: Number, a33: Number -): Matrix3D = Matrix3D().setColumns( - a00.toFloat(), a10.toFloat(), a20.toFloat(), a30.toFloat(), - a01.toFloat(), a11.toFloat(), a21.toFloat(), a31.toFloat(), - a02.toFloat(), a12.toFloat(), a22.toFloat(), a32.toFloat(), - a03.toFloat(), a13.toFloat(), a23.toFloat(), a33.toFloat() -) fun Matrix3D.Companion.fromColumns( a00: Double, a10: Double, a20: Double, a30: Double, a01: Double, a11: Double, a21: Double, a31: Double, @@ -752,16 +684,6 @@ fun Matrix3D.Companion.fromColumns( a03, a13, a23, a33 ) -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun Matrix3D.setColumns2x2( - a00: Number, a10: Number, - a01: Number, a11: Number -): Matrix3D = setColumns( - a00.toFloat(), a10.toFloat(), 0f, 0f, - a01.toFloat(), a11.toFloat(), 0f, 0f, - 0f, 0f, 1f, 0f, - 0f, 0f, 0f, 1f -) fun Matrix3D.setColumns2x2( a00: Double, a10: Double, a01: Double, a11: Double @@ -781,16 +703,6 @@ fun Matrix3D.setColumns2x2( 0f, 0f, 0f, 1f ) -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun Matrix3D.Companion.fromRows3x3( - a00: Number, a01: Number, a02: Number, - a10: Number, a11: Number, a12: Number, - a20: Number, a21: Number, a22: Number -): Matrix3D = Matrix3D().setRows3x3( - a00.toFloat(), a01.toFloat(), a02.toFloat(), - a10.toFloat(), a11.toFloat(), a12.toFloat(), - a20.toFloat(), a21.toFloat(), a22.toFloat() -) fun Matrix3D.Companion.fromRows3x3( a00: Double, a01: Double, a02: Double, a10: Double, a11: Double, a12: Double, @@ -810,16 +722,6 @@ fun Matrix3D.Companion.fromRows3x3( a20, a21, a22 ) -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun Matrix3D.Companion.fromColumns3x3( - a00: Number, a10: Number, a20: Number, - a01: Number, a11: Number, a21: Number, - a02: Number, a12: Number, a22: Number -): Matrix3D = Matrix3D().setColumns3x3( - a00.toFloat(), a10.toFloat(), a20.toFloat(), - a01.toFloat(), a11.toFloat(), a21.toFloat(), - a02.toFloat(), a12.toFloat(), a22.toFloat() -) fun Matrix3D.Companion.fromColumns3x3( a00: Double, a10: Double, a20: Double, a01: Double, a11: Double, a21: Double, @@ -839,14 +741,6 @@ fun Matrix3D.Companion.fromColumns3x3( a02, a12, a22 ) -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun Matrix3D.Companion.fromRows2x2( - a00: Number, a01: Number, - a10: Number, a11: Number -): Matrix3D = Matrix3D().setRows2x2( - a00.toFloat(), a01.toFloat(), - a10.toFloat(), a11.toFloat() -) fun Matrix3D.Companion.fromRows2x2( a00: Double, a01: Double, a10: Double, a11: Double @@ -862,14 +756,6 @@ fun Matrix3D.Companion.fromRows2x2( a10, a11 ) -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun Matrix3D.Companion.fromColumns2x2( - a00: Number, a10: Number, - a01: Number, a11: Number -): Matrix3D = Matrix3D().setColumns2x2( - a00.toFloat(), a10.toFloat(), - a01.toFloat(), a11.toFloat() -) fun Matrix3D.Companion.fromColumns2x2( a00: Double, a10: Double, a01: Double, a11: Double @@ -888,17 +774,14 @@ fun Matrix3D.Companion.fromColumns2x2( operator fun Matrix3D.times(that: Matrix3D): Matrix3D = Matrix3D().multiply(this, that) operator fun Matrix3D.times(value: Float): Matrix3D = Matrix3D(this).multiply(value) operator fun Matrix3D.times(value: Double): Matrix3D = this * value.toFloat() -@Deprecated("Kotlin/Native boxes inline + Number") -inline operator fun Matrix3D.times(value: Number): Matrix3D = this * value.toFloat() +operator fun Matrix3D.times(value: Int): Matrix3D = this * value.toFloat() operator fun Matrix3D.div(value: Float): Matrix3D = this * (1f / value) operator fun Matrix3D.div(value: Double): Matrix3D = this / value.toFloat() -@Deprecated("Kotlin/Native boxes inline + Number") -inline operator fun Matrix3D.div(value: Number): Matrix3D = this / value.toFloat() +operator fun Matrix3D.div(value: Int): Matrix3D = this / value.toFloat() fun Matrix3D.multiply(scale: Double, l: Matrix3D = this) = multiply(scale.toFloat(), l) -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun Matrix3D.multiply(scale: Number, l: Matrix3D = this) = multiply(scale.toFloat(), l) +fun Matrix3D.multiply(scale: Int, l: Matrix3D = this) = multiply(scale.toFloat(), l) @PublishedApi @@ -909,30 +792,23 @@ fun Matrix3D.translate(x: Float, y: Float, z: Float, w: Float = 1f, temp: Matrix temp.setToTranslation(x, y, z, w) this.multiply(this, temp) } +fun Matrix3D.translate(x: Double, y: Double, z: Double, w: Double = 1.0, temp: Matrix3D = tempMat3D) = this.translate(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat(), temp) +fun Matrix3D.translate(x: Int, y: Int, z: Int, w: Int = 1, temp: Matrix3D = tempMat3D) = this.translate(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat(), temp) + fun Matrix3D.rotate(angle: Angle, x: Float, y: Float, z: Float, temp: Matrix3D = tempMat3D) = this.apply { temp.setToRotation(angle, x, y, z) this.multiply(this, temp) } +fun Matrix3D.rotate(angle: Angle, x: Double, y: Double, z: Double, temp: Matrix3D = tempMat3D) = this.rotate(angle, x.toFloat(), y.toFloat(), z.toFloat(), temp) +fun Matrix3D.rotate(angle: Angle, x: Int, y: Int, z: Int, temp: Matrix3D = tempMat3D) = this.rotate(angle, x.toFloat(), y.toFloat(), z.toFloat(), temp) + fun Matrix3D.scale(x: Float, y: Float, z: Float, w: Float = 1f, temp: Matrix3D = tempMat3D) = this.apply { temp.setToScale(x, y, z, w) this.multiply(this, temp) } -inline fun Matrix3D.translate(x: Double, y: Double, z: Double, w: Double = 1.0, temp: Matrix3D = tempMat3D) = this.translate(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat(), temp) -inline fun Matrix3D.rotate(angle: Angle, x: Double, y: Double, z: Double, temp: Matrix3D = tempMat3D) = this.rotate(angle, x.toFloat(), y.toFloat(), z.toFloat(), temp) -inline fun Matrix3D.scale(x: Double, y: Double, z: Double, w: Double = 1.0, temp: Matrix3D = tempMat3D) = this.scale(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat(), temp) - -inline fun Matrix3D.translate(x: Int, y: Int, z: Int, w: Int = 1, temp: Matrix3D = tempMat3D) = this.translate(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat(), temp) -inline fun Matrix3D.rotate(angle: Angle, x: Int, y: Int, z: Int, temp: Matrix3D = tempMat3D) = this.rotate(angle, x.toFloat(), y.toFloat(), z.toFloat(), temp) -inline fun Matrix3D.scale(x: Int, y: Int, z: Int, w: Int = 1, temp: Matrix3D = tempMat3D) = this.scale(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat(), temp) - -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun Matrix3D.translate(x: Number, y: Number, z: Number, w: Number = 1f, temp: Matrix3D = tempMat3D) = this.translate(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat(), temp) -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun Matrix3D.rotate(angle: Angle, x: Number, y: Number, z: Number, temp: Matrix3D = tempMat3D) = this.rotate(angle, x.toFloat(), y.toFloat(), z.toFloat(), temp) -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun Matrix3D.scale(x: Number, y: Number, z: Number, w: Number = 1f, temp: Matrix3D = tempMat3D) = this.scale(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat(), temp) - +fun Matrix3D.scale(x: Double, y: Double, z: Double, w: Double = 1.0, temp: Matrix3D = tempMat3D) = this.scale(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat(), temp) +fun Matrix3D.scale(x: Int, y: Int, z: Int, w: Int = 1, temp: Matrix3D = tempMat3D) = this.scale(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat(), temp) fun Matrix3D.setToRotation(quat: Quaternion, temp: Matrix3D = tempMat3D) = this.apply { quat.toMatrix(temp) @@ -956,15 +832,6 @@ fun Matrix3D.rotate(quat: Quaternion, temp: Matrix3D = tempMat3D) = this.apply { this.multiply(this, temp) } -fun Vector3D.sub(l: Vector3D, r: Vector3D): Vector3D = setTo(l.x - r.x, l.y - r.y, l.z - r.z, l.w - r.w) -fun Vector3D.add(l: Vector3D, r: Vector3D): Vector3D = setTo(l.x + r.x, l.y + r.y, l.z + r.z, l.w + r.w) -fun Vector3D.cross(a: Vector3D, b: Vector3D): Vector3D = setTo( - (a.y * b.z - a.z * b.y), - (a.z * b.x - a.x * b.z), - (a.x * b.y - a.y * b.x), - 1f -) - private val tempVec1 = Vector3D() private val tempVec2 = Vector3D() private val tempVec3 = Vector3D() @@ -1001,10 +868,10 @@ inline fun Matrix3D.rotate(angle: Angle, v: Vector3D, temp: Matrix3D = tempMat3D inline fun Matrix3D.scale(v: Vector3D, temp: Matrix3D = tempMat3D) = scale(v.x, v.y, v.z, v.w, temp) fun Matrix3D.setTRS(translation: Position3D, rotation: Quaternion, scale: Scale3D): Matrix3D { - val rx = rotation.x - val ry = rotation.y - val rz = rotation.z - val rw = rotation.w + val rx = rotation.x.toFloat() + val ry = rotation.y.toFloat() + val rz = rotation.z.toFloat() + val rw = rotation.w.toFloat() val xt = rx + rx val yt = ry + ry @@ -1026,7 +893,7 @@ fun Matrix3D.setTRS(translation: Position3D, rotation: Quaternion, scale: Scale3 ((1 - (yy + zz)) * scale.x), ((xy - wz) * scale.y), ((xz + wy) * scale.z), translation.x, ((xy + wz) * scale.x), ((1 - (xx + zz)) * scale.y), ((yz - wx) * scale.z), translation.y, ((xz - wy) * scale.x), ((yz + wx) * scale.y), ((1 - (xx + yy)) * scale.z), translation.z, - 0, 0, 0, 1 + 0f, 0f, 0f, 1f ) } @@ -1034,11 +901,11 @@ private val tempMat1 = Matrix3D() fun Matrix3D.getTRS(position: Position3D, rotation: Quaternion, scale: Scale3D): Matrix3D = this.apply { val det = determinant - position.setTo(v03, v13, v23, 1) - scale.setTo(Vector3D.length(v00, v10, v20) * det.sign, Vector3D.length(v01, v11, v21), Vector3D.length(v02, v12, v22), 1) - val invSX = 1.0 / scale.x - val invSY = 1.0 / scale.y - val invSZ = 1.0 / scale.z + position.setTo(v03, v13, v23, 1f) + scale.setTo(Vector3D.length(v00, v10, v20) * det.sign, Vector3D.length(v01, v11, v21), Vector3D.length(v02, v12, v22), 1f) + val invSX = 1f / scale.x + val invSY = 1f / scale.y + val invSZ = 1f / scale.z rotation.setFromRotationMatrix(tempMat1.setRows( v00 * invSX, v01 * invSY, v02 * invSZ, v03, v10 * invSX, v11 * invSY, v12 * invSZ, v13, diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/MatrixExt.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/MatrixExt.kt index 91a9e07..7450281 100644 --- a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/MatrixExt.kt +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/MatrixExt.kt @@ -1,10 +1,10 @@ package com.soywiz.korma.geom -fun Matrix3D.copyFrom(that: IMatrix): Matrix3D = that.toMatrix3D(this) +fun Matrix3D.copyFrom(that: Matrix): Matrix3D = that.toMatrix3D(this) -fun IMatrix.toMatrix3D(out: Matrix3D = Matrix3D()): Matrix3D = out.setRows( - a, c, 0, tx, - b, d, 0, ty, - 0, 0, 1, 0, - 0, 0, 0, 1 +fun Matrix.toMatrix3D(out: Matrix3D = Matrix3D()): Matrix3D = out.setRows( + a, c, 0.0, tx, + b, d, 0.0, ty, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 ) diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Point.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Point.kt index 659ef43..d71531c 100644 --- a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Point.kt +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Point.kt @@ -2,122 +2,84 @@ package com.soywiz.korma.geom -import com.soywiz.korma.internal.* +import com.soywiz.korma.internal.niceStr import com.soywiz.korma.interpolation.* import kotlin.math.* -//@Deprecated("Use Point instead") interface IPoint { - val _x: Double - val _y: Double + val x: Double + val y: Double companion object { - //@Deprecated("Use Point instead") operator fun invoke(): IPoint = Point(0.0, 0.0) - @Deprecated("Kotlin/Native boxes inline + Number") - inline operator fun invoke(x: Number, y: Number): IPoint = Point(x.toDouble(), y.toDouble()) + operator fun invoke(v: IPoint): IPoint = Point(v.x, v.y) + operator fun invoke(x: Double, y: Double): IPoint = Point(x, y) + operator fun invoke(x: Float, y: Float): IPoint = Point(x, y) + operator fun invoke(x: Int, y: Int): IPoint = Point(x, y) } } -//@Deprecated("Use Point instead") -val IPoint.x: Double get() = _x -//@Deprecated("Use Point instead") -val IPoint.y: Double get() = _y - -@Deprecated("Kotlin/Native boxes inline + Number") -operator fun Point.Companion.invoke(v: IPoint): Point = Point(v._x, v._y) -//@Deprecated("Use Point instead") -fun Point.Companion.middle(a: IPoint, b: IPoint): Point = Point((a._x + b._x) * 0.5, (a._y + b._y) * 0.5) -//@Deprecated("Use Point instead") +fun Point.Companion.middle(a: IPoint, b: IPoint): Point = Point((a.x + b.x) * 0.5, (a.y + b.y) * 0.5) fun Point.Companion.angle(a: IPoint, b: IPoint): Angle = Angle.fromRadians(acos((a.dot(b)) / (a.length * b.length))) -//@Deprecated("Use Point instead") -fun Point.Companion.compare(l: IPoint, r: IPoint): Int = Point.compare(l._x, l._y, r._x, r._y) -//@Deprecated("Use Point instead") -fun Point.Companion.distance(a: IPoint, b: IPoint): Double = Point.distance(a._x, a._y, b._x, b._y) -//@Deprecated("Use Point instead") -fun Point.copyFrom(that: IPoint) = setTo(that._x, that._y) -//@Deprecated("Use Point instead") +fun Point.Companion.compare(l: IPoint, r: IPoint): Int = Point.compare(l.x, l.y, r.x, r.y) +fun Point.Companion.distance(a: IPoint, b: IPoint): Double = Point.distance(a.x, a.y, b.x, b.y) +fun Point.copyFrom(that: IPoint) = setTo(that.x, that.y) fun Point.add(p: IPoint) = this.setToAdd(this, p) -//@Deprecated("Use Point instead") fun Point.sub(p: IPoint) = this.setToSub(this, p) -// @TODO: mul instead of dot -//@Deprecated("Use Point instead") -operator fun IPoint.plus(that: IPoint): IPoint = IPoint(_x + that._x, _y + that._y) -//@Deprecated("Use Point instead") -operator fun IPoint.minus(that: IPoint): IPoint = IPoint(_x - that._x, _y - that._y) -//@Deprecated("Use Point instead") -operator fun IPoint.times(that: IPoint): IPoint = IPoint(_x * that._x, _y * that._y) -//@Deprecated("Use Point instead") -operator fun IPoint.div(that: IPoint): IPoint = IPoint(_x / that._x, _y / that._y) -//@Deprecated("Use Point instead") -inline operator fun IPoint.times(scale: Number): IPoint = IPoint(_x * scale.toDouble(), _y * scale.toDouble()) -//@Deprecated("Use Point instead") -inline operator fun IPoint.div(scale: Number): IPoint = IPoint(_x / scale.toDouble(), _y / scale.toDouble()) -//@Deprecated("Use Point instead") -infix fun IPoint.dot(that: IPoint): Double = this._x * that._x + this._y * that._y -//@Deprecated("Use Point instead") -inline fun IPoint.distanceTo(x: Number, y: Number): Double = hypot(x.toDouble() - this._x, y.toDouble() - this._y) -//@Deprecated("Use Point instead") -fun IPoint.distanceTo(that: IPoint): Double = distanceTo(that._x, that._y) -//@Deprecated("Use Point instead") -fun IPoint.angleTo(other: IPoint): Angle = Angle.between(this._x, this._y, other._x, other._y) -//@Deprecated("Use Point instead") -fun IPoint.transformed(mat: IMatrix, out: Point = Point()): Point = out.setToTransform(mat, this) -//@Deprecated("Use Point instead") + +operator fun IPoint.plus(that: IPoint): IPoint = IPoint(x + that.x, y + that.y) +operator fun IPoint.minus(that: IPoint): IPoint = IPoint(x - that.x, y - that.y) +operator fun IPoint.times(that: IPoint): IPoint = IPoint(x * that.x, y * that.y) +operator fun IPoint.div(that: IPoint): IPoint = IPoint(x / that.x, y / that.y) + +operator fun IPoint.times(scale: Double): IPoint = IPoint(x * scale, y * scale) +operator fun IPoint.div(scale: Double): IPoint = IPoint(x / scale, y / scale) +fun IPoint.distanceTo(x: Double, y: Double): Double = hypot(x - this.x, y - this.y) + +operator fun IPoint.times(scale: Int): IPoint = this * scale.toDouble() +operator fun IPoint.div(scale: Int): IPoint = this / scale.toDouble() +fun IPoint.distanceTo(x: Int, y: Int): Double = this.distanceTo(x.toDouble(), y.toDouble()) + +operator fun IPoint.times(scale: Float): IPoint = this * scale.toDouble() +operator fun IPoint.div(scale: Float): IPoint = this / scale.toDouble() +fun IPoint.distanceTo(x: Float, y: Float): Double = this.distanceTo(x.toDouble(), y.toDouble()) + +infix fun IPoint.dot(that: IPoint): Double = this.x * that.x + this.y * that.y +fun IPoint.distanceTo(that: IPoint): Double = distanceTo(that.x, that.y) +fun IPoint.angleTo(other: IPoint): Angle = Angle.between(this.x, this.y, other.x, other.y) +fun IPoint.transformed(mat: Matrix, out: Point = Point()): Point = out.setToTransform(mat, this) operator fun IPoint.get(index: Int) = when (index) { - 0 -> _x; 1 -> _y + 0 -> x; 1 -> y else -> throw IndexOutOfBoundsException("IPoint doesn't have $index component") } -//@Deprecated("Use Point instead") val IPoint.unit: IPoint get() = this / this.length -//@Deprecated("Use Point instead") -val IPoint.length: Double get() = hypot(_x, _y) -//@Deprecated("Use Point instead") -val IPoint.magnitude: Double get() = hypot(_x, _y) -//@Deprecated("Use Point instead") +val IPoint.length: Double get() = hypot(x, y) +val IPoint.magnitude: Double get() = hypot(x, y) val IPoint.normalized: IPoint get() { val imag = 1.0 / magnitude - return IPoint(_x * imag, _y * imag) + return IPoint(x * imag, y * imag) } -//@Deprecated("Use Point instead") -val IPoint.mutable: Point get() = Point(_x, _y) -//@Deprecated("Use Point instead") -val IPoint.immutable: IPoint get() = IPoint(_x, _y) -//@Deprecated("Use Point instead") -fun IPoint.copy() = IPoint(_x, _y) -//@Deprecated("Use Point instead") -fun Point.setToTransform(mat: IMatrix, p: IPoint): Point = setToTransform(mat, p._x, p._y) -//@Deprecated("Use Point instead") -fun Point.setToTransform(mat: IMatrix, x: Double, y: Double): Point = setTo(mat.transformX(x, y), mat.transformY(x, y)) -//@Deprecated("Use Point instead") -fun Point.setToAdd(a: IPoint, b: IPoint): Point = setTo(a._x + b._x, a._y + b._y) -//@Deprecated("Use Point instead") -fun Point.setToSub(a: IPoint, b: IPoint): Point = setTo(a._x - b._x, a._y - b._y) -//@Deprecated("Use Point instead") -fun Point.setToMul(a: IPoint, b: IPoint): Point = setTo(a._x * b._x, a._y * b._y) -//@Deprecated("Use Point instead") -fun Point.setToMul(a: IPoint, s: Double): Point = setTo(a._x * s, a._y * s) -//@Deprecated("Use Point instead") +val IPoint.mutable: Point get() = Point(x, y) +val IPoint.immutable: IPoint get() = IPoint(x, y) +fun IPoint.copy() = IPoint(x, y) +fun Point.setToTransform(mat: Matrix, p: IPoint): Point = setToTransform(mat, p.x, p.y) +fun Point.setToTransform(mat: Matrix, x: Double, y: Double): Point = setTo(mat.transformX(x, y), mat.transformY(x, y)) +fun Point.setToAdd(a: IPoint, b: IPoint): Point = setTo(a.x + b.x, a.y + b.y) +fun Point.setToSub(a: IPoint, b: IPoint): Point = setTo(a.x - b.x, a.y - b.y) +fun Point.setToMul(a: IPoint, b: IPoint): Point = setTo(a.x * b.x, a.y * b.y) +fun Point.setToMul(a: IPoint, s: Double): Point = setTo(a.x * s, a.y * s) inline fun Point.setToMul(a: IPoint, s: Number): Point = setToMul(a, s.toDouble()) -//@Deprecated("Use Point instead") -fun Point.setToDiv(a: IPoint, b: IPoint): Point = setTo(a._x / b._x, a._y / b._y) -//@Deprecated("Use Point instead") -fun Point.setToDiv(a: IPoint, s: Double): Point = setTo(a._x / s, a._y / s) -//@Deprecated("Use Point instead") +fun Point.setToDiv(a: IPoint, b: IPoint): Point = setTo(a.x / b.x, a.y / b.y) +fun Point.setToDiv(a: IPoint, s: Double): Point = setTo(a.x / s, a.y / s) inline fun Point.setToDiv(a: IPoint, s: Number): Point = setToDiv(a, s.toDouble()) -//@Deprecated("Use Point instead") -operator fun Point.plusAssign(that: IPoint): Unit = run { setTo(this.x + that._x, this.y + that._y) } +operator fun Point.plusAssign(that: IPoint): Unit = run { setTo(this.x + that.x, this.y + that.y) } data class Point( - var x: Double, - var y: Double + override var x: Double, + override var y: Double ) : MutableInterpolable, Interpolable, Comparable, IPoint { - override val _x: Double get() = x - override val _y: Double get() = y - - @Deprecated("Kotlin/Native boxes inline + Number") - override fun compareTo(other: IPoint): Int = compare(this.x, this.y, other._x, other._y) + override fun compareTo(other: IPoint): Int = compare(this.x, this.y, other.x, other.y) fun compareTo(other: Point): Int = compare(this.x, this.y, other.x, other.y) fun setToZero() = setTo(0.0, 0.0) @@ -128,29 +90,22 @@ data class Point( fun setToRight() = setTo(+1.0, 0.0) companion object { - @Deprecated("") - val Zero: IPoint = Point(0.0, 0.0) - @Deprecated("") - val One: IPoint = Point(1.0, 1.0) - - @Deprecated("") - val Up: IPoint = Point(0.0, +1.0) - @Deprecated("") - val Down: IPoint = Point(0.0, -1.0) - @Deprecated("") - val Left: IPoint = Point(-1.0, 0.0) - @Deprecated("") - val Right: IPoint = Point(+1.0, 0.0) + val Zero: IPoint = IPoint(0.0, 0.0) + val One: IPoint = IPoint(1.0, 1.0) + val Up: IPoint = IPoint(0.0, +1.0) + val Down: IPoint = IPoint(0.0, -1.0) + val Left: IPoint = IPoint(-1.0, 0.0) + val Right: IPoint = IPoint(+1.0, 0.0) //inline operator fun invoke(): Point = Point(0.0, 0.0) // @TODO: // e: java.lang.NullPointerException at org.jetbrains.kotlin.com.google.gwt.dev.js.JsAstMapper.mapFunction(JsAstMapper.java:562) (val pt = Array(1) { Point() }) operator fun invoke(): Point = Point(0.0, 0.0) operator fun invoke(v: Point): Point = Point(v.x, v.y) - - inline operator fun invoke(x: Float, y: Float): Point = Point(x.toDouble(), y.toDouble()) - inline operator fun invoke(x: Int, y: Int): Point = Point(x.toDouble(), y.toDouble()) - inline operator fun invoke(xy: Int): Point = Point(xy.toDouble(), xy.toDouble()) - inline operator fun invoke(xy: Float): Point = Point(xy.toDouble(), xy.toDouble()) - inline operator fun invoke(xy: Double): Point = Point(xy, xy) + operator fun invoke(v: IPoint): Point = Point(v.x, v.y) + operator fun invoke(x: Float, y: Float): Point = Point(x.toDouble(), y.toDouble()) + operator fun invoke(x: Int, y: Int): Point = Point(x.toDouble(), y.toDouble()) + operator fun invoke(xy: Int): Point = Point(xy.toDouble(), xy.toDouble()) + operator fun invoke(xy: Float): Point = Point(xy.toDouble(), xy.toDouble()) + operator fun invoke(xy: Double): Point = Point(xy, xy) /** Constructs a point from polar coordinates determined by an [angle] and a [length]. Angle 0 is pointing to the right, and the direction is counter-clock-wise */ inline operator fun invoke(angle: Angle, length: Double = 1.0): Point = fromPolar(angle, length) @@ -158,11 +113,6 @@ data class Point( /** Constructs a point from polar coordinates determined by an [angle] and a [length]. Angle 0 is pointing to the right, and the direction is counter-clock-wise */ fun fromPolar(angle: Angle, length: Double = 1.0): Point = Point(angle.cosine * length, angle.sine * length) - @Deprecated("Kotlin/Native boxes inline + Number") - inline operator fun invoke(x: Number, y: Number): Point = Point(x.toDouble(), y.toDouble()) - @Deprecated("Kotlin/Native boxes inline + Number") - inline operator fun invoke(xy: Number): Point = Point(xy.toDouble(), xy.toDouble()) - fun middle(a: Point, b: Point): Point = Point((a.x + b.x) * 0.5, (a.y + b.y) * 0.5) fun angle(a: Point, b: Point): Angle = Angle.fromRadians(acos((a.dot(b)) / (a.length * b.length))) @@ -180,11 +130,8 @@ data class Point( fun distance(a: Double, b: Double): Double = kotlin.math.abs(a - b) fun distance(x1: Double, y1: Double, x2: Double, y2: Double): Double = kotlin.math.hypot(x1 - x2, y1 - y2) - - inline fun distance(x1: Float, y1: Float, x2: Float, y2: Float): Double = distance(x1.toDouble(), y1.toDouble(), x2.toDouble(), y2.toDouble()) - inline fun distance(x1: Int, y1: Int, x2: Int, y2: Int): Double = distance(x1.toDouble(), y1.toDouble(), x2.toDouble(), y2.toDouble()) - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun distance(x1: Number, y1: Number, x2: Number, y2: Number): Double = distance(x1.toDouble(), y1.toDouble(), x2.toDouble(), y2.toDouble()) + fun distance(x1: Float, y1: Float, x2: Float, y2: Float): Double = distance(x1.toDouble(), y1.toDouble(), x2.toDouble(), y2.toDouble()) + fun distance(x1: Int, y1: Int, x2: Int, y2: Int): Double = distance(x1.toDouble(), y1.toDouble(), x2.toDouble(), y2.toDouble()) fun distance(a: Point, b: Point): Double = distance(a.x, a.y, b.x, b.y) fun distance(a: IPointInt, b: IPointInt): Double = distance(a.x, a.y, b.x, b.y) @@ -207,10 +154,8 @@ data class Point( /** Updates a point from polar coordinates determined by an [angle] and a [length]. Angle 0 is pointing to the right, and the direction is counter-clock-wise */ fun setToPolar(angle: Angle, length: Double = 1.0): Point = setTo(angle.cosine * length, angle.sine * length) - fun neg() = setTo(-x, -y) - fun mul(s: Double) = setTo(x * s, y * s) - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun mul(s: Number) = mul(s.toDouble()) + fun neg() = setTo(-this.x, -this.y) + fun mul(s: Double) = setTo(this.x * s, this.y * s) fun mul(s: Float) = mul(s.toDouble()) fun mul(s: Int) = mul(s.toDouble()) @@ -225,58 +170,49 @@ data class Point( fun setToSub(a: Point, b: Point): Point = setTo(a.x - b.x, a.y - b.y) fun setToMul(a: Point, b: Point): Point = setTo(a.x * b.x, a.y * b.y) fun setToMul(a: Point, s: Double): Point = setTo(a.x * s, a.y * s) + fun setToMul(a: Point, s: Float): Point = setToMul(a, s.toDouble()) fun setToDiv(a: Point, b: Point): Point = setTo(a.x / b.x, a.y / b.y) fun setToDiv(a: Point, s: Double): Point = setTo(a.x / s, a.y / s) + fun setToDiv(a: Point, s: Float): Point = setToDiv(a, s.toDouble()) operator fun plusAssign(that: Point): Unit = run { setTo(this.x + that.x, this.y + that.y) } - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun setToMul(a: Point, s: Number): Point = setToMul(a, s.toDouble()) - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun setToDiv(a: Point, s: Number): Point = setToDiv(a, s.toDouble()) - - operator fun plus(that: Point): Point = Point(_x + that._x, _y + that._y) - operator fun minus(that: Point): Point = Point(_x - that._x, _y - that._y) - operator fun times(that: Point): Point = Point(_x * that._x, _y * that._y) - operator fun div(that: Point): Point = Point(_x / that._x, _y / that._y) - infix fun dot(that: Point): Double = this._x * that._x + this._y * that._y + operator fun plus(that: Point): Point = Point(this.x + that.x, this.y + that.y) + operator fun minus(that: Point): Point = Point(this.x - that.x, this.y - that.y) + operator fun times(that: Point): Point = Point(this.x * that.x, this.y * that.y) + operator fun div(that: Point): Point = Point(this.x / that.x, this.y / that.y) + infix fun dot(that: Point): Double = this.x * that.x + this.y * that.y - operator fun times(scale: Double): Point = Point(_x * scale.toDouble(), _y * scale.toDouble()) - @Deprecated("Kotlin/Native boxes inline + Number") - inline operator fun times(scale: Number): Point = this * scale.toDouble() + operator fun times(scale: Double): Point = Point(this.x * scale, this.y * scale) operator fun times(scale: Float): Point = this * scale.toDouble() operator fun times(scale: Int): Point = this * scale.toDouble() - operator fun div(scale: Double): Point = Point(_x / scale.toDouble(), _y / scale.toDouble()) - @Deprecated("Kotlin/Native boxes inline + Number") - inline operator fun div(scale: Number): Point = this / scale.toDouble() + operator fun div(scale: Double): Point = Point(this.x / scale, this.y / scale) operator fun div(scale: Float): Point = this / scale.toDouble() operator fun div(scale: Int): Point = this / scale.toDouble() - fun distanceTo(x: Double, y: Double): Double = hypot(x.toDouble() - this._x, y.toDouble() - this._y) - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun distanceTo(x: Number, y: Number): Double = hypot(x.toDouble() - this._x, y.toDouble() - this._y) + fun distanceTo(x: Double, y: Double): Double = hypot(x - this.x, y - this.y) fun distanceTo(x: Int, y: Int): Double = distanceTo(x.toDouble(), y.toDouble()) fun distanceTo(x: Float, y: Float): Float = distanceTo(x.toDouble(), y.toDouble()).toFloat() - fun distanceTo(that: Point): Double = distanceTo(that._x, that._y) - fun angleTo(other: Point): Angle = Angle.between(this._x, this._y, other._x, other._y) + fun distanceTo(that: Point): Double = distanceTo(that.x, that.y) + fun angleTo(other: Point): Angle = Angle.between(this.x, this.y, other.x, other.y) fun transformed(mat: Matrix, out: Point = Point()): Point = out.setToTransform(mat, this) operator fun get(index: Int) = when (index) { - 0 -> x; 1 -> y + 0 -> this.x; 1 -> this.y else -> throw IndexOutOfBoundsException("IPoint doesn't have $index component") } - val mutable: Point get() = Point(_x, _y) - val immutable: Point get() = Point(_x, _y) - fun copy() = Point(_x, _y) + val mutable: Point get() = Point(this.x, this.y) + val immutable: Point get() = Point(this.x, this.y) + fun copy() = Point(this.x, this.y) val unit: Point get() = this / this.length - val length: Double get() = hypot(_x, _y) - val magnitude: Double get() = hypot(_x, _y) + val length: Double get() = hypot(this.x, this.y) + val magnitude: Double get() = hypot(this.x, this.y) val normalized: Point get() { val imag = 1.0 / magnitude - return Point(_x * imag, _y * imag) + return Point(this.x * imag, this.y * imag) } fun normalize() { @@ -290,7 +226,10 @@ data class Point( override fun setToInterpolated(ratio: Double, l: Point, r: Point): Point = this.setTo(ratio.interpolate(l.x, r.x), ratio.interpolate(l.y, r.y)) - override fun toString(): String = "(${x.niceStr}, ${y.niceStr})" + override fun toString(): String = "(${this.x.niceStr}, ${this.y.niceStr})" + + fun rotate(rotation: Angle, out: Point = Point()): Point = + out.setToPolar(Angle.between(0.0, 0.0, this.x, this.y) + rotation, this.length) } @@ -339,9 +278,8 @@ operator fun IPointInt.rem(that: IPointInt) = PointInt(this.x % that.x, this.y % fun Point.asInt(): PointInt = PointInt(this) fun PointInt.asDouble(): Point = this.p -val Point.int get() = PointInt(x.toInt(), y.toInt()) -//@Deprecated("Use Point instead") -val IPoint.int get() = PointInt(_x.toInt(), _y.toInt()) +val Point.int get() = PointInt(this.x.toInt(), this.y.toInt()) +val IPoint.int get() = PointInt(this.x.toInt(), this.y.toInt()) val IPointInt.float get() = IPoint(x.toDouble(), y.toDouble()) fun List.getPolylineLength(): Double { @@ -355,7 +293,6 @@ fun List.getPolylineLength(): Double { } fun List.bounds(out: Rectangle = Rectangle(), bb: BoundsBuilder = BoundsBuilder()): Rectangle = bb.add(this).getBounds(out) -//@Deprecated("Use Point instead") fun Iterable.getPolylineLength(): Double { var out = 0.0 var prev: IPoint? = null @@ -365,5 +302,4 @@ fun Iterable.getPolylineLength(): Double { } return out } -//@Deprecated("Use Point instead") fun Iterable.bounds(out: Rectangle = Rectangle(), bb: BoundsBuilder = BoundsBuilder()): Rectangle = bb.add(this).getBounds(out) diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/PointArrayList.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/PointArrayList.kt index ab33c57..516318a 100644 --- a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/PointArrayList.kt +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/PointArrayList.kt @@ -1,7 +1,6 @@ package com.soywiz.korma.geom import com.soywiz.kds.* -import com.soywiz.korma.algo.* import kotlin.math.* interface IPointArrayList { @@ -10,14 +9,18 @@ interface IPointArrayList { fun getY(index: Int): Double } -fun IPointArrayList.getPoint(index: Int): Point = Point(getX(index), getY(index)) +inline fun IPointArrayList.fastForEach(block: (x: Double, y: Double) -> Unit) { + for (n in 0 until size) { + block(getX(n), getY(n)) + } +} + +fun IPointArrayList.getPoint(index: Int, out: Point = Point()): Point = out.setTo(getX(index), getY(index)) fun IPointArrayList.getIPoint(index: Int): IPoint = IPoint(getX(index), getY(index)) + fun IPointArrayList.toPoints(): List = (0 until size).map { getPoint(it) } -@Deprecated("Use Point instead") fun IPointArrayList.toIPoints(): List = (0 until size).map { getIPoint(it) } -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun IPointArrayList.contains(x: Number, y: Number): Boolean = contains(x.toDouble(), y.toDouble()) fun IPointArrayList.contains(x: Float, y: Float): Boolean = contains(x.toDouble(), y.toDouble()) fun IPointArrayList.contains(x: Int, y: Int): Boolean = contains(x.toDouble(), y.toDouble()) fun IPointArrayList.contains(x: Double, y: Double): Boolean { @@ -52,17 +55,14 @@ class PointArrayList(capacity: Int = 7) : IPointArrayList { xList += x yList += y } + fun add(x: Float, y: Float) = add(x.toDouble(), y.toDouble()) + fun add(x: Int, y: Int) = add(x.toDouble(), y.toDouble()) fun add(p: Point) = add(p.x, p.y) - fun add(p: PointArrayList) = this.apply { p.fastForEach { x, y -> add(x, y) } } - - inline fun fastForEach(block: (x: Double, y: Double) -> Unit) { - for (n in 0 until size) { - block(getX(n), getY(n)) - } - } + fun add(p: IPoint) = add(p.x, p.y) + fun add(p: IPointArrayList) = this.apply { p.fastForEach { x, y -> add(x, y) } } - fun copyFrom(other: PointArrayList): PointArrayList = this.apply { clear() }.apply { add(other) } + fun copyFrom(other: IPointArrayList): PointArrayList = this.apply { clear() }.apply { add(other) } fun clone(out: PointArrayList = PointArrayList()): PointArrayList = out.clear().add(this) fun toList(): List { @@ -92,14 +92,22 @@ class PointArrayList(capacity: Int = 7) : IPointArrayList { yList.removeAt(index, count) } - fun setX(index: Int, x: Double) = run { xList[index] = x } - fun setY(index: Int, y: Double) = run { yList[index] = y } + fun setX(index: Int, x: Double) { xList[index] = x } + fun setX(index: Int, x: Int) = setX(index, x.toDouble()) + fun setX(index: Int, x: Float) = setX(index, x.toDouble()) + + fun setY(index: Int, y: Double) { yList[index] = y } + fun setY(index: Int, y: Int) = setY(index, y.toDouble()) + fun setY(index: Int, y: Float) = setY(index, y.toDouble()) + fun setXY(index: Int, x: Double, y: Double) { xList[index] = x yList[index] = y } + fun setXY(index: Int, x: Int, y: Int) = setXY(index, x.toDouble(), y.toDouble()) + fun setXY(index: Int, x: Float, y: Float) = setXY(index, x.toDouble(), y.toDouble()) - fun transform(matrix: IMatrix) { + fun transform(matrix: Matrix) { for (n in 0 until size) { val x = getX(n) val y = getY(n) @@ -128,8 +136,8 @@ class PointArrayList(capacity: Int = 7) : IPointArrayList { } fun swap(indexA: Int, indexB: Int) { - xList.swapIndices(indexA, indexB) - yList.swapIndices(indexA, indexB) + xList.swap(indexA, indexB) + yList.swap(indexA, indexB) } fun reverse() { @@ -146,27 +154,6 @@ class PointArrayList(capacity: Int = 7) : IPointArrayList { } } -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun PointArrayList.add(x: Number, y: Number) = add(x.toDouble(), y.toDouble()) -@Deprecated("Use Point instead") -fun PointArrayList.add(p: IPoint) = add(p._x, p._y) -fun PointArrayList.add(other: IPointArrayList) = this.apply { for (n in 0 until other.size) add(other.getX(n), other.getY(n)) } - -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun PointArrayList.setX(index: Int, x: Number) = setX(index, x.toDouble()) -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun PointArrayList.setY(index: Int, y: Number) = setY(index, y.toDouble()) -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun PointArrayList.setXY(index: Int, x: Number, y: Number) = setXY(index, x.toDouble(), y.toDouble()) - -fun PointArrayList.setX(index: Int, x: Float) = setX(index, x.toDouble()) -fun PointArrayList.setY(index: Int, y: Float) = setY(index, y.toDouble()) -fun PointArrayList.setXY(index: Int, x: Float, y: Float) = setXY(index, x.toDouble(), y.toDouble()) - -fun PointArrayList.setX(index: Int, x: Int) = setX(index, x.toDouble()) -fun PointArrayList.setY(index: Int, y: Int) = setY(index, y.toDouble()) -fun PointArrayList.setXY(index: Int, x: Int, y: Int) = setXY(index, x.toDouble(), y.toDouble()) - ////////////////////////////////////// interface IPointIntArrayList { @@ -175,6 +162,20 @@ interface IPointIntArrayList { fun getY(index: Int): Int } +fun IPointIntArrayList.getPoint(index: Int, out: PointInt = PointInt()): PointInt = out.setTo(getX(index), getY(index)) +fun IPointIntArrayList.getIPoint(index: Int): IPointInt = IPointInt(getX(index), getY(index)) +fun IPointIntArrayList.toPoints(): List = (0 until size).map { getPoint(it) } +fun IPointIntArrayList.toIPoints(): List = (0 until size).map { getIPoint(it) } +fun IPointIntArrayList.contains(x: Int, y: Int): Boolean { + for (n in 0 until size) if (getX(n) == x && getY(n) == y) return true + return false +} +inline fun IPointIntArrayList.fastForEach(block: (x: Int, y: Int) -> Unit) { + for (n in 0 until size) { + block(getX(n), getY(n)) + } +} + class PointIntArrayList(capacity: Int = 7) : IPointIntArrayList { private val xList = IntArrayList(capacity) private val yList = IntArrayList(capacity) @@ -202,6 +203,8 @@ class PointIntArrayList(capacity: Int = 7) : IPointIntArrayList { xList += x yList += y } + fun add(p: IPointInt) = add(p.x, p.y) + fun add(p: IPointIntArrayList) = this.apply { p.fastForEach { x, y -> add(x, y) } } inline fun fastForEach(block: (x: Int, y: Int) -> Unit) { for (n in 0 until size) { @@ -245,8 +248,8 @@ class PointIntArrayList(capacity: Int = 7) : IPointIntArrayList { } fun swap(indexA: Int, indexB: Int) { - xList.swapIndices(indexA, indexB) - yList.swapIndices(indexA, indexB) + xList.swap(indexA, indexB) + yList.swap(indexA, indexB) } fun reverse() { @@ -262,14 +265,3 @@ class PointIntArrayList(capacity: Int = 7) : IPointIntArrayList { override fun swap(subject: PointIntArrayList, indexL: Int, indexR: Int) = subject.swap(indexL, indexR) } } - -fun PointIntArrayList.add(p: IPointInt) = add(p.x, p.y) -fun PointIntArrayList.add(other: IPointIntArrayList) = this.apply { for (n in 0 until other.size) add(other.getX(n), other.getY(n)) } -fun IPointIntArrayList.getPoint(index: Int): PointInt = PointInt(getX(index), getY(index)) -fun IPointIntArrayList.getIPoint(index: Int): IPointInt = IPointInt(getX(index), getY(index)) -fun IPointIntArrayList.toPoints(): List = (0 until size).map { getPoint(it) } -fun IPointIntArrayList.toIPoints(): List = (0 until size).map { getIPoint(it) } -fun IPointIntArrayList.contains(x: Int, y: Int): Boolean { - for (n in 0 until size) if (getX(n) == x && getY(n) == y) return true - return false -} diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/PointArea.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/PointPool.kt similarity index 70% rename from korma/src/commonMain/kotlin/com/soywiz/korma/geom/PointArea.kt rename to korma/src/commonMain/kotlin/com/soywiz/korma/geom/PointPool.kt index 1df9a72..9b37ad9 100644 --- a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/PointArea.kt +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/PointPool.kt @@ -1,7 +1,7 @@ package com.soywiz.korma.geom @Suppress("NOTHING_TO_INLINE") -class PointArea(val size: Int) { +class PointPool(val size: Int) { @PublishedApi internal val points = Array(size) { com.soywiz.korma.geom.Point() } @PublishedApi @@ -11,30 +11,24 @@ class PointArea(val size: Int) { internal fun alloc() = points[offset++] fun Point(x: Double, y: Double) = alloc().setTo(x, y) + fun Point(x: Float, y: Float) = Point(x.toDouble(), y.toDouble()) fun Point(x: Int, y: Int) = Point(x.toDouble(), y.toDouble()) fun Point() = Point(0.0, 0.0) - @Deprecated("Kotlin/Native boxes Number in inline") - inline fun Point(x: Number, y: Number) = Point(x.toDouble(), y.toDouble()) - operator fun IPoint.plus(other: IPoint): IPoint = alloc().setToAdd(this, other) operator fun IPoint.minus(other: IPoint): IPoint = alloc().setToSub(this, other) operator fun IPoint.times(value: IPoint): IPoint = alloc().setToMul(this, value) - operator fun IPoint.div(value: IPoint): IPoint = alloc().setToDiv(this, value) - operator fun IPoint.times(value: Double): IPoint = alloc().setToMul(this, value) - operator fun IPoint.div(value: Double): IPoint = alloc().setToDiv(this, value) - + operator fun IPoint.times(value: Float): IPoint = this * value.toDouble() operator fun IPoint.times(value: Int): IPoint = this * value.toDouble() - operator fun IPoint.div(value: Int): IPoint = this / value.toDouble() - @Deprecated("Kotlin/Native boxes Number in inline") - inline operator fun IPoint.times(value: Number): IPoint = this * value.toDouble() - @Deprecated("Kotlin/Native boxes Number in inline") - inline operator fun IPoint.div(value: Number): IPoint = this / value.toDouble() + operator fun IPoint.div(value: IPoint): IPoint = alloc().setToDiv(this, value) + operator fun IPoint.div(value: Double): IPoint = alloc().setToDiv(this, value) + operator fun IPoint.div(value: Float): IPoint = this / value.toDouble() + operator fun IPoint.div(value: Int): IPoint = this / value.toDouble() - inline operator fun invoke(callback: PointArea.() -> Unit) { + inline operator fun invoke(callback: PointPool.() -> Unit) { val oldOffset = offset try { callback() diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Quaternion.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Quaternion.kt new file mode 100644 index 0000000..72e5682 --- /dev/null +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Quaternion.kt @@ -0,0 +1,148 @@ +package com.soywiz.korma.geom + +import kotlin.math.* + +// https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles +data class Quaternion( + var x: Double = 0.0, + var y: Double = 0.0, + var z: Double = 0.0, + var w: Double = 1.0 +) { + companion object { + fun dotProduct(l: Quaternion, r: Quaternion): Double = l.x * r.x + l.y * r.y + l.z * r.z + l.w * r.w + operator fun invoke(x: Float, y: Float, z: Float, w: Float) = Quaternion(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble()) + operator fun invoke(x: Int, y: Int, z: Int, w: Int) = Quaternion(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble()) + fun toEuler(q: Quaternion, out: EulerRotation = EulerRotation()): EulerRotation = toEuler(q.x, q.y, q.z, q.w, out) + fun toEuler(x: Double, y: Double, z: Double, w: Double, euler: EulerRotation = EulerRotation()): EulerRotation = + toEuler(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat(), euler) + fun toEuler(x: Int, y: Int, z: Int, w: Int, euler: EulerRotation = EulerRotation()): EulerRotation = + toEuler(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat(), euler) + + fun toEuler(x: Float, y: Float, z: Float, w: Float, out: EulerRotation = EulerRotation()): EulerRotation { + val sinrCosp = +2.0 * (w * x + y * z) + val cosrCosp = +1.0 - 2.0 * (x * x + y * y) + val roll = atan2(sinrCosp, cosrCosp) + val sinp = +2.0 * (w * y - z * x) + val pitch = when { + abs(sinp) >= 1 -> if (sinp > 0) PI / 2 else -PI / 2 + else -> asin(sinp) + } + val sinyCosp = +2.0 * (w * z + x * y) + val cosyCosp = +1.0 - 2.0 * (y * y + z * z) + val yaw = atan2(sinyCosp, cosyCosp) + return out.setTo(roll.radians, pitch.radians, yaw.radians) + } + } + + operator fun get(index: Int): Double = when (index) { + 0 -> x + 1 -> y + 2 -> z + 3 -> w + else -> Double.NaN + } + inline fun setToFunc(callback: (Int) -> Double) = setTo(callback(0), callback(1), callback(2), callback(3)) + fun setTo(x: Double, y: Double, z: Double, w: Double): Quaternion { + this.x = x + this.y = y + this.z = z + this.w = w + return this + } + fun setTo(x: Int, y: Int, z: Int, w: Int): Quaternion = setTo(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble()) + fun setTo(x: Float, y: Float, z: Float, w: Float): Quaternion = setTo(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble()) + fun setTo(euler: EulerRotation): Quaternion = EulerRotation.toQuaternion(euler, this) + fun setTo(other: Quaternion): Quaternion = setTo(other.x, other.y, other.z, other.w) + + fun setEuler(x: Angle, y: Angle, z: Angle): Quaternion = EulerRotation.toQuaternion(x, y, z, this) + fun setEuler(euler: EulerRotation): Quaternion = EulerRotation.toQuaternion(euler, this) + + fun copyFrom(other: Quaternion): Quaternion = this.setTo(other) + + operator fun unaryMinus(): Quaternion = Quaternion(-x, -y, -z, -w) + operator fun plus(other: Quaternion): Quaternion = Quaternion(x + other.x, y + other.y, z + other.z, w + other.w) + operator fun minus(other: Quaternion): Quaternion = Quaternion(x - other.x, y - other.y, z - other.z, w - other.w) + operator fun times(scale: Double): Quaternion = Quaternion(x * scale, y * scale, z * scale, w * scale) + + fun negate() = this.setTo(-x, -y, -z, -w) + + inline fun setToFunc(l: Quaternion, r: Quaternion, func: (l: Double, r: Double) -> Double) = setTo( + func(l.x, r.x), + func(l.y, r.y), + func(l.z, r.z), + func(l.w, r.w) + ) + fun setToSlerp(left: Quaternion, right: Quaternion, t: Double, tleft: Quaternion = Quaternion(), tright: Quaternion = Quaternion()): Quaternion { + val tleft = tleft.copyFrom(left).normalize() + val tright = tright.copyFrom(right).normalize() + + var dot = dotProduct(tleft, right) + + if (dot < 0.0f) { + tright.negate() + dot = -dot + } + + if (dot > 0.99995f) return setToFunc(tleft, tright) { l, r -> l + t * (r - l) } + + val angle0 = acos(dot) + val angle1 = angle0 * t + + val s1 = sin(angle1) / sin(angle0) + val s0 = cos(angle1) - dot * s1 + + return setToFunc(tleft, tright) { l, r -> (s0 * l) + (s1 * r) } + } + + fun setToNlerp(left: Quaternion, right: Quaternion, t: Double): Quaternion { + val sign = if (dotProduct(left, right) < 0) -1 else +1 + return setToFunc { (1f - t) * left[it] + t * right[it] * sign }.normalize() + } + + fun setToInterpolated(left: Quaternion, right: Quaternion, t: Double): Quaternion = setToSlerp(left, right, t) + + fun setFromRotationMatrix(m: Matrix3D) = this.apply { + val q = this + m.apply { + val t = v00 + v11 + v22 + when { + t > 0 -> { + val s = 0.5 / sqrt(t + 1.0) + q.setTo(((v21 - v12) * s), ((v02 - v20) * s), ((v10 - v01) * s), (0.25 / s)) + } + v00 > v11 && v00 > v22 -> { + val s = 2.0 * sqrt(1.0 + v00 - v11 - v22) + q.setTo((0.25 * s), ((v01 + v10) / s), ((v02 + v20) / s), ((v21 - v12) / s)) + } + v11 > v22 -> { + val s = 2.0 * sqrt(1.0 + v11 - v00 - v22) + q.setTo(((v01 + v10) / s), (0.25 * s), ((v12 + v21) / s), ((v02 - v20) / s)) + } + else -> { + val s = 2.0 * sqrt(1.0 + v22 - v00 - v11) + q.setTo(((v02 + v20) / s), ((v12 + v21) / s), (0.25f * s), ((v10 - v01) / s)) + } + } + } + } + + fun normalize(v: Quaternion = this): Quaternion { + val length = 1.0 / Vector3D.length(v.x, v.y, v.z, v.w) + return this.setTo(v.x / length, v.y / length, v.z / length, v.w / length) + } + fun toMatrix(out: Matrix3D = Matrix3D()): Matrix3D = out.multiply( + // Left + w, z, -y, x, + -z, w, x, y, + y, -x, w, z, + -x, -y, -z, w, + // Right + w, z, -y, -x, + -z, w, x, -y, + y, -x, w, -z, + x, y, z, w, + ) +} + +operator fun Double.times(scale: Quaternion): Quaternion = scale.times(this) diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/QuaternionEuler.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/QuaternionEuler.kt deleted file mode 100644 index f8894e9..0000000 --- a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/QuaternionEuler.kt +++ /dev/null @@ -1,221 +0,0 @@ -package com.soywiz.korma.geom - -import kotlin.math.* - -data class EulerRotation( - var x: Angle = 0.degrees, - var y: Angle = 0.degrees, - var z: Angle = 0.degrees -) { - companion object -} - -data class Quaternion( - var x: Double = 0.0, - var y: Double = 0.0, - var z: Double = 0.0, - var w: Double = 1.0 -) { - operator fun get(index: Int): Double = when (index) { - 0 -> x - 1 -> y - 2 -> z - 3 -> w - else -> Double.NaN - } - inline fun setToFunc(callback: (Int) -> Double) = setTo(callback(0), callback(1), callback(2), callback(3)) - fun setTo(x: Double, y: Double, z: Double, w: Double): Quaternion { - this.x = x - this.y = y - this.z = z - this.w = w - return this - } - - companion object { - fun dotProduct(l: Quaternion, r: Quaternion): Double = l.x * r.x + l.y * r.y + l.z * r.z + l.w * r.w - } - - fun normalize(v: Quaternion = this): Quaternion { - val length = 1.0 / Vector3D.length(v.x, v.y, v.z, v.w) - return this.setTo(v.x / length, v.y / length, v.z / length, v.w / length) - } -} - -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun Quaternion(x: Number, y: Number, z: Number, w: Number) = Quaternion(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble()) -fun Quaternion(x: Float, y: Float, z: Float, w: Float) = Quaternion(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble()) -fun Quaternion(x: Int, y: Int, z: Int, w: Int) = Quaternion(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble()) - -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun EulerRotation.setQuaternion(x: Number, y: Number, z: Number, w: Number): EulerRotation = quaternionToEuler(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat(), this) -fun EulerRotation.setQuaternion(x: Double, y: Double, z: Double, w: Double): EulerRotation = quaternionToEuler(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat(), this) -fun EulerRotation.setQuaternion(x: Int, y: Int, z: Int, w: Int): EulerRotation = quaternionToEuler(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat(), this) -fun EulerRotation.setQuaternion(x: Float, y: Float, z: Float, w: Float): EulerRotation = quaternionToEuler(x, y, z, w, this) - -fun EulerRotation.setQuaternion(quaternion: Quaternion): EulerRotation = quaternionToEuler(quaternion.x, quaternion.y, quaternion.z, quaternion.w, this) -fun EulerRotation.setTo(x: Angle, y: Angle, z: Angle): EulerRotation = this - .apply { this.x = x } - .apply { this.y = y } - .apply { this.z = z } - -fun EulerRotation.setTo(other: EulerRotation): EulerRotation = setTo(other.x, other.y, other.z) - -fun Quaternion.setEuler(x: Angle, y: Angle, z: Angle): Quaternion = eulerToQuaternion(x, y, z, this) -fun Quaternion.setEuler(euler: EulerRotation): Quaternion = eulerToQuaternion(euler, this) -fun Quaternion.setTo(euler: EulerRotation): Quaternion = eulerToQuaternion(euler, this) - -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun Quaternion.setTo(x: Number, y: Number, z: Number, w: Number): Quaternion = setTo(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble()) -fun Quaternion.setTo(x: Int, y: Int, z: Int, w: Int): Quaternion = setTo(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble()) -fun Quaternion.setTo(x: Float, y: Float, z: Float, w: Float): Quaternion = setTo(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble()) - -inline fun Quaternion.copyFrom(other: Quaternion): Quaternion = this.setTo(other) - -inline fun Quaternion.setTo(other: Quaternion): Quaternion = setTo(other.x, other.y, other.z, other.w) - -private val tempQuat = Quaternion() -fun EulerRotation.toMatrix(out: Matrix3D = Matrix3D()): Matrix3D = tempQuat.setEuler(this).toMatrix(out) -fun Quaternion.toMatrix(out: Matrix3D = Matrix3D()): Matrix3D = quaternionToMatrix(this, out) - -fun eulerToQuaternion(euler: EulerRotation, quaternion: Quaternion = Quaternion()): Quaternion = eulerToQuaternion(euler.x, euler.y, euler.z, quaternion) - -fun quaternionToEuler(q: Quaternion, euler: EulerRotation = EulerRotation()): EulerRotation = quaternionToEuler(q.x, q.y, q.z, q.w, euler) - -fun quaternionToEuler(x: Double, y: Double, z: Double, w: Double, euler: EulerRotation = EulerRotation()): EulerRotation = - quaternionToEuler(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat(), euler) -fun quaternionToEuler(x: Int, y: Int, z: Int, w: Int, euler: EulerRotation = EulerRotation()): EulerRotation = - quaternionToEuler(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat(), euler) - -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun quaternionToEuler(x: Number, y: Number, z: Number, w: Number, euler: EulerRotation = EulerRotation()): EulerRotation = - quaternionToEuler(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat(), euler) - -// https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles - -fun eulerToQuaternion(roll: Angle, pitch: Angle, yaw: Angle, quaternion: Quaternion = Quaternion()): Quaternion { - val cr = cos(roll * 0.5) - val sr = sin(roll * 0.5) - val cp = cos(pitch * 0.5) - val sp = sin(pitch * 0.5) - val cy = cos(yaw * 0.5) - val sy = sin(yaw * 0.5) - return quaternion.setTo( - (cy * cp * sr - sy * sp * cr), - (sy * cp * sr + cy * sp * cr), - (sy * cp * cr - cy * sp * sr), - (cy * cp * cr + sy * sp * sr) - ) -} - -fun quaternionToEuler(x: Float, y: Float, z: Float, w: Float, euler: EulerRotation = EulerRotation()): EulerRotation { - val sinrCosp = +2.0 * (w * x + y * z) - val cosrCosp = +1.0 - 2.0 * (x * x + y * y) - val roll = atan2(sinrCosp, cosrCosp) - val sinp = +2.0 * (w * y - z * x) - val pitch = when { - abs(sinp) >= 1 -> if (sinp > 0) PI / 2 else -PI / 2 - else -> asin(sinp) - } - val sinyCosp = +2.0 * (w * z + x * y) - val cosyCosp = +1.0 - 2.0 * (y * y + z * z) - val yaw = atan2(sinyCosp, cosyCosp) - return euler.setTo(roll.radians, pitch.radians, yaw.radians) -} - -private val tempMat1 = Matrix3D() -private val tempMat2 = Matrix3D() -fun quaternionToMatrix(quat: Quaternion, out: Matrix3D = Matrix3D(), temp1: Matrix3D = tempMat1, temp2: Matrix3D = tempMat2): Matrix3D { - temp1.setRows( - quat.w, quat.z, -quat.y, quat.x, - -quat.z, quat.w, quat.x, quat.y, - quat.y, -quat.x, quat.w, quat.z, - -quat.x, -quat.y, -quat.z, quat.w - ) - temp2.setRows( - quat.w, quat.z, -quat.y, -quat.x, - -quat.z, quat.w, quat.x, -quat.y, - quat.y, -quat.x, quat.w, -quat.z, - quat.x, quat.y, quat.z, quat.w - ) - return out.multiply(temp1, temp2) -} - -fun Quaternion.setFromRotationMatrix(m: Matrix3D) = this.apply { - val q = this - m.apply { - val t = v00 + v11 + v22 - when { - t > 0 -> { - val s = 0.5 / sqrt(t + 1.0) - q.setTo(((v21 - v12) * s), ((v02 - v20) * s), ((v10 - v01) * s), (0.25 / s)) - } - v00 > v11 && v00 > v22 -> { - val s = 2.0 * sqrt(1.0 + v00 - v11 - v22) - q.setTo((0.25 * s), ((v01 + v10) / s), ((v02 + v20) / s), ((v21 - v12) / s)) - } - v11 > v22 -> { - val s = 2.0 * sqrt(1.0 + v11 - v00 - v22) - q.setTo(((v01 + v10) / s), (0.25 * s), ((v12 + v21) / s), ((v02 - v20) / s)) - } - else -> { - val s = 2.0 * sqrt(1.0 + v22 - v00 - v11) - q.setTo(((v02 + v20) / s), ((v12 + v21) / s), (0.25f * s), ((v10 - v01) / s)) - } - } - } -} - -operator fun Quaternion.unaryMinus(): Quaternion = Quaternion(-x, -y, -z, -w) -operator fun Quaternion.plus(other: Quaternion): Quaternion = Quaternion(x + other.x, y + other.y, z + other.z, w + other.w) -operator fun Quaternion.minus(other: Quaternion): Quaternion = Quaternion(x - other.x, y - other.y, z - other.z, w - other.w) -operator fun Quaternion.times(scale: Double): Quaternion = Quaternion(x * scale, y * scale, z * scale, w * scale) -operator fun Double.times(scale: Quaternion): Quaternion = scale.times(this) - -fun Quaternion.negate() = this.setTo(-x, -y, -z, -w) - -fun Quaternion.setToFunc(l: Quaternion, r: Quaternion, func: (l: Double, r: Double) -> Double) = setTo( - func(l.x, r.x), - func(l.y, r.y), - func(l.z, r.z), - func(l.w, r.w) -) - -fun Vector3D.setToFunc(l: Vector3D, r: Vector3D, func: (l: Float, r: Float) -> Float) = setTo( - func(l.x, r.x), - func(l.y, r.y), - func(l.z, r.z), - func(l.w, r.w) -) - -// @TODO: Allocations and temps! -private val tleft: Quaternion = Quaternion() -private val tright: Quaternion = Quaternion() -fun Quaternion.setToSlerp(left: Quaternion, right: Quaternion, t: Double): Quaternion { - val tleft = tleft.copyFrom(left).normalize() - val tright = tright.copyFrom(right).normalize() - - var dot = Quaternion.dotProduct(tleft, right) - - if (dot < 0.0f) { - tright.negate() - dot = -dot - } - - if (dot > 0.99995f) return setToFunc(tleft, tright) { l, r -> l + t * (r - l) } - - val angle0 = acos(dot) - val angle1 = angle0 * t - - val s1 = sin(angle1) / sin(angle0) - val s0 = cos(angle1) - dot * s1 - - return setToFunc(tleft, tright) { l, r -> (s0 * l) + (s1 * r) } -} - -fun Quaternion.setToNlerp(left: Quaternion, right: Quaternion, t: Double): Quaternion { - val sign = if (Quaternion.dotProduct(left, right) < 0) -1 else +1 - return setToFunc { (1f - t) * left[it] + t * right[it] * sign }.normalize() -} - -fun Quaternion.setToInterpolated(left: Quaternion, right: Quaternion, t: Double): Quaternion = setToSlerp(left, right, t) diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Rectangle.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Rectangle.kt index 4aef116..0ed9207 100644 --- a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Rectangle.kt +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Rectangle.kt @@ -11,8 +11,8 @@ interface IRectangle { companion object { inline operator fun invoke(x: Double, y: Double, width: Double, height: Double): IRectangle = Rectangle(x, y, width, height) - @Deprecated("Kotlin/Native boxes inline + Number") - inline operator fun invoke(x: Number, y: Number, width: Number, height: Number): IRectangle = Rectangle(x, y, width, height) + inline operator fun invoke(x: Float, y: Float, width: Float, height: Float): IRectangle = Rectangle(x, y, width, height) + inline operator fun invoke(x: Int, y: Int, width: Int, height: Int): IRectangle = Rectangle(x, y, width, height) } } @@ -30,6 +30,11 @@ data class Rectangle( var x: Double, var y: Double, var width: Double, var height: Double ) : MutableInterpolable, Interpolable, IRectangle, Sizeable { + val topLeft get() = Point(left, top) + val topRight get() = Point(right, top) + val bottomLeft get() = Point(left, bottom) + val bottomRight get() = Point(right, bottom) + override val _x: Double get() = x override val _y: Double get() = y override val _width: Double get() = width @@ -37,15 +42,14 @@ data class Rectangle( companion object { operator fun invoke(): Rectangle = Rectangle(0.0, 0.0, 0.0, 0.0) + operator fun invoke(x: Int, y: Int, width: Int, height: Int): Rectangle = Rectangle(x.toDouble(), y.toDouble(), width.toDouble(), height.toDouble()) + operator fun invoke(x: Float, y: Float, width: Float, height: Float): Rectangle = Rectangle(x.toDouble(), y.toDouble(), width.toDouble(), height.toDouble()) + operator fun invoke(topLeft: IPoint, size: ISize): Rectangle = Rectangle(topLeft.x, topLeft.y, size.width, size.height) - inline operator fun invoke(x: Int, y: Int, width: Int, height: Int): Rectangle = Rectangle(x.toDouble(), y.toDouble(), width.toDouble(), height.toDouble()) - inline fun fromBounds(left: Double, top: Double, right: Double, bottom: Double): Rectangle = Rectangle().setBounds(left, top, right, bottom) - inline fun fromBounds(left: Int, top: Int, right: Int, bottom: Int): Rectangle = Rectangle().setBounds(left, top, right, bottom) - - @Deprecated("Kotlin/Native boxes inline + Number") - inline operator fun invoke(x: Number, y: Number, width: Number, height: Number): Rectangle = Rectangle(x.toDouble(), y.toDouble(), width.toDouble(), height.toDouble()) - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun fromBounds(left: Number, top: Number, right: Number, bottom: Number): Rectangle = Rectangle().setBounds(left, top, right, bottom) + fun fromBounds(left: Double, top: Double, right: Double, bottom: Double): Rectangle = Rectangle().setBounds(left, top, right, bottom) + fun fromBounds(left: Int, top: Int, right: Int, bottom: Int): Rectangle = Rectangle().setBounds(left, top, right, bottom) + fun fromBounds(left: Float, top: Float, right: Float, bottom: Float): Rectangle = Rectangle().setBounds(left, top, right, bottom) + fun fromBounds(topLeft: Point, bottomRight: Point): Rectangle = Rectangle().setBounds(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y) fun isContainedIn(a: Rectangle, b: Rectangle): Boolean = a.x >= b.x && a.y >= b.y && a.x + a.width <= b.x + b.width && a.y + a.height <= b.y + b.height } @@ -78,16 +82,16 @@ data class Rectangle( fun setBounds(left: Float, top: Float, right: Float, bottom: Float) = setBounds(left.toDouble(), top.toDouble(), right.toDouble(), bottom.toDouble()) operator fun times(scale: Double) = Rectangle(x * scale, y * scale, width * scale, height * scale) - operator fun div(scale: Double) = Rectangle(x / scale, y / scale, width / scale, height / scale) - operator fun times(scale: Float) = this * scale.toDouble() - operator fun div(scale: Float) = this / scale.toDouble() - operator fun times(scale: Int) = this * scale.toDouble() + + operator fun div(scale: Double) = Rectangle(x / scale, y / scale, width / scale, height / scale) + operator fun div(scale: Float) = this / scale.toDouble() operator fun div(scale: Int) = this / scale.toDouble() operator fun contains(that: Rectangle) = isContainedIn(that, this) operator fun contains(that: Point) = contains(that.x, that.y) + operator fun contains(that: IPoint) = contains(that.x, that.y) fun contains(x: Double, y: Double) = (x >= left && x < right) && (y >= top && y < bottom) fun contains(x: Float, y: Float) = contains(x.toDouble(), y.toDouble()) fun contains(x: Int, y: Int) = contains(x.toDouble(), y.toDouble()) @@ -107,12 +111,11 @@ data class Rectangle( ) else null fun displaced(dx: Double, dy: Double) = Rectangle(this.x + dx, this.y + dy, width, height) - fun displace(dx: Double, dy: Double) = setTo(this.x + dx, this.y + dy, this.width, this.height) - fun displaced(dx: Float, dy: Float) = displaced(dx.toDouble(), dy.toDouble()) - fun displace(dx: Float, dy: Float) = displace(dx.toDouble(), dy.toDouble()) - fun displaced(dx: Int, dy: Int) = displaced(dx.toDouble(), dy.toDouble()) + + fun displace(dx: Double, dy: Double) = setTo(this.x + dx, this.y + dy, this.width, this.height) + fun displace(dx: Float, dy: Float) = displace(dx.toDouble(), dy.toDouble()) fun displace(dx: Int, dy: Int) = displace(dx.toDouble(), dy.toDouble()) fun place(item: Size, anchor: Anchor, scale: ScaleMode, out: Rectangle = Rectangle()): Rectangle = @@ -145,11 +148,8 @@ data class Rectangle( ) //override fun toString(): String = "Rectangle([${left.niceStr}, ${top.niceStr}]-[${right.niceStr}, ${bottom.niceStr}])" - override fun toString(): String = - "Rectangle(x=${x.niceStr}, y=${y.niceStr}, width=${width.niceStr}, height=${height.niceStr})" - - fun toStringBounds(): String = - "Rectangle([${left.niceStr},${top.niceStr}]-[${right.niceStr},${bottom.niceStr}])" + override fun toString(): String = "Rectangle(x=${x.niceStr}, y=${y.niceStr}, width=${width.niceStr}, height=${height.niceStr})" + fun toStringBounds(): String = "Rectangle([${left.niceStr},${top.niceStr}]-[${right.niceStr},${bottom.niceStr}])" override fun interpolateWith(ratio: Double, other: Rectangle): Rectangle = Rectangle().setToInterpolated(ratio, this, other) @@ -167,29 +167,11 @@ data class Rectangle( fun toInt() = RectangleInt(x, y, width, height) } -@Deprecated("Use Point instead") -operator fun Rectangle.contains(that: IPoint) = contains(that.x, that.y) - inline fun Rectangle.setTo(x: Number, y: Number, width: Number, height: Number) = this.setTo(x.toDouble(), y.toDouble(), width.toDouble(), height.toDouble()) inline fun Rectangle.setBounds(left: Number, top: Number, right: Number, bottom: Number) = setBounds(left.toDouble(), top.toDouble(), right.toDouble(), bottom.toDouble()) -@Deprecated("Kotlin/Native boxes Number in inline") -inline operator fun Rectangle.times(scale: Number) = this * scale.toDouble() -@Deprecated("Kotlin/Native boxes Number in inline") -inline operator fun Rectangle.div(scale: Number) = this / scale.toDouble() - -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun Rectangle.contains(x: Number, y: Number) = contains(x.toDouble(), y.toDouble()) - -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun Rectangle.displaced(dx: Number, dy: Number) = displaced(dx.toDouble(), dy.toDouble()) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun Rectangle.displace(dx: Number, dy: Number) = displace(dx.toDouble(), dy.toDouble()) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun Rectangle.inflate(dx: Number, dy: Number) = inflate(dx.toDouble(), dy.toDouble()) - //////////// INT interface IRectangleInt { @@ -200,8 +182,8 @@ interface IRectangleInt { companion object { operator fun invoke(x: Int, y: Int, width: Int, height: Int): IRectangleInt = RectangleInt(x, y, width, height) - @Deprecated("Kotlin/Native boxes Number in inline") - inline operator fun invoke(x: Number, y: Number, width: Number, height: Number): IRectangleInt = RectangleInt(x.toInt(), y.toInt(), width.toInt(), height.toInt()) + operator fun invoke(x: Float, y: Float, width: Float, height: Float): IRectangleInt = RectangleInt(x.toInt(), y.toInt(), width.toInt(), height.toInt()) + operator fun invoke(x: Double, y: Double, width: Double, height: Double): IRectangleInt = RectangleInt(x.toInt(), y.toInt(), width.toInt(), height.toInt()) } } @@ -246,8 +228,8 @@ inline class RectangleInt(val rect: Rectangle) : IRectangleInt { companion object { operator fun invoke() = RectangleInt(Rectangle()) operator fun invoke(x: Int, y: Int, width: Int, height: Int) = RectangleInt(Rectangle(x, y, width, height)) - @Deprecated("Kotlin/Native boxes Number in inline") - inline operator fun invoke(x: Number, y: Number, width: Number, height: Number) = RectangleInt(Rectangle(x, y, width, height)) + operator fun invoke(x: Float, y: Float, width: Float, height: Float) = RectangleInt(Rectangle(x, y, width, height)) + operator fun invoke(x: Double, y: Double, width: Double, height: Double) = RectangleInt(Rectangle(x, y, width, height)) fun fromBounds(left: Int, top: Int, right: Int, bottom: Int): RectangleInt = RectangleInt(left, top, right - left, bottom - top) @@ -272,6 +254,12 @@ fun RectangleInt.setSize(width: Int, height: Int) = this.apply { this.height = height } +fun RectangleInt.getPosition(out: PointInt = PointInt()): PointInt = out.setTo(x, y) +fun RectangleInt.getSize(out: SizeInt = SizeInt()): SizeInt = out.setTo(width, height) + +val RectangleInt.position get() = getPosition() +val RectangleInt.size get() = getSize() + fun RectangleInt.setBoundsTo(left: Int, top: Int, right: Int, bottom: Int) = setTo(left, top, right - left, bottom - top) //////////////////// diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/ScaleMode.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/ScaleMode.kt index ffd8646..b8f7cbd 100644 --- a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/ScaleMode.kt +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/ScaleMode.kt @@ -24,14 +24,6 @@ class ScaleMode( ) companion object { - @Deprecated("") - operator fun invoke(function: (item: Size, container: Size, target: Size) -> Unit): ScaleMode { - val t1 = Size() - val t2 = Size() - val tt = Size() - return ScaleMode { c, iw, ih, cw, ch -> function(t1.setTo(iw, ih), t2.setTo(cw, ch), tt).let { if (c == 0) tt.width else tt.height } } - } - val COVER = ScaleMode { c, iw, ih, cw, ch -> val s0 = cw / iw val s1 = ch / ih @@ -46,6 +38,8 @@ class ScaleMode( if (c == 0) iw * s else ih * s } + val FIT get() = SHOW_ALL + val EXACT = ScaleMode { c, iw, ih, cw, ch -> if (c == 0) cw else ch } @@ -60,7 +54,7 @@ fun Rectangle.applyScaleMode(container: Rectangle, mode: ScaleMode, anchor: Anch fun Size.applyScaleMode(container: Rectangle, mode: ScaleMode, anchor: Anchor, out: Rectangle = Rectangle(), tempSize: Size = Size()): Rectangle { val outSize = this.applyScaleMode(container.size, mode, tempSize) - out.setToAnchoredRectangle(Rectangle(0, 0, outSize.width, outSize.height), anchor, container) + out.setToAnchoredRectangle(Rectangle(0.0, 0.0, outSize.width, outSize.height), anchor, container) return out } diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Size.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Size.kt index 9dea1f9..9c1f56f 100644 --- a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Size.kt +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Size.kt @@ -7,11 +7,15 @@ interface ISize { val width: Double val height: Double + val area: Double get() = width * height + val perimeter: Double get() = width * 2 + height * 2 + val min: Double get() = kotlin.math.min(width, height) + val max: Double get() = kotlin.math.max(width, height) + companion object { operator fun invoke(width: Double, height: Double): ISize = Size(Point(width, height)) operator fun invoke(width: Int, height: Int): ISize = Size(Point(width, height)) - @Deprecated("Kotlin/Native boxes Number in inline") - inline operator fun invoke(width: Number, height: Number): ISize = Size(Point(width, height)) + operator fun invoke(width: Float, height: Float): ISize = Size(Point(width, height)) } } @@ -20,10 +24,11 @@ inline class Size(val p: Point) : MutableInterpolable, Interpolable, operator fun invoke(): Size = Size(Point(0, 0)) operator fun invoke(width: Double, height: Double): Size = Size(Point(width, height)) operator fun invoke(width: Int, height: Int): Size = Size(Point(width, height)) - @Deprecated("Kotlin/Native boxes Number in inline") - inline operator fun invoke(width: Number, height: Number): Size = Size(Point(width, height)) + operator fun invoke(width: Float, height: Float): Size = Size(Point(width, height)) } + fun copy() = Size(p.copy()) + override val size: Size get() = this override var width: Double @@ -39,6 +44,12 @@ inline class Size(val p: Point) : MutableInterpolable, Interpolable, return this } fun setTo(width: Int, height: Int) = setTo(width.toDouble(), height.toDouble()) + fun setTo(width: Float, height: Float) = setTo(width.toDouble(), height.toDouble()) + fun setTo(that: ISize) = setTo(that.width, that.height) + + fun setToScaled(sx: Double, sy: Double) = setTo((this.width * sx), (this.height * sy)) + fun setToScaled(sx: Float, sy: Float) = setToScaled(sx.toDouble(), sy.toDouble()) + fun setToScaled(sx: Int, sy: Int) = setToScaled(sx.toDouble(), sy.toDouble()) fun clone() = Size(width, height) @@ -52,21 +63,6 @@ inline class Size(val p: Point) : MutableInterpolable, Interpolable, override fun toString(): String = "Size(width=${width.niceStr}, height=${height.niceStr})" } -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun Size.setTo(width: Number, height: Number) = setTo(width.toDouble(), height.toDouble()) - -fun Size.setTo(that: ISize) = setTo(that.width, that.height) -fun Size.setToScaled(sx: Double, sy: Double) = setTo((this.width * sx), (this.height * sy)) - -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun Size.setToScaled(sx: Number, sy: Number = sx) = setToScaled(sx.toDouble(), sy.toDouble()) - - -val ISize.area: Double get() = width * height -val ISize.perimeter: Double get() = width * 2 + height * 2 -val ISize.min: Double get() = kotlin.math.min(width, height) -val ISize.max: Double get() = kotlin.math.max(width, height) - interface ISizeInt { val width: Int val height: Int @@ -78,6 +74,8 @@ inline class SizeInt(val size: Size) : ISizeInt { operator fun invoke(x: Int, y: Int): SizeInt = SizeInt(Size(x, y)) } + fun clone() = SizeInt(size.clone()) + override var width: Int set(value) = run { size.width = value.toDouble() } get() = size.width.toInt() @@ -97,9 +95,8 @@ fun SizeInt.setTo(width: Int, height: Int) = this.apply { fun SizeInt.setTo(that: SizeInt) = setTo(that.width, that.height) fun SizeInt.setToScaled(sx: Double, sy: Double) = setTo((this.width * sx).toInt(), (this.height * sy).toInt()) - -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun SizeInt.setToScaled(sx: Number, sy: Number = sx) = setToScaled(sx.toDouble(), sy.toDouble()) +fun SizeInt.setToScaled(sx: Int, sy: Int) = setToScaled(sx.toDouble(), sy.toDouble()) +fun SizeInt.setToScaled(sx: Float, sy: Float) = setToScaled(sx.toDouble(), sy.toDouble()) fun SizeInt.anchoredIn(container: RectangleInt, anchor: Anchor, out: RectangleInt = RectangleInt()): RectangleInt { return out.setTo( @@ -113,9 +110,7 @@ fun SizeInt.anchoredIn(container: RectangleInt, anchor: Anchor, out: RectangleIn operator fun SizeInt.contains(v: SizeInt): Boolean = (v.width <= width) && (v.height <= height) operator fun SizeInt.times(v: Double) = SizeInt(Size((width * v).toInt(), (height * v).toInt())) operator fun SizeInt.times(v: Int) = this * v.toDouble() - -@Deprecated("Kotlin/Native boxes Number in inline") -inline operator fun SizeInt.times(v: Number) = this * v.toDouble() +operator fun SizeInt.times(v: Float) = this * v.toDouble() fun SizeInt.getAnchorPosition(anchor: Anchor, out: PointInt = PointInt(0, 0)): PointInt = out.setTo((width * anchor.sx).toInt(), (height * anchor.sy).toInt()) diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Vector3D.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Vector3D.kt index 097f26a..3efc4d0 100644 --- a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Vector3D.kt +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Vector3D.kt @@ -27,9 +27,6 @@ class Vector3D { operator fun invoke(x: Double, y: Double, z: Double, w: Double = 1.0): Vector3D = Vector3D().setTo(x, y, z, w) operator fun invoke(x: Int, y: Int, z: Int, w: Int = 1): Vector3D = Vector3D().setTo(x, y, z, w) - @Deprecated("Kotlin/Native boxes Number in inline") - inline operator fun invoke(x: Number, y: Number, z: Number, w: Number = 1f): Vector3D = Vector3D().setTo(x, y, z, w) - fun length(x: Double, y: Double, z: Double, w: Double): Double = sqrt(lengthSq(x, y, z, w)) fun length(x: Double, y: Double, z: Double): Double = sqrt(lengthSq(x, y, z)) fun length(x: Float, y: Float, z: Float, w: Float): Float = sqrt(lengthSq(x, y, z, w)) @@ -39,16 +36,6 @@ class Vector3D { fun lengthSq(x: Double, y: Double, z: Double): Double = x * x + y * y + z * z fun lengthSq(x: Float, y: Float, z: Float, w: Float): Float = x * x + y * y + z * z + w * w fun lengthSq(x: Float, y: Float, z: Float): Float = x * x + y * y + z * z - - @Deprecated("Kotlin/Native boxes Number in inline") - inline fun length(x: Number, y: Number, z: Number, w: Number) = length(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble()) - @Deprecated("Kotlin/Native boxes Number in inline") - inline fun lengthSq(x: Number, y: Number, z: Number, w: Number) = lengthSq(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble()) - @Deprecated("Kotlin/Native boxes Number in inline") - inline fun length(x: Number, y: Number, z: Number) = length(x.toDouble(), y.toDouble(), z.toDouble()) - @Deprecated("Kotlin/Native boxes Number in inline") - inline fun lengthSq(x: Number, y: Number, z: Number) = lengthSq(x.toDouble(), y.toDouble(), z.toDouble()) - } fun copyFrom(other: Vector3D) = setTo(other.x, other.y, other.z, other.w) @@ -62,19 +49,37 @@ class Vector3D { fun setTo(x: Int, y: Int, z: Int): Vector3D = setTo(x, y, z, 1) inline fun setToFunc(func: (index: Int) -> Float): Vector3D = setTo(func(0), func(1), func(2), func(3)) + inline fun setToFunc(l: Vector3D, r: Vector3D, func: (l: Float, r: Float) -> Float) = setTo( + func(l.x, r.x), + func(l.y, r.y), + func(l.z, r.z), + func(l.w, r.w) + ) + fun setToInterpolated(left: Vector3D, right: Vector3D, t: Double): Vector3D = setToFunc { t.interpolate(left[it], right[it]) } + + fun scale(scale: Float) = this.setTo(this.x * scale, this.y * scale, this.z * scale, this.w * scale) + fun scale(scale: Int) = scale(scale.toFloat()) + fun scale(scale: Double) = scale(scale.toFloat()) fun transform(mat: Matrix3D) = mat.transform(this, this) fun normalize(vector: Vector3D = this): Vector3D = this.apply { val norm = 1.0 / vector.length3 - setTo(vector.x * norm, vector.y * norm, vector.z * norm, 1) + setTo(vector.x * norm, vector.y * norm, vector.z * norm, 1.0) } fun normalized(out: Vector3D = Vector3D()): Vector3D = out.copyFrom(this).normalize() - @Deprecated("Kotlin/Native boxes Number in inline") - inline fun setTo(x: Number, y: Number, z: Number, w: Number): Vector3D = setTo(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat()) + fun dot(v2: Vector3D): Float = this.x*v2.x + this.y*v2.y + this.z*v2.y + fun sub(l: Vector3D, r: Vector3D): Vector3D = setTo(l.x - r.x, l.y - r.y, l.z - r.z, l.w - r.w) + fun add(l: Vector3D, r: Vector3D): Vector3D = setTo(l.x + r.x, l.y + r.y, l.z + r.z, l.w + r.w) + fun cross(a: Vector3D, b: Vector3D): Vector3D = setTo( + (a.y * b.z - a.z * b.y), + (a.z * b.x - a.x * b.z), + (a.x * b.y - a.y * b.x), + 1f + ) override fun equals(other: Any?): Boolean = (other is Vector3D) && almostEquals(this.x, other.x) && almostEquals(this.y, other.y) && almostEquals(this.z, other.z) && almostEquals(this.w, other.w) override fun hashCode(): Int = data.contentHashCode() @@ -89,16 +94,6 @@ inline class IntVector3(val v: Vector3D) { } fun Vector3D.asIntVector3D() = IntVector3(this) -fun Vector3D.setToInterpolated(left: Vector3D, right: Vector3D, t: Double): Vector3D = setToFunc { t.interpolate(left[it], right[it]) } - -fun Vector3D.scale(scale: Float) = this.setTo(this.x * scale, this.y * scale, this.z * scale, this.w * scale) -fun Vector3D.scale(scale: Int) = scale(scale.toFloat()) -fun Vector3D.scale(scale: Double) = scale(scale.toFloat()) - -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun Vector3D.scale(scale: Number) = scale(scale.toFloat()) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun Vector3D.setTo(x: Number, y: Number, z: Number) = setTo(x.toFloat(), y.toFloat(), z.toFloat(), 1f) typealias Position3D = Vector3D typealias Scale3D = Vector3D diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/binpack/BinPacker.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/binpack/BinPacker.kt index 6e5eccc..82ec854 100644 --- a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/binpack/BinPacker.kt +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/binpack/BinPacker.kt @@ -27,6 +27,8 @@ class BinPacker(val width: Double, val height: Double, val algo: Algo = MaxRects fun add(width: Double, height: Double): Rectangle = addOrNull(width, height) ?: throw IllegalStateException("Size '${this.width}x${this.height}' doesn't fit in '${this.width}x${this.height}'") + fun add(width: Int, height: Int): Rectangle = add(width.toDouble(), height.toDouble()) + fun add(width: Float, height: Float): Rectangle = add(width.toDouble(), height.toDouble()) fun addOrNull(width: Double, height: Double): Rectangle? { val rect = algo.add(width, height) ?: return null @@ -34,13 +36,9 @@ class BinPacker(val width: Double, val height: Double, val algo: Algo = MaxRects return rect } - fun add(width: Int, height: Int): Rectangle = add(width.toDouble(), height.toDouble()) - fun addOrNull(width: Int, height: Int): Rectangle? = addOrNull(width.toDouble(), height.toDouble()) - @Deprecated("Kotlin/Native boxes Number in inline") - inline fun add(width: Number, height: Number): Rectangle = add(width.toDouble(), height.toDouble()) - @Deprecated("Kotlin/Native boxes Number in inline") - inline fun addOrNull(width: Number, height: Number): Rectangle? = addOrNull(width.toDouble(), height.toDouble()) + fun addOrNull(width: Int, height: Int): Rectangle? = addOrNull(width.toDouble(), height.toDouble()) + fun addOrNull(width: Float, height: Float): Rectangle? = addOrNull(width.toDouble(), height.toDouble()) fun addBatch(items: Iterable, getSize: (T) -> Size): Result { return Result(width, height, algo.addBatch(items, getSize)) @@ -49,20 +47,13 @@ class BinPacker(val width: Double, val height: Double, val algo: Algo = MaxRects fun addBatch(items: Iterable): List = algo.addBatch(items) { it }.map { it.second } companion object { + operator fun invoke(width: Double, height: Double, algo: Algo = MaxRects(width, height)) = BinPacker(width, height, algo) operator fun invoke(width: Int, height: Int, algo: Algo = MaxRects(width.toDouble(), height.toDouble())) = BinPacker(width.toDouble(), height.toDouble(), algo) - - @Deprecated("Kotlin/Native boxes Number in inline") - inline operator fun invoke(width: Number, height: Number, algo: Algo = MaxRects(width.toDouble(), height.toDouble())) = BinPacker(width.toDouble(), height.toDouble(), algo) + operator fun invoke(width: Float, height: Float, algo: Algo = MaxRects(width.toDouble(), height.toDouble())) = BinPacker(width.toDouble(), height.toDouble(), algo) fun pack(width: Double, height: Double, items: Iterable, getSize: (T) -> Size): Result = BinPacker(width, height).addBatch(items, getSize) fun pack(width: Int, height: Int, items: Iterable, getSize: (T) -> Size): Result = pack(width.toDouble(), height.toDouble(), items, getSize) - - @Deprecated("Kotlin/Native boxes Number in inline") - inline fun pack(width: Number, height: Number, items: Iterable, noinline getSize: (T) -> Size): Result = pack(width.toDouble(), height.toDouble(), items, getSize) - - @Deprecated("Kotlin/Native boxes Number in inline") - inline fun packSeveral(maxWidth: Number, maxHeight: Number, items: Iterable): List> = packSeveral(maxWidth.toDouble(), maxHeight.toDouble(), items) { it.size } - fun packSeveral(maxWidth: Int, maxHeight: Int, items: Iterable): List> = packSeveral(maxWidth.toDouble(), maxHeight.toDouble(), items) { it.size } + fun pack(width: Float, height: Float, items: Iterable, getSize: (T) -> Size): Result = pack(width.toDouble(), height.toDouble(), items, getSize) fun packSeveral( maxWidth: Double, @@ -117,5 +108,8 @@ class BinPacker(val width: Double, val height: Double, val algo: Algo = MaxRects return out } + fun packSeveral(maxWidth: Int, maxHeight: Int, items: Iterable): List> = packSeveral(maxWidth.toDouble(), maxHeight.toDouble(), items) { it.size } + fun packSeveral(maxWidth: Float, maxHeight: Float, items: Iterable): List> = packSeveral(maxWidth.toDouble(), maxHeight.toDouble(), items) { it.size } + } } diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/shape/Shape2d.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/shape/Shape2d.kt index 6792b68..81d8c7f 100644 --- a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/shape/Shape2d.kt +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/shape/Shape2d.kt @@ -26,8 +26,6 @@ abstract class Shape2d { companion object { operator fun invoke(x0: Float, y0: Float, x1: Float, y1: Float) = Line(x0.toDouble(), y0.toDouble(), x1.toDouble(), y1.toDouble()) operator fun invoke(x0: Int, y0: Int, x1: Int, y1: Int) = Line(x0.toDouble(), y0.toDouble(), x1.toDouble(), y1.toDouble()) - @Deprecated("Kotlin/Native boxes inline + Number") - inline operator fun invoke(x0: Number, y0: Number, x1: Number, y1: Number) = Line(x0.toDouble(), y0.toDouble(), x1.toDouble(), y1.toDouble()) } override val paths get() = listOf(PointArrayList(2).apply { add(x0, y0).add(x1, y1) }) @@ -40,8 +38,6 @@ abstract class Shape2d { companion object { operator fun invoke(x: Float, y: Float, radius: Float, totalPoints: Int = 32) = Circle(x.toDouble(), y.toDouble(), radius.toDouble(), totalPoints) operator fun invoke(x: Int, y: Int, radius: Int, totalPoints: Int = 32) = Circle(x.toDouble(), y.toDouble(), radius.toDouble(), totalPoints) - @Deprecated("Kotlin/Native boxes inline + Number") - inline operator fun invoke(x: Number, y: Number, radius: Number, totalPoints: Int = 32) = Circle(x.toDouble(), y.toDouble(), radius.toDouble(), totalPoints) } override val paths by lazy { @@ -63,8 +59,7 @@ abstract class Shape2d { companion object { inline operator fun invoke(x: Double, y: Double, width: Double, height: Double) = Rectangle(com.soywiz.korma.geom.Rectangle(x, y, width, height)) inline operator fun invoke(x: Float, y: Float, width: Float, height: Float) = Rectangle(com.soywiz.korma.geom.Rectangle(x, y, width, height)) - @Deprecated("Kotlin/Native boxes inline + Number") - inline operator fun invoke(x: Number, y: Number, width: Number, height: Number) = Rectangle(com.soywiz.korma.geom.Rectangle(x, y, width, height)) + inline operator fun invoke(x: Int, y: Int, width: Int, height: Int) = Rectangle(com.soywiz.korma.geom.Rectangle(x, y, width, height)) } override val paths = listOf(PointArrayList(4) { add(x, y).add(x + width, y).add(x + width, y + height).add(x, y + height) }) diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/vector/Edge.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/vector/Edge.kt index 7454045..91f8ce8 100644 --- a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/vector/Edge.kt +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/vector/Edge.kt @@ -50,18 +50,7 @@ class Edge { val Cy: Double = b.ay.toDouble() val Dx: Double = b.bx.toDouble() val Dy: Double = b.by.toDouble() - val a1 = By - Ay - val b1 = Ax - Bx - val c1 = a1 * (Ax) + b1 * (Ay) - val a2 = Dy - Cy - val b2 = Cx - Dx - val c2 = a2 * (Cx) + b2 * (Cy) - val determinant = a1 * b2 - a2 * b1 - if (determinant == 0.0) return false - val x = (b2 * c1 - b1 * c2) / determinant - val y = (a1 * c2 - a2 * c1) / determinant - out(floorCeil(x), floorCeil(y)) - return true + return getIntersectXY(Ax, Ay, Bx, By, Cx, Cy, Dx, Dy) { x, y -> out(floorCeil(x), floorCeil(y)) } } inline fun getIntersectXY(Ax: Double, Ay: Double, Bx: Double, By: Double, Cx: Double, Cy: Double, Dx: Double, Dy: Double, out: (x: Double, y: Double) -> Unit): Boolean { @@ -125,8 +114,7 @@ class Edge { fun containsY(y: Int): Boolean = y >= ay && y < by //fun containsY(y: Int): Boolean = y in ay until by // @TODO: Kotlin/Native at least on Debug doesn't optimize this - @Deprecated("") - fun containsYNear(y: Int, offset: Int): Boolean = y >= (ay - offset) && y < (by + offset) + //fun containsYNear(y: Int, offset: Int): Boolean = y >= (ay - offset) && y < (by + offset) //fun containsY(y: Int): Boolean = y in ay..by //fun containsYNear(y: Int, offset: Int): Boolean = y >= (ay - offset) && y <= (by + offset) fun intersectX(y: Int): Int = if (isCoplanarY) ax else ((y - h) * dx) / dy diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/vector/LineJoin.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/vector/LineJoin.kt index dc4d345..2d0254d 100644 --- a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/vector/LineJoin.kt +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/vector/LineJoin.kt @@ -7,5 +7,14 @@ enum class LineJoin { companion object { val SQUARE = BEVEL + + operator fun get(str: String?): LineJoin = when (str) { + null -> MITER + "MITER", "miter" -> MITER + "BEVEL", "bevel" -> BEVEL + "SQUARE", "square" -> SQUARE + "ROUND", "round" -> ROUND + else -> MITER + } } } diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/vector/PolygonScanline.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/vector/PolygonScanline.kt index 64c15e5..3d6de20 100644 --- a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/vector/PolygonScanline.kt +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/vector/PolygonScanline.kt @@ -184,8 +184,6 @@ class PolygonScanline : RastScale() { fun add(x: Double, y: Double, move: Boolean) = if (move) moveTo(x, y) else lineTo(x, y) fun add(x: Float, y: Float, move: Boolean) = add(x.toDouble(), y.toDouble(), move) fun add(x: Int, y: Int, move: Boolean) = add(x.toDouble(), y.toDouble(), move) - @Deprecated("Kotlin/Native boxes inline + Number") - inline fun add(x: Number, y: Number, move: Boolean) = add(x.toDouble(), y.toDouble(), move) internal inline fun forEachActiveEdgeAtY(y: Int, block: (Edge) -> Unit): Int { var edgesChecked = 0 @@ -319,8 +317,8 @@ class PolygonScanline : RastScale() { private object IntArrayListSort : SortOps() { override fun compare(subject: XWithWind, l: Int, r: Int): Int = subject.x.getAt(l).compareTo(subject.x.getAt(r)) override fun swap(subject: XWithWind, indexL: Int, indexR: Int) { - subject.x.swapIndices(indexL, indexR) - subject.w.swapIndices(indexL, indexR) + subject.x.swap(indexL, indexR) + subject.w.swap(indexL, indexR) } } } diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/vector/VectorBuilder.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/vector/VectorBuilder.kt index 723c063..b35e481 100644 --- a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/vector/VectorBuilder.kt +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/vector/VectorBuilder.kt @@ -47,7 +47,10 @@ fun VectorBuilder.arcTo(ax: Double, ay: Double, cx: Double, cy: Double, r: Doubl lineTo(A.x, A.y) quadTo(a.x, a.y, B.x, B.y) } +fun VectorBuilder.arcTo(ax: Float, ay: Float, cx: Float, cy: Float, r: Float) = arcTo(ax.toDouble(), ay.toDouble(), cx.toDouble(), cy.toDouble(), r.toDouble()) +fun VectorBuilder.arcTo(ax: Int, ay: Int, cx: Int, cy: Int, r: Int) = arcTo(ax.toDouble(), ay.toDouble(), cx.toDouble(), cy.toDouble(), r.toDouble()) +fun VectorBuilder.rect(rect: Rectangle) = rect(rect.x, rect.y, rect.width, rect.height) fun VectorBuilder.rect(x: Double, y: Double, width: Double, height: Double) { moveTo(x, y) lineTo(x + width, y) @@ -55,6 +58,8 @@ fun VectorBuilder.rect(x: Double, y: Double, width: Double, height: Double) { lineTo(x, y + height) close() } +fun VectorBuilder.rect(x: Float, y: Float, width: Float, height: Float) = rect(x.toDouble(), y.toDouble(), width.toDouble(), height.toDouble()) +fun VectorBuilder.rect(x: Int, y: Int, width: Int, height: Int) = rect(x.toDouble(), y.toDouble(), width.toDouble(), height.toDouble()) fun VectorBuilder.rectHole(x: Double, y: Double, width: Double, height: Double) { moveTo(x, y) @@ -76,15 +81,20 @@ fun VectorBuilder.roundRect(x: Double, y: Double, w: Double, h: Double, rx: Doub this.arcTo(x, y, x + w, y, r) } } +fun VectorBuilder.roundRect(x: Float, y: Float, w: Float, h: Float, rx: Float, ry: Float = rx) = roundRect(x.toDouble(), y.toDouble(), w.toDouble(), h.toDouble(), rx.toDouble(), ry.toDouble()) +fun VectorBuilder.roundRect(x: Int, y: Int, w: Int, h: Int, rx: Int, ry: Int = rx) = roundRect(x.toDouble(), y.toDouble(), w.toDouble(), h.toDouble(), rx.toDouble(), ry.toDouble()) -fun VectorBuilder.arc(x: Double, y: Double, r: Double, start: Double, end: Double) { +fun VectorBuilder.rectHole(x: Float, y: Float, width: Float, height: Float) = rectHole(x.toDouble(), y.toDouble(), width.toDouble(), height.toDouble()) +fun VectorBuilder.rectHole(x: Int, y: Int, width: Int, height: Int) = rectHole(x.toDouble(), y.toDouble(), width.toDouble(), height.toDouble()) + +fun VectorBuilder.arc(x: Double, y: Double, r: Double, start: Angle, end: Angle) { // http://hansmuller-flex.blogspot.com.es/2011/04/approximating-circular-arc-with-cubic.html val EPSILON = 0.00001 val PI_TWO = PI * 2.0 val PI_OVER_TWO = PI / 2.0 - val startAngle = start % PI_TWO - val endAngle = end % PI_TWO + val startAngle = start.radians % PI_TWO + val endAngle = end.radians % PI_TWO var remainingAngle = kotlin.math.min(PI_TWO, abs(endAngle - startAngle)) if (remainingAngle == 0.0 && start != end) remainingAngle = PI_TWO val sgn = if (startAngle < endAngle) +1 else -1 @@ -127,8 +137,13 @@ fun VectorBuilder.arc(x: Double, y: Double, r: Double, start: Double, end: Doubl close() } } +fun VectorBuilder.arc(x: Float, y: Float, r: Float, start: Angle, end: Angle) = arc(x.toDouble(), y.toDouble(), r.toDouble(), start, end) +fun VectorBuilder.arc(x: Int, y: Int, r: Int, start: Angle, end: Angle) = arc(x.toDouble(), y.toDouble(), r.toDouble(), start, end) -fun VectorBuilder.circle(x: Double, y: Double, radius: Double) = arc(x, y, radius, 0.0, PI.toDouble() * 2f) +fun VectorBuilder.circle(point: Point, radius: Double) = arc(point.x, point.y, radius, 0.degrees, 360.degrees) +fun VectorBuilder.circle(x: Double, y: Double, radius: Double) = arc(x, y, radius, 0.degrees, 360.degrees) +fun VectorBuilder.circle(x: Float, y: Float, radius: Float) = circle(x.toDouble(), y.toDouble(), radius.toDouble()) +fun VectorBuilder.circle(x: Int, y: Int, radius: Int) = circle(x.toDouble(), y.toDouble(), radius.toDouble()) fun VectorBuilder.ellipse(x: Double, y: Double, rw: Double, rh: Double) { val k = .5522848 @@ -144,6 +159,8 @@ fun VectorBuilder.ellipse(x: Double, y: Double, rw: Double, rh: Double) { cubicTo(xe, ym + oy, xm + ox, ye, xm, ye) cubicTo(xm - ox, ye, x, ym + oy, x, ym) } +fun VectorBuilder.ellipse(x: Float, y: Float, rw: Float, rh: Float) = ellipse(x.toDouble(), y.toDouble(), rw.toDouble(), rh.toDouble()) +fun VectorBuilder.ellipse(x: Int, y: Int, rw: Int, rh: Int) = ellipse(x.toDouble(), y.toDouble(), rw.toDouble(), rh.toDouble()) fun VectorBuilder.moveTo(p: Point) = moveTo(p.x, p.y) fun VectorBuilder.lineTo(p: Point) = lineTo(p.x, p.y) @@ -152,123 +169,114 @@ fun VectorBuilder.cubicTo(c1: Point, c2: Point, a: Point) = cubicTo(c1.x, c1.y, fun VectorBuilder.moveToH(x: Double) = moveTo(x, lastY) +fun VectorBuilder.moveToH(x: Float) = moveToH(x.toDouble()) +fun VectorBuilder.moveToH(x: Int) = moveToH(x.toDouble()) + fun VectorBuilder.rMoveToH(x: Double) = rMoveTo(x, 0.0) +fun VectorBuilder.rMoveToH(x: Float) = rMoveToH(x.toDouble()) +fun VectorBuilder.rMoveToH(x: Int) = rMoveToH(x.toDouble()) fun VectorBuilder.moveToV(y: Double) = moveTo(lastX, y) +fun VectorBuilder.moveToV(y: Float) = moveToV(y.toDouble()) +fun VectorBuilder.moveToV(y: Int) = moveToV(y.toDouble()) + fun VectorBuilder.rMoveToV(y: Double) = rMoveTo(0.0, y) +fun VectorBuilder.rMoveToV(y: Float) = rMoveToV(y.toDouble()) +fun VectorBuilder.rMoveToV(y: Int) = rMoveToV(y.toDouble()) fun VectorBuilder.lineToH(x: Double) = lineTo(x, lastY) +fun VectorBuilder.lineToH(x: Float) = lineToH(x.toDouble()) +fun VectorBuilder.lineToH(x: Int) = lineToH(x.toDouble()) + fun VectorBuilder.rLineToH(x: Double) = rLineTo(x, 0.0) +fun VectorBuilder.rLineToH(x: Float) = rLineToH(x.toDouble()) +fun VectorBuilder.rLineToH(x: Int) = rLineToH(x.toDouble()) fun VectorBuilder.lineToV(y: Double) = lineTo(lastX, y) +fun VectorBuilder.lineToV(y: Float) = lineToV(y.toDouble()) +fun VectorBuilder.lineToV(y: Int) = lineToV(y.toDouble()) + fun VectorBuilder.rLineToV(y: Double) = rLineTo(0.0, y) +fun VectorBuilder.rLineToV(y: Float) = rLineToV(y.toDouble()) +fun VectorBuilder.rLineToV(y: Int) = rLineToV(y.toDouble()) fun VectorBuilder.rMoveTo(x: Double, y: Double) = moveTo(this.lastX + x, this.lastY + y) +fun VectorBuilder.rMoveTo(x: Float, y: Float) = rMoveTo(x.toDouble(), y.toDouble()) +fun VectorBuilder.rMoveTo(x: Int, y: Int) = rMoveTo(x.toDouble(), y.toDouble()) + fun VectorBuilder.rLineTo(x: Double, y: Double) = lineTo(this.lastX + x, this.lastY + y) +fun VectorBuilder.rLineTo(x: Float, y: Float) = rLineTo(x.toDouble(), y.toDouble()) +fun VectorBuilder.rLineTo(x: Int, y: Int) = rLineTo(x.toDouble(), y.toDouble()) fun VectorBuilder.rQuadTo(cx: Double, cy: Double, ax: Double, ay: Double) = quadTo(this.lastX + cx, this.lastY + cy, this.lastX + ax, this.lastY + ay) +fun VectorBuilder.rQuadTo(cx: Float, cy: Float, ax: Float, ay: Float) = rQuadTo(cx.toDouble(), cy.toDouble(), ax.toDouble(), ay.toDouble()) +fun VectorBuilder.rQuadTo(cx: Int, cy: Int, ax: Int, ay: Int) = rQuadTo(cx.toDouble(), cy.toDouble(), ax.toDouble(), ay.toDouble()) -fun VectorBuilder.rCubicTo(cx1: Double, cy1: Double, cx2: Double, cy2: Double, ax: Double, ay: Double) = cubicTo( - this.lastX + cx1, this.lastY + cy1, this.lastX + cx2, this.lastY + cy2, this.lastX + ax, this.lastY + ay -) - - -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.moveTo(x: Number, y: Number) = moveTo(x.toDouble(), y.toDouble()) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.lineTo(x: Number, y: Number) = lineTo(x.toDouble(), y.toDouble()) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.quadTo(controlX: Number, controlY: Number, anchorX: Number, anchorY: Number) = quadTo(controlX.toDouble(), controlY.toDouble(), anchorX.toDouble(), anchorY.toDouble()) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.cubicTo(cx1: Number, cy1: Number, cx2: Number, cy2: Number, ax: Number, ay: Number) = cubicTo(cx1.toDouble(), cy1.toDouble(), cx2.toDouble(), cy2.toDouble(), ax.toDouble(), ay.toDouble()) - -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.moveToH(x: Number) = moveToH(x.toDouble()) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.rMoveToH(x: Number) = rMoveToH(x.toDouble()) - -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.moveToV(y: Number) = moveToV(y.toDouble()) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.rMoveToV(y: Number) = rMoveToV(y.toDouble()) - -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.lineToH(x: Number) = lineToH(x.toDouble()) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.rLineToH(x: Number) = rLineToH(x.toDouble()) - -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.lineToV(y: Number) = lineToV(y.toDouble()) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.rLineToV(y: Number) = rLineToV(y.toDouble()) - -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.rMoveTo(x: Number, y: Number) = rMoveTo(x.toDouble(), y.toDouble()) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.rLineTo(x: Number, y: Number) = rLineTo(x.toDouble(), y.toDouble()) - -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.rQuadTo(cx: Number, cy: Number, ax: Number, ay: Number) = rQuadTo(cx.toDouble(), cy.toDouble(), ax.toDouble(), ay.toDouble()) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.rCubicTo(cx1: Number, cy1: Number, cx2: Number, cy2: Number, ax: Number, ay: Number) = rCubicTo(cx1.toDouble(), cy1.toDouble(), cx2.toDouble(), cy2.toDouble(), ax.toDouble(), ay.toDouble()) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.arcTo(ax: Number, ay: Number, cx: Number, cy: Number, r: Number) = arcTo(ax.toDouble(), ay.toDouble(), cx.toDouble(), cy.toDouble(), r.toDouble()) +fun VectorBuilder.rCubicTo(cx1: Double, cy1: Double, cx2: Double, cy2: Double, ax: Double, ay: Double) = cubicTo(this.lastX + cx1, this.lastY + cy1, this.lastX + cx2, this.lastY + cy2, this.lastX + ax, this.lastY + ay) +fun VectorBuilder.rCubicTo(cx1: Float, cy1: Float, cx2: Float, cy2: Float, ax: Float, ay: Float) = rCubicTo(cx1.toDouble(), cy1.toDouble(), cx2.toDouble(), cy2.toDouble(), ax.toDouble(), ay.toDouble()) +fun VectorBuilder.rCubicTo(cx1: Int, cy1: Int, cx2: Int, cy2: Int, ax: Int, ay: Int) = rCubicTo(cx1.toDouble(), cy1.toDouble(), cx2.toDouble(), cy2.toDouble(), ax.toDouble(), ay.toDouble()) +fun VectorBuilder.moveTo(x: Float, y: Float) = moveTo(x.toDouble(), y.toDouble()) +fun VectorBuilder.moveTo(x: Int, y: Int) = moveTo(x.toDouble(), y.toDouble()) + +fun VectorBuilder.lineTo(x: Float, y: Float) = lineTo(x.toDouble(), y.toDouble()) +fun VectorBuilder.lineTo(x: Int, y: Int) = lineTo(x.toDouble(), y.toDouble()) + +fun VectorBuilder.quadTo(controlX: Float, controlY: Float, anchorX: Float, anchorY: Float) = quadTo(controlX.toDouble(), controlY.toDouble(), anchorX.toDouble(), anchorY.toDouble()) +fun VectorBuilder.quadTo(controlX: Int, controlY: Int, anchorX: Int, anchorY: Int) = quadTo(controlX.toDouble(), controlY.toDouble(), anchorX.toDouble(), anchorY.toDouble()) + +fun VectorBuilder.cubicTo(cx1: Float, cy1: Float, cx2: Float, cy2: Float, ax: Float, ay: Float) = cubicTo(cx1.toDouble(), cy1.toDouble(), cx2.toDouble(), cy2.toDouble(), ax.toDouble(), ay.toDouble()) +fun VectorBuilder.cubicTo(cx1: Int, cy1: Int, cx2: Int, cy2: Int, ax: Int, ay: Int) = cubicTo(cx1.toDouble(), cy1.toDouble(), cx2.toDouble(), cy2.toDouble(), ax.toDouble(), ay.toDouble()) + +fun VectorBuilder.line(p0: Point, p1: Point) = line(p0.x, p0.y, p1.x, p1.y) fun VectorBuilder.line(x0: Double, y0: Double, x1: Double, y1: Double) = moveTo(x0, y0).also { lineTo(x1, y1) } +fun VectorBuilder.line(x0: Float, y0: Float, x1: Float, y1: Float) = line(x0.toDouble(), y0.toDouble(), x1.toDouble(), y1.toDouble()) +fun VectorBuilder.line(x0: Int, y0: Int, x1: Int, y1: Int) = line(x0.toDouble(), y0.toDouble(), x1.toDouble(), y1.toDouble()) + fun VectorBuilder.quad(x0: Double, y0: Double, controlX: Double, controlY: Double, anchorX: Double, anchorY: Double) = moveTo(x0, y0).also { quadTo(controlX, controlY, anchorX, anchorY) } +fun VectorBuilder.quad(x0: Float, y0: Float, controlX: Float, controlY: Float, anchorX: Float, anchorY: Float) = quad(x0.toDouble(), y0.toDouble(), controlX.toDouble(), controlY.toDouble(), anchorX.toDouble(), anchorY.toDouble()) +fun VectorBuilder.quad(x0: Int, y0: Int, controlX: Int, controlY: Int, anchorX: Int, anchorY: Int) = quad(x0.toDouble(), y0.toDouble(), controlX.toDouble(), controlY.toDouble(), anchorX.toDouble(), anchorY.toDouble()) + fun VectorBuilder.cubic(x0: Double, y0: Double, cx1: Double, cy1: Double, cx2: Double, cy2: Double, ax: Double, ay: Double) = moveTo(x0, y0).also { cubicTo(cx1, cy1, cx2, cy2, ax, ay) } +fun VectorBuilder.cubic(x0: Float, y0: Float, cx1: Float, cy1: Float, cx2: Float, cy2: Float, ax: Float, ay: Float) = cubic(x0.toDouble(), y0.toDouble(), cx1.toDouble(), cy1.toDouble(), cx2.toDouble(), cy2.toDouble(), ax.toDouble(), ay.toDouble()) +fun VectorBuilder.cubic(x0: Int, y0: Int, cx1: Int, cy1: Int, cx2: Int, cy2: Int, ax: Int, ay: Int) = cubic(x0.toDouble(), y0.toDouble(), cx1.toDouble(), cy1.toDouble(), cx2.toDouble(), cy2.toDouble(), ax.toDouble(), ay.toDouble()) -fun VectorBuilder.line(p0: Point, p1: Point) = line(p0.x, p0.y, p1.x, p1.y) fun VectorBuilder.quad(o: Point, c: Point, a: Point) = quad(o.x, o.y, c.x, c.y, a.x, a.y) fun VectorBuilder.cubic(o: Point, c1: Point, c2: Point, a: Point) = cubic(o.x, o.y, c1.x, c1.y, c2.x, c2.y, a.x, a.y) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.line(x0: Number, y0: Number, x1: Number, y1: Number) = line(x0.toDouble(), y0.toDouble(), x1.toDouble(), y1.toDouble()) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.quad(x0: Number, y0: Number, controlX: Number, controlY: Number, anchorX: Number, anchorY: Number) = quad(x0.toDouble(), y0.toDouble(), controlX.toDouble(), controlY.toDouble(), anchorX.toDouble(), anchorY.toDouble()) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.cubic(x0: Number, y0: Number, cx1: Number, cy1: Number, cx2: Number, cy2: Number, ax: Number, ay: Number) = cubic(x0.toDouble(), y0.toDouble(), cx1.toDouble(), cy1.toDouble(), cx2.toDouble(), cy2.toDouble(), ax.toDouble(), ay.toDouble()) - -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.rect(x: Number, y: Number, width: Number, height: Number) = rect(x.toDouble(), y.toDouble(), width.toDouble(), height.toDouble()) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.rectHole(x: Number, y: Number, width: Number, height: Number) = rectHole(x.toDouble(), y.toDouble(), width.toDouble(), height.toDouble()) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.roundRect(x: Number, y: Number, w: Number, h: Number, rx: Number, ry: Number = rx) = roundRect(x.toDouble(), y.toDouble(), w.toDouble(), h.toDouble(), rx.toDouble(), ry.toDouble()) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.arc(x: Number, y: Number, r: Number, start: Number, end: Number) = arc(x.toDouble(), y.toDouble(), r.toDouble(), start.toDouble(), end.toDouble()) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.circle(x: Number, y: Number, radius: Number) = circle(x.toDouble(), y.toDouble(), radius.toDouble()) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.ellipse(x: Number, y: Number, rw: Number, rh: Number) = ellipse(x.toDouble(), y.toDouble(), rw.toDouble(), rh.toDouble()) - // Variants supporting relative and absolute modes fun VectorBuilder.rCubicTo(cx1: Double, cy1: Double, cx2: Double, cy2: Double, ax: Double, ay: Double, relative: Boolean) = if (relative) rCubicTo(cx1, cy1, cx2, cy2, ax, ay) else cubicTo(cx1, cy1, cx2, cy2, ax, ay) +fun VectorBuilder.rCubicTo(cx1: Float, cy1: Float, cx2: Float, cy2: Float, ax: Float, ay: Float, relative: Boolean) = if (relative) rCubicTo(cx1, cy1, cx2, cy2, ax, ay) else cubicTo(cx1, cy1, cx2, cy2, ax, ay) +fun VectorBuilder.rCubicTo(cx1: Int, cy1: Int, cx2: Int, cy2: Int, ax: Int, ay: Int, relative: Boolean) = if (relative) rCubicTo(cx1, cy1, cx2, cy2, ax, ay) else cubicTo(cx1, cy1, cx2, cy2, ax, ay) + fun VectorBuilder.rQuadTo(cx: Double, cy: Double, ax: Double, ay: Double, relative: Boolean) = if (relative) rQuadTo(cx, cy, ax, ay) else quadTo(cx, cy, ax, ay) +fun VectorBuilder.rQuadTo(cx: Float, cy: Float, ax: Float, ay: Float, relative: Boolean) = if (relative) rQuadTo(cx, cy, ax, ay) else quadTo(cx, cy, ax, ay) +fun VectorBuilder.rQuadTo(cx: Int, cy: Int, ax: Int, ay: Int, relative: Boolean) = if (relative) rQuadTo(cx, cy, ax, ay) else quadTo(cx, cy, ax, ay) + fun VectorBuilder.rLineTo(ax: Double, ay: Double, relative: Boolean) = if (relative) rLineTo(ax, ay) else lineTo(ax, ay) +fun VectorBuilder.rLineTo(ax: Float, ay: Float, relative: Boolean) = if (relative) rLineTo(ax, ay) else lineTo(ax, ay) +fun VectorBuilder.rLineTo(ax: Int, ay: Int, relative: Boolean) = if (relative) rLineTo(ax, ay) else lineTo(ax, ay) + fun VectorBuilder.rMoveTo(ax: Double, ay: Double, relative: Boolean) = if (relative) rMoveTo(ax, ay) else moveTo(ax, ay) +fun VectorBuilder.rMoveTo(ax: Float, ay: Float, relative: Boolean) = if (relative) rMoveTo(ax, ay) else moveTo(ax, ay) +fun VectorBuilder.rMoveTo(ax: Int, ay: Int, relative: Boolean) = if (relative) rMoveTo(ax, ay) else moveTo(ax, ay) + fun VectorBuilder.rMoveToH(ax: Double, relative: Boolean) = if (relative) rMoveToH(ax) else moveToH(ax) +fun VectorBuilder.rMoveToH(ax: Float, relative: Boolean) = if (relative) rMoveToH(ax) else moveToH(ax) +fun VectorBuilder.rMoveToH(ax: Int, relative: Boolean) = if (relative) rMoveToH(ax) else moveToH(ax) + fun VectorBuilder.rMoveToV(ay: Double, relative: Boolean) = if (relative) rMoveToV(ay) else moveToV(ay) +fun VectorBuilder.rMoveToV(ay: Float, relative: Boolean) = if (relative) rMoveToV(ay) else moveToV(ay) +fun VectorBuilder.rMoveToV(ay: Int, relative: Boolean) = if (relative) rMoveToV(ay) else moveToV(ay) + fun VectorBuilder.rLineToH(ax: Double, relative: Boolean) = if (relative) rLineToH(ax) else lineToH(ax) -fun VectorBuilder.rLineToV(ay: Double, relative: Boolean) = if (relative) rLineToV(ay) else lineToV(ay) +fun VectorBuilder.rLineToH(ax: Float, relative: Boolean) = if (relative) rLineToH(ax) else lineToH(ax) +fun VectorBuilder.rLineToH(ax: Int, relative: Boolean) = if (relative) rLineToH(ax) else lineToH(ax) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.rCubicTo(cx1: Number, cy1: Number, cx2: Number, cy2: Number, ax: Number, ay: Number, relative: Boolean) = if (relative) rCubicTo(cx1, cy1, cx2, cy2, ax, ay) else cubicTo(cx1, cy1, cx2, cy2, ax, ay) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.rQuadTo(cx: Number, cy: Number, ax: Number, ay: Number, relative: Boolean) = if (relative) rQuadTo(cx, cy, ax, ay) else quadTo(cx, cy, ax, ay) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.rLineTo(ax: Number, ay: Number, relative: Boolean) = if (relative) rLineTo(ax, ay) else lineTo(ax, ay) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.rMoveTo(ax: Number, ay: Number, relative: Boolean) = if (relative) rMoveTo(ax, ay) else moveTo(ax, ay) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.rMoveToH(ax: Number, relative: Boolean) = if (relative) rMoveToH(ax) else moveToH(ax) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.rMoveToV(ay: Number, relative: Boolean) = if (relative) rMoveToV(ay) else moveToV(ay) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.rLineToH(ax: Number, relative: Boolean) = if (relative) rLineToH(ax) else lineToH(ax) -@Deprecated("Kotlin/Native boxes Number in inline") -inline fun VectorBuilder.rLineToV(ay: Number, relative: Boolean) = if (relative) rLineToV(ay) else lineToV(ay) +fun VectorBuilder.rLineToV(ay: Double, relative: Boolean) = if (relative) rLineToV(ay) else lineToV(ay) +fun VectorBuilder.rLineToV(ay: Float, relative: Boolean) = if (relative) rLineToV(ay) else lineToV(ay) +fun VectorBuilder.rLineToV(ay: Int, relative: Boolean) = if (relative) rLineToV(ay) else lineToV(ay) fun VectorBuilder.transformed(m: Matrix): VectorBuilder { val im = m.inverted() diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/vector/VectorPath.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/vector/VectorPath.kt index 8578890..509d0dc 100644 --- a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/vector/VectorPath.kt +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/vector/VectorPath.kt @@ -9,6 +9,12 @@ import com.soywiz.korma.geom.shape.* import com.soywiz.korma.internal.niceStr import kotlin.native.concurrent.ThreadLocal +// @TODO: ThreadLocal on JVM +@ThreadLocal +private val tempMatrix: Matrix = Matrix() +@ThreadLocal +private val identityMatrix: Matrix = Matrix() + open class VectorPath( val commands: IntArrayList = IntArrayList(), val data: DoubleArrayList = DoubleArrayList(), @@ -19,6 +25,8 @@ open class VectorPath( open fun clone(): VectorPath = VectorPath(IntArrayList(commands), DoubleArrayList(data), winding) companion object { + private val identityMatrix = Matrix() + inline operator fun invoke(winding: Winding = Winding.EVEN_ODD, callback: VectorPath.() -> Unit): VectorPath = VectorPath(winding = winding).apply(callback) fun intersects(left: VectorPath, leftTransform: Matrix, right: VectorPath, rightTransform: Matrix): Boolean = @@ -226,15 +234,14 @@ open class VectorPath( return points } - private val p1 = Point() - private val p2 = Point() - // http://erich.realtimerendering.com/ptinpoly/ // http://stackoverflow.com/questions/217578/how-can-i-determine-whether-a-2d-point-is-within-a-polygon/2922778#2922778 // https://www.particleincell.com/2013/cubic-line-intersection/ // I run a semi-infinite ray horizontally (increasing x, fixed y) out from the test point, and count how many edges it crosses. // At each crossing, the ray switches between inside and outside. This is called the Jordan curve theorem. fun containsPoint(x: Double, y: Double): Boolean = containsPoint(x, y, this.winding) + fun containsPoint(x: Int, y: Int): Boolean = containsPoint(x.toDouble(), y.toDouble()) + fun containsPoint(x: Float, y: Float): Boolean = containsPoint(x.toDouble(), y.toDouble()) @OptIn(KormaExperimental::class) private val scanline by lazy { PolygonScanline().also { @@ -249,12 +256,8 @@ open class VectorPath( } } fun containsPoint(x: Double, y: Double, winding: Winding): Boolean = ensureScanline().containsPoint(x, y, winding) - - @ThreadLocal - private val tempMatrix: Matrix = Matrix() - - @ThreadLocal - private val identityMatrix: Matrix = Matrix() + fun containsPoint(x: Int, y: Int, winding: Winding): Boolean = containsPoint(x.toDouble(), y.toDouble(), winding) + fun containsPoint(x: Float, y: Float, winding: Winding): Boolean = containsPoint(x.toDouble(), y.toDouble(), winding) fun intersectsWith(right: VectorPath): Boolean = intersectsWith(identityMatrix, right, identityMatrix) @@ -284,21 +287,22 @@ open class VectorPath( return false } - @Deprecated("Use containsPoint instead that work with both windings") - fun numberOfIntersections(x: Double, y: Double): Int { - val testx = x - val testy = y - - var intersections = 0 - - visitEdges( - line = { x0, y0, x1, y1 -> intersections += HorizontalLine.intersectionsWithLine(testx, testy, x0, y0, x1, y1) }, - quad = { x0, y0, x1, y1, x2, y2 -> intersections += HorizontalLine.interesectionsWithQuadBezier(testx, testy, x0, y0, x1, y1, x2, y2, p1, p2) }, - cubic = { x0, y0, x1, y1, x2, y2, x3, y3 -> intersections += HorizontalLine.intersectionsWithCubicBezier(testx, testy, x0, y0, x1, y1, x2, y2, x3, y3, p1, p2) }, - close = {} - ) - return intersections - } + //private val p1 = Point() + //private val p2 = Point() + //fun numberOfIntersections(x: Double, y: Double): Int { + // val testx = x + // val testy = y + // var intersections = 0 + // visitEdges( + // line = { x0, y0, x1, y1 -> intersections += HorizontalLine.intersectionsWithLine(testx, testy, x0, y0, x1, y1) }, + // quad = { x0, y0, x1, y1, x2, y2 -> intersections += HorizontalLine.interesectionsWithQuadBezier(testx, testy, x0, y0, x1, y1, x2, y2, p1, p2) }, + // cubic = { x0, y0, x1, y1, x2, y2, x3, y3 -> intersections += HorizontalLine.intersectionsWithCubicBezier(testx, testy, x0, y0, x1, y1, x2, y2, x3, y3, p1, p2) }, + // close = {} + // ) + // return intersections + //} + //fun numberOfIntersections(x: Float, y: Float): Int = numberOfIntersections(x.toDouble(), y.toDouble()) + //fun numberOfIntersections(x: Int, y: Int): Int = numberOfIntersections(x.toDouble(), y.toDouble()) class Stats { val stats = IntArray(5) @@ -327,26 +331,22 @@ open class VectorPath( const val CLOSE = 4 } - @Deprecated("") - // Can cause problems because we are not applying transforms at all that might be applied by the VectorBuilder - fun write(path: VectorPath) { + fun write(path: VectorPath, transform: Matrix = identityMatrix) { this.commands += path.commands - this.data += path.data - this.lastX = path.lastX - this.lastY = path.lastY - version++ - } - - fun write(path: VectorPath, transform: Matrix) { - this.commands += path.commands - for (n in 0 until path.data.size step 2) { - val x = path.data.getAt(n + 0) - val y = path.data.getAt(n + 1) - this.data += transform.transformX(x, y) - this.data += transform.transformY(x, y) + if (transform.isIdentity()) { + this.data += path.data + this.lastX = path.lastX + this.lastY = path.lastY + } else { + for (n in 0 until path.data.size step 2) { + val x = path.data.getAt(n + 0) + val y = path.data.getAt(n + 1) + this.data += transform.transformX(x, y) + this.data += transform.transformY(x, y) + } + this.lastX = transform.transformX(path.lastX, path.lastY) + this.lastY = transform.transformY(path.lastX, path.lastY) } - this.lastX = transform.transformX(path.lastX, path.lastY) - this.lastY = transform.transformY(path.lastX, path.lastY) version++ } @@ -376,18 +376,6 @@ fun VectorBuilder.write(path: VectorPath) { ) } -inline fun VectorPath.containsPoint(x: Int, y: Int): Boolean = containsPoint(x.toDouble(), y.toDouble()) -inline fun VectorPath.containsPoint(x: Int, y: Int, winding: Winding): Boolean = containsPoint(x.toDouble(), y.toDouble(), winding) -inline fun VectorPath.containsPoint(x: Float, y: Float): Boolean = containsPoint(x.toDouble(), y.toDouble()) -inline fun VectorPath.containsPoint(x: Float, y: Float, winding: Winding): Boolean = containsPoint(x.toDouble(), y.toDouble(), winding) - -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun VectorPath.containsPoint(x: Number, y: Number): Boolean = containsPoint(x.toDouble(), y.toDouble()) -@Deprecated("Kotlin/Native boxes inline + Number") -inline fun VectorPath.containsPoint(x: Number, y: Number, winding: Winding): Boolean = containsPoint(x.toDouble(), y.toDouble(), winding) -@Deprecated("Use containsPoint instead that work with both windings") -inline fun VectorPath.numberOfIntersections(x: Number, y: Number): Int = numberOfIntersections(x.toDouble(), y.toDouble()) - fun BoundsBuilder.add(path: VectorPath, transform: Matrix) { val bb = this var lx = 0.0 diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/internal/KormaVersion.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/internal/KormaVersion.kt index 76c4bff..44d1bf1 100644 --- a/korma/src/commonMain/kotlin/com/soywiz/korma/internal/KormaVersion.kt +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/internal/KormaVersion.kt @@ -1,3 +1,3 @@ package com.soywiz.korma.internal -internal const val KORMA_VERSION = "1.11.18-SNAPSHOT" \ No newline at end of file +internal const val KORMA_VERSION = "2.0.0-SNAPSHOT" \ No newline at end of file diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/interpolation/Easing.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/interpolation/Easing.kt index 76d236d..7697119 100644 --- a/korma/src/commonMain/kotlin/com/soywiz/korma/interpolation/Easing.kt +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/interpolation/Easing.kt @@ -2,96 +2,158 @@ package com.soywiz.korma.interpolation import kotlin.math.* +private inline fun combine(it: Double, start: Easing, end: Easing) = + if (it < 0.5) 0.5 * start(it * 2.0) else 0.5 * end((it - 0.5) * 2.0) + 0.5 +private const val BOUNCE_FACTOR = 1.70158 +private const val HALF_PI = PI / 2.0 + @Suppress("unused") -interface Easing { +fun interface Easing { operator fun invoke(it: Double): Double companion object { fun cubic(f: (t: Double, b: Double, c: Double, d: Double) -> Double): Easing = Easing { f(it, 0.0, 1.0, 1.0) } - fun combine(start: Easing, end: Easing) = - Easing { if (it < 0.5) 0.5 * start(it * 2.0) else 0.5 * end((it - 0.5) * 2.0) + 0.5 } + fun combine(start: Easing, end: Easing) = Easing { combine(it, start, end) } - operator fun invoke(f: (Double) -> Double) = object : Easing { - override fun invoke(it: Double): Double = f(it) + /** + * Retrieves a mapping of all standard easings defined directly in [Easing], for example "SMOOTH" -> Easing.SMOOTH. + */ + val ALL: Map by lazy(LazyThreadSafetyMode.PUBLICATION) { + Easings.values().associateBy { it.name } } - val SMOOTH get() = Easings.SMOOTH - val EASE_IN_ELASTIC get() = Easings.EASE_IN_ELASTIC - val EASE_OUT_ELASTIC get() = Easings.EASE_OUT_ELASTIC - val EASE_OUT_BOUNCE get() = Easings.EASE_OUT_BOUNCE - val LINEAR get() = Easings.LINEAR - val EASE_IN get() = Easings.EASE_IN - val EASE_OUT get() = Easings.EASE_OUT - val EASE_IN_OUT get() = Easings.EASE_IN_OUT - val EASE_OUT_IN get() = Easings.EASE_OUT_IN - val EASE_IN_BACK get() = Easings.EASE_IN_BACK - val EASE_OUT_BACK get() = Easings.EASE_OUT_BACK - val EASE_IN_OUT_BACK get() = Easings.EASE_IN_OUT_BACK - val EASE_OUT_IN_BACK get() = Easings.EASE_OUT_IN_BACK - val EASE_IN_OUT_ELASTIC get() = Easings.EASE_IN_OUT_ELASTIC - val EASE_OUT_IN_ELASTIC get() = Easings.EASE_OUT_IN_ELASTIC - val EASE_IN_BOUNCE get() = Easings.EASE_IN_BOUNCE - val EASE_IN_OUT_BOUNCE get() = Easings.EASE_IN_OUT_BOUNCE - val EASE_OUT_IN_BOUNCE get() = Easings.EASE_OUT_IN_BOUNCE - val EASE_IN_QUAD get() = Easings.EASE_IN_QUAD - val EASE_OUT_QUAD get() = Easings.EASE_OUT_QUAD - val EASE_IN_OUT_QUAD get() = Easings.EASE_IN_OUT_QUAD - val EASE_SINE get() = Easings.EASE_SINE - } -} - -private object Easings { - private const val BOUNCE_10 = 1.70158 - private const val PI_2 = PI / 2.0; - - val SMOOTH = Easing { it * it * (3 - 2 * it) } + // Author's note: + // 1. Make sure new standard easings are added both here and in the Easings enum class + // 2. Make sure the name is the same, otherwise [ALL] will return confusing results - val EASE_IN_ELASTIC = Easing { - if (it == 0.0 || it == 1.0) it else { - val p = 0.3 - val s = p / 4.0 - val inv = it - 1 - -1.0 * 2.0.pow(10.0 * inv) * sin((inv - s) * (2.0 * PI) / p) - } + val SMOOTH: Easing get() = Easings.SMOOTH + val EASE_IN_ELASTIC: Easing get() = Easings.EASE_IN_ELASTIC + val EASE_OUT_ELASTIC: Easing get() = Easings.EASE_OUT_ELASTIC + val EASE_OUT_BOUNCE: Easing get() = Easings.EASE_OUT_BOUNCE + val LINEAR: Easing get() = Easings.LINEAR + val EASE_IN: Easing get() = Easings.EASE_IN + val EASE_OUT: Easing get() = Easings.EASE_OUT + val EASE_IN_OUT: Easing get() = Easings.EASE_IN_OUT + val EASE_OUT_IN: Easing get() = Easings.EASE_OUT_IN + val EASE_IN_BACK: Easing get() = Easings.EASE_IN_BACK + val EASE_OUT_BACK: Easing get() = Easings.EASE_OUT_BACK + val EASE_IN_OUT_BACK: Easing get() = Easings.EASE_IN_OUT_BACK + val EASE_OUT_IN_BACK: Easing get() = Easings.EASE_OUT_IN_BACK + val EASE_IN_OUT_ELASTIC: Easing get() = Easings.EASE_IN_OUT_ELASTIC + val EASE_OUT_IN_ELASTIC: Easing get() = Easings.EASE_OUT_IN_ELASTIC + val EASE_IN_BOUNCE: Easing get() = Easings.EASE_IN_BOUNCE + val EASE_IN_OUT_BOUNCE: Easing get() = Easings.EASE_IN_OUT_BOUNCE + val EASE_OUT_IN_BOUNCE: Easing get() = Easings.EASE_OUT_IN_BOUNCE + val EASE_IN_QUAD: Easing get() = Easings.EASE_IN_QUAD + val EASE_OUT_QUAD: Easing get() = Easings.EASE_OUT_QUAD + val EASE_IN_OUT_QUAD: Easing get() = Easings.EASE_IN_OUT_QUAD + val EASE_SINE: Easing get() = Easings.EASE_SINE } +} - val EASE_OUT_ELASTIC = Easing { - if (it == 0.0 || it == 1.0) it else { - val p = 0.3 - val s = p / 4.0 - 2.0.pow(-10.0 * it) * sin((it - s) * (2.0 * PI) / p) + 1 - } - } +private enum class Easings : Easing { + SMOOTH { + override fun invoke(it: Double): Double = it * it * (3 - 2 * it) + }, + EASE_IN_ELASTIC { + override fun invoke(it: Double): Double = + if (it == 0.0 || it == 1.0) { + it + } else { + val p = 0.3 + val s = p / 4.0 + val inv = it - 1 - val EASE_OUT_BOUNCE = Easing { - val s = 7.5625 - val p = 2.75 - when { - it < (1.0 / p) -> s * it.pow(2.0) - it < (2.0 / p) -> s * (it - 1.5 / p).pow(2.0) + 0.75 - it < 2.5 / p -> s * (it - 2.25 / p).pow(2.0) + 0.9375 - else -> s * (it - 2.625 / p).pow(2.0) + 0.984375 + -1.0 * 2.0.pow(10.0 * inv) * sin((inv - s) * (2.0 * PI) / p) + } + }, + EASE_OUT_ELASTIC { + override fun invoke(it: Double): Double = + if (it == 0.0 || it == 1.0) { + it + } else { + val p = 0.3 + val s = p / 4.0 + 2.0.pow(-10.0 * it) * sin((it - s) * (2.0 * PI) / p) + 1 + } + }, + EASE_OUT_BOUNCE { + override fun invoke(it: Double): Double { + val s = 7.5625 + val p = 2.75 + return when { + it < 1.0 / p -> s * it.pow(2.0) + it < 2.0 / p -> s * (it - 1.5 / p).pow(2.0) + 0.75 + it < 2.5 / p -> s * (it - 2.25 / p).pow(2.0) + 0.9375 + else -> s * (it - 2.625 / p).pow(2.0) + 0.984375 + } } + }, + LINEAR { + override fun invoke(it: Double): Double = it + }, + EASE_IN { + override fun invoke(it: Double): Double = it * it * it + }, + EASE_OUT { + override fun invoke(it: Double): Double = + (it - 1.0).let { inv -> + inv * inv * inv + 1 + } + }, + EASE_IN_OUT { + override fun invoke(it: Double): Double = combine(it, EASE_IN, EASE_OUT) + }, + EASE_OUT_IN { + override fun invoke(it: Double): Double = combine(it, EASE_OUT, EASE_IN) + }, + EASE_IN_BACK { + override fun invoke(it: Double): Double = it.pow(2.0) * ((BOUNCE_FACTOR + 1.0) * it - BOUNCE_FACTOR) + }, + EASE_OUT_BACK { + override fun invoke(it: Double): Double = + (it - 1.0).let { inv -> + inv.pow(2.0) * ((BOUNCE_FACTOR + 1.0) * inv + BOUNCE_FACTOR) + 1.0 + } + }, + EASE_IN_OUT_BACK { + override fun invoke(it: Double): Double = combine(it, EASE_IN_BACK, EASE_OUT_BACK) + }, + EASE_OUT_IN_BACK { + override fun invoke(it: Double): Double = combine(it, EASE_OUT_BACK, EASE_IN_BACK) + }, + EASE_IN_OUT_ELASTIC { + override fun invoke(it: Double): Double = combine(it, EASE_IN_ELASTIC, EASE_OUT_ELASTIC) + }, + EASE_OUT_IN_ELASTIC { + override fun invoke(it: Double): Double = combine(it, EASE_OUT_ELASTIC, EASE_IN_ELASTIC) + }, + EASE_IN_BOUNCE { + override fun invoke(it: Double): Double = 1.0 - EASE_OUT_BOUNCE(1.0 - it) + }, + EASE_IN_OUT_BOUNCE { + override fun invoke(it: Double): Double = combine(it, EASE_IN_BOUNCE, EASE_OUT_BOUNCE) + }, + EASE_OUT_IN_BOUNCE { + override fun invoke(it: Double): Double = combine(it, EASE_OUT_BOUNCE, EASE_IN_BOUNCE) + }, + EASE_IN_QUAD { + override fun invoke(it: Double): Double = 1.0 * it * it + }, + EASE_OUT_QUAD { + override fun invoke(it: Double): Double = -1.0 * it * (it - 2) + }, + EASE_IN_OUT_QUAD { + override fun invoke(it: Double): Double = + (it * 2.0).let { t -> + if (t < 1) { + 1.0 / 2 * t * t + } else { + -1.0 / 2 * ((t - 1) * ((t - 1) - 2) - 1) + } + } + }, + EASE_SINE { + override fun invoke(it: Double): Double = sin(it * HALF_PI) } - - val LINEAR = Easing { it } - val EASE_IN = Easing { it * it * it } - val EASE_OUT = Easing { val inv = it - 1.0; inv * inv * inv + 1 } - val EASE_IN_OUT = Easing.combine(EASE_IN, EASE_OUT) - val EASE_OUT_IN = Easing.combine(EASE_OUT, EASE_IN) - val EASE_IN_BACK = Easing { it.pow(2.0) * ((BOUNCE_10 + 1.0) * it - BOUNCE_10) } - val EASE_OUT_BACK = Easing { val inv = it - 1.0; inv.pow(2.0) * ((BOUNCE_10 + 1.0) * inv + BOUNCE_10) + 1.0 } - val EASE_IN_OUT_BACK = Easing.combine(EASE_IN_BACK, EASE_OUT_BACK) - val EASE_OUT_IN_BACK = Easing.combine(EASE_OUT_BACK, EASE_IN_BACK) - val EASE_IN_OUT_ELASTIC = Easing.combine(EASE_IN_ELASTIC, EASE_OUT_ELASTIC) - val EASE_OUT_IN_ELASTIC = Easing.combine(EASE_OUT_ELASTIC, EASE_IN_ELASTIC) - val EASE_IN_BOUNCE = Easing { 1.0 - EASE_OUT_BOUNCE(1.0 - it) } - val EASE_IN_OUT_BOUNCE = Easing.combine(EASE_IN_BOUNCE, EASE_OUT_BOUNCE) - val EASE_OUT_IN_BOUNCE = Easing.combine(EASE_OUT_BOUNCE, EASE_IN_BOUNCE) - val EASE_IN_QUAD = Easing { 1.0 * it * it } - val EASE_OUT_QUAD = Easing { -1.0 * it * (it - 2) } - val EASE_IN_OUT_QUAD = - Easing { val t = it * 2.0; if (t < 1) (1.0 / 2 * t * t) else (-1.0 / 2 * ((t - 1) * ((t - 1) - 2) - 1)) } - - val EASE_SINE = Easing { sin(it * PI_2) } } diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/interpolation/Interpolation.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/interpolation/Interpolation.kt index 3ad6937..c69b3b5 100644 --- a/korma/src/commonMain/kotlin/com/soywiz/korma/interpolation/Interpolation.kt +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/interpolation/Interpolation.kt @@ -8,17 +8,6 @@ interface MutableInterpolable { fun setToInterpolated(ratio: Double, l: T, r: T): T } -@Suppress("UNCHECKED_CAST", "USELESS_CAST", "DeprecatedCallableAddReplaceWith") -@Deprecated("Kotlin.JS can't differentiate numeric types, so this might cause strange issues with Ints having decimals") -fun Double.interpolateAny(min: T, max: T): T = when (min) { - is Float -> this.interpolate(min as Float, max as Float) as T - is Int -> this.interpolate(min as Int, max as Int) as T - is Double -> this.interpolate(min as Double, max as Double) as T - is Long -> this.interpolate(min as Long, max as Long) as T - is Interpolable<*> -> (min as Interpolable).interpolateWith(this, max as Interpolable) as T - else -> throw IllegalArgumentException("Value is not interpolable") -} - fun Double.interpolate(l: Float, r: Float): Float = (l + (r - l) * this).toFloat() fun Double.interpolate(l: Double, r: Double): Double = (l + (r - l) * this) fun Double.interpolate(l: Int, r: Int): Int = (l + (r - l) * this).toInt() diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/random/RandomExt.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/random/RandomExt.kt index 56790c6..e14bb68 100644 --- a/korma/src/commonMain/kotlin/com/soywiz/korma/random/RandomExt.kt +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/random/RandomExt.kt @@ -2,7 +2,6 @@ package com.soywiz.korma.random import com.soywiz.korma.geom.* import com.soywiz.korma.interpolation.* -import com.soywiz.korma.math.* import kotlin.math.* import kotlin.random.* @@ -29,7 +28,6 @@ operator fun > Random.get(l: T, r: T): T = (this.nextInt(0x1 operator fun Random.get(list: List): T = list[this[list.indices]] operator fun Random.get(rectangle: Rectangle): IPoint = IPoint(this[rectangle.left, rectangle.right], this[rectangle.top, rectangle.bottom]) fun > T.setToRandom(min: T, max: T, random: Random = Random) = run { this.setToInterpolated(random.nextDouble(), min, max) } -operator fun > Random.get(range: ClosedRange): T = (this.nextInt(0x10001).toDouble() / 0x10000.toDouble()).interpolateAny(range.start, range.endInclusive) fun Random.weighted(weights: Map): T = shuffledWeighted(weights).first() fun Random.weighted(weights: RandomWeights): T = shuffledWeighted(weights).first() diff --git a/korma/src/commonTest/kotlin/com/soywiz/korma/geom/Matrix3DTest.kt b/korma/src/commonTest/kotlin/com/soywiz/korma/geom/Matrix3DTest.kt index f323310..89ea498 100644 --- a/korma/src/commonTest/kotlin/com/soywiz/korma/geom/Matrix3DTest.kt +++ b/korma/src/commonTest/kotlin/com/soywiz/korma/geom/Matrix3DTest.kt @@ -29,23 +29,23 @@ class Matrix3DTest { @Test fun testMultiply() { val l = Matrix3D.fromRows( - 1, 2, 3, 4, - 5, 6, 7, 8, - 9, 10, 11, 12, - 13, 14, 15, 16 + 1f, 2f, 3f, 4f, + 5f, 6f, 7f, 8f, + 9f, 10f, 11f, 12f, + 13f, 14f, 15f, 16f ) val r = Matrix3D.fromRows( - 17, 18, 19, 20, - 21, 22, 23, 24, - 25, 26, 27, 28, - 29, 30, 31, 32 + 17f, 18f, 19f, 20f, + 21f, 22f, 23f, 24f, + 25f, 26f, 27f, 28f, + 29f, 30f, 31f, 32f ) assertEquals( Matrix3D.fromRows( - 250, 260, 270, 280, - 618, 644, 670, 696, - 986, 1028, 1070, 1112, - 1354, 1412, 1470, 1528 + 250f, 260f, 270f, 280f, + 618f, 644f, 670f, 696f, + 986f, 1028f, 1070f, 1112f, + 1354f, 1412f, 1470f, 1528f ), (l * r) diff --git a/korma/src/commonTest/kotlin/com/soywiz/korma/geom/MatrixTest.kt b/korma/src/commonTest/kotlin/com/soywiz/korma/geom/MatrixTest.kt index 6c54543..654a5e2 100644 --- a/korma/src/commonTest/kotlin/com/soywiz/korma/geom/MatrixTest.kt +++ b/korma/src/commonTest/kotlin/com/soywiz/korma/geom/MatrixTest.kt @@ -4,7 +4,7 @@ import com.soywiz.korma.interpolation.* import kotlin.test.* class MatrixTest { - private val identity: IMatrix = Matrix(1, 0, 0, 1, 0, 0) + private val identity: Matrix = Matrix(1, 0, 0, 1, 0, 0) @Test fun test() { @@ -22,7 +22,6 @@ class MatrixTest { assertEquals(75.0, matrix.transformY(10, 20)) assertEquals(Point(30.0, 75.0), matrix.transform(Point(10, 20))) assertEquals(Point(20.0, 60.0), matrix.deltaTransformPoint(Point(10, 20))) - } @Test @@ -93,21 +92,21 @@ class MatrixTest { @Test fun transform2() { - assertEquals(Matrix(2, 0, 0, 3, 10, 20), Matrix.Transform(10, 20, scaleX = 2, scaleY = 3).toMatrix()) + assertEquals(Matrix(2, 0, 0, 3, 10, 20), Matrix.Transform(10.0, 20.0, scaleX = 2.0, scaleY = 3.0).toMatrix()) // @TODO: Kotlin.JS BUG (missing arguments are NaN or undefined but it works fine on JVM) //val t1 = Matrix.Transform(10, 20, scaleX = 2, scaleY = 3, rotation = 90.degrees) //val t2 = Matrix.Transform(20, 40, scaleX = 4, scaleY = 5, rotation = 180.degrees) - val t1 = Matrix.Transform(10, 20, scaleX = 2, scaleY = 3, skewX = 0.0, skewY = 0.0, rotation = 90.degrees) - val t2 = Matrix.Transform(20, 40, scaleX = 4, scaleY = 5, skewX = 0.0, skewY = 0.0, rotation = 180.degrees) + val t1 = Matrix.Transform(10.0, 20.0, scaleX = 2.0, scaleY = 3.0, skewX = 0.0.degrees, skewY = 0.0.degrees, rotation = 90.degrees) + val t2 = Matrix.Transform(20.0, 40.0, scaleX = 4.0, scaleY = 5.0, skewX = 0.0.degrees, skewY = 0.0.degrees, rotation = 180.degrees) assertEquals( - Matrix.Transform(x = 15.0, y = 30.0, scaleX = 3.0, scaleY = 4.0, skewX = 0.0, skewY = 0.0, rotation = 135.degrees), + Matrix.Transform(x = 15.0, y = 30.0, scaleX = 3.0, scaleY = 4.0, skewX = 0.0.degrees, skewY = 0.0.degrees, rotation = 135.degrees), 0.5.interpolate(t1, t2) ) val identity = Matrix.Transform() - val mt = Matrix.Transform(1, 2, 3, 4, 5, 6, 7.radians) + val mt = Matrix.Transform(1.0, 2.0, 3.0, 4.0, 5.0.radians, 6.0.radians, 7.0.radians) mt.identity() assertEquals(identity, mt) assertNotSame(mt, mt.clone()) diff --git a/korma/src/commonTest/kotlin/com/soywiz/korma/geom/PointAreaTest.kt b/korma/src/commonTest/kotlin/com/soywiz/korma/geom/PointPoolTest.kt similarity index 85% rename from korma/src/commonTest/kotlin/com/soywiz/korma/geom/PointAreaTest.kt rename to korma/src/commonTest/kotlin/com/soywiz/korma/geom/PointPoolTest.kt index 8cb905b..b469153 100644 --- a/korma/src/commonTest/kotlin/com/soywiz/korma/geom/PointAreaTest.kt +++ b/korma/src/commonTest/kotlin/com/soywiz/korma/geom/PointPoolTest.kt @@ -2,11 +2,11 @@ package com.soywiz.korma.geom import kotlin.test.* -class PointAreaTest { +class PointPoolTest { @Test fun test() { var called = false - val area = PointArea(7) + val area = PointPool(7) area { called = true assertEquals(Point(30, 30), Point(10, 10) + Point(20, 20)) diff --git a/korma/src/commonTest/kotlin/com/soywiz/korma/geom/Vector2Test.kt b/korma/src/commonTest/kotlin/com/soywiz/korma/geom/Vector2Test.kt index 18d99a3..c89b694 100644 --- a/korma/src/commonTest/kotlin/com/soywiz/korma/geom/Vector2Test.kt +++ b/korma/src/commonTest/kotlin/com/soywiz/korma/geom/Vector2Test.kt @@ -7,7 +7,7 @@ import kotlin.test.assertEquals class Vector2Test { @Test fun name() { - val v = IPoint(1, 1.0) + val v = IPoint(1.0, 1.0) //assertEquals(sqrt(2.0), v.length, 0.001) assertEquals(sqrt(2.0), v.length) } diff --git a/korma/src/commonTest/kotlin/com/soywiz/korma/geom/Vector3DTest.kt b/korma/src/commonTest/kotlin/com/soywiz/korma/geom/Vector3DTest.kt index 5227a99..400cc77 100644 --- a/korma/src/commonTest/kotlin/com/soywiz/korma/geom/Vector3DTest.kt +++ b/korma/src/commonTest/kotlin/com/soywiz/korma/geom/Vector3DTest.kt @@ -4,7 +4,7 @@ import kotlin.test.* class Vector3DTest { @Test - fun test() { + fun testNormalize() { val v = Vector3D(2, 0, 0) // Normalized doesn't changes the original vector assertEquals(Vector3D(1, 0, 0), v.normalized()) @@ -14,4 +14,30 @@ class Vector3DTest { assertEquals(Vector3D(1, 0, 0), v.normalize()) assertEquals(Vector3D(1, 0, 0), v) } + + @Test + fun testCrossProduct() { + val xInt = Vector3D().cross(Vector3D(1, 0, 0), Vector3D(0, 1, 0)) + assertEquals(Vector3D(0, 0, 1), xInt) + val xDouble = Vector3D().cross(Vector3D(1.0, 0.0, 0.0), Vector3D(0.0, 1.0, 0.0)) + assertEquals(Vector3D(0.0, 0.0, 1.0), xDouble) + } + + @Test + fun testDotProduct() { + val dot = Vector3D(0.5, 1.0, 0.0).dot(Vector3D(3.0, 1.0, 1.0)) + assertEquals(2.5f, dot) + } + + @Test + fun testBasicMath() { + val v = Vector3D(0,0,0) + v.add(v, Vector3D(1,0,0)) + assertEquals(Vector3D(1, 0,0, 2), v) + v.scale(5) + assertEquals(Vector3D(5, 0 ,0,10), v) + v.sub(v, Vector3D(2, 1, 0)) + assertEquals(Vector3D(3, -1, 0, 9), v) + } + } diff --git a/korma/src/commonTest/kotlin/com/soywiz/korma/geom/vector/VectorPathTest.kt b/korma/src/commonTest/kotlin/com/soywiz/korma/geom/vector/VectorPathTest.kt index c6599ce..94b0c8b 100644 --- a/korma/src/commonTest/kotlin/com/soywiz/korma/geom/vector/VectorPathTest.kt +++ b/korma/src/commonTest/kotlin/com/soywiz/korma/geom/vector/VectorPathTest.kt @@ -26,7 +26,7 @@ class VectorPathTest { val g = VectorPath() g.circle(0, 0, 100) println(g.readStats()) - println(g.numberOfIntersections(0, 0)) + //println(g.numberOfIntersections(0, 0)) assertEquals(true, g.containsPoint(0, 0)) assertEquals(false, g.containsPoint(120, 0)) assertEquals(false, g.containsPoint(-100, -100)) diff --git a/korma/src/commonTest/kotlin/com/soywiz/korma/interpolation/EasingTest.kt b/korma/src/commonTest/kotlin/com/soywiz/korma/interpolation/EasingTest.kt index 423bfdb..cbadbb9 100644 --- a/korma/src/commonTest/kotlin/com/soywiz/korma/interpolation/EasingTest.kt +++ b/korma/src/commonTest/kotlin/com/soywiz/korma/interpolation/EasingTest.kt @@ -1,5 +1,6 @@ package com.soywiz.korma.interpolation +import kotlin.math.abs import kotlin.test.* class EasingTest { @@ -26,4 +27,20 @@ class EasingTest { assertEquals(0.0, Easing.EASE_SINE(0.0)) assertEquals(1.0, Easing.EASE_SINE(1.0)) } + + @Test + fun testStartsAtZero() { + Easing.ALL.values.forEach { easing -> + val v = easing(0.0) + assertTrue(abs(v) < 0.0001, "Easing $easing did not start at 0, was $v") + } + } + + @Test + fun testEndsAtOne() { + Easing.ALL.values.forEach { easing -> + val v = easing(1.0) + assertTrue(abs(v - 1.0) < 0.0001, "Easing $easing did not end at 1, was $v") + } + } } diff --git a/korma/src/commonTest/kotlin/com/soywiz/korma/math/MathTest.kt b/korma/src/commonTest/kotlin/com/soywiz/korma/math/MathTest.kt index 0fee5a2..caeb697 100644 --- a/korma/src/commonTest/kotlin/com/soywiz/korma/math/MathTest.kt +++ b/korma/src/commonTest/kotlin/com/soywiz/korma/math/MathTest.kt @@ -1,5 +1,6 @@ package com.soywiz.korma.math +import kotlin.math.E import kotlin.test.* class MathTest { @@ -16,6 +17,13 @@ class MathTest { assertEquals(4, log10(10000)) } + + @Test + fun testLn() { + assertEquals(0, ln(1)) + assertEquals(2, ln(20)) + } + @Test fun testSmoothStep() { assertEquals(0.0, 100.0.smoothstep(100.0, 200.0)) @@ -109,4 +117,16 @@ class MathTest { assertEquals(true, Float.NEGATIVE_INFINITY.isNanOrInfinite()) assertEquals(true, Float.NaN.isNanOrInfinite()) } + + @Test + fun testIsMultipleOf() { + assertTrue(4.isMultipleOf(2)) + assertTrue(25L.isMultipleOf(5L)) + + assertEquals(12, 10.nextMultipleOf(3)) + assertEquals(15L, 11L.nextMultipleOf(5L)) + + assertEquals(9, 10.prevMultipleOf(3)) + assertEquals(10L, 11L.prevMultipleOf(5L)) + } }