v0.2.0-dev-22 #47

Merged
altavir merged 158 commits from dev into master 2021-07-17 11:04:22 +03:00
32 changed files with 135 additions and 144 deletions
Showing only changes of commit 2b7971eeea - Show all commits

View File

@ -73,7 +73,7 @@ The `visionforge-core` module also includes configuration editors for JS (in `js
**Class diagram:** **Class diagram:**
![](docs/resources/class-diag-core.png) ![](docs/images/class-diag-core.png)
### visionforge-solid ### visionforge-solid
@ -82,7 +82,7 @@ Includes common classes and serializers for 3D visualization, as well as Three.j
**Class diagram:** **Class diagram:**
![](docs/resources/class-diag-solid.png) ![](docs/images/class-diag-solid.png)
##### Prototypes ##### Prototypes
@ -127,7 +127,7 @@ Some shapes will also periodically change their color and visibility.
**Example view:** **Example view:**
![](docs/resources/spatial-showcase.png) ![](docs/images/spatial-showcase.png)
### Full-Stack Application Example - Muon Monitor Visualization ### Full-Stack Application Example - Muon Monitor Visualization
@ -139,7 +139,7 @@ A full-stack application example, showing the
**Example view:** **Example view:**
![](docs/resources/muon-monitor.png) ![](docs/images/muon-monitor.png)
### GDML Example ### GDML Example
@ -150,7 +150,7 @@ Visualization example for geometry defined as GDML file.
##### Example view: ##### Example view:
![](docs/resources/gdml-demo.png) ![](docs/images/gdml-demo.png)
## Thanks and references ## Thanks and references

View File

@ -12,4 +12,4 @@ drag-and-drop GDML file to the window to see visualization. For an example file,
##### Example view: ##### Example view:
![](../../docs/resources/gdml-demo.png) ![](../../docs/images/gdml-demo.png)

View File

@ -30,5 +30,5 @@ run `demo/muon-monitor/application/run` task.
##### Example view: ##### Example view:
![](../../docs/resources/muon-monitor.png) ![](../../docs/images/muon-monitor.png)

View File

@ -12,8 +12,8 @@ To see Java FX demo, run `demo/spatial-showcase/Tasks/application/run` Gradle ta
##### Example view for JS: ##### Example view for JS:
![](../../docs/resources/spatial-showcase.png) ![](../../docs/images/spatial-showcase.png)
##### Example view for Java FX: ##### Example view for Java FX:
![](../../docs/resources/spatial-showcase-FX.png) ![](../../docs/images/spatial-showcase-FX.png)

View File

@ -5,6 +5,7 @@ import hep.dataforge.names.plus
import hep.dataforge.names.startsWith import hep.dataforge.names.startsWith
import hep.dataforge.values.asValue import hep.dataforge.values.asValue
import hep.dataforge.vision.getProperty import hep.dataforge.vision.getProperty
import hep.dataforge.vision.onPropertyChange
import hep.dataforge.vision.set import hep.dataforge.vision.set
import hep.dataforge.vision.setProperty import hep.dataforge.vision.setProperty
import hep.dataforge.vision.solid.* import hep.dataforge.vision.solid.*

View File

After

Width:  |  Height:  |  Size: 16 KiB

View File

After

Width:  |  Height:  |  Size: 20 KiB

View File

After

Width:  |  Height:  |  Size: 97 KiB

View File

After

Width:  |  Height:  |  Size: 87 KiB

View File

After

Width:  |  Height:  |  Size: 28 KiB

View File

After

Width:  |  Height:  |  Size: 47 KiB

View File

@ -5,14 +5,13 @@ import hep.dataforge.names.Name
import hep.dataforge.names.NameToken import hep.dataforge.names.NameToken
import hep.dataforge.names.asName import hep.dataforge.names.asName
import hep.dataforge.names.plus import hep.dataforge.names.plus
import kotlinx.coroutines.launch
/** /**
* A container for styles * A container for styles
*/ */
public inline class StyleSheet(private val owner: VisionGroup) { public inline class StyleSheet(private val owner: VisionGroup) {
private val styleNode get() = owner.getOwnProperty(STYLESHEET_KEY).node private val styleNode get() = owner.ownProperties[STYLESHEET_KEY].node
public val items: Map<NameToken, Meta>? get() = styleNode?.items?.mapValues { it.value.node ?: Meta.EMPTY } public val items: Map<NameToken, Meta>? get() = styleNode?.items?.mapValues { it.value.node ?: Meta.EMPTY }
@ -55,9 +54,7 @@ internal fun Vision.styleChanged(key: String, oldStyle: Meta?, newStyle: Meta?)
val tokens: Collection<Name> = val tokens: Collection<Name> =
((oldStyle?.items?.keys ?: emptySet()) + (newStyle?.items?.keys ?: emptySet())) ((oldStyle?.items?.keys ?: emptySet()) + (newStyle?.items?.keys ?: emptySet()))
.map { it.asName() } .map { it.asName() }
parent?.scope?.launch { tokens.forEach { parent?.invalidateProperty(it) }
tokens.forEach { parent?.notifyPropertyChanged(it) }
}
} }
if (this is VisionGroup) { if (this is VisionGroup) {
for (obj in this) { for (obj in this) {
@ -71,7 +68,7 @@ internal fun Vision.styleChanged(key: String, oldStyle: Meta?, newStyle: Meta?)
* List of names of styles applied to this object. Order matters. Not inherited. * List of names of styles applied to this object. Order matters. Not inherited.
*/ */
public var Vision.styles: List<String> public var Vision.styles: List<String>
get() = getOwnProperty(Vision.STYLE_KEY)?.stringList ?: emptyList() get() = ownProperties[Vision.STYLE_KEY]?.stringList ?: emptyList()
set(value) { set(value) {
setProperty(Vision.STYLE_KEY, value) setProperty(Vision.STYLE_KEY, value)
} }
@ -86,7 +83,7 @@ public val VisionGroup.styleSheet: StyleSheet get() = StyleSheet(this)
* Add style name to the list of styles to be resolved later. The style with given name does not necessary exist at the moment. * Add style name to the list of styles to be resolved later. The style with given name does not necessary exist at the moment.
*/ */
public fun Vision.useStyle(name: String) { public fun Vision.useStyle(name: String) {
styles = (getOwnProperty(Vision.STYLE_KEY)?.stringList ?: emptyList()) + name styles = (ownProperties[Vision.STYLE_KEY]?.stringList ?: emptyList()) + name
} }
@ -94,7 +91,7 @@ public fun Vision.useStyle(name: String) {
* Find a style with given name for given [Vision]. The style is not necessary applied to this [Vision]. * Find a style with given name for given [Vision]. The style is not necessary applied to this [Vision].
*/ */
public tailrec fun Vision.getStyle(name: String): Meta? = public tailrec fun Vision.getStyle(name: String): Meta? =
getOwnProperty(StyleSheet.STYLESHEET_KEY + name).node ?: parent?.getStyle(name) ownProperties[StyleSheet.STYLESHEET_KEY + name].node ?: parent?.getStyle(name)
/** /**
* Resolve an item in all style layers * Resolve an item in all style layers

View File

@ -1,9 +1,6 @@
package hep.dataforge.vision package hep.dataforge.vision
import hep.dataforge.meta.DFExperimental import hep.dataforge.meta.*
import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaItem
import hep.dataforge.meta.MutableItemProvider
import hep.dataforge.meta.descriptors.Described import hep.dataforge.meta.descriptors.Described
import hep.dataforge.meta.descriptors.NodeDescriptor import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.meta.descriptors.get import hep.dataforge.meta.descriptors.get
@ -12,11 +9,10 @@ import hep.dataforge.names.Name
import hep.dataforge.names.asName import hep.dataforge.names.asName
import hep.dataforge.names.toName import hep.dataforge.names.toName
import hep.dataforge.vision.Vision.Companion.TYPE import hep.dataforge.vision.Vision.Companion.TYPE
import kotlinx.coroutines.* import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.launchIn
import kotlinx.serialization.Transient import kotlinx.coroutines.flow.onEach
/** /**
* A root type for display hierarchy * A root type for display hierarchy
@ -27,26 +23,8 @@ public interface Vision : Described {
/** /**
* The parent object of this one. If null, this one is a root. * The parent object of this one. If null, this one is a root.
*/ */
@Transient
public var parent: VisionGroup? public var parent: VisionGroup?
/**
* Properties belonging to this [Vision] potentially including artificial properties
*/
@Transient
public val meta: Meta
/**
* A coroutine scope for asynchronous calls and locks
*/
public val scope: CoroutineScope get() = parent?.scope ?: GlobalScope
/**
* A fast accessor method to get own property (no inheritance or styles).
* Should be equivalent to `getProperty(name,false,false,false)`.
*/
public fun getOwnProperty(name: Name): MetaItem?
/** /**
* Get property. * Get property.
* @param inherit toggles parent node property lookup. Null means inference from descriptor. Default is false. * @param inherit toggles parent node property lookup. Null means inference from descriptor. Default is false.
@ -59,38 +37,32 @@ public interface Vision : Described {
includeDefaults: Boolean = true, includeDefaults: Boolean = true,
): MetaItem? ): MetaItem?
/**
* Get an intrinsic property of this Vision excluding any inheritance or defaults. In most cases should be the same as
* `getProperty(name, false, false, false`.
*/
public fun getOwnProperty(name: Name): MetaItem? = getProperty(
name,
inherit = false,
includeStyles = false,
includeDefaults = false
)
/** /**
* Set the property value * Set the property value
*/ */
public fun setProperty(name: Name, item: MetaItem?, notify: Boolean = true) public fun setProperty(name: Name, item: MetaItem?, notify: Boolean = true)
/**
* Subscribe on property updates. The subscription is bound to the given [scope] and canceled when the scope is canceled
*/
public fun onPropertyChange(scope: CoroutineScope, callback: suspend (Name) -> Unit)
/** /**
* Flow of property invalidation events. It does not contain property values after invalidation since it is not clear * Flow of property invalidation events. It does not contain property values after invalidation since it is not clear
* if it should include inherited properties etc. * if it should include inherited properties etc.
*/ */
@DFExperimental
@OptIn(ExperimentalCoroutinesApi::class)
public val propertyChanges: Flow<Name> public val propertyChanges: Flow<Name>
get() = callbackFlow<Name> {
coroutineScope {
onPropertyChange(this) {
send(it)
}
awaitClose { cancel() }
}
}
/** /**
* Notify all listeners that a property has been changed and should be invalidated * Notify all listeners that a property has been changed and should be invalidated
*/ */
public suspend fun notifyPropertyChanged(propertyName: Name): Unit public fun invalidateProperty(propertyName: Name): Unit
/** /**
* Update this vision using a dif represented by [VisionChange]. * Update this vision using a dif represented by [VisionChange].
@ -107,12 +79,19 @@ public interface Vision : Described {
} }
} }
public fun Vision.asyncNotifyPropertyChange(propertyName: Name) { /**
scope.launch { * Root property node
notifyPropertyChanged(propertyName) */
} public val Vision.meta: Meta get() = ownProperties[Name.EMPTY]?.node ?: Meta.EMPTY
/**
* Subscribe on property updates. The subscription is bound to the given [scope] and canceled when the scope is canceled
*/
public fun Vision.onPropertyChange(scope: CoroutineScope, callback: suspend (Name) -> Unit) {
propertyChanges.onEach(callback).launchIn(scope)
} }
/** /**
* Own properties, excluding inheritance, styles and descriptor * Own properties, excluding inheritance, styles and descriptor
*/ */
@ -122,7 +101,6 @@ public val Vision.ownProperties: MutableItemProvider
override fun setItem(name: Name, item: MetaItem?): Unit = setProperty(name, item) override fun setItem(name: Name, item: MetaItem?): Unit = setProperty(name, item)
} }
/** /**
* Convenient accessor for all properties of a vision. * Convenient accessor for all properties of a vision.
* @param inherit - inherit property value from the parent by default. If null, inheritance is inferred from descriptor * @param inherit - inherit property value from the parent by default. If null, inheritance is inferred from descriptor

View File

@ -11,10 +11,9 @@ import hep.dataforge.values.Null
import hep.dataforge.values.ValueType import hep.dataforge.values.ValueType
import hep.dataforge.vision.Vision.Companion.STYLE_KEY import hep.dataforge.vision.Vision.Companion.STYLE_KEY
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@ -32,13 +31,14 @@ internal data class PropertyListener(
*/ */
@Serializable @Serializable
@SerialName("vision") @SerialName("vision")
public open class VisionBase(internal var properties: Config? = null) : Vision { public open class VisionBase(
internal var properties: Config? = null,
@Transient public val coroutineScope: CoroutineScope = GlobalScope,
) : Vision {
@Transient @Transient
override var parent: VisionGroup? = null override var parent: VisionGroup? = null
override val meta: Meta get() = properties ?: Meta.EMPTY
@Synchronized @Synchronized
protected fun getOrCreateConfig(): Config { protected fun getOrCreateConfig(): Config {
if (properties == null) { if (properties == null) {
@ -51,8 +51,10 @@ public open class VisionBase(internal var properties: Config? = null) : Vision {
/** /**
* A fast accessor method to get own property (no inheritance or styles * A fast accessor method to get own property (no inheritance or styles
*/ */
override fun getOwnProperty(name: Name): MetaItem? { override fun getOwnProperty(name: Name): MetaItem? = if (name == Name.EMPTY) {
return properties?.getItem(name) properties?.asMetaItem()
} else {
properties?.getItem(name)
} }
override fun getProperty( override fun getProperty(
@ -60,7 +62,10 @@ public open class VisionBase(internal var properties: Config? = null) : Vision {
inherit: Boolean, inherit: Boolean,
includeStyles: Boolean, includeStyles: Boolean,
includeDefaults: Boolean, includeDefaults: Boolean,
): MetaItem? = sequence { ): MetaItem? = if (!inherit && !includeStyles && !includeDefaults) {
getOwnProperty(name)
} else {
sequence {
yield(getOwnProperty(name)) yield(getOwnProperty(name))
if (includeStyles) { if (includeStyles) {
yieldAll(getStyleItems(name)) yieldAll(getStyleItems(name))
@ -72,13 +77,12 @@ public open class VisionBase(internal var properties: Config? = null) : Vision {
yield(descriptor?.get(name)?.defaultItem()) yield(descriptor?.get(name)?.defaultItem())
} }
}.merge() }.merge()
}
override fun setProperty(name: Name, item: MetaItem?, notify: Boolean) { override fun setProperty(name: Name, item: MetaItem?, notify: Boolean) {
getOrCreateConfig().setItem(name, item) getOrCreateConfig().setItem(name, item)
if (notify) { if (notify) {
scope.launch { invalidateProperty(name)
notifyPropertyChanged(name)
}
} }
} }
@ -89,7 +93,7 @@ public open class VisionBase(internal var properties: Config? = null) : Vision {
.flatMap { it.items.asSequence() } .flatMap { it.items.asSequence() }
.distinctBy { it.key } .distinctBy { it.key }
.forEach { .forEach {
notifyPropertyChanged(it.key.asName()) invalidateProperty(it.key.asName())
} }
} }
@ -99,18 +103,17 @@ public open class VisionBase(internal var properties: Config? = null) : Vision {
private val propertyInvalidationFlow: MutableSharedFlow<Name> = MutableSharedFlow() private val propertyInvalidationFlow: MutableSharedFlow<Name> = MutableSharedFlow()
@DFExperimental @DFExperimental
override val propertyChanges: Flow<Name> get() = propertyInvalidationFlow override val propertyChanges: Flow<Name>
get() = propertyInvalidationFlow
override fun onPropertyChange(scope: CoroutineScope, callback: suspend (Name) -> Unit) { override fun invalidateProperty(propertyName: Name) {
propertyInvalidationFlow.onEach(callback).launchIn(scope) coroutineScope.launch {
}
override suspend fun notifyPropertyChanged(propertyName: Name) {
if (propertyName == STYLE_KEY) { if (propertyName == STYLE_KEY) {
updateStyles(styles) updateStyles(styles)
} }
propertyInvalidationFlow.emit(propertyName) propertyInvalidationFlow.emit(propertyName)
} }
}
override fun update(change: VisionChange) { override fun update(change: VisionChange) {
change.properties?.let { change.properties?.let {

View File

@ -82,7 +82,7 @@ private fun CoroutineScope.collectChange(
//Collect properties change //Collect properties change
source.onPropertyChange(this) { propertyName -> source.onPropertyChange(this) { propertyName ->
val newItem = source.getOwnProperty(propertyName) val newItem = source.ownProperties[propertyName]
collector().propertyChanged(name, propertyName, newItem) collector().propertyChanged(name, propertyName, newItem)
} }

View File

@ -31,10 +31,10 @@ public open class VisionGroupBase(
} }
} }
override suspend fun notifyPropertyChanged(propertyName: Name) { override fun invalidateProperty(propertyName: Name) {
super.notifyPropertyChanged(propertyName) super.invalidateProperty(propertyName)
for (obj in this) { for (obj in this) {
obj.notifyPropertyChanged(propertyName) obj.invalidateProperty(propertyName)
} }
} }
@ -47,7 +47,7 @@ public open class VisionGroupBase(
* Propagate children change event upwards * Propagate children change event upwards
*/ */
private fun childrenChanged(name: NameToken, before: Vision?, after: Vision?) { private fun childrenChanged(name: NameToken, before: Vision?, after: Vision?) {
scope.launch { coroutineScope.launch {
_structureChanges.emit(MutableVisionGroup.StructureChange(name, before, after)) _structureChanges.emit(MutableVisionGroup.StructureChange(name, before, after))
} }
} }

View File

@ -4,6 +4,7 @@ import hep.dataforge.meta.DFExperimental
import hep.dataforge.meta.set import hep.dataforge.meta.set
import hep.dataforge.vision.VisionBase import hep.dataforge.vision.VisionBase
import hep.dataforge.vision.configure import hep.dataforge.vision.configure
import hep.dataforge.vision.meta
import kotlinx.html.* import kotlinx.html.*
import kotlinx.html.stream.createHTML import kotlinx.html.stream.createHTML
import kotlin.test.Test import kotlin.test.Test

View File

@ -2,6 +2,7 @@ package hep.dataforge.vision.solid
import hep.dataforge.names.* import hep.dataforge.names.*
import hep.dataforge.vision.Vision import hep.dataforge.vision.Vision
import hep.dataforge.vision.onPropertyChange
import javafx.scene.Group import javafx.scene.Group
import javafx.scene.Node import javafx.scene.Node
import kotlin.reflect.KClass import kotlin.reflect.KClass

View File

@ -4,15 +4,18 @@ import hep.dataforge.meta.*
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.startsWith import hep.dataforge.names.startsWith
import hep.dataforge.names.toName import hep.dataforge.names.toName
import hep.dataforge.values.Value
import hep.dataforge.vision.Vision import hep.dataforge.vision.Vision
import hep.dataforge.vision.onPropertyChange
import javafx.application.Platform import javafx.application.Platform
import javafx.beans.binding.Binding
import javafx.beans.binding.ObjectBinding import javafx.beans.binding.ObjectBinding
import tornadofx.* import tornadofx.*
/** /**
* A caching binding collection for [Vision] properties * A caching binding collection for [Vision] properties
*/ */
class VisualObjectFXBinding(val fx: FX3DPlugin, val obj: Vision) { public class VisualObjectFXBinding(public val fx: FX3DPlugin, public val obj: Vision) {
private val bindings = HashMap<Name, ObjectBinding<MetaItem?>>() private val bindings = HashMap<Name, ObjectBinding<MetaItem?>>()
init { init {
@ -31,7 +34,7 @@ class VisualObjectFXBinding(val fx: FX3DPlugin, val obj: Vision) {
} }
} }
operator fun get(key: Name): ObjectBinding<MetaItem?> { public operator fun get(key: Name): ObjectBinding<MetaItem?> {
return bindings.getOrPut(key) { return bindings.getOrPut(key) {
object : ObjectBinding<MetaItem?>() { object : ObjectBinding<MetaItem?>() {
override fun computeValue(): MetaItem? = obj.getProperty(key) override fun computeValue(): MetaItem? = obj.getProperty(key)
@ -39,10 +42,10 @@ class VisualObjectFXBinding(val fx: FX3DPlugin, val obj: Vision) {
} }
} }
operator fun get(key: String) = get(key.toName()) public operator fun get(key: String) = get(key.toName())
} }
fun ObjectBinding<MetaItem?>.value() = objectBinding { it.value } public fun ObjectBinding<MetaItem?>.value(): Binding<Value?> = objectBinding { it.value }
fun ObjectBinding<MetaItem?>.string() = stringBinding { it.string } fun ObjectBinding<MetaItem?>.string() = stringBinding { it.string }
fun ObjectBinding<MetaItem?>.number() = objectBinding { it.number } fun ObjectBinding<MetaItem?>.number() = objectBinding { it.number }
fun ObjectBinding<MetaItem?>.double() = objectBinding { it.double } fun ObjectBinding<MetaItem?>.double() = objectBinding { it.double }

View File

@ -3,6 +3,7 @@ package hep.dataforge.vision.gdml
import hep.dataforge.meta.DFExperimental import hep.dataforge.meta.DFExperimental
import hep.dataforge.meta.itemSequence import hep.dataforge.meta.itemSequence
import hep.dataforge.vision.Vision import hep.dataforge.vision.Vision
import hep.dataforge.vision.meta
import hep.dataforge.vision.solid.* import hep.dataforge.vision.solid.*
public expect class Counter() { public expect class Counter() {

View File

@ -152,21 +152,21 @@ public var Solid.x: Number
get() = position?.x ?: 0f get() = position?.x ?: 0f
set(value) { set(value) {
position().x = value.toDouble() position().x = value.toDouble()
asyncNotifyPropertyChange(Solid.X_POSITION_KEY) invalidateProperty(Solid.X_POSITION_KEY)
} }
public var Solid.y: Number public var Solid.y: Number
get() = position?.y ?: 0f get() = position?.y ?: 0f
set(value) { set(value) {
position().y = value.toDouble() position().y = value.toDouble()
asyncNotifyPropertyChange(Solid.Y_POSITION_KEY) invalidateProperty(Solid.Y_POSITION_KEY)
} }
public var Solid.z: Number public var Solid.z: Number
get() = position?.z ?: 0f get() = position?.z ?: 0f
set(value) { set(value) {
position().z = value.toDouble() position().z = value.toDouble()
asyncNotifyPropertyChange(Solid.Z_POSITION_KEY) invalidateProperty(Solid.Z_POSITION_KEY)
} }
private fun Solid.rotation(): Point3D = private fun Solid.rotation(): Point3D =
@ -176,21 +176,21 @@ public var Solid.rotationX: Number
get() = rotation?.x ?: 0f get() = rotation?.x ?: 0f
set(value) { set(value) {
rotation().x = value.toDouble() rotation().x = value.toDouble()
asyncNotifyPropertyChange(Solid.X_ROTATION_KEY) invalidateProperty(Solid.X_ROTATION_KEY)
} }
public var Solid.rotationY: Number public var Solid.rotationY: Number
get() = rotation?.y ?: 0f get() = rotation?.y ?: 0f
set(value) { set(value) {
rotation().y = value.toDouble() rotation().y = value.toDouble()
asyncNotifyPropertyChange(Solid.Y_ROTATION_KEY) invalidateProperty(Solid.Y_ROTATION_KEY)
} }
public var Solid.rotationZ: Number public var Solid.rotationZ: Number
get() = rotation?.z ?: 0f get() = rotation?.z ?: 0f
set(value) { set(value) {
rotation().z = value.toDouble() rotation().z = value.toDouble()
asyncNotifyPropertyChange(Solid.Z_ROTATION_KEY) invalidateProperty(Solid.Z_ROTATION_KEY)
} }
private fun Solid.scale(): Point3D = private fun Solid.scale(): Point3D =
@ -200,19 +200,19 @@ public var Solid.scaleX: Number
get() = scale?.x ?: 1f get() = scale?.x ?: 1f
set(value) { set(value) {
scale().x = value.toDouble() scale().x = value.toDouble()
asyncNotifyPropertyChange(Solid.X_SCALE_KEY) invalidateProperty(Solid.X_SCALE_KEY)
} }
public var Solid.scaleY: Number public var Solid.scaleY: Number
get() = scale?.y ?: 1f get() = scale?.y ?: 1f
set(value) { set(value) {
scale().y = value.toDouble() scale().y = value.toDouble()
asyncNotifyPropertyChange(Solid.Y_SCALE_KEY) invalidateProperty(Solid.Y_SCALE_KEY)
} }
public var Solid.scaleZ: Number public var Solid.scaleZ: Number
get() = scale?.z ?: 1f get() = scale?.z ?: 1f
set(value) { set(value) {
scale().z = value.toDouble() scale().z = value.toDouble()
asyncNotifyPropertyChange(Solid.Z_SCALE_KEY) invalidateProperty(Solid.Z_SCALE_KEY)
} }

View File

@ -107,8 +107,6 @@ internal class Prototypes(
} }
} }
override fun getOwnProperty(name: Name): MetaItem? = null
override fun getProperty( override fun getProperty(
name: Name, name: Name,
inherit: Boolean, inherit: Boolean,

View File

@ -3,9 +3,9 @@ package hep.dataforge.vision.solid
import hep.dataforge.meta.* import hep.dataforge.meta.*
import hep.dataforge.meta.descriptors.NodeDescriptor import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.names.* import hep.dataforge.names.*
import hep.dataforge.values.Null
import hep.dataforge.vision.* import hep.dataforge.vision.*
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@ -18,8 +18,7 @@ private fun SolidReference.getRefProperty(
inherit: Boolean, inherit: Boolean,
includeStyles: Boolean, includeStyles: Boolean,
includeDefaults: Boolean, includeDefaults: Boolean,
): MetaItem? { ): MetaItem? = sequence {
return sequence {
yield(getOwnProperty(name)) yield(getOwnProperty(name))
if (includeStyles) { if (includeStyles) {
yieldAll(getStyleItems(name)) yieldAll(getStyleItems(name))
@ -29,7 +28,6 @@ private fun SolidReference.getRefProperty(
yield(parent?.getProperty(name, inherit)) yield(parent?.getProperty(name, inherit))
} }
}.merge() }.merge()
}
/** /**
* A reference [Solid] to reuse a template object * A reference [Solid] to reuse a template object
@ -100,8 +98,6 @@ public class SolidReferenceGroup(
ReferenceChild(childName + key.asName()) ReferenceChild(childName + key.asName())
} ?: emptyMap() } ?: emptyMap()
override val meta: Meta get() = TODO()// getChildProperty(childName, Name.EMPTY).node ?: Meta.EMPTY
override fun getOwnProperty(name: Name): MetaItem? = getChildProperty(childName, name) override fun getOwnProperty(name: Name): MetaItem? = getChildProperty(childName, name)
override fun setProperty(name: Name, item: MetaItem?, notify: Boolean) { override fun setProperty(name: Name, item: MetaItem?, notify: Boolean) {
@ -113,7 +109,11 @@ public class SolidReferenceGroup(
inherit: Boolean, inherit: Boolean,
includeStyles: Boolean, includeStyles: Boolean,
includeDefaults: Boolean, includeDefaults: Boolean,
): MetaItem? = getRefProperty(name, inherit, includeStyles, includeDefaults) ): MetaItem? = if (!inherit && !includeStyles && !includeDefaults) {
getOwnProperty(name)
} else {
getRefProperty(name, inherit, includeStyles, includeDefaults)
}
override var parent: VisionGroup? override var parent: VisionGroup?
get() { get() {
@ -124,16 +124,18 @@ public class SolidReferenceGroup(
error("Setting a parent for a reference child is not possible") error("Setting a parent for a reference child is not possible")
} }
override fun onPropertyChange(scope: CoroutineScope, callback: suspend (Name) -> Unit) { @DFExperimental
this@SolidReferenceGroup.onPropertyChange(scope) { name -> override val propertyChanges: Flow<Name>
get() = this@SolidReferenceGroup.propertyChanges.mapNotNull { name ->
if (name.startsWith(childToken(childName))) { if (name.startsWith(childToken(childName))) {
callback(name.cutFirst()) name.cutFirst()
} } else {
null
} }
} }
override suspend fun notifyPropertyChanged(propertyName: Name) { override fun invalidateProperty(propertyName: Name) {
this@SolidReferenceGroup.notifyPropertyChanged(childPropertyName(childName, propertyName)) this@SolidReferenceGroup.invalidateProperty(childPropertyName(childName, propertyName))
} }
override fun update(change: VisionChange) { override fun update(change: VisionChange) {

View File

@ -4,6 +4,7 @@ import hep.dataforge.names.Name
import hep.dataforge.names.toName import hep.dataforge.names.toName
import hep.dataforge.vision.MutableVisionGroup import hep.dataforge.vision.MutableVisionGroup
import hep.dataforge.vision.get import hep.dataforge.vision.get
import hep.dataforge.vision.meta
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals

View File

@ -2,19 +2,18 @@ package hep.dataforge.vision.solid
import hep.dataforge.vision.get import hep.dataforge.vision.get
import hep.dataforge.vision.style import hep.dataforge.vision.style
import hep.dataforge.vision.styles
import hep.dataforge.vision.useStyle import hep.dataforge.vision.useStyle
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
class SolidReferenceTest { class SolidReferenceTest {
val groupWithReference = SolidGroup { val groupWithReference = SolidGroup {
val referenceStyle by style { val theStyle by style {
SolidMaterial.MATERIAL_COLOR_KEY put "red" SolidMaterial.MATERIAL_COLOR_KEY put "red"
} }
ref("test", Box(100f,100f,100f).apply { ref("test", Box(100f,100f,100f).apply {
color("blue") color("blue")
useStyle(referenceStyle) useStyle(theStyle)
}) })
} }

View File

@ -6,6 +6,7 @@ import hep.dataforge.names.Name
import hep.dataforge.names.asName import hep.dataforge.names.asName
import hep.dataforge.names.plus import hep.dataforge.names.plus
import hep.dataforge.names.startsWith import hep.dataforge.names.startsWith
import hep.dataforge.vision.onPropertyChange
import hep.dataforge.vision.solid.Solid import hep.dataforge.vision.solid.Solid
import hep.dataforge.vision.solid.SolidMaterial import hep.dataforge.vision.solid.SolidMaterial
import hep.dataforge.vision.solid.layer import hep.dataforge.vision.solid.layer

View File

@ -2,6 +2,7 @@ package hep.dataforge.vision.solid.three
import hep.dataforge.context.logger import hep.dataforge.context.logger
import hep.dataforge.vision.onPropertyChange
import hep.dataforge.vision.solid.SolidLabel import hep.dataforge.vision.solid.SolidLabel
import info.laht.threekt.core.Object3D import info.laht.threekt.core.Object3D
import info.laht.threekt.geometries.TextBufferGeometry import info.laht.threekt.geometries.TextBufferGeometry

View File

@ -1,6 +1,7 @@
package hep.dataforge.vision.solid.three package hep.dataforge.vision.solid.three
import hep.dataforge.meta.node import hep.dataforge.meta.node
import hep.dataforge.vision.onPropertyChange
import hep.dataforge.vision.solid.PolyLine import hep.dataforge.vision.solid.PolyLine
import hep.dataforge.vision.solid.color import hep.dataforge.vision.solid.color
import hep.dataforge.vision.solid.string import hep.dataforge.vision.solid.string

View File

@ -7,6 +7,7 @@ import hep.dataforge.values.int
import hep.dataforge.values.string import hep.dataforge.values.string
import hep.dataforge.vision.Colors import hep.dataforge.vision.Colors
import hep.dataforge.vision.Vision import hep.dataforge.vision.Vision
import hep.dataforge.vision.ownProperties
import hep.dataforge.vision.solid.SolidMaterial import hep.dataforge.vision.solid.SolidMaterial
import info.laht.threekt.materials.LineBasicMaterial import info.laht.threekt.materials.LineBasicMaterial
import info.laht.threekt.materials.Material import info.laht.threekt.materials.Material
@ -119,7 +120,7 @@ private var Material.cached: Boolean
public fun Mesh.updateMaterial(vision: Vision) { public fun Mesh.updateMaterial(vision: Vision) {
//val meta = vision.getProperty(SolidMaterial.MATERIAL_KEY, inherit = true).node //val meta = vision.getProperty(SolidMaterial.MATERIAL_KEY, inherit = true).node
val ownMaterialMeta = vision.getOwnProperty(SolidMaterial.MATERIAL_KEY) val ownMaterialMeta = vision.ownProperties[SolidMaterial.MATERIAL_KEY]
val parentMaterialMeta = vision.parent?.getProperty( val parentMaterialMeta = vision.parent?.getProperty(
SolidMaterial.MATERIAL_KEY, SolidMaterial.MATERIAL_KEY,
inherit = true, inherit = true,

View File

@ -6,6 +6,7 @@ import hep.dataforge.names.*
import hep.dataforge.vision.Vision import hep.dataforge.vision.Vision
import hep.dataforge.vision.VisionForge import hep.dataforge.vision.VisionForge
import hep.dataforge.vision.client.ElementVisionRenderer import hep.dataforge.vision.client.ElementVisionRenderer
import hep.dataforge.vision.onPropertyChange
import hep.dataforge.vision.solid.* import hep.dataforge.vision.solid.*
import hep.dataforge.vision.solid.specifications.Canvas3DOptions import hep.dataforge.vision.solid.specifications.Canvas3DOptions
import hep.dataforge.vision.visible import hep.dataforge.vision.visible

View File

@ -3,6 +3,7 @@ package hep.dataforge.vision.solid.three
import hep.dataforge.names.cutFirst import hep.dataforge.names.cutFirst
import hep.dataforge.names.firstOrNull import hep.dataforge.names.firstOrNull
import hep.dataforge.names.toName import hep.dataforge.names.toName
import hep.dataforge.vision.onPropertyChange
import hep.dataforge.vision.solid.Solid import hep.dataforge.vision.solid.Solid
import hep.dataforge.vision.solid.SolidReferenceGroup import hep.dataforge.vision.solid.SolidReferenceGroup
import hep.dataforge.vision.solid.SolidReferenceGroup.Companion.REFERENCE_CHILD_PROPERTY_PREFIX import hep.dataforge.vision.solid.SolidReferenceGroup.Companion.REFERENCE_CHILD_PROPERTY_PREFIX