Added satelite detector demo
This commit is contained in:
parent
6b4bc6912f
commit
5b8d298ac6
24
demo/sat-demo/build.gradle.kts
Normal file
24
demo/sat-demo/build.gradle.kts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
plugins {
|
||||||
|
id("ru.mipt.npm.mpp")
|
||||||
|
}
|
||||||
|
|
||||||
|
val kvisionVersion: String = "3.16.2"
|
||||||
|
|
||||||
|
kscience{
|
||||||
|
application()
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
sourceSets {
|
||||||
|
commonMain {
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":visionforge-solid"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jsMain {
|
||||||
|
dependencies {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
package ru.mipt.npm.sat
|
||||||
|
|
||||||
|
import hep.dataforge.vision.solid.*
|
||||||
|
import kotlin.math.PI
|
||||||
|
|
||||||
|
internal fun visionOfSatellite(
|
||||||
|
layers: Int = 10,
|
||||||
|
layerHeight: Number = 10,
|
||||||
|
xSegments: Int = 3,
|
||||||
|
ySegments: Int = xSegments,
|
||||||
|
xSegmentSize: Number = 30,
|
||||||
|
ySegmentSize: Number = xSegmentSize,
|
||||||
|
fiberDiameter: Number = 1.0,
|
||||||
|
): SolidGroup = SolidGroup {
|
||||||
|
opacity = 0.3
|
||||||
|
val totalXSize = xSegments * xSegmentSize.toDouble()
|
||||||
|
val totalYSize = ySegments * ySegmentSize.toDouble()
|
||||||
|
for (layer in 1..layers) {
|
||||||
|
group("layer[$layer]") {
|
||||||
|
for (i in 1..xSegments) {
|
||||||
|
for (j in 1..ySegments) {
|
||||||
|
box(xSegmentSize, ySegmentSize, layerHeight, name = "segment[$i,$j]") {
|
||||||
|
z = (layer - 0.5) * layerHeight.toDouble()
|
||||||
|
x = (i - 0.5) * xSegmentSize.toDouble()
|
||||||
|
y = (j - 0.5) * ySegmentSize.toDouble()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
group("fibers") {
|
||||||
|
for (i in 1..xSegments) {
|
||||||
|
cylinder(fiberDiameter, totalYSize) {
|
||||||
|
rotationX = PI / 2
|
||||||
|
z = (layer - 1.0) * layerHeight.toDouble() + fiberDiameter.toDouble()
|
||||||
|
x = (i - 0.5) * xSegmentSize.toDouble()
|
||||||
|
y = totalYSize/2
|
||||||
|
|
||||||
|
color("red")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j in 1..ySegments) {
|
||||||
|
cylinder(fiberDiameter, totalXSize) {
|
||||||
|
rotationY = PI / 2
|
||||||
|
z = (layer) * layerHeight.toDouble() - fiberDiameter.toDouble()
|
||||||
|
y = (j - 0.5) * xSegmentSize.toDouble()
|
||||||
|
x = totalXSize/2
|
||||||
|
|
||||||
|
color("blue")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
|||||||
|
package ru.mipt.npm.sat
|
||||||
|
|
||||||
|
import hep.dataforge.context.Global
|
||||||
|
import hep.dataforge.js.Application
|
||||||
|
import hep.dataforge.js.startApplication
|
||||||
|
import hep.dataforge.vision.solid.three.ThreePlugin
|
||||||
|
import hep.dataforge.vision.solid.three.render
|
||||||
|
import kotlinx.browser.document
|
||||||
|
import hep.dataforge.meta.invoke
|
||||||
|
import org.w3c.dom.HTMLElement
|
||||||
|
|
||||||
|
private class SatDemoApp : Application {
|
||||||
|
|
||||||
|
override fun start(state: Map<String, Any>) {
|
||||||
|
val element = document.getElementById("canvas") as? HTMLElement
|
||||||
|
?: error("Element with id 'canvas' not found on page")
|
||||||
|
val three = Global.plugins.fetch(ThreePlugin)
|
||||||
|
val sat = visionOfSatellite(
|
||||||
|
ySegments = 5,
|
||||||
|
)
|
||||||
|
three.render(element, sat){
|
||||||
|
minSize = 500
|
||||||
|
axes {
|
||||||
|
size = 500.0
|
||||||
|
visible = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
startApplication(::SatDemoApp)
|
||||||
|
}
|
12
demo/sat-demo/src/jsMain/resources/index.html
Normal file
12
demo/sat-demo/src/jsMain/resources/index.html
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
|
<title>Three js demo for particle physics</title>
|
||||||
|
<script type="text/javascript" src="sat-demo.js"></script>
|
||||||
|
</head>
|
||||||
|
<body class="application">
|
||||||
|
<div id="canvas"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -6,6 +6,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
kscience {
|
kscience {
|
||||||
|
useCoroutines()
|
||||||
val fxVersion: String by rootProject.extra
|
val fxVersion: String by rootProject.extra
|
||||||
useFx(FXModule.CONTROLS, version = fxVersion, configuration = DependencyConfiguration.IMPLEMENTATION)
|
useFx(FXModule.CONTROLS, version = fxVersion, configuration = DependencyConfiguration.IMPLEMENTATION)
|
||||||
application()
|
application()
|
||||||
|
@ -2,7 +2,14 @@ package hep.dataforge.vision.solid.demo
|
|||||||
|
|
||||||
import hep.dataforge.js.Application
|
import hep.dataforge.js.Application
|
||||||
import hep.dataforge.js.startApplication
|
import hep.dataforge.js.startApplication
|
||||||
import kotlin.browser.document
|
import hep.dataforge.vision.solid.x
|
||||||
|
import hep.dataforge.vision.solid.y
|
||||||
|
import kotlinx.browser.document
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.isActive
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
private class ThreeDemoApp : Application {
|
private class ThreeDemoApp : Application {
|
||||||
|
|
||||||
@ -13,27 +20,25 @@ private class ThreeDemoApp : Application {
|
|||||||
ThreeDemoGrid(element).run {
|
ThreeDemoGrid(element).run {
|
||||||
showcase()
|
showcase()
|
||||||
showcaseCSG()
|
showcaseCSG()
|
||||||
// demo("dynamicBox", "Dancing boxes") {
|
demo("dynamicBox", "Dancing boxes") {
|
||||||
// val boxes = (-10..10).flatMap { i ->
|
val boxes = (-10..10).flatMap { i ->
|
||||||
// (-10..10).map { j ->
|
(-10..10).map { j ->
|
||||||
// varBox(10, 10, 0, name = "cell_${i}_${j}") {
|
varBox(10, 10, 0, name = "cell_${i}_${j}") {
|
||||||
// x = i * 10
|
x = i * 10
|
||||||
// y = j * 10
|
y = j * 10
|
||||||
// value = 128
|
value = 128
|
||||||
// setProperty(EDGES_ENABLED_KEY, false)
|
}
|
||||||
// setProperty(WIREFRAME_ENABLED_KEY, false)
|
}
|
||||||
// }
|
}
|
||||||
// }
|
GlobalScope.launch {
|
||||||
// }
|
while (isActive) {
|
||||||
// GlobalScope.launch {
|
delay(500)
|
||||||
// while (isActive) {
|
boxes.forEach { box ->
|
||||||
// delay(500)
|
box.value = (box.value + Random.nextInt(-15, 15)).coerceIn(1..255)
|
||||||
// boxes.forEach { box ->
|
}
|
||||||
// box.value = (box.value + Random.nextInt(-15, 15)).coerceIn(0..255)
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,6 +11,8 @@ import hep.dataforge.vision.Vision
|
|||||||
import hep.dataforge.vision.solid.three.ThreeCanvas
|
import hep.dataforge.vision.solid.three.ThreeCanvas
|
||||||
import hep.dataforge.vision.solid.three.ThreePlugin
|
import hep.dataforge.vision.solid.three.ThreePlugin
|
||||||
import hep.dataforge.vision.solid.three.output
|
import hep.dataforge.vision.solid.three.output
|
||||||
|
import kotlinx.browser.document
|
||||||
|
import kotlinx.dom.clear
|
||||||
import kotlinx.html.dom.append
|
import kotlinx.html.dom.append
|
||||||
import kotlinx.html.dom.create
|
import kotlinx.html.dom.create
|
||||||
import kotlinx.html.h2
|
import kotlinx.html.h2
|
||||||
@ -19,8 +21,6 @@ import kotlinx.html.id
|
|||||||
import kotlinx.html.js.div
|
import kotlinx.html.js.div
|
||||||
import kotlinx.html.span
|
import kotlinx.html.span
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
import kotlin.browser.document
|
|
||||||
import kotlin.dom.clear
|
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
class ThreeDemoGrid(element: Element, meta: Meta = Meta.EMPTY) : OutputManager {
|
class ThreeDemoGrid(element: Element, meta: Meta = Meta.EMPTY) : OutputManager {
|
||||||
|
@ -4,6 +4,7 @@ package hep.dataforge.vision.solid.demo
|
|||||||
|
|
||||||
import hep.dataforge.meta.int
|
import hep.dataforge.meta.int
|
||||||
import hep.dataforge.meta.number
|
import hep.dataforge.meta.number
|
||||||
|
import hep.dataforge.meta.set
|
||||||
import hep.dataforge.meta.setItem
|
import hep.dataforge.meta.setItem
|
||||||
import hep.dataforge.names.plus
|
import hep.dataforge.names.plus
|
||||||
import hep.dataforge.names.startsWith
|
import hep.dataforge.names.startsWith
|
||||||
@ -12,7 +13,6 @@ import hep.dataforge.vision.getProperty
|
|||||||
import hep.dataforge.vision.set
|
import hep.dataforge.vision.set
|
||||||
import hep.dataforge.vision.solid.*
|
import hep.dataforge.vision.solid.*
|
||||||
import hep.dataforge.vision.solid.Solid.Companion.GEOMETRY_KEY
|
import hep.dataforge.vision.solid.Solid.Companion.GEOMETRY_KEY
|
||||||
import hep.dataforge.vision.solid.demo.VariableBoxThreeFactory.Z_SIZE_KEY
|
|
||||||
import hep.dataforge.vision.solid.three.*
|
import hep.dataforge.vision.solid.three.*
|
||||||
import hep.dataforge.vision.solid.three.ThreeMaterials.getMaterial
|
import hep.dataforge.vision.solid.three.ThreeMaterials.getMaterial
|
||||||
import info.laht.threekt.core.BufferGeometry
|
import info.laht.threekt.core.BufferGeometry
|
||||||
@ -21,86 +21,89 @@ import info.laht.threekt.geometries.BoxBufferGeometry
|
|||||||
import info.laht.threekt.objects.Mesh
|
import info.laht.threekt.objects.Mesh
|
||||||
import kotlinx.serialization.UseSerializers
|
import kotlinx.serialization.UseSerializers
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.reflect.KClass
|
|
||||||
|
|
||||||
internal var Solid.variableZSize: Number
|
internal fun SolidGroup.varBox(
|
||||||
get() = getProperty(Z_SIZE_KEY, false).number ?: 0f
|
|
||||||
set(value) {
|
|
||||||
setItem(Z_SIZE_KEY, value.asValue())
|
|
||||||
}
|
|
||||||
|
|
||||||
internal var Solid.value: Int
|
|
||||||
get() = getProperty("value", false).int ?: 0
|
|
||||||
set(value) {
|
|
||||||
setItem("value", value.asValue())
|
|
||||||
val size = value.toFloat() / 255f * 20f
|
|
||||||
scaleZ = size
|
|
||||||
z = -size / 2
|
|
||||||
|
|
||||||
val b = max(0, 255 - value)
|
|
||||||
val r = max(0, value - 255)
|
|
||||||
val g = 255 - b - r
|
|
||||||
color(r.toUByte(), g.toUByte(), b.toUByte())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun SolidGroup.varBox(
|
|
||||||
xSize: Number,
|
xSize: Number,
|
||||||
ySize: Number,
|
ySize: Number,
|
||||||
zSize: Number,
|
zSize: Number,
|
||||||
name: String = "",
|
name: String = "",
|
||||||
action: Solid.() -> Unit = {}
|
action: VariableBox.() -> Unit = {},
|
||||||
) = CustomThreeVision(VariableBoxThreeFactory).apply {
|
): VariableBox = VariableBox(xSize, ySize, zSize).apply(action).also { set(name, it) }
|
||||||
|
|
||||||
|
internal class VariableBox(xSize: Number, ySize: Number, zSize: Number) : ThreeVision() {
|
||||||
|
init {
|
||||||
scaleX = xSize
|
scaleX = xSize
|
||||||
scaleY = ySize
|
scaleY = ySize
|
||||||
scaleZ = zSize
|
scaleZ = zSize
|
||||||
}.apply(action).also { set(name, it) }
|
config[MeshThreeFactory.EDGES_ENABLED_KEY] = false
|
||||||
|
config[MeshThreeFactory.WIREFRAME_ENABLED_KEY] = false
|
||||||
|
}
|
||||||
|
|
||||||
private object VariableBoxThreeFactory : ThreeFactory<Solid> {
|
override fun render(): Object3D {
|
||||||
val X_SIZE_KEY = GEOMETRY_KEY + "xSize"
|
val xSize = getProperty(X_SIZE_KEY, false).number?.toDouble() ?: 1.0
|
||||||
val Y_SIZE_KEY = GEOMETRY_KEY + "ySize"
|
val ySize = getProperty(Y_SIZE_KEY, false).number?.toDouble() ?: 1.0
|
||||||
val Z_SIZE_KEY = GEOMETRY_KEY + "zSize"
|
val zSize = getProperty(Z_SIZE_KEY, false).number?.toDouble() ?: 1.0
|
||||||
|
|
||||||
override val type: KClass<in Solid> get() = Solid::class
|
|
||||||
|
|
||||||
override fun invoke(obj: Solid): Object3D {
|
|
||||||
val xSize = obj.getProperty(X_SIZE_KEY, false).number?.toDouble() ?: 1.0
|
|
||||||
val ySize = obj.getProperty(Y_SIZE_KEY, false).number?.toDouble() ?: 1.0
|
|
||||||
val zSize = obj.getProperty(Z_SIZE_KEY, false).number?.toDouble() ?: 1.0
|
|
||||||
val geometry = BoxBufferGeometry(1, 1, 1)
|
val geometry = BoxBufferGeometry(1, 1, 1)
|
||||||
|
|
||||||
//JS sometimes tries to pass Geometry as BufferGeometry
|
//JS sometimes tries to pass Geometry as BufferGeometry
|
||||||
@Suppress("USELESS_IS_CHECK") if (geometry !is BufferGeometry) error("BufferGeometry expected")
|
@Suppress("USELESS_IS_CHECK") if (geometry !is BufferGeometry) error("BufferGeometry expected")
|
||||||
|
|
||||||
val mesh = Mesh(geometry, getMaterial(obj,true)).apply {
|
val mesh = Mesh(geometry, getMaterial(this@VariableBox, true)).apply {
|
||||||
applyEdges(obj)
|
applyEdges(this@VariableBox)
|
||||||
applyWireFrame(obj)
|
applyWireFrame(this@VariableBox)
|
||||||
|
|
||||||
//set position for mesh
|
//set position for mesh
|
||||||
updatePosition(obj)
|
updatePosition(this@VariableBox)
|
||||||
|
|
||||||
layers.enable(obj.layer)
|
layers.enable(this@VariableBox.layer)
|
||||||
children.forEach {
|
children.forEach {
|
||||||
it.layers.enable(obj.layer)
|
it.layers.enable(this@VariableBox.layer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh.scale.set(xSize, ySize, zSize)
|
mesh.scale.set(xSize, ySize, zSize)
|
||||||
|
|
||||||
//add listener to object properties
|
//add listener to object properties
|
||||||
obj.onPropertyChange(this) { name ->
|
onPropertyChange(mesh) { name ->
|
||||||
when {
|
when {
|
||||||
// name.startsWith(GEOMETRY_KEY) -> {
|
name.startsWith(GEOMETRY_KEY) -> {
|
||||||
// val newXSize = obj.getProperty(X_SIZE_KEY, false).number?.toDouble() ?: 1.0
|
val newXSize = getProperty(X_SIZE_KEY, false).number?.toDouble() ?: 1.0
|
||||||
// val newYSize = obj.getProperty(Y_SIZE_KEY, false).number?.toDouble() ?: 1.0
|
val newYSize = getProperty(Y_SIZE_KEY, false).number?.toDouble() ?: 1.0
|
||||||
// val newZSize = obj.getProperty(Z_SIZE_KEY, false).number?.toDouble() ?: 1.0
|
val newZSize = getProperty(Z_SIZE_KEY, false).number?.toDouble() ?: 1.0
|
||||||
// mesh.scale.set(newXSize, newYSize, newZSize)
|
mesh.scale.set(newXSize, newYSize, newZSize)
|
||||||
// mesh.updateMatrix()
|
mesh.updateMatrix()
|
||||||
// }
|
}
|
||||||
name.startsWith(MeshThreeFactory.WIREFRAME_KEY) -> mesh.applyWireFrame(obj)
|
name.startsWith(MeshThreeFactory.WIREFRAME_KEY) -> mesh.applyWireFrame(this@VariableBox)
|
||||||
name.startsWith(MeshThreeFactory.EDGES_KEY) -> mesh.applyEdges(obj)
|
name.startsWith(MeshThreeFactory.EDGES_KEY) -> mesh.applyEdges(this@VariableBox)
|
||||||
else -> mesh.updateProperty(obj, name)
|
else -> mesh.updateProperty(this@VariableBox, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return mesh
|
return mesh
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var variableZSize: Number
|
||||||
|
get() = getProperty(Z_SIZE_KEY, false).number ?: 0f
|
||||||
|
set(value) {
|
||||||
|
setItem(Z_SIZE_KEY, value.asValue())
|
||||||
|
}
|
||||||
|
|
||||||
|
var value: Int
|
||||||
|
get() = getProperty("value", false).int ?: 0
|
||||||
|
set(value) {
|
||||||
|
setItem("value", value.asValue())
|
||||||
|
val size = value.toFloat() / 255f * 20f
|
||||||
|
scaleZ = size
|
||||||
|
z = size / 2
|
||||||
|
|
||||||
|
val b = max(0, 128 - value)
|
||||||
|
val r = max(0, value - 128)
|
||||||
|
val g = 255 - b - r
|
||||||
|
color(r.toUByte(), g.toUByte(), b.toUByte())
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object{
|
||||||
|
private val X_SIZE_KEY = GEOMETRY_KEY + "xSize"
|
||||||
|
private val Y_SIZE_KEY = GEOMETRY_KEY + "ySize"
|
||||||
|
private val Z_SIZE_KEY = GEOMETRY_KEY + "zSize"
|
||||||
|
}
|
||||||
}
|
}
|
@ -43,5 +43,6 @@ include(
|
|||||||
":demo:spatial-showcase",
|
":demo:spatial-showcase",
|
||||||
":demo:gdml",
|
":demo:gdml",
|
||||||
":demo:muon-monitor",
|
":demo:muon-monitor",
|
||||||
|
":demo:sat-demo",
|
||||||
":playground"
|
":playground"
|
||||||
)
|
)
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package hep.dataforge.vision.bootstrap
|
package hep.dataforge.vision.bootstrap
|
||||||
|
|
||||||
import hep.dataforge.meta.DFExperimental
|
|
||||||
import hep.dataforge.vision.solid.SolidGroup
|
import hep.dataforge.vision.solid.SolidGroup
|
||||||
import hep.dataforge.vision.solid.SolidManager
|
import hep.dataforge.vision.solid.SolidManager
|
||||||
import hep.dataforge.vision.solid.three.ThreeCanvas
|
import hep.dataforge.vision.solid.three.ThreeCanvas
|
||||||
@ -15,8 +14,7 @@ import org.w3c.dom.HTMLInputElement
|
|||||||
import org.w3c.dom.events.Event
|
import org.w3c.dom.events.Event
|
||||||
import org.w3c.files.Blob
|
import org.w3c.files.Blob
|
||||||
import org.w3c.files.BlobPropertyBag
|
import org.w3c.files.BlobPropertyBag
|
||||||
import react.RBuilder
|
import react.*
|
||||||
import react.ReactElement
|
|
||||||
import react.dom.button
|
import react.dom.button
|
||||||
import react.dom.div
|
import react.dom.div
|
||||||
import react.dom.input
|
import react.dom.input
|
||||||
@ -31,17 +29,33 @@ private fun saveData(event: Event, fileName: String, mimeType: String = "text/pl
|
|||||||
fileSaver.saveAs(blob, fileName)
|
fileSaver.saveAs(blob, fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(DFExperimental::class)
|
public fun RBuilder.canvasControls(canvas: ThreeCanvas): ReactElement {
|
||||||
public fun RBuilder.canvasControls(canvas: ThreeCanvas): ReactElement = accordion("controls") {
|
return child(CanvasControls){
|
||||||
|
attrs{
|
||||||
|
this.canvas = canvas
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public external interface CanvasControlsProps : RProps {
|
||||||
|
public var canvas: ThreeCanvas
|
||||||
|
}
|
||||||
|
|
||||||
|
public val CanvasControls: FunctionalComponent<CanvasControlsProps> = functionalComponent ("CanvasControls") { props ->
|
||||||
|
val visionManager = useMemo(
|
||||||
|
{ props.canvas.context.plugins.fetch(SolidManager).visionManager },
|
||||||
|
arrayOf(props.canvas)
|
||||||
|
)
|
||||||
|
accordion("controls") {
|
||||||
entry("Settings") {
|
entry("Settings") {
|
||||||
div("row") {
|
div("row") {
|
||||||
div("col-2") {
|
div("col-2") {
|
||||||
label("checkbox-inline") {
|
label("checkbox-inline") {
|
||||||
input(type = InputType.checkBox) {
|
input(type = InputType.checkBox) {
|
||||||
attrs {
|
attrs {
|
||||||
defaultChecked = canvas.axes.visible
|
defaultChecked = props.canvas.axes.visible
|
||||||
onChangeFunction = {
|
onChangeFunction = {
|
||||||
canvas.axes.visible = (it.target as HTMLInputElement).checked
|
props.canvas.axes.visible = (it.target as HTMLInputElement).checked
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,11 +67,8 @@ public fun RBuilder.canvasControls(canvas: ThreeCanvas): ReactElement = accordio
|
|||||||
+"Export"
|
+"Export"
|
||||||
attrs {
|
attrs {
|
||||||
onClickFunction = {
|
onClickFunction = {
|
||||||
val json = (canvas.content as? SolidGroup)?.let { group ->
|
val json = (props.canvas.content as? SolidGroup)?.let { group ->
|
||||||
SolidManager.jsonForSolids.encodeToString(
|
visionManager.encodeToString(group)
|
||||||
SolidGroup.serializer(),
|
|
||||||
group
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
if (json != null) {
|
if (json != null) {
|
||||||
saveData(it, "object.json", "text/json") {
|
saveData(it, "object.json", "text/json") {
|
||||||
@ -82,9 +93,10 @@ public fun RBuilder.canvasControls(canvas: ThreeCanvas): ReactElement = accordio
|
|||||||
}
|
}
|
||||||
onChangeFunction = {
|
onChangeFunction = {
|
||||||
if ((it.target as HTMLInputElement).checked) {
|
if ((it.target as HTMLInputElement).checked) {
|
||||||
canvas.camera.layers.enable(layer)
|
props.canvas.camera.layers.enable(layer)
|
||||||
} else {
|
} else {
|
||||||
canvas.camera.layers.disable(layer)
|
props.canvas.camera.layers.disable(layer)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,10 +130,8 @@ public fun Element.displayCanvasControls(canvas: ThreeCanvas, block: TagConsumer
|
|||||||
+"Export"
|
+"Export"
|
||||||
onClickFunction = {
|
onClickFunction = {
|
||||||
val json = (canvas.content as? SolidGroup)?.let { group ->
|
val json = (canvas.content as? SolidGroup)?.let { group ->
|
||||||
SolidManager.jsonForSolids.encodeToString(
|
val visionManager = canvas.context.plugins.fetch(SolidManager).visionManager
|
||||||
SolidGroup.serializer(),
|
visionManager.encodeToString(group)
|
||||||
group
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
if (json != null) {
|
if (json != null) {
|
||||||
saveData(it, "object.json", "text/json") {
|
saveData(it, "object.json", "text/json") {
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package hep.dataforge.vision
|
package hep.dataforge.vision
|
||||||
|
|
||||||
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.meta.get
|
||||||
|
import hep.dataforge.meta.node
|
||||||
import hep.dataforge.names.*
|
import hep.dataforge.names.*
|
||||||
import kotlinx.serialization.Transient
|
import kotlinx.serialization.Transient
|
||||||
|
|
||||||
@ -7,7 +10,7 @@ import kotlinx.serialization.Transient
|
|||||||
/**
|
/**
|
||||||
* Abstract implementation of mutable group of [Vision]
|
* Abstract implementation of mutable group of [Vision]
|
||||||
*/
|
*/
|
||||||
abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup {
|
public abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup {
|
||||||
|
|
||||||
//protected abstract val _children: MutableMap<NameToken, T>
|
//protected abstract val _children: MutableMap<NameToken, T>
|
||||||
|
|
||||||
@ -22,9 +25,11 @@ abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup {
|
|||||||
/**
|
/**
|
||||||
* Update or create stylesheet
|
* Update or create stylesheet
|
||||||
*/
|
*/
|
||||||
fun styleSheet(block: StyleSheet.() -> Unit) {
|
public fun styleSheet(block: StyleSheet.() -> Unit) {
|
||||||
val res = styleSheet ?: StyleSheet(this).also { styleSheet = it }
|
if (styleSheet == null) {
|
||||||
res.block()
|
styleSheet = StyleSheet(this@AbstractVisionGroup)
|
||||||
|
}
|
||||||
|
styleSheet!!.block()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun propertyChanged(name: Name) {
|
override fun propertyChanged(name: Name) {
|
||||||
@ -34,18 +39,17 @@ abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Consider renaming to `StructureChangeListener` (singular)
|
private data class StructureChangeListener(val owner: Any?, val callback: (NameToken, Vision?) -> Unit)
|
||||||
private data class StructureChangeListeners(val owner: Any?, val callback: (Name, Vision?) -> Unit)
|
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
private val structureChangeListeners = HashSet<StructureChangeListeners>()
|
private val structureChangeListeners = HashSet<StructureChangeListener>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add listener for children change
|
* Add listener for children change
|
||||||
*/
|
*/
|
||||||
override fun onChildrenChange(owner: Any?, action: (Name, Vision?) -> Unit) {
|
override fun onChildrenChange(owner: Any?, action: (NameToken, Vision?) -> Unit) {
|
||||||
structureChangeListeners.add(
|
structureChangeListeners.add(
|
||||||
StructureChangeListeners(
|
StructureChangeListener(
|
||||||
owner,
|
owner,
|
||||||
action
|
action
|
||||||
)
|
)
|
||||||
@ -62,7 +66,7 @@ abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup {
|
|||||||
/**
|
/**
|
||||||
* Propagate children change event upwards
|
* Propagate children change event upwards
|
||||||
*/
|
*/
|
||||||
protected fun childrenChanged(name: Name, child: Vision?) {
|
protected fun childrenChanged(name: NameToken, child: Vision?) {
|
||||||
structureChangeListeners.forEach { it.callback(name, child) }
|
structureChangeListeners.forEach { it.callback(name, child) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,10 +81,11 @@ abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup {
|
|||||||
protected abstract fun setChild(token: NameToken, child: Vision)
|
protected abstract fun setChild(token: NameToken, child: Vision)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a static child. Statics could not be found by name, removed or replaced
|
* Add a static child. Statics could not be found by name, removed or replaced. Changing statics also do not trigger events.
|
||||||
*/
|
*/
|
||||||
protected open fun addStatic(child: Vision) =
|
protected open fun addStatic(child: Vision): Unit {
|
||||||
set(NameToken("@static(${child.hashCode()})").asName(), child)
|
setChild(NameToken("@static", index = child.hashCode().toString()), child)
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract fun createGroup(): AbstractVisionGroup
|
protected abstract fun createGroup(): AbstractVisionGroup
|
||||||
|
|
||||||
@ -124,6 +129,7 @@ abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup {
|
|||||||
when {
|
when {
|
||||||
name.isEmpty() -> {
|
name.isEmpty() -> {
|
||||||
if (child != null) {
|
if (child != null) {
|
||||||
|
attach(child)
|
||||||
addStatic(child)
|
addStatic(child)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,6 +141,7 @@ abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup {
|
|||||||
attach(child)
|
attach(child)
|
||||||
setChild(token, child)
|
setChild(token, child)
|
||||||
}
|
}
|
||||||
|
childrenChanged(token, child)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
//TODO add safety check
|
//TODO add safety check
|
||||||
@ -142,7 +149,13 @@ abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup {
|
|||||||
parent[name.tokens.last().asName()] = child
|
parent[name.tokens.last().asName()] = child
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
childrenChanged(name, child)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun update(meta: Meta) {
|
||||||
|
val styleMeta = meta.get("styleSheet").node
|
||||||
|
if (styleMeta != null) {
|
||||||
|
this.styleSheet?.update(styleMeta)
|
||||||
|
}
|
||||||
|
super.update(meta)
|
||||||
|
}
|
||||||
}
|
}
|
@ -235,12 +235,12 @@ public object Colors {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Convert three bytes representing color to Meta
|
// * Convert three bytes representing color to Meta
|
||||||
*/
|
// */
|
||||||
fun rgbToMeta(r: UByte, g: UByte, b: UByte): Meta = Meta {
|
// fun rgbToMeta(r: UByte, g: UByte, b: UByte): Meta = Meta {
|
||||||
RED_KEY put r.toInt()
|
// RED_KEY put r.toInt()
|
||||||
GREEN_KEY put g.toInt()
|
// GREEN_KEY put g.toInt()
|
||||||
BLUE_KEY put b.toInt()
|
// BLUE_KEY put b.toInt()
|
||||||
}
|
// }
|
||||||
}
|
}
|
@ -8,13 +8,10 @@ import kotlinx.serialization.Serializable
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("group")
|
@SerialName("group")
|
||||||
class SimpleVisionGroup : AbstractVisionGroup() {
|
public class SimpleVisionGroup : AbstractVisionGroup() {
|
||||||
|
|
||||||
override var styleSheet: StyleSheet? = null
|
override var styleSheet: StyleSheet? = null
|
||||||
|
|
||||||
//FIXME to be lifted to AbstractVisualGroup after https://github.com/Kotlin/kotlinx.serialization/issues/378 is fixed
|
|
||||||
override var properties: Config? = null
|
|
||||||
|
|
||||||
@SerialName("children")
|
@SerialName("children")
|
||||||
private val _children = HashMap<NameToken, Vision>()
|
private val _children = HashMap<NameToken, Vision>()
|
||||||
override val children: Map<NameToken, Vision> get() = _children
|
override val children: Map<NameToken, Vision> get() = _children
|
||||||
|
@ -16,11 +16,11 @@ import kotlinx.serialization.encoding.Encoder
|
|||||||
* A container for styles
|
* A container for styles
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
public class StyleSheet private constructor(private val styleMap: MutableMap<String, Meta> = LinkedHashMap()) {
|
public class StyleSheet private constructor(private val styleMap: MutableMap<String, Meta>) {
|
||||||
@Transient
|
@Transient
|
||||||
internal var owner: Vision? = null
|
internal var owner: Vision? = null
|
||||||
|
|
||||||
public constructor(owner: Vision) : this() {
|
public constructor(owner: Vision) : this(LinkedHashMap()) {
|
||||||
this.owner = owner
|
this.owner = owner
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,6 +91,10 @@ public class StyleSheet private constructor(private val styleMap: MutableMap<Str
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun StyleSheet.update(styleMeta: Meta){
|
||||||
|
TODO()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add style name to the list of styles to be resolved later. The style with given name does not necessary exist at the moment.
|
* Add style name to the list of styles to be resolved later. The style with given name does not necessary exist at the moment.
|
||||||
|
@ -69,7 +69,7 @@ public interface Vision : Configurable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update this vision using external meta.
|
* Update this vision using external meta. Children are not updated.
|
||||||
*/
|
*/
|
||||||
public fun update(meta: Meta)
|
public fun update(meta: Meta)
|
||||||
|
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
package hep.dataforge.vision
|
||||||
|
|
||||||
|
import hep.dataforge.meta.Config
|
||||||
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.meta.get
|
||||||
|
import hep.dataforge.meta.set
|
||||||
|
import hep.dataforge.names.NameToken
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
|
||||||
|
|
||||||
|
//public class VisionChange(public val properties: Meta, public val childrenChange: Map<NameToken, VisionChange>)
|
||||||
|
|
||||||
|
public class VisionChangeCollector(
|
||||||
|
public val manager: VisionManager,
|
||||||
|
public val scope: CoroutineScope,
|
||||||
|
public val vision: Vision,
|
||||||
|
public val lock: Mutex = Mutex()
|
||||||
|
) {
|
||||||
|
private val collector: Config = Config()
|
||||||
|
private val childrenCollectors = HashMap<NameToken, VisionChangeCollector>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
vision.onPropertyChange(this) { propertyName ->
|
||||||
|
collector[propertyName] = vision.properties?.get(propertyName)
|
||||||
|
}
|
||||||
|
if (vision is VisionGroup) {
|
||||||
|
vision.children.forEach { (token, child) ->
|
||||||
|
childrenCollectors[token] = VisionChangeCollector(manager, scope, child, lock)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (vision is MutableVisionGroup) {
|
||||||
|
TODO("Tread vision structure change")
|
||||||
|
// vision.onChildrenChange(this) { childName, child ->
|
||||||
|
// if(child == null){
|
||||||
|
// childrenCollectors[childName] = null
|
||||||
|
// } else {
|
||||||
|
// childrenCollectors[childName] = manager.encodeToMeta(child)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
//fun collectUpdates(manager: VisionManager, scope: CoroutineScope, vision: Vision): Flow<Meta> {
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// vision.
|
||||||
|
//}
|
@ -87,7 +87,7 @@ public interface MutableVisionGroup : VisionGroup, VisionContainerBuilder<Vision
|
|||||||
* @param owner the handler to properly remove listeners
|
* @param owner the handler to properly remove listeners
|
||||||
* @param action First argument of the action is the name of changed child. Second argument is the new value of the object.
|
* @param action First argument of the action is the name of changed child. Second argument is the new value of the object.
|
||||||
*/
|
*/
|
||||||
public fun onChildrenChange(owner: Any?, action: (Name, Vision?) -> Unit)
|
public fun onChildrenChange(owner: Any?, action: (NameToken, Vision?) -> Unit)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove children change listener
|
* Remove children change listener
|
||||||
|
@ -3,6 +3,10 @@ package hep.dataforge.vision
|
|||||||
import hep.dataforge.context.*
|
import hep.dataforge.context.*
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
import hep.dataforge.meta.descriptors.NodeDescriptor
|
import hep.dataforge.meta.descriptors.NodeDescriptor
|
||||||
|
import hep.dataforge.names.asName
|
||||||
|
import hep.dataforge.values.Null
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.json.JsonElement
|
import kotlinx.serialization.json.JsonElement
|
||||||
import kotlinx.serialization.modules.SerializersModule
|
import kotlinx.serialization.modules.SerializersModule
|
||||||
@ -10,7 +14,6 @@ import kotlinx.serialization.modules.polymorphic
|
|||||||
import kotlinx.serialization.modules.subclass
|
import kotlinx.serialization.modules.subclass
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
@DFExperimental
|
|
||||||
public class VisionManager(meta: Meta) : AbstractPlugin(meta) {
|
public class VisionManager(meta: Meta) : AbstractPlugin(meta) {
|
||||||
override val tag: PluginTag get() = Companion.tag
|
override val tag: PluginTag get() = Companion.tag
|
||||||
|
|
||||||
@ -50,35 +53,29 @@ public class VisionManager(meta: Meta) : AbstractPlugin(meta) {
|
|||||||
?: error("Expected node, but value found. Check your serializer!")
|
?: error("Expected node, but value found. Check your serializer!")
|
||||||
|
|
||||||
public fun updateVision(vision: Vision, meta: Meta) {
|
public fun updateVision(vision: Vision, meta: Meta) {
|
||||||
|
vision.update(meta)
|
||||||
|
if (vision is MutableVisionGroup) {
|
||||||
|
val children by meta.node()
|
||||||
|
children?.items?.forEach { (token, item) ->
|
||||||
|
when {
|
||||||
|
item.value == Null -> vision[token] = null //Null means removal
|
||||||
|
item.node != null -> {
|
||||||
|
val node = item.node!!
|
||||||
|
val type by node.string()
|
||||||
|
if (type != null) {
|
||||||
|
//If the type is present considering it as new node, not an update
|
||||||
|
vision[token.asName()] = decodeFromMeta(node)
|
||||||
|
} else {
|
||||||
|
val existing = vision.children[token]
|
||||||
|
if (existing != null) {
|
||||||
|
updateVision(existing, node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// public fun <T : Vision> VisionForm<T>.buildVision(meta: Meta, descriptor: NodeDescriptor? = null): T {
|
|
||||||
// val json = meta.toJson(descriptor)
|
|
||||||
// return jsonFormat.decodeFromJsonElement(serializer, json)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @OptIn(ExperimentalSerializationApi::class)
|
|
||||||
// public fun buildVision(meta: Meta): Vision {
|
|
||||||
// val type = meta["type"].string ?: Vision.serializer().descriptor.serialName
|
|
||||||
// val form = forms.values.find { it.name.toString() == type } ?: error("Could not resolve a form for type $type")
|
|
||||||
// return form.buildVision(meta)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public inline fun <reified T : Vision> buildSpecificVision(meta: Meta): T {
|
|
||||||
// val factory = resolveVisionForm(T::class)
|
|
||||||
// return factory.buildVision(meta)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public fun <T : Vision> writeVisionToMeta(vision: T): Meta {
|
|
||||||
// val form = resolveVisionForm(vision::class) ?: error("Could not resolve a form for $vision")
|
|
||||||
// val json = jsonFormat.encodeToJsonElement(form.serializer, vision)
|
|
||||||
// return json.toMetaItem().node!!
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public fun updateVision(vision: Vision, meta: Meta) {
|
|
||||||
// resolveVisionForm(vision::class).patch(vision, meta)
|
|
||||||
// }
|
|
||||||
|
|
||||||
public companion object : PluginFactory<VisionManager> {
|
public companion object : PluginFactory<VisionManager> {
|
||||||
override val tag: PluginTag = PluginTag(name = "vision", group = PluginTag.DATAFORGE_GROUP)
|
override val tag: PluginTag = PluginTag(name = "vision", group = PluginTag.DATAFORGE_GROUP)
|
||||||
|
@ -57,7 +57,7 @@ public class SolidGroup : AbstractVisionGroup(), Solid, PrototypeHolder {
|
|||||||
override var scale: Point3D? = null
|
override var scale: Point3D? = null
|
||||||
|
|
||||||
@SerialName("children")
|
@SerialName("children")
|
||||||
private val _children = HashMap<NameToken, Vision>()
|
private val _children = LinkedHashMap<NameToken, Vision>()
|
||||||
override val children: Map<NameToken, Vision> get() = _children
|
override val children: Map<NameToken, Vision> get() = _children
|
||||||
|
|
||||||
override fun attachChildren() {
|
override fun attachChildren() {
|
||||||
@ -122,7 +122,7 @@ internal class Prototypes(
|
|||||||
|
|
||||||
override fun removeChild(token: NameToken) {
|
override fun removeChild(token: NameToken) {
|
||||||
children.remove(token)
|
children.remove(token)
|
||||||
childrenChanged(token.asName(), null)
|
childrenChanged(token, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setChild(token: NameToken, child: Vision) {
|
override fun setChild(token: NameToken, child: Vision) {
|
||||||
|
@ -16,43 +16,7 @@ import kotlinx.serialization.json.Json
|
|||||||
import kotlinx.serialization.modules.*
|
import kotlinx.serialization.modules.*
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
//@OptIn(ExperimentalSerializationApi::class)
|
|
||||||
//@DFExperimental
|
|
||||||
//private fun SerializersModule.extractFactories(): List<SolidForm<*>> {
|
|
||||||
// val list = ArrayList<SolidForm<*>>()
|
|
||||||
//
|
|
||||||
// val collector = object : SerializersModuleCollector {
|
|
||||||
// override fun <T : Any> contextual(kClass: KClass<T>, serializer: KSerializer<T>) {
|
|
||||||
// //Do nothing
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun <Base : Any, Sub : Base> polymorphic(
|
|
||||||
// baseClass: KClass<Base>,
|
|
||||||
// actualClass: KClass<Sub>,
|
|
||||||
// actualSerializer: KSerializer<Sub>,
|
|
||||||
// ) {
|
|
||||||
// if (baseClass == Vision::class) {
|
|
||||||
// @Suppress("UNCHECKED_CAST") val factory: SolidForm<Solid> = SolidForm(
|
|
||||||
// actualClass as KClass<Solid>,
|
|
||||||
// actualSerializer as KSerializer<Solid>
|
|
||||||
// )
|
|
||||||
// list.add(factory)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun <Base : Any> polymorphicDefault(
|
|
||||||
// baseClass: KClass<Base>,
|
|
||||||
// defaultSerializerProvider: (className: String?) -> DeserializationStrategy<out Base>?,
|
|
||||||
// ) {
|
|
||||||
// TODO("Not yet implemented")
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
// dumpTo(collector)
|
|
||||||
// return list
|
|
||||||
//}
|
|
||||||
|
|
||||||
@DFExperimental
|
|
||||||
public class SolidManager(meta: Meta) : AbstractPlugin(meta) {
|
public class SolidManager(meta: Meta) : AbstractPlugin(meta) {
|
||||||
|
|
||||||
public val visionManager: VisionManager by require(VisionManager)
|
public val visionManager: VisionManager by require(VisionManager)
|
||||||
@ -96,18 +60,16 @@ public class SolidManager(meta: Meta) : AbstractPlugin(meta) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public val jsonForSolids = Json{
|
internal val jsonForSolids: Json = Json{
|
||||||
prettyPrint = true
|
prettyPrint = true
|
||||||
useArrayPolymorphism = false
|
useArrayPolymorphism = false
|
||||||
encodeDefaults = false
|
encodeDefaults = false
|
||||||
ignoreUnknownKeys = true
|
ignoreUnknownKeys = true
|
||||||
serializersModule = SolidManager.serializersModuleForSolids
|
serializersModule = serializersModuleForSolids
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(DFExperimental::class)
|
|
||||||
public fun encodeToString(solid: Solid): String = jsonForSolids.encodeToString(Vision.serializer(), solid)
|
public fun encodeToString(solid: Solid): String = jsonForSolids.encodeToString(Vision.serializer(), solid)
|
||||||
|
|
||||||
@OptIn(DFExperimental::class)
|
|
||||||
public fun decodeFromString(str: String): Vision = jsonForSolids.decodeFromString(Vision.serializer(), str).also {
|
public fun decodeFromString(str: String): Vision = jsonForSolids.decodeFromString(Vision.serializer(), str).also {
|
||||||
if(it is VisionGroup){
|
if(it is VisionGroup){
|
||||||
it.attachChildren()
|
it.attachChildren()
|
||||||
|
@ -91,7 +91,7 @@ public fun Solid.color(rgb: Int) {
|
|||||||
|
|
||||||
public fun Solid.color(r: UByte, g: UByte, b: UByte): Unit = setItem(
|
public fun Solid.color(r: UByte, g: UByte, b: UByte): Unit = setItem(
|
||||||
MATERIAL_COLOR_KEY,
|
MATERIAL_COLOR_KEY,
|
||||||
Colors.rgbToMeta(r, g, b)
|
Colors.rgbToString(r, g, b).asValue()
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,15 +1,20 @@
|
|||||||
package hep.dataforge.vision.solid.specifications
|
package hep.dataforge.vision.solid.specifications
|
||||||
|
|
||||||
import hep.dataforge.meta.Scheme
|
import hep.dataforge.meta.*
|
||||||
import hep.dataforge.meta.SchemeSpec
|
|
||||||
import hep.dataforge.meta.int
|
|
||||||
import hep.dataforge.meta.spec
|
|
||||||
|
|
||||||
public class Canvas3DOptions : Scheme() {
|
public class Canvas3DOptions : Scheme() {
|
||||||
public var axes: Axes by spec(Axes, Axes.empty())
|
public var axes: Axes by spec(Axes, Axes.empty())
|
||||||
public var camera: Camera by spec(Camera, Camera.empty())
|
public var camera: Camera by spec(Camera, Camera.empty())
|
||||||
public var controls: Controls by spec(Controls, Controls.empty())
|
public var controls: Controls by spec(Controls, Controls.empty())
|
||||||
|
|
||||||
public var minSize: Int by int(300)
|
public var minSize: Int by int(300)
|
||||||
|
public var minWith: Number by number { minSize }
|
||||||
|
public var minHeight: Number by number { minSize }
|
||||||
|
|
||||||
|
public var maxSize: Int by int(Int.MAX_VALUE)
|
||||||
|
public var maxWith: Number by number { maxSize }
|
||||||
|
public var maxHeight: Number by number { maxSize }
|
||||||
|
|
||||||
|
|
||||||
public companion object : SchemeSpec<Canvas3DOptions>(::Canvas3DOptions)
|
public companion object : SchemeSpec<Canvas3DOptions>(::Canvas3DOptions)
|
||||||
}
|
}
|
@ -4,6 +4,6 @@ import hep.dataforge.meta.Scheme
|
|||||||
import hep.dataforge.meta.SchemeSpec
|
import hep.dataforge.meta.SchemeSpec
|
||||||
|
|
||||||
|
|
||||||
class Controls : Scheme() {
|
public class Controls : Scheme() {
|
||||||
companion object : SchemeSpec<Controls>(::Controls)
|
public companion object : SchemeSpec<Controls>(::Controls)
|
||||||
}
|
}
|
@ -35,7 +35,7 @@ internal fun mergeChild(parent: VisionGroup, child: Vision): Vision {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@DFExperimental
|
@DFExperimental
|
||||||
object RemoveSingleChild : VisualTreeTransform<SolidGroup>() {
|
internal object RemoveSingleChild : VisualTreeTransform<SolidGroup>() {
|
||||||
|
|
||||||
override fun SolidGroup.transformInPlace() {
|
override fun SolidGroup.transformInPlace() {
|
||||||
fun MutableVisionGroup.replaceChildren() {
|
fun MutableVisionGroup.replaceChildren() {
|
||||||
|
@ -9,7 +9,7 @@ import hep.dataforge.vision.solid.Proxy
|
|||||||
import hep.dataforge.vision.solid.SolidGroup
|
import hep.dataforge.vision.solid.SolidGroup
|
||||||
|
|
||||||
@DFExperimental
|
@DFExperimental
|
||||||
object UnRef : VisualTreeTransform<SolidGroup>() {
|
internal object UnRef : VisualTreeTransform<SolidGroup>() {
|
||||||
private fun VisionGroup.countRefs(): Map<Name, Int> {
|
private fun VisionGroup.countRefs(): Map<Name, Int> {
|
||||||
return children.values.fold(HashMap()) { reducer, obj ->
|
return children.values.fold(HashMap()) { reducer, obj ->
|
||||||
if (obj is VisionGroup) {
|
if (obj is VisionGroup) {
|
||||||
|
@ -5,11 +5,11 @@ import hep.dataforge.vision.Vision
|
|||||||
/**
|
/**
|
||||||
* A root class for [Vision] tree optimization
|
* A root class for [Vision] tree optimization
|
||||||
*/
|
*/
|
||||||
abstract class VisualTreeTransform<T : Vision> {
|
public abstract class VisualTreeTransform<T : Vision> {
|
||||||
protected abstract fun T.transformInPlace()
|
protected abstract fun T.transformInPlace()
|
||||||
protected abstract fun T.clone(): T
|
protected abstract fun T.clone(): T
|
||||||
|
|
||||||
operator fun invoke(source: T, inPlace: Boolean = true): T {
|
public operator fun invoke(source: T, inPlace: Boolean = true): T {
|
||||||
val newSource = if (inPlace) {
|
val newSource = if (inPlace) {
|
||||||
source
|
source
|
||||||
} else {
|
} else {
|
||||||
@ -21,7 +21,7 @@ abstract class VisualTreeTransform<T : Vision> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Vision> T.transform(vararg transform: VisualTreeTransform<T>): T {
|
public fun <T : Vision> T.transform(vararg transform: VisualTreeTransform<T>): T {
|
||||||
var res = this
|
var res = this
|
||||||
transform.forEach {
|
transform.forEach {
|
||||||
res = it(res)
|
res = it(res)
|
||||||
@ -29,6 +29,6 @@ fun <T : Vision> T.transform(vararg transform: VisualTreeTransform<T>): T {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Vision> T.transformInPlace(vararg transform: VisualTreeTransform<in T>) {
|
public fun <T : Vision> T.transformInPlace(vararg transform: VisualTreeTransform<in T>) {
|
||||||
transform.forEach { it(this) }
|
transform.forEach { it(this) }
|
||||||
}
|
}
|
@ -2,6 +2,7 @@ package hep.dataforge.vision.solid.three
|
|||||||
|
|
||||||
import hep.dataforge.meta.boolean
|
import hep.dataforge.meta.boolean
|
||||||
import hep.dataforge.meta.node
|
import hep.dataforge.meta.node
|
||||||
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
import hep.dataforge.names.plus
|
import hep.dataforge.names.plus
|
||||||
import hep.dataforge.names.startsWith
|
import hep.dataforge.names.startsWith
|
||||||
@ -19,13 +20,13 @@ import kotlin.reflect.KClass
|
|||||||
/**
|
/**
|
||||||
* Basic geometry-based factory
|
* Basic geometry-based factory
|
||||||
*/
|
*/
|
||||||
abstract class MeshThreeFactory<in T : Solid>(
|
public abstract class MeshThreeFactory<in T : Solid>(
|
||||||
override val type: KClass<in T>
|
override val type: KClass<in T>
|
||||||
) : ThreeFactory<T> {
|
) : ThreeFactory<T> {
|
||||||
/**
|
/**
|
||||||
* Build a geometry for an object
|
* Build a geometry for an object
|
||||||
*/
|
*/
|
||||||
abstract fun buildGeometry(obj: T): BufferGeometry
|
public abstract fun buildGeometry(obj: T): BufferGeometry
|
||||||
|
|
||||||
override fun invoke(obj: T): Mesh {
|
override fun invoke(obj: T): Mesh {
|
||||||
val geometry = buildGeometry(obj)
|
val geometry = buildGeometry(obj)
|
||||||
@ -60,14 +61,14 @@ abstract class MeshThreeFactory<in T : Solid>(
|
|||||||
return mesh
|
return mesh
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
public companion object {
|
||||||
val EDGES_KEY = "edges".asName()
|
public val EDGES_KEY: Name = "edges".asName()
|
||||||
val WIREFRAME_KEY = "wireframe".asName()
|
public val WIREFRAME_KEY: Name = "wireframe".asName()
|
||||||
val ENABLED_KEY = "enabled".asName()
|
public val ENABLED_KEY: Name = "enabled".asName()
|
||||||
val EDGES_ENABLED_KEY = EDGES_KEY + ENABLED_KEY
|
public val EDGES_ENABLED_KEY: Name = EDGES_KEY + ENABLED_KEY
|
||||||
val EDGES_MATERIAL_KEY = EDGES_KEY + SolidMaterial.MATERIAL_KEY
|
public val EDGES_MATERIAL_KEY: Name = EDGES_KEY + SolidMaterial.MATERIAL_KEY
|
||||||
val WIREFRAME_ENABLED_KEY = WIREFRAME_KEY + ENABLED_KEY
|
public val WIREFRAME_ENABLED_KEY: Name = WIREFRAME_KEY + ENABLED_KEY
|
||||||
val WIREFRAME_MATERIAL_KEY = WIREFRAME_KEY + SolidMaterial.MATERIAL_KEY
|
public val WIREFRAME_MATERIAL_KEY: Name = WIREFRAME_KEY + SolidMaterial.MATERIAL_KEY
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,8 +4,8 @@ import hep.dataforge.vision.solid.Box
|
|||||||
import hep.dataforge.vision.solid.detail
|
import hep.dataforge.vision.solid.detail
|
||||||
import info.laht.threekt.geometries.BoxBufferGeometry
|
import info.laht.threekt.geometries.BoxBufferGeometry
|
||||||
|
|
||||||
object ThreeBoxFactory : MeshThreeFactory<Box>(Box::class) {
|
public object ThreeBoxFactory : MeshThreeFactory<Box>(Box::class) {
|
||||||
override fun buildGeometry(obj: Box) =
|
override fun buildGeometry(obj: Box): BoxBufferGeometry =
|
||||||
obj.detail?.let { detail ->
|
obj.detail?.let { detail ->
|
||||||
BoxBufferGeometry(obj.xSize, obj.ySize, obj.zSize, detail, detail, detail)
|
BoxBufferGeometry(obj.xSize, obj.ySize, obj.zSize, detail, detail, detail)
|
||||||
} ?: BoxBufferGeometry(obj.xSize, obj.ySize, obj.zSize)
|
} ?: BoxBufferGeometry(obj.xSize, obj.ySize, obj.zSize)
|
||||||
|
@ -35,7 +35,6 @@ import org.w3c.dom.HTMLElement
|
|||||||
import org.w3c.dom.Node
|
import org.w3c.dom.Node
|
||||||
import org.w3c.dom.events.MouseEvent
|
import org.w3c.dom.events.MouseEvent
|
||||||
import kotlin.math.cos
|
import kotlin.math.cos
|
||||||
import kotlin.math.max
|
|
||||||
import kotlin.math.sin
|
import kotlin.math.sin
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -112,7 +111,10 @@ public class ThreeCanvas(
|
|||||||
|
|
||||||
element.appendChild(renderer.domElement)
|
element.appendChild(renderer.domElement)
|
||||||
|
|
||||||
renderer.setSize(max(options.minSize, element.clientWidth), max(options.minSize, element.clientWidth))
|
renderer.setSize(
|
||||||
|
element.clientWidth.coerceIn(options.minWith.toInt()..options.maxWith.toInt()),
|
||||||
|
element.clientHeight.coerceIn(options.minHeight.toInt()..options.maxHeight.toInt())
|
||||||
|
)
|
||||||
|
|
||||||
window.onresize = {
|
window.onresize = {
|
||||||
renderer.setSize(element.clientWidth, element.clientWidth)
|
renderer.setSize(element.clientWidth, element.clientWidth)
|
||||||
@ -238,7 +240,7 @@ public class ThreeCanvas(
|
|||||||
}
|
}
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
public const val DO_NOT_HIGHLIGHT_TAG = "doNotHighlight"
|
public const val DO_NOT_HIGHLIGHT_TAG: String = "doNotHighlight"
|
||||||
private const val HIGHLIGHT_NAME = "@highlight"
|
private const val HIGHLIGHT_NAME = "@highlight"
|
||||||
private const val SELECT_NAME = "@select"
|
private const val SELECT_NAME = "@select"
|
||||||
}
|
}
|
||||||
@ -251,7 +253,8 @@ public fun ThreePlugin.output(
|
|||||||
): ThreeCanvas = ThreeCanvas(element, this, spec, onClick)
|
): ThreeCanvas = ThreeCanvas(element, this, spec, onClick)
|
||||||
|
|
||||||
public fun ThreePlugin.render(
|
public fun ThreePlugin.render(
|
||||||
element: HTMLElement, obj: Solid,
|
element: HTMLElement,
|
||||||
spec: Canvas3DOptions = Canvas3DOptions.empty(),
|
obj: Solid,
|
||||||
onClick: ((Name?) -> Unit)? = null,
|
onSelect: ((Name?) -> Unit)? = null,
|
||||||
): Unit = output(element, spec, onClick).render(obj)
|
options: Canvas3DOptions.() -> Unit = {},
|
||||||
|
): Unit = output(element, Canvas3DOptions(options), onSelect).render(obj)
|
@ -9,17 +9,17 @@ import info.laht.threekt.geometries.PlaneBufferGeometry
|
|||||||
import info.laht.threekt.materials.MeshBasicMaterial
|
import info.laht.threekt.materials.MeshBasicMaterial
|
||||||
import info.laht.threekt.objects.Mesh
|
import info.laht.threekt.objects.Mesh
|
||||||
import info.laht.threekt.textures.Texture
|
import info.laht.threekt.textures.Texture
|
||||||
|
import kotlinx.browser.document
|
||||||
import org.w3c.dom.CanvasRenderingContext2D
|
import org.w3c.dom.CanvasRenderingContext2D
|
||||||
import org.w3c.dom.CanvasTextBaseline
|
import org.w3c.dom.CanvasTextBaseline
|
||||||
import org.w3c.dom.HTMLCanvasElement
|
import org.w3c.dom.HTMLCanvasElement
|
||||||
import org.w3c.dom.MIDDLE
|
import org.w3c.dom.MIDDLE
|
||||||
import kotlin.browser.document
|
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Using example from http://stemkoski.github.io/Three.js/Texture-From-Canvas.html
|
* Using example from http://stemkoski.github.io/Three.js/Texture-From-Canvas.html
|
||||||
*/
|
*/
|
||||||
object ThreeCanvasLabelFactory : ThreeFactory<SolidLabel> {
|
public object ThreeCanvasLabelFactory : ThreeFactory<SolidLabel> {
|
||||||
override val type: KClass<in SolidLabel> get() = SolidLabel::class
|
override val type: KClass<in SolidLabel> get() = SolidLabel::class
|
||||||
|
|
||||||
override fun invoke(obj: SolidLabel): Object3D {
|
override fun invoke(obj: SolidLabel): Object3D {
|
||||||
|
@ -8,7 +8,7 @@ import info.laht.threekt.objects.Mesh
|
|||||||
/**
|
/**
|
||||||
* This should be inner, because it uses object builder
|
* This should be inner, because it uses object builder
|
||||||
*/
|
*/
|
||||||
class ThreeCompositeFactory(val three: ThreePlugin) : MeshThreeFactory<Composite>(Composite::class) {
|
public class ThreeCompositeFactory(public val three: ThreePlugin) : MeshThreeFactory<Composite>(Composite::class) {
|
||||||
|
|
||||||
override fun buildGeometry(obj: Composite): BufferGeometry {
|
override fun buildGeometry(obj: Composite): BufferGeometry {
|
||||||
val first = three.buildObject3D(obj.first) as? Mesh ?: error("First part of composite is not a mesh")
|
val first = three.buildObject3D(obj.first) as? Mesh ?: error("First part of composite is not a mesh")
|
||||||
|
@ -4,7 +4,7 @@ import hep.dataforge.vision.solid.Convex
|
|||||||
import info.laht.threekt.external.geometries.ConvexBufferGeometry
|
import info.laht.threekt.external.geometries.ConvexBufferGeometry
|
||||||
import info.laht.threekt.math.Vector3
|
import info.laht.threekt.math.Vector3
|
||||||
|
|
||||||
object ThreeConvexFactory : MeshThreeFactory<Convex>(Convex::class) {
|
public object ThreeConvexFactory : MeshThreeFactory<Convex>(Convex::class) {
|
||||||
override fun buildGeometry(obj: Convex): ConvexBufferGeometry {
|
override fun buildGeometry(obj: Convex): ConvexBufferGeometry {
|
||||||
@Suppress("USELESS_CAST") val vectors = obj.points.toTypedArray() as Array<Vector3>
|
@Suppress("USELESS_CAST") val vectors = obj.points.toTypedArray() as Array<Vector3>
|
||||||
return ConvexBufferGeometry(vectors)
|
return ConvexBufferGeometry(vectors)
|
||||||
|
@ -7,7 +7,7 @@ import info.laht.threekt.geometries.CylinderBufferGeometry
|
|||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
|
|
||||||
object ThreeCylinderFactory : MeshThreeFactory<ConeSegment>(ConeSegment::class) {
|
public object ThreeCylinderFactory : MeshThreeFactory<ConeSegment>(ConeSegment::class) {
|
||||||
override fun buildGeometry(obj: ConeSegment): BufferGeometry {
|
override fun buildGeometry(obj: ConeSegment): BufferGeometry {
|
||||||
val cylinder = obj.detail?.let {
|
val cylinder = obj.detail?.let {
|
||||||
val segments = it.toDouble().pow(0.5).toInt()
|
val segments = it.toDouble().pow(0.5).toInt()
|
||||||
|
@ -18,21 +18,21 @@ import kotlin.reflect.KClass
|
|||||||
* Builder and updater for three.js object
|
* Builder and updater for three.js object
|
||||||
*/
|
*/
|
||||||
@Type(TYPE)
|
@Type(TYPE)
|
||||||
interface ThreeFactory<in T : Vision> {
|
public interface ThreeFactory<in T : Vision> {
|
||||||
|
|
||||||
val type: KClass<in T>
|
public val type: KClass<in T>
|
||||||
|
|
||||||
operator fun invoke(obj: T): Object3D
|
public operator fun invoke(obj: T): Object3D
|
||||||
|
|
||||||
companion object {
|
public companion object {
|
||||||
const val TYPE = "threeFactory"
|
public const val TYPE: String = "threeFactory"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update position, rotation and visibility
|
* Update position, rotation and visibility
|
||||||
*/
|
*/
|
||||||
fun Object3D.updatePosition(obj: Vision) {
|
public fun Object3D.updatePosition(obj: Vision) {
|
||||||
visible = obj.visible ?: true
|
visible = obj.visible ?: true
|
||||||
if(obj is Solid) {
|
if(obj is Solid) {
|
||||||
position.set(obj.x, obj.y, obj.z)
|
position.set(obj.x, obj.y, obj.z)
|
||||||
@ -45,7 +45,7 @@ fun Object3D.updatePosition(obj: Vision) {
|
|||||||
/**
|
/**
|
||||||
* Update non-position non-geometry property
|
* Update non-position non-geometry property
|
||||||
*/
|
*/
|
||||||
fun Object3D.updateProperty(source: Vision, propertyName: Name) {
|
public fun Object3D.updateProperty(source: Vision, propertyName: Name) {
|
||||||
if (this is Mesh && propertyName.startsWith(MATERIAL_KEY)) {
|
if (this is Mesh && propertyName.startsWith(MATERIAL_KEY)) {
|
||||||
this.material = getMaterial(source, false)
|
this.material = getMaterial(source, false)
|
||||||
} else if (
|
} else if (
|
||||||
@ -63,7 +63,7 @@ fun Object3D.updateProperty(source: Vision, propertyName: Name) {
|
|||||||
/**
|
/**
|
||||||
* Generic factory for elements which provide inside geometry builder
|
* Generic factory for elements which provide inside geometry builder
|
||||||
*/
|
*/
|
||||||
object ThreeShapeFactory : MeshThreeFactory<GeometrySolid>(GeometrySolid::class) {
|
public object ThreeShapeFactory : MeshThreeFactory<GeometrySolid>(GeometrySolid::class) {
|
||||||
override fun buildGeometry(obj: GeometrySolid): BufferGeometry {
|
override fun buildGeometry(obj: GeometrySolid): BufferGeometry {
|
||||||
return obj.run {
|
return obj.run {
|
||||||
ThreeGeometryBuilder().apply { toGeometry(this) }.build()
|
ThreeGeometryBuilder().apply { toGeometry(this) }.build()
|
||||||
|
@ -12,7 +12,7 @@ import kotlin.reflect.KClass
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
object ThreeLabelFactory : ThreeFactory<SolidLabel> {
|
public object ThreeLabelFactory : ThreeFactory<SolidLabel> {
|
||||||
override val type: KClass<in SolidLabel> get() = SolidLabel::class
|
override val type: KClass<in SolidLabel> get() = SolidLabel::class
|
||||||
|
|
||||||
override fun invoke(obj: SolidLabel): Object3D {
|
override fun invoke(obj: SolidLabel): Object3D {
|
||||||
|
@ -10,7 +10,7 @@ import info.laht.threekt.math.Color
|
|||||||
import info.laht.threekt.objects.LineSegments
|
import info.laht.threekt.objects.LineSegments
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
object ThreeLineFactory : ThreeFactory<PolyLine> {
|
public object ThreeLineFactory : ThreeFactory<PolyLine> {
|
||||||
override val type: KClass<PolyLine> get() = PolyLine::class
|
override val type: KClass<PolyLine> get() = PolyLine::class
|
||||||
|
|
||||||
override fun invoke(obj: PolyLine): Object3D {
|
override fun invoke(obj: PolyLine): Object3D {
|
||||||
|
@ -11,7 +11,7 @@ import kotlin.collections.set
|
|||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import info.laht.threekt.objects.Group as ThreeGroup
|
import info.laht.threekt.objects.Group as ThreeGroup
|
||||||
|
|
||||||
class ThreePlugin : AbstractPlugin() {
|
public class ThreePlugin : AbstractPlugin() {
|
||||||
override val tag: PluginTag get() = Companion.tag
|
override val tag: PluginTag get() = Companion.tag
|
||||||
|
|
||||||
private val objectFactories = HashMap<KClass<out Solid>, ThreeFactory<*>>()
|
private val objectFactories = HashMap<KClass<out Solid>, ThreeFactory<*>>()
|
||||||
@ -35,9 +35,9 @@ class ThreePlugin : AbstractPlugin() {
|
|||||||
as ThreeFactory<Solid>?
|
as ThreeFactory<Solid>?
|
||||||
}
|
}
|
||||||
|
|
||||||
fun buildObject3D(obj: Solid): Object3D {
|
public fun buildObject3D(obj: Solid): Object3D {
|
||||||
return when (obj) {
|
return when (obj) {
|
||||||
is ThreeVision -> obj.toObject3D()
|
is ThreeVision -> obj.render()
|
||||||
is Proxy -> proxyFactory(obj)
|
is Proxy -> proxyFactory(obj)
|
||||||
is SolidGroup -> {
|
is SolidGroup -> {
|
||||||
val group = ThreeGroup()
|
val group = ThreeGroup()
|
||||||
@ -69,17 +69,17 @@ class ThreePlugin : AbstractPlugin() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.onChildrenChange(this) { name, child ->
|
obj.onChildrenChange(this) { nameToken, child ->
|
||||||
if (name.isEmpty()) {
|
// if (name.isEmpty()) {
|
||||||
logger.error { "Children change with empty name on $group" }
|
// logger.error { "Children change with empty name on $group" }
|
||||||
return@onChildrenChange
|
// return@onChildrenChange
|
||||||
}
|
// }
|
||||||
|
|
||||||
// val parentName = name.cutLast()
|
// val parentName = name.cutLast()
|
||||||
// val childName = name.last()!!
|
// val childName = name.last()!!
|
||||||
|
|
||||||
//removing old object
|
//removing old object
|
||||||
findChild(name)?.let { oldChild ->
|
findChild(nameToken.asName())?.let { oldChild ->
|
||||||
oldChild.parent?.remove(oldChild)
|
oldChild.parent?.remove(oldChild)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,7 +87,7 @@ class ThreePlugin : AbstractPlugin() {
|
|||||||
if (child != null && child is Solid) {
|
if (child != null && child is Solid) {
|
||||||
try {
|
try {
|
||||||
val object3D = buildObject3D(child)
|
val object3D = buildObject3D(child)
|
||||||
set(name, object3D)
|
set(nameToken, object3D)
|
||||||
} catch (ex: Throwable) {
|
} catch (ex: Throwable) {
|
||||||
logger.error(ex) { "Failed to render $child" }
|
logger.error(ex) { "Failed to render $child" }
|
||||||
}
|
}
|
||||||
@ -108,10 +108,10 @@ class ThreePlugin : AbstractPlugin() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : PluginFactory<ThreePlugin> {
|
public companion object : PluginFactory<ThreePlugin> {
|
||||||
override val tag = PluginTag("visual.three", PluginTag.DATAFORGE_GROUP)
|
override val tag: PluginTag = PluginTag("visual.three", PluginTag.DATAFORGE_GROUP)
|
||||||
override val type = ThreePlugin::class
|
override val type: KClass<ThreePlugin> = ThreePlugin::class
|
||||||
override fun invoke(meta: Meta, context: Context) = ThreePlugin()
|
override fun invoke(meta: Meta, context: Context): ThreePlugin = ThreePlugin()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import info.laht.threekt.core.Object3D
|
|||||||
import info.laht.threekt.objects.Mesh
|
import info.laht.threekt.objects.Mesh
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
class ThreeProxyFactory(val three: ThreePlugin) : ThreeFactory<Proxy> {
|
public class ThreeProxyFactory(public val three: ThreePlugin) : ThreeFactory<Proxy> {
|
||||||
private val cache = HashMap<Solid, Object3D>()
|
private val cache = HashMap<Solid, Object3D>()
|
||||||
|
|
||||||
override val type: KClass<Proxy> = Proxy::class
|
override val type: KClass<Proxy> = Proxy::class
|
||||||
|
@ -5,7 +5,7 @@ import hep.dataforge.vision.solid.detail
|
|||||||
import info.laht.threekt.core.BufferGeometry
|
import info.laht.threekt.core.BufferGeometry
|
||||||
import info.laht.threekt.geometries.SphereBufferGeometry
|
import info.laht.threekt.geometries.SphereBufferGeometry
|
||||||
|
|
||||||
object ThreeSphereFactory : MeshThreeFactory<Sphere>(Sphere::class) {
|
public object ThreeSphereFactory : MeshThreeFactory<Sphere>(Sphere::class) {
|
||||||
override fun buildGeometry(obj: Sphere): BufferGeometry {
|
override fun buildGeometry(obj: Sphere): BufferGeometry {
|
||||||
return obj.detail?.let {detail ->
|
return obj.detail?.let {detail ->
|
||||||
SphereBufferGeometry(
|
SphereBufferGeometry(
|
||||||
|
@ -8,11 +8,6 @@ import kotlinx.serialization.Serializable
|
|||||||
/**
|
/**
|
||||||
* A custom visual object that has its own Three.js renderer
|
* A custom visual object that has its own Three.js renderer
|
||||||
*/
|
*/
|
||||||
public interface ThreeVision : Solid {
|
public abstract class ThreeVision : BasicSolid() {
|
||||||
public fun toObject3D(): Object3D
|
public abstract fun render(): Object3D
|
||||||
}
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
public class CustomThreeVision(public val threeFactory: ThreeFactory<Solid>) : BasicSolid(), ThreeVision {
|
|
||||||
override fun toObject3D(): Object3D = threeFactory(this)
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user