diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt index df25dcbea..d37ed45c0 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt @@ -18,45 +18,5 @@ public data class Circle2D( public val radius: Double ) -public enum class DubinsRoutes { - RSR, RSL, LSR, LSL -} - -public fun Circle2D.tangentsToCircle(other: Circle2D): Map> { - val R1 = this.radius - val R2 = other.radius - val line = LineSegment(this.center, other.center) - val d = line.begin.distanceTo(line.end) - val angle1 = atan2(other.center.x - this.center.x, other.center.y - this.center.y) - var r: Double - var angle2: Double - val routes = mapOf( - DubinsRoutes.RSR to Pair(R1, R2), - DubinsRoutes.RSL to Pair(R1, -R2), - DubinsRoutes.LSR to Pair(-R1, R2), - DubinsRoutes.LSL to Pair(-R1, -R2)) - val segments = mutableMapOf>() - for ((route, r1r2) in routes) { - val r1 = r1r2.first - val r2 = r1r2.second - r = if (r1.sign == r2.sign) { - r1.absoluteValue - r2.absoluteValue - } else { - r1.absoluteValue + r2.absoluteValue - } - val L = (d * d - r * r).pow(0.5) - angle2 = if (r1.absoluteValue > r2.absoluteValue) { - angle1 + r1.sign * atan2(r.absoluteValue, L) - } else { - angle1 - r2.sign * atan2(r.absoluteValue, L) - } - val W = Euclidean2DSpace.vector(-cos(angle2), sin(angle2)) - segments[route] = LineSegment( - Euclidean2DSpace.add(this.center, Euclidean2DSpace.scale(W, r1)), - Euclidean2DSpace.add(other.center, Euclidean2DSpace.scale(W, r2)) - ) - } - return segments -} public val Circle2D.circumference: Double get() = radius * 2 * PI diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/TangentTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/TangentTest.kt index 214495dfe..4ffd4dcab 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/TangentTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/TangentTest.kt @@ -3,43 +3,43 @@ * 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.geometry.Euclidean2DSpace.equalLineSegments -import space.kscience.kmath.geometry.Euclidean2DSpace.vector -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -class TangentTest { - @Test - fun tangent() { - val c1 = Circle2D(vector(0.0, 0.0), 1.0) - val c2 = Circle2D(vector(4.0, 0.0), 1.0) - val routes = arrayListOf( - DubinsRoutes.RSR, - DubinsRoutes.RSL, - DubinsRoutes.LSR, - DubinsRoutes.LSL - ) - val segments = arrayListOf>( - LineSegment(begin = vector(0.0, 1.0), - end = vector(4.0, 1.0)), - LineSegment(begin = vector(0.5, 0.8660254), - end = vector(3.5, -0.8660254)), - LineSegment(begin = vector(0.5, -0.8660254), - end = vector(3.5, 0.8660254)), - LineSegment(begin = vector(0.0, -1.0), - end = vector(4.0, -1.0)) - ) - - val tangentMap = c1.tangentsToCircle(c2) - val tangentMapKeys = tangentMap.keys.toList() - val tangentMapValues = tangentMap.values.toList() - - assertEquals(routes, tangentMapKeys) - for (i in segments.indices) { - assertTrue(equalLineSegments(segments[i], tangentMapValues[i])) - } - } -} \ No newline at end of file +//package space.kscience.kmath.geometry +// +//import space.kscience.kmath.geometry.Euclidean2DSpace.equalLineSegments +//import space.kscience.kmath.geometry.Euclidean2DSpace.vector +//import kotlin.test.Test +//import kotlin.test.assertEquals +//import kotlin.test.assertTrue +// +//class TangentTest { +// @Test +// fun tangent() { +// val c1 = Circle2D(vector(0.0, 0.0), 1.0) +// val c2 = Circle2D(vector(4.0, 0.0), 1.0) +// val routes = arrayListOf( +// DubinsRoutes.RSR, +// DubinsRoutes.RSL, +// DubinsRoutes.LSR, +// DubinsRoutes.LSL +// ) +// val segments = arrayListOf>( +// LineSegment(begin = vector(0.0, 1.0), +// end = vector(4.0, 1.0)), +// LineSegment(begin = vector(0.5, 0.8660254), +// end = vector(3.5, -0.8660254)), +// LineSegment(begin = vector(0.5, -0.8660254), +// end = vector(3.5, 0.8660254)), +// LineSegment(begin = vector(0.0, -1.0), +// end = vector(4.0, -1.0)) +// ) +// +// val tangentMap = c1.tangentsToCircle(c2) +// val tangentMapKeys = tangentMap.keys.toList() +// val tangentMapValues = tangentMap.values.toList() +// +// assertEquals(routes, tangentMapKeys) +// for (i in segments.indices) { +// assertTrue(equalLineSegments(segments[i], tangentMapValues[i])) +// } +// } +//} \ No newline at end of file diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Tangent.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Tangent.kt new file mode 100644 index 000000000..9546a8d64 --- /dev/null +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Tangent.kt @@ -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.trajectory + +import space.kscience.kmath.geometry.Circle2D +import space.kscience.kmath.geometry.DoubleVector2D +import space.kscience.kmath.geometry.Euclidean2DSpace +import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo +import space.kscience.kmath.geometry.LineSegment +import kotlin.math.* + +public enum class DubinsRoutes { + RSR, RSL, LSR, LSL +} + +public fun Circle2D.tangentsToCircle(other: Circle2D): Map> { + val R1 = this.radius + val R2 = other.radius + val line = LineSegment(this.center, other.center) + val d = line.begin.distanceTo(line.end) + val angle1 = atan2(other.center.x - this.center.x, other.center.y - this.center.y) + var r: Double + var angle2: Double + val routes = mapOf( + DubinsRoutes.RSR to Pair(R1, R2), + DubinsRoutes.RSL to Pair(R1, -R2), + DubinsRoutes.LSR to Pair(-R1, R2), + DubinsRoutes.LSL to Pair(-R1, -R2) + ) + val segments = mutableMapOf>() + for ((route, r1r2) in routes) { + val r1 = r1r2.first + val r2 = r1r2.second + r = if (r1.sign == r2.sign) { + r1.absoluteValue - r2.absoluteValue + } else { + r1.absoluteValue + r2.absoluteValue + } + val L = (d * d - r * r).pow(0.5) + angle2 = if (r1.absoluteValue > r2.absoluteValue) { + angle1 + r1.sign * atan2(r.absoluteValue, L) + } else { + angle1 - r2.sign * atan2(r.absoluteValue, L) + } + val W = Euclidean2DSpace.vector(-cos(angle2), sin(angle2)) + segments[route] = LineSegment( + Euclidean2DSpace.add(this.center, Euclidean2DSpace.scale(W, r1)), + Euclidean2DSpace.add(other.center, Euclidean2DSpace.scale(W, r2)) + ) + } + return segments +} \ No newline at end of file diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/TangentTest.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/TangentTest.kt new file mode 100644 index 000000000..cfa2fa52b --- /dev/null +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/TangentTest.kt @@ -0,0 +1,48 @@ +/* + * 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.trajectory + +import space.kscience.kmath.geometry.Circle2D +import space.kscience.kmath.geometry.DoubleVector2D +import space.kscience.kmath.geometry.Euclidean2DSpace.equalLineSegments +import space.kscience.kmath.geometry.Euclidean2DSpace.vector +import space.kscience.kmath.geometry.LineSegment +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class TangentTest { + @Test + fun tangent() { + val c1 = Circle2D(vector(0.0, 0.0), 1.0) + val c2 = Circle2D(vector(4.0, 0.0), 1.0) + val routes = arrayListOf( + DubinsRoutes.RSR, + DubinsRoutes.RSL, + DubinsRoutes.LSR, + DubinsRoutes.LSL + ) + val segments = arrayListOf>( + LineSegment(begin = vector(0.0, 1.0), + end = vector(4.0, 1.0)), + LineSegment(begin = vector(0.5, 0.8660254), + end = vector(3.5, -0.8660254)), + LineSegment(begin = vector(0.5, -0.8660254), + end = vector(3.5, 0.8660254)), + LineSegment(begin = vector(0.0, -1.0), + end = vector(4.0, -1.0)) + ) + + val tangentMap = c1.tangentsToCircle(c2) + val tangentMapKeys = tangentMap.keys.toList() + val tangentMapValues = tangentMap.values.toList() + + assertEquals(routes, tangentMapKeys) + for (i in segments.indices) { + assertTrue(equalLineSegments(segments[i], tangentMapValues[i])) + } + } +} \ No newline at end of file