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