API cleanup
10
README.md
@ -73,7 +73,7 @@ The `visionforge-core` module also includes configuration editors for JS (in `js
|
||||
|
||||
**Class diagram:**
|
||||
|
||||
![](docs/resources/class-diag-core.png)
|
||||
![](docs/images/class-diag-core.png)
|
||||
|
||||
|
||||
### visionforge-solid
|
||||
@ -82,7 +82,7 @@ Includes common classes and serializers for 3D visualization, as well as Three.j
|
||||
|
||||
**Class diagram:**
|
||||
|
||||
![](docs/resources/class-diag-solid.png)
|
||||
![](docs/images/class-diag-solid.png)
|
||||
|
||||
##### Prototypes
|
||||
|
||||
@ -127,7 +127,7 @@ Some shapes will also periodically change their color and visibility.
|
||||
|
||||
**Example view:**
|
||||
|
||||
![](docs/resources/spatial-showcase.png)
|
||||
![](docs/images/spatial-showcase.png)
|
||||
|
||||
|
||||
### Full-Stack Application Example - Muon Monitor Visualization
|
||||
@ -139,7 +139,7 @@ A full-stack application example, showing the
|
||||
|
||||
**Example view:**
|
||||
|
||||
![](docs/resources/muon-monitor.png)
|
||||
![](docs/images/muon-monitor.png)
|
||||
|
||||
|
||||
### GDML Example
|
||||
@ -150,7 +150,7 @@ Visualization example for geometry defined as GDML file.
|
||||
|
||||
##### Example view:
|
||||
|
||||
![](docs/resources/gdml-demo.png)
|
||||
![](docs/images/gdml-demo.png)
|
||||
|
||||
|
||||
## Thanks and references
|
||||
|
@ -12,4 +12,4 @@ drag-and-drop GDML file to the window to see visualization. For an example file,
|
||||
|
||||
##### 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:
|
||||
|
||||
![](../../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:
|
||||
|
||||
![](../../docs/resources/spatial-showcase.png)
|
||||
![](../../docs/images/spatial-showcase.png)
|
||||
|
||||
##### 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.values.asValue
|
||||
import hep.dataforge.vision.getProperty
|
||||
import hep.dataforge.vision.onPropertyChange
|
||||
import hep.dataforge.vision.set
|
||||
import hep.dataforge.vision.setProperty
|
||||
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.asName
|
||||
import hep.dataforge.names.plus
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* A container for styles
|
||||
*/
|
||||
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 }
|
||||
|
||||
@ -55,9 +54,7 @@ internal fun Vision.styleChanged(key: String, oldStyle: Meta?, newStyle: Meta?)
|
||||
val tokens: Collection<Name> =
|
||||
((oldStyle?.items?.keys ?: emptySet()) + (newStyle?.items?.keys ?: emptySet()))
|
||||
.map { it.asName() }
|
||||
parent?.scope?.launch {
|
||||
tokens.forEach { parent?.notifyPropertyChanged(it) }
|
||||
}
|
||||
tokens.forEach { parent?.invalidateProperty(it) }
|
||||
}
|
||||
if (this is VisionGroup) {
|
||||
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.
|
||||
*/
|
||||
public var Vision.styles: List<String>
|
||||
get() = getOwnProperty(Vision.STYLE_KEY)?.stringList ?: emptyList()
|
||||
get() = ownProperties[Vision.STYLE_KEY]?.stringList ?: emptyList()
|
||||
set(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.
|
||||
*/
|
||||
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].
|
||||
*/
|
||||
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
|
||||
|
@ -1,9 +1,6 @@
|
||||
package hep.dataforge.vision
|
||||
|
||||
import hep.dataforge.meta.DFExperimental
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.MetaItem
|
||||
import hep.dataforge.meta.MutableItemProvider
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.meta.descriptors.Described
|
||||
import hep.dataforge.meta.descriptors.NodeDescriptor
|
||||
import hep.dataforge.meta.descriptors.get
|
||||
@ -12,11 +9,10 @@ import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.asName
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.vision.Vision.Companion.TYPE
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
import kotlinx.serialization.Transient
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@Transient
|
||||
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.
|
||||
* @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,
|
||||
): 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
|
||||
*/
|
||||
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
|
||||
* if it should include inherited properties etc.
|
||||
*/
|
||||
@DFExperimental
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
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
|
||||
*/
|
||||
public suspend fun notifyPropertyChanged(propertyName: Name): Unit
|
||||
public fun invalidateProperty(propertyName: Name): Unit
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
notifyPropertyChanged(propertyName)
|
||||
}
|
||||
/**
|
||||
* Root property node
|
||||
*/
|
||||
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
|
||||
*/
|
||||
@ -122,7 +101,6 @@ public val Vision.ownProperties: MutableItemProvider
|
||||
override fun setItem(name: Name, item: MetaItem?): Unit = setProperty(name, item)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -11,10 +11,9 @@ import hep.dataforge.values.Null
|
||||
import hep.dataforge.values.ValueType
|
||||
import hep.dataforge.vision.Vision.Companion.STYLE_KEY
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
@ -32,13 +31,14 @@ internal data class PropertyListener(
|
||||
*/
|
||||
@Serializable
|
||||
@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
|
||||
override var parent: VisionGroup? = null
|
||||
|
||||
override val meta: Meta get() = properties ?: Meta.EMPTY
|
||||
|
||||
@Synchronized
|
||||
protected fun getOrCreateConfig(): Config {
|
||||
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
|
||||
*/
|
||||
override fun getOwnProperty(name: Name): MetaItem? {
|
||||
return properties?.getItem(name)
|
||||
override fun getOwnProperty(name: Name): MetaItem? = if (name == Name.EMPTY) {
|
||||
properties?.asMetaItem()
|
||||
} else {
|
||||
properties?.getItem(name)
|
||||
}
|
||||
|
||||
override fun getProperty(
|
||||
@ -60,7 +62,10 @@ public open class VisionBase(internal var properties: Config? = null) : Vision {
|
||||
inherit: Boolean,
|
||||
includeStyles: Boolean,
|
||||
includeDefaults: Boolean,
|
||||
): MetaItem? = sequence {
|
||||
): MetaItem? = if (!inherit && !includeStyles && !includeDefaults) {
|
||||
getOwnProperty(name)
|
||||
} else {
|
||||
sequence {
|
||||
yield(getOwnProperty(name))
|
||||
if (includeStyles) {
|
||||
yieldAll(getStyleItems(name))
|
||||
@ -72,13 +77,12 @@ public open class VisionBase(internal var properties: Config? = null) : Vision {
|
||||
yield(descriptor?.get(name)?.defaultItem())
|
||||
}
|
||||
}.merge()
|
||||
}
|
||||
|
||||
override fun setProperty(name: Name, item: MetaItem?, notify: Boolean) {
|
||||
getOrCreateConfig().setItem(name, item)
|
||||
if (notify) {
|
||||
scope.launch {
|
||||
notifyPropertyChanged(name)
|
||||
}
|
||||
invalidateProperty(name)
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,7 +93,7 @@ public open class VisionBase(internal var properties: Config? = null) : Vision {
|
||||
.flatMap { it.items.asSequence() }
|
||||
.distinctBy { it.key }
|
||||
.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()
|
||||
|
||||
@DFExperimental
|
||||
override val propertyChanges: Flow<Name> get() = propertyInvalidationFlow
|
||||
override val propertyChanges: Flow<Name>
|
||||
get() = propertyInvalidationFlow
|
||||
|
||||
override fun onPropertyChange(scope: CoroutineScope, callback: suspend (Name) -> Unit) {
|
||||
propertyInvalidationFlow.onEach(callback).launchIn(scope)
|
||||
}
|
||||
|
||||
override suspend fun notifyPropertyChanged(propertyName: Name) {
|
||||
override fun invalidateProperty(propertyName: Name) {
|
||||
coroutineScope.launch {
|
||||
if (propertyName == STYLE_KEY) {
|
||||
updateStyles(styles)
|
||||
}
|
||||
propertyInvalidationFlow.emit(propertyName)
|
||||
}
|
||||
}
|
||||
|
||||
override fun update(change: VisionChange) {
|
||||
change.properties?.let {
|
||||
|
@ -82,7 +82,7 @@ private fun CoroutineScope.collectChange(
|
||||
|
||||
//Collect properties change
|
||||
source.onPropertyChange(this) { propertyName ->
|
||||
val newItem = source.getOwnProperty(propertyName)
|
||||
val newItem = source.ownProperties[propertyName]
|
||||
collector().propertyChanged(name, propertyName, newItem)
|
||||
}
|
||||
|
||||
|
@ -31,10 +31,10 @@ public open class VisionGroupBase(
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun notifyPropertyChanged(propertyName: Name) {
|
||||
super.notifyPropertyChanged(propertyName)
|
||||
override fun invalidateProperty(propertyName: Name) {
|
||||
super.invalidateProperty(propertyName)
|
||||
for (obj in this) {
|
||||
obj.notifyPropertyChanged(propertyName)
|
||||
obj.invalidateProperty(propertyName)
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ public open class VisionGroupBase(
|
||||
* Propagate children change event upwards
|
||||
*/
|
||||
private fun childrenChanged(name: NameToken, before: Vision?, after: Vision?) {
|
||||
scope.launch {
|
||||
coroutineScope.launch {
|
||||
_structureChanges.emit(MutableVisionGroup.StructureChange(name, before, after))
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import hep.dataforge.meta.DFExperimental
|
||||
import hep.dataforge.meta.set
|
||||
import hep.dataforge.vision.VisionBase
|
||||
import hep.dataforge.vision.configure
|
||||
import hep.dataforge.vision.meta
|
||||
import kotlinx.html.*
|
||||
import kotlinx.html.stream.createHTML
|
||||
import kotlin.test.Test
|
||||
|
@ -2,6 +2,7 @@ package hep.dataforge.vision.solid
|
||||
|
||||
import hep.dataforge.names.*
|
||||
import hep.dataforge.vision.Vision
|
||||
import hep.dataforge.vision.onPropertyChange
|
||||
import javafx.scene.Group
|
||||
import javafx.scene.Node
|
||||
import kotlin.reflect.KClass
|
||||
|
@ -4,15 +4,18 @@ import hep.dataforge.meta.*
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.startsWith
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.values.Value
|
||||
import hep.dataforge.vision.Vision
|
||||
import hep.dataforge.vision.onPropertyChange
|
||||
import javafx.application.Platform
|
||||
import javafx.beans.binding.Binding
|
||||
import javafx.beans.binding.ObjectBinding
|
||||
import tornadofx.*
|
||||
|
||||
/**
|
||||
* 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?>>()
|
||||
|
||||
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) {
|
||||
object : ObjectBinding<MetaItem?>() {
|
||||
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?>.number() = objectBinding { it.number }
|
||||
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.itemSequence
|
||||
import hep.dataforge.vision.Vision
|
||||
import hep.dataforge.vision.meta
|
||||
import hep.dataforge.vision.solid.*
|
||||
|
||||
public expect class Counter() {
|
||||
|
@ -152,21 +152,21 @@ public var Solid.x: Number
|
||||
get() = position?.x ?: 0f
|
||||
set(value) {
|
||||
position().x = value.toDouble()
|
||||
asyncNotifyPropertyChange(Solid.X_POSITION_KEY)
|
||||
invalidateProperty(Solid.X_POSITION_KEY)
|
||||
}
|
||||
|
||||
public var Solid.y: Number
|
||||
get() = position?.y ?: 0f
|
||||
set(value) {
|
||||
position().y = value.toDouble()
|
||||
asyncNotifyPropertyChange(Solid.Y_POSITION_KEY)
|
||||
invalidateProperty(Solid.Y_POSITION_KEY)
|
||||
}
|
||||
|
||||
public var Solid.z: Number
|
||||
get() = position?.z ?: 0f
|
||||
set(value) {
|
||||
position().z = value.toDouble()
|
||||
asyncNotifyPropertyChange(Solid.Z_POSITION_KEY)
|
||||
invalidateProperty(Solid.Z_POSITION_KEY)
|
||||
}
|
||||
|
||||
private fun Solid.rotation(): Point3D =
|
||||
@ -176,21 +176,21 @@ public var Solid.rotationX: Number
|
||||
get() = rotation?.x ?: 0f
|
||||
set(value) {
|
||||
rotation().x = value.toDouble()
|
||||
asyncNotifyPropertyChange(Solid.X_ROTATION_KEY)
|
||||
invalidateProperty(Solid.X_ROTATION_KEY)
|
||||
}
|
||||
|
||||
public var Solid.rotationY: Number
|
||||
get() = rotation?.y ?: 0f
|
||||
set(value) {
|
||||
rotation().y = value.toDouble()
|
||||
asyncNotifyPropertyChange(Solid.Y_ROTATION_KEY)
|
||||
invalidateProperty(Solid.Y_ROTATION_KEY)
|
||||
}
|
||||
|
||||
public var Solid.rotationZ: Number
|
||||
get() = rotation?.z ?: 0f
|
||||
set(value) {
|
||||
rotation().z = value.toDouble()
|
||||
asyncNotifyPropertyChange(Solid.Z_ROTATION_KEY)
|
||||
invalidateProperty(Solid.Z_ROTATION_KEY)
|
||||
}
|
||||
|
||||
private fun Solid.scale(): Point3D =
|
||||
@ -200,19 +200,19 @@ public var Solid.scaleX: Number
|
||||
get() = scale?.x ?: 1f
|
||||
set(value) {
|
||||
scale().x = value.toDouble()
|
||||
asyncNotifyPropertyChange(Solid.X_SCALE_KEY)
|
||||
invalidateProperty(Solid.X_SCALE_KEY)
|
||||
}
|
||||
|
||||
public var Solid.scaleY: Number
|
||||
get() = scale?.y ?: 1f
|
||||
set(value) {
|
||||
scale().y = value.toDouble()
|
||||
asyncNotifyPropertyChange(Solid.Y_SCALE_KEY)
|
||||
invalidateProperty(Solid.Y_SCALE_KEY)
|
||||
}
|
||||
|
||||
public var Solid.scaleZ: Number
|
||||
get() = scale?.z ?: 1f
|
||||
set(value) {
|
||||
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(
|
||||
name: Name,
|
||||
inherit: Boolean,
|
||||
|
@ -3,9 +3,9 @@ package hep.dataforge.vision.solid
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.meta.descriptors.NodeDescriptor
|
||||
import hep.dataforge.names.*
|
||||
import hep.dataforge.values.Null
|
||||
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.Serializable
|
||||
|
||||
@ -18,8 +18,7 @@ private fun SolidReference.getRefProperty(
|
||||
inherit: Boolean,
|
||||
includeStyles: Boolean,
|
||||
includeDefaults: Boolean,
|
||||
): MetaItem? {
|
||||
return sequence {
|
||||
): MetaItem? = sequence {
|
||||
yield(getOwnProperty(name))
|
||||
if (includeStyles) {
|
||||
yieldAll(getStyleItems(name))
|
||||
@ -29,7 +28,6 @@ private fun SolidReference.getRefProperty(
|
||||
yield(parent?.getProperty(name, inherit))
|
||||
}
|
||||
}.merge()
|
||||
}
|
||||
|
||||
/**
|
||||
* A reference [Solid] to reuse a template object
|
||||
@ -100,8 +98,6 @@ public class SolidReferenceGroup(
|
||||
ReferenceChild(childName + key.asName())
|
||||
} ?: 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 setProperty(name: Name, item: MetaItem?, notify: Boolean) {
|
||||
@ -113,7 +109,11 @@ public class SolidReferenceGroup(
|
||||
inherit: Boolean,
|
||||
includeStyles: 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?
|
||||
get() {
|
||||
@ -124,16 +124,18 @@ public class SolidReferenceGroup(
|
||||
error("Setting a parent for a reference child is not possible")
|
||||
}
|
||||
|
||||
override fun onPropertyChange(scope: CoroutineScope, callback: suspend (Name) -> Unit) {
|
||||
this@SolidReferenceGroup.onPropertyChange(scope) { name ->
|
||||
@DFExperimental
|
||||
override val propertyChanges: Flow<Name>
|
||||
get() = this@SolidReferenceGroup.propertyChanges.mapNotNull { name ->
|
||||
if (name.startsWith(childToken(childName))) {
|
||||
callback(name.cutFirst())
|
||||
}
|
||||
name.cutFirst()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun notifyPropertyChanged(propertyName: Name) {
|
||||
this@SolidReferenceGroup.notifyPropertyChanged(childPropertyName(childName, propertyName))
|
||||
override fun invalidateProperty(propertyName: Name) {
|
||||
this@SolidReferenceGroup.invalidateProperty(childPropertyName(childName, propertyName))
|
||||
}
|
||||
|
||||
override fun update(change: VisionChange) {
|
||||
|
@ -4,6 +4,7 @@ import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.vision.MutableVisionGroup
|
||||
import hep.dataforge.vision.get
|
||||
import hep.dataforge.vision.meta
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
|
@ -2,19 +2,18 @@ package hep.dataforge.vision.solid
|
||||
|
||||
import hep.dataforge.vision.get
|
||||
import hep.dataforge.vision.style
|
||||
import hep.dataforge.vision.styles
|
||||
import hep.dataforge.vision.useStyle
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class SolidReferenceTest {
|
||||
val groupWithReference = SolidGroup {
|
||||
val referenceStyle by style {
|
||||
val theStyle by style {
|
||||
SolidMaterial.MATERIAL_COLOR_KEY put "red"
|
||||
}
|
||||
ref("test", Box(100f,100f,100f).apply {
|
||||
color("blue")
|
||||
useStyle(referenceStyle)
|
||||
useStyle(theStyle)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.asName
|
||||
import hep.dataforge.names.plus
|
||||
import hep.dataforge.names.startsWith
|
||||
import hep.dataforge.vision.onPropertyChange
|
||||
import hep.dataforge.vision.solid.Solid
|
||||
import hep.dataforge.vision.solid.SolidMaterial
|
||||
import hep.dataforge.vision.solid.layer
|
||||
|
@ -2,6 +2,7 @@ package hep.dataforge.vision.solid.three
|
||||
|
||||
|
||||
import hep.dataforge.context.logger
|
||||
import hep.dataforge.vision.onPropertyChange
|
||||
import hep.dataforge.vision.solid.SolidLabel
|
||||
import info.laht.threekt.core.Object3D
|
||||
import info.laht.threekt.geometries.TextBufferGeometry
|
||||
|
@ -1,6 +1,7 @@
|
||||
package hep.dataforge.vision.solid.three
|
||||
|
||||
import hep.dataforge.meta.node
|
||||
import hep.dataforge.vision.onPropertyChange
|
||||
import hep.dataforge.vision.solid.PolyLine
|
||||
import hep.dataforge.vision.solid.color
|
||||
import hep.dataforge.vision.solid.string
|
||||
|
@ -7,6 +7,7 @@ import hep.dataforge.values.int
|
||||
import hep.dataforge.values.string
|
||||
import hep.dataforge.vision.Colors
|
||||
import hep.dataforge.vision.Vision
|
||||
import hep.dataforge.vision.ownProperties
|
||||
import hep.dataforge.vision.solid.SolidMaterial
|
||||
import info.laht.threekt.materials.LineBasicMaterial
|
||||
import info.laht.threekt.materials.Material
|
||||
@ -119,7 +120,7 @@ private var Material.cached: Boolean
|
||||
|
||||
public fun Mesh.updateMaterial(vision: Vision) {
|
||||
//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(
|
||||
SolidMaterial.MATERIAL_KEY,
|
||||
inherit = true,
|
||||
|
@ -6,6 +6,7 @@ import hep.dataforge.names.*
|
||||
import hep.dataforge.vision.Vision
|
||||
import hep.dataforge.vision.VisionForge
|
||||
import hep.dataforge.vision.client.ElementVisionRenderer
|
||||
import hep.dataforge.vision.onPropertyChange
|
||||
import hep.dataforge.vision.solid.*
|
||||
import hep.dataforge.vision.solid.specifications.Canvas3DOptions
|
||||
import hep.dataforge.vision.visible
|
||||
|
@ -3,6 +3,7 @@ package hep.dataforge.vision.solid.three
|
||||
import hep.dataforge.names.cutFirst
|
||||
import hep.dataforge.names.firstOrNull
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.vision.onPropertyChange
|
||||
import hep.dataforge.vision.solid.Solid
|
||||
import hep.dataforge.vision.solid.SolidReferenceGroup
|
||||
import hep.dataforge.vision.solid.SolidReferenceGroup.Companion.REFERENCE_CHILD_PROPERTY_PREFIX
|
||||
|