diff --git a/demo/sat-demo/build.gradle.kts b/demo/sat-demo/build.gradle.kts new file mode 100644 index 00000000..0e623614 --- /dev/null +++ b/demo/sat-demo/build.gradle.kts @@ -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 { + + } + } + } +} \ No newline at end of file diff --git a/demo/sat-demo/src/commonMain/kotlin/ru/mipt/npm/sat/geometry.kt b/demo/sat-demo/src/commonMain/kotlin/ru/mipt/npm/sat/geometry.kt new file mode 100644 index 00000000..c9c1512f --- /dev/null +++ b/demo/sat-demo/src/commonMain/kotlin/ru/mipt/npm/sat/geometry.kt @@ -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") + } + } + } + } + } +} + diff --git a/demo/sat-demo/src/jsMain/kotlin/ru/mipt/npm/sat/SatDemoApp.kt b/demo/sat-demo/src/jsMain/kotlin/ru/mipt/npm/sat/SatDemoApp.kt new file mode 100644 index 00000000..d3c03541 --- /dev/null +++ b/demo/sat-demo/src/jsMain/kotlin/ru/mipt/npm/sat/SatDemoApp.kt @@ -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) { + 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) +} \ No newline at end of file diff --git a/demo/sat-demo/src/jsMain/resources/index.html b/demo/sat-demo/src/jsMain/resources/index.html new file mode 100644 index 00000000..0fd32551 --- /dev/null +++ b/demo/sat-demo/src/jsMain/resources/index.html @@ -0,0 +1,12 @@ + + + + + + Three js demo for particle physics + + + +
+ + \ No newline at end of file diff --git a/demo/spatial-showcase/build.gradle.kts b/demo/spatial-showcase/build.gradle.kts index 40c4b04d..87140138 100644 --- a/demo/spatial-showcase/build.gradle.kts +++ b/demo/spatial-showcase/build.gradle.kts @@ -6,6 +6,7 @@ plugins { } kscience { + useCoroutines() val fxVersion: String by rootProject.extra useFx(FXModule.CONTROLS, version = fxVersion, configuration = DependencyConfiguration.IMPLEMENTATION) application() diff --git a/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vision/solid/demo/ThreeDemoApp.kt b/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vision/solid/demo/ThreeDemoApp.kt index 2be73f5e..0bcd047b 100644 --- a/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vision/solid/demo/ThreeDemoApp.kt +++ b/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vision/solid/demo/ThreeDemoApp.kt @@ -2,7 +2,14 @@ package hep.dataforge.vision.solid.demo import hep.dataforge.js.Application 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 { @@ -13,27 +20,25 @@ private class ThreeDemoApp : Application { ThreeDemoGrid(element).run { showcase() showcaseCSG() -// demo("dynamicBox", "Dancing boxes") { -// val boxes = (-10..10).flatMap { i -> -// (-10..10).map { j -> -// varBox(10, 10, 0, name = "cell_${i}_${j}") { -// x = i * 10 -// y = j * 10 -// value = 128 -// setProperty(EDGES_ENABLED_KEY, false) -// setProperty(WIREFRAME_ENABLED_KEY, false) -// } -// } -// } -// GlobalScope.launch { -// while (isActive) { -// delay(500) -// boxes.forEach { box -> -// box.value = (box.value + Random.nextInt(-15, 15)).coerceIn(0..255) -// } -// } -// } -// } + demo("dynamicBox", "Dancing boxes") { + val boxes = (-10..10).flatMap { i -> + (-10..10).map { j -> + varBox(10, 10, 0, name = "cell_${i}_${j}") { + x = i * 10 + y = j * 10 + value = 128 + } + } + } + GlobalScope.launch { + while (isActive) { + delay(500) + boxes.forEach { box -> + box.value = (box.value + Random.nextInt(-15, 15)).coerceIn(1..255) + } + } + } + } } diff --git a/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vision/solid/demo/ThreeDemoGrid.kt b/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vision/solid/demo/ThreeDemoGrid.kt index 84a73d0d..d8420d6f 100644 --- a/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vision/solid/demo/ThreeDemoGrid.kt +++ b/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vision/solid/demo/ThreeDemoGrid.kt @@ -11,6 +11,8 @@ import hep.dataforge.vision.Vision import hep.dataforge.vision.solid.three.ThreeCanvas import hep.dataforge.vision.solid.three.ThreePlugin import hep.dataforge.vision.solid.three.output +import kotlinx.browser.document +import kotlinx.dom.clear import kotlinx.html.dom.append import kotlinx.html.dom.create import kotlinx.html.h2 @@ -19,8 +21,6 @@ import kotlinx.html.id import kotlinx.html.js.div import kotlinx.html.span import org.w3c.dom.Element -import kotlin.browser.document -import kotlin.dom.clear import kotlin.reflect.KClass class ThreeDemoGrid(element: Element, meta: Meta = Meta.EMPTY) : OutputManager { diff --git a/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vision/solid/demo/VariableBox.kt b/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vision/solid/demo/VariableBox.kt index abe6097b..c5f023ff 100644 --- a/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vision/solid/demo/VariableBox.kt +++ b/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vision/solid/demo/VariableBox.kt @@ -4,6 +4,7 @@ package hep.dataforge.vision.solid.demo import hep.dataforge.meta.int import hep.dataforge.meta.number +import hep.dataforge.meta.set import hep.dataforge.meta.setItem import hep.dataforge.names.plus import hep.dataforge.names.startsWith @@ -12,7 +13,6 @@ import hep.dataforge.vision.getProperty import hep.dataforge.vision.set import hep.dataforge.vision.solid.* 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.ThreeMaterials.getMaterial import info.laht.threekt.core.BufferGeometry @@ -21,86 +21,89 @@ import info.laht.threekt.geometries.BoxBufferGeometry import info.laht.threekt.objects.Mesh import kotlinx.serialization.UseSerializers import kotlin.math.max -import kotlin.reflect.KClass -internal var Solid.variableZSize: Number - 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( +internal fun SolidGroup.varBox( xSize: Number, ySize: Number, zSize: Number, name: String = "", - action: Solid.() -> Unit = {} -) = CustomThreeVision(VariableBoxThreeFactory).apply { - scaleX = xSize - scaleY = ySize - scaleZ = zSize -}.apply(action).also { set(name, it) } + action: VariableBox.() -> Unit = {}, +): VariableBox = VariableBox(xSize, ySize, zSize).apply(action).also { set(name, it) } -private object VariableBoxThreeFactory : ThreeFactory { - val X_SIZE_KEY = GEOMETRY_KEY + "xSize" - val Y_SIZE_KEY = GEOMETRY_KEY + "ySize" - val Z_SIZE_KEY = GEOMETRY_KEY + "zSize" +internal class VariableBox(xSize: Number, ySize: Number, zSize: Number) : ThreeVision() { + init { + scaleX = xSize + scaleY = ySize + scaleZ = zSize + config[MeshThreeFactory.EDGES_ENABLED_KEY] = false + config[MeshThreeFactory.WIREFRAME_ENABLED_KEY] = false + } - override val type: KClass 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 + override fun render(): Object3D { + val xSize = getProperty(X_SIZE_KEY, false).number?.toDouble() ?: 1.0 + val ySize = getProperty(Y_SIZE_KEY, false).number?.toDouble() ?: 1.0 + val zSize = getProperty(Z_SIZE_KEY, false).number?.toDouble() ?: 1.0 val geometry = BoxBufferGeometry(1, 1, 1) //JS sometimes tries to pass Geometry as BufferGeometry @Suppress("USELESS_IS_CHECK") if (geometry !is BufferGeometry) error("BufferGeometry expected") - val mesh = Mesh(geometry, getMaterial(obj,true)).apply { - applyEdges(obj) - applyWireFrame(obj) + val mesh = Mesh(geometry, getMaterial(this@VariableBox, true)).apply { + applyEdges(this@VariableBox) + applyWireFrame(this@VariableBox) //set position for mesh - updatePosition(obj) + updatePosition(this@VariableBox) - layers.enable(obj.layer) + layers.enable(this@VariableBox.layer) children.forEach { - it.layers.enable(obj.layer) + it.layers.enable(this@VariableBox.layer) } } mesh.scale.set(xSize, ySize, zSize) //add listener to object properties - obj.onPropertyChange(this) { name -> + onPropertyChange(mesh) { name -> when { -// name.startsWith(GEOMETRY_KEY) -> { -// val newXSize = obj.getProperty(X_SIZE_KEY, false).number?.toDouble() ?: 1.0 -// val newYSize = obj.getProperty(Y_SIZE_KEY, false).number?.toDouble() ?: 1.0 -// val newZSize = obj.getProperty(Z_SIZE_KEY, false).number?.toDouble() ?: 1.0 -// mesh.scale.set(newXSize, newYSize, newZSize) -// mesh.updateMatrix() -// } - name.startsWith(MeshThreeFactory.WIREFRAME_KEY) -> mesh.applyWireFrame(obj) - name.startsWith(MeshThreeFactory.EDGES_KEY) -> mesh.applyEdges(obj) - else -> mesh.updateProperty(obj, name) + name.startsWith(GEOMETRY_KEY) -> { + val newXSize = getProperty(X_SIZE_KEY, false).number?.toDouble() ?: 1.0 + val newYSize = getProperty(Y_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.updateMatrix() + } + name.startsWith(MeshThreeFactory.WIREFRAME_KEY) -> mesh.applyWireFrame(this@VariableBox) + name.startsWith(MeshThreeFactory.EDGES_KEY) -> mesh.applyEdges(this@VariableBox) + else -> mesh.updateProperty(this@VariableBox, name) } } 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" + } } \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 8ab3e4e4..55158bb5 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -43,5 +43,6 @@ include( ":demo:spatial-showcase", ":demo:gdml", ":demo:muon-monitor", + ":demo:sat-demo", ":playground" ) diff --git a/ui/bootstrap/src/main/kotlin/hep/dataforge/vision/bootstrap/outputConfig.kt b/ui/bootstrap/src/main/kotlin/hep/dataforge/vision/bootstrap/outputConfig.kt index e3579fc0..4d039b92 100644 --- a/ui/bootstrap/src/main/kotlin/hep/dataforge/vision/bootstrap/outputConfig.kt +++ b/ui/bootstrap/src/main/kotlin/hep/dataforge/vision/bootstrap/outputConfig.kt @@ -1,6 +1,5 @@ package hep.dataforge.vision.bootstrap -import hep.dataforge.meta.DFExperimental import hep.dataforge.vision.solid.SolidGroup import hep.dataforge.vision.solid.SolidManager 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.files.Blob import org.w3c.files.BlobPropertyBag -import react.RBuilder -import react.ReactElement +import react.* import react.dom.button import react.dom.div import react.dom.input @@ -31,37 +29,51 @@ private fun saveData(event: Event, fileName: String, mimeType: String = "text/pl fileSaver.saveAs(blob, fileName) } -@OptIn(DFExperimental::class) -public fun RBuilder.canvasControls(canvas: ThreeCanvas): ReactElement = accordion("controls") { - entry("Settings") { - div("row") { - div("col-2") { - label("checkbox-inline") { - input(type = InputType.checkBox) { - attrs { - defaultChecked = canvas.axes.visible - onChangeFunction = { - canvas.axes.visible = (it.target as HTMLInputElement).checked +public fun RBuilder.canvasControls(canvas: ThreeCanvas): ReactElement { + return child(CanvasControls){ + attrs{ + this.canvas = canvas + } + } +} + +public external interface CanvasControlsProps : RProps { + public var canvas: ThreeCanvas +} + +public val CanvasControls: FunctionalComponent = functionalComponent ("CanvasControls") { props -> + val visionManager = useMemo( + { props.canvas.context.plugins.fetch(SolidManager).visionManager }, + arrayOf(props.canvas) + ) + accordion("controls") { + entry("Settings") { + div("row") { + div("col-2") { + label("checkbox-inline") { + input(type = InputType.checkBox) { + attrs { + defaultChecked = props.canvas.axes.visible + onChangeFunction = { + props.canvas.axes.visible = (it.target as HTMLInputElement).checked + } } } + +"Axes" } - +"Axes" } - } - div("col-1") { - button { - +"Export" - attrs { - onClickFunction = { - val json = (canvas.content as? SolidGroup)?.let { group -> - SolidManager.jsonForSolids.encodeToString( - SolidGroup.serializer(), - group - ) - } - if (json != null) { - saveData(it, "object.json", "text/json") { - json + div("col-1") { + button { + +"Export" + attrs { + onClickFunction = { + val json = (props.canvas.content as? SolidGroup)?.let { group -> + visionManager.encodeToString(group) + } + if (json != null) { + saveData(it, "object.json", "text/json") { + json + } } } } @@ -69,22 +81,22 @@ public fun RBuilder.canvasControls(canvas: ThreeCanvas): ReactElement = accordio } } } - } - entry("Layers") { - div("row") { - (0..11).forEach { layer -> - div("col-1") { - label { +layer.toString() } - input(type = InputType.checkBox) { - attrs { - if (layer == 0) { - defaultChecked = true - } - onChangeFunction = { - if ((it.target as HTMLInputElement).checked) { - canvas.camera.layers.enable(layer) - } else { - canvas.camera.layers.disable(layer) + entry("Layers") { + div("row") { + (0..11).forEach { layer -> + div("col-1") { + label { +layer.toString() } + input(type = InputType.checkBox) { + attrs { + if (layer == 0) { + defaultChecked = true + } + onChangeFunction = { + if ((it.target as HTMLInputElement).checked) { + props.canvas.camera.layers.enable(layer) + } else { + props.canvas.camera.layers.disable(layer) + } } } } @@ -118,10 +130,8 @@ public fun Element.displayCanvasControls(canvas: ThreeCanvas, block: TagConsumer +"Export" onClickFunction = { val json = (canvas.content as? SolidGroup)?.let { group -> - SolidManager.jsonForSolids.encodeToString( - SolidGroup.serializer(), - group - ) + val visionManager = canvas.context.plugins.fetch(SolidManager).visionManager + visionManager.encodeToString(group) } if (json != null) { saveData(it, "object.json", "text/json") { diff --git a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/AbstractVisionGroup.kt b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/AbstractVisionGroup.kt index f2c343d6..c6d05e8c 100644 --- a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/AbstractVisionGroup.kt +++ b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/AbstractVisionGroup.kt @@ -1,5 +1,8 @@ package hep.dataforge.vision +import hep.dataforge.meta.Meta +import hep.dataforge.meta.get +import hep.dataforge.meta.node import hep.dataforge.names.* import kotlinx.serialization.Transient @@ -7,7 +10,7 @@ import kotlinx.serialization.Transient /** * Abstract implementation of mutable group of [Vision] */ -abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup { +public abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup { //protected abstract val _children: MutableMap @@ -22,30 +25,31 @@ abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup { /** * Update or create stylesheet */ - fun styleSheet(block: StyleSheet.() -> Unit) { - val res = styleSheet ?: StyleSheet(this).also { styleSheet = it } - res.block() + public fun styleSheet(block: StyleSheet.() -> Unit) { + if (styleSheet == null) { + styleSheet = StyleSheet(this@AbstractVisionGroup) + } + styleSheet!!.block() } override fun propertyChanged(name: Name) { super.propertyChanged(name) - for(obj in this) { + for (obj in this) { obj.propertyChanged(name) } } - // TODO Consider renaming to `StructureChangeListener` (singular) - private data class StructureChangeListeners(val owner: Any?, val callback: (Name, Vision?) -> Unit) + private data class StructureChangeListener(val owner: Any?, val callback: (NameToken, Vision?) -> Unit) @Transient - private val structureChangeListeners = HashSet() + private val structureChangeListeners = HashSet() /** * 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( + StructureChangeListener( owner, action ) @@ -62,7 +66,7 @@ abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup { /** * 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) } } @@ -77,10 +81,11 @@ abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup { 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) = - set(NameToken("@static(${child.hashCode()})").asName(), child) + protected open fun addStatic(child: Vision): Unit { + setChild(NameToken("@static", index = child.hashCode().toString()), child) + } protected abstract fun createGroup(): AbstractVisionGroup @@ -124,6 +129,7 @@ abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup { when { name.isEmpty() -> { if (child != null) { + attach(child) addStatic(child) } } @@ -135,6 +141,7 @@ abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup { attach(child) setChild(token, child) } + childrenChanged(token, child) } else -> { //TODO add safety check @@ -142,7 +149,13 @@ abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup { 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) + } } \ No newline at end of file diff --git a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/Colors.kt b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/Colors.kt index 1b3d4763..c8d18a08 100644 --- a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/Colors.kt +++ b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/Colors.kt @@ -235,12 +235,12 @@ public object Colors { } } - /** - * Convert three bytes representing color to Meta - */ - fun rgbToMeta(r: UByte, g: UByte, b: UByte): Meta = Meta { - RED_KEY put r.toInt() - GREEN_KEY put g.toInt() - BLUE_KEY put b.toInt() - } +// /** +// * Convert three bytes representing color to Meta +// */ +// fun rgbToMeta(r: UByte, g: UByte, b: UByte): Meta = Meta { +// RED_KEY put r.toInt() +// GREEN_KEY put g.toInt() +// BLUE_KEY put b.toInt() +// } } \ No newline at end of file diff --git a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/SimpleVisionGroup.kt b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/SimpleVisionGroup.kt index 4a73bd14..69a28f07 100644 --- a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/SimpleVisionGroup.kt +++ b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/SimpleVisionGroup.kt @@ -8,13 +8,10 @@ import kotlinx.serialization.Serializable @Serializable @SerialName("group") -class SimpleVisionGroup : AbstractVisionGroup() { +public class SimpleVisionGroup : AbstractVisionGroup() { 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") private val _children = HashMap() override val children: Map get() = _children diff --git a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/StyleSheet.kt b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/StyleSheet.kt index 0a5f27e5..fa5ef9e9 100644 --- a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/StyleSheet.kt +++ b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/StyleSheet.kt @@ -16,11 +16,11 @@ import kotlinx.serialization.encoding.Encoder * A container for styles */ @Serializable -public class StyleSheet private constructor(private val styleMap: MutableMap = LinkedHashMap()) { +public class StyleSheet private constructor(private val styleMap: MutableMap) { @Transient internal var owner: Vision? = null - public constructor(owner: Vision) : this() { + public constructor(owner: Vision) : this(LinkedHashMap()) { this.owner = owner } @@ -91,6 +91,10 @@ public class StyleSheet private constructor(private val styleMap: MutableMap) + +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() + + 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 { +// +// +// vision. +//} diff --git a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionGroup.kt b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionGroup.kt index 3035e18d..004693a2 100644 --- a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionGroup.kt +++ b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionGroup.kt @@ -87,7 +87,7 @@ public interface MutableVisionGroup : VisionGroup, VisionContainerBuilder Unit) + public fun onChildrenChange(owner: Any?, action: (NameToken, Vision?) -> Unit) /** * Remove children change listener diff --git a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionManager.kt b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionManager.kt index a1e5170c..3e417935 100644 --- a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionManager.kt +++ b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionManager.kt @@ -3,6 +3,10 @@ package hep.dataforge.vision import hep.dataforge.context.* import hep.dataforge.meta.* 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.JsonElement import kotlinx.serialization.modules.SerializersModule @@ -10,7 +14,6 @@ import kotlinx.serialization.modules.polymorphic import kotlinx.serialization.modules.subclass import kotlin.reflect.KClass -@DFExperimental public class VisionManager(meta: Meta) : AbstractPlugin(meta) { override val tag: PluginTag get() = Companion.tag @@ -50,36 +53,30 @@ public class VisionManager(meta: Meta) : AbstractPlugin(meta) { ?: error("Expected node, but value found. Check your serializer!") 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 VisionForm.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 buildSpecificVision(meta: Meta): T { -// val factory = resolveVisionForm(T::class) -// return factory.buildVision(meta) -// } -// -// public fun 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 { override val tag: PluginTag = PluginTag(name = "vision", group = PluginTag.DATAFORGE_GROUP) override val type: KClass = VisionManager::class diff --git a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidGroup.kt b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidGroup.kt index 6d787bb5..f27ea3f3 100644 --- a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidGroup.kt +++ b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidGroup.kt @@ -57,7 +57,7 @@ public class SolidGroup : AbstractVisionGroup(), Solid, PrototypeHolder { override var scale: Point3D? = null @SerialName("children") - private val _children = HashMap() + private val _children = LinkedHashMap() override val children: Map get() = _children override fun attachChildren() { @@ -122,7 +122,7 @@ internal class Prototypes( override fun removeChild(token: NameToken) { children.remove(token) - childrenChanged(token.asName(), null) + childrenChanged(token, null) } override fun setChild(token: NameToken, child: Vision) { diff --git a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidManager.kt b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidManager.kt index dd070481..8db54e7e 100644 --- a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidManager.kt +++ b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidManager.kt @@ -16,43 +16,7 @@ import kotlinx.serialization.json.Json import kotlinx.serialization.modules.* import kotlin.reflect.KClass -//@OptIn(ExperimentalSerializationApi::class) -//@DFExperimental -//private fun SerializersModule.extractFactories(): List> { -// val list = ArrayList>() -// -// val collector = object : SerializersModuleCollector { -// override fun contextual(kClass: KClass, serializer: KSerializer) { -// //Do nothing -// } -// -// override fun polymorphic( -// baseClass: KClass, -// actualClass: KClass, -// actualSerializer: KSerializer, -// ) { -// if (baseClass == Vision::class) { -// @Suppress("UNCHECKED_CAST") val factory: SolidForm = SolidForm( -// actualClass as KClass, -// actualSerializer as KSerializer -// ) -// list.add(factory) -// } -// } -// -// override fun polymorphicDefault( -// baseClass: KClass, -// defaultSerializerProvider: (className: String?) -> DeserializationStrategy?, -// ) { -// TODO("Not yet implemented") -// } -// -// } -// dumpTo(collector) -// return list -//} -@DFExperimental public class SolidManager(meta: Meta) : AbstractPlugin(meta) { 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 useArrayPolymorphism = false encodeDefaults = false ignoreUnknownKeys = true - serializersModule = SolidManager.serializersModuleForSolids + serializersModule = serializersModuleForSolids } - @OptIn(DFExperimental::class) 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 { if(it is VisionGroup){ it.attachChildren() diff --git a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidMaterial.kt b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidMaterial.kt index d1a9b121..50d7d508 100644 --- a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidMaterial.kt +++ b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidMaterial.kt @@ -91,7 +91,7 @@ public fun Solid.color(rgb: Int) { public fun Solid.color(r: UByte, g: UByte, b: UByte): Unit = setItem( MATERIAL_COLOR_KEY, - Colors.rgbToMeta(r, g, b) + Colors.rgbToString(r, g, b).asValue() ) /** diff --git a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/specifications/Canvas3DOptions.kt b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/specifications/Canvas3DOptions.kt index 33ba4bd0..0ef38797 100644 --- a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/specifications/Canvas3DOptions.kt +++ b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/specifications/Canvas3DOptions.kt @@ -1,15 +1,20 @@ package hep.dataforge.vision.solid.specifications -import hep.dataforge.meta.Scheme -import hep.dataforge.meta.SchemeSpec -import hep.dataforge.meta.int -import hep.dataforge.meta.spec +import hep.dataforge.meta.* public class Canvas3DOptions : Scheme() { public var axes: Axes by spec(Axes, Axes.empty()) public var camera: Camera by spec(Camera, Camera.empty()) public var controls: Controls by spec(Controls, Controls.empty()) + 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) } \ No newline at end of file diff --git a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/specifications/Controls.kt b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/specifications/Controls.kt index adc22cbf..90d024c3 100644 --- a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/specifications/Controls.kt +++ b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/specifications/Controls.kt @@ -4,6 +4,6 @@ import hep.dataforge.meta.Scheme import hep.dataforge.meta.SchemeSpec -class Controls : Scheme() { - companion object : SchemeSpec(::Controls) +public class Controls : Scheme() { + public companion object : SchemeSpec(::Controls) } \ No newline at end of file diff --git a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/transform/RemoveSingleChild.kt b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/transform/RemoveSingleChild.kt index 2fc1ffdb..3f205893 100644 --- a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/transform/RemoveSingleChild.kt +++ b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/transform/RemoveSingleChild.kt @@ -35,7 +35,7 @@ internal fun mergeChild(parent: VisionGroup, child: Vision): Vision { } @DFExperimental -object RemoveSingleChild : VisualTreeTransform() { +internal object RemoveSingleChild : VisualTreeTransform() { override fun SolidGroup.transformInPlace() { fun MutableVisionGroup.replaceChildren() { diff --git a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/transform/UnRef.kt b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/transform/UnRef.kt index 9028b667..c3f2109b 100644 --- a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/transform/UnRef.kt +++ b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/transform/UnRef.kt @@ -9,7 +9,7 @@ import hep.dataforge.vision.solid.Proxy import hep.dataforge.vision.solid.SolidGroup @DFExperimental -object UnRef : VisualTreeTransform() { +internal object UnRef : VisualTreeTransform() { private fun VisionGroup.countRefs(): Map { return children.values.fold(HashMap()) { reducer, obj -> if (obj is VisionGroup) { diff --git a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/transform/VisualTreeTransform.kt b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/transform/VisualTreeTransform.kt index 83d38baa..22825f6c 100644 --- a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/transform/VisualTreeTransform.kt +++ b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/transform/VisualTreeTransform.kt @@ -5,11 +5,11 @@ import hep.dataforge.vision.Vision /** * A root class for [Vision] tree optimization */ -abstract class VisualTreeTransform { +public abstract class VisualTreeTransform { protected abstract fun T.transformInPlace() 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) { source } else { @@ -21,7 +21,7 @@ abstract class VisualTreeTransform { } } -fun T.transform(vararg transform: VisualTreeTransform): T { +public fun T.transform(vararg transform: VisualTreeTransform): T { var res = this transform.forEach { res = it(res) @@ -29,6 +29,6 @@ fun T.transform(vararg transform: VisualTreeTransform): T { return res } -fun T.transformInPlace(vararg transform: VisualTreeTransform) { +public fun T.transformInPlace(vararg transform: VisualTreeTransform) { transform.forEach { it(this) } } \ No newline at end of file diff --git a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/MeshThreeFactory.kt b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/MeshThreeFactory.kt index ac153ab5..5cd52b01 100644 --- a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/MeshThreeFactory.kt +++ b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/MeshThreeFactory.kt @@ -2,6 +2,7 @@ package hep.dataforge.vision.solid.three import hep.dataforge.meta.boolean import hep.dataforge.meta.node +import hep.dataforge.names.Name import hep.dataforge.names.asName import hep.dataforge.names.plus import hep.dataforge.names.startsWith @@ -19,13 +20,13 @@ import kotlin.reflect.KClass /** * Basic geometry-based factory */ -abstract class MeshThreeFactory( +public abstract class MeshThreeFactory( override val type: KClass ) : ThreeFactory { /** * 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 { val geometry = buildGeometry(obj) @@ -60,14 +61,14 @@ abstract class MeshThreeFactory( return mesh } - companion object { - val EDGES_KEY = "edges".asName() - val WIREFRAME_KEY = "wireframe".asName() - val ENABLED_KEY = "enabled".asName() - val EDGES_ENABLED_KEY = EDGES_KEY + ENABLED_KEY - val EDGES_MATERIAL_KEY = EDGES_KEY + SolidMaterial.MATERIAL_KEY - val WIREFRAME_ENABLED_KEY = WIREFRAME_KEY + ENABLED_KEY - val WIREFRAME_MATERIAL_KEY = WIREFRAME_KEY + SolidMaterial.MATERIAL_KEY + public companion object { + public val EDGES_KEY: Name = "edges".asName() + public val WIREFRAME_KEY: Name = "wireframe".asName() + public val ENABLED_KEY: Name = "enabled".asName() + public val EDGES_ENABLED_KEY: Name = EDGES_KEY + ENABLED_KEY + public val EDGES_MATERIAL_KEY: Name = EDGES_KEY + SolidMaterial.MATERIAL_KEY + public val WIREFRAME_ENABLED_KEY: Name = WIREFRAME_KEY + ENABLED_KEY + public val WIREFRAME_MATERIAL_KEY: Name = WIREFRAME_KEY + SolidMaterial.MATERIAL_KEY } } diff --git a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeBoxFactory.kt b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeBoxFactory.kt index 18f98942..b1a3d07b 100644 --- a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeBoxFactory.kt +++ b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeBoxFactory.kt @@ -4,8 +4,8 @@ import hep.dataforge.vision.solid.Box import hep.dataforge.vision.solid.detail import info.laht.threekt.geometries.BoxBufferGeometry -object ThreeBoxFactory : MeshThreeFactory(Box::class) { - override fun buildGeometry(obj: Box) = +public object ThreeBoxFactory : MeshThreeFactory(Box::class) { + override fun buildGeometry(obj: Box): BoxBufferGeometry = obj.detail?.let { detail -> BoxBufferGeometry(obj.xSize, obj.ySize, obj.zSize, detail, detail, detail) } ?: BoxBufferGeometry(obj.xSize, obj.ySize, obj.zSize) diff --git a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeCanvas.kt b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeCanvas.kt index 72db7ba4..f7243194 100644 --- a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeCanvas.kt +++ b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeCanvas.kt @@ -35,7 +35,6 @@ import org.w3c.dom.HTMLElement import org.w3c.dom.Node import org.w3c.dom.events.MouseEvent import kotlin.math.cos -import kotlin.math.max import kotlin.math.sin /** @@ -112,7 +111,10 @@ public class ThreeCanvas( 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 = { renderer.setSize(element.clientWidth, element.clientWidth) @@ -238,7 +240,7 @@ public class ThreeCanvas( } 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 SELECT_NAME = "@select" } @@ -251,7 +253,8 @@ public fun ThreePlugin.output( ): ThreeCanvas = ThreeCanvas(element, this, spec, onClick) public fun ThreePlugin.render( - element: HTMLElement, obj: Solid, - spec: Canvas3DOptions = Canvas3DOptions.empty(), - onClick: ((Name?) -> Unit)? = null, -): Unit = output(element, spec, onClick).render(obj) \ No newline at end of file + element: HTMLElement, + obj: Solid, + onSelect: ((Name?) -> Unit)? = null, + options: Canvas3DOptions.() -> Unit = {}, +): Unit = output(element, Canvas3DOptions(options), onSelect).render(obj) \ No newline at end of file diff --git a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeCanvasLabelFactory.kt b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeCanvasLabelFactory.kt index 793a3c1a..90027451 100644 --- a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeCanvasLabelFactory.kt +++ b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeCanvasLabelFactory.kt @@ -9,17 +9,17 @@ import info.laht.threekt.geometries.PlaneBufferGeometry import info.laht.threekt.materials.MeshBasicMaterial import info.laht.threekt.objects.Mesh import info.laht.threekt.textures.Texture +import kotlinx.browser.document import org.w3c.dom.CanvasRenderingContext2D import org.w3c.dom.CanvasTextBaseline import org.w3c.dom.HTMLCanvasElement import org.w3c.dom.MIDDLE -import kotlin.browser.document import kotlin.reflect.KClass /** * Using example from http://stemkoski.github.io/Three.js/Texture-From-Canvas.html */ -object ThreeCanvasLabelFactory : ThreeFactory { +public object ThreeCanvasLabelFactory : ThreeFactory { override val type: KClass get() = SolidLabel::class override fun invoke(obj: SolidLabel): Object3D { diff --git a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeCompositeFactory.kt b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeCompositeFactory.kt index 59c513a5..ffe249d2 100644 --- a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeCompositeFactory.kt +++ b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeCompositeFactory.kt @@ -8,7 +8,7 @@ import info.laht.threekt.objects.Mesh /** * This should be inner, because it uses object builder */ -class ThreeCompositeFactory(val three: ThreePlugin) : MeshThreeFactory(Composite::class) { +public class ThreeCompositeFactory(public val three: ThreePlugin) : MeshThreeFactory(Composite::class) { override fun buildGeometry(obj: Composite): BufferGeometry { val first = three.buildObject3D(obj.first) as? Mesh ?: error("First part of composite is not a mesh") diff --git a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeConvexFactory.kt b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeConvexFactory.kt index 6652047e..0f5160f8 100644 --- a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeConvexFactory.kt +++ b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeConvexFactory.kt @@ -4,7 +4,7 @@ import hep.dataforge.vision.solid.Convex import info.laht.threekt.external.geometries.ConvexBufferGeometry import info.laht.threekt.math.Vector3 -object ThreeConvexFactory : MeshThreeFactory(Convex::class) { +public object ThreeConvexFactory : MeshThreeFactory(Convex::class) { override fun buildGeometry(obj: Convex): ConvexBufferGeometry { @Suppress("USELESS_CAST") val vectors = obj.points.toTypedArray() as Array return ConvexBufferGeometry(vectors) diff --git a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeCylinderFactory.kt b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeCylinderFactory.kt index 9ba89cbf..00154c88 100644 --- a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeCylinderFactory.kt +++ b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeCylinderFactory.kt @@ -7,7 +7,7 @@ import info.laht.threekt.geometries.CylinderBufferGeometry import kotlin.math.PI import kotlin.math.pow -object ThreeCylinderFactory : MeshThreeFactory(ConeSegment::class) { +public object ThreeCylinderFactory : MeshThreeFactory(ConeSegment::class) { override fun buildGeometry(obj: ConeSegment): BufferGeometry { val cylinder = obj.detail?.let { val segments = it.toDouble().pow(0.5).toInt() diff --git a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeFactory.kt b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeFactory.kt index 28bb21d6..d01eed4c 100644 --- a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeFactory.kt +++ b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeFactory.kt @@ -18,21 +18,21 @@ import kotlin.reflect.KClass * Builder and updater for three.js object */ @Type(TYPE) -interface ThreeFactory { +public interface ThreeFactory { - val type: KClass + public val type: KClass - operator fun invoke(obj: T): Object3D + public operator fun invoke(obj: T): Object3D - companion object { - const val TYPE = "threeFactory" + public companion object { + public const val TYPE: String = "threeFactory" } } /** * Update position, rotation and visibility */ -fun Object3D.updatePosition(obj: Vision) { +public fun Object3D.updatePosition(obj: Vision) { visible = obj.visible ?: true if(obj is Solid) { position.set(obj.x, obj.y, obj.z) @@ -45,7 +45,7 @@ fun Object3D.updatePosition(obj: Vision) { /** * 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)) { this.material = getMaterial(source, false) } else if ( @@ -63,7 +63,7 @@ fun Object3D.updateProperty(source: Vision, propertyName: Name) { /** * Generic factory for elements which provide inside geometry builder */ -object ThreeShapeFactory : MeshThreeFactory(GeometrySolid::class) { +public object ThreeShapeFactory : MeshThreeFactory(GeometrySolid::class) { override fun buildGeometry(obj: GeometrySolid): BufferGeometry { return obj.run { ThreeGeometryBuilder().apply { toGeometry(this) }.build() diff --git a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeLabelFactory.kt b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeLabelFactory.kt index dad40782..ecea5d23 100644 --- a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeLabelFactory.kt +++ b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeLabelFactory.kt @@ -12,7 +12,7 @@ import kotlin.reflect.KClass /** * */ -object ThreeLabelFactory : ThreeFactory { +public object ThreeLabelFactory : ThreeFactory { override val type: KClass get() = SolidLabel::class override fun invoke(obj: SolidLabel): Object3D { diff --git a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeLineFactory.kt b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeLineFactory.kt index a032f527..5954a5a3 100644 --- a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeLineFactory.kt +++ b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeLineFactory.kt @@ -10,7 +10,7 @@ import info.laht.threekt.math.Color import info.laht.threekt.objects.LineSegments import kotlin.reflect.KClass -object ThreeLineFactory : ThreeFactory { +public object ThreeLineFactory : ThreeFactory { override val type: KClass get() = PolyLine::class override fun invoke(obj: PolyLine): Object3D { diff --git a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreePlugin.kt b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreePlugin.kt index 546cb882..b3a9200e 100644 --- a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreePlugin.kt +++ b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreePlugin.kt @@ -11,7 +11,7 @@ import kotlin.collections.set import kotlin.reflect.KClass import info.laht.threekt.objects.Group as ThreeGroup -class ThreePlugin : AbstractPlugin() { +public class ThreePlugin : AbstractPlugin() { override val tag: PluginTag get() = Companion.tag private val objectFactories = HashMap, ThreeFactory<*>>() @@ -35,9 +35,9 @@ class ThreePlugin : AbstractPlugin() { as ThreeFactory? } - fun buildObject3D(obj: Solid): Object3D { + public fun buildObject3D(obj: Solid): Object3D { return when (obj) { - is ThreeVision -> obj.toObject3D() + is ThreeVision -> obj.render() is Proxy -> proxyFactory(obj) is SolidGroup -> { val group = ThreeGroup() @@ -69,17 +69,17 @@ class ThreePlugin : AbstractPlugin() { } } - obj.onChildrenChange(this) { name, child -> - if (name.isEmpty()) { - logger.error { "Children change with empty name on $group" } - return@onChildrenChange - } + obj.onChildrenChange(this) { nameToken, child -> +// if (name.isEmpty()) { +// logger.error { "Children change with empty name on $group" } +// return@onChildrenChange +// } // val parentName = name.cutLast() // val childName = name.last()!! //removing old object - findChild(name)?.let { oldChild -> + findChild(nameToken.asName())?.let { oldChild -> oldChild.parent?.remove(oldChild) } @@ -87,7 +87,7 @@ class ThreePlugin : AbstractPlugin() { if (child != null && child is Solid) { try { val object3D = buildObject3D(child) - set(name, object3D) + set(nameToken, object3D) } catch (ex: Throwable) { logger.error(ex) { "Failed to render $child" } } @@ -108,10 +108,10 @@ class ThreePlugin : AbstractPlugin() { } } - companion object : PluginFactory { - override val tag = PluginTag("visual.three", PluginTag.DATAFORGE_GROUP) - override val type = ThreePlugin::class - override fun invoke(meta: Meta, context: Context) = ThreePlugin() + public companion object : PluginFactory { + override val tag: PluginTag = PluginTag("visual.three", PluginTag.DATAFORGE_GROUP) + override val type: KClass = ThreePlugin::class + override fun invoke(meta: Meta, context: Context): ThreePlugin = ThreePlugin() } } diff --git a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeProxyFactory.kt b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeProxyFactory.kt index b6321d25..b1b17fe6 100644 --- a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeProxyFactory.kt +++ b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeProxyFactory.kt @@ -11,7 +11,7 @@ import info.laht.threekt.core.Object3D import info.laht.threekt.objects.Mesh import kotlin.reflect.KClass -class ThreeProxyFactory(val three: ThreePlugin) : ThreeFactory { +public class ThreeProxyFactory(public val three: ThreePlugin) : ThreeFactory { private val cache = HashMap() override val type: KClass = Proxy::class diff --git a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeSphereFactory.kt b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeSphereFactory.kt index ffed6a45..37910fc9 100644 --- a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeSphereFactory.kt +++ b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeSphereFactory.kt @@ -5,7 +5,7 @@ import hep.dataforge.vision.solid.detail import info.laht.threekt.core.BufferGeometry import info.laht.threekt.geometries.SphereBufferGeometry -object ThreeSphereFactory : MeshThreeFactory(Sphere::class) { +public object ThreeSphereFactory : MeshThreeFactory(Sphere::class) { override fun buildGeometry(obj: Sphere): BufferGeometry { return obj.detail?.let {detail -> SphereBufferGeometry( diff --git a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeVision.kt b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeVision.kt index a96e39e4..8c8362a0 100644 --- a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeVision.kt +++ b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeVision.kt @@ -8,11 +8,6 @@ import kotlinx.serialization.Serializable /** * A custom visual object that has its own Three.js renderer */ -public interface ThreeVision : Solid { - public fun toObject3D(): Object3D +public abstract class ThreeVision : BasicSolid() { + public abstract fun render(): Object3D } - -@Serializable -public class CustomThreeVision(public val threeFactory: ThreeFactory) : BasicSolid(), ThreeVision { - override fun toObject3D(): Object3D = threeFactory(this) -} \ No newline at end of file