diff --git a/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/GDMLAppComponent.kt b/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/GDMLAppComponent.kt index fe2d377c..4f6560b6 100644 --- a/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/GDMLAppComponent.kt +++ b/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/GDMLAppComponent.kt @@ -10,6 +10,7 @@ import space.kscience.dataforge.context.fetch import space.kscience.dataforge.names.Name import space.kscience.gdml.Gdml import space.kscience.gdml.decodeFromString +import space.kscience.visionforge.gdml.markLayers import space.kscience.visionforge.gdml.toVision import space.kscience.visionforge.ring.ThreeCanvasWithControls import space.kscience.visionforge.ring.tab @@ -33,8 +34,9 @@ val GDMLApp = functionalComponent("GDMLApp") { props -> name.endsWith(".gdml") || name.endsWith(".xml") -> { val gdml = Gdml.decodeFromString(data) gdml.toVision().apply { -// console.info("Marking layers for file $name") -// markLayers() + root(visionManager) + console.info("Marking layers for file $name") + markLayers() } } name.endsWith(".json") -> visionManager.decodeFromString(data) diff --git a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/markLayers.kt b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/markLayers.kt index 2689d1d6..a47374d0 100644 --- a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/markLayers.kt +++ b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/markLayers.kt @@ -1,5 +1,7 @@ package space.kscience.visionforge.gdml +import space.kscience.dataforge.context.info +import space.kscience.dataforge.context.logger import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.NameToken import space.kscience.dataforge.names.length @@ -7,24 +9,36 @@ import space.kscience.dataforge.names.plus import space.kscience.visionforge.VisionGroup import space.kscience.visionforge.solid.Solid import space.kscience.visionforge.solid.SolidGroup +import space.kscience.visionforge.solid.SolidReferenceGroup import space.kscience.visionforge.solid.layer + private class VisionCounterTree( val name: Name, val vision: Solid, + val prototypes: HashMap ) { - val children: Map = - (vision as? VisionGroup)?.children?.mapValues { - VisionCounterTree(name + it.key, it.value as Solid) + + // self count for prototypes + var selfCount = 1 + + val children: Map by lazy { + (vision as? VisionGroup)?.children?.mapValues { (key, vision) -> + if (vision is SolidReferenceGroup) { + prototypes.getOrPut(vision.refName) { + VisionCounterTree(vision.refName, vision.prototype, prototypes) + }.apply { + selfCount += 1 + } + } else { + VisionCounterTree(name + key, vision as Solid, prototypes) + } } ?: emptyMap() + } -// -// val directChildrenCount: Int by lazy { -// children.size -// } - - val childrenCount: Int = + val childrenCount: Int by lazy { children.values.sumOf { it.childrenCount + 1 } + } } @@ -36,27 +50,41 @@ private fun VisionCounterTree.topToBottom(): Sequence = seque } } -public fun SolidGroup.markLayers(thresholds: List = listOf(1000, 20000, 100000)) { - val counterTree = VisionCounterTree(Name.EMPTY, this) +public fun SolidGroup.markLayers(thresholds: List = listOf(500, 1000, 20000, 50000)) { + val logger = manager?.context?.logger + val counterTree = VisionCounterTree(Name.EMPTY, this, hashMapOf()) val totalCount = counterTree.childrenCount if (totalCount > thresholds.firstOrNull() ?: 0) { - val allNodes = counterTree.topToBottom().toMutableList() + val allNodes = counterTree.topToBottom().filter { it.selfCount > 1 }.distinct().toMutableList() //println("tree construction finished") - allNodes.sortWith(compareBy({ it.name.length }, { it.childrenCount }).reversed()) + allNodes.sortWith( + compareBy( + { it.name.length }, + { it.childrenCount * it.selfCount } + ).reversed() + ) //mark layers - var removed = 0 - var thresholdIndex = thresholds.indexOfLast { it < totalCount } + var remaining = totalCount for (node in allNodes) { - node.vision.layer = thresholdIndex + 1 - removed++ - if (totalCount - removed < thresholds[thresholdIndex]) { - thresholdIndex-- + val layerIndex = if (remaining > thresholds.last()) + thresholds.size + else + thresholds.indexOfLast { remaining < it } + + if (layerIndex == 0) break + + node.vision.layer = layerIndex + val removedCount = node.selfCount * node.children.size + logger?.apply { + if (node.selfCount > 1) { + info { "Prototype with name ${node.name} moved to layer $layerIndex" } + } else { + info { "Vision with name ${node.name} moved to layer $layerIndex" } + } } - if (thresholdIndex < 0) break + remaining -= removedCount } - - } } \ No newline at end of file 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 1ba659b9..1cb5eac8 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 @@ -99,15 +99,15 @@ public class SolidReferenceGroup( */ private class ReferenceChild( val owner: SolidReferenceGroup, - private val childName: Name + private val refName: Name ) : SolidReference, VisionGroup, Solid { override val prototype: Solid by lazy { - if (childName.isEmpty()) owner.prototype else { - val proto = (owner.prototype as? VisionGroup)?.get(childName) - ?: error("Prototype with name $childName not found in SolidReferenceGroup ${owner.refName}") + 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 $childName is ${proto::class} but expected Solid") + ?: error("Prototype with name $refName is ${proto::class} but expected Solid") } } @@ -115,14 +115,14 @@ public class SolidReferenceGroup( get() = (prototype as? VisionGroup)?.children ?.filter { it.key != SolidGroup.PROTOTYPES_TOKEN } ?.mapValues { (key, _) -> - ReferenceChild(owner, childName + key.asName()) + ReferenceChild(owner, refName + key.asName()) } ?: emptyMap() override fun getOwnProperty(name: Name): MetaItem? = - owner.getOwnProperty(childPropertyName(childName, name)) + owner.getOwnProperty(childPropertyName(refName, name)) override fun setProperty(name: Name, item: MetaItem?, notify: Boolean) { - owner.setProperty(childPropertyName(childName, name), item, notify) + owner.setProperty(childPropertyName(refName, name), item, notify) } override fun getProperty( @@ -134,7 +134,7 @@ public class SolidReferenceGroup( override var parent: VisionGroup? get() { - val parentName = childName.cutLast() + val parentName = refName.cutLast() return if (parentName.isEmpty()) owner else ReferenceChild(owner, parentName) } set(_) { @@ -144,7 +144,7 @@ public class SolidReferenceGroup( @DFExperimental override val propertyChanges: Flow get() = owner.propertyChanges.mapNotNull { name -> - if (name.startsWith(childToken(childName))) { + if (name.startsWith(childToken(refName))) { name.cutFirst() } else { null @@ -152,7 +152,7 @@ public class SolidReferenceGroup( } override fun invalidateProperty(propertyName: Name) { - owner.invalidateProperty(childPropertyName(childName, propertyName)) + owner.invalidateProperty(childPropertyName(refName, propertyName)) } override fun update(change: VisionChange) { 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 14665a8b..7cbd4d3d 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 @@ -74,9 +74,9 @@ internal fun Mesh.applyProperties(obj: Solid): Mesh = apply { updateMaterial(obj) applyEdges(obj) //applyWireFrame(obj) - layers.enable(obj.layer) + layers.set(obj.layer) children.forEach { - it.layers.enable(obj.layer) + it.layers.set(obj.layer) } } diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvas.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvas.kt index 7dd89a32..3afb6776 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvas.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvas.kt @@ -250,8 +250,11 @@ public class ThreeCanvas( } public fun render(vision: Solid) { - three.logger.info { "Replacing root node in three canvas" } - scene.findChild("@root".asName())?.let { scene.remove(it) } + if (root != null) { + three.logger.info { "Replacing root node in three canvas" } + scene.findChild("@root".asName())?.let { scene.remove(it) } + root?.dispose() + } val object3D = three.buildObject3D(vision) object3D.name = "@root" diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeGeometryBuilder.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeGeometryBuilder.kt index 4f3e0b58..c1c5aa72 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeGeometryBuilder.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeGeometryBuilder.kt @@ -54,6 +54,9 @@ public class ThreeGeometryBuilder : GeometryBuilder { setAttribute("position", Float32BufferAttribute(positions.toTypedArray(), 3)) setAttribute("normal", Float32BufferAttribute(normals.toTypedArray(), 3)) //setAttribute("color", Float32BufferAttribute(colors.toFloatArray(), 3)) + //a temporary fix for CSG problem + val uvsArray = Array((counter+1)*2){0f} + setAttribute("uv", Float32BufferAttribute(uvsArray, 2)) computeBoundingSphere() }