diff --git a/CHANGELOG.md b/CHANGELOG.md index dbb44a80..87fe2343 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Added - Context receivers flag - MeshLine for thick lines +- Custom client-side events and thier processing in VisionServer ### Changed - Color accessor property is now `colorProperty`. Color uses `invoke` instead of `set` diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/dRootToSolid.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/dRootToSolid.kt index c81ca577..ba3e4616 100644 --- a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/dRootToSolid.kt +++ b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/dRootToSolid.kt @@ -3,6 +3,7 @@ package ru.mipt.npm.root import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.double import space.kscience.dataforge.meta.int +import space.kscience.dataforge.meta.set import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.parseAsName import space.kscience.dataforge.names.plus @@ -12,7 +13,6 @@ import space.kscience.kmath.geometry.fromRotationMatrix import space.kscience.kmath.linear.VirtualMatrix import space.kscience.visionforge.MutableVisionContainer import space.kscience.visionforge.isEmpty -import space.kscience.visionforge.set import space.kscience.visionforge.solid.* import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY import kotlin.math.PI @@ -188,7 +188,7 @@ private fun SolidGroup.addShape( } "TGeoPgon" -> { - //TODO add a inner polygone layer + val fDphi by shape.meta.double(0.0) val fNz by shape.meta.int(2) val fPhi1 by shape.meta.double(360.0) @@ -201,19 +201,26 @@ private fun SolidGroup.addShape( val startphi = degToRad(fPhi1) val deltaphi = degToRad(fDphi) - extruded(name) { + fun Shape2DBuilder.pGon(radius: Double){ + (0.. 1) { "The polyhedron geometry requires at least two planes" } - val baseRadius = fRmax[0] - shape { - (0.. - //scaling all radii relative to first layer radius - layer(fZ[index], scale = fRmax[index] / baseRadius) + for (index in 0 until fNz){ + layer( + fZ[index], + innerBuilder = { + pGon(fRmin[index]) + }, + outerBuilder = { + pGon(fRmax[index]) + } + ) } }.apply(block) } diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/serialization/jsonToRoot.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/serialization/jsonToRoot.kt index c443f646..e3cf446c 100644 --- a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/serialization/jsonToRoot.kt +++ b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/serialization/jsonToRoot.kt @@ -12,6 +12,7 @@ import kotlinx.serialization.modules.polymorphic import kotlinx.serialization.modules.subclass +@Suppress("UNUSED_PARAMETER") private fun jsonRootDeserializer( tSerializer: KSerializer, builder: (JsonElement) -> T, @@ -83,7 +84,7 @@ private object RootDecoder { return ref.getOrPutValue { // println("Decoding $it") - val actualTypeName = it.jsonObject["_typename"]?.jsonPrimitive?.content +// val actualTypeName = it.jsonObject["_typename"]?.jsonPrimitive?.content input.json.decodeFromJsonElement(tSerializer, it) } } 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 294af3ee..ba9cb333 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 @@ -34,6 +34,6 @@ class GDMLVisionTest { val child = cubes[Name.of("composite-000","segment-0")] assertNotNull(child) child.properties.setValue(SolidMaterial.MATERIAL_COLOR_KEY, "red".asValue()) - assertEquals("red", child.properties.getProperty(SolidMaterial.MATERIAL_COLOR_KEY).string) + assertEquals("red", child.properties.getMeta(SolidMaterial.MATERIAL_COLOR_KEY).string) } } \ No newline at end of file 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 f11c9e01..2cc8e9a5 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 @@ -69,7 +69,7 @@ class Model(val manager: VisionManager) { fun reset() { map.values.forEach { - it.properties.setProperty(SolidMaterial.MATERIAL_COLOR_KEY, null) + it.properties.setMeta(SolidMaterial.MATERIAL_COLOR_KEY, null) } tracks.children.clear() } diff --git a/demo/playground/src/jvmMain/kotlin/antenna.kt b/demo/playground/src/jvmMain/kotlin/antenna.kt index 5ec997f7..5080e939 100644 --- a/demo/playground/src/jvmMain/kotlin/antenna.kt +++ b/demo/playground/src/jvmMain/kotlin/antenna.kt @@ -75,7 +75,7 @@ fun main() = serve { val incRot = Quaternion.fromRotation(30.degrees, Euclidean3DSpace.zAxis) - val rotationJob = context.launch { + context.launch { var time: Long = 0L while (isActive) { with(QuaternionField) { diff --git a/demo/playground/src/jvmMain/kotlin/extruded.kt b/demo/playground/src/jvmMain/kotlin/extruded.kt index 8a25549f..c45b2564 100644 --- a/demo/playground/src/jvmMain/kotlin/extruded.kt +++ b/demo/playground/src/jvmMain/kotlin/extruded.kt @@ -12,9 +12,10 @@ fun main() = makeVisionFile { extruded("extruded") { shape{ polygon(8, 100) - layer(-30) - layer(30) } + layer(-30) + layer(0, x = 10, y = 10) + layer(30) } } } diff --git a/demo/playground/src/jvmMain/kotlin/surface.kt b/demo/playground/src/jvmMain/kotlin/surface.kt new file mode 100644 index 00000000..01fbfb50 --- /dev/null +++ b/demo/playground/src/jvmMain/kotlin/surface.kt @@ -0,0 +1,19 @@ +package space.kscience.visionforge.examples + +import space.kscience.visionforge.solid.ambientLight +import space.kscience.visionforge.solid.polygon +import space.kscience.visionforge.solid.solid +import space.kscience.visionforge.solid.surface + +fun main() = makeVisionFile { + vision("canvas") { + solid { + ambientLight() + surface("surface") { + layer(0, { polygon(8, 10) }, { polygon(8, 20) }) + layer(10, { polygon(8, 20) }, { polygon(8, 30) }) + layer(20, { polygon(8, 10) }, { polygon(8, 20) }) + } + } + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index e65394ef..dc7d1342 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ kotlin.code.style=official kotlin.mpp.stability.nowarn=true kotlin.js.compiler=ir -kotlin.incremental.js.ir=true +#kotlin.incremental.js.ir=true org.gradle.parallel=true org.gradle.jvmargs=-Xmx4G diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/AbstractVision.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/AbstractVision.kt index e7df2198..0cba6a37 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/AbstractVision.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/AbstractVision.kt @@ -3,7 +3,7 @@ package space.kscience.visionforge import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.Transient -import space.kscience.dataforge.meta.* +import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.meta.descriptors.MetaDescriptor 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 7320839d..00213644 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/StyleSheet.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/StyleSheet.kt @@ -13,7 +13,7 @@ import kotlin.jvm.JvmInline @JvmInline public value class StyleSheet(private val owner: Vision) { - private val styleNode: Meta get() = owner.properties.getProperty(STYLESHEET_KEY) + private val styleNode: Meta get() = owner.properties.getMeta(STYLESHEET_KEY) public val items: Map get() = styleNode.items @@ -23,7 +23,7 @@ public value class StyleSheet(private val owner: Vision) { * Define a style without notifying owner */ public fun define(key: String, style: Meta?) { - owner.properties.setProperty(STYLESHEET_KEY + key, style) + owner.properties.setMeta(STYLESHEET_KEY + key, style) } /** diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/Vision.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/Vision.kt index ce5f588f..31ff307e 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/Vision.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/Vision.kt @@ -37,6 +37,9 @@ public interface Vision : Described { * Update this vision using a dif represented by [VisionChange]. */ public fun update(change: VisionChange) { + if (change.children?.isNotEmpty() == true) { + error("Vision is not a group") + } change.properties?.let { updateProperties(it, Name.EMPTY) } @@ -67,7 +70,7 @@ public var Vision.visible: Boolean? */ public fun Vision.onPropertyChange( scope: CoroutineScope? = manager?.context, - callback: suspend (Name) -> Unit + callback: suspend (Name) -> Unit, ): Job = properties.changes.onEach { callback(it) }.launchIn(scope ?: error("Orphan Vision can't observe properties")) \ No newline at end of file diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionChange.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionChangeBuilder.kt similarity index 84% rename from visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionChange.kt rename to visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionChangeBuilder.kt index 847368f3..5b143023 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionChange.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionChangeBuilder.kt @@ -1,15 +1,15 @@ package space.kscience.visionforge -import kotlinx.coroutines.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock -import kotlinx.serialization.Serializable import space.kscience.dataforge.meta.* -import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.isEmpty import space.kscience.dataforge.names.plus @@ -27,22 +27,6 @@ private fun Vision.deepCopy(manager: VisionManager): Vision { return manager.decodeFromJson(json) } -/** - * A vision used only in change propagation and showing that the target should be removed - */ -@Serializable -public object NullVision : Vision { - override var parent: Vision? - get() = null - set(_) { - error("Can't set parent for null vision") - } - - override val properties: MutableVisionProperties get() = error("Can't get properties of `NullVision`") - - override val descriptor: MetaDescriptor? = null -} - /** * An update for a [Vision] @@ -111,18 +95,6 @@ public class VisionChangeBuilder : MutableVisionContainer { ) } -/** - * @param vision a new value for vision content. If the Vision is to be removed should be [NullVision] - * @param properties updated properties - * @param children a map of children changed in ths [VisionChange]. If a child to be removed, set [delete] flag to true. - */ -@Serializable -public data class VisionChange( - public val vision: Vision? = null, - public val properties: Meta? = null, - public val children: Map? = null, -) - public inline fun VisionManager.VisionChange(block: VisionChangeBuilder.() -> Unit): VisionChange = VisionChangeBuilder().apply(block).deepCopy(this) diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionEvent.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionEvent.kt new file mode 100644 index 00000000..3f86a2c0 --- /dev/null +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionEvent.kt @@ -0,0 +1,52 @@ +package space.kscience.visionforge + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import space.kscience.dataforge.meta.Meta +import space.kscience.dataforge.meta.descriptors.MetaDescriptor +import space.kscience.dataforge.names.Name + +/** + * An event propagated from client to a server + */ +@Serializable +public sealed interface VisionEvent + +/** + * An event that consists of custom meta + */ +@Serializable +@SerialName("meta") +public class VisionMetaEvent(public val targetName: Name, public val meta: Meta) : VisionEvent + + +/** + * A vision used only in change propagation and showing that the target should be removed + */ +@Serializable +@SerialName("null") +public object NullVision : Vision { + override var parent: Vision? + get() = null + set(_) { + error("Can't set parent for null vision") + } + + override val properties: MutableVisionProperties get() = error("Can't get properties of `NullVision`") + + override val descriptor: MetaDescriptor? = null +} + + +/** + * @param vision a new value for vision content. If the Vision is to be removed should be [NullVision] + * @param properties updated properties + * @param children a map of children changed in ths [VisionChange]. + */ +@Serializable +@SerialName("change") +public data class VisionChange( + public val vision: Vision? = null, + public val properties: Meta? = null, + public val children: Map? = null, +) : VisionEvent \ No newline at end of file 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 8a651ffc..fd8aaa16 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionGroup.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionGroup.kt @@ -10,11 +10,25 @@ import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.NameToken import space.kscience.dataforge.names.parseAsName import space.kscience.dataforge.names.plus +import space.kscience.visionforge.AbstractVisionGroup.Companion.updateProperties import space.kscience.visionforge.Vision.Companion.STYLE_KEY public interface VisionGroup : Vision { public val children: VisionChildren + + override fun update(change: VisionChange) { + change.children?.forEach { (name, change) -> + if (change.vision != null || change.vision == NullVision) { + error("VisionGroup is read-only") + } else { + children.getChild(name)?.update(change) + } + } + change.properties?.let { + updateProperties(it, Name.EMPTY) + } + } } public interface MutableVisionGroup : VisionGroup { @@ -22,15 +36,6 @@ public interface MutableVisionGroup : VisionGroup { override val children: MutableVisionChildren public fun createGroup(): MutableVisionGroup -} - -public val Vision.children: VisionChildren? get() = (this as? VisionGroup)?.children - -/** - * A full base implementation for a [Vision] - */ -@Serializable -public abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup { override fun update(change: VisionChange) { change.children?.forEach { (name, change) -> @@ -44,6 +49,15 @@ public abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup updateProperties(it, Name.EMPTY) } } +} + +public val Vision.children: VisionChildren? get() = (this as? VisionGroup)?.children + +/** + * A full base implementation for a [Vision] + */ +@Serializable +public abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup { @SerialName("children") protected var childrenInternal: MutableMap? = null diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionProperties.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionProperties.kt index 2fa88248..dfb06b50 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionProperties.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionProperties.kt @@ -12,7 +12,7 @@ import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.get import space.kscience.dataforge.names.* -public interface VisionProperties { +public interface VisionProperties : MetaProvider { /** * Raw Visions own properties without styles, defaults, etc. @@ -23,21 +23,26 @@ public interface VisionProperties { public fun getValue( name: Name, - inherit: Boolean? = null, + inherit: Boolean?, includeStyles: Boolean? = null, ): Value? + override fun getValue(name: Name): Value? = getValue(name, null, null) + /** * Get property with given layer flags. * @param inherit toggles parent node property lookup. Null means inference from descriptor. * @param includeStyles toggles inclusion of properties from styles. */ - public fun getProperty( + public fun getMeta( name: Name, - inherit: Boolean? = null, + inherit: Boolean?, includeStyles: Boolean? = null, ): Meta + override fun getMeta(name: Name): Meta? = getMeta(name, null, null) + + public val changes: Flow /** @@ -47,9 +52,9 @@ public interface VisionProperties { public fun invalidate(propertyName: Name) } -public interface MutableVisionProperties : VisionProperties { +public interface MutableVisionProperties : VisionProperties, MutableMetaProvider { - override fun getProperty( + override fun getMeta( name: Name, inherit: Boolean?, includeStyles: Boolean?, @@ -60,21 +65,31 @@ public interface MutableVisionProperties : VisionProperties { includeStyles, ) - public fun setProperty( + public fun setMeta( name: Name, node: Meta?, - notify: Boolean = true, + notify: Boolean, ) public fun setValue( name: Name, value: Value?, - notify: Boolean = true, + notify: Boolean, ) + + override fun getMeta(name: Name): MutableMeta = getMeta(name, null, null) + + override fun setMeta(name: Name, node: Meta?) { + setMeta(name, node, true) + } + + override fun setValue(name: Name, value: Value?) { + setValue(name, value, true) + } } public fun MutableVisionProperties.remove(name: Name) { - setProperty(name, null) + setMeta(name, null) } public fun MutableVisionProperties.remove(name: String) { @@ -134,7 +149,7 @@ private class VisionPropertiesItem( ) override fun setMeta(name: Name, node: Meta?) { - properties.setProperty(nodeName + name, node) + properties.setMeta(nodeName + name, node) } override fun toString(): String = Meta.toString(this) @@ -187,7 +202,7 @@ public abstract class AbstractVisionProperties( return descriptor?.defaultValue } - override fun setProperty(name: Name, node: Meta?, notify: Boolean) { + override fun setMeta(name: Name, node: Meta?, notify: Boolean) { //ignore if the value is the same as existing if (own?.getMeta(name) == node) return @@ -257,11 +272,11 @@ public fun VisionProperties.getValue( /** * Get [Vision] property using key as a String */ -public fun VisionProperties.getProperty( +public fun VisionProperties.getMeta( name: String, inherit: Boolean? = null, includeStyles: Boolean? = null, -): Meta = getProperty(name.parseAsName(), inherit, includeStyles) +): Meta = getMeta(name.parseAsName(), inherit, includeStyles) /** * The root property node with given inheritance and style flags @@ -271,33 +286,33 @@ public fun VisionProperties.getProperty( public fun MutableVisionProperties.root( inherit: Boolean? = null, includeStyles: Boolean? = null, -): MutableMeta = getProperty(Name.EMPTY, inherit, includeStyles) +): MutableMeta = getMeta(Name.EMPTY, inherit, includeStyles) /** * Get [Vision] property using key as a String */ -public fun MutableVisionProperties.getProperty( +public fun MutableVisionProperties.getMeta( name: String, inherit: Boolean? = null, includeStyles: Boolean? = null, -): MutableMeta = getProperty(name.parseAsName(), inherit, includeStyles) +): MutableMeta = getMeta(name.parseAsName(), inherit, includeStyles) - -public operator fun MutableVisionProperties.set(name: Name, value: Number): Unit = - setValue(name, value.asValue()) - -public operator fun MutableVisionProperties.set(name: String, value: Number): Unit = - set(name.parseAsName(), value) - -public operator fun MutableVisionProperties.set(name: Name, value: Boolean): Unit = - setValue(name, value.asValue()) - -public operator fun MutableVisionProperties.set(name: String, value: Boolean): Unit = - set(name.parseAsName(), value) - -public operator fun MutableVisionProperties.set(name: Name, value: String): Unit = - setValue(name, value.asValue()) - -public operator fun MutableVisionProperties.set(name: String, value: String): Unit = - set(name.parseAsName(), value) \ No newline at end of file +// +//public operator fun MutableVisionProperties.set(name: Name, value: Number): Unit = +// setValue(name, value.asValue()) +// +//public operator fun MutableVisionProperties.set(name: String, value: Number): Unit = +// set(name.parseAsName(), value) +// +//public operator fun MutableVisionProperties.set(name: Name, value: Boolean): Unit = +// setValue(name, value.asValue()) +// +//public operator fun MutableVisionProperties.set(name: String, value: Boolean): Unit = +// set(name.parseAsName(), value) +// +//public operator fun MutableVisionProperties.set(name: Name, value: String): Unit = +// setValue(name, value.asValue()) +// +//public operator fun MutableVisionProperties.set(name: String, value: String): Unit = +// set(name.parseAsName(), value) \ No newline at end of file diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/flowProperty.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/flowProperty.kt index c8f14ae3..f8d128e1 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/flowProperty.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/flowProperty.kt @@ -17,10 +17,10 @@ public fun Vision.flowProperty( includeStyles: Boolean? = null, ): Flow = flow { //Pass initial value. - emit(properties.getProperty(propertyName, inherit, includeStyles)) + emit(properties.getMeta(propertyName, inherit, includeStyles)) properties.changes.collect { name -> if (name.startsWith(propertyName)) { - emit(properties.getProperty(propertyName, inherit, includeStyles)) + emit(properties.getMeta(propertyName, inherit, includeStyles)) } } } diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/HtmlVisionRenderer.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/HtmlVisionRenderer.kt index c02b6e64..d71e848a 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/HtmlVisionRenderer.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/HtmlVisionRenderer.kt @@ -93,7 +93,6 @@ public fun FlowContent.visionFragment( updatesUrl: String? = null, onVisionRendered: (Name, Vision) -> Unit = { _, _ -> }, idPrefix: String? = null, - fragment: HtmlVisionFragment, ): Unit = consumer.visionFragment( visionManager = visionManager, diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionOfHtmlInput.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionOfHtmlInput.kt index 3a818b08..d2bb2c52 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionOfHtmlInput.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionOfHtmlInput.kt @@ -6,10 +6,11 @@ import space.kscience.dataforge.meta.boolean import space.kscience.dataforge.meta.number import space.kscience.dataforge.meta.string import space.kscience.dataforge.names.Name -import space.kscience.visionforge.* +import space.kscience.visionforge.AbstractVision +import space.kscience.visionforge.Vision //TODO replace by something -internal val Vision.mutableProperties get() = properties.getProperty(Name.EMPTY, false, false) +internal val Vision.mutableProperties get() = properties.getMeta(Name.EMPTY, false, false) @Serializable public abstract class VisionOfHtmlInput : AbstractVision() { diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/useProperty.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/useProperty.kt index 87312f6f..f6f95a6f 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/useProperty.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/useProperty.kt @@ -23,10 +23,10 @@ public fun Vision.useProperty( callback: (Meta) -> Unit, ): Job { //Pass initial value. - callback(properties.getProperty(propertyName, inherit, includeStyles)) + callback(properties.getMeta(propertyName, inherit, includeStyles)) return properties.changes.onEach { name -> if (name.startsWith(propertyName)) { - callback(properties.getProperty(propertyName, inherit, includeStyles)) + callback(properties.getMeta(propertyName, inherit, includeStyles)) } }.launchIn(scope ?: error("Orphan Vision can't observe properties")) } 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 eaea0a4e..20868b96 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 @@ -4,6 +4,7 @@ import kotlinx.html.* import kotlinx.html.stream.createHTML import space.kscience.dataforge.context.Global import space.kscience.dataforge.meta.Meta +import space.kscience.dataforge.meta.set import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.names.Name import space.kscience.visionforge.* diff --git a/visionforge-core/src/commonTest/kotlin/space/kscience/visionforge/meta/VisionPropertyTest.kt b/visionforge-core/src/commonTest/kotlin/space/kscience/visionforge/meta/VisionPropertyTest.kt index e9a0685e..a6ea86a2 100644 --- a/visionforge-core/src/commonTest/kotlin/space/kscience/visionforge/meta/VisionPropertyTest.kt +++ b/visionforge-core/src/commonTest/kotlin/space/kscience/visionforge/meta/VisionPropertyTest.kt @@ -42,7 +42,7 @@ internal class VisionPropertyTest { @Test fun testPropertyEdit() { val vision = manager.group() - vision.properties.getProperty("fff.ddd").apply { + vision.properties.getMeta("fff.ddd").apply { value = 2.asValue() } assertEquals(2, vision.properties.getValue("fff.ddd")?.int) @@ -52,7 +52,7 @@ internal class VisionPropertyTest { @Test fun testPropertyUpdate() { val vision = manager.group() - vision.properties.getProperty("fff").updateWith(TestScheme) { + vision.properties.getMeta("fff").updateWith(TestScheme) { ddd = 2 } assertEquals(2, vision.properties.getValue("fff.ddd")?.int) @@ -87,7 +87,7 @@ internal class VisionPropertyTest { child.properties.remove("test") - assertEquals(11, child.properties.getProperty("test", inherit = true).int) + assertEquals(11, child.properties.getMeta("test", inherit = true).int) // assertEquals(11, deferred.await()?.int) // assertEquals(2, callCounter) subscription.cancel() diff --git a/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/VisionClient.kt b/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/VisionClient.kt index c9146efd..91e4f1bc 100644 --- a/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/VisionClient.kt +++ b/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/VisionClient.kt @@ -4,6 +4,7 @@ import kotlinx.browser.document import kotlinx.browser.window import kotlinx.coroutines.Job import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex @@ -11,10 +12,7 @@ import kotlinx.coroutines.sync.withLock import org.w3c.dom.* import org.w3c.dom.url.URL import space.kscience.dataforge.context.* -import space.kscience.dataforge.meta.Meta -import space.kscience.dataforge.meta.MetaSerializer -import space.kscience.dataforge.meta.get -import space.kscience.dataforge.meta.int +import space.kscience.dataforge.meta.* import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.parseAsName import space.kscience.visionforge.html.VisionTagConsumer @@ -68,7 +66,7 @@ public class VisionClient : AbstractPlugin() { /** * Communicate vision property changed from rendering engine to model */ - public fun visionPropertyChanged(visionName: Name, propertyName: Name, item: Meta?) { + public fun notifyPropertyChanged(visionName: Name, propertyName: Name, item: Meta?) { context.launch { mutex.withLock { changeCollector.propertyChanged(visionName, propertyName, item) @@ -76,9 +74,17 @@ public class VisionClient : AbstractPlugin() { } } -// public fun visionChanged(name: Name?, child: Vision?) { -// changeCollector.setChild(name, child) -// } + private val eventCollector by lazy { + MutableSharedFlow(meta["feedback.eventCache"].int ?: 100) + } + + + /** + * Send a custom feedback event + */ + public suspend fun sendEvent(event: VisionEvent) { + eventCollector.emit(event) + } private fun renderVision(element: Element, name: Name, vision: Vision, outputMeta: Meta) { vision.setAsRoot(visionManager) @@ -103,7 +109,7 @@ public class VisionClient : AbstractPlugin() { logger.info { "Updating vision data from $wsUrl" } - //Individual websocket for this element + //Individual websocket for this vision WebSocket(wsUrl.toString()).apply { onmessage = { messageEvent -> val stringData: String? = messageEvent.data as? String @@ -131,7 +137,7 @@ public class VisionClient : AbstractPlugin() { var feedbackJob: Job? = null //Feedback changes aggregation time in milliseconds - val feedbackAggregationTime = meta["aggregationTime"]?.int ?: 300 + val feedbackAggregationTime = meta["feedback.aggregationTime"]?.int ?: 300 onopen = { feedbackJob = visionManager.context.launch { @@ -144,18 +150,24 @@ public class VisionClient : AbstractPlugin() { change.reset() } } +// // take channel for given vision name +// eventCollector[name]?.let { channel -> +// for (e in channel) { +// send(visionManager.jsonFormat.encodeToString(VisionEvent.serializer(), e)) +// } +// } } } - logger.info { "WebSocket update channel established for output '$name'" } + logger.info { "WebSocket feedback channel established for output '$name'" } } onclose = { feedbackJob?.cancel() - logger.info { "WebSocket update channel closed for output '$name'" } + logger.info { "WebSocket feedback channel closed for output '$name'" } } onerror = { feedbackJob?.cancel() - logger.error { "WebSocket update channel error for output '$name'" } + logger.error { "WebSocket feedback channel error for output '$name'" } } } } @@ -248,20 +260,26 @@ public class VisionClient : AbstractPlugin() { } } -public fun VisionClient.visionPropertyChanged(visionName: Name, propertyName: String, item: Meta?) { - visionPropertyChanged(visionName, propertyName.parseAsName(true), item) +public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: Meta?) { + notifyPropertyChanged(visionName, propertyName.parseAsName(true), item) } -public fun VisionClient.visionPropertyChanged(visionName: Name, propertyName: String, item: Number) { - visionPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item)) +public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: Number) { + notifyPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item)) } -public fun VisionClient.visionPropertyChanged(visionName: Name, propertyName: String, item: String) { - visionPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item)) +public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: String) { + notifyPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item)) } -public fun VisionClient.visionPropertyChanged(visionName: Name, propertyName: String, item: Boolean) { - visionPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item)) +public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: Boolean) { + notifyPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item)) +} + +public fun VisionClient.sendEvent(visionName: Name, event: MetaRepr): Unit { + context.launch { + sendEvent(VisionMetaEvent(visionName, event.toMeta())) + } } private fun whenDocumentLoaded(block: Document.() -> Unit): Unit { diff --git a/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/inputRenderers.kt b/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/inputRenderers.kt index 390058ea..faf82d13 100644 --- a/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/inputRenderers.kt +++ b/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/inputRenderers.kt @@ -36,7 +36,7 @@ internal fun textVisionRenderer( value = it ?: "" } onChangeFunction = { - client.visionPropertyChanged(name, VisionOfTextField::text.name, value) + client.notifyPropertyChanged(name, VisionOfTextField::text.name, value) } } } @@ -58,7 +58,7 @@ internal fun numberVisionRenderer( value = it?.toDouble() ?: 0.0 } onChangeFunction = { - client.visionPropertyChanged(name, VisionOfNumberField::value.name, value) + client.notifyPropertyChanged(name, VisionOfNumberField::value.name, value) } } } @@ -106,7 +106,7 @@ internal fun formVisionRenderer( form.onsubmit = { event -> event.preventDefault() val formData = FormData(form).toMeta() - client.visionPropertyChanged(name, VisionOfHtmlForm::values.name, formData) + client.notifyPropertyChanged(name, VisionOfHtmlForm::values.name, formData) console.info("Sent: ${formData.toMap()}") false } 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 f92e7d4d..d5333dda 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 @@ -10,7 +10,6 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.Transient import space.kscience.dataforge.meta.* import space.kscience.dataforge.meta.descriptors.MetaDescriptor -import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.names.Name import space.kscience.plotly.Plot import space.kscience.plotly.Plotly @@ -34,7 +33,7 @@ public class VisionOfPlotly private constructor( @Transient override val properties: MutableVisionProperties = object : MutableVisionProperties { - override fun setProperty(name: Name, node: Meta?, notify: Boolean) { + override fun setMeta(name: Name, node: Meta?, notify: Boolean) { meta.setMeta(name, node) } @@ -46,7 +45,7 @@ public class VisionOfPlotly private constructor( override val descriptor: MetaDescriptor? get() = this@VisionOfPlotly.descriptor - override fun getProperty( + override fun getMeta( name: Name, inherit: Boolean?, includeStyles: Boolean?, diff --git a/visionforge-server/src/main/kotlin/space/kscience/visionforge/server/VisionServer.kt b/visionforge-server/src/main/kotlin/space/kscience/visionforge/server/VisionServer.kt index 61952497..873a52c9 100644 --- a/visionforge-server/src/main/kotlin/space/kscience/visionforge/server/VisionServer.kt +++ b/visionforge-server/src/main/kotlin/space/kscience/visionforge/server/VisionServer.kt @@ -23,10 +23,7 @@ import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.ContextAware import space.kscience.dataforge.meta.* import space.kscience.dataforge.names.Name -import space.kscience.visionforge.Vision -import space.kscience.visionforge.VisionChange -import space.kscience.visionforge.VisionManager -import space.kscience.visionforge.flowChanges +import space.kscience.visionforge.* import space.kscience.visionforge.html.* import kotlin.time.Duration.Companion.milliseconds @@ -77,6 +74,11 @@ public class VisionRoute( */ public fun Application.serveVisionData( configuration: VisionRoute, + onEvent: suspend Vision.(VisionEvent) -> Unit = { event -> + if (event is VisionChange) { + update(event) + } + }, resolveVision: (Name) -> Vision?, ) { require(WebSockets) @@ -96,11 +98,11 @@ public fun Application.serveVisionData( launch { for (frame in incoming) { val data = frame.data.decodeToString() - application.log.debug("Received update for $name: \n$data") - val change = configuration.visionManager.jsonFormat.decodeFromString( - VisionChange.serializer(), data + application.log.debug("Received event for $name: \n$data") + val event = configuration.visionManager.jsonFormat.decodeFromString( + VisionEvent.serializer(), data ) - vision.update(change) + vision.onEvent(event) } } 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 7c6ab3ec..65a1bcd5 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 @@ -3,7 +3,10 @@ package space.kscience.visionforge.solid import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import space.kscience.dataforge.names.Name -import space.kscience.visionforge.* +import space.kscience.visionforge.MutableVisionContainer +import space.kscience.visionforge.VisionBuilder +import space.kscience.visionforge.setChild +import space.kscience.visionforge.static public enum class CompositeType { GROUP, // Dumb sum of meshes @@ -33,7 +36,7 @@ public inline fun MutableVisionContainer.composite( } val res = Composite(type, children[0], children[1]) - res.properties.setProperty(Name.EMPTY, group.properties.own) + res.properties.setMeta(Name.EMPTY, group.properties.own) setChild(name, res) return res diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Extruded.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Extruded.kt index 46430b30..8276722e 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Extruded.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Extruded.kt @@ -9,37 +9,8 @@ import space.kscience.kmath.geometry.component2 import space.kscience.visionforge.MutableVisionContainer import space.kscience.visionforge.VisionBuilder import space.kscience.visionforge.setChild -import kotlin.math.PI -import kotlin.math.cos -import kotlin.math.sin -public typealias Shape2D = List - -@Serializable -public class Shape2DBuilder(private val points: ArrayList = ArrayList()) { - - public fun point(x: Number, y: Number) { - points.add(Float32Vector2D(x, y)) - } - - public fun build(): Shape2D = points -} - -public fun Shape2DBuilder.polygon(vertices: Int, radius: Number) { - require(vertices > 2) { "Polygon must have more than 2 vertices" } - val angle = 2 * PI / vertices - for (i in 0 until vertices) { - point(radius.toDouble() * cos(angle * i), radius.toDouble() * sin(angle * i)) - } -} - -/** - * A layer for extruded shape - */ -@Serializable -public data class Layer(var x: Float, var y: Float, var z: Float, var scale: Float) - /** * An extruded shape with the same number of points on each layer. */ @@ -50,6 +21,12 @@ public class Extruded( public val layers: List, ) : SolidBase(), GeometrySolid { + /** + * A layer for extruded shape + */ + @Serializable + public data class Layer(var x: Float, var y: Float, var z: Float, var scale: Float) + init { require(shape.size > 2) { "Extruded shape requires more than 2 points per layer" } } @@ -72,6 +49,8 @@ public class Extruded( var lowerLayer = layers.first() var upperLayer: List + geometryBuilder.cap(layers.first().reversed()) + for (i in (1 until layers.size)) { upperLayer = layers[i] for (j in (0 until shape.size - 1)) { @@ -93,7 +72,7 @@ public class Extruded( ) lowerLayer = upperLayer } - geometryBuilder.cap(layers.first().reversed()) + geometryBuilder.cap(layers.last()) } @@ -102,16 +81,18 @@ public class Extruded( public var layers: MutableList = ArrayList(), public val properties: MutableMeta = MutableMeta(), ) { + @VisionBuilder public fun shape(block: Shape2DBuilder.() -> Unit) { this.shape = Shape2DBuilder().apply(block).build() } + @VisionBuilder public fun layer(z: Number, x: Number = 0.0, y: Number = 0.0, scale: Number = 1.0) { layers.add(Layer(x.toFloat(), y.toFloat(), z.toFloat(), scale.toFloat())) } internal fun build(): Extruded = Extruded(shape, layers).apply { - this.properties.setProperty(Name.EMPTY, this@Builder.properties) + this.properties.setMeta(Name.EMPTY, this@Builder.properties) } } diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/PolyLine.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/PolyLine.kt index 1681f44a..0ead1642 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/PolyLine.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/PolyLine.kt @@ -13,7 +13,10 @@ import space.kscience.visionforge.setChild public class PolyLine(public val points: List) : SolidBase() { //var lineType by string() - public var thickness: Number by properties.root(inherit = false, includeStyles = true).number { DEFAULT_THICKNESS } + public var thickness: Number by properties.root( + inherit = false, + includeStyles = true + ).number { DEFAULT_THICKNESS } public companion object { public const val DEFAULT_THICKNESS: Double = 1.0 diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Shape2D.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Shape2D.kt new file mode 100644 index 00000000..4f5d48a4 --- /dev/null +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Shape2D.kt @@ -0,0 +1,26 @@ +package space.kscience.visionforge.solid + +import kotlinx.serialization.Serializable +import kotlin.math.PI +import kotlin.math.cos +import kotlin.math.sin + +public typealias Shape2D = List + +@Serializable +public class Shape2DBuilder(private val points: ArrayList = ArrayList()) { + + public fun point(x: Number, y: Number) { + points.add(Float32Vector2D(x, y)) + } + + public fun build(): Shape2D = points +} + +public fun Shape2DBuilder.polygon(vertices: Int, radius: Number) { + require(vertices > 2) { "Polygon must have more than 2 vertices" } + val angle = 2 * PI / vertices + for (i in 0 until vertices) { + point(radius.toDouble() * cos(angle * i), radius.toDouble() * sin(angle * i)) + } +} \ No newline at end of file diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt index f33573d7..3972de83 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt @@ -11,8 +11,10 @@ import space.kscience.dataforge.names.plus import space.kscience.kmath.complex.Quaternion import space.kscience.kmath.complex.QuaternionField import space.kscience.kmath.geometry.* -import space.kscience.visionforge.* +import space.kscience.visionforge.Vision import space.kscience.visionforge.Vision.Companion.VISIBLE_KEY +import space.kscience.visionforge.hide +import space.kscience.visionforge.inherited import space.kscience.visionforge.solid.Solid.Companion.DETAIL_KEY import space.kscience.visionforge.solid.Solid.Companion.IGNORE_KEY import space.kscience.visionforge.solid.Solid.Companion.LAYER_KEY @@ -182,7 +184,7 @@ internal fun point( override fun setValue(thisRef: Solid, property: KProperty<*>, value: Float32Vector3D?) { if (value == null) { - thisRef.properties.setProperty(name, null) + thisRef.properties.setMeta(name, null) } else { thisRef.properties[name + X_KEY] = value.x thisRef.properties[name + Y_KEY] = value.y 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 df720e6c..14784065 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 @@ -107,12 +107,12 @@ public val Solid.color: ColorAccessor get() = ColorAccessor(properties.root(true), MATERIAL_COLOR_KEY) public var Solid.material: SolidMaterial? - get() = SolidMaterial.read(properties.getProperty(MATERIAL_KEY)) - set(value) = properties.setProperty(MATERIAL_KEY, value?.meta) + get() = SolidMaterial.read(properties.getMeta(MATERIAL_KEY)) + set(value) = properties.setMeta(MATERIAL_KEY, value?.meta) @VisionBuilder public fun Solid.material(builder: SolidMaterial.() -> Unit) { - properties.getProperty(MATERIAL_KEY).updateWith(SolidMaterial, builder) + properties.getMeta(MATERIAL_KEY).updateWith(SolidMaterial, builder) } public var Solid.opacity: Number? @@ -125,5 +125,5 @@ public var Solid.opacity: Number? @VisionBuilder public fun Solid.edges(enabled: Boolean = true, block: SolidMaterial.() -> Unit = {}) { properties[SolidMaterial.EDGES_ENABLED_KEY] = enabled - SolidMaterial.write(properties.getProperty(SolidMaterial.EDGES_MATERIAL_KEY)).apply(block) + SolidMaterial.write(properties.getMeta(SolidMaterial.EDGES_MATERIAL_KEY)).apply(block) } \ 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 2770a7aa..a6aabe67 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 @@ -14,7 +14,6 @@ import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.get import space.kscience.dataforge.names.* import space.kscience.visionforge.* -import space.kscience.visionforge.AbstractVisionGroup.Companion.updateProperties import space.kscience.visionforge.solid.SolidReference.Companion.REFERENCE_CHILD_PROPERTY_PREFIX @@ -162,7 +161,7 @@ internal class SolidReferenceChild( override val properties: MutableVisionProperties = object : MutableVisionProperties { override val descriptor: MetaDescriptor get() = this@SolidReferenceChild.descriptor - override val own: MutableMeta by lazy { owner.properties.getProperty(childToken(childName).asName()) } + override val own: MutableMeta by lazy { owner.properties.getMeta(childToken(childName).asName()) } override fun getValue( name: Name, @@ -170,7 +169,7 @@ internal class SolidReferenceChild( includeStyles: Boolean?, ): Value? = own.getValue(name) ?: prototype.properties.getValue(name, inherit, includeStyles) - override fun setProperty(name: Name, node: Meta?, notify: Boolean) { + override fun setMeta(name: Name, node: Meta?, notify: Boolean) { own.setMeta(name, node) } @@ -185,20 +184,6 @@ internal class SolidReferenceChild( } } - override fun update(change: VisionChange) { - change.children?.forEach { (name, change) -> - when { - change.vision == NullVision -> error("Deleting children inside ref is not allowed.") - change.vision != null -> error("Updating content of the ref is not allowed") - else -> children.getChild(name)?.update(change) - } - } - change.properties?.let { - updateProperties(it, Name.EMPTY) - } - } - - override val children: VisionChildren = object : VisionChildren { override val parent: Vision get() = this@SolidReferenceChild diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solids.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solids.kt index 1477c2a0..2a2e86fc 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solids.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solids.kt @@ -41,6 +41,7 @@ public class Solids(meta: Meta) : VisionPlugin(meta), MutableVisionContainer Iterable.sumOf(selector: (T) -> Float32): Float32 { @@ -20,9 +25,9 @@ private inline fun Iterable.sumOf(selector: (T) -> Float32): Float32 { */ @Serializable @SerialName("solid.surface") -public class LayersSurface( +public class Surface( public val layers: List, -) : SolidBase(), GeometrySolid { +) : SolidBase(), GeometrySolid { @Serializable public data class Layer(val z: Float32, val outer: Shape2D, val inner: Shape2D?) { @@ -58,7 +63,7 @@ public class LayersSurface( //outer and inner for (i in 0 until layers.size - 1) { val bottom = layers[i] - val top = layers[i+1] + val top = layers[i + 1] //creating shape in x-y plane with z = 0 val bottomOuterPoints = bottom.outerPoints() @@ -130,7 +135,39 @@ public class LayersSurface( } } + public class Builder( + public var layers: MutableList = ArrayList(), + public val properties: MutableMeta = MutableMeta(), + ) { + + public fun layer( + z: Number, + innerBuilder: (Shape2DBuilder.() -> Unit)? = null, + outerBuilder: Shape2DBuilder.() -> Unit, + ) { + layers.add( + Layer( + z.toFloat(), + outer = Shape2DBuilder().apply(outerBuilder).build(), + inner = innerBuilder?.let { Shape2DBuilder().apply(innerBuilder).build() } + ) + ) + } + + internal fun build(): Surface = Surface(layers).apply { + properties.setMeta(Name.EMPTY, this@Builder.properties) + } + } + + public companion object { public const val TYPE: String = "solid.surface" } } + + +@VisionBuilder +public fun MutableVisionContainer.surface( + name: String? = null, + action: Surface.Builder.() -> Unit = {}, +): Surface = Surface.Builder().apply(action).build().also { setChild(name, it) } diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/transform/RemoveSingleChild.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/transform/RemoveSingleChild.kt index d2667e76..cdc9caaf 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/transform/RemoveSingleChild.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/transform/RemoveSingleChild.kt @@ -19,7 +19,7 @@ internal fun Solid.updateFrom(other: Solid): Solid { scaleX *= other.scaleX scaleY *= other.scaleY scaleZ *= other.scaleZ - properties.setProperty(Name.EMPTY, other.properties.root()) + properties.setMeta(Name.EMPTY, other.properties.root()) return this } diff --git a/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/SolidPropertyTest.kt b/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/SolidPropertyTest.kt index 87ba368c..e4b0619d 100644 --- a/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/SolidPropertyTest.kt +++ b/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/SolidPropertyTest.kt @@ -5,6 +5,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.delay import kotlinx.coroutines.test.runTest import space.kscience.dataforge.meta.int +import space.kscience.dataforge.meta.set import space.kscience.dataforge.meta.string import space.kscience.dataforge.names.asName import space.kscience.visionforge.* diff --git a/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreeLineFactory.kt b/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreeLineFactory.kt index 45325430..42722254 100644 --- a/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreeLineFactory.kt +++ b/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreeLineFactory.kt @@ -24,7 +24,7 @@ public object ThreeLineFactory : ThreeFactory { } val material = ThreeMaterials.getLineMaterial( - vision.properties.getProperty(SolidMaterial.MATERIAL_KEY), + vision.properties.getMeta(SolidMaterial.MATERIAL_KEY), false ) diff --git a/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreeMaterials.kt b/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreeMaterials.kt index f5ac5c2b..49667c8e 100644 --- a/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreeMaterials.kt +++ b/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreeMaterials.kt @@ -83,7 +83,7 @@ public object ThreeMaterials { private val visionMaterialCache = HashMap() internal fun cacheMaterial(vision: Vision): Material = visionMaterialCache.getOrPut(vision) { - buildMaterial(vision.properties.getProperty(SolidMaterial.MATERIAL_KEY)).apply { + buildMaterial(vision.properties.getMeta(SolidMaterial.MATERIAL_KEY)).apply { cached = true } } @@ -133,11 +133,11 @@ public fun Mesh.setMaterial(vision: Vision) { } else { material = vision.parent?.let { parent -> //TODO cache parent material - ThreeMaterials.buildMaterial(parent.properties.getProperty(SolidMaterial.MATERIAL_KEY)) + ThreeMaterials.buildMaterial(parent.properties.getMeta(SolidMaterial.MATERIAL_KEY)) } ?: ThreeMaterials.cacheMaterial(vision) } } else { - material = ThreeMaterials.buildMaterial(vision.properties.getProperty(SolidMaterial.MATERIAL_KEY)) + material = ThreeMaterials.buildMaterial(vision.properties.getMeta(SolidMaterial.MATERIAL_KEY)) } } @@ -153,18 +153,18 @@ public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) { when (propertyName) { SolidMaterial.MATERIAL_COLOR_KEY -> { material.asDynamic().color = - vision.properties.getProperty(SolidMaterial.MATERIAL_COLOR_KEY).threeColor() + vision.properties.getMeta(SolidMaterial.MATERIAL_COLOR_KEY).threeColor() ?: ThreeMaterials.DEFAULT_COLOR } SolidMaterial.SPECULAR_COLOR_KEY -> { material.asDynamic().specular = - vision.properties.getProperty(SolidMaterial.SPECULAR_COLOR_KEY).threeColor() + vision.properties.getMeta(SolidMaterial.SPECULAR_COLOR_KEY).threeColor() ?: ThreeMaterials.DEFAULT_COLOR } SolidMaterial.MATERIAL_EMISSIVE_COLOR_KEY -> { - material.asDynamic().emissive = vision.properties.getProperty(SolidMaterial.MATERIAL_EMISSIVE_COLOR_KEY) + material.asDynamic().emissive = vision.properties.getMeta(SolidMaterial.MATERIAL_EMISSIVE_COLOR_KEY) .threeColor() ?: ThreeMaterials.BLACK_COLOR } diff --git a/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreeMeshFactory.kt b/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreeMeshFactory.kt index 06224bbb..4ba19998 100644 --- a/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreeMeshFactory.kt +++ b/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreeMeshFactory.kt @@ -76,7 +76,7 @@ public fun Mesh.applyEdges(vision: Solid) { val edges = children.find { it.name == EDGES_OBJECT_NAME } as? LineSegments //inherited edges definition, enabled by default if (vision.properties.getValue(EDGES_ENABLED_KEY, inherit = false)?.boolean != false) { - val material = ThreeMaterials.getLineMaterial(vision.properties.getProperty(EDGES_MATERIAL_KEY), true) + val material = ThreeMaterials.getLineMaterial(vision.properties.getMeta(EDGES_MATERIAL_KEY), true) if (edges == null) { add( LineSegments(