API cleanup
10
README.md
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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.*
|
||||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 97 KiB |
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 87 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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,25 +62,27 @@ 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) {
|
||||||
yield(getOwnProperty(name))
|
getOwnProperty(name)
|
||||||
if (includeStyles) {
|
} else {
|
||||||
yieldAll(getStyleItems(name))
|
sequence {
|
||||||
}
|
yield(getOwnProperty(name))
|
||||||
if (inherit) {
|
if (includeStyles) {
|
||||||
yield(parent?.getProperty(name, inherit, includeStyles, includeDefaults))
|
yieldAll(getStyleItems(name))
|
||||||
}
|
}
|
||||||
if (includeDefaults) {
|
if (inherit) {
|
||||||
yield(descriptor?.get(name)?.defaultItem())
|
yield(parent?.getProperty(name, inherit, includeStyles, includeDefaults))
|
||||||
}
|
}
|
||||||
}.merge()
|
if (includeDefaults) {
|
||||||
|
yield(descriptor?.get(name)?.defaultItem())
|
||||||
|
}
|
||||||
|
}.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,17 +103,16 @@ 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 {
|
||||||
}
|
if (propertyName == STYLE_KEY) {
|
||||||
|
updateStyles(styles)
|
||||||
override suspend fun notifyPropertyChanged(propertyName: Name) {
|
}
|
||||||
if (propertyName == STYLE_KEY) {
|
propertyInvalidationFlow.emit(propertyName)
|
||||||
updateStyles(styles)
|
|
||||||
}
|
}
|
||||||
propertyInvalidationFlow.emit(propertyName)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun update(change: VisionChange) {
|
override fun update(change: VisionChange) {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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 }
|
||||||
|
@ -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() {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
@ -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,
|
||||||
|
@ -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,18 +18,16 @@ 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))
|
}
|
||||||
}
|
yield(prototype.getProperty(name, inherit, includeStyles, includeDefaults))
|
||||||
yield(prototype.getProperty(name, inherit, includeStyles, includeDefaults))
|
if (inherit) {
|
||||||
if (inherit) {
|
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) {
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|