Improve dancing boxes performance. A lot.

This commit is contained in:
Alexander Nozik 2021-05-09 22:40:30 +03:00
parent b8fadb06b5
commit 5afa9117c4
10 changed files with 48 additions and 146 deletions

View File

@ -7,7 +7,7 @@ plugins {
id("ru.mipt.npm.gradle.js") apply false id("ru.mipt.npm.gradle.js") apply false
} }
val dataforgeVersion by extra("0.4.0") val dataforgeVersion by extra("0.4.1")
val kotlinWrappersVersion by extra("pre.152-kotlin-1.4.32") val kotlinWrappersVersion by extra("pre.152-kotlin-1.4.32")
val fxVersion by extra("11") val fxVersion by extra("11")

View File

@ -23,7 +23,7 @@ private class ThreeDemoApp : Application {
demo("dynamicBox", "Dancing boxes") { demo("dynamicBox", "Dancing boxes") {
val boxes = (-10..10).flatMap { i -> val boxes = (-10..10).flatMap { i ->
(-10..10).map { j -> (-10..10).map { j ->
varBox(10, 10, 0, name = "cell_${i}_${j}") { varBox(10, 10, name = "cell_${i}_${j}") {
x = i * 10 x = i * 10
y = j * 10 y = j * 10
value = 128 value = 128

View File

@ -1,49 +1,37 @@
package space.kscience.visionforge.solid.demo package space.kscience.visionforge.solid.demo
import info.laht.threekt.core.BufferGeometry
import info.laht.threekt.core.Object3D import info.laht.threekt.core.Object3D
import info.laht.threekt.geometries.BoxBufferGeometry import info.laht.threekt.geometries.BoxBufferGeometry
import info.laht.threekt.objects.Mesh import info.laht.threekt.objects.Mesh
import space.kscience.dataforge.meta.int import space.kscience.dataforge.meta.int
import space.kscience.dataforge.meta.number import space.kscience.dataforge.meta.number
import space.kscience.dataforge.names.plus import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.startsWith import space.kscience.dataforge.names.startsWith
import space.kscience.dataforge.values.asValue import space.kscience.dataforge.values.asValue
import space.kscience.visionforge.getProperty
import space.kscience.visionforge.onPropertyChange import space.kscience.visionforge.onPropertyChange
import space.kscience.visionforge.set import space.kscience.visionforge.set
import space.kscience.visionforge.setProperty import space.kscience.visionforge.setProperty
import space.kscience.visionforge.solid.* import space.kscience.visionforge.solid.SolidGroup
import space.kscience.visionforge.solid.Solid.Companion.GEOMETRY_KEY import space.kscience.visionforge.solid.layer
import space.kscience.visionforge.solid.three.* import space.kscience.visionforge.solid.three.*
import kotlin.math.max import kotlin.math.max
internal fun SolidGroup.varBox( internal fun SolidGroup.varBox(
xSize: Number, xSize: Number,
ySize: Number, ySize: Number,
zSize: Number,
name: String = "", name: String = "",
action: VariableBox.() -> Unit = {}, action: VariableBox.() -> Unit = {},
): VariableBox = VariableBox(xSize, ySize, zSize).apply(action).also { set(name, it) } ): VariableBox = VariableBox(xSize, ySize).apply(action).also { set(name, it) }
internal class VariableBox(xSize: Number, ySize: Number, zSize: Number) : ThreeVision() { internal class VariableBox(val xSize: Number, val ySize: Number) : ThreeVision() {
init {
scaleX = xSize
scaleY = ySize
scaleZ = zSize
}
override fun render(three: ThreePlugin): Object3D { override fun render(three: ThreePlugin): Object3D {
val xSize = getProperty(X_SIZE_KEY, false).number?.toDouble() ?: 1.0 val geometry = BoxBufferGeometry(xSize, ySize, 1)
val ySize = getProperty(Y_SIZE_KEY, false).number?.toDouble() ?: 1.0
val zSize = getProperty(Z_SIZE_KEY, false).number?.toDouble() ?: 1.0
val geometry = BoxBufferGeometry(1, 1, 1)
//JS sometimes tries to pass Geometry as BufferGeometry val material = ThreeMaterials.DEFAULT.clone()
@Suppress("USELESS_IS_CHECK") if (geometry !is BufferGeometry) error("BufferGeometry expected")
val mesh = Mesh(geometry, ThreeMaterials.DEFAULT).apply { val mesh = Mesh(geometry, material).apply {
updateMaterial(this@VariableBox) //updateMaterial(this@VariableBox)
applyEdges(this@VariableBox) applyEdges(this@VariableBox)
//applyWireFrame(this@VariableBox) //applyWireFrame(this@VariableBox)
@ -55,21 +43,24 @@ internal class VariableBox(xSize: Number, ySize: Number, zSize: Number) : ThreeV
it.layers.enable(this@VariableBox.layer) it.layers.enable(this@VariableBox.layer)
} }
} }
mesh.scale.z = getOwnProperty(VALUE).number?.toDouble() ?: 1.0
mesh.scale.set(xSize, ySize, zSize)
//add listener to object properties //add listener to object properties
onPropertyChange(three.context) { name -> onPropertyChange(three.context) { name ->
when { when {
name.startsWith(GEOMETRY_KEY) -> { name == VALUE -> {
val newXSize = getProperty(X_SIZE_KEY, false).number?.toDouble() ?: 1.0 val value = getOwnProperty(VALUE).int ?: 0
val newYSize = getProperty(Y_SIZE_KEY, false).number?.toDouble() ?: 1.0 val size = value.toFloat() / 255f * 20f
val newZSize = getProperty(Z_SIZE_KEY, false).number?.toDouble() ?: 1.0 mesh.scale.z = size.toDouble()
mesh.scale.set(newXSize, newYSize, newZSize) mesh.position.z = size.toDouble() / 2
val b = max(0, 128 - value)
val r = max(0, value - 128)
val g = 255 - b - r
material.color.setRGB(r.toFloat() / 256, g.toFloat() / 256, b.toFloat() / 256)
mesh.updateMatrix() mesh.updateMatrix()
} }
name.startsWith(MeshThreeFactory.EDGES_KEY) -> mesh.applyEdges(this@VariableBox) name.startsWith(MeshThreeFactory.EDGES_KEY) -> mesh.applyEdges(this@VariableBox)
//name.startsWith(MATERIAL_COLOR_KEY) -> mesh.updateMaterialProperty(this, name)
else -> mesh.updateProperty(this@VariableBox, name) else -> mesh.updateProperty(this@VariableBox, name)
} }
} }
@ -77,29 +68,17 @@ internal class VariableBox(xSize: Number, ySize: Number, zSize: Number) : ThreeV
return mesh return mesh
} }
var variableZSize: Number
get() = getProperty(Z_SIZE_KEY, false).number ?: 0f
set(value) {
setProperty(Z_SIZE_KEY, value.asValue())
}
var value: Int var value: Int
get() = getProperty("value", false).int ?: 0 get() = getOwnProperty(VALUE).int ?: 0
set(value) { set(value) {
setProperty("value", value.asValue()) setProperty(VALUE, value.asValue())
val size = value.toFloat() / 255f * 20f
scaleZ = size
z = size / 2
val b = max(0, 128 - value)
val r = max(0, value - 128)
val g = 255 - b - r
color(r.toUByte(), g.toUByte(), b.toUByte())
} }
companion object { companion object {
private val X_SIZE_KEY = GEOMETRY_KEY + "xSize" private val VALUE = "value".asName()
private val Y_SIZE_KEY = GEOMETRY_KEY + "ySize" //
private val Z_SIZE_KEY = GEOMETRY_KEY + "zSize" // private val X_SIZE_KEY = GEOMETRY_KEY + "xSize"
// private val Y_SIZE_KEY = GEOMETRY_KEY + "ySize"
// private val Z_SIZE_KEY = GEOMETRY_KEY + "zSize"
} }
} }

View File

@ -11,7 +11,6 @@ import org.w3c.files.Blob
import org.w3c.files.BlobPropertyBag import org.w3c.files.BlobPropertyBag
import react.* import react.*
import react.dom.button import react.dom.button
import space.kscience.dataforge.meta.descriptors.defaultMeta
import space.kscience.dataforge.meta.withDefault import space.kscience.dataforge.meta.withDefault
import space.kscience.visionforge.react.flexColumn import space.kscience.visionforge.react.flexColumn
import space.kscience.visionforge.react.flexRow import space.kscience.visionforge.react.flexRow
@ -71,81 +70,9 @@ public val CanvasControls: FunctionalComponent<CanvasControlsProps> = functional
} }
propertyEditor( propertyEditor(
ownProperties = props.canvas.options, ownProperties = props.canvas.options,
allProperties = props.canvas.options.withDefault(Canvas3DOptions.descriptor.defaultMeta()), allProperties = props.canvas.options.withDefault(Canvas3DOptions.descriptor.defaultMeta),
descriptor = Canvas3DOptions.descriptor, descriptor = Canvas3DOptions.descriptor,
expanded = false expanded = false
) )
/* h3 { +"Axes" }
flexRow {
css{
border(1.px,BorderStyle.solid, Color.blue)
padding(4.px)
}
label("checkbox-inline") {
input(type = InputType.checkBox) {
attrs {
defaultChecked = props.canvas.options.axes.visible
onChangeFunction = {
props.canvas.options.axes.visible = (it.target as HTMLInputElement).checked
}
}
}
+"Axes"
}
}
h3 { +"Export" }
flexRow {
css{
border(1.px,BorderStyle.solid, Color.blue)
padding(4.px)
}
button {
+"Export"
attrs {
onClickFunction = {
val json = (props.canvas.content as? SolidGroup)?.let { group ->
visionManager.encodeToString(group)
}
if (json != null) {
saveData(it, "object.json", "text/json") {
json
}
}
}
}
}
}
h3 { +"Layers" }
flexRow {
css {
flexWrap = FlexWrap.wrap
border(1.px,BorderStyle.solid, Color.blue)
padding(4.px)
}
(0..31).forEach { layer ->
styledDiv {
css{
padding(4.px)
}
label { +layer.toString() }
input(type = InputType.checkBox) {
attrs {
if (layer == 0) {
defaultChecked = true
}
onChangeFunction = {
if ((it.target as HTMLInputElement).checked) {
props.canvas.camera.layers.enable(layer)
} else {
props.canvas.camera.layers.disable(layer)
}
}
}
}
}
}
}
*/
} }
} }

View File

@ -9,7 +9,6 @@ import space.kscience.dataforge.meta.MetaItemNode
import space.kscience.dataforge.meta.MetaItemValue import space.kscience.dataforge.meta.MetaItemValue
import space.kscience.dataforge.meta.descriptors.ItemDescriptor import space.kscience.dataforge.meta.descriptors.ItemDescriptor
import space.kscience.dataforge.meta.descriptors.NodeDescriptor import space.kscience.dataforge.meta.descriptors.NodeDescriptor
import space.kscience.dataforge.meta.descriptors.defaultItem
import space.kscience.dataforge.meta.descriptors.get import space.kscience.dataforge.meta.descriptors.get
import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.get
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
@ -43,7 +42,7 @@ private fun RBuilder.metaViewerItem(props: MetaViewerProps) {
var expanded: Boolean by useState { true } var expanded: Boolean by useState { true }
val item = props.root[props.name] val item = props.root[props.name]
val descriptorItem: ItemDescriptor? = props.descriptor?.get(props.name) val descriptorItem: ItemDescriptor? = props.descriptor?.get(props.name)
val actualItem = item ?: descriptorItem?.defaultItem() val actualItem = item ?: descriptorItem?.defaultValue
val token = props.name.lastOrNull()?.toString() ?: "Meta" val token = props.name.lastOrNull()?.toString() ?: "Meta"

View File

@ -12,7 +12,6 @@ import react.dom.h2
import ringui.island.ringIsland import ringui.island.ringIsland
import ringui.tabs.ringSmartTabs import ringui.tabs.ringSmartTabs
import ringui.tabs.ringTab import ringui.tabs.ringTab
import space.kscience.dataforge.meta.descriptors.defaultMeta
import space.kscience.dataforge.meta.withDefault import space.kscience.dataforge.meta.withDefault
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.isEmpty import space.kscience.dataforge.names.isEmpty
@ -78,7 +77,7 @@ internal val CanvasControls: FunctionalComponent<CanvasControlsProps> = function
} }
propertyEditor( propertyEditor(
ownProperties = props.canvas.options, ownProperties = props.canvas.options,
allProperties = props.canvas.options.withDefault(Canvas3DOptions.descriptor.defaultMeta()), allProperties = props.canvas.options.withDefault(Canvas3DOptions.descriptor.defaultMeta),
descriptor = Canvas3DOptions.descriptor, descriptor = Canvas3DOptions.descriptor,
expanded = false expanded = false
) )

View File

@ -98,8 +98,8 @@ public tailrec fun Vision.getStyle(name: String): Meta? =
/** /**
* Resolve an item in all style layers * Resolve an item in all style layers
*/ */
public fun Vision.getStyleItems(name: Name): Sequence<MetaItem> = styles.asSequence().map { public fun Vision.getStyleItems(name: Name): List<MetaItem> = styles.mapNotNull {
getStyle(it)[name] getStyle(it)[name]
}.filterNotNull() }

View File

@ -10,8 +10,6 @@ import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient import kotlinx.serialization.Transient
import space.kscience.dataforge.meta.* import space.kscience.dataforge.meta.*
import space.kscience.dataforge.meta.descriptors.NodeDescriptor import space.kscience.dataforge.meta.descriptors.NodeDescriptor
import space.kscience.dataforge.meta.descriptors.defaultItem
import space.kscience.dataforge.meta.descriptors.get
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.asName
@ -66,16 +64,16 @@ public open class VisionBase(
): MetaItem? = if (!inherit && !includeStyles && !includeDefaults) { ): MetaItem? = if (!inherit && !includeStyles && !includeDefaults) {
getOwnProperty(name) getOwnProperty(name)
} else { } else {
sequence { buildList {
yield(getOwnProperty(name)) add(getOwnProperty(name))
if (includeStyles) { if (includeStyles) {
yieldAll(getStyleItems(name)) addAll(getStyleItems(name))
} }
if (inherit) { if (inherit) {
yield(parent?.getProperty(name, inherit, includeStyles, includeDefaults)) add(parent?.getProperty(name, inherit, includeStyles, includeDefaults))
} }
if (includeDefaults) { if (includeDefaults) {
yield(descriptor?.get(name)?.defaultItem()) add(descriptor?.defaultMeta?.get(name))
} }
}.merge() }.merge()
} }

View File

@ -6,12 +6,12 @@ import space.kscience.dataforge.values.asValue
@DslMarker @DslMarker
public annotation class VisionBuilder public annotation class VisionBuilder
public fun Sequence<MetaItem?>.merge(): MetaItem? = when (val first = firstOrNull { it != null }) { public fun List<MetaItem?>.merge(): MetaItem? = when (val first = firstOrNull { it != null }) {
null -> null null -> null
is MetaItemValue -> first //fast search for first entry if it is value is MetaItemValue -> first //fast search for first entry if it is value
is MetaItemNode -> { is MetaItemNode -> {
//merge nodes if first encountered node is meta //merge nodes if first encountered node is meta
val laminate: Laminate = Laminate(mapNotNull { it.node }.toList()) val laminate: Laminate = Laminate(mapNotNull { it.node })
MetaItemNode(laminate) MetaItemNode(laminate)
} }
} }

View File

@ -20,14 +20,14 @@ private fun SolidReference.getRefProperty(
inherit: Boolean, inherit: Boolean,
includeStyles: Boolean, includeStyles: Boolean,
includeDefaults: Boolean, includeDefaults: Boolean,
): MetaItem? = sequence { ): MetaItem? = buildList {
yield(getOwnProperty(name)) add(getOwnProperty(name))
if (includeStyles) { if (includeStyles) {
yieldAll(getStyleItems(name)) addAll(getStyleItems(name))
} }
yield(prototype.getProperty(name, inherit, includeStyles, includeDefaults)) add(prototype.getProperty(name, inherit, includeStyles, includeDefaults))
if (inherit) { if (inherit) {
yield(parent?.getProperty(name, inherit)) add(parent?.getProperty(name, inherit))
} }
}.merge() }.merge()
@ -45,8 +45,8 @@ public class SolidReferenceGroup(
*/ */
override val prototype: Solid override val prototype: Solid
get() { get() {
if(parent == null) error("No parent is present for SolidReferenceGroup") if (parent == null) error("No parent is present for SolidReferenceGroup")
if(parent !is SolidGroup) error("Reference parent is not a group") if (parent !is SolidGroup) error("Reference parent is not a group")
return (parent as? SolidGroup)?.getPrototype(refName) return (parent as? SolidGroup)?.getPrototype(refName)
?: error("Prototype with name $refName not found") ?: error("Prototype with name $refName not found")
} }