diff --git a/demo/gdml/src/commonMain/kotlin/hep/dataforge/vision/gdml/demo/cubes.kt b/demo/gdml/src/commonMain/kotlin/hep/dataforge/vision/gdml/demo/cubes.kt index e0666f2a..1f0b8cf9 100644 --- a/demo/gdml/src/commonMain/kotlin/hep/dataforge/vision/gdml/demo/cubes.kt +++ b/demo/gdml/src/commonMain/kotlin/hep/dataforge/vision/gdml/demo/cubes.kt @@ -20,7 +20,7 @@ fun cubes(): GDML = GDML { val circle = volume("composite", boxMaterial, smallBox.ref()) { for (i in 0 until 6) { physVolume(segmentVolume) { - name = "segment$i" + name = "segment_$i" positionref = center.ref() rotation { z = 60 * i diff --git a/demo/gdml/src/commonTest/kotlin/hep/dataforge/vision/gdml/GDMLVisualTest.kt b/demo/gdml/src/commonTest/kotlin/hep/dataforge/vision/gdml/GDMLVisualTest.kt index ed3710e3..59545bdf 100644 --- a/demo/gdml/src/commonTest/kotlin/hep/dataforge/vision/gdml/GDMLVisualTest.kt +++ b/demo/gdml/src/commonTest/kotlin/hep/dataforge/vision/gdml/GDMLVisualTest.kt @@ -10,11 +10,21 @@ import kotlin.test.Test import kotlin.test.assertEquals class GDMLVisualTest { + val gdml = cubes() + +// @Test +// fun testCubesStyles(){ +// val cubes = gdml.toVision() +// val segment = cubes["composite000.segment_0".toName()] as Solid +// println(segment.styles) +// println(segment.material) +// } + + @Test fun testPrototypeProperty() { - val gdml = cubes() val visual = gdml.toVision() - visual["composite000.segment0".toName()]?.setItem(SolidMaterial.MATERIAL_COLOR_KEY, "red".asValue()) - assertEquals("red", visual["composite000.segment0".toName()]?.getItem(SolidMaterial.MATERIAL_COLOR_KEY).string) + visual["composite000.segment_0".toName()]?.setItem(SolidMaterial.MATERIAL_COLOR_KEY, "red".asValue()) + assertEquals("red", visual["composite000.segment_0".toName()]?.getItem(SolidMaterial.MATERIAL_COLOR_KEY).string) } } \ No newline at end of file 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 1ff736c9..d4199657 100644 --- a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/StyleSheet.kt +++ b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/StyleSheet.kt @@ -84,7 +84,6 @@ class StyleSheet private constructor(private val styleMap: MutableMap get() = properties[STYLE_KEY].stringList set(value) { - setItem(STYLE_KEY,value.map { it.asValue() }.asValue()) + config[STYLE_KEY] = value } companion object { diff --git a/visionforge-gdml/src/commonMain/kotlin/hep/dataforge/vision/gdml/GDMLTransformer.kt b/visionforge-gdml/src/commonMain/kotlin/hep/dataforge/vision/gdml/GDMLTransformer.kt index 82413d93..ad48480b 100644 --- a/visionforge-gdml/src/commonMain/kotlin/hep/dataforge/vision/gdml/GDMLTransformer.kt +++ b/visionforge-gdml/src/commonMain/kotlin/hep/dataforge/vision/gdml/GDMLTransformer.kt @@ -6,7 +6,6 @@ import hep.dataforge.names.Name import hep.dataforge.names.asName import hep.dataforge.names.plus import hep.dataforge.names.toName -import hep.dataforge.vision.get import hep.dataforge.vision.set import hep.dataforge.vision.solid.* import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY @@ -27,6 +26,7 @@ class GDMLTransformer(val root: GDML) { } var lUnit: LUnit = LUnit.MM + var aUnit: AUnit = AUnit.RADIAN var solidAction: (GDMLSolid) -> Action = { Action.CACHE } var volumeAction: (GDMLGroup) -> Action = { Action.CACHE } @@ -65,10 +65,6 @@ class GDMLTransformer(val root: GDML) { obj.solidConfiguration(parent, solid) } -// -// internal fun solidAdded(solid: GDMLSolid) { -// solidCounter[solid.name] = (solidCounter[solid.name] ?: 0) + 1 -// } var onFinish: GDMLTransformer.() -> Unit = {} @@ -94,6 +90,7 @@ class GDMLTransformer(val root: GDML) { private fun Solid.withPosition( lUnit: LUnit, + aUnit: AUnit = AUnit.RADIAN, newPos: GDMLPosition? = null, newRotation: GDMLRotation? = null, newScale: GDMLScale? = null @@ -105,7 +102,7 @@ private fun Solid.withPosition( } } newRotation?.let { - val point = Point3D(it.x(), it.y(), it.z()) + val point = Point3D(it.x(aUnit), it.y(aUnit), it.z(aUnit)) if (rotation != null || point != World.ZERO) { rotation = point } @@ -120,6 +117,13 @@ private fun Solid.withPosition( //TODO convert units if needed } +private fun Solid.withPosition(context: GDMLTransformer, physVolume: GDMLPhysVolume) = withPosition( + context.lUnit, context.aUnit, + physVolume.resolvePosition(context.root), + physVolume.resolveRotation(context.root), + physVolume.resolveScale(context.root) +) + @Suppress("NOTHING_TO_INLINE") private inline operator fun Number.times(d: Double) = toDouble() * d @@ -129,8 +133,7 @@ private inline operator fun Number.times(f: Float) = toFloat() * f private fun SolidGroup.addSolid( context: GDMLTransformer, solid: GDMLSolid, - name: String = "", - block: Solid.() -> Unit = {} + name: String = "" ): Solid { //context.solidAdded(solid) val lScale = solid.lscale(context.lUnit) @@ -168,11 +171,10 @@ private fun SolidGroup.addSolid( } is GDMLScaledSolid -> { //Add solid with modified scale - val innerSolid = solid.solidref.resolve(context.root) + val innerSolid: GDMLSolid = solid.solidref.resolve(context.root) ?: error("Solid with tag ${solid.solidref.ref} for scaled solid ${solid.name} not defined") - addSolid(context, innerSolid, name) { - block() + addSolid(context, innerSolid, name).apply { scaleX *= solid.scale.x.toFloat() scaleY *= solid.scale.y.toFloat() scaleZ = solid.scale.z.toFloat() @@ -199,8 +201,8 @@ private fun SolidGroup.addSolid( } } is GDMLBoolSolid -> { - val first = solid.first.resolve(context.root) ?: error("") - val second = solid.second.resolve(context.root) ?: error("") + val first: GDMLSolid = solid.first.resolve(context.root) ?: error("") + val second: GDMLSolid = solid.second.resolve(context.root) ?: error("") val type: CompositeType = when (solid) { is GDMLUnion -> CompositeType.UNION is GDMLSubtraction -> CompositeType.SUBTRACT @@ -208,54 +210,51 @@ private fun SolidGroup.addSolid( } return composite(type, name) { - addSolid(context, first) { - withPosition( - context.lUnit, - solid.resolveFirstPosition(context.root), - solid.resolveFirstRotation(context.root), - null - ) - } - addSolid(context, second) { - withPosition( - context.lUnit, - solid.resolvePosition(context.root), - solid.resolveRotation(context.root), - null - ) - } + addSolid(context, first).withPosition( + context.lUnit, context.aUnit, + solid.resolveFirstPosition(context.root), + solid.resolveFirstRotation(context.root), + null + ) + + addSolid(context, second).withPosition( + context.lUnit, context.aUnit, + solid.resolvePosition(context.root), + solid.resolveRotation(context.root), + null + ) + } } else -> error("Renderer for $solid not supported yet") - }.apply(block) + } } +private val solidsName = "solids".asName() + private fun SolidGroup.addSolidWithCaching( context: GDMLTransformer, solid: GDMLSolid, - volume: GDMLVolume, name: String = solid.name -) { - when (context.solidAction(solid)) { +): Solid? { + return when (context.solidAction(solid)) { GDMLTransformer.Action.ACCEPT -> { - addSolid(context, solid, name) { - context.configureSolid(this, volume, solid) - } + addSolid(context, solid, name) } GDMLTransformer.Action.CACHE -> { - if (context.proto[solid.name] == null) { - context.proto.addSolid(context, solid, name) { - context.configureSolid(this, volume, solid) - } + val fullName = solidsName + solid.name.asName() + if (context.proto[fullName] == null) { + val parent = (context.proto[solidsName] as? SolidGroup) ?: context.proto.group(solidsName) + parent.addSolid(context, solid, solid.name) } - ref(solid.name.asName(), name) + ref(fullName, name) } GDMLTransformer.Action.REJECT -> { //ignore + null } } - } private val volumesName = "volumes".asName() @@ -268,31 +267,20 @@ private fun SolidGroup.addPhysicalVolume( ?: error("Volume with ref ${physVolume.volumeref.ref} could not be resolved") // a special case for single solid volume -// if (volume is GDMLVolume && volume.physVolumes.isEmpty() && volume.placement == null) { -// val solid = volume.solidref.resolve(context.root) -// ?: error("Solid with tag ${volume.solidref.ref} for volume ${volume.name} not defined") -// addSolidWithCaching(context, solid, volume, physVolume.name ?: "").apply { -// withPosition( -// context.lUnit, -// physVolume.resolvePosition(context.root), -// physVolume.resolveRotation(context.root), -// physVolume.resolveScale(context.root) -// ) -// } -// return -// } + if (volume is GDMLVolume && volume.physVolumes.isEmpty() && volume.placement == null) { + val solid = volume.solidref.resolve(context.root) + ?: error("Solid with tag ${volume.solidref.ref} for volume ${volume.name} not defined") + addSolidWithCaching(context, solid, physVolume.name ?: "")?.apply { + context.configureSolid(this, volume, solid) + withPosition(context, physVolume) + } + return + } when (context.volumeAction(volume)) { GDMLTransformer.Action.ACCEPT -> { val group: SolidGroup = volume(context, volume) - this[physVolume.name ?: ""] = group.apply { - withPosition( - context.lUnit, - physVolume.resolvePosition(context.root), - physVolume.resolveRotation(context.root), - physVolume.resolveScale(context.root) - ) - } + this[physVolume.name ?: ""] = group.withPosition(context, physVolume) } GDMLTransformer.Action.CACHE -> { val fullName = volumesName + volume.name.asName() @@ -300,14 +288,7 @@ private fun SolidGroup.addPhysicalVolume( context.proto[fullName] = volume(context, volume) } - this[physVolume.name ?: ""] = Proxy(this, fullName).apply { - withPosition( - context.lUnit, - physVolume.resolvePosition(context.root), - physVolume.resolveRotation(context.root), - physVolume.resolveScale(context.root) - ) - } + this[physVolume.name ?: ""] = Proxy(this, fullName).withPosition(context, physVolume) } GDMLTransformer.Action.REJECT -> { //ignore @@ -326,8 +307,6 @@ private fun SolidGroup.addDivisionVolume( set(Name.EMPTY, volume(context, volume)) } -//private val solidsName = "solids".asName() - private fun volume( context: GDMLTransformer, group: GDMLGroup @@ -336,7 +315,9 @@ private fun volume( val solid: GDMLSolid = group.solidref.resolve(context.root) ?: error("Solid with tag ${group.solidref.ref} for volume ${group.name} not defined") - addSolidWithCaching(context, solid, group) + addSolidWithCaching(context, solid)?.apply { + context.configureSolid(this, group, solid) + } when (val vol: GDMLPlacement? = group.placement) { is GDMLPhysVolume -> addPhysicalVolume(context, vol) diff --git a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/Proxy.kt b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/Proxy.kt index 85d122c8..bf2369a7 100644 --- a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/Proxy.kt +++ b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/Proxy.kt @@ -5,7 +5,6 @@ package hep.dataforge.vision.solid import hep.dataforge.meta.* import hep.dataforge.meta.descriptors.NodeDescriptor import hep.dataforge.names.* -import hep.dataforge.values.asValue import hep.dataforge.vision.* import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -13,36 +12,8 @@ import kotlinx.serialization.Transient import kotlinx.serialization.UseSerializers import kotlin.collections.set - -class AbstractProxy - -/** - * A proxy [Solid] to reuse a template object - */ -@Serializable -@SerialName("solid.proxy") -class Proxy private constructor( - val templateName: Name -) : AbstractVision(), VisionGroup, Solid { - - constructor(parent: SolidGroup, templateName: Name) : this(templateName) { - this.parent = parent - } - - override var position: Point3D? = null - override var rotation: Point3D? = null - override var scale: Point3D? = null - - override var properties: Config? = null - - /** - * Recursively search for defined template in the parent - */ - val prototype: Solid - get() = (parent as? SolidGroup)?.getPrototype(templateName) - ?: error("Prototype with name $templateName not found in $parent") - - override val styleSheet: StyleSheet get() = parent?.styleSheet ?: StyleSheet(this) +abstract class AbstractProxy : AbstractVision(), VisionGroup { + abstract val prototype: Vision override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? { return if (inherit) { @@ -61,24 +32,11 @@ class Proxy private constructor( } } - override val children: Map - get() = (prototype as? VisionGroup)?.children - ?.filter { !it.key.toString().startsWith("@") } - ?.mapValues { - ProxyChild(it.key.asName()) - } ?: emptyMap() - - @Transient - private val propertyCache: HashMap = HashMap() - - fun childPropertyName(childName: Name, propertyName: Name): Name { - return NameToken(PROXY_CHILD_PROPERTY_PREFIX, childName.toString()) + propertyName - } - - private fun prototypeFor(name: Name): Vision { - return (prototype as? VisionGroup)?.get(name) - ?: error("Prototype with name $name not found in $this") - } + override var styles: List + get() = properties[Vision.STYLE_KEY].stringList + prototype.styles + set(value) { + config[Vision.STYLE_KEY] = value + } override fun getAllProperties(): Laminate = Laminate(properties, allStyles, prototype.getAllProperties(), parent?.getAllProperties()) @@ -87,29 +45,77 @@ class Proxy private constructor( //do nothing } + override val descriptor: NodeDescriptor? get() = prototype.descriptor +} + +/** + * A proxy [Solid] to reuse a template object + */ +@Serializable +@SerialName("solid.proxy") +class Proxy private constructor( + val templateName: Name +) : AbstractProxy(), Solid { + + constructor(parent: SolidGroup, templateName: Name) : this(templateName) { + this.parent = parent + } + + override var position: Point3D? = null + override var rotation: Point3D? = null + override var scale: Point3D? = null + + override var properties: Config? = null + + /** + * Recursively search for defined template in the parent + */ + override val prototype: Solid + get() = (parent as? SolidGroup)?.getPrototype(templateName) + ?: error("Prototype with name $templateName not found in $parent") + + override val styleSheet: StyleSheet get() = parent?.styleSheet ?: StyleSheet(this) + + @Transient + private val propertyCache: HashMap = HashMap() + + + override val children: Map + get() = (prototype as? VisionGroup)?.children + ?.filter { !it.key.toString().startsWith("@") } + ?.mapValues { + ProxyChild(it.key.asName()) + } ?: emptyMap() + + private fun childPropertyName(childName: Name, propertyName: Name): Name { + return NameToken(PROXY_CHILD_PROPERTY_PREFIX, childName.toString()) + propertyName + } + + private fun prototypeFor(name: Name): Vision { + return (prototype as? VisionGroup)?.get(name) + ?: error("Prototype with name $name not found in $this") + } + + override val descriptor: NodeDescriptor? get() = prototype.descriptor + //override fun findAllStyles(): Laminate = Laminate((styles + prototype.styles).mapNotNull { findStyle(it) }) - override var styles: List - get() = properties[Vision.STYLE_KEY].stringList + prototype.styles - set(value) { - setItem(Vision.STYLE_KEY, value.map { it.asValue() }.asValue()) - } + /** + * A ProxyChild is created temporarily only to interact with properties, it does not store any values + * (properties are stored in external cache) and created and destroyed on-demand). + */ + inner class ProxyChild(val name: Name) : AbstractProxy() { - override val descriptor: NodeDescriptor? - get() = prototype.descriptor - - inner class ProxyChild(val name: Name) : AbstractVision(), VisionGroup { - - val prototype: Vision get() = prototypeFor(name) + override val prototype: Vision get() = prototypeFor(name) override val styleSheet: StyleSheet get() = this@Proxy.styleSheet override val children: Map - get() = (prototype as? VisionGroup)?.children?.mapValues { (key, _) -> - ProxyChild( - name + key.asName() - ) - } ?: emptyMap() + get() = (prototype as? VisionGroup)?.children + ?.filter { !it.key.toString().startsWith("@") } + ?.mapValues { (key, _) -> + ProxyChild(name + key.asName()) + } ?: emptyMap() override var properties: Config? get() = propertyCache[name] @@ -128,39 +134,6 @@ class Proxy private constructor( } } - override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? { - return if (inherit) { - sequence { - yield(properties?.get(name)) - yieldAll(getStyleItems(name)) - yield(prototype.getItem(name)) - yield(parent?.getProperty(name, inherit)) - }.merge() - } else { - sequence { - yield(properties?.get(name)) - yieldAll(getStyleItems(name)) - yield(prototype.getProperty(name, false)) - }.merge() - } - } - - override fun attachChildren() { - //do nothing - } - - override fun getAllProperties(): Laminate = - Laminate(properties, allStyles, prototype.getAllProperties(), parent?.getAllProperties()) - - - override var styles: List - get() = properties[Vision.STYLE_KEY].stringList + prototype.styles - set(value) { - setItem(Vision.STYLE_KEY, value.map { it.asValue() }.asValue()) - } - - override val descriptor: NodeDescriptor? - get() = prototype.descriptor } companion object { @@ -170,8 +143,7 @@ class Proxy private constructor( val Vision.prototype: Vision get() = when (this) { - is Proxy -> prototype - is Proxy.ProxyChild -> prototype + is AbstractProxy -> prototype else -> this } 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 e7f17c9b..83e2deff 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 @@ -99,13 +99,14 @@ fun SolidGroup(block: SolidGroup.() -> Unit): SolidGroup { tailrec fun PrototypeHolder.getPrototype(name: Name): Solid? = prototypes?.get(name) as? Solid ?: (parent as? PrototypeHolder)?.getPrototype(name) +fun MutableVisionGroup.group(name: Name = Name.EMPTY, action: SolidGroup.() -> Unit = {}): SolidGroup = + SolidGroup().apply(action).also { set(name, it) } + /** * Define a group with given [name], attach it to this parent and return it. */ -fun MutableVisionGroup.group(name: String = "", action: SolidGroup.() -> Unit = {}): SolidGroup = - SolidGroup().apply(action).also { - set(name, it) - } +fun MutableVisionGroup.group(name: String, action: SolidGroup.() -> Unit = {}): SolidGroup = + SolidGroup().apply(action).also { set(name, it) } /** * A special class which works as a holder for prototypes 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 eb7192c0..ac153ab5 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 @@ -35,19 +35,11 @@ abstract class MeshThreeFactory( //val meshMeta: Meta = obj.properties[Material3D.MATERIAL_KEY]?.node ?: Meta.empty - val mesh = Mesh(geometry, getMaterial(obj, true)).apply { + val mesh = Mesh(geometry, null).apply{ matrixAutoUpdate = false - applyEdges(obj) - applyWireFrame(obj) - //set position for mesh updatePosition(obj) - - layers.enable(obj.layer) - children.forEach { - it.layers.enable(obj.layer) - } - } + }.applyProperties(obj) //add listener to object properties obj.onPropertyChange(this) { name -> @@ -79,6 +71,16 @@ abstract class MeshThreeFactory( } } +fun Mesh.applyProperties(obj: Solid): Mesh = apply{ + material = getMaterial(obj, true) + applyEdges(obj) + applyWireFrame(obj) + layers.enable(obj.layer) + children.forEach { + it.layers.enable(obj.layer) + } +} + fun Mesh.applyEdges(obj: Solid) { val edges = children.find { it.name == "@edges" } as? LineSegments //inherited edges definition, enabled by default 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 8b83ef16..c432fbd3 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 @@ -41,18 +41,6 @@ fun Object3D.updatePosition(obj: Vision) { } } -///** -// * Unsafe invocation of a factory -// */ -//operator fun ThreeFactory.invoke(obj: Any): Object3D { -// if (type.isInstance(obj)) { -// @Suppress("UNCHECKED_CAST") -// return invoke(obj as T) -// } else { -// error("The object of type ${obj::class} could not be rendered by this factory") -// } -//} - /** * Update non-position non-geometry property */ 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 2fd83dfa..9063a968 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 @@ -4,7 +4,6 @@ import hep.dataforge.names.toName import hep.dataforge.vision.solid.Proxy import hep.dataforge.vision.solid.Proxy.Companion.PROXY_CHILD_PROPERTY_PREFIX import hep.dataforge.vision.solid.Solid -import info.laht.threekt.core.BufferGeometry import info.laht.threekt.core.Object3D import info.laht.threekt.objects.Mesh import kotlin.reflect.KClass @@ -14,16 +13,16 @@ class ThreeProxyFactory(val three: ThreePlugin) : ThreeFactory { override val type: KClass = Proxy::class - private fun Object3D.replicate(): Object3D { - return when (this) { - is Mesh -> Mesh(geometry as BufferGeometry, material) - else -> clone(false) - }.also { obj: Object3D -> - children.forEach { child: Object3D -> - obj.add(child.replicate()) - } - } - } +// private fun Object3D.replicate(): Object3D { +// return when (this) { +// is Mesh -> Mesh(geometry as BufferGeometry, material) +// else -> clone(false) +// }.also { obj: Object3D -> +// children.forEach { child: Object3D -> +// obj.add(child.replicate()) +// } +// } +// } override fun invoke(obj: Proxy): Object3D { val template = obj.prototype @@ -31,10 +30,13 @@ class ThreeProxyFactory(val three: ThreePlugin) : ThreeFactory { three.buildObject3D(template) } - val object3D: Object3D = cachedObject.replicate() - + val object3D: Object3D = cachedObject.clone()//cachedObject.replicate() object3D.updatePosition(obj) + if(object3D is Mesh){ + object3D.applyProperties(obj) + } + obj.onPropertyChange(this) { name -> if (name.first()?.body == PROXY_CHILD_PROPERTY_PREFIX) { val childName = name.first()?.index?.toName() ?: error("Wrong syntax for proxy child property: '$name'") diff --git a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/outputConfig.kt b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/outputConfig.kt index fe01bba8..2956f8cc 100644 --- a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/outputConfig.kt +++ b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/outputConfig.kt @@ -1,6 +1,7 @@ package hep.dataforge.vision.solid.three import hep.dataforge.js.requireJS +import hep.dataforge.meta.DFExperimental import hep.dataforge.vision.bootstrap.accordion import hep.dataforge.vision.bootstrap.entry import hep.dataforge.vision.solid.SolidGroup @@ -31,6 +32,7 @@ private fun saveData(event: Event, fileName: String, mimeType: String = "text/pl fileSaver.saveAs(blob, fileName) } +@OptIn(DFExperimental::class) fun RBuilder.canvasControls(canvas: ThreeCanvas) = accordion("controls") { entry("Settings") { div("row") { diff --git a/visionforge-solid/src/jsMain/kotlin/info/laht/threekt/objects/Mesh.kt b/visionforge-solid/src/jsMain/kotlin/info/laht/threekt/objects/Mesh.kt index 6c5b4555..78dcb9f6 100644 --- a/visionforge-solid/src/jsMain/kotlin/info/laht/threekt/objects/Mesh.kt +++ b/visionforge-solid/src/jsMain/kotlin/info/laht/threekt/objects/Mesh.kt @@ -33,8 +33,8 @@ import info.laht.threekt.materials.Material open external class Mesh : Object3D { - constructor(geometry: Geometry, material: Material) - constructor(geometry: BufferGeometry, material: Material) + constructor(geometry: Geometry?, material: Material?) + constructor(geometry: BufferGeometry?, material: Material?) var geometry: dynamic var material: Material