forked from kscience/kmath
Refactor geometry
This commit is contained in:
parent
19bebfd1ed
commit
efb853c1bc
@ -3,11 +3,14 @@
|
||||
## Unreleased
|
||||
|
||||
### Added
|
||||
- Integer divistion algebras
|
||||
- Integer division algebras
|
||||
- Float32 geometries
|
||||
|
||||
### Changed
|
||||
- Default naming for algebra and buffers now uses IntXX/FloatXX notation instead of Java types.
|
||||
- Remove unnecessary inlines in basic algebras.
|
||||
- QuaternionField -> QuaternionAlgebra and does not implement `Field` anymore since it is non-commutative
|
||||
- kmath-geometry is split into `euclidean2d` and `euclidean3d`
|
||||
|
||||
### Deprecated
|
||||
|
||||
|
@ -122,16 +122,17 @@ public val Quaternion.reciprocal: Quaternion
|
||||
/**
|
||||
* Produce a normalized version of this quaternion
|
||||
*/
|
||||
public fun Quaternion.normalized(): Quaternion = with(QuaternionField){ this@normalized / norm(this@normalized) }
|
||||
public fun Quaternion.normalized(): Quaternion = with(QuaternionAlgebra){ this@normalized / norm(this@normalized) }
|
||||
|
||||
/**
|
||||
* A field of [Quaternion].
|
||||
*/
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public object QuaternionField : Field<Quaternion>, Norm<Quaternion, Double>, PowerOperations<Quaternion>,
|
||||
public object QuaternionAlgebra : Group<Quaternion>, Norm<Quaternion, Double>, PowerOperations<Quaternion>,
|
||||
ExponentialOperations<Quaternion>, NumbersAddOps<Quaternion>, ScaleOperations<Quaternion> {
|
||||
|
||||
override val zero: Quaternion = Quaternion(0.0)
|
||||
override val one: Quaternion = Quaternion(1.0)
|
||||
public val one: Quaternion = Quaternion(1.0)
|
||||
|
||||
/**
|
||||
* The `i` quaternion unit.
|
||||
@ -154,14 +155,16 @@ public object QuaternionField : Field<Quaternion>, Norm<Quaternion, Double>, Pow
|
||||
override fun scale(a: Quaternion, value: Double): Quaternion =
|
||||
Quaternion(a.w * value, a.x * value, a.y * value, a.z * value)
|
||||
|
||||
override fun multiply(left: Quaternion, right: Quaternion): Quaternion = Quaternion(
|
||||
public fun multiply(left: Quaternion, right: Quaternion): Quaternion = Quaternion(
|
||||
left.w * right.w - left.x * right.x - left.y * right.y - left.z * right.z,
|
||||
left.w * right.x + left.x * right.w + left.y * right.z - left.z * right.y,
|
||||
left.w * right.y - left.x * right.z + left.y * right.w + left.z * right.x,
|
||||
left.w * right.z + left.x * right.y - left.y * right.x + left.z * right.w,
|
||||
)
|
||||
|
||||
override fun divide(left: Quaternion, right: Quaternion): Quaternion {
|
||||
public operator fun Quaternion.times(other: Quaternion): Quaternion = multiply(this, other)
|
||||
|
||||
public fun divide(left: Quaternion, right: Quaternion): Quaternion {
|
||||
val s = right.w * right.w + right.x * right.x + right.y * right.y + right.z * right.z
|
||||
|
||||
return Quaternion(
|
||||
@ -172,14 +175,17 @@ public object QuaternionField : Field<Quaternion>, Norm<Quaternion, Double>, Pow
|
||||
)
|
||||
}
|
||||
|
||||
public operator fun Quaternion.div(other: Quaternion): Quaternion = divide(this, other)
|
||||
|
||||
|
||||
override fun power(arg: Quaternion, pow: Number): Quaternion {
|
||||
if (pow is Int) return pwr(arg, pow)
|
||||
if (floor(pow.toDouble()) == pow.toDouble()) return pwr(arg, pow.toInt())
|
||||
if (pow is Int) return power(arg, pow)
|
||||
if (floor(pow.toDouble()) == pow.toDouble()) return power(arg, pow.toInt())
|
||||
return exp(pow * ln(arg))
|
||||
}
|
||||
|
||||
private fun pwr(x: Quaternion, a: Int): Quaternion = when {
|
||||
a < 0 -> -(pwr(x, -a))
|
||||
private fun power(x: Quaternion, a: Int): Quaternion = when {
|
||||
a < 0 -> -(power(x, -a))
|
||||
a == 0 -> one
|
||||
a == 1 -> x
|
||||
a == 2 -> pwr2(x)
|
||||
@ -243,14 +249,15 @@ public object QuaternionField : Field<Quaternion>, Norm<Quaternion, Double>, Pow
|
||||
return Quaternion(ln(n), th * arg.x, th * arg.y, th * arg.z)
|
||||
}
|
||||
|
||||
override operator fun Number.plus(other: Quaternion): Quaternion =
|
||||
public override operator fun Number.plus(other: Quaternion): Quaternion =
|
||||
Quaternion(toDouble() + other.w, other.x, other.y, other.z)
|
||||
|
||||
override operator fun Number.minus(other: Quaternion): Quaternion =
|
||||
public override operator fun Number.minus(other: Quaternion): Quaternion =
|
||||
Quaternion(toDouble() - other.w, -other.x, -other.y, -other.z)
|
||||
|
||||
override operator fun Quaternion.plus(other: Number): Quaternion = Quaternion(w + other.toDouble(), x, y, z)
|
||||
override operator fun Quaternion.minus(other: Number): Quaternion = Quaternion(w - other.toDouble(), x, y, z)
|
||||
public override operator fun Quaternion.plus(other: Number): Quaternion = Quaternion(w + other.toDouble(), x, y, z)
|
||||
|
||||
public override operator fun Quaternion.minus(other: Number): Quaternion = Quaternion(w - other.toDouble(), x, y, z)
|
||||
|
||||
override operator fun Number.times(arg: Quaternion): Quaternion =
|
||||
Quaternion(toDouble() * arg.w, toDouble() * arg.x, toDouble() * arg.y, toDouble() * arg.z)
|
||||
@ -275,7 +282,7 @@ public object QuaternionField : Field<Quaternion>, Norm<Quaternion, Double>, Pow
|
||||
override fun sinh(arg: Quaternion): Quaternion = (exp(arg) - exp(-arg)) / 2.0
|
||||
override fun cosh(arg: Quaternion): Quaternion = (exp(arg) + exp(-arg)) / 2.0
|
||||
override fun tanh(arg: Quaternion): Quaternion = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg))
|
||||
override fun asinh(arg: Quaternion): Quaternion = ln(sqrt(arg * arg + one) + arg)
|
||||
override fun asinh(arg: Quaternion): Quaternion = ln(sqrt(pwr2(arg) + one) + arg)
|
||||
override fun acosh(arg: Quaternion): Quaternion = ln(arg + sqrt((arg - one) * (arg + one)))
|
||||
override fun atanh(arg: Quaternion): Quaternion = (ln(arg + one) - ln(one - arg)) / 2.0
|
||||
}
|
||||
|
@ -14,20 +14,20 @@ internal class QuaternionTest {
|
||||
|
||||
@Test
|
||||
fun testNorm() {
|
||||
assertEquals(2.0, QuaternionField.norm(Quaternion(1.0, 1.0, 1.0, 1.0)))
|
||||
assertEquals(2.0, QuaternionAlgebra.norm(Quaternion(1.0, 1.0, 1.0, 1.0)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInverse() = QuaternionField {
|
||||
fun testInverse() = QuaternionAlgebra {
|
||||
val q = Quaternion(1.0, 2.0, -3.0, 4.0)
|
||||
assertBufferEquals(one, q * q.reciprocal, 1e-4)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAddition() {
|
||||
assertEquals(Quaternion(42, 42), QuaternionField { Quaternion(16, 16) + Quaternion(26, 26) })
|
||||
assertEquals(Quaternion(42, 16), QuaternionField { Quaternion(16, 16) + 26 })
|
||||
assertEquals(Quaternion(42, 16), QuaternionField { 26 + Quaternion(16, 16) })
|
||||
assertEquals(Quaternion(42, 42), QuaternionAlgebra { Quaternion(16, 16) + Quaternion(26, 26) })
|
||||
assertEquals(Quaternion(42, 16), QuaternionAlgebra { Quaternion(16, 16) + 26 })
|
||||
assertEquals(Quaternion(42, 16), QuaternionAlgebra { 26 + Quaternion(16, 16) })
|
||||
}
|
||||
|
||||
// @Test
|
||||
@ -39,9 +39,9 @@ internal class QuaternionTest {
|
||||
|
||||
@Test
|
||||
fun testMultiplication() {
|
||||
assertEquals(Quaternion(42, 42), QuaternionField { Quaternion(4.2, 0) * Quaternion(10, 10) })
|
||||
assertEquals(Quaternion(42, 21), QuaternionField { Quaternion(4.2, 2.1) * 10 })
|
||||
assertEquals(Quaternion(42, 21), QuaternionField { 10 * Quaternion(4.2, 2.1) })
|
||||
assertEquals(Quaternion(42, 42), QuaternionAlgebra { Quaternion(4.2, 0) * Quaternion(10, 10) })
|
||||
assertEquals(Quaternion(42, 21), QuaternionAlgebra { Quaternion(4.2, 2.1) * 10 })
|
||||
assertEquals(Quaternion(42, 21), QuaternionAlgebra { 10 * Quaternion(4.2, 2.1) })
|
||||
}
|
||||
|
||||
// @Test
|
||||
@ -53,11 +53,11 @@ internal class QuaternionTest {
|
||||
|
||||
@Test
|
||||
fun testPower() {
|
||||
assertEquals(QuaternionField.zero, QuaternionField { zero pow 2 })
|
||||
assertEquals(QuaternionField.zero, QuaternionField { zero pow 2 })
|
||||
assertEquals(QuaternionAlgebra.zero, QuaternionAlgebra { zero pow 2 })
|
||||
assertEquals(QuaternionAlgebra.zero, QuaternionAlgebra { zero pow 2 })
|
||||
|
||||
assertEquals(
|
||||
QuaternionField { i * 8 }.let { it.x.toInt() to it.w.toInt() },
|
||||
QuaternionField { Quaternion(2, 2) pow 2 }.let { it.x.toInt() to it.w.toInt() })
|
||||
QuaternionAlgebra { i * 8 }.let { it.x.toInt() to it.w.toInt() },
|
||||
QuaternionAlgebra { Quaternion(2, 2) pow 2 }.let { it.x.toInt() to it.w.toInt() })
|
||||
}
|
||||
}
|
||||
|
@ -300,7 +300,7 @@ public interface Ring<T> : Group<T>, RingOps<T> {
|
||||
* commutative operations [add] and [multiply]; binary operation [divide] as multiplication of left operand by
|
||||
* reciprocal of right one.
|
||||
*
|
||||
* @param T the type of element of this semifield.
|
||||
* @param T the type of the semifield element.
|
||||
*/
|
||||
public interface FieldOps<T> : RingOps<T> {
|
||||
/**
|
||||
@ -336,10 +336,12 @@ public interface FieldOps<T> : RingOps<T> {
|
||||
|
||||
/**
|
||||
* Represents field i.e., algebraic structure with three operations: associative, commutative addition and
|
||||
* multiplication, and division. **This interface differs from the eponymous mathematical definition: fields in KMath
|
||||
* multiplication, and division.
|
||||
*
|
||||
* **This interface differs from the eponymous mathematical definition: fields in KMath
|
||||
* also support associative multiplication by scalar.**
|
||||
*
|
||||
* @param T the type of element of this field.
|
||||
* @param T the type of the field element.
|
||||
*/
|
||||
public interface Field<T> : Ring<T>, FieldOps<T>, ScaleOperations<T>, NumericAlgebra<T> {
|
||||
override fun number(value: Number): T = scale(one, value.toDouble())
|
||||
|
@ -150,7 +150,7 @@ public interface ScaleOperations<T> : Algebra<T> {
|
||||
* TODO to be removed and replaced by extensions after multiple receivers are there
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public interface NumbersAddOps<T> : RingOps<T>, NumericAlgebra<T> {
|
||||
public interface NumbersAddOps<T> : GroupOps<T>, NumericAlgebra<T> {
|
||||
/**
|
||||
* Addition of element and scalar.
|
||||
*
|
||||
@ -177,7 +177,7 @@ public interface NumbersAddOps<T> : RingOps<T>, NumericAlgebra<T> {
|
||||
public operator fun T.minus(other: Number): T = this - number(other)
|
||||
|
||||
/**
|
||||
* Subtraction of number from element.
|
||||
* Subtraction of number from the element.
|
||||
*
|
||||
* @receiver the minuend.
|
||||
* @param other the subtrahend.
|
||||
|
@ -82,9 +82,9 @@ public expect fun Number.isInteger(): Boolean
|
||||
/**
|
||||
* A context extension to include power operations based on exponentiation.
|
||||
*
|
||||
* @param T the type of element of this structure.
|
||||
* @param T the type of this structure element
|
||||
*/
|
||||
public interface PowerOperations<T> : FieldOps<T> {
|
||||
public interface PowerOperations<T>: Algebra<T> {
|
||||
|
||||
/**
|
||||
* Raises [arg] to a power if possible (negative number could not be raised to a fractional power).
|
||||
|
@ -16,7 +16,6 @@ import kotlin.math.pow
|
||||
|
||||
public typealias DoubleVector = Point<Double>
|
||||
|
||||
@Suppress("FunctionName")
|
||||
public fun DoubleVector(vararg doubles: Double): DoubleVector = doubles.asBuffer()
|
||||
|
||||
/**
|
||||
|
@ -7,6 +7,8 @@ package space.kscience.kmath.geometry
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import space.kscience.kmath.geometry.euclidean2d.DoubleVector2D
|
||||
import space.kscience.kmath.geometry.euclidean3d.DoubleVector3D
|
||||
|
||||
/**
|
||||
* A line formed by [start] vector of start and a [direction] vector. Direction vector is not necessarily normalized,
|
||||
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2018-2023 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.geometry
|
||||
|
||||
import space.kscience.kmath.linear.Point
|
||||
|
||||
public interface Vector2D<T> : Point<T>, Vector {
|
||||
public val x: T
|
||||
public val y: T
|
||||
override val size: Int get() = 2
|
||||
|
||||
override operator fun get(index: Int): T = when (index) {
|
||||
0 -> x
|
||||
1 -> y
|
||||
else -> error("Accessing outside of point bounds")
|
||||
}
|
||||
|
||||
override operator fun iterator(): Iterator<T> = iterator {
|
||||
yield(x)
|
||||
yield(y)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public operator fun <T> Vector2D<T>.component1(): T = x
|
||||
public operator fun <T> Vector2D<T>.component2(): T = y
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2018-2023 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.geometry
|
||||
|
||||
import space.kscience.kmath.linear.Point
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
|
||||
public interface Vector3D<T> : Point<T>, Vector {
|
||||
public val x: T
|
||||
public val y: T
|
||||
public val z: T
|
||||
override val size: Int get() = 3
|
||||
|
||||
override operator fun get(index: Int): T = when (index) {
|
||||
0 -> x
|
||||
1 -> y
|
||||
2 -> z
|
||||
else -> error("Accessing outside of point bounds")
|
||||
}
|
||||
|
||||
override operator fun iterator(): Iterator<T> = listOf(x, y, z).iterator()
|
||||
}
|
||||
|
||||
public operator fun <T> Vector3D<T>.component1(): T = x
|
||||
public operator fun <T> Vector3D<T>.component2(): T = y
|
||||
public operator fun <T> Vector3D<T>.component3(): T = z
|
||||
|
||||
public fun <T> Buffer<T>.asVector3D(): Vector3D<T> = object : Vector3D<T> {
|
||||
init {
|
||||
require(this@asVector3D.size == 3) { "Buffer of size 3 is required for Vector3D" }
|
||||
}
|
||||
|
||||
override val x: T get() = this@asVector3D[0]
|
||||
override val y: T get() = this@asVector3D[1]
|
||||
override val z: T get() = this@asVector3D[2]
|
||||
|
||||
override fun toString(): String = this@asVector3D.toString()
|
||||
}
|
@ -1,20 +1,19 @@
|
||||
/*
|
||||
* Copyright 2018-2022 KMath contributors.
|
||||
* Copyright 2018-2023 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.geometry
|
||||
package space.kscience.kmath.geometry.euclidean2d
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo
|
||||
import kotlin.math.*
|
||||
import kotlin.math.PI
|
||||
|
||||
/**
|
||||
* A circle in 2D space
|
||||
*/
|
||||
@Serializable
|
||||
public data class Circle2D(
|
||||
@Serializable(Euclidean2DSpace.VectorSerializer::class) public val center: DoubleVector2D,
|
||||
@Serializable(Float64Space2D.VectorSerializer::class) public val center: DoubleVector2D,
|
||||
public val radius: Double
|
||||
)
|
||||
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2018-2023 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.geometry.euclidean2d
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import space.kscience.kmath.geometry.GeometrySpace
|
||||
import space.kscience.kmath.geometry.Vector2D
|
||||
import space.kscience.kmath.operations.Float32Field
|
||||
import space.kscience.kmath.operations.ScaleOperations
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sqrt
|
||||
|
||||
@Serializable(Float32Space2D.VectorSerializer::class)
|
||||
public interface Float32Vector2D: Vector2D<Float>
|
||||
|
||||
|
||||
public object Float32Space2D :
|
||||
GeometrySpace<Float32Vector2D>,
|
||||
ScaleOperations<Float32Vector2D> {
|
||||
|
||||
@Serializable
|
||||
@SerialName("Float32Vector2D")
|
||||
private data class Vector2DImpl(
|
||||
override val x: Float,
|
||||
override val y: Float,
|
||||
) : Float32Vector2D
|
||||
|
||||
public object VectorSerializer : KSerializer<Float32Vector2D> {
|
||||
private val proxySerializer = Vector2DImpl.serializer()
|
||||
override val descriptor: SerialDescriptor get() = proxySerializer.descriptor
|
||||
|
||||
override fun deserialize(decoder: Decoder): Float32Vector2D = decoder.decodeSerializableValue(proxySerializer)
|
||||
|
||||
override fun serialize(encoder: Encoder, value: Float32Vector2D) {
|
||||
val vector = value as? Vector2DImpl ?: Vector2DImpl(value.x, value.y)
|
||||
encoder.encodeSerializableValue(proxySerializer, vector)
|
||||
}
|
||||
}
|
||||
|
||||
public fun vector(x: Float, y: Float): Float32Vector2D =
|
||||
Vector2DImpl(x, y)
|
||||
|
||||
public fun vector(x: Number, y: Number): Float32Vector2D =
|
||||
vector(x.toFloat(), y.toFloat())
|
||||
|
||||
override val zero: Float32Vector2D by lazy { vector(0f, 0f) }
|
||||
|
||||
override fun norm(arg: Float32Vector2D): Double = sqrt(arg.x.pow(2) + arg.y.pow(2)).toDouble()
|
||||
|
||||
public fun Float32Vector2D.norm(): Double = norm(this)
|
||||
|
||||
override fun Float32Vector2D.unaryMinus(): Float32Vector2D = vector(-x, -y)
|
||||
|
||||
override fun Float32Vector2D.distanceTo(other: Float32Vector2D): Double = (this - other).norm()
|
||||
|
||||
override fun add(left: Float32Vector2D, right: Float32Vector2D): Float32Vector2D =
|
||||
vector(left.x + right.x, left.y + right.y)
|
||||
|
||||
override fun scale(a: Float32Vector2D, value: Double): Float32Vector2D =
|
||||
vector(a.x * value, a.y * value)
|
||||
|
||||
override fun Float32Vector2D.dot(other: Float32Vector2D): Double =
|
||||
(x * other.x + y * other.y).toDouble()
|
||||
|
||||
public val xAxis: Float32Vector2D = vector(1.0, 0.0)
|
||||
public val yAxis: Float32Vector2D = vector(0.0, 1.0)
|
||||
}
|
||||
|
||||
public fun Float32Vector2D(x: Number, y: Number): Float32Vector2D = Float32Space2D.vector(x, y)
|
||||
|
||||
public val Float32Field.euclidean2D: Float32Space2D get() = Float32Space2D
|
@ -1,9 +1,9 @@
|
||||
/*
|
||||
* Copyright 2018-2022 KMath contributors.
|
||||
* Copyright 2018-2023 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.geometry
|
||||
package space.kscience.kmath.geometry.euclidean2d
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.SerialName
|
||||
@ -11,43 +11,26 @@ import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import space.kscience.kmath.linear.Point
|
||||
import space.kscience.kmath.geometry.GeometrySpace
|
||||
import space.kscience.kmath.geometry.Vector2D
|
||||
import space.kscience.kmath.operations.Float64Field
|
||||
import space.kscience.kmath.operations.Norm
|
||||
import space.kscience.kmath.operations.ScaleOperations
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sqrt
|
||||
|
||||
public interface Vector2D<T> : Point<T>, Vector {
|
||||
public val x: T
|
||||
public val y: T
|
||||
override val size: Int get() = 2
|
||||
|
||||
override operator fun get(index: Int): T = when (index) {
|
||||
0 -> x
|
||||
1 -> y
|
||||
else -> error("Accessing outside of point bounds")
|
||||
}
|
||||
|
||||
override operator fun iterator(): Iterator<T> = iterator {
|
||||
yield(x)
|
||||
yield(y)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public operator fun <T> Vector2D<T>.component1(): T = x
|
||||
public operator fun <T> Vector2D<T>.component2(): T = y
|
||||
|
||||
public typealias DoubleVector2D = Vector2D<Double>
|
||||
public typealias Float64Vector2D = Vector2D<Double>
|
||||
|
||||
public val Vector2D<Double>.r: Double get() = Euclidean2DSpace.norm(this)
|
||||
public val Vector2D<Double>.r: Double get() = Float64Space2D.norm(this)
|
||||
|
||||
|
||||
/**
|
||||
* 2D Euclidean space
|
||||
*/
|
||||
public object Euclidean2DSpace : GeometrySpace<DoubleVector2D>,
|
||||
public object Float64Space2D : GeometrySpace<DoubleVector2D>,
|
||||
ScaleOperations<DoubleVector2D>,
|
||||
Norm<DoubleVector2D, Double> {
|
||||
|
||||
@ -88,3 +71,5 @@ public object Euclidean2DSpace : GeometrySpace<DoubleVector2D>,
|
||||
public val xAxis: DoubleVector2D = vector(1.0, 0.0)
|
||||
public val yAxis: DoubleVector2D = vector(0.0, 1.0)
|
||||
}
|
||||
|
||||
public val Float64Field.euclidean2D: Float64Space2D get() = Float64Space2D
|
@ -3,7 +3,9 @@
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.geometry
|
||||
package space.kscience.kmath.geometry.euclidean2d
|
||||
|
||||
import space.kscience.kmath.geometry.Vector2D
|
||||
|
||||
|
||||
/**
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2018-2023 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.geometry.euclidean3d
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import space.kscience.kmath.geometry.GeometrySpace
|
||||
import space.kscience.kmath.geometry.Vector3D
|
||||
import space.kscience.kmath.operations.Float32Field
|
||||
import space.kscience.kmath.operations.ScaleOperations
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sqrt
|
||||
|
||||
@Serializable(Float32Space3D.VectorSerializer::class)
|
||||
public interface Float32Vector3D: Vector3D<Float>
|
||||
|
||||
|
||||
public object Float32Space3D :
|
||||
GeometrySpace<Float32Vector3D>,
|
||||
ScaleOperations<Float32Vector3D>{
|
||||
|
||||
@Serializable
|
||||
@SerialName("Float32Vector3D")
|
||||
private data class Vector3DImpl(
|
||||
override val x: Float,
|
||||
override val y: Float,
|
||||
override val z: Float,
|
||||
) : Float32Vector3D
|
||||
|
||||
public object VectorSerializer : KSerializer<Float32Vector3D> {
|
||||
private val proxySerializer = Vector3DImpl.serializer()
|
||||
override val descriptor: SerialDescriptor get() = proxySerializer.descriptor
|
||||
|
||||
override fun deserialize(decoder: Decoder): Float32Vector3D = decoder.decodeSerializableValue(proxySerializer)
|
||||
|
||||
override fun serialize(encoder: Encoder, value: Float32Vector3D) {
|
||||
val vector = value as? Vector3DImpl ?: Vector3DImpl(value.x, value.y, value.z)
|
||||
encoder.encodeSerializableValue(proxySerializer, vector)
|
||||
}
|
||||
}
|
||||
|
||||
public fun vector(x: Float, y: Float, z: Float): Float32Vector3D =
|
||||
Vector3DImpl(x, y, z)
|
||||
|
||||
public fun vector(x: Number, y: Number, z: Number): Float32Vector3D =
|
||||
vector(x.toFloat(), y.toFloat(), z.toFloat())
|
||||
|
||||
override val zero: Float32Vector3D by lazy { vector(0.0, 0.0, 0.0) }
|
||||
|
||||
override fun norm(arg: Float32Vector3D): Double = sqrt(arg.x.pow(2) + arg.y.pow(2) + arg.z.pow(2)).toDouble()
|
||||
|
||||
public fun Float32Vector3D.norm(): Double = norm(this)
|
||||
|
||||
override fun Float32Vector3D.unaryMinus(): Float32Vector3D = vector(-x, -y, -z)
|
||||
|
||||
override fun Float32Vector3D.distanceTo(other: Float32Vector3D): Double = (this - other).norm()
|
||||
|
||||
override fun add(left: Float32Vector3D, right: Float32Vector3D): Float32Vector3D =
|
||||
vector(left.x + right.x, left.y + right.y, left.z + right.z)
|
||||
|
||||
override fun scale(a: Float32Vector3D, value: Double): Float32Vector3D =
|
||||
vector(a.x * value, a.y * value, a.z * value)
|
||||
|
||||
override fun Float32Vector3D.dot(other: Float32Vector3D): Double =
|
||||
(x * other.x + y * other.y + z * other.z).toDouble()
|
||||
|
||||
/**
|
||||
* Compute vector product of [first] and [second]. The basis is assumed to be right-handed.
|
||||
*/
|
||||
public fun vectorProduct(
|
||||
first: Float32Vector3D,
|
||||
second: Float32Vector3D,
|
||||
): Float32Vector3D {
|
||||
var x = 0.0
|
||||
var y = 0.0
|
||||
var z = 0.0
|
||||
|
||||
for (j in (0..2)) {
|
||||
for (k in (0..2)) {
|
||||
x += leviCivita(0, j, k) * first[j] * second[k]
|
||||
y += leviCivita(1, j, k) * first[j] * second[k]
|
||||
z += leviCivita(2, j, k) * first[j] * second[k]
|
||||
}
|
||||
}
|
||||
|
||||
return vector(x, y, z)
|
||||
}
|
||||
|
||||
/**
|
||||
* Vector product in a right-handed basis
|
||||
*/
|
||||
public infix fun Float32Vector3D.cross(other: Float32Vector3D): Float32Vector3D = vectorProduct(this, other)
|
||||
|
||||
public val xAxis: Float32Vector3D = vector(1.0, 0.0, 0.0)
|
||||
public val yAxis: Float32Vector3D = vector(0.0, 1.0, 0.0)
|
||||
public val zAxis: Float32Vector3D = vector(0.0, 0.0, 1.0)
|
||||
}
|
||||
|
||||
public fun Float32Vector3D(x: Number, y: Number, z: Number): Float32Vector3D = Float32Space3D.vector(x, y, z)
|
||||
|
||||
public val Float32Field.euclidean3D: Float32Space3D get() = Float32Space3D
|
@ -1,9 +1,9 @@
|
||||
/*
|
||||
* Copyright 2018-2022 KMath contributors.
|
||||
* Copyright 2018-2023 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.geometry
|
||||
package space.kscience.kmath.geometry.euclidean3d
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.SerialName
|
||||
@ -11,51 +11,33 @@ import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import space.kscience.kmath.linear.Point
|
||||
import space.kscience.kmath.geometry.GeometrySpace
|
||||
import space.kscience.kmath.geometry.Vector3D
|
||||
import space.kscience.kmath.operations.Float64Field
|
||||
import space.kscience.kmath.operations.Norm
|
||||
import space.kscience.kmath.operations.ScaleOperations
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sqrt
|
||||
|
||||
public interface Vector3D<T> : Point<T>, Vector {
|
||||
public val x: T
|
||||
public val y: T
|
||||
public val z: T
|
||||
override val size: Int get() = 3
|
||||
internal fun leviCivita(i: Int, j: Int, k: Int): Int = when {
|
||||
// even permutation
|
||||
i == 0 && j == 1 && k == 2 -> 1
|
||||
i == 1 && j == 2 && k == 0 -> 1
|
||||
i == 2 && j == 0 && k == 1 -> 1
|
||||
// odd permutations
|
||||
i == 2 && j == 1 && k == 0 -> -1
|
||||
i == 0 && j == 2 && k == 1 -> -1
|
||||
i == 1 && j == 0 && k == 2 -> -1
|
||||
|
||||
override operator fun get(index: Int): T = when (index) {
|
||||
0 -> x
|
||||
1 -> y
|
||||
2 -> z
|
||||
else -> error("Accessing outside of point bounds")
|
||||
}
|
||||
|
||||
override operator fun iterator(): Iterator<T> = listOf(x, y, z).iterator()
|
||||
}
|
||||
|
||||
public operator fun <T> Vector3D<T>.component1(): T = x
|
||||
public operator fun <T> Vector3D<T>.component2(): T = y
|
||||
public operator fun <T> Vector3D<T>.component3(): T = z
|
||||
|
||||
public fun <T> Buffer<T>.asVector3D(): Vector3D<T> = object : Vector3D<T> {
|
||||
init {
|
||||
require(this@asVector3D.size == 3) { "Buffer of size 3 is required for Vector3D" }
|
||||
}
|
||||
|
||||
override val x: T get() = this@asVector3D[0]
|
||||
override val y: T get() = this@asVector3D[1]
|
||||
override val z: T get() = this@asVector3D[2]
|
||||
|
||||
override fun toString(): String = this@asVector3D.toString()
|
||||
else -> 0
|
||||
}
|
||||
|
||||
public typealias DoubleVector3D = Vector3D<Double>
|
||||
public typealias Float64Vector3D = Vector3D<Double>
|
||||
|
||||
public val DoubleVector3D.r: Double get() = Euclidean3DSpace.norm(this)
|
||||
public val DoubleVector3D.r: Double get() = Float64Space3D.norm(this)
|
||||
|
||||
public object Euclidean3DSpace : GeometrySpace<DoubleVector3D>, ScaleOperations<DoubleVector3D>,
|
||||
public object Float64Space3D : GeometrySpace<DoubleVector3D>, ScaleOperations<DoubleVector3D>,
|
||||
Norm<DoubleVector3D, Double> {
|
||||
|
||||
@Serializable
|
||||
@ -103,21 +85,8 @@ public object Euclidean3DSpace : GeometrySpace<DoubleVector3D>, ScaleOperations<
|
||||
override fun DoubleVector3D.dot(other: DoubleVector3D): Double =
|
||||
x * other.x + y * other.y + z * other.z
|
||||
|
||||
private fun leviCivita(i: Int, j: Int, k: Int): Int = when {
|
||||
// even permutation
|
||||
i == 0 && j == 1 && k == 2 -> 1
|
||||
i == 1 && j == 2 && k == 0 -> 1
|
||||
i == 2 && j == 0 && k == 1 -> 1
|
||||
// odd permutations
|
||||
i == 2 && j == 1 && k == 0 -> -1
|
||||
i == 0 && j == 2 && k == 1 -> -1
|
||||
i == 1 && j == 0 && k == 2 -> -1
|
||||
|
||||
else -> 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute vector product of [first] and [second]. The basis assumed to be right-handed.
|
||||
* Compute vector product of [first] and [second]. The basis is assumed to be right-handed.
|
||||
*/
|
||||
public fun vectorProduct(
|
||||
first: DoubleVector3D,
|
||||
@ -139,7 +108,7 @@ public object Euclidean3DSpace : GeometrySpace<DoubleVector3D>, ScaleOperations<
|
||||
}
|
||||
|
||||
/**
|
||||
* Vector product with right basis
|
||||
* Vector product with the right basis
|
||||
*/
|
||||
public infix fun DoubleVector3D.cross(other: DoubleVector3D): Vector3D<Double> = vectorProduct(this, other)
|
||||
|
||||
@ -147,3 +116,5 @@ public object Euclidean3DSpace : GeometrySpace<DoubleVector3D>, ScaleOperations<
|
||||
public val yAxis: DoubleVector3D = vector(0.0, 1.0, 0.0)
|
||||
public val zAxis: DoubleVector3D = vector(0.0, 0.0, 1.0)
|
||||
}
|
||||
|
||||
public val Float64Field.euclidean3D: Float64Space3D get() = Float64Space3D
|
@ -1,15 +1,16 @@
|
||||
/*
|
||||
* Copyright 2018-2022 KMath contributors.
|
||||
* Copyright 2018-2023 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.geometry
|
||||
package space.kscience.kmath.geometry.euclidean3d
|
||||
|
||||
import space.kscience.kmath.UnstableKMathAPI
|
||||
import space.kscience.kmath.complex.Quaternion
|
||||
import space.kscience.kmath.complex.QuaternionField
|
||||
import space.kscience.kmath.complex.QuaternionAlgebra
|
||||
import space.kscience.kmath.complex.normalized
|
||||
import space.kscience.kmath.complex.reciprocal
|
||||
import space.kscience.kmath.geometry.*
|
||||
import space.kscience.kmath.linear.LinearSpace
|
||||
import space.kscience.kmath.linear.Matrix
|
||||
import space.kscience.kmath.linear.linearSpace
|
||||
@ -31,7 +32,7 @@ public val Quaternion.theta: Radians get() = (kotlin.math.acos(normalized().w) *
|
||||
public fun Quaternion.Companion.fromRotation(theta: Angle, vector: DoubleVector3D): Quaternion {
|
||||
val s = sin(theta / 2)
|
||||
val c = cos(theta / 2)
|
||||
val norm = with(Euclidean3DSpace) { vector.norm() }
|
||||
val norm = with(Float64Space3D) { vector.norm() }
|
||||
return Quaternion(c, vector.x * s / norm, vector.y * s / norm, vector.z * s / norm)
|
||||
}
|
||||
|
||||
@ -50,9 +51,9 @@ public val Quaternion.vector: DoubleVector3D
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate a vector in a [Euclidean3DSpace]
|
||||
* Rotate a vector in a [Float64Space3D]
|
||||
*/
|
||||
public fun Euclidean3DSpace.rotate(vector: DoubleVector3D, q: Quaternion): DoubleVector3D = with(QuaternionField) {
|
||||
public fun Float64Space3D.rotate(vector: DoubleVector3D, q: Quaternion): DoubleVector3D = with(QuaternionAlgebra) {
|
||||
val p = vector.toQuaternion()
|
||||
(q * p * q.reciprocal).vector
|
||||
}
|
||||
@ -61,10 +62,10 @@ public fun Euclidean3DSpace.rotate(vector: DoubleVector3D, q: Quaternion): Doubl
|
||||
* Use a composition of quaternions to create a rotation
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun Euclidean3DSpace.rotate(vector: DoubleVector3D, composition: QuaternionField.() -> Quaternion): DoubleVector3D =
|
||||
rotate(vector, QuaternionField.composition())
|
||||
public fun Float64Space3D.rotate(vector: DoubleVector3D, composition: QuaternionAlgebra.() -> Quaternion): DoubleVector3D =
|
||||
rotate(vector, QuaternionAlgebra.composition())
|
||||
|
||||
public fun Euclidean3DSpace.rotate(vector: DoubleVector3D, matrix: Matrix<Double>): DoubleVector3D {
|
||||
public fun Float64Space3D.rotate(vector: DoubleVector3D, matrix: Matrix<Double>): DoubleVector3D {
|
||||
require(matrix.colNum == 3 && matrix.rowNum == 3) { "Square 3x3 rotation matrix is required" }
|
||||
return with(Float64Field.linearSpace) { matrix.dot(vector).asVector3D() }
|
||||
}
|
||||
@ -76,7 +77,7 @@ public fun Euclidean3DSpace.rotate(vector: DoubleVector3D, matrix: Matrix<Double
|
||||
public fun Quaternion.toRotationMatrix(
|
||||
linearSpace: LinearSpace<Double, *> = Float64Field.linearSpace,
|
||||
): Matrix<Double> {
|
||||
val s = QuaternionField.norm(this).pow(-2)
|
||||
val s = QuaternionAlgebra.norm(this).pow(-2)
|
||||
return linearSpace.matrix(3, 3)(
|
||||
1.0 - 2 * s * (y * y + z * z), 2 * s * (x * y - z * w), 2 * s * (x * z + y * w),
|
||||
2 * s * (x * y + z * w), 1.0 - 2 * s * (x * x + z * z), 2 * s * (y * z - x * w),
|
@ -6,6 +6,10 @@
|
||||
package space.kscience.kmath.geometry
|
||||
|
||||
import space.kscience.kmath.geometry.GeometrySpace.Companion.DEFAULT_PRECISION
|
||||
import space.kscience.kmath.geometry.euclidean2d.Float64Space2D
|
||||
import space.kscience.kmath.geometry.euclidean2d.Float64Vector2D
|
||||
import space.kscience.kmath.geometry.euclidean3d.Float64Space3D
|
||||
import space.kscience.kmath.geometry.euclidean3d.Float64Vector3D
|
||||
|
||||
/**
|
||||
* Float equality within given [precision]
|
||||
@ -36,7 +40,7 @@ public fun <V : Vector> V.equalsVector(
|
||||
public fun Float64Vector2D.equalsVector(
|
||||
other: Float64Vector2D,
|
||||
precision: Double = DEFAULT_PRECISION,
|
||||
): Boolean = equalsVector(Euclidean2DSpace, other, precision)
|
||||
): Boolean = equalsVector(Float64Space2D, other, precision)
|
||||
|
||||
/**
|
||||
* Vector equality using Euclidian L2 norm and given [precision]
|
||||
@ -44,7 +48,7 @@ public fun Float64Vector2D.equalsVector(
|
||||
public fun Float64Vector3D.equalsVector(
|
||||
other: Float64Vector3D,
|
||||
precision: Double = DEFAULT_PRECISION,
|
||||
): Boolean = equalsVector(Euclidean3DSpace, other, precision)
|
||||
): Boolean = equalsVector(Float64Space3D, other, precision)
|
||||
|
||||
/**
|
||||
* Line equality using [GeometrySpace.norm] provided by the [space] and given [precision]
|
||||
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2018-2023 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.geometry
|
||||
|
||||
import space.kscience.kmath.complex.Quaternion
|
||||
import space.kscience.kmath.complex.QuaternionAlgebra
|
||||
import space.kscience.kmath.complex.conjugate
|
||||
import space.kscience.kmath.complex.normalized
|
||||
import space.kscience.kmath.geometry.euclidean3d.Float32Space3D
|
||||
import space.kscience.kmath.geometry.euclidean3d.Float32Vector3D
|
||||
import space.kscience.kmath.geometry.euclidean3d.theta
|
||||
import kotlin.math.asin
|
||||
import kotlin.math.atan2
|
||||
import kotlin.math.pow
|
||||
|
||||
public operator fun Quaternion.times(other: Quaternion): Quaternion = QuaternionAlgebra.multiply(this, other)
|
||||
|
||||
public operator fun Quaternion.div(other: Quaternion): Quaternion = QuaternionAlgebra.divide(this, other)
|
||||
|
||||
public fun Quaternion.power(number: Number): Quaternion = QuaternionAlgebra.power(this, number)
|
||||
|
||||
/**
|
||||
* Linear interpolation between [from] and [to] in spherical space
|
||||
*/
|
||||
public fun QuaternionAlgebra.slerp(from: Quaternion, to: Quaternion, fraction: Double): Quaternion =
|
||||
(to / from).pow(fraction) * from
|
||||
|
||||
public fun QuaternionAlgebra.angleBetween(q1: Quaternion, q2: Quaternion): Angle = (q1.conjugate * q2).theta
|
||||
|
||||
public val Quaternion.inclination: Radians get() = asin(2 * (w * y - x * z)).radians
|
||||
|
||||
public val Quaternion.azimuth: Angle get() = atan2(2 * (w * z + x * y), 1 - 2 * (y.pow(2) + z.pow(2))).radians.normalized()
|
||||
|
||||
public infix fun Quaternion.dot(other: Quaternion): Double = w * other.w + x * other.x + y * other.y + z * other.z
|
||||
|
||||
|
||||
private fun Quaternion.normalizedToEuler(): Float32Vector3D {
|
||||
val roll = atan2(2 * y * w + 2 * x * z, 1 - 2 * y * y - 2 * z * z);
|
||||
val pitch = atan2(2 * x * w - 2 * y * z, 1 - 2 * x * x - 2 * z * z);
|
||||
val yaw = asin(2 * x * y + 2 * z * w);
|
||||
|
||||
return Float32Vector3D(roll, pitch, yaw)
|
||||
}
|
||||
|
||||
/**
|
||||
* Quaternion to XYZ Cardan angles
|
||||
*/
|
||||
public fun Quaternion.toEuler(): Float32Vector3D = if (QuaternionAlgebra.norm(this) == 0.0) {
|
||||
Float32Space3D.zero
|
||||
} else {
|
||||
normalized().normalizedToEuler()
|
||||
}
|
@ -5,6 +5,7 @@
|
||||
|
||||
package space.kscience.kmath.geometry
|
||||
|
||||
import space.kscience.kmath.geometry.euclidean2d.Float64Space2D
|
||||
import kotlin.math.sqrt
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
@ -12,12 +13,12 @@ import kotlin.test.assertEquals
|
||||
internal class Euclidean2DSpaceTest {
|
||||
@Test
|
||||
fun zero() {
|
||||
assertVectorEquals(Euclidean2DSpace.vector(0.0, 0.0), Euclidean2DSpace.zero)
|
||||
assertVectorEquals(Float64Space2D.vector(0.0, 0.0), Float64Space2D.zero)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun norm() {
|
||||
with(Euclidean2DSpace) {
|
||||
with(Float64Space2D) {
|
||||
assertEquals(0.0, norm(zero))
|
||||
assertEquals(1.0, norm(vector(1.0, 0.0)))
|
||||
assertEquals(sqrt(2.0), norm(vector(1.0, 1.0)))
|
||||
@ -27,7 +28,7 @@ internal class Euclidean2DSpaceTest {
|
||||
|
||||
@Test
|
||||
fun dotProduct() {
|
||||
with(Euclidean2DSpace) {
|
||||
with(Float64Space2D) {
|
||||
assertEquals(0.0, zero dot zero)
|
||||
assertEquals(0.0, zero dot vector(1.0, 0.0))
|
||||
assertEquals(0.0, vector(-2.0, 0.001) dot zero)
|
||||
@ -44,7 +45,7 @@ internal class Euclidean2DSpaceTest {
|
||||
|
||||
@Test
|
||||
fun add() {
|
||||
with(Euclidean2DSpace) {
|
||||
with(Float64Space2D) {
|
||||
assertVectorEquals(
|
||||
vector(-2.0, 0.001),
|
||||
vector(-2.0, 0.001) + zero
|
||||
@ -58,7 +59,7 @@ internal class Euclidean2DSpaceTest {
|
||||
|
||||
@Test
|
||||
fun multiply() {
|
||||
with(Euclidean2DSpace) {
|
||||
with(Float64Space2D) {
|
||||
assertVectorEquals(vector(-4.0, 0.0), vector(-2.0, 0.0) * 2)
|
||||
assertVectorEquals(vector(4.0, 0.0), vector(-2.0, 0.0) * -2)
|
||||
assertVectorEquals(vector(300.0, 0.0003), vector(100.0, 0.0001) * 3)
|
||||
|
@ -5,18 +5,19 @@
|
||||
|
||||
package space.kscience.kmath.geometry
|
||||
|
||||
import space.kscience.kmath.geometry.euclidean3d.Float64Space3D
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class Euclidean3DSpaceTest {
|
||||
@Test
|
||||
fun zero() {
|
||||
assertVectorEquals(Euclidean3DSpace.vector(0.0, 0.0, 0.0), Euclidean3DSpace.zero)
|
||||
assertVectorEquals(Float64Space3D.vector(0.0, 0.0, 0.0), Float64Space3D.zero)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun distance() {
|
||||
with(Euclidean3DSpace) {
|
||||
with(Float64Space3D) {
|
||||
assertEquals(0.0, zero.distanceTo(zero))
|
||||
assertEquals(1.0, zero.distanceTo(vector(1.0, 0.0, 0.0)))
|
||||
assertEquals(kotlin.math.sqrt(5.000001), vector(1.0, -2.0, 0.001).distanceTo(zero))
|
||||
@ -31,7 +32,7 @@ internal class Euclidean3DSpaceTest {
|
||||
|
||||
@Test
|
||||
fun norm() {
|
||||
with(Euclidean3DSpace) {
|
||||
with(Float64Space3D) {
|
||||
assertEquals(0.0, zero.norm())
|
||||
assertEquals(1.0, vector(1.0, 0.0, 0.0).norm())
|
||||
assertEquals(kotlin.math.sqrt(3.0), vector(1.0, 1.0, 1.0).norm())
|
||||
@ -41,7 +42,7 @@ internal class Euclidean3DSpaceTest {
|
||||
|
||||
@Test
|
||||
fun dotProduct() {
|
||||
with(Euclidean3DSpace) {
|
||||
with(Float64Space3D) {
|
||||
assertEquals(0.0, zero dot zero)
|
||||
assertEquals(0.0, zero dot vector(1.0, 0.0, 0.0))
|
||||
assertEquals(0.0, vector(1.0, -2.0, 0.001) dot zero)
|
||||
@ -57,7 +58,7 @@ internal class Euclidean3DSpaceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun add() = with(Euclidean3DSpace) {
|
||||
fun add() = with(Float64Space3D) {
|
||||
assertVectorEquals(
|
||||
vector(1.0, -2.0, 0.001),
|
||||
vector(1.0, -2.0, 0.001) + zero
|
||||
@ -69,19 +70,19 @@ internal class Euclidean3DSpaceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun multiply() = with(Euclidean3DSpace) {
|
||||
fun multiply() = with(Float64Space3D) {
|
||||
assertVectorEquals(vector(2.0, -4.0, 0.0), vector(1.0, -2.0, 0.0) * 2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun vectorProduct() = with(Euclidean3DSpace) {
|
||||
fun vectorProduct() = with(Float64Space3D) {
|
||||
assertVectorEquals(zAxis, vectorProduct(xAxis, yAxis))
|
||||
assertVectorEquals(zAxis, xAxis cross yAxis)
|
||||
assertVectorEquals(-zAxis, vectorProduct(yAxis, xAxis))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun doubleVectorProduct() = with(Euclidean3DSpace) {
|
||||
fun doubleVectorProduct() = with(Float64Space3D) {
|
||||
val a = vector(1, 2, -3)
|
||||
val b = vector(-1, 0, 1)
|
||||
val c = vector(4, 5, 6)
|
||||
|
@ -5,13 +5,15 @@
|
||||
|
||||
package space.kscience.kmath.geometry
|
||||
|
||||
import space.kscience.kmath.geometry.euclidean2d.Float64Space2D
|
||||
import space.kscience.kmath.geometry.euclidean3d.Float64Space3D
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
internal class ProjectionAlongTest {
|
||||
@Test
|
||||
fun projectionIntoYEqualsX() {
|
||||
with(Euclidean2DSpace) {
|
||||
with(Float64Space2D) {
|
||||
val normal = vector(-2.0, 2.0)
|
||||
val base = vector(2.3, 2.3)
|
||||
|
||||
@ -26,7 +28,7 @@ internal class ProjectionAlongTest {
|
||||
|
||||
@Test
|
||||
fun projectionOntoLine() {
|
||||
with(Euclidean2DSpace) {
|
||||
with(Float64Space2D) {
|
||||
val a = 5.0
|
||||
val b = -3.0
|
||||
val c = -15.0
|
||||
@ -42,11 +44,11 @@ internal class ProjectionAlongTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun projectOntoPlane() = with(Euclidean3DSpace){
|
||||
fun projectOntoPlane() = with(Float64Space3D){
|
||||
val normal = vector(1.0, 3.5, 0.07)
|
||||
val base = vector(2.0, -0.0037, 11.1111)
|
||||
|
||||
with(Euclidean3DSpace) {
|
||||
with(Float64Space3D) {
|
||||
val testDomain = (-10.0..10.0).generateList(0.43)
|
||||
for (x in testDomain) {
|
||||
for (y in testDomain) {
|
||||
|
@ -5,13 +5,15 @@
|
||||
|
||||
package space.kscience.kmath.geometry
|
||||
|
||||
import space.kscience.kmath.geometry.euclidean2d.Float64Space2D
|
||||
import space.kscience.kmath.geometry.euclidean3d.Float64Space3D
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
internal class ProjectionOntoLineTest {
|
||||
@Test
|
||||
fun projectionIntoOx() {
|
||||
with(Euclidean2DSpace) {
|
||||
with(Float64Space2D) {
|
||||
val ox = Line(zero, vector(1.0, 0.0))
|
||||
|
||||
grid(-10.0..10.0, -10.0..10.0, 0.15).forEach { (x, y) ->
|
||||
@ -22,7 +24,7 @@ internal class ProjectionOntoLineTest {
|
||||
|
||||
@Test
|
||||
fun projectionIntoOy() {
|
||||
with(Euclidean2DSpace) {
|
||||
with(Float64Space2D) {
|
||||
val line = Line(zero, vector(0.0, 1.0))
|
||||
|
||||
grid(-10.0..10.0, -10.0..10.0, 0.15).forEach { (x, y) ->
|
||||
@ -33,7 +35,7 @@ internal class ProjectionOntoLineTest {
|
||||
|
||||
@Test
|
||||
fun projectionIntoYEqualsX() {
|
||||
with(Euclidean2DSpace) {
|
||||
with(Float64Space2D) {
|
||||
val line = Line(zero, vector(1.0, 1.0))
|
||||
|
||||
assertVectorEquals(zero, projectToLine(zero, line))
|
||||
@ -47,7 +49,7 @@ internal class ProjectionOntoLineTest {
|
||||
|
||||
@Test
|
||||
fun projectionOntoLine2d() {
|
||||
with(Euclidean2DSpace) {
|
||||
with(Float64Space2D) {
|
||||
val a = 5.0
|
||||
val b = -3.0
|
||||
val c = -15.0
|
||||
@ -62,7 +64,7 @@ internal class ProjectionOntoLineTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun projectionOntoLine3d() = with(Euclidean3DSpace) {
|
||||
fun projectionOntoLine3d() = with(Float64Space3D) {
|
||||
val line = Line(
|
||||
base = vector(1.0, 3.5, 0.07),
|
||||
direction = vector(2.0, -0.0037, 11.1111)
|
||||
|
@ -7,6 +7,7 @@ package space.kscience.kmath.geometry
|
||||
|
||||
import space.kscience.kmath.complex.Quaternion
|
||||
import space.kscience.kmath.complex.normalized
|
||||
import space.kscience.kmath.geometry.euclidean3d.*
|
||||
import space.kscience.kmath.structures.Float64Buffer
|
||||
import space.kscience.kmath.testutils.assertBufferEquals
|
||||
import kotlin.test.Test
|
||||
@ -14,7 +15,7 @@ import kotlin.test.Test
|
||||
class RotationTest {
|
||||
|
||||
@Test
|
||||
fun differentRotations() = with(Euclidean3DSpace) {
|
||||
fun differentRotations() = with(Float64Space3D) {
|
||||
val vector = vector(1.0, 1.0, 1.0)
|
||||
val q = Quaternion(1.0, 2.0, -3.0, 4.0).normalized()
|
||||
val rotatedByQ = rotate(vector, q)
|
||||
@ -36,7 +37,7 @@ class RotationTest {
|
||||
|
||||
@Test
|
||||
fun fromRotation() {
|
||||
val q = Quaternion.fromRotation(0.3.radians, Euclidean3DSpace.vector(1.0, 1.0, 1.0))
|
||||
val q = Quaternion.fromRotation(0.3.radians, Float64Space3D.vector(1.0, 1.0, 1.0))
|
||||
|
||||
assertBufferEquals(Float64Buffer(0.9887711, 0.0862781, 0.0862781, 0.0862781), q)
|
||||
}
|
||||
|
@ -6,12 +6,13 @@
|
||||
package space.kscience.kmath.geometry
|
||||
|
||||
|
||||
import space.kscience.kmath.geometry.euclidean2d.Float64Space2D
|
||||
import space.kscience.kmath.operations.toList
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class Vector2DTest {
|
||||
private val vector = Euclidean2DSpace.vector(1.0, -7.999)
|
||||
private val vector = Float64Space2D.vector(1.0, -7.999)
|
||||
|
||||
@Test
|
||||
fun size() {
|
||||
|
@ -5,12 +5,13 @@
|
||||
|
||||
package space.kscience.kmath.geometry
|
||||
|
||||
import space.kscience.kmath.geometry.euclidean3d.Float64Space3D
|
||||
import space.kscience.kmath.operations.toList
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class Vector3DTest {
|
||||
private val vector = Euclidean3DSpace.vector(1.0, -7.999, 0.001)
|
||||
private val vector = Float64Space3D.vector(1.0, -7.999, 0.001)
|
||||
|
||||
@Test
|
||||
fun size() {
|
||||
|
@ -5,6 +5,8 @@
|
||||
|
||||
package space.kscience.kmath.geometry
|
||||
|
||||
import space.kscience.kmath.geometry.euclidean2d.DoubleVector2D
|
||||
import space.kscience.kmath.geometry.euclidean3d.DoubleVector3D
|
||||
import kotlin.math.abs
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
|
@ -16,6 +16,7 @@ import space.kscience.kmath.expressions.Symbol
|
||||
import space.kscience.kmath.nd.ColumnStrides
|
||||
import space.kscience.kmath.nd.ShapeND
|
||||
import space.kscience.kmath.nd.StructureND
|
||||
import space.kscience.kmath.operations.FieldOps
|
||||
import space.kscience.kmath.operations.Float64Field
|
||||
import space.kscience.kmath.operations.PowerOperations
|
||||
|
||||
@ -32,7 +33,8 @@ internal fun ShapeND.toLongArray(): LongArray = LongArray(size) { get(it).toLong
|
||||
|
||||
public class DoubleTensorFlowAlgebra internal constructor(
|
||||
graph: Graph,
|
||||
) : TensorFlowAlgebra<Double, TFloat64, Float64Field>(graph), PowerOperations<StructureND<Double>> {
|
||||
) : TensorFlowAlgebra<Double, TFloat64,
|
||||
Float64Field>(graph), FieldOps<StructureND<Double>>, PowerOperations<StructureND<Double>> {
|
||||
|
||||
override val elementAlgebra: Float64Field get() = Float64Field
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user