[WIP] refactor inner logic
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
package space.kscience.dataforge.meta
|
||||
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.NameToken
|
||||
import space.kscience.dataforge.names.plus
|
||||
|
||||
public class MutableMetaProxy(
|
||||
public val upstream: MutableMeta,
|
||||
public val proxyName: Name
|
||||
) : MutableMeta {
|
||||
|
||||
override val items: Map<NameToken, MutableMeta>
|
||||
get() = upstream[proxyName]?.items ?: emptyMap()
|
||||
|
||||
override var value: Value?
|
||||
get() = upstream[proxyName]?.value
|
||||
set(value) {
|
||||
upstream[proxyName] = value
|
||||
}
|
||||
|
||||
override fun getOrCreate(name: Name): MutableMeta = upstream.getOrCreate(proxyName + name)
|
||||
|
||||
|
||||
override fun set(name: Name, node: Meta?) {
|
||||
set(proxyName + name, node)
|
||||
}
|
||||
|
||||
|
||||
override fun equals(other: Any?): Boolean = Meta.equals(this, other as? Meta)
|
||||
|
||||
|
||||
override fun hashCode(): Int = Meta.hashCode(this)
|
||||
|
||||
override fun toString(): String = Meta.toString(this)
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package space.kscience.visionforge
|
||||
import space.kscience.dataforge.meta.MutableMeta
|
||||
import space.kscience.dataforge.meta.Scheme
|
||||
import space.kscience.dataforge.meta.SchemeSpec
|
||||
import space.kscience.dataforge.names.parseAsName
|
||||
import kotlin.properties.ReadOnlyProperty
|
||||
|
||||
/**
|
||||
@@ -18,10 +17,10 @@ private tailrec fun styleIsDefined(vision: Vision, reference: StyleReference): B
|
||||
}
|
||||
|
||||
@VisionBuilder
|
||||
public fun Vision.useStyle(reference: StyleReference, notify: Boolean = true) {
|
||||
public fun MutableVision.useStyle(reference: StyleReference) {
|
||||
//check that style is defined in a parent
|
||||
//check(styleIsDefined(this, reference)) { "Style reference does not belong to a Vision parent" }
|
||||
useStyle(reference.name, notify)
|
||||
useStyle(reference.name)
|
||||
}
|
||||
|
||||
@VisionBuilder
|
||||
@@ -30,7 +29,7 @@ public fun MutableVision.style(
|
||||
builder: MutableMeta.() -> Unit,
|
||||
): ReadOnlyProperty<Any?, StyleReference> = ReadOnlyProperty { _, property ->
|
||||
val styleName = styleKey ?: property.name
|
||||
updateStyle(styleName.parseAsName(), builder)
|
||||
updateStyle(styleName, builder)
|
||||
StyleReference(this, styleName)
|
||||
}
|
||||
|
||||
@@ -41,6 +40,6 @@ public fun <T : Scheme> MutableVision.style(
|
||||
builder: T.() -> Unit,
|
||||
): ReadOnlyProperty<Any?, StyleReference> = ReadOnlyProperty { _, property ->
|
||||
val styleName = styleKey ?: property.name
|
||||
updateStyle(styleName.parseAsName(), spec(builder))
|
||||
setStyle(styleName, spec.invoke(builder).toMeta())
|
||||
StyleReference(this, styleName)
|
||||
}
|
||||
@@ -6,11 +6,14 @@ import space.kscience.dataforge.context.warn
|
||||
import space.kscience.dataforge.meta.*
|
||||
import space.kscience.dataforge.meta.descriptors.Described
|
||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||
import space.kscience.dataforge.meta.descriptors.get
|
||||
import space.kscience.dataforge.misc.DfType
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.asName
|
||||
import space.kscience.dataforge.names.parseAsName
|
||||
import space.kscience.dataforge.names.plus
|
||||
import space.kscience.visionforge.SimpleVisionGroup.Companion.updateProperties
|
||||
import space.kscience.visionforge.Vision.Companion.STYLESHEET_KEY
|
||||
import space.kscience.visionforge.Vision.Companion.TYPE
|
||||
|
||||
/**
|
||||
@@ -45,6 +48,23 @@ public interface Vision : Described {
|
||||
manager?.logger?.warn { "Undispatched event: $event" }
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a property, taking into account inherited properties and styles if necessary
|
||||
*/
|
||||
public fun readProperty(
|
||||
name: Name,
|
||||
inherited: Boolean = isInheritedProperty(name),
|
||||
useStyles: Boolean = isStyledProperty(name),
|
||||
): Meta? {
|
||||
val ownMeta = properties[name]
|
||||
val styleMeta = if (useStyles) getStyleProperty(name) else null
|
||||
val inheritMeta = if (inherited) parent?.readProperty(name, inherited, useStyles) else null
|
||||
val defaultMeta = descriptor?.defaultNode?.get(name)
|
||||
val listOfMeta = listOf(ownMeta, styleMeta, inheritMeta, defaultMeta)
|
||||
|
||||
return if (listOfMeta.all { it == null }) null else Laminate(listOfMeta)
|
||||
}
|
||||
|
||||
public companion object {
|
||||
public const val TYPE: String = "vision"
|
||||
public val STYLE_KEY: Name = "@style".asName()
|
||||
@@ -55,6 +75,23 @@ public interface Vision : Described {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Vision.isInheritedProperty(name: Name): Boolean = descriptor?.get(name)?.inherited ?: false
|
||||
internal fun Vision.isInheritedProperty(name: String): Boolean = descriptor?.get(name)?.inherited ?: false
|
||||
internal fun Vision.isStyledProperty(name: Name): Boolean = descriptor?.get(name)?.usesStyles ?: true
|
||||
internal fun Vision.isStyledProperty(name: String): Boolean = descriptor?.get(name)?.usesStyles ?: true
|
||||
|
||||
public fun Vision.readProperty(
|
||||
name: String,
|
||||
inherited: Boolean = isInheritedProperty(name),
|
||||
useStyles: Boolean = isStyledProperty(name),
|
||||
): Meta? = readProperty(name.parseAsName(), inherited, useStyles)
|
||||
|
||||
|
||||
public fun Vision.readProperties(
|
||||
inherited: Boolean = false,
|
||||
useStyles: Boolean = true,
|
||||
): Meta = readProperty(Name.EMPTY, inherited, useStyles) ?: Meta.EMPTY
|
||||
|
||||
public interface MutableVision : Vision {
|
||||
override val properties: MutableMeta
|
||||
|
||||
@@ -71,8 +108,27 @@ public interface MutableVision : Vision {
|
||||
}
|
||||
} else super.receiveEvent(event)
|
||||
}
|
||||
|
||||
public fun writeProperty(
|
||||
name: Name,
|
||||
inherited: Boolean = isInheritedProperty(name),
|
||||
useStyles: Boolean = isStyledProperty(name),
|
||||
): MutableMeta {
|
||||
|
||||
val styleMeta = if (useStyles) getStyleProperty(name) else null
|
||||
val inheritMeta = if (inherited) parent?.readProperty(name, inherited, useStyles) else null
|
||||
val defaultMeta = descriptor?.defaultNode?.get(name)
|
||||
val listOfMeta = listOf(styleMeta, inheritMeta, defaultMeta)
|
||||
|
||||
return properties.getOrCreate(name).withDefault(Laminate(listOfMeta))
|
||||
}
|
||||
}
|
||||
|
||||
public fun MutableVision.writeProperties(
|
||||
inherited: Boolean = false,
|
||||
useStyles: Boolean = true,
|
||||
): MutableMeta = writeProperty(Name.EMPTY, inherited, useStyles)
|
||||
|
||||
/**
|
||||
* Control visibility of the element
|
||||
*/
|
||||
@@ -84,7 +140,7 @@ public var MutableVision.visible: Boolean?
|
||||
|
||||
|
||||
public val Vision.styleSheet: Meta?
|
||||
get() = properties[Vision.STYLESHEET_KEY]
|
||||
get() = properties[STYLESHEET_KEY]
|
||||
|
||||
/**
|
||||
* List of style names applied to this object. Order matters. Not inherited.
|
||||
@@ -99,7 +155,7 @@ public var MutableVision.styles: List<String>
|
||||
properties[Vision.STYLE_KEY] = value.map { it.asValue() }.asValue()
|
||||
}
|
||||
|
||||
public fun MutableVision.setStyle(styleName: String, style: Meta){
|
||||
public fun MutableVision.setStyle(styleName: String, style: Meta) {
|
||||
properties[Vision.STYLESHEET_KEY + styleName] = style
|
||||
}
|
||||
|
||||
@@ -115,7 +171,8 @@ public fun MutableVision.updateStyle(styleName: String, block: MutableMeta.() ->
|
||||
* The style with given name does not necessary exist at the moment.
|
||||
*/
|
||||
public fun MutableVision.useStyle(styleName: String) {
|
||||
val newStyleList = properties[Vision.STYLE_KEY]?.value?.list?.plus(styleName.asValue()) ?: listOf(styleName.asValue())
|
||||
val newStyleList =
|
||||
properties[Vision.STYLE_KEY]?.value?.list?.plus(styleName.asValue()) ?: listOf(styleName.asValue())
|
||||
properties.setValue(Vision.STYLE_KEY, newStyleList.asValue())
|
||||
}
|
||||
|
||||
@@ -123,7 +180,7 @@ public fun MutableVision.useStyle(styleName: String) {
|
||||
* Resolve a style with given name for given [Vision]. The style is not necessarily applied to this [Vision].
|
||||
*/
|
||||
public fun Vision.getStyle(name: String): Meta? =
|
||||
properties[Vision.STYLESHEET_KEY + name] ?: parent?.getStyle(name)
|
||||
properties[STYLESHEET_KEY + name] ?: parent?.getStyle(name)
|
||||
|
||||
/**
|
||||
* Resolve a property from all styles
|
||||
|
||||
@@ -2,6 +2,7 @@ package space.kscience.visionforge
|
||||
|
||||
import com.benasher44.uuid.uuid4
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.parseAsName
|
||||
|
||||
@DslMarker
|
||||
public annotation class VisionBuilder
|
||||
@@ -14,6 +15,8 @@ public interface VisionContainer<out V : Vision> {
|
||||
public fun getVision(name: Name): V?
|
||||
}
|
||||
|
||||
public fun <V : Vision> VisionContainer<V>.getVision(name: String): V? = getVision(name.parseAsName())
|
||||
|
||||
/**
|
||||
* A container interface with write/replace/delete access to its content.
|
||||
*/
|
||||
@@ -21,7 +24,11 @@ public interface MutableVisionContainer<in V : Vision> {
|
||||
//TODO add documentation
|
||||
public fun setVision(name: Name, vision: V?)
|
||||
|
||||
public companion object{
|
||||
public companion object {
|
||||
public fun generateID(): String = "@vision[${uuid4().leastSignificantBits.toString(16)}]"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun <V : Vision> MutableVisionContainer<V>.setVision(name: String, vision: V?) {
|
||||
setVision(name.parseAsName(), vision)
|
||||
}
|
||||
|
||||
@@ -40,8 +40,10 @@ public interface VisionGroup<out V : Vision> : Vision, VisionContainer<V> {
|
||||
/**
|
||||
* An event that indicates that [VisionGroup] composition is invalidated (not necessarily changed
|
||||
*/
|
||||
public data class VisionGroupCompositionChangedEvent(public val source: VisionGroup<*>, public val name: Name) :
|
||||
VisionEvent
|
||||
public data class VisionGroupCompositionChangedEvent(
|
||||
public val source: VisionContainer<*>,
|
||||
public val name: Name
|
||||
) : VisionEvent
|
||||
|
||||
///**
|
||||
// * An event that indicates that child property value has been invalidated
|
||||
|
||||
@@ -1,165 +0,0 @@
|
||||
package space.kscience.visionforge
|
||||
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.MutableMeta
|
||||
import space.kscience.dataforge.meta.Value
|
||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||
import space.kscience.dataforge.meta.descriptors.get
|
||||
import space.kscience.dataforge.names.*
|
||||
|
||||
private class VisionProperty(
|
||||
val parent: Vision,
|
||||
val nodeName: Name,
|
||||
val inherited: Boolean,
|
||||
val useStyles: Boolean,
|
||||
val default: Meta? = null,
|
||||
) : Meta {
|
||||
|
||||
val descriptor: MetaDescriptor? by lazy { parent.descriptor?.get(nodeName) }
|
||||
|
||||
|
||||
override val items: Map<NameToken, VisionProperty>
|
||||
get() {
|
||||
val metaKeys = parent.properties[nodeName]?.items?.keys ?: emptySet()
|
||||
val descriptorKeys = descriptor?.nodes?.map { NameToken(it.key) } ?: emptySet()
|
||||
val defaultKeys = default?.get(nodeName)?.items?.keys ?: emptySet()
|
||||
return (metaKeys + descriptorKeys + defaultKeys).associateWith {
|
||||
VisionProperty(
|
||||
parent = parent,
|
||||
nodeName = nodeName + it,
|
||||
inherited = inherited,
|
||||
useStyles = useStyles,
|
||||
default = default
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override val value: Value?
|
||||
get() {
|
||||
return parent.getProperty(nodeName, inherited, useStyles).value ?: default?.getValue(nodeName)
|
||||
}
|
||||
|
||||
//TODO remove with DataForge 0.9.1
|
||||
override fun get(name: Name): VisionProperty? {
|
||||
tailrec fun VisionProperty.find(name: Name): VisionProperty? = if (name.isEmpty()) {
|
||||
this
|
||||
} else {
|
||||
items[name.firstOrNull()!!]?.find(name.cutFirst())
|
||||
}
|
||||
|
||||
return find(name)
|
||||
}
|
||||
|
||||
override fun toString(): String = Meta.toString(this)
|
||||
override fun equals(other: Any?): Boolean = Meta.equals(this, other as? Meta)
|
||||
override fun hashCode(): Int = Meta.hashCode(this)
|
||||
}
|
||||
|
||||
internal fun Vision.isInheritedProperty(name: Name): Boolean = descriptor?.get(name)?.inherited ?: false
|
||||
internal fun Vision.isInheritedProperty(name: String): Boolean = descriptor?.get(name)?.inherited ?: false
|
||||
internal fun Vision.isStyledProperty(name: Name): Boolean = descriptor?.get(name)?.usesStyles ?: true
|
||||
internal fun Vision.isStyledProperty(name: String): Boolean = descriptor?.get(name)?.usesStyles ?: true
|
||||
|
||||
|
||||
/**
|
||||
* Read a property, taking into account inherited properties and styles if necessary
|
||||
*/
|
||||
public fun Vision.getProperty(
|
||||
name: Name,
|
||||
inherited: Boolean = isInheritedProperty(name),
|
||||
useStyles: Boolean = isStyledProperty(name),
|
||||
): Meta = VisionProperty(this, name, inherited, useStyles)
|
||||
|
||||
public fun Vision.getProperty(
|
||||
name: String,
|
||||
inherited: Boolean = isInheritedProperty(name),
|
||||
useStyles: Boolean = isStyledProperty(name),
|
||||
): Meta = getProperty(name.parseAsName(), inherited, useStyles)
|
||||
|
||||
public fun Vision.properties(
|
||||
inherited: Boolean = false,
|
||||
useStyles: Boolean = true,
|
||||
): Meta = getProperty(Name.EMPTY,inherited, useStyles)
|
||||
|
||||
|
||||
internal class MutableVisionProperty(
|
||||
val parent: MutableVision,
|
||||
val nodeName: Name,
|
||||
val inherited: Boolean,
|
||||
val useStyles: Boolean,
|
||||
val default: Meta? = null,
|
||||
) : MutableMeta {
|
||||
|
||||
|
||||
val descriptor: MetaDescriptor? by lazy { parent.descriptor?.get(nodeName) }
|
||||
|
||||
|
||||
override val items: Map<NameToken, MutableVisionProperty>
|
||||
get() {
|
||||
val metaKeys = parent.properties[nodeName]?.items?.keys ?: emptySet()
|
||||
val descriptorKeys = descriptor?.nodes?.map { NameToken(it.key) } ?: emptySet()
|
||||
val defaultKeys = default?.get(nodeName)?.items?.keys ?: emptySet()
|
||||
return (metaKeys + descriptorKeys + defaultKeys).associateWith {
|
||||
MutableVisionProperty(
|
||||
parent = parent,
|
||||
nodeName = nodeName + it,
|
||||
inherited = inherited,
|
||||
useStyles = useStyles,
|
||||
default = default
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override var value: Value?
|
||||
get() {
|
||||
return parent.getProperty(nodeName, inherited, useStyles).value ?: default?.getValue(nodeName)
|
||||
}
|
||||
set(value) {
|
||||
parent.properties.setValue(nodeName, value)
|
||||
}
|
||||
|
||||
//TODO remove with DataForge 0.9.1
|
||||
override fun get(name: Name): MutableVisionProperty? {
|
||||
tailrec fun MutableVisionProperty.find(name: Name): MutableVisionProperty? = if (name.isEmpty()) {
|
||||
this
|
||||
} else {
|
||||
items[name.firstOrNull()!!]?.find(name.cutFirst())
|
||||
}
|
||||
|
||||
return find(name)
|
||||
}
|
||||
|
||||
|
||||
override fun getOrCreate(name: Name): MutableVisionProperty = MutableVisionProperty(
|
||||
parent = parent,
|
||||
nodeName = nodeName + name,
|
||||
inherited = inherited,
|
||||
useStyles = useStyles,
|
||||
default = default
|
||||
)
|
||||
|
||||
override fun set(name: Name, node: Meta?) {
|
||||
parent.properties[nodeName + name] = node
|
||||
}
|
||||
|
||||
override fun toString(): String = Meta.toString(this)
|
||||
override fun equals(other: Any?): Boolean = Meta.equals(this, other as? Meta)
|
||||
override fun hashCode(): Int = Meta.hashCode(this)
|
||||
}
|
||||
|
||||
public fun MutableVision.getProperty(
|
||||
name: Name,
|
||||
inherited: Boolean = isInheritedProperty(name),
|
||||
useStyles: Boolean = isStyledProperty(name),
|
||||
): MutableMeta = MutableVisionProperty(this, name, inherited, useStyles)
|
||||
|
||||
public fun MutableVision.getProperty(
|
||||
name: String,
|
||||
inherited: Boolean = isInheritedProperty(name),
|
||||
useStyles: Boolean = isStyledProperty(name),
|
||||
): MutableMeta = getProperty(name.parseAsName(), inherited, useStyles)
|
||||
|
||||
public fun MutableVision.properties(
|
||||
inherited: Boolean = false,
|
||||
useStyles: Boolean = true,
|
||||
): MutableMeta = getProperty(Name.EMPTY,inherited, useStyles)
|
||||
@@ -22,7 +22,7 @@ public interface VisionOfHtml : MutableVision {
|
||||
* Html class strings for this instance. Does not use vision inheritance, but uses styles
|
||||
*/
|
||||
public var classes: Set<String>
|
||||
get() = getProperty(::classes.name, false, true).stringList?.toSet() ?: emptySet()
|
||||
get() = readProperty(::classes.name, false, true).stringList?.toSet() ?: emptySet()
|
||||
set(value) {
|
||||
properties[::classes.name] = value.map { it.asValue() }
|
||||
}
|
||||
@@ -31,7 +31,7 @@ public interface VisionOfHtml : MutableVision {
|
||||
* A custom style string
|
||||
*/
|
||||
public var styleString: String?
|
||||
get() = getProperty(::styleString.name,false,true).string
|
||||
get() = readProperty(::styleString.name,false,true).string
|
||||
set(value){
|
||||
properties[::styleString.name] = value?.asValue()
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ public fun Vision.flowProperty(
|
||||
useStyles: Boolean = isStyledProperty(propertyName),
|
||||
): Flow<Meta> = flow {
|
||||
//Pass initial value.
|
||||
emit(getProperty(propertyName, inherited, useStyles))
|
||||
readProperty(propertyName, inherited, useStyles)?.let { emit(it) }
|
||||
|
||||
val combinedFlow: Flow<VisionEvent> = if (inherited) {
|
||||
inheritedEventFlow()
|
||||
@@ -33,7 +33,7 @@ public fun Vision.flowProperty(
|
||||
|
||||
combinedFlow.filterIsInstance<VisionPropertyChangedEvent>().collect { event ->
|
||||
if (event.property == propertyName || (useStyles && event.property == Vision.STYLE_KEY)) {
|
||||
emit(event.source.getProperty(event.property, inherited, useStyles))
|
||||
readProperty(event.property, inherited, useStyles)?.let { emit(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,7 +73,7 @@ public fun Vision.useProperty(
|
||||
): Job = scope.launch {
|
||||
//Pass initial value synchronously
|
||||
|
||||
callback(getProperty(propertyName, inherited, useStyles))
|
||||
readProperty(propertyName, inherited, useStyles)?.let { callback(it) }
|
||||
|
||||
val combinedFlow = if (inherited) {
|
||||
inheritedEventFlow()
|
||||
@@ -81,9 +81,9 @@ public fun Vision.useProperty(
|
||||
eventFlow
|
||||
}
|
||||
|
||||
combinedFlow.filterIsInstance<VisionPropertyChangedEvent>().onEach {
|
||||
if (it.property == propertyName || (useStyles && it.property == Vision.STYLE_KEY)) {
|
||||
callback(getProperty(propertyName, inherited, useStyles))
|
||||
combinedFlow.filterIsInstance<VisionPropertyChangedEvent>().onEach { event ->
|
||||
if (event.property == propertyName || (useStyles && event.property == Vision.STYLE_KEY)) {
|
||||
readProperty(event.property, inherited, useStyles)?.let { callback(it) }
|
||||
}
|
||||
}.collect()
|
||||
}
|
||||
|
||||
@@ -59,11 +59,11 @@ internal class VisionPropertyTest {
|
||||
@Test
|
||||
fun testChildrenPropertyPropagation() = runTest(timeout = 200.milliseconds) {
|
||||
val group = Global.request(VisionManager).group {
|
||||
properties {
|
||||
writeProperties {
|
||||
"test" put 11
|
||||
}
|
||||
group("child") {
|
||||
properties {
|
||||
writeProperties {
|
||||
"test" put 22
|
||||
}
|
||||
}
|
||||
@@ -96,12 +96,12 @@ internal class VisionPropertyTest {
|
||||
fun testChildrenPropertyFlow() = runTest(timeout = 500.milliseconds) {
|
||||
val group = Global.request(VisionManager).group {
|
||||
|
||||
properties {
|
||||
writeProperties {
|
||||
"test" put 11
|
||||
}
|
||||
|
||||
group("child") {
|
||||
properties {
|
||||
writeProperties {
|
||||
"test" put 22
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,12 +22,12 @@ internal class PropertyFlowTest {
|
||||
fun testChildrenPropertyFlow() = runBlocking{
|
||||
val group = Global.request(VisionManager).group {
|
||||
|
||||
properties {
|
||||
writeProperties {
|
||||
"test" put 11
|
||||
}
|
||||
|
||||
group("child") {
|
||||
properties {
|
||||
writeProperties {
|
||||
"test" put 22
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,7 +334,8 @@ private class GdmlLoader(val settings: GdmlLoaderOptions) {
|
||||
?: error("Volume with ref ${divisionVolume.volumeref.ref} could not be resolved")
|
||||
|
||||
//TODO add divisions
|
||||
items.static(volume(root, volume))
|
||||
setSolid()
|
||||
solids.static(volume(root, volume))
|
||||
}
|
||||
|
||||
private fun volume(
|
||||
@@ -368,18 +369,16 @@ private class GdmlLoader(val settings: GdmlLoaderOptions) {
|
||||
Solid.ROTATION_ORDER_KEY put RotationOrder.ZXY
|
||||
}
|
||||
|
||||
rootSolid.useStyle(rootStyle, false)
|
||||
rootSolid.useStyle(rootStyle)
|
||||
|
||||
rootSolid.prototypes {
|
||||
templates.items.forEach { (token, item) ->
|
||||
templates.solids.forEach { (token, item) ->
|
||||
item.parent = null
|
||||
setVision(token.asName(), item)
|
||||
}
|
||||
}
|
||||
settings.styleCache.forEach {
|
||||
rootSolid.styleSheet {
|
||||
define(it.key.toString(), it.value)
|
||||
}
|
||||
rootSolid.setStyle(it.key.toString(), it.value)
|
||||
}
|
||||
return rootSolid
|
||||
}
|
||||
@@ -389,7 +388,7 @@ private class GdmlLoader(val settings: GdmlLoaderOptions) {
|
||||
public fun Gdml.toVision(block: GdmlLoaderOptions.() -> Unit = {}): SolidGroup {
|
||||
val settings = GdmlLoaderOptions().apply(block)
|
||||
return GdmlLoader(settings).transform(this).also {
|
||||
it.items["light"] = settings.light
|
||||
it.setVision("light", settings.light)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,7 +398,7 @@ public fun Gdml.toVision(block: GdmlLoaderOptions.() -> Unit = {}): SolidGroup {
|
||||
public fun SolidGroup.gdml(gdml: Gdml, key: String? = null, transformer: GdmlLoaderOptions.() -> Unit = {}) {
|
||||
val vision = gdml.toVision(transformer)
|
||||
//println(Visual3DPlugin.json.stringify(VisualGroup3D.serializer(), visual))
|
||||
items.setChild(key, vision)
|
||||
setSolid(key, vision)
|
||||
}
|
||||
|
||||
@VisionBuilder
|
||||
|
||||
@@ -12,7 +12,6 @@ import space.kscience.visionforge.AbstractVision
|
||||
import space.kscience.visionforge.Vision
|
||||
import space.kscience.visionforge.VisionBuilder
|
||||
import space.kscience.visionforge.html.VisionOutput
|
||||
import space.kscience.visionforge.root
|
||||
|
||||
@Serializable
|
||||
@SerialName("vision.markup")
|
||||
@@ -22,7 +21,7 @@ public class VisionOfMarkup(
|
||||
|
||||
//TODO add templates
|
||||
|
||||
public var content: String? by properties.root().string(CONTENT_PROPERTY_KEY)
|
||||
public var content: String? by properties.string(CONTENT_PROPERTY_KEY)
|
||||
|
||||
public companion object {
|
||||
public val CONTENT_PROPERTY_KEY: Name = "content".asName()
|
||||
|
||||
@@ -28,7 +28,7 @@ public class ColorAccessor(
|
||||
public fun MutableVision.colorProperty(
|
||||
propertyName: Name? = null,
|
||||
): ReadOnlyProperty<Vision, ColorAccessor> = ReadOnlyProperty { _, property ->
|
||||
ColorAccessor(properties(inherited = true), propertyName ?: property.name.asName())
|
||||
ColorAccessor(writeProperties(inherited = true), propertyName ?: property.name.asName())
|
||||
}
|
||||
|
||||
public var ColorAccessor.string: String?
|
||||
|
||||
@@ -6,7 +6,6 @@ import space.kscience.dataforge.meta.isEmpty
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.visionforge.MutableVisionContainer
|
||||
import space.kscience.visionforge.VisionBuilder
|
||||
import space.kscience.visionforge.static
|
||||
|
||||
public enum class CompositeType {
|
||||
GROUP, // Dumb sum of meshes
|
||||
@@ -33,15 +32,15 @@ public inline fun MutableVisionContainer<Solid>.composite(
|
||||
@VisionBuilder builder: SolidGroup.() -> Unit,
|
||||
): Composite {
|
||||
val group = SolidGroup().apply(builder)
|
||||
val children = group.items.values.toList()
|
||||
val children = group.solids.values.toList()
|
||||
if (children.size != 2) {
|
||||
error("Composite requires exactly two children, but found ${children.size}")
|
||||
}
|
||||
val res = Composite(type, children[0], children[1])
|
||||
|
||||
res.properties[Name.EMPTY] = group.properties.own
|
||||
res.properties[Name.EMPTY] = group.properties
|
||||
|
||||
setVision(name, res)
|
||||
setVision(SolidGroup.inferNameFor(name, res), res)
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -55,19 +54,19 @@ public fun SolidGroup.smartComposite(
|
||||
@VisionBuilder builder: SolidGroup.() -> Unit,
|
||||
): Solid = if (type == CompositeType.GROUP) {
|
||||
val group = SolidGroup().apply(builder)
|
||||
if (name == null && group.properties.own.isEmpty()) {
|
||||
if (name == null && group.properties.isEmpty()) {
|
||||
//append directly to group if no properties are defined
|
||||
group.items.forEach { (_, value) ->
|
||||
group.solids.forEach { (_, value) ->
|
||||
value.parent = null
|
||||
items.static(value)
|
||||
static(value)
|
||||
}
|
||||
this
|
||||
} else {
|
||||
items.setChild(name, group)
|
||||
setVision(SolidGroup.inferNameFor(name, group), group)
|
||||
group
|
||||
}
|
||||
} else {
|
||||
items.composite(type, name, builder)
|
||||
composite(type, name, builder)
|
||||
}
|
||||
|
||||
@VisionBuilder
|
||||
|
||||
@@ -80,7 +80,9 @@ public inline fun MutableVisionContainer<Solid>.cylinder(
|
||||
r.toFloat(),
|
||||
height.toFloat(),
|
||||
r.toFloat()
|
||||
).apply(block).also { setSolid(name, it) }
|
||||
).apply(block).also {
|
||||
setVision(SolidGroup.inferNameFor(name, it), it)
|
||||
}
|
||||
|
||||
@VisionBuilder
|
||||
public inline fun MutableVisionContainer<Solid>.cone(
|
||||
@@ -97,4 +99,6 @@ public inline fun MutableVisionContainer<Solid>.cone(
|
||||
topRadius = upperRadius.toFloat(),
|
||||
phiStart = startAngle.toFloat(),
|
||||
phi = angle.toFloat()
|
||||
).apply(block).also { setSolid(name, it) }
|
||||
).apply(block).also {
|
||||
setVision(SolidGroup.inferNameFor(name, it), it)
|
||||
}
|
||||
@@ -136,7 +136,9 @@ public inline fun MutableVisionContainer<Solid>.tube(
|
||||
topInnerRadius = innerRadius.toFloat(),
|
||||
phiStart = startAngle.toFloat(),
|
||||
phi = angle.toFloat()
|
||||
).apply(block).also { setSolid(name, it) }
|
||||
).apply(block).also {
|
||||
setVision(SolidGroup.inferNameFor(name, it), it)
|
||||
}
|
||||
|
||||
@VisionBuilder
|
||||
public inline fun MutableVisionContainer<Solid>.coneSurface(
|
||||
@@ -157,4 +159,6 @@ public inline fun MutableVisionContainer<Solid>.coneSurface(
|
||||
topInnerRadius = topInnerRadius.toFloat(),
|
||||
phiStart = startAngle.toFloat(),
|
||||
phi = angle.toFloat()
|
||||
).apply(block).also { setSolid(name, it) }
|
||||
).apply(block).also {
|
||||
setVision(SolidGroup.inferNameFor(name, it), it)
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package space.kscience.visionforge.solid
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import space.kscience.dataforge.names.parseAsName
|
||||
import space.kscience.visionforge.MutableVisionContainer
|
||||
|
||||
/**
|
||||
@@ -14,7 +15,9 @@ public class Convex(public val points: List<Float32Vector3D>) : SolidBase<Convex
|
||||
public inline fun MutableVisionContainer<Solid>.convex(
|
||||
name: String? = null,
|
||||
action: ConvexBuilder.() -> Unit = {},
|
||||
): Convex = ConvexBuilder().apply(action).build().also { setSolid(name, it) }
|
||||
): Convex = ConvexBuilder().apply(action).build().also {
|
||||
setVision(name?.parseAsName() ?: SolidGroup.staticNameFor(it), it)
|
||||
}
|
||||
|
||||
public class ConvexBuilder {
|
||||
private val points = ArrayList<Float32Vector3D>()
|
||||
|
||||
@@ -164,4 +164,6 @@ public inline fun MutableVisionContainer<Solid>.cutTube(
|
||||
phi = angle.toFloat(),
|
||||
nTop = topNormal,
|
||||
nBottom = bottomNormal
|
||||
).apply(block).also { setSolid(name, it) }
|
||||
).apply(block).also {
|
||||
setVision(SolidGroup.inferNameFor(name, it), it)
|
||||
}
|
||||
|
||||
@@ -104,4 +104,6 @@ public class Extruded(
|
||||
public fun MutableVisionContainer<Solid>.extruded(
|
||||
name: String? = null,
|
||||
action: Extruded.Builder.() -> Unit = {},
|
||||
): Extruded = Extruded.Builder().apply(action).build().also { setSolid(name, it) }
|
||||
): Extruded = Extruded.Builder().apply(action).build().also {
|
||||
setVision(SolidGroup.inferNameFor(name, it), it)
|
||||
}
|
||||
@@ -57,7 +57,9 @@ public inline fun MutableVisionContainer<Solid>.box(
|
||||
zSize: Number,
|
||||
name: String? = null,
|
||||
block: Box.() -> Unit = {},
|
||||
): Box = Box(xSize.toFloat(), ySize.toFloat(), zSize.toFloat()).apply(block).also { setSolid(name, it) }
|
||||
): Box = Box(xSize.toFloat(), ySize.toFloat(), zSize.toFloat()).apply(block).also {
|
||||
setVision(SolidGroup.inferNameFor(name, it), it)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
@SerialName("solid.hexagon")
|
||||
@@ -84,4 +86,6 @@ public inline fun MutableVisionContainer<Solid>.hexagon(
|
||||
node8: Float32Vector3D,
|
||||
name: String? = null,
|
||||
action: Hexagon.() -> Unit = {},
|
||||
): Hexagon = GenericHexagon(node1, node2, node3, node4, node5, node6, node7, node8).apply(action).also { setSolid(name, it) }
|
||||
): Hexagon = GenericHexagon(node1, node2, node3, node4, node5, node6, node7, node8).apply(action).also {
|
||||
setVision(SolidGroup.inferNameFor(name, it), it)
|
||||
}
|
||||
@@ -16,7 +16,7 @@ public abstract class LightSource : MiscSolid() {
|
||||
override val descriptor: MetaDescriptor get() = LightSource.descriptor
|
||||
|
||||
public val color: ColorAccessor by colorProperty(SolidMaterial.COLOR_KEY)
|
||||
public var intensity: Number by properties.root(includeStyles = false).number(INTENSITY_KEY) { 1.0 }
|
||||
public var intensity: Number by properties.number(INTENSITY_KEY) { 1.0 }
|
||||
|
||||
public companion object {
|
||||
public val INTENSITY_KEY: Name = "intensity".asName()
|
||||
@@ -55,7 +55,9 @@ public class AmbientLightSource : LightSource()
|
||||
public fun MutableVisionContainer<Solid>.ambientLight(
|
||||
name: String? = "@ambientLight",
|
||||
block: AmbientLightSource.() -> Unit = {},
|
||||
): AmbientLightSource = AmbientLightSource().apply(block).also { setSolid(name, it) }
|
||||
): AmbientLightSource = AmbientLightSource().apply(block).also {
|
||||
setVision(SolidGroup.inferNameFor(name, it), it)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
@SerialName("solid.light.point")
|
||||
|
||||
@@ -3,19 +3,16 @@ package space.kscience.visionforge.solid
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import space.kscience.dataforge.meta.number
|
||||
import space.kscience.dataforge.names.parseAsName
|
||||
import space.kscience.visionforge.MutableVisionContainer
|
||||
import space.kscience.visionforge.VisionBuilder
|
||||
import space.kscience.visionforge.properties
|
||||
|
||||
@Serializable
|
||||
@SerialName("solid.line")
|
||||
public class PolyLine(public val points: List<Float32Vector3D>) : SolidBase<PolyLine>() {
|
||||
|
||||
//var lineType by string()
|
||||
public var thickness: Number by properties(
|
||||
inherited = false,
|
||||
useStyles = true
|
||||
).number { DEFAULT_THICKNESS }
|
||||
public var thickness: Number by properties.number { DEFAULT_THICKNESS }
|
||||
|
||||
public companion object {
|
||||
public const val DEFAULT_THICKNESS: Double = 1.0
|
||||
@@ -27,4 +24,6 @@ public fun MutableVisionContainer<Solid>.polyline(
|
||||
vararg points: Float32Vector3D,
|
||||
name: String? = null,
|
||||
action: PolyLine.() -> Unit = {},
|
||||
): PolyLine = PolyLine(points.toList()).apply(action).also { setSolid(name, it) }
|
||||
): PolyLine = PolyLine(points.toList()).apply(action).also {
|
||||
setVision(name?.parseAsName() ?: SolidGroup.staticNameFor(it), it)
|
||||
}
|
||||
@@ -11,8 +11,11 @@ import space.kscience.dataforge.names.plus
|
||||
import space.kscience.kmath.complex.Quaternion
|
||||
import space.kscience.kmath.complex.QuaternionField
|
||||
import space.kscience.kmath.geometry.*
|
||||
import space.kscience.visionforge.*
|
||||
import space.kscience.visionforge.MutableVision
|
||||
import space.kscience.visionforge.Vision
|
||||
import space.kscience.visionforge.Vision.Companion.VISIBLE_KEY
|
||||
import space.kscience.visionforge.hide
|
||||
import space.kscience.visionforge.inherited
|
||||
import space.kscience.visionforge.solid.Solid.Companion.DETAIL_KEY
|
||||
import space.kscience.visionforge.solid.Solid.Companion.IGNORE_KEY
|
||||
import space.kscience.visionforge.solid.Solid.Companion.LAYER_KEY
|
||||
@@ -116,7 +119,7 @@ public interface Solid : MutableVision {
|
||||
* Get the layer number this solid belongs to. Return 0 if layer is not defined.
|
||||
*/
|
||||
public var Solid.layer: Int
|
||||
get() = getProperty(LAYER_KEY, inherited = true).int ?: 0
|
||||
get() = readProperty(LAYER_KEY, inherited = true).int ?: 0
|
||||
set(value) {
|
||||
properties[LAYER_KEY] = value
|
||||
}
|
||||
@@ -135,7 +138,7 @@ public var Solid.rotationOrder: RotationOrder
|
||||
* Preferred number of polygons for displaying the object. If not defined, uses shape or renderer default. Not inherited
|
||||
*/
|
||||
public var Solid.detail: Int?
|
||||
get() = getProperty(DETAIL_KEY, inherited = false).int
|
||||
get() = readProperty(DETAIL_KEY, inherited = false).int
|
||||
set(value) = properties.setValue(DETAIL_KEY, value?.asValue())
|
||||
|
||||
/**
|
||||
@@ -143,7 +146,7 @@ public var Solid.detail: Int?
|
||||
* Property is not inherited.
|
||||
*/
|
||||
public var MutableVision.ignore: Boolean?
|
||||
get() = getProperty(IGNORE_KEY, inherited = false, useStyles = false).boolean
|
||||
get() = readProperty(IGNORE_KEY, inherited = false, useStyles = false).boolean
|
||||
set(value) = properties.setValue(IGNORE_KEY, value?.asValue())
|
||||
|
||||
//var VisualObject.selected: Boolean?
|
||||
|
||||
@@ -15,7 +15,7 @@ public interface PrototypeHolder {
|
||||
* Build or update the prototype tree
|
||||
*/
|
||||
@VisionBuilder
|
||||
public fun prototypes(builder: MutableVisionGroup<Solid>.() -> Unit)
|
||||
public fun prototypes(builder: SolidGroup.() -> Unit)
|
||||
|
||||
/**
|
||||
* Resolve a prototype from this container. Should never return a ref.
|
||||
@@ -25,45 +25,40 @@ public interface PrototypeHolder {
|
||||
|
||||
private fun MutableMap<Name, Solid>.fillFrom(prefix: Name, solids: Map<NameToken, Solid>) {
|
||||
solids.forEach { (token, solid) ->
|
||||
if(!token.body.startsWith("@")) {
|
||||
put(prefix + token, solid)
|
||||
if (solid is SolidGroup) {
|
||||
fillFrom(prefix + token, solid.solids)
|
||||
}
|
||||
put(prefix + token, solid)
|
||||
if (solid is SolidGroup) {
|
||||
fillFrom(prefix + token, solid.solids)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface SolidContainer : VisionContainer<Solid> {
|
||||
|
||||
public val solids: Map<NameToken, Solid>
|
||||
|
||||
public operator fun get(token: NameToken): Solid? = solids[token]
|
||||
|
||||
override fun getVision(name: Name): Solid? = when (name.length) {
|
||||
0 -> this as? Solid
|
||||
1 -> get(name.first())
|
||||
else -> (get(name.first()) as? SolidContainer)?.get(name.cutFirst())
|
||||
}
|
||||
}
|
||||
|
||||
public operator fun SolidContainer.get(name: Name): Solid? = getVision(name)
|
||||
|
||||
/**
|
||||
* A [Solid] group with additional accessor methods
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName("group.solid")
|
||||
public class SolidGroup : AbstractVision(), Solid, PrototypeHolder, MutableVisionGroup<Solid> {
|
||||
public class SolidGroup : AbstractVision(), Solid, PrototypeHolder, SolidContainer, MutableVisionContainer<Solid> {
|
||||
|
||||
private val _solids = LinkedHashMap<NameToken, Solid>()
|
||||
|
||||
public val solids: Map<NameToken, Solid> get() = _solids
|
||||
override val solids: Map<NameToken, Solid> get() = _solids
|
||||
|
||||
/**
|
||||
* All items in this [SolidGroup] excluding invisible items (starting with @)
|
||||
*/
|
||||
override val items: Map<Name, Solid> get() = buildMap { fillFrom(Name.EMPTY, solids) }
|
||||
|
||||
/**
|
||||
* Get a child solid with given relative [name] if it exists
|
||||
*/
|
||||
public operator fun get(name: Name): Solid? = items[name] as? Solid
|
||||
|
||||
private var prototypes: SolidGroup?
|
||||
get() = _solids[PROTOTYPES_TOKEN] as? SolidGroup
|
||||
set(value) {
|
||||
if (value == null) {
|
||||
_solids.remove(PROTOTYPES_TOKEN)
|
||||
} else {
|
||||
_solids[PROTOTYPES_TOKEN] = value
|
||||
}
|
||||
}
|
||||
private var prototypes: SolidGroup? = null
|
||||
|
||||
override val descriptor: MetaDescriptor get() = Solid.descriptor
|
||||
|
||||
@@ -77,14 +72,11 @@ public class SolidGroup : AbstractVision(), Solid, PrototypeHolder, MutableVisio
|
||||
/**
|
||||
* Create or edit prototype node as a group
|
||||
*/
|
||||
override fun prototypes(builder: MutableVisionGroup<Solid>.() -> Unit): Unit {
|
||||
(prototypes ?: SolidGroup().also { prototypes = it }).apply(builder)
|
||||
}
|
||||
|
||||
override fun getVision(name: Name): Solid? = when (name.length) {
|
||||
0 -> this
|
||||
1 -> solids[name.first()]
|
||||
else -> (solids[name.first()] as? SolidGroup)?.getVision(name.cutFirst())
|
||||
override fun prototypes(builder: SolidGroup.() -> Unit): Unit {
|
||||
(prototypes ?: SolidGroup().also {
|
||||
prototypes = it
|
||||
parent = this
|
||||
}).apply(builder)
|
||||
}
|
||||
|
||||
private fun getOrCreateGroup(name: Name): SolidGroup = when (name.length) {
|
||||
@@ -105,18 +97,18 @@ public class SolidGroup : AbstractVision(), Solid, PrototypeHolder, MutableVisio
|
||||
override fun setVision(name: Name, vision: Solid?) {
|
||||
if (name.isEmpty()) error("Can't set vision with empty name")
|
||||
if (vision == null) {
|
||||
getVision(name.cutLast())
|
||||
(get(name.cutLast()) as SolidGroup)._solids.remove(name.last())
|
||||
} else {
|
||||
val parent = getOrCreateGroup(name.cutLast())
|
||||
vision.parent = parent
|
||||
parent._solids[name.last()] = vision
|
||||
}
|
||||
emitEvent(VisionGroupCompositionChangedEvent(this, name))
|
||||
}
|
||||
|
||||
override fun convertVisionOrNull(vision: Vision): Solid? = vision as? Solid
|
||||
|
||||
public companion object {
|
||||
public val PROTOTYPES_TOKEN: NameToken = NameToken("@prototypes")
|
||||
public fun staticNameFor(vision: Vision): Name = NameToken("@static", vision.hashCode().toString(16)).asName()
|
||||
public fun inferNameFor(name: String?, vision: Vision): Name = name?.parseAsName() ?: staticNameFor(vision)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +134,9 @@ public fun MutableVisionContainer<Solid>.setSolid(name: String?, vision: Solid?)
|
||||
public inline fun MutableVisionContainer<Solid>.solidGroup(
|
||||
name: Name? = null,
|
||||
builder: SolidGroup.() -> Unit = {},
|
||||
): SolidGroup = SolidGroup().also { setSolid(name, it) }.apply(builder)
|
||||
): SolidGroup = SolidGroup().also {
|
||||
setVision(name ?: SolidGroup.staticNameFor(it), it)
|
||||
}.apply(builder)
|
||||
//root first, update later
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,4 +20,6 @@ public fun MutableVisionContainer<Solid>.label(
|
||||
fontFamily: String = "Arial",
|
||||
name: String? = null,
|
||||
action: SolidLabel.() -> Unit = {},
|
||||
): SolidLabel = SolidLabel(text, fontSize.toDouble(), fontFamily).apply(action).also { setSolid(name, it) }
|
||||
): SolidLabel = SolidLabel(text, fontSize.toDouble(), fontFamily).apply(action).also {
|
||||
setVision(SolidGroup.inferNameFor(name, it), it)
|
||||
}
|
||||
@@ -111,7 +111,7 @@ public class SolidMaterial : Scheme() {
|
||||
}
|
||||
|
||||
public val Solid.color: ColorAccessor
|
||||
get() = ColorAccessor(properties(inherited = true), MATERIAL_COLOR_KEY)
|
||||
get() = ColorAccessor(writeProperties(inherited = true), MATERIAL_COLOR_KEY)
|
||||
|
||||
public var Solid.material: SolidMaterial?
|
||||
get() = properties[MATERIAL_KEY]?.let { SolidMaterial.read(it)}
|
||||
@@ -119,11 +119,11 @@ public var Solid.material: SolidMaterial?
|
||||
|
||||
@VisionBuilder
|
||||
public fun Solid.material(builder: SolidMaterial.() -> Unit) {
|
||||
properties[MATERIAL_KEY].updateWith(SolidMaterial, builder)
|
||||
writeProperty(MATERIAL_KEY, inherited = false, useStyles = false).updateWith(SolidMaterial, builder)
|
||||
}
|
||||
|
||||
public var Solid.opacity: Number?
|
||||
get() = getProperty(MATERIAL_OPACITY_KEY, inherited = true).number
|
||||
get() = readProperty(MATERIAL_OPACITY_KEY, inherited = true).number
|
||||
set(value) {
|
||||
properties.setValue(MATERIAL_OPACITY_KEY, value?.asValue())
|
||||
}
|
||||
@@ -132,5 +132,5 @@ public var Solid.opacity: Number?
|
||||
@VisionBuilder
|
||||
public fun Solid.edges(enabled: Boolean = true, block: SolidMaterial.() -> Unit = {}) {
|
||||
properties[SolidMaterial.EDGES_ENABLED_KEY] = enabled
|
||||
SolidMaterial.write(properties[SolidMaterial.EDGES_MATERIAL_KEY]).apply(block)
|
||||
SolidMaterial.write(writeProperty(SolidMaterial.EDGES_MATERIAL_KEY)).apply(block)
|
||||
}
|
||||
@@ -1,10 +1,16 @@
|
||||
package space.kscience.visionforge.solid
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.serialization.*
|
||||
import space.kscience.dataforge.meta.*
|
||||
import kotlinx.coroutines.flow.filterIsInstance
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.Transient
|
||||
import space.kscience.dataforge.meta.Laminate
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.MutableMeta
|
||||
import space.kscience.dataforge.meta.MutableMetaProxy
|
||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||
import space.kscience.dataforge.names.*
|
||||
import space.kscience.visionforge.*
|
||||
@@ -28,7 +34,7 @@ public val Vision.prototype: Solid
|
||||
@SerialName("solid.ref")
|
||||
public class SolidReference(
|
||||
@SerialName("prototype") public val prototypeName: Name,
|
||||
) : AbstractVision(), VisionGroup<Solid>, Solid {
|
||||
) : AbstractVision(), Solid, SolidContainer {
|
||||
|
||||
@Transient
|
||||
override var parent: Vision? = null
|
||||
@@ -43,17 +49,48 @@ public class SolidReference(
|
||||
(parent as? PrototypeHolder)?.getPrototype(prototypeName)
|
||||
?: error("Prototype with name $prototypeName not found")
|
||||
}
|
||||
|
||||
override val descriptor: MetaDescriptor get() = prototype.descriptor
|
||||
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override val items: Map<Name, Solid> = (prototype as? VisionGroup<Solid>)?.items?.mapValues { (key, solid)->
|
||||
SolidReferenceChild(this@SolidReference, this@SolidReference, key)
|
||||
} ?: emptyMap()
|
||||
override val solids: Map<NameToken, Solid>
|
||||
get() = (prototype as? SolidContainer)?.solids?.mapValues { (key, _) ->
|
||||
SolidReferenceChild(this@SolidReference, this@SolidReference, key.asName())
|
||||
} ?: emptyMap()
|
||||
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun getVision(name: Name): Solid? = (prototype as? VisionGroup<Solid>)?.getVision(name)
|
||||
override fun getVision(name: Name): Solid? = (prototype as? SolidContainer)?.getVision(name)
|
||||
|
||||
|
||||
override fun readProperty(
|
||||
name: Name,
|
||||
inherited: Boolean,
|
||||
useStyles: Boolean
|
||||
): Meta? {
|
||||
val listOfMeta = buildList {
|
||||
//1. resolve own properties
|
||||
add(properties[name])
|
||||
//2. Resolve prototype own properties
|
||||
add(prototype.properties[name])
|
||||
|
||||
if (useStyles) {
|
||||
//3. own styles
|
||||
add(getStyleProperty(name))
|
||||
//4. prototype styles
|
||||
add(prototype.getStyleProperty(name))
|
||||
}
|
||||
|
||||
if (inherited) {
|
||||
//5. own inheritance
|
||||
add(parent?.readProperty(name, inherited, useStyles))
|
||||
//6. prototype inheritance
|
||||
add(prototype.parent?.readProperty(name, inherited, useStyles))
|
||||
}
|
||||
|
||||
add(descriptor.defaultNode[name])
|
||||
}
|
||||
|
||||
return if (listOfMeta.all { it == null }) null else Laminate(listOfMeta)
|
||||
}
|
||||
|
||||
//
|
||||
// override val properties: MutableVisionProperties by lazy {
|
||||
@@ -147,54 +184,89 @@ private class SolidReferenceChild(
|
||||
val owner: SolidReference,
|
||||
override var parent: Vision?,
|
||||
val childName: Name,
|
||||
) : Solid, VisionGroup {
|
||||
) : Solid, SolidContainer {
|
||||
|
||||
private val childToken = childToken(childName)
|
||||
|
||||
val prototype: Solid
|
||||
get() = owner.prototype.children?.getChild(childName) as? Solid
|
||||
get() = (owner.prototype as SolidContainer)[childName]
|
||||
?: error("Prototype with name $childName not found")
|
||||
|
||||
override val descriptor: MetaDescriptor get() = prototype.descriptor
|
||||
|
||||
@Transient
|
||||
override val properties: MutableVisionProperties = object : MutableVisionProperties {
|
||||
override val descriptor: MetaDescriptor get() = this@SolidReferenceChild.descriptor
|
||||
|
||||
override val own: MutableMeta by lazy { owner.properties[childToken(childName).asName()] }
|
||||
|
||||
override fun getValue(
|
||||
name: Name,
|
||||
inherit: Boolean?,
|
||||
includeStyles: Boolean?,
|
||||
): Value? = own.getValue(name) ?: prototype.properties.getValue(name, inherit, includeStyles)
|
||||
|
||||
override fun set(name: Name, item: Meta?, notify: Boolean) {
|
||||
own[name] = item
|
||||
override val eventFlow: Flow<VisionEvent>
|
||||
get() = owner.eventFlow.filterIsInstance<VisionPropertyChangedEvent>().filter {
|
||||
it.property.startsWith(childToken)
|
||||
}.map {
|
||||
VisionPropertyChangedEvent(this@SolidReferenceChild, it.property.cutFirst())
|
||||
}
|
||||
|
||||
override fun setValue(name: Name, value: Value?, notify: Boolean) {
|
||||
own.setValue(name, value)
|
||||
|
||||
override val properties: MutableMeta = MutableMetaProxy(owner.properties, childToken.asName())
|
||||
|
||||
override fun readProperty(
|
||||
name: Name,
|
||||
inherited: Boolean,
|
||||
useStyles: Boolean
|
||||
): Meta? {
|
||||
val listOfMeta = buildList {
|
||||
//1. resolve own properties
|
||||
add(properties[name])
|
||||
//2. Resolve prototype own properties
|
||||
add(prototype.properties[name])
|
||||
|
||||
if (useStyles) {
|
||||
//3. own styles
|
||||
add(getStyleProperty(name))
|
||||
//4. prototype styles
|
||||
add(prototype.getStyleProperty(name))
|
||||
}
|
||||
|
||||
if (inherited) {
|
||||
//5. own inheritance
|
||||
add(parent?.readProperty(name, inherited, useStyles))
|
||||
//6. prototype inheritance
|
||||
add(prototype.parent?.readProperty(name, inherited, useStyles))
|
||||
}
|
||||
|
||||
add(descriptor.defaultNode[name])
|
||||
}
|
||||
|
||||
override val changes: Flow<Name>
|
||||
get() = owner.properties.changes.filter { it.startsWith(childToken(childName)) }
|
||||
|
||||
override fun invalidate(propertyName: Name) {
|
||||
owner.properties.invalidate(childPropertyName(childName, propertyName))
|
||||
}
|
||||
return if (listOfMeta.all { it == null }) null else Laminate(listOfMeta)
|
||||
}
|
||||
|
||||
override val children: VisionChildren = object : VisionChildren {
|
||||
override val parent: Vision get() = this@SolidReferenceChild
|
||||
override val solids: Map<NameToken, Solid>
|
||||
get() = (prototype as? SolidContainer)?.solids?.mapValues { (key, _) ->
|
||||
SolidReferenceChild(owner, this, childName + key)
|
||||
} ?: emptyMap()
|
||||
|
||||
override val keys: Set<NameToken> get() = prototype.children?.keys ?: emptySet()
|
||||
|
||||
override val changes: Flow<Name> get() = emptyFlow()
|
||||
|
||||
override fun get(token: NameToken): SolidReferenceChild? {
|
||||
if (token !in (prototype.children?.keys ?: emptySet())) return null
|
||||
return SolidReferenceChild(this@SolidReferenceChild.owner, this@SolidReferenceChild, childName + token)
|
||||
}
|
||||
}
|
||||
// @Transient
|
||||
// override val properties: MutableVisionProperties = object : MutableVisionProperties {
|
||||
// override val descriptor: MetaDescriptor get() = this@SolidReferenceChild.descriptor
|
||||
//
|
||||
// override val own: MutableMeta by lazy { owner.properties[childToken(childName).asName()] }
|
||||
//
|
||||
// override fun getValue(
|
||||
// name: Name,
|
||||
// inherit: Boolean?,
|
||||
// includeStyles: Boolean?,
|
||||
// ): Value? = own.getValue(name) ?: prototype.properties.getValue(name, inherit, includeStyles)
|
||||
//
|
||||
// override fun set(name: Name, item: Meta?, notify: Boolean) {
|
||||
// own[name] = item
|
||||
// }
|
||||
//
|
||||
// override fun setValue(name: Name, value: Value?, notify: Boolean) {
|
||||
// own.setValue(name, value)
|
||||
// }
|
||||
//
|
||||
// override val changes: Flow<Name>
|
||||
// get() = owner.properties.changes.filter { it.startsWith(childToken(childName)) }
|
||||
//
|
||||
// override fun invalidate(propertyName: Name) {
|
||||
// owner.properties.invalidate(childPropertyName(childName, propertyName))
|
||||
// }
|
||||
// }
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -213,7 +285,9 @@ private class SolidReferenceChild(
|
||||
public fun MutableVisionContainer<Solid>.ref(
|
||||
templateName: Name,
|
||||
name: Name? = null,
|
||||
): SolidReference = SolidReference(templateName).also { setVision(name, it) }
|
||||
): SolidReference = SolidReference(templateName).also {
|
||||
setVision(name ?: SolidGroup.staticNameFor(it), it)
|
||||
}
|
||||
|
||||
public fun MutableVisionContainer<Solid>.ref(
|
||||
templateName: Name,
|
||||
@@ -237,5 +311,5 @@ public fun SolidGroup.newRef(
|
||||
} else if (existing != obj) {
|
||||
error("Can't add different prototype on top of existing one")
|
||||
}
|
||||
return items.ref(prototypeName, name?.parseAsName())
|
||||
return ref(prototypeName, name?.parseAsName())
|
||||
}
|
||||
@@ -22,7 +22,7 @@ public class Solids(meta: Meta) : VisionPlugin(meta), MutableVisionContainer<Sol
|
||||
|
||||
override val visionSerializersModule: SerializersModule get() = serializersModuleForSolids
|
||||
|
||||
override fun setVision(name: Name?, vision: Solid?) {
|
||||
override fun setVision(name: Name, vision: Solid?) {
|
||||
vision?.setAsRoot(visionManager)
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ public inline fun VisionOutput.solid(options: Canvas3DOptions? = null, block: So
|
||||
meta = options.meta
|
||||
}
|
||||
return SolidGroup().apply(block).apply {
|
||||
if (items.values.none { it is LightSource }) {
|
||||
if (solids.values.none { it is LightSource }) {
|
||||
ambientLight()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package space.kscience.visionforge.solid
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import space.kscience.dataforge.names.parseAsName
|
||||
import space.kscience.visionforge.MutableVisionContainer
|
||||
import space.kscience.visionforge.VisionBuilder
|
||||
import kotlin.math.PI
|
||||
@@ -57,4 +58,6 @@ public inline fun MutableVisionContainer<Solid>.sphere(
|
||||
action: Sphere.() -> Unit = {},
|
||||
): Sphere = Sphere(
|
||||
radius.toFloat(),
|
||||
).apply(action).also { setSolid(name, it) }
|
||||
).apply(action).also {
|
||||
setVision(name?.parseAsName() ?: SolidGroup.staticNameFor(it), it)
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package space.kscience.visionforge.solid
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import space.kscience.dataforge.names.parseAsName
|
||||
import space.kscience.visionforge.MutableVisionContainer
|
||||
import space.kscience.visionforge.VisionBuilder
|
||||
import kotlin.math.PI
|
||||
@@ -84,4 +85,6 @@ public inline fun MutableVisionContainer<Solid>.sphereLayer(
|
||||
phi.toFloat(),
|
||||
thetaStart.toFloat(),
|
||||
theta.toFloat()
|
||||
).apply(action).also { setSolid(name, it) }
|
||||
).apply(action).also {
|
||||
setVision(name?.parseAsName() ?: SolidGroup.staticNameFor(it), it)
|
||||
}
|
||||
@@ -21,4 +21,6 @@ public inline fun MutableVisionContainer<Solid>.stl(
|
||||
url: String,
|
||||
name: String? = null,
|
||||
action: StlSolid.() -> Unit = {},
|
||||
): StlSolid = StlUrlSolid(url).apply(action).also { setSolid(name, it) }
|
||||
): StlSolid = StlUrlSolid(url).apply(action).also {
|
||||
setVision(SolidGroup.inferNameFor(name, it), it)
|
||||
}
|
||||
@@ -169,4 +169,6 @@ public class Surface(
|
||||
public fun MutableVisionContainer<Solid>.surface(
|
||||
name: String? = null,
|
||||
action: Surface.Builder.() -> Unit = {},
|
||||
): Surface = Surface.Builder().apply(action).build().also { setSolid(name, it) }
|
||||
): Surface = Surface.Builder().apply(action).build().also {
|
||||
setVision(SolidGroup.inferNameFor(name, it), it)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import space.kscience.dataforge.misc.DFExperimental
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.asName
|
||||
import space.kscience.kmath.complex.QuaternionField
|
||||
import space.kscience.visionforge.root
|
||||
import space.kscience.visionforge.solid.*
|
||||
|
||||
private operator fun Number.plus(other: Number) = toFloat() + other.toFloat()
|
||||
@@ -19,7 +18,7 @@ internal fun Solid.updateFrom(other: Solid): Solid {
|
||||
scaleX *= other.scaleX
|
||||
scaleY *= other.scaleY
|
||||
scaleZ *= other.scaleZ
|
||||
properties[Name.EMPTY] = other.properties.root()
|
||||
properties[Name.EMPTY] = other.properties
|
||||
return this
|
||||
}
|
||||
|
||||
@@ -29,16 +28,16 @@ internal object RemoveSingleChild : VisualTreeTransform<SolidGroup>() {
|
||||
|
||||
override fun SolidGroup.transformInPlace() {
|
||||
fun SolidGroup.replaceChildren() {
|
||||
items.forEach { (childName, parent) ->
|
||||
solids.forEach { (childName, parent) ->
|
||||
if (parent is SolidReference) return@forEach //ignore refs
|
||||
if (parent is SolidGroup) {
|
||||
parent.replaceChildren()
|
||||
}
|
||||
if (parent is SolidGroup && parent.items.size == 1) {
|
||||
val child: Solid = parent.items.values.first()
|
||||
if (parent is SolidGroup && parent.solids.size == 1) {
|
||||
val child: Solid = parent.solids.values.first()
|
||||
val newParent = child.updateFrom(parent)
|
||||
newParent.parent = null
|
||||
items.setChild(childName.asName(), newParent)
|
||||
setVision(childName.asName(), newParent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ class ConvexTest {
|
||||
}
|
||||
}
|
||||
|
||||
val convex = group.items.values.first() as Convex
|
||||
val convex = group.solids.values.first() as Convex
|
||||
|
||||
val json = Solids.jsonForSolids.encodeToJsonElement(Convex.serializer(), convex)
|
||||
val meta = json.toMeta()
|
||||
|
||||
@@ -51,7 +51,7 @@ class SerializationTest {
|
||||
val string = Solids.encodeToString(group)
|
||||
println(string)
|
||||
val reconstructed = Solids.decodeFromString(string) as SolidGroup
|
||||
assertEquals(group.items.getChild("cube")?.properties?.own, reconstructed.items.getChild("cube")?.properties?.own)
|
||||
assertEquals(group["cube"]?.properties, reconstructed["cube"]?.properties)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -65,7 +65,7 @@ class SerializationTest {
|
||||
val serialized = Solids.encodeToString(group)
|
||||
|
||||
val reconstructed = Solids.decodeFromString(serialized) as SolidGroup
|
||||
assertEquals(100.0, (reconstructed.items.getChild("@ambientLight") as AmbientLightSource).intensity.toDouble())
|
||||
assertEquals(100.0, (reconstructed["@ambientLight"] as AmbientLightSource).intensity.toDouble())
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import space.kscience.dataforge.meta.int
|
||||
import space.kscience.dataforge.meta.set
|
||||
import space.kscience.dataforge.meta.string
|
||||
import space.kscience.dataforge.names.asName
|
||||
import space.kscience.visionforge.getProperty
|
||||
import space.kscience.visionforge.styles
|
||||
import space.kscience.visionforge.updateStyle
|
||||
import space.kscience.visionforge.useStyle
|
||||
@@ -47,7 +46,7 @@ class SolidPropertyTest {
|
||||
box = box(100, 100, 100)
|
||||
}
|
||||
}
|
||||
assertEquals(22, box?.getProperty("test".asName(), inherited = true)?.int)
|
||||
assertEquals(22, box?.readProperty("test".asName(), inherited = true)?.int)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -11,7 +11,6 @@ import space.kscience.dataforge.misc.DFExperimental
|
||||
import space.kscience.tables.*
|
||||
import space.kscience.visionforge.AbstractVision
|
||||
import space.kscience.visionforge.html.VisionOutput
|
||||
import space.kscience.visionforge.root
|
||||
import kotlin.jvm.JvmName
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
@@ -42,14 +41,14 @@ public class VisionOfTable(
|
||||
) : AbstractVision(), Rows<Value> {
|
||||
|
||||
public var data: List<Meta>
|
||||
get() = properties.root().getIndexed("rows").entries.sortedBy {
|
||||
get() = properties.getIndexed("rows").entries.sortedBy {
|
||||
it.key?.toInt()
|
||||
}.map {
|
||||
it.value
|
||||
}
|
||||
set(value) {
|
||||
//TODO Make it better
|
||||
properties.root()["rows"] = value
|
||||
properties["rows"] = value
|
||||
}
|
||||
|
||||
public val rows: List<MetaRow> get() = data.map(::MetaRow)
|
||||
|
||||
@@ -70,8 +70,8 @@ public class ThreePlugin : AbstractPlugin(), ComposeHtmlVisionRenderer {
|
||||
is SolidReference -> ThreeReferenceFactory.build(this, vision, observe)
|
||||
is SolidGroup -> {
|
||||
val group = ThreeGroup()
|
||||
vision.items.forEach { (token, child) ->
|
||||
if (token != SolidGroup.PROTOTYPES_TOKEN && child.ignore != true) {
|
||||
vision.solids.forEach { (token, child) ->
|
||||
if (child.ignore != true) {
|
||||
try {
|
||||
val object3D = buildObject3D(
|
||||
child,
|
||||
|
||||
Reference in New Issue
Block a user