[WIP] refactor inner logic

This commit is contained in:
2024-09-03 14:53:28 +03:00
parent 723c0b82e5
commit 6619fde71d
38 changed files with 380 additions and 348 deletions

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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()
}

View File

@@ -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()
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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

View File

@@ -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()

View File

@@ -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?

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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>()

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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")

View File

@@ -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)
}

View File

@@ -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?

View File

@@ -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
/**

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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())
}

View File

@@ -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()
}
}

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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)
}
}
}

View File

@@ -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()

View File

@@ -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())
}
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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,