diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualObject.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualObject.kt index 385c9360..effe38d8 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualObject.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualObject.kt @@ -74,7 +74,7 @@ abstract class AbstractVisualObject : VisualObject { override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? { return if (inherit) { - properties?.get(name) ?: parent?.getProperty(name, inherit) ?: actualStyles[name] + properties?.get(name) ?: actualStyles[name] ?: parent?.getProperty(name, inherit) } else { properties?.get(name) ?: actualStyles[name] } diff --git a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDML.kt b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDML.kt index 8206c166..e3935a0f 100644 --- a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDML.kt +++ b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDML.kt @@ -153,7 +153,7 @@ private fun VisualGroup3D.addPhysicalVolume( //optimizing single child case if (context.optimizeSingleChild && group.children.size == 1) { this[physVolume.name ?: ""] = group.children.values.first().apply { - //Must ser this to avoid parent reset error + //Must set this to avoid parent reset error parent = null //setting offset from physical volume withPosition( diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt index 8c31dd8f..31f6f915 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt @@ -22,6 +22,11 @@ class Composite( val second: VisualObject3D ) : AbstractVisualObject(), VisualObject3D { + init { + first.parent = this + second.parent = this + } + override var position: Point3D? = null override var rotation: Point3D? = null override var scale: Point3D? = null diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt index 3324bfed..60b3b7fb 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt @@ -15,6 +15,9 @@ import hep.dataforge.vis.common.VisualGroup import hep.dataforge.vis.common.VisualObject import kotlinx.serialization.Serializable import kotlinx.serialization.UseSerializers +import kotlin.collections.component1 +import kotlin.collections.component2 +import kotlin.collections.set /** * A proxy [VisualObject3D] to reuse a template object @@ -63,6 +66,10 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua private val propertyCache: HashMap = HashMap() + fun childPropertyName(childName: Name, propertyName: Name): Name { + return NameToken(PROXY_CHILD_PROPERTY_PREFIX, childName.toString()) + propertyName + } + inner class ProxyChild(val name: Name) : AbstractVisualObject(), VisualGroup { override val children: Map @@ -89,9 +96,16 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua get() = propertyCache[name] set(value) { if (value == null) { - propertyCache.remove(name) + propertyCache.remove(name)?.also { + //Removing listener if it is present + removeChangeListener(this@Proxy) + } } else { - propertyCache[name] = value + propertyCache[name] = value.also { + onPropertyChange(this@Proxy) { propertyName, before, after -> + this@Proxy.propertyChanged(childPropertyName(name, propertyName), before, after) + } + } } } @@ -108,13 +122,18 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua } } } + + companion object { + const val PROXY_CHILD_PROPERTY_PREFIX = "@child" + } } -val VisualObject.prototype: VisualObject? get() = when(this){ - is Proxy -> prototype - is Proxy.ProxyChild -> prototype - else -> null -} +val VisualObject.prototype: VisualObject? + get() = when (this) { + is Proxy -> prototype + is Proxy.ProxyChild -> prototype + else -> null + } inline fun VisualGroup3D.ref( templateName: Name, diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt index 039f17dc..9a18af53 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt @@ -42,6 +42,8 @@ interface VisualObject3D : VisualObject { val DETAIL_KEY = "detail".asName() val LAYER_KEY = "layer".asName() + val GEOMETRY_KEY = "geometey".asName() + val COLOR_KEY = MATERIAL_KEY + "color" val OPACITY_KEY = MATERIAL_KEY + "opacity" diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeCompositeFactory.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeCompositeFactory.kt index 96ff9122..b6ee8852 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeCompositeFactory.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeCompositeFactory.kt @@ -11,9 +11,9 @@ import info.laht.threekt.objects.Mesh class ThreeCompositeFactory(val three: ThreePlugin) : MeshThreeFactory(Composite::class) { override fun buildGeometry(obj: Composite): BufferGeometry { - val first = three.buildObject3D(obj.first.apply { parent = obj.parent }) as? Mesh ?: error("First part of composite is not a mesh") + val first = three.buildObject3D(obj.first) as? Mesh ?: error("First part of composite is not a mesh") first.updateMatrix() - val second = three.buildObject3D(obj.second.apply { parent = obj.parent }) as? Mesh ?: error("Second part of composite is not a mesh") + val second = three.buildObject3D(obj.second) as? Mesh ?: error("Second part of composite is not a mesh") second.updateMatrix() val firstCSG = CSG.fromMesh(first) val secondCSG = CSG.fromMesh(second) diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeFactory.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeFactory.kt index 466e1c4f..e0b4e11a 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeFactory.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeFactory.kt @@ -2,11 +2,14 @@ package hep.dataforge.vis.spatial.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 import hep.dataforge.provider.Type +import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.spatial.* +import hep.dataforge.vis.spatial.VisualObject3D.Companion.GEOMETRY_KEY import hep.dataforge.vis.spatial.three.ThreeFactory.Companion.TYPE import info.laht.threekt.core.BufferGeometry import info.laht.threekt.core.Object3D @@ -115,22 +118,9 @@ abstract class MeshThreeFactory(override val type: KClass - if (name.startsWith(VisualObject3D.MATERIAL_KEY)) { - //updated material - mesh.material = obj.material.jsMaterial() - } else if ( - name.startsWith(VisualObject3D.position) || - name.startsWith(VisualObject3D.rotation) || - name.startsWith(VisualObject3D.scale) - ) { - //update position of mesh using this object - mesh.updatePosition(obj) - } else if (name == VisualObject3D.VISIBLE_KEY) { - mesh.visible = obj.visible ?: true - } else { - //full update + mesh.updateProperty(obj, name) + if (name.startsWith(GEOMETRY_KEY)) { mesh.geometry = geometryBuilder(obj) - mesh.material = obj.material.jsMaterial() } } return mesh @@ -138,6 +128,23 @@ abstract class MeshThreeFactory(override val type: KClass { object3D.updatePosition(obj) obj.onPropertyChange(this) { name, _, _ -> - if (object3D is Mesh && name.startsWith(VisualObject3D.MATERIAL_KEY)) { - //updated material - object3D.material = obj.material.jsMaterial() - } else if ( - name.startsWith(VisualObject3D.position) || - name.startsWith(VisualObject3D.rotation) || - name.startsWith(VisualObject3D.scale) - ) { - //update position of mesh using this object - object3D.updatePosition(obj) - } else if (name == VisualObject3D.VISIBLE_KEY) { - object3D.visible = obj.visible ?: true + if (name.first()?.body == PROXY_CHILD_PROPERTY_PREFIX) { + val childName = name.first()?.index?.toName() ?: error("Wrong syntax for proxy child property: '$name'") + val propertyName = name.cutFirst() + val proxyChild = obj[childName] ?: error("Proxy child with name '$childName' not found") + val child = object3D.findChild(childName)?: error("Object child with name '$childName' not found") + child.updateProperty(proxyChild, propertyName) + } else { + object3D.updateProperty(obj, name) } }