diff --git a/build.gradle.kts b/build.gradle.kts index ec691447..08ad66d8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,14 +2,13 @@ plugins { id("ru.mipt.npm.gradle.project") } -val dataforgeVersion by extra("0.5.0-dev-10") +val dataforgeVersion by extra("0.5.0-dev-11") val fxVersion by extra("11") allprojects { repositories { mavenLocal() mavenCentral() - jcenter() maven("https://repo.kotlin.link") maven("https://maven.jzy3d.org/releases") } diff --git a/demo/gdml/src/commonTest/kotlin/space/kscience/visionforge/gdml/GDMLVisionTest.kt b/demo/gdml/src/commonTest/kotlin/space/kscience/visionforge/gdml/GDMLVisionTest.kt index 50ba6d12..12918532 100644 --- a/demo/gdml/src/commonTest/kotlin/space/kscience/visionforge/gdml/GDMLVisionTest.kt +++ b/demo/gdml/src/commonTest/kotlin/space/kscience/visionforge/gdml/GDMLVisionTest.kt @@ -4,27 +4,36 @@ import space.kscience.dataforge.names.Name import space.kscience.dataforge.values.asValue import space.kscience.dataforge.values.string import space.kscience.gdml.GdmlShowCase +import space.kscience.visionforge.Vision +import space.kscience.visionforge.computeProperties +import space.kscience.visionforge.get import space.kscience.visionforge.setProperty +import space.kscience.visionforge.solid.Solid import space.kscience.visionforge.solid.SolidMaterial +import space.kscience.visionforge.solid.material import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull class GDMLVisionTest { + private val cubes = GdmlShowCase.cubes().toVision() -// @Test -// fun testCubesStyles(){ -// val cubes = gdml.toVision() -// val segment = cubes["composite000.segment_0".toName()] as Solid -// println(segment.styles) -// println(segment.material) -// } + @Test + fun testCubesStyles(){ + val segment = cubes["composite-000.segment-0"] as Solid + println(segment.computeProperties().getValue(Vision.STYLE_KEY)) +// println(segment.computePropertyNode(SolidMaterial.MATERIAL_KEY)) +// println(segment.computeProperty(SolidMaterial.MATERIAL_COLOR_KEY)) + + println(segment.material?.meta) + + //println(Solids.encodeToString(cubes)) + } @Test fun testPrototypeProperty() { - val vision = GdmlShowCase.cubes().toVision() - val child = vision[Name.of("composite-000","segment-0")] + val child = cubes[Name.of("composite-000","segment-0")] assertNotNull(child) child.setProperty(SolidMaterial.MATERIAL_COLOR_KEY, "red".asValue()) assertEquals("red", child.getPropertyValue(SolidMaterial.MATERIAL_COLOR_KEY)?.string) diff --git a/demo/gdml/src/jvmMain/kotlin/space/kscience/visionforge/gdml/demo/GdmlFxDemoApp.kt b/demo/gdml/src/jvmMain/kotlin/space/kscience/visionforge/gdml/demo/GdmlFxDemoApp.kt index cb40431c..f2371f44 100644 --- a/demo/gdml/src/jvmMain/kotlin/space/kscience/visionforge/gdml/demo/GdmlFxDemoApp.kt +++ b/demo/gdml/src/jvmMain/kotlin/space/kscience/visionforge/gdml/demo/GdmlFxDemoApp.kt @@ -7,7 +7,6 @@ import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.fetch import space.kscience.gdml.GdmlShowCase import space.kscience.visionforge.VisionManager -import space.kscience.visionforge.computeProperties import space.kscience.visionforge.editor.VisionEditorFragment import space.kscience.visionforge.editor.VisionTreeFragment import space.kscience.visionforge.gdml.toVision @@ -33,9 +32,7 @@ class GDMLView : View() { this.itemProperty.bind(canvas.rootObjectProperty) } - private val propertyEditor = VisionEditorFragment { - it.computeProperties() - }.apply { + private val propertyEditor = VisionEditorFragment().apply { descriptorProperty.set(SolidMaterial.descriptor) visionProperty.bind(treeFragment.selectedProperty) } diff --git a/demo/muon-monitor/src/commonMain/kotlin/ru/mipt/npm/muon/monitor/Model.kt b/demo/muon-monitor/src/commonMain/kotlin/ru/mipt/npm/muon/monitor/Model.kt index 87065723..854e520c 100644 --- a/demo/muon-monitor/src/commonMain/kotlin/ru/mipt/npm/muon/monitor/Model.kt +++ b/demo/muon-monitor/src/commonMain/kotlin/ru/mipt/npm/muon/monitor/Model.kt @@ -28,6 +28,7 @@ class Model(val manager: VisionManager) { private fun SolidGroup.detector(detector: SC16) { group(detector.name) { + position = detector.center detector.pixels.forEach { pixel(it) } @@ -38,6 +39,10 @@ class Model(val manager: VisionManager) { val root: SolidGroup = SolidGroup().apply { root(this@Model.manager) + material { + wireframe + color("darkgreen") + } rotationX = PI / 2 group("bottom") { Monitor.detectors.filter { it.center.z == LOWER_LAYER_Z }.forEach { diff --git a/demo/muon-monitor/src/commonMain/kotlin/ru/mipt/npm/muon/monitor/Monitor.kt b/demo/muon-monitor/src/commonMain/kotlin/ru/mipt/npm/muon/monitor/Monitor.kt index 17d5ac86..3b64bb5a 100644 --- a/demo/muon-monitor/src/commonMain/kotlin/ru/mipt/npm/muon/monitor/Monitor.kt +++ b/demo/muon-monitor/src/commonMain/kotlin/ru/mipt/npm/muon/monitor/Monitor.kt @@ -3,7 +3,6 @@ package ru.mipt.npm.muon.monitor import ru.mipt.npm.muon.monitor.Monitor.PIXEL_XY_SIZE import ru.mipt.npm.muon.monitor.Monitor.PIXEL_Z_SIZE import space.kscience.visionforge.solid.Point3D -import space.kscience.visionforge.solid.plus /** * A single pixel @@ -98,7 +97,7 @@ class SC16( } val offset = Point3D(-y, x, 0)//rotateDetector(Point3D(x, y, 0.0)); val pixelName = "${name}_${index}" - SC1(pixelName, center + offset) + SC1(pixelName, offset) } } } diff --git a/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMAppComponent.kt b/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMAppComponent.kt index 75b610ac..d981fa44 100644 --- a/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMAppComponent.kt +++ b/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMAppComponent.kt @@ -2,6 +2,7 @@ package ru.mipt.npm.muon.monitor import io.ktor.client.HttpClient import io.ktor.client.request.get +import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import kotlinx.css.* @@ -23,6 +24,7 @@ import space.kscience.visionforge.react.flexColumn import space.kscience.visionforge.react.visionTree import space.kscience.visionforge.solid.specifications.Camera import space.kscience.visionforge.solid.specifications.Canvas3DOptions +import space.kscience.visionforge.solid.three.edges import styled.css import styled.styledDiv import kotlin.math.PI @@ -34,6 +36,7 @@ external interface MMAppProps : RProps { var selected: Name? } +@OptIn(DelicateCoroutinesApi::class) @JsExport val MMApp = functionalComponent("Muon monitor") { props -> var selected by useState { props.selected } @@ -53,7 +56,9 @@ val MMApp = functionalComponent("Muon monitor") { props -> } } - val root = props.model.root + val root = props.model.root.apply { + edges() + } gridRow { flexColumn { diff --git a/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMDemoApp.kt b/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMDemoApp.kt index 5c4a589a..9daa6213 100644 --- a/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMDemoApp.kt +++ b/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMDemoApp.kt @@ -7,18 +7,15 @@ import kotlinx.browser.document import react.child import react.dom.render import space.kscience.dataforge.context.Context -import space.kscience.dataforge.context.Global import space.kscience.dataforge.context.fetch import space.kscience.visionforge.Application import space.kscience.visionforge.VisionManager import space.kscience.visionforge.bootstrap.useBootstrap +import space.kscience.visionforge.solid.three.ThreePlugin import space.kscience.visionforge.startApplication private class MMDemoApp : Application { - private val visionManager = Global.fetch(VisionManager) - private val model = Model(visionManager) - private val connection = HttpClient { install(JsonFeature) { serializer = KotlinxSerializer() @@ -28,13 +25,18 @@ private class MMDemoApp : Application { override fun start(state: Map) { useBootstrap() - val element = document.getElementById("app") ?: error("Element with id 'app' not found on page") + val context = Context("MM-demo"){ + plugin(ThreePlugin) + } + val visionManager = context.fetch(VisionManager) - val context = Context("demo") + val model = Model(visionManager) + + val element = document.getElementById("app") ?: error("Element with id 'app' not found on page") render(element) { child(MMApp) { attrs { - this.model = this@MMDemoApp.model + this.model = model this.connection = this@MMDemoApp.connection this.context = context } diff --git a/demo/solid-showcase/src/commonMain/kotlin/space/kscience/visionforge/solid/demo/demo.kt b/demo/solid-showcase/src/commonMain/kotlin/space/kscience/visionforge/solid/demo/demo.kt index c933c3ce..2f533c95 100644 --- a/demo/solid-showcase/src/commonMain/kotlin/space/kscience/visionforge/solid/demo/demo.kt +++ b/demo/solid-showcase/src/commonMain/kotlin/space/kscience/visionforge/solid/demo/demo.kt @@ -19,7 +19,7 @@ fun VisionLayout.demo(name: String, title: String = name, block: SolidGro "title" put title } val vision = SolidGroup(block) - render(Name.parse(name), vision) + render(Name.parse(name), vision, meta) } val canvasOptions = Canvas3DOptions { @@ -36,6 +36,7 @@ val canvasOptions = Canvas3DOptions { } } +@OptIn(DelicateCoroutinesApi::class) fun VisionLayout.showcase() { demo("shapes", "Basic shapes") { box(100.0, 100.0, 100.0) { diff --git a/demo/solid-showcase/src/jvmMain/kotlin/space/kscience/visionforge/solid/demo/FXDemoApp.kt b/demo/solid-showcase/src/jvmMain/kotlin/space/kscience/visionforge/solid/demo/FXDemoApp.kt index 3ce92f0f..7f278d28 100644 --- a/demo/solid-showcase/src/jvmMain/kotlin/space/kscience/visionforge/solid/demo/FXDemoApp.kt +++ b/demo/solid-showcase/src/jvmMain/kotlin/space/kscience/visionforge/solid/demo/FXDemoApp.kt @@ -14,7 +14,7 @@ class FXDemoApp : App(FXDemoGrid::class) { stage.height = 600.0 view.showcase() - view.showcaseCSG() + //view.showcaseCSG() } } diff --git a/demo/solid-showcase/src/jvmMain/kotlin/space/kscience/visionforge/solid/demo/MetaEditorDemo.kt b/demo/solid-showcase/src/jvmMain/kotlin/space/kscience/visionforge/solid/demo/MetaEditorDemo.kt index b00ef055..3cdf058e 100644 --- a/demo/solid-showcase/src/jvmMain/kotlin/space/kscience/visionforge/solid/demo/MetaEditorDemo.kt +++ b/demo/solid-showcase/src/jvmMain/kotlin/space/kscience/visionforge/solid/demo/MetaEditorDemo.kt @@ -1,7 +1,6 @@ package space.kscience.visionforge.demo import javafx.geometry.Orientation -import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.node @@ -46,12 +45,12 @@ class MetaEditorDemo : View("Meta editor demo") { } } - private val rootNode = FXMetaModel.root(meta, descriptor) + private val rootNode:FXMetaModel = FXMetaModel.root(meta, descriptor) override val root = splitpane( Orientation.HORIZONTAL, - MetaViewer(rootNode as Meta).root, - MutableMetaEditor(rootNode as FXMetaModel).root + MetaViewer(rootNode).root, + MutableMetaEditor(rootNode).root ) } diff --git a/ui/bootstrap/src/main/kotlin/space/kscience/visionforge/bootstrap/outputConfig.kt b/ui/bootstrap/src/main/kotlin/space/kscience/visionforge/bootstrap/outputConfig.kt index f16985c5..8088d2fd 100644 --- a/ui/bootstrap/src/main/kotlin/space/kscience/visionforge/bootstrap/outputConfig.kt +++ b/ui/bootstrap/src/main/kotlin/space/kscience/visionforge/bootstrap/outputConfig.kt @@ -12,9 +12,9 @@ import org.w3c.files.BlobPropertyBag import react.* import react.dom.attrs import react.dom.button -import space.kscience.dataforge.meta.descriptors.defaultNode import space.kscience.dataforge.meta.withDefault import space.kscience.visionforge.Vision +import space.kscience.visionforge.encodeToString import space.kscience.visionforge.react.flexColumn import space.kscience.visionforge.react.flexRow import space.kscience.visionforge.react.propertyEditor @@ -51,12 +51,12 @@ public val CanvasControls: FunctionComponent = functionalCo border(1.px, BorderStyle.solid, Color.blue) padding(4.px) } - props.vision?.manager?.let { manager -> + props.vision?.let{ vision -> button { +"Export" attrs { onClickFunction = { - val json = manager.encodeToString(props.vision!!) + val json = vision.encodeToString() saveData(it, "object.json", "text/json") { json } diff --git a/ui/bootstrap/src/main/kotlin/space/kscience/visionforge/bootstrap/threeControls.kt b/ui/bootstrap/src/main/kotlin/space/kscience/visionforge/bootstrap/threeControls.kt index e8166f35..95219db1 100644 --- a/ui/bootstrap/src/main/kotlin/space/kscience/visionforge/bootstrap/threeControls.kt +++ b/ui/bootstrap/src/main/kotlin/space/kscience/visionforge/bootstrap/threeControls.kt @@ -21,7 +21,7 @@ public external interface ThreeControlsProps : RProps { } @JsExport -public val ThreeControls: FunctionalComponent = functionalComponent { props -> +public val ThreeControls: FunctionComponent = functionalComponent { props -> tabPane(if (props.selected != null) "Properties" else null) { tab("Canvas") { card("Canvas configuration") { diff --git a/ui/react/src/main/kotlin/space/kscience/visionforge/react/MetaViewer.kt b/ui/react/src/main/kotlin/space/kscience/visionforge/react/MetaViewer.kt index 288251e0..69683bc5 100644 --- a/ui/react/src/main/kotlin/space/kscience/visionforge/react/MetaViewer.kt +++ b/ui/react/src/main/kotlin/space/kscience/visionforge/react/MetaViewer.kt @@ -9,7 +9,6 @@ import react.dom.a import react.dom.attrs import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.descriptors.MetaDescriptor -import space.kscience.dataforge.meta.descriptors.defaultNode import space.kscience.dataforge.meta.descriptors.get import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.isLeaf diff --git a/ui/react/src/main/kotlin/space/kscience/visionforge/react/PropertyEditor.kt b/ui/react/src/main/kotlin/space/kscience/visionforge/react/PropertyEditor.kt index cdb1bf30..47b0d818 100644 --- a/ui/react/src/main/kotlin/space/kscience/visionforge/react/PropertyEditor.kt +++ b/ui/react/src/main/kotlin/space/kscience/visionforge/react/PropertyEditor.kt @@ -121,7 +121,7 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) { }?.forEach { add(NameToken(it.key)) } - ownProperty?.items?.keys?.filterNot { it.body.startsWith("@") }?.let { addAll(it) } + //ownProperty?.items?.keys?.filterNot { it.body.startsWith("@") }?.let { addAll(it) } } flexRow { diff --git a/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ringThreeControls.kt b/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ringThreeControls.kt index 1d9626ed..ca5ca00f 100644 --- a/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ringThreeControls.kt +++ b/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ringThreeControls.kt @@ -15,7 +15,6 @@ import react.dom.button import ringui.Island import ringui.SmartTabs import ringui.Tab -import space.kscience.dataforge.meta.descriptors.defaultNode import space.kscience.dataforge.meta.withDefault import space.kscience.dataforge.names.Name import space.kscience.visionforge.Vision diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/ComputedVisionProperties.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/ComputedVisionProperties.kt index 1007eee6..925eecfe 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/ComputedVisionProperties.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/ComputedVisionProperties.kt @@ -1,53 +1,84 @@ package space.kscience.visionforge import space.kscience.dataforge.meta.Meta -import space.kscience.dataforge.meta.ObservableMutableMeta import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.get import space.kscience.dataforge.meta.get import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.NameToken import space.kscience.dataforge.names.plus +import space.kscience.dataforge.values.MutableValueProvider import space.kscience.dataforge.values.Value private class ComputedVisionProperties( - public val vision: Vision, - public val rootName: Name, - public val visionDescriptor: MetaDescriptor -) : ObservableMutableMeta by vision.meta { + val vision: Vision, + val pathName: Name, + val visionDescriptor: MetaDescriptor, + val parentInheritFlag: Boolean?, + val parentStylesFlag: Boolean? +) : Meta { - public val descriptor: MetaDescriptor? = visionDescriptor[rootName] + val descriptor: MetaDescriptor? by lazy { visionDescriptor[pathName] } - override val items: Map + override val items: Map get() { - val metaKeys = vision.meta.items.keys + val metaKeys = vision.meta.getMeta(pathName)?.items?.keys ?: emptySet() val descriptorKeys = descriptor?.children?.map { NameToken(it.key) } ?: emptySet() - return (metaKeys + descriptorKeys).associateWith { getMeta(rootName + it) } + val inheritFlag = descriptor?.inherited ?: parentInheritFlag + val stylesFlag = descriptor?.usesStyles ?: parentStylesFlag + return (metaKeys + descriptorKeys).associateWith { + ComputedVisionProperties( + vision, + pathName + it, + visionDescriptor, + inheritFlag, + stylesFlag + ) + } } - override var value: Value? + override val value: Value? get() { - val inheritFlag = descriptor?.inherited ?: false - val stylesFlag = descriptor?.usesStyles ?: true - return vision.getPropertyValue(rootName, inheritFlag, stylesFlag, true) - } - set(value) { - vision.meta.setValue(rootName, value) + val inheritFlag = descriptor?.inherited ?: parentInheritFlag ?: false + val stylesFlag = descriptor?.usesStyles ?: parentStylesFlag ?: true + return vision.getPropertyValue(pathName, inheritFlag, stylesFlag, true) } - override fun getMeta(name: Name): ObservableMutableMeta = - ComputedVisionProperties(vision, rootName + name, visionDescriptor) - - override fun getOrCreate(name: Name): ObservableMutableMeta = getMeta(name) - - override fun toMeta(): Meta = this + override fun toString(): String = Meta.toString(this) + override fun equals(other: Any?): Boolean = Meta.equals(this, other as? Meta) + override fun hashCode(): Int = Meta.hashCode(this) } /** * Compute property node based on inheritance and style information from the descriptor */ -public fun Vision.computeProperties(descriptor: MetaDescriptor? = this.descriptor): ObservableMutableMeta = - if (descriptor == null) meta else ComputedVisionProperties(this, Name.EMPTY, descriptor) +public fun Vision.computeProperties(descriptor: MetaDescriptor? = this.descriptor): Meta = + if (descriptor == null) meta else ComputedVisionProperties(this, Name.EMPTY, descriptor, null, null) + +public fun Vision.computePropertyNode( + name: Name, + descriptor: MetaDescriptor? = this.descriptor +): Meta? = computeProperties(descriptor)[name] + +/** + * Compute the property based on the provided value descriptor. By default, use Vision own descriptor + */ +public fun Vision.computeProperty(name: Name, valueDescriptor: MetaDescriptor? = descriptor?.get(name)): Value? { + val inheritFlag = valueDescriptor?.inherited ?: false + val stylesFlag = valueDescriptor?.usesStyles ?: true + return getPropertyValue(name, inheritFlag, stylesFlag) +} + +/** + * Accessor to all vision properties + */ +public fun Vision.computePropertyValues( + descriptor: MetaDescriptor? = this.descriptor +): MutableValueProvider = object : MutableValueProvider { + override fun getValue(name: Name): Value? = computeProperty(name, descriptor?.get(name)) + + override fun setValue(name: Name, value: Value?) { + setProperty(name, value) + } +} -public fun Vision.computePropertyNode(name: Name, descriptor: MetaDescriptor? = this.descriptor): ObservableMutableMeta? = - computeProperties(descriptor)[name] \ No newline at end of file diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/StyleSheet.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/StyleSheet.kt index dacc09b1..52deee3c 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/StyleSheet.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/StyleSheet.kt @@ -7,6 +7,7 @@ import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.plus import space.kscience.dataforge.values.Value import space.kscience.dataforge.values.asValue +import space.kscience.dataforge.values.stringList import kotlin.jvm.JvmInline /** @@ -72,7 +73,7 @@ internal fun Vision.styleChanged(key: String, oldStyle: Meta?, newStyle: Meta?) * List of names of styles applied to this object. Order matters. Not inherited. */ public var Vision.styles: List - get() = meta.getMeta(Vision.STYLE_KEY)?.stringList ?: emptyList() + get() = meta.getValue(Vision.STYLE_KEY)?.stringList ?: emptyList() set(value) { meta.setValue(Vision.STYLE_KEY, value.map { it.asValue() }.asValue()) } @@ -105,7 +106,7 @@ public fun Vision.getStyleProperty(name: Name): Value? = styles.firstNotNullOfOr /** * Resolve an item in all style layers */ -public fun Vision.getStyleItems(name: Name): List = styles.mapNotNull { +public fun Vision.getStyleNodes(name: Name): List = styles.mapNotNull { getStyle(it)?.get(name) } diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionBase.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionBase.kt index c123938d..77a682aa 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionBase.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionBase.kt @@ -7,7 +7,6 @@ import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.meta.ObservableMutableMeta import space.kscience.dataforge.meta.descriptors.MetaDescriptor -import space.kscience.dataforge.meta.descriptors.defaultNode import space.kscience.dataforge.meta.descriptors.value import space.kscience.dataforge.meta.get import space.kscience.dataforge.misc.DFExperimental @@ -30,9 +29,11 @@ internal data class MetaListener( @SerialName("vision") public open class VisionBase( @Transient override var parent: VisionGroup? = null, - protected var properties: MutableMeta? = null ) : Vision { + @Transient + protected open var properties: MutableMeta? = null + @Synchronized protected fun getOrCreateProperties(): MutableMeta { if (properties == null) { @@ -45,50 +46,55 @@ public open class VisionBase( @Transient private val listeners = HashSet() - private inner class VisionBaseProperties(val rootName: Name) : ObservableMutableMeta { + private inner class VisionProperties(val pathName: Name) : ObservableMutableMeta { override val items: Map - get() = properties?.get(rootName)?.items?.mapValues { entry -> - VisionBaseProperties(rootName + entry.key) + get() = properties?.get(pathName)?.items?.mapValues { entry -> + VisionProperties(pathName + entry.key) } ?: emptyMap() override var value: Value? - get() = properties?.get(rootName)?.value + get() = properties?.get(pathName)?.value set(value) { - getOrCreateProperties().setValue(rootName, value) + val oldValue = properties?.get(pathName)?.value + getOrCreateProperties().setValue(pathName, value) + if (oldValue != value) { + invalidate(Name.EMPTY) + } } - override fun getOrCreate(name: Name): ObservableMutableMeta = VisionBaseProperties(this.rootName + name) + override fun getOrCreate(name: Name): ObservableMutableMeta = VisionProperties(pathName + name) override fun setMeta(name: Name, node: Meta?) { - getOrCreateProperties().setMeta(name, node) + getOrCreateProperties().setMeta(pathName + name, node) + invalidate(name) } @DFExperimental override fun attach(name: Name, node: ObservableMutableMeta) { val ownProperties = getOrCreateProperties() if (ownProperties is ObservableMutableMeta) { - ownProperties.attach(rootName + name, node) + ownProperties.attach(pathName + name, node) } else { - ownProperties.setMeta(rootName + name, node) + ownProperties.setMeta(pathName + name, node) node.onChange(this) { childName -> - ownProperties.setMeta(rootName + name + childName, this[childName]) + ownProperties.setMeta(pathName + name + childName, this[childName]) } } } override fun invalidate(name: Name) { - invalidateProperty(rootName + name) + invalidateProperty(pathName + name) } @Synchronized override fun onChange(owner: Any?, callback: Meta.(name: Name) -> Unit) { - if (rootName.isEmpty()) { + if (pathName.isEmpty()) { listeners.add((MetaListener(owner, callback))) } else { listeners.add(MetaListener(owner) { name -> - if (name.startsWith(rootName)) { - (get(rootName) ?: Meta.EMPTY).callback(name.removeHeadOrNull(rootName)!!) + if (name.startsWith(pathName)) { + (this@MetaListener[pathName] ?: Meta.EMPTY).callback(name.removeHeadOrNull(pathName)!!) } }) } @@ -104,7 +110,7 @@ public open class VisionBase( override fun hashCode(): Int = Meta.hashCode(this) } - override val meta: ObservableMutableMeta get() = VisionBaseProperties(Name.EMPTY) + override val meta: ObservableMutableMeta get() = VisionProperties(Name.EMPTY) override fun getPropertyValue( name: Name, diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionGroup.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionGroup.kt index c7c47901..76640bee 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionGroup.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionGroup.kt @@ -4,6 +4,9 @@ import kotlinx.coroutines.flow.Flow import space.kscience.dataforge.names.* import space.kscience.dataforge.provider.Provider +@DslMarker +public annotation class VisionBuilder + public interface VisionContainer { public operator fun get(name: Name): V? } diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/misc.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/misc.kt deleted file mode 100644 index 084416ac..00000000 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/misc.kt +++ /dev/null @@ -1,17 +0,0 @@ -package space.kscience.visionforge - -import space.kscience.dataforge.meta.Laminate -import space.kscience.dataforge.meta.Meta -import space.kscience.dataforge.meta.isLeaf - -@DslMarker -public annotation class VisionBuilder - -public fun List.merge(): Meta? { - val first = firstOrNull { it != null } - return when { - first == null -> null - first.isLeaf -> first //fast search for first entry if it is value - else -> Laminate(filterNotNull()) //merge nodes if first encountered node is meta - } -} \ No newline at end of file diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/visionDescriptor.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/visionDescriptor.kt index a02a3b3e..15ef9229 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/visionDescriptor.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/visionDescriptor.kt @@ -7,20 +7,20 @@ import space.kscience.dataforge.values.asValue private const val INHERITED_DESCRIPTOR_ATTRIBUTE = "inherited" private const val STYLE_DESCRIPTOR_ATTRIBUTE = "useStyles" -public val MetaDescriptor.inherited: Boolean - get() = attributes[INHERITED_DESCRIPTOR_ATTRIBUTE].boolean ?: false +public val MetaDescriptor.inherited: Boolean? + get() = attributes[INHERITED_DESCRIPTOR_ATTRIBUTE].boolean -public var MetaDescriptorBuilder.inherited: Boolean - get() = attributes[INHERITED_DESCRIPTOR_ATTRIBUTE].boolean ?: false - set(value) = attributes.set(INHERITED_DESCRIPTOR_ATTRIBUTE, value) +public var MetaDescriptorBuilder.inherited: Boolean? + get() = attributes[INHERITED_DESCRIPTOR_ATTRIBUTE].boolean + set(value) = attributes.set(INHERITED_DESCRIPTOR_ATTRIBUTE, value?.asValue()) -public val MetaDescriptor.usesStyles: Boolean - get() = attributes[STYLE_DESCRIPTOR_ATTRIBUTE].boolean ?: true +public val MetaDescriptor.usesStyles: Boolean? + get() = attributes[STYLE_DESCRIPTOR_ATTRIBUTE].boolean -public var MetaDescriptorBuilder.usesStyles: Boolean - get() = attributes[STYLE_DESCRIPTOR_ATTRIBUTE].boolean ?: true - set(value) = attributes.set(STYLE_DESCRIPTOR_ATTRIBUTE, value) +public var MetaDescriptorBuilder.usesStyles: Boolean? + get() = attributes[STYLE_DESCRIPTOR_ATTRIBUTE].boolean + set(value) = attributes.set(STYLE_DESCRIPTOR_ATTRIBUTE, value?.asValue()) public val MetaDescriptor.widget: Meta get() = attributes["widget"] ?: Meta.EMPTY @@ -38,7 +38,7 @@ public val MetaDescriptor.widgetType: String? get() = attributes["widget.type"].string /** - * Extension property to access the "widget.type" key of [ValueDescriptor] + * Extension property to access the "widget.type" key of [MetaDescriptorBuilder] */ public var MetaDescriptorBuilder.widgetType: String? get() = attributes["widget.type"].string diff --git a/visionforge-core/src/commonTest/kotlin/space/kscience/visionforge/html/HtmlTagTest.kt b/visionforge-core/src/commonTest/kotlin/space/kscience/visionforge/html/HtmlTagTest.kt index c09c7c6c..3572dd42 100644 --- a/visionforge-core/src/commonTest/kotlin/space/kscience/visionforge/html/HtmlTagTest.kt +++ b/visionforge-core/src/commonTest/kotlin/space/kscience/visionforge/html/HtmlTagTest.kt @@ -12,9 +12,6 @@ import space.kscience.dataforge.names.Name import space.kscience.visionforge.Vision import space.kscience.visionforge.VisionBase import space.kscience.visionforge.VisionManager -import kotlin.collections.HashMap -import kotlin.collections.Map -import kotlin.collections.forEach import kotlin.collections.set import kotlin.test.Test diff --git a/visionforge-fx/build.gradle.kts b/visionforge-fx/build.gradle.kts index 09adb66a..961d181d 100644 --- a/visionforge-fx/build.gradle.kts +++ b/visionforge-fx/build.gradle.kts @@ -14,17 +14,10 @@ dependencies { api("no.tornado:tornadofx:1.7.20") - api("de.jensd:fontawesomefx-fontawesome:4.7.0-11") { - exclude(group = "org.openjfx") - } - - api("de.jensd:fontawesomefx-commons:11.0") { - exclude(group = "org.openjfx") - } - api("org.fxyz3d:fxyz3d:0.5.4") { exclude(module = "slf4j-simple") } + api("org.jetbrains.kotlinx:kotlinx-coroutines-javafx:${ru.mipt.npm.gradle.KScienceVersions.coroutinesVersion}") implementation("eu.mihosoft.vrl.jcsg:jcsg:0.5.7") { diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/FXMetaModel.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/FXMetaModel.kt index 476890a6..7d8e71b2 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/FXMetaModel.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/FXMetaModel.kt @@ -21,23 +21,29 @@ import tornadofx.* public class FXMetaModel( public val root: M, public val rootDescriptor: MetaDescriptor?, - public val nodeName: Name, - public val title: String = nodeName.lastOrNull()?.toString() ?: "Meta" + public val defaultRoot: Meta?, + public val pathName: Name, + public val title: String = pathName.lastOrNull()?.toString() ?: "Meta" ) : Comparable> { private val existingNode = object: ObjectBinding() { - override fun computeValue(): Meta? =root[nodeName] + override fun computeValue(): Meta? = root[pathName] } + private val defaultNode: Meta? get() = defaultRoot?.getMeta(pathName) + + public val descriptor: MetaDescriptor? = rootDescriptor?.get(pathName) + public val children: ListBinding> = object : ListBinding>() { override fun computeValue(): ObservableList> { val nodeKeys = existingNode.get()?.items?.keys?: emptySet() - val descriptorKeys = descriptor?.children?.keys?.map { NameToken(it) } ?: emptySet() - return (nodeKeys + descriptorKeys).map { + val defaultKeys = defaultNode?.items?.keys ?: emptySet() + return (nodeKeys + defaultKeys).map { FXMetaModel( root, rootDescriptor, - nodeName + it + defaultRoot, + pathName + it ) }.filter(filter).asObservable() } @@ -47,16 +53,14 @@ public class FXMetaModel( //add listener to the root node if possible if (root is ObservableMeta) { root.onChange(this) { changed -> - if (changed.startsWith(nodeName)) { - if (nodeName.length == changed.length) existingNode.invalidate() - else if (changed.length == nodeName.length + 1) children.invalidate() + if (changed.startsWith(pathName)) { + if (pathName.length == changed.length) existingNode.invalidate() + else if (changed.length == pathName.length + 1) children.invalidate() } } } } - public val descriptor: MetaDescriptor? = rootDescriptor?.get(nodeName) - public val existsProperty: BooleanBinding = existingNode.isNotNull public val exists: Boolean by existsProperty @@ -66,7 +70,7 @@ public class FXMetaModel( } override fun compareTo(other: FXMetaModel<*>): Int = if (this.exists == other.exists) { - this.nodeName.toString().compareTo(other.nodeName.toString()) + this.pathName.toString().compareTo(other.pathName.toString()) } else { this.exists.compareTo(other.exists) } @@ -79,7 +83,8 @@ public class FXMetaModel( public fun root( node: M, descriptor: MetaDescriptor? = null, + defaultRoot: Meta? = null, rootName: String = "root" - ): FXMetaModel = FXMetaModel(node, descriptor, Name.EMPTY, title = rootName) + ): FXMetaModel = FXMetaModel(node, descriptor, defaultRoot, Name.EMPTY, title = rootName) } } \ No newline at end of file diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/MetaViewer.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/MetaViewer.kt index 92c1222f..4563ade5 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/MetaViewer.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/MetaViewer.kt @@ -26,14 +26,12 @@ import space.kscience.visionforge.dfIconView import tornadofx.* public class MetaViewer( - private val rootNode: FXMetaModel, + private val rootNode: FXMetaModel, title: String = "Meta viewer" ) : Fragment(title, dfIconView) { public constructor(meta: Meta, title: String = "Meta viewer") : this( - FXMetaModel.root( - meta - ), title = title + FXMetaModel.root(meta), title = title ) override val root: BorderPane = borderpane { diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/MutableMetaEditor.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/MutableMetaEditor.kt index 59f49c38..231029cb 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/MutableMetaEditor.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/MutableMetaEditor.kt @@ -13,7 +13,6 @@ import javafx.scene.paint.Color import javafx.scene.text.Text import space.kscience.dataforge.context.Global import space.kscience.dataforge.meta.MutableMeta -import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.remove import space.kscience.visionforge.dfIconView import tornadofx.* @@ -25,16 +24,16 @@ import tornadofx.* */ public class MutableMetaEditor( public val rootNode: FXMetaModel, - public val allowNew: Boolean = true, - title: String = "Configuration editor" + //public val allowNew: Boolean = true, + title: String = "Meta editor" ) : Fragment(title = title, icon = dfIconView) { //TODO replace parameters by properties - - public constructor( - MutableMeta: MutableMeta, - descriptor: MetaDescriptor?, - title: String = "Configuration editor" - ) : this(FXMetaModel.root(MutableMeta, descriptor = descriptor), title = title) +// +// public constructor( +// MutableMeta: MutableMeta, +// descriptor: MetaDescriptor?, +// title: String = "Configuration editor" +// ) : this(FXMetaModel.root(MutableMeta, descriptor = descriptor), title = title) override val root: BorderPane = borderpane { center = treetableview> { @@ -65,7 +64,7 @@ public class MutableMetaEditor( contextmenu { item("Remove") { action { - content.root.remove(content.nodeName) + content.root.remove(content.pathName) } } } @@ -128,7 +127,7 @@ public class MutableMetaEditor( item.valueProperty, item.descriptor ) { value -> - item.root.setValue(item.nodeName, value) + item.root.setValue(item.pathName, value) } graphic = chooser.node diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/VisionEditorFragment.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/VisionEditorFragment.kt index d159dd11..bf1033ba 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/VisionEditorFragment.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/VisionEditorFragment.kt @@ -5,31 +5,40 @@ import javafx.beans.property.SimpleObjectProperty import javafx.scene.Node import javafx.scene.Parent import javafx.scene.layout.VBox +import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.meta.ObservableMutableMeta import space.kscience.dataforge.meta.descriptors.MetaDescriptor +import space.kscience.dataforge.names.Name import space.kscience.visionforge.Vision import space.kscience.visionforge.computeProperties import space.kscience.visionforge.getStyle import space.kscience.visionforge.styles import tornadofx.* -public class VisionEditorFragment(public val selector: (Vision) -> ObservableMutableMeta = {it.computeProperties()}) : Fragment() { +public class VisionEditorFragment : Fragment() { public val visionProperty: SimpleObjectProperty = SimpleObjectProperty() public var vision: Vision? by visionProperty public val descriptorProperty: SimpleObjectProperty = SimpleObjectProperty() private val configProperty: Binding = visionProperty.objectBinding { vision -> - vision?.let(selector) + vision?.meta } private val configEditorProperty: Binding = configProperty.objectBinding(descriptorProperty) { - it?.let { - MutableMetaEditor(it, descriptorProperty.get()).root + it?.let { meta -> + val node:FXMetaModel = FXMetaModel( + meta, + vision?.descriptor, + vision?.computeProperties(), + Name.EMPTY, + "Vision properties" + ) + MutableMetaEditor(node).root } } - private val styleBoxProperty: Binding = configProperty.objectBinding() { + private val styleBoxProperty: Binding = configProperty.objectBinding { VBox().apply { vision?.styles?.forEach { styleName -> val styleMeta = vision?.getStyle(styleName) diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FX3DPlugin.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FX3DPlugin.kt index 72a7ac8a..84dcb31d 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FX3DPlugin.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FX3DPlugin.kt @@ -24,7 +24,7 @@ import kotlin.collections.set import kotlin.math.PI import kotlin.reflect.KClass -class FX3DPlugin : AbstractPlugin() { +public class FX3DPlugin : AbstractPlugin() { override val tag: PluginTag get() = Companion.tag private val objectFactories = HashMap, FX3DFactory<*>>() @@ -43,7 +43,7 @@ class FX3DPlugin : AbstractPlugin() { as FX3DFactory? } - fun buildNode(obj: Solid): Node { + public fun buildNode(obj: Solid): Node { val binding = VisualObjectFXBinding(this, obj) return when (obj) { is SolidReferenceGroup -> referenceFactory(obj, binding) diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXMaterials.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXMaterials.kt index 0b205626..ca5e6583 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXMaterials.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXMaterials.kt @@ -37,24 +37,22 @@ public object FXMaterials { * Infer color based on meta item * @param opacity default opacity */ -public fun Meta.color(opacity: Double = 1.0): Color { - return value?.let { - if (it.type == ValueType.NUMBER) { - val int = it.int - val red = int and 0x00ff0000 shr 16 - val green = int and 0x0000ff00 shr 8 - val blue = int and 0x000000ff - Color.rgb(red, green, blue, opacity) - } else { - Color.web(it.string) - } - } ?: Color.rgb( - this[Colors.RED_KEY]?.int ?: 0, - this[Colors.GREEN_KEY]?.int ?: 0, - this[Colors.BLUE_KEY]?.int ?: 0, - this[SolidMaterial.OPACITY_KEY]?.double ?: opacity - ) -} +public fun Meta.color(opacity: Double = 1.0): Color = value?.let { + if (it.type == ValueType.NUMBER) { + val int = it.int + val red = int and 0x00ff0000 shr 16 + val green = int and 0x0000ff00 shr 8 + val blue = int and 0x000000ff + Color.rgb(red, green, blue, opacity) + } else { + Color.web(it.string) + } +} ?: Color.rgb( + this[Colors.RED_KEY]?.int ?: 0, + this[Colors.GREEN_KEY]?.int ?: 0, + this[Colors.BLUE_KEY]?.int ?: 0, + this[SolidMaterial.OPACITY_KEY]?.double ?: opacity +) /** * Infer FX material based on meta item diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXReferenceFactory.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXReferenceFactory.kt index ac05e8d5..af00f7c5 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXReferenceFactory.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXReferenceFactory.kt @@ -10,7 +10,7 @@ import space.kscience.visionforge.Vision import space.kscience.visionforge.onPropertyChange import kotlin.reflect.KClass -class FXReferenceFactory(val plugin: FX3DPlugin) : FX3DFactory { +public class FXReferenceFactory(public val plugin: FX3DPlugin) : FX3DFactory { override val type: KClass get() = SolidReferenceGroup::class override fun invoke(obj: SolidReferenceGroup, binding: VisualObjectFXBinding): Node { diff --git a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlTransformer.kt b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlTransformer.kt index 0a837919..269df511 100644 --- a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlTransformer.kt +++ b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlTransformer.kt @@ -441,20 +441,6 @@ private class GdmlTransformerEnv(val settings: GdmlTransformer) { } final.useStyle(rootStyle) - //inline prototypes -// referenceStore.forEach { (protoName, list) -> -// val proxy = list.singleOrNull() ?: return@forEach -// val parent = proxy.parent as? MutableVisionGroup ?: return@forEach -// val token = parent.children.entries.find { it.value == proxy }?.key ?: error("Inconsistent reference cache") -// val prototype = proto[protoName] as? Solid ?: error("Inconsistent reference cache") -// prototype.parent = null -// parent[token] = prototype -// prototype.updateFrom(proxy) -// -// //FIXME update prototype -// proto[protoName] = null -// } - final.prototypes { proto.children.forEach { (token, item) -> item.parent = null diff --git a/visionforge-plotly/src/commonMain/kotlin/space/kscience/visionforge/plotly/VisionOfPlotly.kt b/visionforge-plotly/src/commonMain/kotlin/space/kscience/visionforge/plotly/VisionOfPlotly.kt index 36102036..8874c694 100644 --- a/visionforge-plotly/src/commonMain/kotlin/space/kscience/visionforge/plotly/VisionOfPlotly.kt +++ b/visionforge-plotly/src/commonMain/kotlin/space/kscience/visionforge/plotly/VisionOfPlotly.kt @@ -15,7 +15,6 @@ public class VisionOfPlotly private constructor() : VisionBase() { public constructor(plot: Plot) : this() { properties = plot.meta } - public val plot: Plot get() = Plot(meta) } diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ColorAccessor.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ColorAccessor.kt index 25631c42..f06a7c6f 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ColorAccessor.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ColorAccessor.kt @@ -1,29 +1,28 @@ package space.kscience.visionforge.solid -import space.kscience.dataforge.meta.* import space.kscience.dataforge.names.Name +import space.kscience.dataforge.names.plus +import space.kscience.dataforge.values.MutableValueProvider import space.kscience.dataforge.values.Value import space.kscience.dataforge.values.asValue import space.kscience.dataforge.values.string import space.kscience.visionforge.Colors -import space.kscience.visionforge.Vision import space.kscience.visionforge.VisionBuilder -import space.kscience.visionforge.VisionPropertyContainer -import kotlin.jvm.JvmInline @VisionBuilder -public class ColorAccessor(private val colorKey: Name, private val parent: () -> MutableMetaProvider) { +public class ColorAccessor(private val provider: MutableValueProvider, private val colorKey: Name) : + MutableValueProvider { public var value: Value? - get() = parent().getMeta(colorKey)?.value + get() = provider.getValue(colorKey) set(value) { - parent().setValue(colorKey,value) + provider.setValue(colorKey, value) } - public var item: Meta? - get() = parent().getMeta(colorKey) - set(value) { - parent().setMeta(colorKey,value) - } + override fun getValue(name: Name): Value? = provider.getValue(colorKey + name) + + override fun setValue(name: Name, value: Value?) { + provider.setValue(colorKey + name, value) + } } public var ColorAccessor?.string: String? diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Composite.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Composite.kt index b3770d37..9debf612 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Composite.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Composite.kt @@ -2,9 +2,10 @@ package space.kscience.visionforge.solid import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import space.kscience.dataforge.meta.configure import space.kscience.dataforge.meta.update -import space.kscience.visionforge.* +import space.kscience.visionforge.VisionBuilder +import space.kscience.visionforge.VisionContainerBuilder +import space.kscience.visionforge.set public enum class CompositeType { SUM, // Dumb sum of meshes @@ -30,34 +31,38 @@ public inline fun VisionContainerBuilder.composite( val group = SolidGroup().apply(builder) val children = group.children.values.filterIsInstance() if (children.size != 2) error("Composite requires exactly two children") - return Composite(type, children[0], children[1]).apply { - configure { - update(group.meta) - } - if (group.position != null) { - position = group.position - } - if (group.rotation != null) { - rotation = group.rotation - } - if (group.scale != null) { - scale = group.scale - } - set(name, this) + val res = Composite(type, children[0], children[1]) + + res.meta.update(group.meta) + + if (group.position != null) { + res.position = group.position } + if (group.rotation != null) { + res.rotation = group.rotation + } + if (group.scale != null) { + res.scale = group.scale + } + + set(name, res) + return res } @VisionBuilder -public inline fun VisionContainerBuilder.union(name: String? = null, builder: SolidGroup.() -> Unit): Composite = - composite(CompositeType.UNION, name, builder = builder) +public inline fun VisionContainerBuilder.union( + name: String? = null, + builder: SolidGroup.() -> Unit +): Composite = composite(CompositeType.UNION, name, builder = builder) @VisionBuilder -public inline fun VisionContainerBuilder.subtract(name: String? = null, builder: SolidGroup.() -> Unit): Composite = - composite(CompositeType.SUBTRACT, name, builder = builder) +public inline fun VisionContainerBuilder.subtract( + name: String? = null, + builder: SolidGroup.() -> Unit +): Composite = composite(CompositeType.SUBTRACT, name, builder = builder) @VisionBuilder public inline fun VisionContainerBuilder.intersect( name: String? = null, builder: SolidGroup.() -> Unit, -): Composite = - composite(CompositeType.INTERSECT, name, builder = builder) \ No newline at end of file +): Composite = composite(CompositeType.INTERSECT, name, builder = builder) \ No newline at end of file diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidBase.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidBase.kt index f18a3869..7ca5c45d 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidBase.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidBase.kt @@ -2,6 +2,7 @@ package space.kscience.visionforge.solid import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.visionforge.VisionBase import space.kscience.visionforge.VisionChange @@ -9,6 +10,9 @@ import space.kscience.visionforge.VisionChange @Serializable @SerialName("solid") public open class SolidBase : VisionBase(), Solid { + //FIXME to be removed after https://github.com/Kotlin/kotlinx.serialization/issues/1602 fix + override var properties: MutableMeta? = null + override val descriptor: MetaDescriptor get() = Solid.descriptor override fun update(change: VisionChange) { diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt index f0f28fc5..ec6dd5f1 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt @@ -2,6 +2,7 @@ package space.kscience.visionforge.solid import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.NameToken @@ -31,6 +32,9 @@ public interface PrototypeHolder { @SerialName("group.solid") public class SolidGroup : VisionGroupBase(), Solid, PrototypeHolder { + //FIXME to be removed after https://github.com/Kotlin/kotlinx.serialization/issues/1602 fix + override var properties: MutableMeta? = null + override val children: Map get() = super.childrenInternal.filter { it.key != PROTOTYPES_TOKEN } private var prototypes: MutableVisionGroup? diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidMaterial.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidMaterial.kt index 78d787a3..fa5b0d76 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidMaterial.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidMaterial.kt @@ -20,14 +20,14 @@ public class SolidMaterial : Scheme() { /** * Primary web-color for the material */ - public val color: ColorAccessor = ColorAccessor(COLOR_KEY) { meta } + public val color: ColorAccessor = ColorAccessor(meta, COLOR_KEY) /** * Specular color for phong material */ - public val specularColor: ColorAccessor = ColorAccessor(SPECULAR_COLOR_KEY) { meta } + public val specularColor: ColorAccessor = ColorAccessor(meta, SPECULAR_COLOR_KEY) - public val emissiveColor: ColorAccessor = ColorAccessor("emissiveColor".asName()) { meta } + public val emissiveColor: ColorAccessor = ColorAccessor(meta, "emissiveColor".asName()) /** * Opacity @@ -55,33 +55,29 @@ public class SolidMaterial : Scheme() { //must be lazy to avoid initialization bug MetaDescriptor { inherited = true - usesStyles = true value(COLOR_KEY, ValueType.STRING, ValueType.NUMBER) { inherited = true - usesStyles = true widgetType = "color" } value(SPECULAR_COLOR_KEY, ValueType.STRING, ValueType.NUMBER) { inherited = true - usesStyles = true widgetType = "color" hide() } value(OPACITY_KEY, ValueType.NUMBER) { inherited = true - usesStyles = true default(1.0) attributes["min"] = 0.0 attributes["max"] = 1.0 attributes["step"] = 0.1 widgetType = "slider" } + value(WIREFRAME_KEY, ValueType.BOOLEAN) { inherited = true - usesStyles = true default(false) } } @@ -90,7 +86,7 @@ public class SolidMaterial : Scheme() { } public val Solid.color: ColorAccessor - get() = ColorAccessor(MATERIAL_COLOR_KEY) { computeProperties() } + get() = ColorAccessor(computePropertyValues(), MATERIAL_COLOR_KEY) public var Solid.material: SolidMaterial? get() = computePropertyNode(MATERIAL_KEY)?.let { SolidMaterial.read(it) } diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt index 427ef9a2..d2080924 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt @@ -2,6 +2,7 @@ package space.kscience.visionforge.solid import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.meta.ObservableMutableMeta import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.get @@ -12,11 +13,16 @@ import space.kscience.visionforge.* public interface SolidReference : VisionGroup { /** - * The prototype for this reference. Always returns a "real" prototype, not a reference + * The prototype for this reference. */ public val prototype: Solid - override fun getPropertyValue(name: Name, inherit: Boolean, includeStyles: Boolean, includeDefaults: Boolean): Value? { + override fun getPropertyValue( + name: Name, + inherit: Boolean, + includeStyles: Boolean, + includeDefaults: Boolean + ): Value? { meta[name]?.value?.let { return it } if (includeStyles) { getStyleProperty(name)?.let { return it } @@ -56,6 +62,8 @@ public class SolidReferenceGroup( public val refName: Name, ) : VisionBase(), SolidReference, VisionGroup, Solid { + override var properties: MutableMeta? = null + /** * Recursively search for defined template in the parent */ @@ -72,8 +80,12 @@ public class SolidReferenceGroup( ReferenceChild(this, it.key.asName()) } ?: emptyMap() - override fun getPropertyValue(name: Name, inherit: Boolean, includeStyles: Boolean, includeDefaults: Boolean): Value? = - super.getPropertyValue(name, inherit, includeStyles, includeDefaults) + override fun getPropertyValue( + name: Name, + inherit: Boolean, + includeStyles: Boolean, + includeDefaults: Boolean + ): Value? = super.getPropertyValue(name, inherit, includeStyles, includeDefaults) override val descriptor: MetaDescriptor get() = prototype.descriptor @@ -88,11 +100,14 @@ public class SolidReferenceGroup( ) : SolidReference, VisionGroup, Solid { override val prototype: Solid by lazy { - if (refName.isEmpty()) owner.prototype else { + if (refName.isEmpty()) { + owner.prototype + } else { val proto = (owner.prototype as? VisionGroup)?.get(refName) ?: error("Prototype with name $refName not found in SolidReferenceGroup ${owner.refName}") - proto.unref as? Solid - ?: error("Prototype with name $refName is ${proto::class} but expected Solid") + proto as? Solid ?: error("Prototype with name $refName is ${proto::class} but expected Solid") +// proto.unref as? Solid +// ?: error("Prototype with name $refName is ${proto::class} but expected Solid") } } diff --git a/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/PropertyTest.kt b/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/PropertyTest.kt index d146195a..ec58e4d2 100644 --- a/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/PropertyTest.kt +++ b/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/PropertyTest.kt @@ -1,6 +1,7 @@ package space.kscience.visionforge.solid -import space.kscience.dataforge.meta.* +import space.kscience.dataforge.meta.get +import space.kscience.dataforge.meta.string import space.kscience.dataforge.names.asName import space.kscience.dataforge.values.int import space.kscience.visionforge.* @@ -10,13 +11,32 @@ import kotlin.test.assertEquals @Suppress("UNUSED_VARIABLE") class PropertyTest { @Test - fun testColorUpdate(){ + fun testColor(){ val box = Box(10.0f, 10.0f,10.0f) box.material { //meta["color"] = "pink" color("pink") } assertEquals("pink", box.meta["material.color"]?.string) + assertEquals("pink", box.color.string) + } + + @Test + fun testColorUpdate(){ + val box = Box(10.0f, 10.0f,10.0f) + + var c: String? = null + box.onPropertyChange { + if(it == SolidMaterial.MATERIAL_COLOR_KEY){ + c = box.color.string + } + } + + box.material { + color("pink") + } + + assertEquals("pink", c) } @Test diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/MeshThreeFactory.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/MeshThreeFactory.kt index 992035a6..8b1428ec 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/MeshThreeFactory.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/MeshThreeFactory.kt @@ -4,17 +4,20 @@ import info.laht.threekt.core.BufferGeometry import info.laht.threekt.geometries.EdgesGeometry import info.laht.threekt.objects.LineSegments import info.laht.threekt.objects.Mesh -import space.kscience.dataforge.meta.get +import space.kscience.dataforge.meta.updateWith import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.plus import space.kscience.dataforge.names.startsWith import space.kscience.dataforge.values.boolean -import space.kscience.visionforge.computeProperties +import space.kscience.visionforge.computePropertyNode import space.kscience.visionforge.onPropertyChange +import space.kscience.visionforge.setProperty import space.kscience.visionforge.solid.Solid import space.kscience.visionforge.solid.SolidMaterial import space.kscience.visionforge.solid.layer +import space.kscience.visionforge.solid.three.MeshThreeFactory.Companion.EDGES_ENABLED_KEY +import space.kscience.visionforge.solid.three.MeshThreeFactory.Companion.EDGES_MATERIAL_KEY import kotlin.reflect.KClass /** @@ -62,6 +65,7 @@ public abstract class MeshThreeFactory( 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 @@ -71,6 +75,11 @@ public abstract class MeshThreeFactory( } } +public fun Solid.edges(enabled: Boolean = true, block: SolidMaterial.() -> Unit = {}) { + setProperty(EDGES_ENABLED_KEY, enabled) + meta.getOrCreate(EDGES_MATERIAL_KEY).updateWith(SolidMaterial, block) +} + internal fun Mesh.applyProperties(obj: Solid): Mesh = apply { updateMaterial(obj) applyEdges(obj) @@ -84,12 +93,9 @@ internal fun Mesh.applyProperties(obj: Solid): Mesh = apply { public fun Mesh.applyEdges(obj: Solid) { val edges = children.find { it.name == "@edges" } as? LineSegments //inherited edges definition, enabled by default - if (obj.getPropertyValue(MeshThreeFactory.EDGES_ENABLED_KEY, inherit = true, includeStyles = true)?.boolean != false) { + if (obj.getPropertyValue(EDGES_ENABLED_KEY, inherit = true)?.boolean != false) { val bufferGeometry = geometry as? BufferGeometry ?: return - val material = ThreeMaterials.getLineMaterial( - obj.computeProperties().get(MeshThreeFactory.EDGES_MATERIAL_KEY), - true - ) + val material = ThreeMaterials.getLineMaterial(obj.computePropertyNode(EDGES_MATERIAL_KEY), true) if (edges == null) { add( LineSegments( diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvasLabelFactory.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvasLabelFactory.kt index 4855abcd..7dd30a34 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvasLabelFactory.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvasLabelFactory.kt @@ -12,7 +12,7 @@ import org.w3c.dom.CanvasTextBaseline import org.w3c.dom.HTMLCanvasElement import org.w3c.dom.MIDDLE import space.kscience.visionforge.solid.SolidLabel -import space.kscience.visionforge.solid.color +import space.kscience.visionforge.solid.SolidMaterial import space.kscience.visionforge.solid.three.ThreeCanvas.Companion.DO_NOT_HIGHLIGHT_TAG import kotlin.reflect.KClass @@ -26,7 +26,7 @@ public object ThreeCanvasLabelFactory : ThreeFactory { val canvas = document.createElement("canvas") as HTMLCanvasElement val context = canvas.getContext("2d") as CanvasRenderingContext2D context.font = "Bold ${obj.fontSize}pt ${obj.fontFamily}" - context.fillStyle = obj.color.value ?: "black" + context.fillStyle = obj.getPropertyValue(SolidMaterial.MATERIAL_COLOR_KEY)?.value ?: "black" context.textBaseline = CanvasTextBaseline.MIDDLE val metrics = context.measureText(obj.text) //canvas.width = metrics.width.toInt() diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeMaterials.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeMaterials.kt index 9a3c6be9..dc0ab967 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeMaterials.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeMaterials.kt @@ -3,16 +3,21 @@ package space.kscience.visionforge.solid.three import info.laht.threekt.materials.LineBasicMaterial import info.laht.threekt.materials.Material import info.laht.threekt.materials.MeshBasicMaterial -import info.laht.threekt.materials.MeshPhongMaterial import info.laht.threekt.math.Color import info.laht.threekt.objects.Mesh -import space.kscience.dataforge.meta.* +import space.kscience.dataforge.meta.Meta +import space.kscience.dataforge.meta.boolean +import space.kscience.dataforge.meta.double +import space.kscience.dataforge.meta.get import space.kscience.dataforge.names.Name +import space.kscience.dataforge.names.asName import space.kscience.dataforge.values.* import space.kscience.visionforge.Colors import space.kscience.visionforge.Vision import space.kscience.visionforge.computePropertyNode +import space.kscience.visionforge.getStyleNodes import space.kscience.visionforge.solid.SolidMaterial +import space.kscience.visionforge.solid.SolidReference public object ThreeMaterials { @@ -56,56 +61,57 @@ public object ThreeMaterials { private val materialCache = HashMap() - internal fun buildMaterial(meta: Meta): Material { - val material = SolidMaterial.read(meta) - return meta[SolidMaterial.SPECULAR_COLOR_KEY]?.let { specularColor -> - MeshPhongMaterial().apply { - color = meta[SolidMaterial.COLOR_KEY]?.threeColor() ?: DEFAULT_COLOR - specular = specularColor.threeColor() - emissive = material.emissiveColor.item?.threeColor() ?: specular - reflectivity = 0.5 - refractionRatio = 1.0 - shininess = 100.0 - opacity = meta[SolidMaterial.OPACITY_KEY]?.double ?: 1.0 - transparent = opacity < 1.0 - wireframe = meta[SolidMaterial.WIREFRAME_KEY].boolean ?: false - needsUpdate = true - } - } ?: MeshBasicMaterial().apply { - color = meta[SolidMaterial.COLOR_KEY]?.threeColor() ?: DEFAULT_COLOR - opacity = meta[SolidMaterial.OPACITY_KEY]?.double ?: 1.0 - transparent = opacity < 1.0 - wireframe = meta[SolidMaterial.WIREFRAME_KEY].boolean ?: false - needsUpdate = true - } - + internal fun buildMaterial(meta: Meta): Material = MeshBasicMaterial().apply { + color = meta[SolidMaterial.COLOR_KEY]?.threeColor() ?: DEFAULT_COLOR + opacity = meta[SolidMaterial.OPACITY_KEY]?.double ?: 1.0 + transparent = opacity < 1.0 + wireframe = meta[SolidMaterial.WIREFRAME_KEY].boolean ?: false + needsUpdate = true } +// val material = SolidMaterial.read(meta) +// return meta[SolidMaterial.SPECULAR_COLOR_KEY]?.let { specularColor -> +// MeshPhongMaterial().apply { +// color = meta[SolidMaterial.COLOR_KEY]?.threeColor() ?: DEFAULT_COLOR +// specular = specularColor.threeColor() +// emissive = material.emissiveColor.threeColor() ?: specular +// reflectivity = 0.5 +// refractionRatio = 1.0 +// shininess = 100.0 +// opacity = meta[SolidMaterial.OPACITY_KEY]?.double ?: 1.0 +// transparent = opacity < 1.0 +// wireframe = meta[SolidMaterial.WIREFRAME_KEY].boolean ?: false +// needsUpdate = true +// } +// } ?: MeshBasicMaterial().apply { +// color = meta[SolidMaterial.COLOR_KEY]?.threeColor() ?: DEFAULT_COLOR +// opacity = meta[SolidMaterial.OPACITY_KEY]?.double ?: 1.0 +// transparent = opacity < 1.0 +// wireframe = meta[SolidMaterial.WIREFRAME_KEY].boolean ?: false +// needsUpdate = true +// } internal fun cacheMaterial(meta: Meta): Material = materialCache.getOrPut(meta) { buildMaterial(meta).apply { cached = true } } - } /** - * Infer color based on meta item + * Compute color */ -public fun Meta.threeColor(): Color { - return value?.let { value -> - if (value.type == ValueType.NUMBER) { - val int = value.int - Color(int) - } else { - Color(value.string) - } - } ?: Color( - this[Colors.RED_KEY]?.int ?: 0, - this[Colors.GREEN_KEY]?.int ?: 0, - this[Colors.BLUE_KEY]?.int ?: 0 - ) -} +public fun Meta.threeColor(): Color = getValue(Name.EMPTY)?.let { value -> + if (value.type == ValueType.NUMBER) { + val int = value.int + Color(int) + } else { + Color(value.string) + } +} ?: Color( + getValue(Colors.RED_KEY.asName())?.int ?: 0, + getValue(Colors.GREEN_KEY.asName())?.int ?: 0, + getValue(Colors.BLUE_KEY.asName())?.int ?: 0 +) private var Material.cached: Boolean get() = userData["cached"] == true @@ -114,31 +120,19 @@ private var Material.cached: Boolean } public fun Mesh.updateMaterial(vision: Vision) { - //val meta = vision.getProperty(SolidMaterial.MATERIAL_KEY, inherit = true).node val ownMaterialMeta = vision.meta.getMeta(SolidMaterial.MATERIAL_KEY) - val parentMaterialMeta = vision.parent?.getPropertyValue( - SolidMaterial.MATERIAL_KEY, - inherit = true, - includeStyles = false, - includeDefaults = false - ) - - material = when { - ownMaterialMeta == null && parentMaterialMeta == null -> { - //If material is style-based, use cached - vision.computePropertyNode( - SolidMaterial.MATERIAL_KEY, - )?.let { + if (ownMaterialMeta == null) { + if (vision is SolidReference && vision.getStyleNodes(SolidMaterial.MATERIAL_KEY).isEmpty()) { + updateMaterial(vision.prototype) + } else { + material = vision.computePropertyNode(SolidMaterial.MATERIAL_KEY)?.let { ThreeMaterials.cacheMaterial(it) } ?: ThreeMaterials.DEFAULT } - else -> { - vision.computePropertyNode( - SolidMaterial.MATERIAL_KEY, - )?.let { - ThreeMaterials.buildMaterial(it) - } ?: ThreeMaterials.DEFAULT - } + } else { + material = vision.computePropertyNode(SolidMaterial.MATERIAL_KEY)?.let { + ThreeMaterials.buildMaterial(it) + } ?: ThreeMaterials.DEFAULT } } @@ -149,17 +143,14 @@ public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) { } else { when (propertyName) { SolidMaterial.MATERIAL_COLOR_KEY -> { - material.asDynamic().color = vision.computePropertyNode( - SolidMaterial.MATERIAL_COLOR_KEY, - )?.threeColor() ?: ThreeMaterials.DEFAULT_COLOR + material.asDynamic().color = vision.computePropertyNode(SolidMaterial.MATERIAL_COLOR_KEY)?.threeColor() + ?: ThreeMaterials.DEFAULT_COLOR material.needsUpdate = true } SolidMaterial.MATERIAL_OPACITY_KEY -> { val opacity = vision.getPropertyValue( SolidMaterial.MATERIAL_OPACITY_KEY, inherit = true, - includeStyles = true, - includeDefaults = false )?.double ?: 1.0 material.opacity = opacity material.transparent = opacity < 1.0 @@ -169,8 +160,6 @@ public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) { material.asDynamic().wireframe = vision.getPropertyValue( SolidMaterial.MATERIAL_WIREFRAME_KEY, inherit = true, - includeStyles = true, - includeDefaults = false )?.boolean ?: false material.needsUpdate = true } diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeReferenceFactory.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeReferenceFactory.kt index 53e9c2c9..aa779e46 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeReferenceFactory.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeReferenceFactory.kt @@ -1,6 +1,5 @@ package space.kscience.visionforge.solid.three -import info.laht.threekt.core.BufferGeometry import info.laht.threekt.core.Object3D import info.laht.threekt.objects.Mesh import space.kscience.dataforge.names.Name @@ -19,7 +18,7 @@ public object ThreeReferenceFactory : ThreeFactory { private fun Object3D.replicate(): Object3D { return when (this) { - is Mesh -> Mesh(geometry as BufferGeometry, material).also { + is Mesh -> Mesh(geometry, material).also { it.applyMatrix4(matrix) } else -> clone(false)