forked from kscience/visionforge
Use KMath-geometry for solids
This commit is contained in:
parent
a872f10523
commit
38302eac4c
@ -32,12 +32,12 @@ private fun Solid.rotate(rot: DoubleArray) {
|
||||
val xAngle = atan2(-rot[5], rot[8])
|
||||
val yAngle = atan2(rot[2], sqrt(1.0 - rot[2].pow(2)))
|
||||
val zAngle = atan2(-rot[1], rot[0])
|
||||
rotation = Point3D(xAngle, yAngle, zAngle)
|
||||
rotation = Float32Vector3D(xAngle, yAngle, zAngle)
|
||||
}
|
||||
|
||||
private fun Solid.translate(trans: DoubleArray) {
|
||||
val (x, y, z) = trans
|
||||
position = Point3D(x, y, z)
|
||||
position = Float32Vector3D(x, y, z)
|
||||
}
|
||||
|
||||
private fun Solid.useMatrix(matrix: DGeoMatrix?) {
|
||||
@ -72,7 +72,7 @@ private fun Solid.useMatrix(matrix: DGeoMatrix?) {
|
||||
val fScale by matrix.meta.doubleArray()
|
||||
translate(fTranslation)
|
||||
rotate(fRotationMatrix)
|
||||
scale = Point3D(fScale[0], fScale[1], fScale[2])
|
||||
scale = Float32Vector3D(fScale[0], fScale[1], fScale[2])
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -248,14 +248,14 @@ private fun SolidGroup.addShape(
|
||||
|
||||
val fDz by shape.meta.double(0.0)
|
||||
//TODO check proper node order
|
||||
val node1 = Point3D(-fBl1, -fH1, -fDz)
|
||||
val node2 = Point3D(fBl1, -fH1, -fDz)
|
||||
val node3 = Point3D(fTl1, fH1, -fDz)
|
||||
val node4 = Point3D(-fTl1, fH1, -fDz)
|
||||
val node5 = Point3D(-fBl2, -fH2, fDz)
|
||||
val node6 = Point3D(fBl2, -fH2, fDz)
|
||||
val node7 = Point3D(fTl2, fH2, fDz)
|
||||
val node8 = Point3D(-fTl2, fH2, fDz)
|
||||
val node1 = Float32Vector3D(-fBl1, -fH1, -fDz)
|
||||
val node2 = Float32Vector3D(fBl1, -fH1, -fDz)
|
||||
val node3 = Float32Vector3D(fTl1, fH1, -fDz)
|
||||
val node4 = Float32Vector3D(-fTl1, fH1, -fDz)
|
||||
val node5 = Float32Vector3D(-fBl2, -fH2, fDz)
|
||||
val node6 = Float32Vector3D(fBl2, -fH2, fDz)
|
||||
val node7 = Float32Vector3D(fTl2, fH2, fDz)
|
||||
val node8 = Float32Vector3D(-fTl2, fH2, fDz)
|
||||
hexagon(node1, node2, node3, node4, node5, node6, node7, node8, name)
|
||||
}
|
||||
|
||||
@ -264,7 +264,7 @@ private fun SolidGroup.addShape(
|
||||
val fScale by shape.dObject(::DGeoScale)
|
||||
fShape?.let { scaledShape ->
|
||||
solidGroup(name?.let { Name.parse(it) }) {
|
||||
scale = Point3D(fScale?.x ?: 1.0, fScale?.y ?: 1.0, fScale?.z ?: 1.0)
|
||||
scale = Float32Vector3D(fScale?.x ?: 1.0, fScale?.y ?: 1.0, fScale?.z ?: 1.0)
|
||||
addShape(scaledShape, context)
|
||||
apply(block)
|
||||
}
|
||||
|
@ -25,12 +25,12 @@ private fun Solid.rotate(rot: DoubleArray) {
|
||||
val xAngle = atan2(-rot[5], rot[8])
|
||||
val yAngle = atan2(rot[2], sqrt(1.0 - rot[2].pow(2)))
|
||||
val zAngle = atan2(-rot[1], rot[0])
|
||||
rotation = Point3D(xAngle, yAngle, zAngle)
|
||||
rotation = Float32Vector3D(xAngle, yAngle, zAngle)
|
||||
}
|
||||
|
||||
private fun Solid.translate(trans: DoubleArray) {
|
||||
val (x, y, z) = trans
|
||||
position = Point3D(x, y, z)
|
||||
position = Float32Vector3D(x, y, z)
|
||||
}
|
||||
|
||||
private fun Solid.useMatrix(matrix: TGeoMatrix?) {
|
||||
@ -52,7 +52,7 @@ private fun Solid.useMatrix(matrix: TGeoMatrix?) {
|
||||
translate(matrix.fTranslation)
|
||||
rotate(matrix.fRotationMatrix)
|
||||
val (xScale, yScale, zScale) = matrix.fScale
|
||||
scale = Point3D(xScale, yScale, zScale)
|
||||
scale = Float32Vector3D(xScale, yScale, zScale)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ kscience{
|
||||
}
|
||||
|
||||
kotlin{
|
||||
explicitApi = null
|
||||
js(IR){
|
||||
useCommonJs()
|
||||
browser {
|
||||
|
@ -40,6 +40,8 @@ kscience {
|
||||
}
|
||||
}
|
||||
|
||||
kotlin.explicitApi = null
|
||||
|
||||
application {
|
||||
mainClass.set("ru.mipt.npm.muon.monitor.server.MMServerKt")
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
package ru.mipt.npm.muon.monitor
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import space.kscience.visionforge.solid.Point3D
|
||||
import space.kscience.visionforge.solid.Float32Vector3D
|
||||
|
||||
typealias Track = List<Point3D>
|
||||
typealias Track = List<Float32Vector3D>
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -16,7 +16,7 @@ class Model(val manager: VisionManager) {
|
||||
|
||||
private fun MutableVisionContainer<Solid>.pixel(pixel: SC1) {
|
||||
val group = solidGroup(pixel.name) {
|
||||
position = Point3D(pixel.center.x, pixel.center.y, pixel.center.z)
|
||||
position = Float32Vector3D(pixel.center.x, pixel.center.y, pixel.center.z)
|
||||
box(pixel.xSize, pixel.ySize, pixel.zSize)
|
||||
label(pixel.name) {
|
||||
z = -Monitor.PIXEL_Z_SIZE / 2 - 5
|
||||
|
@ -2,21 +2,21 @@ package ru.mipt.npm.muon.monitor
|
||||
|
||||
import ru.mipt.npm.muon.monitor.Monitor.PIXEL_XY_SIZE
|
||||
import ru.mipt.npm.muon.monitor.Monitor.PIXEL_Z_SIZE
|
||||
import space.kscience.visionforge.solid.Point3D
|
||||
import space.kscience.visionforge.solid.plus
|
||||
import space.kscience.visionforge.solid.Float32Euclidean3DSpace
|
||||
import space.kscience.visionforge.solid.Float32Vector3D
|
||||
|
||||
/**
|
||||
* A single pixel
|
||||
*/
|
||||
class SC1(
|
||||
val name: String,
|
||||
val center: Point3D,
|
||||
val center: Float32Vector3D,
|
||||
val xSize: Float = PIXEL_XY_SIZE, val ySize: Float = PIXEL_XY_SIZE, val zSize: Float = PIXEL_Z_SIZE,
|
||||
)
|
||||
|
||||
class SC16(
|
||||
val name: String,
|
||||
val center: Point3D,
|
||||
val center: Float32Vector3D,
|
||||
) {
|
||||
|
||||
/**
|
||||
@ -109,9 +109,9 @@ class SC16(
|
||||
|
||||
else -> throw Error()
|
||||
}
|
||||
val offset = Point3D(-y, x, 0)//rotateDetector(Point3D(x, y, 0.0));
|
||||
val offset = Float32Vector3D(-y, x, 0)//rotateDetector(Point3D(x, y, 0.0));
|
||||
val pixelName = "${name}_${index}"
|
||||
SC1(pixelName, offset + center)
|
||||
SC1(pixelName, with(Float32Euclidean3DSpace) { offset + center })
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -154,7 +154,7 @@ object Monitor {
|
||||
val x = split[4].toDouble() - 500
|
||||
val y = split[5].toDouble() - 500
|
||||
val z = 180 - split[6].toDouble()
|
||||
SC16(detectorName, Point3D(x, y, z))
|
||||
SC16(detectorName, Float32Vector3D(x, y, z))
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
@ -10,8 +10,7 @@ import io.ktor.server.application.install
|
||||
import io.ktor.server.application.log
|
||||
import io.ktor.server.cio.CIO
|
||||
import io.ktor.server.engine.embeddedServer
|
||||
import io.ktor.server.http.content.resources
|
||||
import io.ktor.server.http.content.static
|
||||
import io.ktor.server.http.content.staticResources
|
||||
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
|
||||
import io.ktor.server.response.respond
|
||||
import io.ktor.server.response.respondText
|
||||
@ -53,9 +52,7 @@ fun Application.module(context: Context = Global) {
|
||||
status = HttpStatusCode.OK
|
||||
)
|
||||
}
|
||||
static("/") {
|
||||
resources()
|
||||
}
|
||||
staticResources("/", null)
|
||||
}
|
||||
try {
|
||||
Desktop.getDesktop().browse(URI("http://localhost:8080/index.html"))
|
||||
|
@ -5,7 +5,7 @@ import org.apache.commons.math3.geometry.euclidean.threed.Plane
|
||||
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D
|
||||
import ru.mipt.npm.muon.monitor.Monitor.CENTRAL_LAYER_Z
|
||||
import ru.mipt.npm.muon.monitor.Monitor.GEOMETRY_TOLERANCE
|
||||
import space.kscience.visionforge.solid.Point3D
|
||||
import space.kscience.visionforge.solid.Float32Vector3D
|
||||
|
||||
/**
|
||||
* Created by darksnake on 11-May-16.
|
||||
@ -50,12 +50,12 @@ fun makeTrack(x: Double, y: Double, theta: Double, phi: Double): Line {
|
||||
)
|
||||
}
|
||||
|
||||
fun Vector3D.toPoint() = Point3D(x, y, z)
|
||||
fun Vector3D.toKMathVector() = Float32Vector3D(x, y, z)
|
||||
|
||||
fun Line.toPoints(): List<Point3D> {
|
||||
fun Line.toKMathVectors(): List<Float32Vector3D> {
|
||||
val basePoint = basePlane.intersection(this)
|
||||
val bottom = basePoint.subtract(2000.0, direction)
|
||||
val top = basePoint.add(2000.0, direction)
|
||||
return listOf(bottom.toPoint(), top.toPoint())
|
||||
return listOf(bottom.toKMathVector(), top.toKMathVector())
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,7 @@ fun readEffs(): Map<String, Double> {
|
||||
|
||||
|
||||
fun buildEventByTrack(index: Int, track: Line, hitResolver: (Line) -> Collection<SC1> = defaultHitResolver): Event {
|
||||
return Event(index, track.toPoints(), hitResolver(track).map { it.name })
|
||||
return Event(index, track.toKMathVectors(), hitResolver(track).map { it.name })
|
||||
}
|
||||
|
||||
val defaultHitResolver: (Line) -> Collection<SC1> = { track: Line ->
|
||||
|
@ -19,6 +19,8 @@ kscience {
|
||||
}
|
||||
}
|
||||
|
||||
kotlin.explicitApi = null
|
||||
|
||||
application {
|
||||
mainClass.set("space.kscience.visionforge.solid.demo.FXDemoAppKt")
|
||||
}
|
@ -130,7 +130,10 @@ fun VisionLayout<Solid>.showcase() {
|
||||
color.set(Colors.blue)
|
||||
}
|
||||
repeat(20) {
|
||||
polyline(Point3D(100, 100, 100), Point3D(-100, -100, -100)) {
|
||||
polyline(
|
||||
Float32Vector3D(100, 100, 100),
|
||||
Float32Vector3D(-100, -100, -100)
|
||||
) {
|
||||
thickness = 3.0
|
||||
rotationX = it * PI2 / 20
|
||||
color.set(Colors.green)
|
||||
|
@ -248,14 +248,14 @@ private class GdmlLoader(val settings: GdmlLoaderOptions) {
|
||||
val dyBottom = solid.y1.toDouble() / 2
|
||||
val dyTop = solid.y2.toDouble() / 2
|
||||
val dz = solid.z.toDouble() / 2
|
||||
val node1 = Point3D(-dxBottom, -dyBottom, -dz)
|
||||
val node2 = Point3D(dxBottom, -dyBottom, -dz)
|
||||
val node3 = Point3D(dxBottom, dyBottom, -dz)
|
||||
val node4 = Point3D(-dxBottom, dyBottom, -dz)
|
||||
val node5 = Point3D(-dxTop, -dyTop, dz)
|
||||
val node6 = Point3D(dxTop, -dyTop, dz)
|
||||
val node7 = Point3D(dxTop, dyTop, dz)
|
||||
val node8 = Point3D(-dxTop, dyTop, dz)
|
||||
val node1 = Float32Vector3D(-dxBottom, -dyBottom, -dz)
|
||||
val node2 = Float32Vector3D(dxBottom, -dyBottom, -dz)
|
||||
val node3 = Float32Vector3D(dxBottom, dyBottom, -dz)
|
||||
val node4 = Float32Vector3D(-dxBottom, dyBottom, -dz)
|
||||
val node5 = Float32Vector3D(-dxTop, -dyTop, dz)
|
||||
val node6 = Float32Vector3D(dxTop, -dyTop, dz)
|
||||
val node7 = Float32Vector3D(dxTop, dyTop, dz)
|
||||
val node8 = Float32Vector3D(-dxTop, dyTop, dz)
|
||||
hexagon(node1, node2, node3, node4, node5, node6, node7, node8, name)
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,8 @@ plugins {
|
||||
id("space.kscience.gradle.mpp")
|
||||
}
|
||||
|
||||
val kmathVersion = "0.3.1"
|
||||
|
||||
kscience {
|
||||
jvm()
|
||||
js()
|
||||
@ -11,6 +13,7 @@ kscience {
|
||||
}
|
||||
useCoroutines()
|
||||
dependencies {
|
||||
api("space.kscience:kmath-geometry:0.3.1")
|
||||
api(projects.visionforgeCore)
|
||||
}
|
||||
dependencies(jvmTest) {
|
||||
|
@ -36,8 +36,8 @@ public class ConeSegment(
|
||||
require(segments >= 4) { "The number of segments in cone is too small" }
|
||||
val angleStep = phi / (segments - 1)
|
||||
|
||||
fun shape(r: Float, z: Float): List<Point3D> = (0 until segments).map { i ->
|
||||
Point3D(r * cos(phiStart + angleStep * i), r * sin(phiStart + angleStep * i), z)
|
||||
fun shape(r: Float, z: Float): List<Float32Vector3D> = (0 until segments).map { i ->
|
||||
Float32Vector3D(r * cos(phiStart + angleStep * i), r * sin(phiStart + angleStep * i), z)
|
||||
}
|
||||
|
||||
geometryBuilder.apply {
|
||||
@ -53,8 +53,8 @@ public class ConeSegment(
|
||||
if (phi == PI2) {
|
||||
face4(bottomPoints.last(), bottomPoints[0], topPoints[0], topPoints.last())
|
||||
}
|
||||
val zeroBottom = Point3D(0f, 0f, -height / 2)
|
||||
val zeroTop = Point3D(0f, 0f, +height / 2)
|
||||
val zeroBottom = Float32Vector3D(0f, 0f, -height / 2)
|
||||
val zeroTop = Float32Vector3D(0f, 0f, +height / 2)
|
||||
for (it in 1 until segments) {
|
||||
face(bottomPoints[it - 1], zeroBottom, bottomPoints[it])
|
||||
face(topPoints[it - 1], topPoints[it], zeroTop)
|
||||
|
@ -38,8 +38,8 @@ public class ConeSurface(
|
||||
require(segments >= 4) { "The number of segments in tube is too small" }
|
||||
val angleStep = phi / (segments - 1)
|
||||
|
||||
fun shape(r: Float, z: Float): List<Point3D> = (0 until segments).map { i ->
|
||||
Point3D(r * cos(phiStart + angleStep * i), r * sin(phiStart + angleStep * i), z)
|
||||
fun shape(r: Float, z: Float): List<Float32Vector3D> = (0 until segments).map { i ->
|
||||
Float32Vector3D(r * cos(phiStart + angleStep * i), r * sin(phiStart + angleStep * i), z)
|
||||
}
|
||||
|
||||
geometryBuilder.apply {
|
||||
@ -56,8 +56,8 @@ public class ConeSurface(
|
||||
face4(bottomOuterPoints.last(), bottomOuterPoints[0], topOuterPoints[0], topOuterPoints.last())
|
||||
}
|
||||
if (bottomInnerRadius == 0f) {
|
||||
val zeroBottom = Point3D(0f, 0f, -height / 2)
|
||||
val zeroTop = Point3D(0f, 0f, height / 2)
|
||||
val zeroBottom = Float32Vector3D(0f, 0f, -height / 2)
|
||||
val zeroTop = Float32Vector3D(0f, 0f, height / 2)
|
||||
(1 until segments).forEach {
|
||||
face(bottomOuterPoints[it - 1], zeroBottom, bottomOuterPoints[it])
|
||||
face(topOuterPoints[it - 1], topOuterPoints[it], zeroTop)
|
||||
|
@ -7,7 +7,7 @@ import space.kscience.visionforge.setChild
|
||||
|
||||
@Serializable
|
||||
@SerialName("solid.convex")
|
||||
public class Convex(public val points: List<Point3D>) : SolidBase<Convex>()
|
||||
public class Convex(public val points: List<Float32Vector3D>) : SolidBase<Convex>()
|
||||
|
||||
public inline fun MutableVisionContainer<Solid>.convex(
|
||||
name: String? = null,
|
||||
@ -15,10 +15,10 @@ public inline fun MutableVisionContainer<Solid>.convex(
|
||||
): Convex = ConvexBuilder().apply(action).build().also { setChild(name, it) }
|
||||
|
||||
public class ConvexBuilder {
|
||||
private val points = ArrayList<Point3D>()
|
||||
private val points = ArrayList<Float32Vector3D>()
|
||||
|
||||
public fun point(x: Number, y: Number, z: Number) {
|
||||
points.add(Point3D(x, y, z))
|
||||
points.add(Float32Vector3D(x, y, z))
|
||||
}
|
||||
|
||||
public fun build(): Convex {
|
||||
|
@ -4,19 +4,23 @@ import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import space.kscience.dataforge.meta.MutableMeta
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.visionforge.*
|
||||
import space.kscience.kmath.geometry.component1
|
||||
import space.kscience.kmath.geometry.component2
|
||||
import space.kscience.visionforge.MutableVisionContainer
|
||||
import space.kscience.visionforge.VisionBuilder
|
||||
import space.kscience.visionforge.setChild
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
||||
|
||||
public typealias Shape2D = List<Point2D>
|
||||
public typealias Shape2D = List<Float32Vector2D>
|
||||
|
||||
@Serializable
|
||||
public class Shape2DBuilder(private val points: ArrayList<Point2D> = ArrayList()) {
|
||||
public class Shape2DBuilder(private val points: ArrayList<Float32Vector2D> = ArrayList()) {
|
||||
|
||||
public fun point(x: Number, y: Number) {
|
||||
points.add(Point2D(x, y))
|
||||
points.add(Float32Vector2D(x, y))
|
||||
}
|
||||
|
||||
public infix fun Number.to(y: Number): Unit = point(this, y)
|
||||
@ -38,7 +42,7 @@ public data class Layer(var x: Float, var y: Float, var z: Float, var scale: Flo
|
||||
@Serializable
|
||||
@SerialName("solid.extrude")
|
||||
public class Extruded(
|
||||
public val shape: List<Point2D>,
|
||||
public val shape: List<Float32Vector2D>,
|
||||
public val layers: List<Layer>,
|
||||
) : SolidBase<Extruded>(), GeometrySolid {
|
||||
|
||||
@ -50,18 +54,18 @@ public class Extruded(
|
||||
/**
|
||||
* Expand the shape for specific layers
|
||||
*/
|
||||
val layers: List<List<Point3D>> = layers.map { layer ->
|
||||
val layers: List<List<Float32Vector3D>> = layers.map { layer ->
|
||||
shape.map { (x, y) ->
|
||||
val newX = layer.x + x * layer.scale
|
||||
val newY = layer.y + y * layer.scale
|
||||
Point3D(newX, newY, layer.z)
|
||||
Float32Vector3D(newX, newY, layer.z)
|
||||
}
|
||||
}
|
||||
|
||||
if (layers.size < 2) error("Extruded shape requires more than one layer")
|
||||
|
||||
var lowerLayer = layers.first()
|
||||
var upperLayer: List<Point3D>
|
||||
var upperLayer: List<Float32Vector3D>
|
||||
|
||||
for (i in (1 until layers.size)) {
|
||||
upperLayer = layers[i]
|
||||
@ -94,7 +98,7 @@ public class Extruded(
|
||||
}
|
||||
|
||||
public class ExtrudeBuilder(
|
||||
public var shape: List<Point2D> = emptyList(),
|
||||
public var shape: List<Float32Vector2D> = emptyList(),
|
||||
public var layers: MutableList<Layer> = ArrayList(),
|
||||
public val properties: MutableMeta = MutableMeta(),
|
||||
) {
|
||||
|
@ -0,0 +1,71 @@
|
||||
package space.kscience.visionforge.solid
|
||||
|
||||
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.ScaleOperations
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sqrt
|
||||
|
||||
@Serializable(Float32Euclidean2DSpace.VectorSerializer::class)
|
||||
public interface Float32Vector2D: Vector2D<Float>
|
||||
|
||||
|
||||
public object Float32Euclidean2DSpace :
|
||||
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 = Float32Euclidean2DSpace.vector(x, y)
|
@ -0,0 +1,113 @@
|
||||
package space.kscience.visionforge.solid
|
||||
|
||||
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.ScaleOperations
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sqrt
|
||||
|
||||
@Serializable(Float32Euclidean3DSpace.VectorSerializer::class)
|
||||
public interface Float32Vector3D: Vector3D<Float>
|
||||
|
||||
|
||||
public object Float32Euclidean3DSpace :
|
||||
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()
|
||||
|
||||
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 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 = Float32Euclidean3DSpace.vector(x,y,z)
|
@ -13,17 +13,17 @@ public interface GeometryBuilder<T : Any> {
|
||||
* @param normal optional external normal to the face
|
||||
* @param meta optional additional platform-specific parameters like color or texture index
|
||||
*/
|
||||
public fun face(vertex1: Point3D, vertex2: Point3D, vertex3: Point3D, normal: Point3D? = null, meta: Meta = Meta.EMPTY)
|
||||
public fun face(vertex1: Float32Vector3D, vertex2: Float32Vector3D, vertex3: Float32Vector3D, normal: Float32Vector3D? = null, meta: Meta = Meta.EMPTY)
|
||||
|
||||
public fun build(): T
|
||||
}
|
||||
|
||||
public fun GeometryBuilder<*>.face4(
|
||||
vertex1: Point3D,
|
||||
vertex2: Point3D,
|
||||
vertex3: Point3D,
|
||||
vertex4: Point3D,
|
||||
normal: Point3D? = null,
|
||||
vertex1: Float32Vector3D,
|
||||
vertex2: Float32Vector3D,
|
||||
vertex3: Float32Vector3D,
|
||||
vertex4: Float32Vector3D,
|
||||
normal: Float32Vector3D? = null,
|
||||
meta: Meta = Meta.EMPTY
|
||||
) {
|
||||
face(vertex1, vertex2, vertex3, normal, meta)
|
||||
@ -37,9 +37,9 @@ public interface GeometrySolid : Solid {
|
||||
public fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>)
|
||||
}
|
||||
|
||||
public fun <T : Any> GeometryBuilder<T>.cap(shape: List<Point3D>, normal: Point3D? = null) {
|
||||
public fun <T : Any> GeometryBuilder<T>.cap(shape: List<Float32Vector3D>, normal: Float32Vector3D? = null) {
|
||||
//FIXME won't work for non-convex shapes
|
||||
val center = Point3D(
|
||||
val center = Float32Vector3D(
|
||||
shape.map { it.x }.average(),
|
||||
shape.map { it.y }.average(),
|
||||
shape.map { it.z }.average()
|
||||
|
@ -7,14 +7,14 @@ import space.kscience.visionforge.VisionBuilder
|
||||
import space.kscience.visionforge.setChild
|
||||
|
||||
public interface Hexagon : GeometrySolid {
|
||||
public val node1: Point3D
|
||||
public val node2: Point3D
|
||||
public val node3: Point3D
|
||||
public val node4: Point3D
|
||||
public val node5: Point3D
|
||||
public val node6: Point3D
|
||||
public val node7: Point3D
|
||||
public val node8: Point3D
|
||||
public val node1: Float32Vector3D
|
||||
public val node2: Float32Vector3D
|
||||
public val node3: Float32Vector3D
|
||||
public val node4: Float32Vector3D
|
||||
public val node5: Float32Vector3D
|
||||
public val node6: Float32Vector3D
|
||||
public val node7: Float32Vector3D
|
||||
public val node8: Float32Vector3D
|
||||
|
||||
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {
|
||||
geometryBuilder.face4(node1, node4, node3, node2)
|
||||
@ -41,14 +41,14 @@ public class Box(
|
||||
private inline val dy get() = ySize / 2
|
||||
private inline val dz get() = zSize / 2
|
||||
|
||||
override val node1: Point3D get() = Point3D(-dx, -dy, -dz)
|
||||
override val node2: Point3D get() = Point3D(dx, -dy, -dz)
|
||||
override val node3: Point3D get() = Point3D(dx, dy, -dz)
|
||||
override val node4: Point3D get() = Point3D(-dx, dy, -dz)
|
||||
override val node5: Point3D get() = Point3D(-dx, -dy, dz)
|
||||
override val node6: Point3D get() = Point3D(dx, -dy, dz)
|
||||
override val node7: Point3D get() = Point3D(dx, dy, dz)
|
||||
override val node8: Point3D get() = Point3D(-dx, dy, dz)
|
||||
override val node1: Float32Vector3D get() = Float32Vector3D(-dx, -dy, -dz)
|
||||
override val node2: Float32Vector3D get() = Float32Vector3D(dx, -dy, -dz)
|
||||
override val node3: Float32Vector3D get() = Float32Vector3D(dx, dy, -dz)
|
||||
override val node4: Float32Vector3D get() = Float32Vector3D(-dx, dy, -dz)
|
||||
override val node5: Float32Vector3D get() = Float32Vector3D(-dx, -dy, dz)
|
||||
override val node6: Float32Vector3D get() = Float32Vector3D(dx, -dy, dz)
|
||||
override val node7: Float32Vector3D get() = Float32Vector3D(dx, dy, dz)
|
||||
override val node8: Float32Vector3D get() = Float32Vector3D(-dx, dy, dz)
|
||||
}
|
||||
|
||||
@VisionBuilder
|
||||
@ -63,26 +63,26 @@ public inline fun MutableVisionContainer<Solid>.box(
|
||||
@Serializable
|
||||
@SerialName("solid.hexagon")
|
||||
public class GenericHexagon(
|
||||
override val node1: Point3D,
|
||||
override val node2: Point3D,
|
||||
override val node3: Point3D,
|
||||
override val node4: Point3D,
|
||||
override val node5: Point3D,
|
||||
override val node6: Point3D,
|
||||
override val node7: Point3D,
|
||||
override val node8: Point3D,
|
||||
override val node1: Float32Vector3D,
|
||||
override val node2: Float32Vector3D,
|
||||
override val node3: Float32Vector3D,
|
||||
override val node4: Float32Vector3D,
|
||||
override val node5: Float32Vector3D,
|
||||
override val node6: Float32Vector3D,
|
||||
override val node7: Float32Vector3D,
|
||||
override val node8: Float32Vector3D,
|
||||
) : SolidBase<GenericHexagon>(), Hexagon
|
||||
|
||||
@VisionBuilder
|
||||
public inline fun MutableVisionContainer<Solid>.hexagon(
|
||||
node1: Point3D,
|
||||
node2: Point3D,
|
||||
node3: Point3D,
|
||||
node4: Point3D,
|
||||
node5: Point3D,
|
||||
node6: Point3D,
|
||||
node7: Point3D,
|
||||
node8: Point3D,
|
||||
node1: Float32Vector3D,
|
||||
node2: Float32Vector3D,
|
||||
node3: Float32Vector3D,
|
||||
node4: Float32Vector3D,
|
||||
node5: Float32Vector3D,
|
||||
node6: Float32Vector3D,
|
||||
node7: Float32Vector3D,
|
||||
node8: Float32Vector3D,
|
||||
name: String? = null,
|
||||
action: Hexagon.() -> Unit = {},
|
||||
): Hexagon = GenericHexagon(node1, node2, node3, node4, node5, node6, node7, node8).apply(action).also { setChild(name, it) }
|
@ -70,6 +70,6 @@ public fun MutableVisionContainer<Solid>.pointLight(
|
||||
name: String? = null,
|
||||
block: PointLightSource.() -> Unit = {},
|
||||
): PointLightSource = PointLightSource().apply(block).also {
|
||||
it.position = Point3D(x, y, z)
|
||||
it.position = Float32Vector3D(x, y, z)
|
||||
setChild(name, it)
|
||||
}
|
@ -3,11 +3,14 @@ package space.kscience.visionforge.solid
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import space.kscience.dataforge.meta.number
|
||||
import space.kscience.visionforge.*
|
||||
import space.kscience.visionforge.MutableVisionContainer
|
||||
import space.kscience.visionforge.VisionBuilder
|
||||
import space.kscience.visionforge.root
|
||||
import space.kscience.visionforge.setChild
|
||||
|
||||
@Serializable
|
||||
@SerialName("solid.line")
|
||||
public class PolyLine(public val points: List<Point3D>) : SolidBase<PolyLine>() {
|
||||
public class PolyLine(public val points: List<Float32Vector3D>) : SolidBase<PolyLine>() {
|
||||
|
||||
//var lineType by string()
|
||||
public var thickness: Number by properties.root(inherit = false, includeStyles = true).number { DEFAULT_THICKNESS }
|
||||
@ -19,7 +22,7 @@ public class PolyLine(public val points: List<Point3D>) : SolidBase<PolyLine>()
|
||||
|
||||
@VisionBuilder
|
||||
public fun MutableVisionContainer<Solid>.polyline(
|
||||
vararg points: Point3D,
|
||||
vararg points: Float32Vector3D,
|
||||
name: String? = null,
|
||||
action: PolyLine.() -> Unit = {},
|
||||
): PolyLine = PolyLine(points.toList()).apply(action).also { setChild(name, it) }
|
@ -174,18 +174,21 @@ internal fun point(
|
||||
defaultX: Float,
|
||||
defaultY: Float = defaultX,
|
||||
defaultZ: Float = defaultX,
|
||||
): ReadWriteProperty<Solid, Point3D?> =
|
||||
object : ReadWriteProperty<Solid, Point3D?> {
|
||||
override fun getValue(thisRef: Solid, property: KProperty<*>): Point3D? {
|
||||
): ReadWriteProperty<Solid, Float32Vector3D?> =
|
||||
object : ReadWriteProperty<Solid, Float32Vector3D?> {
|
||||
override fun getValue(thisRef: Solid, property: KProperty<*>): Float32Vector3D? {
|
||||
val item = thisRef.properties.own?.get(name) ?: return null
|
||||
return object : Point3D {
|
||||
//using dynamic property accessor because values could change
|
||||
return object : Float32Vector3D {
|
||||
override val x: Float get() = item[X_KEY]?.float ?: defaultX
|
||||
override val y: Float get() = item[Y_KEY]?.float ?: defaultY
|
||||
override val z: Float get() = item[Z_KEY]?.float ?: defaultZ
|
||||
|
||||
override fun toString(): String = item.toString()
|
||||
}
|
||||
}
|
||||
|
||||
override fun setValue(thisRef: Solid, property: KProperty<*>, value: Point3D?) {
|
||||
override fun setValue(thisRef: Solid, property: KProperty<*>, value: Float32Vector3D?) {
|
||||
if (value == null) {
|
||||
thisRef.properties.setProperty(name, null)
|
||||
} else {
|
||||
@ -196,9 +199,9 @@ internal fun point(
|
||||
}
|
||||
}
|
||||
|
||||
public var Solid.position: Point3D? by point(POSITION_KEY, 0f)
|
||||
public var Solid.rotation: Point3D? by point(ROTATION_KEY, 0f)
|
||||
public var Solid.scale: Point3D? by point(SCALE_KEY, 1f)
|
||||
public var Solid.position: Float32Vector3D? by point(POSITION_KEY, 0f)
|
||||
public var Solid.rotation: Float32Vector3D? by point(ROTATION_KEY, 0f)
|
||||
public var Solid.scale: Float32Vector3D? by point(SCALE_KEY, 1f)
|
||||
|
||||
public var Solid.x: Number by float(X_POSITION_KEY, 0f)
|
||||
public var Solid.y: Number by float(Y_POSITION_KEY, 0f)
|
||||
@ -208,10 +211,10 @@ public var Solid.rotationX: Number by float(X_ROTATION_KEY, 0f)
|
||||
public var Solid.rotationY: Number by float(Y_ROTATION_KEY, 0f)
|
||||
public var Solid.rotationZ: Number by float(Z_ROTATION_KEY, 0f)
|
||||
|
||||
public var Solid.quaternion: Pair<Float, Point3D>?
|
||||
public var Solid.quaternion: Pair<Float, Float32Vector3D>?
|
||||
get() = properties.getValue(Solid.QUATERNION_KEY)?.list?.let {
|
||||
require(it.size == 4) { "Quaternion must be a number array of 4 elements" }
|
||||
it[0].float to Point3D(it[1].float, it[2].float, it[3].float)
|
||||
it[0].float to Float32Vector3D(it[1].float, it[2].float, it[3].float)
|
||||
}
|
||||
set(value) {
|
||||
properties.setValue(
|
||||
|
@ -51,6 +51,7 @@ public class Solids(meta: Meta) : VisionPlugin(meta), MutableVisionContainer<Sol
|
||||
}
|
||||
|
||||
public val serializersModuleForSolids: SerializersModule = SerializersModule {
|
||||
|
||||
polymorphic(Vision::class) {
|
||||
subclass(SimpleVisionGroup.serializer())
|
||||
solids()
|
||||
|
@ -20,12 +20,12 @@ public class Sphere(
|
||||
) : SolidBase<Sphere>(), GeometrySolid {
|
||||
|
||||
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {
|
||||
fun point3dFromSphCoord(r: Float, theta: Float, phi: Float): Point3D {
|
||||
fun point3dFromSphCoord(r: Float, theta: Float, phi: Float): Float32Vector3D {
|
||||
// This transformation matches three.js sphere implementation
|
||||
val y = r * cos(theta)
|
||||
val z = r * sin(theta) * sin(phi)
|
||||
val x = -r * sin(theta) * cos(phi)
|
||||
return Point3D(x, y, z)
|
||||
return Float32Vector3D(x, y, z)
|
||||
}
|
||||
|
||||
val segments = this.detail ?: 32
|
||||
|
@ -27,12 +27,12 @@ public class SphereLayer(
|
||||
require(outerRadius > 0) { "Outer radius must be positive" }
|
||||
require(innerRadius >= 0) { "inner radius must be non-negative" }
|
||||
|
||||
fun point3dFromSphCoord(r: Float, theta: Float, phi: Float): Point3D {
|
||||
fun point3dFromSphCoord(r: Float, theta: Float, phi: Float): Float32Vector3D {
|
||||
// This transformation matches three.js sphere implementation
|
||||
val y = r * cos(theta)
|
||||
val z = r * sin(theta) * sin(phi)
|
||||
val x = -r * sin(theta) * cos(phi)
|
||||
return Point3D(x, y, z)
|
||||
return Float32Vector3D(x, y, z)
|
||||
}
|
||||
|
||||
val segments = detail ?: 32
|
||||
|
@ -1,10 +1,5 @@
|
||||
package space.kscience.visionforge.solid
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.MetaProvider
|
||||
import space.kscience.dataforge.meta.float
|
||||
@ -13,105 +8,48 @@ import space.kscience.visionforge.solid.Solid.Companion.X_KEY
|
||||
import space.kscience.visionforge.solid.Solid.Companion.Y_KEY
|
||||
import space.kscience.visionforge.solid.Solid.Companion.Z_KEY
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sqrt
|
||||
|
||||
public const val PI2: Float = 2 * PI.toFloat()
|
||||
|
||||
@Serializable
|
||||
public data class Point2D(public var x: Float, public var y: Float)
|
||||
|
||||
public fun Point2D(x: Number, y: Number): Point2D = Point2D(x.toFloat(), y.toFloat())
|
||||
|
||||
public fun Point2D.toMeta(): Meta = Meta {
|
||||
public fun Float32Vector2D.toMeta(): Meta = Meta {
|
||||
X_KEY put x
|
||||
Y_KEY put y
|
||||
}
|
||||
|
||||
internal fun Meta.point2D(): Point2D = Point2D(this["x"].float ?: 0f, this["y"].float ?: 0f)
|
||||
internal fun Meta.toVector2D(): Float32Vector2D =
|
||||
Float32Vector2D(this["x"].float ?: 0f, this["y"].float ?: 0f)
|
||||
|
||||
@Serializable(Point3DSerializer::class)
|
||||
public interface Point3D {
|
||||
public val x: Float
|
||||
public val y: Float
|
||||
public val z: Float
|
||||
//@Suppress("SERIALIZER_TYPE_INCOMPATIBLE")
|
||||
//@Serializable(Point3DSerializer::class)
|
||||
//public interface MutablePoint3D : Float32Vector3D {
|
||||
// override var x: Float
|
||||
// override var y: Float
|
||||
// override var z: Float
|
||||
//}
|
||||
//
|
||||
//
|
||||
//public fun MutablePoint3D.normalizeInPlace() {
|
||||
// val norm = sqrt(x.pow(2) + y.pow(2) + z.pow(2))
|
||||
// x /= norm
|
||||
// y /= norm
|
||||
// z /= norm
|
||||
//}
|
||||
|
||||
public companion object {
|
||||
public val ZERO: Point3D = Point3D(0.0, 0.0, 0.0)
|
||||
public val ONE: Point3D = Point3D(1.0, 1.0, 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("SERIALIZER_TYPE_INCOMPATIBLE")
|
||||
@Serializable(Point3DSerializer::class)
|
||||
public interface MutablePoint3D : Point3D {
|
||||
override var x: Float
|
||||
override var y: Float
|
||||
override var z: Float
|
||||
}
|
||||
|
||||
@Serializable
|
||||
private class Point3DImpl(override var x: Float, override var y: Float, override var z: Float) : MutablePoint3D
|
||||
|
||||
internal object Point3DSerializer : KSerializer<Point3D> {
|
||||
|
||||
override val descriptor: SerialDescriptor = Point3DImpl.serializer().descriptor
|
||||
|
||||
override fun deserialize(decoder: Decoder): MutablePoint3D = decoder.decodeSerializableValue(Point3DImpl.serializer())
|
||||
|
||||
override fun serialize(encoder: Encoder, value: Point3D) {
|
||||
val impl: Point3DImpl = (value as? Point3DImpl) ?: Point3DImpl(value.x, value.y, value.z)
|
||||
encoder.encodeSerializableValue(Point3DImpl.serializer(), impl)
|
||||
}
|
||||
}
|
||||
|
||||
public fun Point3D(x: Number, y: Number, z: Number): Point3D = Point3DImpl(x.toFloat(), y.toFloat(), z.toFloat())
|
||||
|
||||
public operator fun Point3D.plus(other: Point3D): Point3D = Point3D(
|
||||
this.x + other.x,
|
||||
this.y + other.y,
|
||||
this.z + other.z
|
||||
internal fun MetaProvider.point3D(default: Float = 0f) = Float32Euclidean3DSpace.vector(
|
||||
getMeta(X_KEY).float ?: default,
|
||||
getMeta(Y_KEY).float ?: default,
|
||||
getMeta(Z_KEY).float ?: default
|
||||
)
|
||||
|
||||
public operator fun Point3D.minus(other: Point3D): Point3D = Point3D(
|
||||
this.x - other.x,
|
||||
this.y - other.y,
|
||||
this.z - other.z
|
||||
)
|
||||
|
||||
public operator fun Point3D.unaryMinus(): Point3D = Point3D(
|
||||
-x,
|
||||
-y,
|
||||
-z
|
||||
)
|
||||
|
||||
public infix fun Point3D.cross(other: Point3D): Point3D = Point3D(
|
||||
y * other.z - z * other.y,
|
||||
z * other.x - x * other.z,
|
||||
x * other.y - y * other.x
|
||||
)
|
||||
|
||||
public fun MutablePoint3D.normalizeInPlace() {
|
||||
val norm = sqrt(x.pow(2) + y.pow(2) + z.pow(2))
|
||||
x /= norm
|
||||
y /= norm
|
||||
z /= norm
|
||||
}
|
||||
|
||||
internal fun MetaProvider.point3D(default: Float = 0f) = object : Point3D {
|
||||
override val x: Float by float(default)
|
||||
override val y: Float by float(default)
|
||||
override val z: Float by float(default)
|
||||
}
|
||||
|
||||
public fun Point3D.toMeta(): Meta = Meta {
|
||||
public fun Float32Vector3D.toMeta(): Meta = Meta {
|
||||
X_KEY put x
|
||||
Y_KEY put y
|
||||
Z_KEY put z
|
||||
}
|
||||
|
||||
|
||||
internal fun Meta.toVector(default: Float = 0f) = Point3D(
|
||||
internal fun Meta.toVector3D(default: Float = 0f) = Float32Vector3D(
|
||||
this[X_KEY].float ?: default,
|
||||
this[Y_KEY].float ?: default,
|
||||
this[Z_KEY].float ?: default
|
||||
|
@ -2,13 +2,10 @@ package space.kscience.visionforge.solid
|
||||
|
||||
import space.kscience.dataforge.meta.getIndexed
|
||||
import space.kscience.dataforge.meta.toMeta
|
||||
import space.kscience.dataforge.misc.DFExperimental
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class ConvexTest {
|
||||
@OptIn(DFExperimental::class)
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
@Test
|
||||
fun testConvexBuilder() {
|
||||
val group = testSolids.solidGroup {
|
||||
|
@ -1,15 +1,14 @@
|
||||
package space.kscience.visionforge.solid.three
|
||||
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.visionforge.solid.Float32Euclidean3DSpace
|
||||
import space.kscience.visionforge.solid.Float32Vector3D
|
||||
import space.kscience.visionforge.solid.GeometryBuilder
|
||||
import three.core.BufferGeometry
|
||||
import three.core.Float32BufferAttribute
|
||||
import three.math.Vector3
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.visionforge.solid.GeometryBuilder
|
||||
import space.kscience.visionforge.solid.Point3D
|
||||
import space.kscience.visionforge.solid.cross
|
||||
import space.kscience.visionforge.solid.minus
|
||||
|
||||
internal fun Point3D.toVector() = Vector3(x, y, z)
|
||||
internal fun Float32Vector3D.toVector() = Vector3(x, y, z)
|
||||
|
||||
internal fun <T> MutableList<T>.add(vararg values: T) {
|
||||
values.forEach {
|
||||
@ -27,10 +26,10 @@ public class ThreeGeometryBuilder : GeometryBuilder<BufferGeometry> {
|
||||
private val normals = ArrayList<Float>()
|
||||
// private val colors = ArrayList<Float>()
|
||||
|
||||
private val vertexCache = HashMap<Point3D, Short>()
|
||||
private val vertexCache = HashMap<Float32Vector3D, Short>()
|
||||
private var counter: Short = -1
|
||||
|
||||
private fun vertex(vertex: Point3D, normal: Point3D): Short = vertexCache.getOrPut(vertex) {
|
||||
private fun vertex(vertex: Float32Vector3D, normal: Float32Vector3D): Short = vertexCache.getOrPut(vertex) {
|
||||
//add vertex and update cache if needed
|
||||
positions.add(vertex.x, vertex.y, vertex.z)
|
||||
normals.add(normal.x, vertex.y, vertex.z)
|
||||
@ -39,8 +38,14 @@ public class ThreeGeometryBuilder : GeometryBuilder<BufferGeometry> {
|
||||
counter
|
||||
}
|
||||
|
||||
override fun face(vertex1: Point3D, vertex2: Point3D, vertex3: Point3D, normal: Point3D?, meta: Meta) {
|
||||
val actualNormal: Point3D = normal ?: ((vertex3 - vertex2) cross (vertex1 - vertex2))
|
||||
override fun face(
|
||||
vertex1: Float32Vector3D,
|
||||
vertex2: Float32Vector3D,
|
||||
vertex3: Float32Vector3D,
|
||||
normal: Float32Vector3D?,
|
||||
meta: Meta,
|
||||
) = with(Float32Euclidean3DSpace) {
|
||||
val actualNormal: Float32Vector3D = normal ?: ((vertex3 - vertex2) cross (vertex1 - vertex2))
|
||||
indices.add(
|
||||
vertex(vertex1, actualNormal),
|
||||
vertex(vertex2, actualNormal),
|
||||
|
@ -8,6 +8,7 @@ import kotlin.test.Test
|
||||
|
||||
class TestServerExtensions {
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
@Test
|
||||
fun testServerHeader(){
|
||||
val string = createHTML().apply {
|
||||
|
Loading…
Reference in New Issue
Block a user