Merge branch 'dev' into beta/1.9.20
This commit is contained in:
commit
bdc2885c0d
@ -4,6 +4,7 @@
|
||||
### Added
|
||||
- Context receivers flag
|
||||
- MeshLine for thick lines
|
||||
- Custom client-side events and thier processing in VisionServer
|
||||
|
||||
### Changed
|
||||
- Color accessor property is now `colorProperty`. Color uses `invoke` instead of `set`
|
||||
|
@ -3,6 +3,7 @@ package ru.mipt.npm.root
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.double
|
||||
import space.kscience.dataforge.meta.int
|
||||
import space.kscience.dataforge.meta.set
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.parseAsName
|
||||
import space.kscience.dataforge.names.plus
|
||||
@ -12,7 +13,6 @@ import space.kscience.kmath.geometry.fromRotationMatrix
|
||||
import space.kscience.kmath.linear.VirtualMatrix
|
||||
import space.kscience.visionforge.MutableVisionContainer
|
||||
import space.kscience.visionforge.isEmpty
|
||||
import space.kscience.visionforge.set
|
||||
import space.kscience.visionforge.solid.*
|
||||
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY
|
||||
import kotlin.math.PI
|
||||
@ -188,7 +188,7 @@ private fun SolidGroup.addShape(
|
||||
}
|
||||
|
||||
"TGeoPgon" -> {
|
||||
//TODO add a inner polygone layer
|
||||
|
||||
val fDphi by shape.meta.double(0.0)
|
||||
val fNz by shape.meta.int(2)
|
||||
val fPhi1 by shape.meta.double(360.0)
|
||||
@ -201,19 +201,26 @@ private fun SolidGroup.addShape(
|
||||
val startphi = degToRad(fPhi1)
|
||||
val deltaphi = degToRad(fDphi)
|
||||
|
||||
extruded(name) {
|
||||
//getting the radius of first
|
||||
require(fNz > 1) { "The polyhedron geometry requires at least two planes" }
|
||||
val baseRadius = fRmax[0]
|
||||
shape {
|
||||
fun Shape2DBuilder.pGon(radius: Double){
|
||||
(0..<fNedges).forEach {
|
||||
val phi = deltaphi / fNedges * it + startphi
|
||||
point(baseRadius * cos(phi), baseRadius * sin(phi))
|
||||
point(radius * cos(phi), radius * sin(phi))
|
||||
}
|
||||
}
|
||||
(0 until fNz).forEach { index ->
|
||||
//scaling all radii relative to first layer radius
|
||||
layer(fZ[index], scale = fRmax[index] / baseRadius)
|
||||
|
||||
surface(name) {
|
||||
//getting the radius of first
|
||||
require(fNz > 1) { "The polyhedron geometry requires at least two planes" }
|
||||
for (index in 0 until fNz){
|
||||
layer(
|
||||
fZ[index],
|
||||
innerBuilder = {
|
||||
pGon(fRmin[index])
|
||||
},
|
||||
outerBuilder = {
|
||||
pGon(fRmax[index])
|
||||
}
|
||||
)
|
||||
}
|
||||
}.apply(block)
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import kotlinx.serialization.modules.polymorphic
|
||||
import kotlinx.serialization.modules.subclass
|
||||
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
private fun <T> jsonRootDeserializer(
|
||||
tSerializer: KSerializer<T>,
|
||||
builder: (JsonElement) -> T,
|
||||
@ -83,7 +84,7 @@ private object RootDecoder {
|
||||
|
||||
return ref.getOrPutValue {
|
||||
// println("Decoding $it")
|
||||
val actualTypeName = it.jsonObject["_typename"]?.jsonPrimitive?.content
|
||||
// val actualTypeName = it.jsonObject["_typename"]?.jsonPrimitive?.content
|
||||
input.json.decodeFromJsonElement(tSerializer, it)
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,6 @@ class GDMLVisionTest {
|
||||
val child = cubes[Name.of("composite-000","segment-0")]
|
||||
assertNotNull(child)
|
||||
child.properties.setValue(SolidMaterial.MATERIAL_COLOR_KEY, "red".asValue())
|
||||
assertEquals("red", child.properties.getProperty(SolidMaterial.MATERIAL_COLOR_KEY).string)
|
||||
assertEquals("red", child.properties.getMeta(SolidMaterial.MATERIAL_COLOR_KEY).string)
|
||||
}
|
||||
}
|
@ -69,7 +69,7 @@ class Model(val manager: VisionManager) {
|
||||
|
||||
fun reset() {
|
||||
map.values.forEach {
|
||||
it.properties.setProperty(SolidMaterial.MATERIAL_COLOR_KEY, null)
|
||||
it.properties.setMeta(SolidMaterial.MATERIAL_COLOR_KEY, null)
|
||||
}
|
||||
tracks.children.clear()
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ fun main() = serve {
|
||||
val incRot = Quaternion.fromRotation(30.degrees, Euclidean3DSpace.zAxis)
|
||||
|
||||
|
||||
val rotationJob = context.launch {
|
||||
context.launch {
|
||||
var time: Long = 0L
|
||||
while (isActive) {
|
||||
with(QuaternionField) {
|
||||
|
@ -12,10 +12,11 @@ fun main() = makeVisionFile {
|
||||
extruded("extruded") {
|
||||
shape{
|
||||
polygon(8, 100)
|
||||
}
|
||||
layer(-30)
|
||||
layer(0, x = 10, y = 10)
|
||||
layer(30)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
19
demo/playground/src/jvmMain/kotlin/surface.kt
Normal file
19
demo/playground/src/jvmMain/kotlin/surface.kt
Normal file
@ -0,0 +1,19 @@
|
||||
package space.kscience.visionforge.examples
|
||||
|
||||
import space.kscience.visionforge.solid.ambientLight
|
||||
import space.kscience.visionforge.solid.polygon
|
||||
import space.kscience.visionforge.solid.solid
|
||||
import space.kscience.visionforge.solid.surface
|
||||
|
||||
fun main() = makeVisionFile {
|
||||
vision("canvas") {
|
||||
solid {
|
||||
ambientLight()
|
||||
surface("surface") {
|
||||
layer(0, { polygon(8, 10) }, { polygon(8, 20) })
|
||||
layer(10, { polygon(8, 20) }, { polygon(8, 30) })
|
||||
layer(20, { polygon(8, 10) }, { polygon(8, 20) })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
kotlin.code.style=official
|
||||
kotlin.mpp.stability.nowarn=true
|
||||
kotlin.js.compiler=ir
|
||||
kotlin.incremental.js.ir=true
|
||||
#kotlin.incremental.js.ir=true
|
||||
|
||||
org.gradle.parallel=true
|
||||
org.gradle.jvmargs=-Xmx4G
|
||||
|
@ -3,7 +3,7 @@ package space.kscience.visionforge
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.Transient
|
||||
import space.kscience.dataforge.meta.*
|
||||
import space.kscience.dataforge.meta.MutableMeta
|
||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||
|
||||
|
||||
|
@ -13,7 +13,7 @@ import kotlin.jvm.JvmInline
|
||||
@JvmInline
|
||||
public value class StyleSheet(private val owner: Vision) {
|
||||
|
||||
private val styleNode: Meta get() = owner.properties.getProperty(STYLESHEET_KEY)
|
||||
private val styleNode: Meta get() = owner.properties.getMeta(STYLESHEET_KEY)
|
||||
|
||||
public val items: Map<NameToken, Meta> get() = styleNode.items
|
||||
|
||||
@ -23,7 +23,7 @@ public value class StyleSheet(private val owner: Vision) {
|
||||
* Define a style without notifying owner
|
||||
*/
|
||||
public fun define(key: String, style: Meta?) {
|
||||
owner.properties.setProperty(STYLESHEET_KEY + key, style)
|
||||
owner.properties.setMeta(STYLESHEET_KEY + key, style)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -37,6 +37,9 @@ public interface Vision : Described {
|
||||
* Update this vision using a dif represented by [VisionChange].
|
||||
*/
|
||||
public fun update(change: VisionChange) {
|
||||
if (change.children?.isNotEmpty() == true) {
|
||||
error("Vision is not a group")
|
||||
}
|
||||
change.properties?.let {
|
||||
updateProperties(it, Name.EMPTY)
|
||||
}
|
||||
@ -67,7 +70,7 @@ public var Vision.visible: Boolean?
|
||||
*/
|
||||
public fun Vision.onPropertyChange(
|
||||
scope: CoroutineScope? = manager?.context,
|
||||
callback: suspend (Name) -> Unit
|
||||
callback: suspend (Name) -> Unit,
|
||||
): Job = properties.changes.onEach {
|
||||
callback(it)
|
||||
}.launchIn(scope ?: error("Orphan Vision can't observe properties"))
|
@ -1,15 +1,15 @@
|
||||
package space.kscience.visionforge
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.serialization.Serializable
|
||||
import space.kscience.dataforge.meta.*
|
||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.isEmpty
|
||||
import space.kscience.dataforge.names.plus
|
||||
@ -27,22 +27,6 @@ private fun Vision.deepCopy(manager: VisionManager): Vision {
|
||||
return manager.decodeFromJson(json)
|
||||
}
|
||||
|
||||
/**
|
||||
* A vision used only in change propagation and showing that the target should be removed
|
||||
*/
|
||||
@Serializable
|
||||
public object NullVision : Vision {
|
||||
override var parent: Vision?
|
||||
get() = null
|
||||
set(_) {
|
||||
error("Can't set parent for null vision")
|
||||
}
|
||||
|
||||
override val properties: MutableVisionProperties get() = error("Can't get properties of `NullVision`")
|
||||
|
||||
override val descriptor: MetaDescriptor? = null
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An update for a [Vision]
|
||||
@ -111,18 +95,6 @@ public class VisionChangeBuilder : MutableVisionContainer<Vision> {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param vision a new value for vision content. If the Vision is to be removed should be [NullVision]
|
||||
* @param properties updated properties
|
||||
* @param children a map of children changed in ths [VisionChange]. If a child to be removed, set [delete] flag to true.
|
||||
*/
|
||||
@Serializable
|
||||
public data class VisionChange(
|
||||
public val vision: Vision? = null,
|
||||
public val properties: Meta? = null,
|
||||
public val children: Map<Name, VisionChange>? = null,
|
||||
)
|
||||
|
||||
public inline fun VisionManager.VisionChange(block: VisionChangeBuilder.() -> Unit): VisionChange =
|
||||
VisionChangeBuilder().apply(block).deepCopy(this)
|
||||
|
@ -0,0 +1,52 @@
|
||||
package space.kscience.visionforge
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||
import space.kscience.dataforge.names.Name
|
||||
|
||||
/**
|
||||
* An event propagated from client to a server
|
||||
*/
|
||||
@Serializable
|
||||
public sealed interface VisionEvent
|
||||
|
||||
/**
|
||||
* An event that consists of custom meta
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName("meta")
|
||||
public class VisionMetaEvent(public val targetName: Name, public val meta: Meta) : VisionEvent
|
||||
|
||||
|
||||
/**
|
||||
* A vision used only in change propagation and showing that the target should be removed
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName("null")
|
||||
public object NullVision : Vision {
|
||||
override var parent: Vision?
|
||||
get() = null
|
||||
set(_) {
|
||||
error("Can't set parent for null vision")
|
||||
}
|
||||
|
||||
override val properties: MutableVisionProperties get() = error("Can't get properties of `NullVision`")
|
||||
|
||||
override val descriptor: MetaDescriptor? = null
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param vision a new value for vision content. If the Vision is to be removed should be [NullVision]
|
||||
* @param properties updated properties
|
||||
* @param children a map of children changed in ths [VisionChange].
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName("change")
|
||||
public data class VisionChange(
|
||||
public val vision: Vision? = null,
|
||||
public val properties: Meta? = null,
|
||||
public val children: Map<Name, VisionChange>? = null,
|
||||
) : VisionEvent
|
@ -10,11 +10,25 @@ import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.NameToken
|
||||
import space.kscience.dataforge.names.parseAsName
|
||||
import space.kscience.dataforge.names.plus
|
||||
import space.kscience.visionforge.AbstractVisionGroup.Companion.updateProperties
|
||||
import space.kscience.visionforge.Vision.Companion.STYLE_KEY
|
||||
|
||||
|
||||
public interface VisionGroup : Vision {
|
||||
public val children: VisionChildren
|
||||
|
||||
override fun update(change: VisionChange) {
|
||||
change.children?.forEach { (name, change) ->
|
||||
if (change.vision != null || change.vision == NullVision) {
|
||||
error("VisionGroup is read-only")
|
||||
} else {
|
||||
children.getChild(name)?.update(change)
|
||||
}
|
||||
}
|
||||
change.properties?.let {
|
||||
updateProperties(it, Name.EMPTY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface MutableVisionGroup : VisionGroup {
|
||||
@ -22,15 +36,6 @@ public interface MutableVisionGroup : VisionGroup {
|
||||
override val children: MutableVisionChildren
|
||||
|
||||
public fun createGroup(): MutableVisionGroup
|
||||
}
|
||||
|
||||
public val Vision.children: VisionChildren? get() = (this as? VisionGroup)?.children
|
||||
|
||||
/**
|
||||
* A full base implementation for a [Vision]
|
||||
*/
|
||||
@Serializable
|
||||
public abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup {
|
||||
|
||||
override fun update(change: VisionChange) {
|
||||
change.children?.forEach { (name, change) ->
|
||||
@ -44,6 +49,15 @@ public abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup
|
||||
updateProperties(it, Name.EMPTY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public val Vision.children: VisionChildren? get() = (this as? VisionGroup)?.children
|
||||
|
||||
/**
|
||||
* A full base implementation for a [Vision]
|
||||
*/
|
||||
@Serializable
|
||||
public abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup {
|
||||
|
||||
@SerialName("children")
|
||||
protected var childrenInternal: MutableMap<NameToken, Vision>? = null
|
||||
|
@ -12,7 +12,7 @@ import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||
import space.kscience.dataforge.meta.descriptors.get
|
||||
import space.kscience.dataforge.names.*
|
||||
|
||||
public interface VisionProperties {
|
||||
public interface VisionProperties : MetaProvider {
|
||||
|
||||
/**
|
||||
* Raw Visions own properties without styles, defaults, etc.
|
||||
@ -23,21 +23,26 @@ public interface VisionProperties {
|
||||
|
||||
public fun getValue(
|
||||
name: Name,
|
||||
inherit: Boolean? = null,
|
||||
inherit: Boolean?,
|
||||
includeStyles: Boolean? = null,
|
||||
): Value?
|
||||
|
||||
override fun getValue(name: Name): Value? = getValue(name, null, null)
|
||||
|
||||
/**
|
||||
* Get property with given layer flags.
|
||||
* @param inherit toggles parent node property lookup. Null means inference from descriptor.
|
||||
* @param includeStyles toggles inclusion of properties from styles.
|
||||
*/
|
||||
public fun getProperty(
|
||||
public fun getMeta(
|
||||
name: Name,
|
||||
inherit: Boolean? = null,
|
||||
inherit: Boolean?,
|
||||
includeStyles: Boolean? = null,
|
||||
): Meta
|
||||
|
||||
override fun getMeta(name: Name): Meta? = getMeta(name, null, null)
|
||||
|
||||
|
||||
public val changes: Flow<Name>
|
||||
|
||||
/**
|
||||
@ -47,9 +52,9 @@ public interface VisionProperties {
|
||||
public fun invalidate(propertyName: Name)
|
||||
}
|
||||
|
||||
public interface MutableVisionProperties : VisionProperties {
|
||||
public interface MutableVisionProperties : VisionProperties, MutableMetaProvider {
|
||||
|
||||
override fun getProperty(
|
||||
override fun getMeta(
|
||||
name: Name,
|
||||
inherit: Boolean?,
|
||||
includeStyles: Boolean?,
|
||||
@ -60,21 +65,31 @@ public interface MutableVisionProperties : VisionProperties {
|
||||
includeStyles,
|
||||
)
|
||||
|
||||
public fun setProperty(
|
||||
public fun setMeta(
|
||||
name: Name,
|
||||
node: Meta?,
|
||||
notify: Boolean = true,
|
||||
notify: Boolean,
|
||||
)
|
||||
|
||||
public fun setValue(
|
||||
name: Name,
|
||||
value: Value?,
|
||||
notify: Boolean = true,
|
||||
notify: Boolean,
|
||||
)
|
||||
|
||||
override fun getMeta(name: Name): MutableMeta = getMeta(name, null, null)
|
||||
|
||||
override fun setMeta(name: Name, node: Meta?) {
|
||||
setMeta(name, node, true)
|
||||
}
|
||||
|
||||
override fun setValue(name: Name, value: Value?) {
|
||||
setValue(name, value, true)
|
||||
}
|
||||
}
|
||||
|
||||
public fun MutableVisionProperties.remove(name: Name) {
|
||||
setProperty(name, null)
|
||||
setMeta(name, null)
|
||||
}
|
||||
|
||||
public fun MutableVisionProperties.remove(name: String) {
|
||||
@ -134,7 +149,7 @@ private class VisionPropertiesItem(
|
||||
)
|
||||
|
||||
override fun setMeta(name: Name, node: Meta?) {
|
||||
properties.setProperty(nodeName + name, node)
|
||||
properties.setMeta(nodeName + name, node)
|
||||
}
|
||||
|
||||
override fun toString(): String = Meta.toString(this)
|
||||
@ -187,7 +202,7 @@ public abstract class AbstractVisionProperties(
|
||||
return descriptor?.defaultValue
|
||||
}
|
||||
|
||||
override fun setProperty(name: Name, node: Meta?, notify: Boolean) {
|
||||
override fun setMeta(name: Name, node: Meta?, notify: Boolean) {
|
||||
//ignore if the value is the same as existing
|
||||
if (own?.getMeta(name) == node) return
|
||||
|
||||
@ -257,11 +272,11 @@ public fun VisionProperties.getValue(
|
||||
/**
|
||||
* Get [Vision] property using key as a String
|
||||
*/
|
||||
public fun VisionProperties.getProperty(
|
||||
public fun VisionProperties.getMeta(
|
||||
name: String,
|
||||
inherit: Boolean? = null,
|
||||
includeStyles: Boolean? = null,
|
||||
): Meta = getProperty(name.parseAsName(), inherit, includeStyles)
|
||||
): Meta = getMeta(name.parseAsName(), inherit, includeStyles)
|
||||
|
||||
/**
|
||||
* The root property node with given inheritance and style flags
|
||||
@ -271,33 +286,33 @@ public fun VisionProperties.getProperty(
|
||||
public fun MutableVisionProperties.root(
|
||||
inherit: Boolean? = null,
|
||||
includeStyles: Boolean? = null,
|
||||
): MutableMeta = getProperty(Name.EMPTY, inherit, includeStyles)
|
||||
): MutableMeta = getMeta(Name.EMPTY, inherit, includeStyles)
|
||||
|
||||
|
||||
/**
|
||||
* Get [Vision] property using key as a String
|
||||
*/
|
||||
public fun MutableVisionProperties.getProperty(
|
||||
public fun MutableVisionProperties.getMeta(
|
||||
name: String,
|
||||
inherit: Boolean? = null,
|
||||
includeStyles: Boolean? = null,
|
||||
): MutableMeta = getProperty(name.parseAsName(), inherit, includeStyles)
|
||||
): MutableMeta = getMeta(name.parseAsName(), inherit, includeStyles)
|
||||
|
||||
|
||||
public operator fun MutableVisionProperties.set(name: Name, value: Number): Unit =
|
||||
setValue(name, value.asValue())
|
||||
|
||||
public operator fun MutableVisionProperties.set(name: String, value: Number): Unit =
|
||||
set(name.parseAsName(), value)
|
||||
|
||||
public operator fun MutableVisionProperties.set(name: Name, value: Boolean): Unit =
|
||||
setValue(name, value.asValue())
|
||||
|
||||
public operator fun MutableVisionProperties.set(name: String, value: Boolean): Unit =
|
||||
set(name.parseAsName(), value)
|
||||
|
||||
public operator fun MutableVisionProperties.set(name: Name, value: String): Unit =
|
||||
setValue(name, value.asValue())
|
||||
|
||||
public operator fun MutableVisionProperties.set(name: String, value: String): Unit =
|
||||
set(name.parseAsName(), value)
|
||||
//
|
||||
//public operator fun MutableVisionProperties.set(name: Name, value: Number): Unit =
|
||||
// setValue(name, value.asValue())
|
||||
//
|
||||
//public operator fun MutableVisionProperties.set(name: String, value: Number): Unit =
|
||||
// set(name.parseAsName(), value)
|
||||
//
|
||||
//public operator fun MutableVisionProperties.set(name: Name, value: Boolean): Unit =
|
||||
// setValue(name, value.asValue())
|
||||
//
|
||||
//public operator fun MutableVisionProperties.set(name: String, value: Boolean): Unit =
|
||||
// set(name.parseAsName(), value)
|
||||
//
|
||||
//public operator fun MutableVisionProperties.set(name: Name, value: String): Unit =
|
||||
// setValue(name, value.asValue())
|
||||
//
|
||||
//public operator fun MutableVisionProperties.set(name: String, value: String): Unit =
|
||||
// set(name.parseAsName(), value)
|
@ -17,10 +17,10 @@ public fun Vision.flowProperty(
|
||||
includeStyles: Boolean? = null,
|
||||
): Flow<Meta> = flow {
|
||||
//Pass initial value.
|
||||
emit(properties.getProperty(propertyName, inherit, includeStyles))
|
||||
emit(properties.getMeta(propertyName, inherit, includeStyles))
|
||||
properties.changes.collect { name ->
|
||||
if (name.startsWith(propertyName)) {
|
||||
emit(properties.getProperty(propertyName, inherit, includeStyles))
|
||||
emit(properties.getMeta(propertyName, inherit, includeStyles))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -93,7 +93,6 @@ public fun FlowContent.visionFragment(
|
||||
updatesUrl: String? = null,
|
||||
onVisionRendered: (Name, Vision) -> Unit = { _, _ -> },
|
||||
idPrefix: String? = null,
|
||||
|
||||
fragment: HtmlVisionFragment,
|
||||
): Unit = consumer.visionFragment(
|
||||
visionManager = visionManager,
|
||||
|
@ -6,10 +6,11 @@ import space.kscience.dataforge.meta.boolean
|
||||
import space.kscience.dataforge.meta.number
|
||||
import space.kscience.dataforge.meta.string
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.visionforge.*
|
||||
import space.kscience.visionforge.AbstractVision
|
||||
import space.kscience.visionforge.Vision
|
||||
|
||||
//TODO replace by something
|
||||
internal val Vision.mutableProperties get() = properties.getProperty(Name.EMPTY, false, false)
|
||||
internal val Vision.mutableProperties get() = properties.getMeta(Name.EMPTY, false, false)
|
||||
|
||||
@Serializable
|
||||
public abstract class VisionOfHtmlInput : AbstractVision() {
|
||||
|
@ -23,10 +23,10 @@ public fun Vision.useProperty(
|
||||
callback: (Meta) -> Unit,
|
||||
): Job {
|
||||
//Pass initial value.
|
||||
callback(properties.getProperty(propertyName, inherit, includeStyles))
|
||||
callback(properties.getMeta(propertyName, inherit, includeStyles))
|
||||
return properties.changes.onEach { name ->
|
||||
if (name.startsWith(propertyName)) {
|
||||
callback(properties.getProperty(propertyName, inherit, includeStyles))
|
||||
callback(properties.getMeta(propertyName, inherit, includeStyles))
|
||||
}
|
||||
}.launchIn(scope ?: error("Orphan Vision can't observe properties"))
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import kotlinx.html.*
|
||||
import kotlinx.html.stream.createHTML
|
||||
import space.kscience.dataforge.context.Global
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.set
|
||||
import space.kscience.dataforge.misc.DFExperimental
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.visionforge.*
|
||||
|
@ -42,7 +42,7 @@ internal class VisionPropertyTest {
|
||||
@Test
|
||||
fun testPropertyEdit() {
|
||||
val vision = manager.group()
|
||||
vision.properties.getProperty("fff.ddd").apply {
|
||||
vision.properties.getMeta("fff.ddd").apply {
|
||||
value = 2.asValue()
|
||||
}
|
||||
assertEquals(2, vision.properties.getValue("fff.ddd")?.int)
|
||||
@ -52,7 +52,7 @@ internal class VisionPropertyTest {
|
||||
@Test
|
||||
fun testPropertyUpdate() {
|
||||
val vision = manager.group()
|
||||
vision.properties.getProperty("fff").updateWith(TestScheme) {
|
||||
vision.properties.getMeta("fff").updateWith(TestScheme) {
|
||||
ddd = 2
|
||||
}
|
||||
assertEquals(2, vision.properties.getValue("fff.ddd")?.int)
|
||||
@ -87,7 +87,7 @@ internal class VisionPropertyTest {
|
||||
|
||||
child.properties.remove("test")
|
||||
|
||||
assertEquals(11, child.properties.getProperty("test", inherit = true).int)
|
||||
assertEquals(11, child.properties.getMeta("test", inherit = true).int)
|
||||
// assertEquals(11, deferred.await()?.int)
|
||||
// assertEquals(2, callCounter)
|
||||
subscription.cancel()
|
||||
|
@ -4,6 +4,7 @@ import kotlinx.browser.document
|
||||
import kotlinx.browser.window
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
@ -11,10 +12,7 @@ import kotlinx.coroutines.sync.withLock
|
||||
import org.w3c.dom.*
|
||||
import org.w3c.dom.url.URL
|
||||
import space.kscience.dataforge.context.*
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.MetaSerializer
|
||||
import space.kscience.dataforge.meta.get
|
||||
import space.kscience.dataforge.meta.int
|
||||
import space.kscience.dataforge.meta.*
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.parseAsName
|
||||
import space.kscience.visionforge.html.VisionTagConsumer
|
||||
@ -68,7 +66,7 @@ public class VisionClient : AbstractPlugin() {
|
||||
/**
|
||||
* Communicate vision property changed from rendering engine to model
|
||||
*/
|
||||
public fun visionPropertyChanged(visionName: Name, propertyName: Name, item: Meta?) {
|
||||
public fun notifyPropertyChanged(visionName: Name, propertyName: Name, item: Meta?) {
|
||||
context.launch {
|
||||
mutex.withLock {
|
||||
changeCollector.propertyChanged(visionName, propertyName, item)
|
||||
@ -76,9 +74,17 @@ public class VisionClient : AbstractPlugin() {
|
||||
}
|
||||
}
|
||||
|
||||
// public fun visionChanged(name: Name?, child: Vision?) {
|
||||
// changeCollector.setChild(name, child)
|
||||
// }
|
||||
private val eventCollector by lazy {
|
||||
MutableSharedFlow<VisionEvent>(meta["feedback.eventCache"].int ?: 100)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send a custom feedback event
|
||||
*/
|
||||
public suspend fun sendEvent(event: VisionEvent) {
|
||||
eventCollector.emit(event)
|
||||
}
|
||||
|
||||
private fun renderVision(element: Element, name: Name, vision: Vision, outputMeta: Meta) {
|
||||
vision.setAsRoot(visionManager)
|
||||
@ -103,7 +109,7 @@ public class VisionClient : AbstractPlugin() {
|
||||
|
||||
logger.info { "Updating vision data from $wsUrl" }
|
||||
|
||||
//Individual websocket for this element
|
||||
//Individual websocket for this vision
|
||||
WebSocket(wsUrl.toString()).apply {
|
||||
onmessage = { messageEvent ->
|
||||
val stringData: String? = messageEvent.data as? String
|
||||
@ -131,7 +137,7 @@ public class VisionClient : AbstractPlugin() {
|
||||
var feedbackJob: Job? = null
|
||||
|
||||
//Feedback changes aggregation time in milliseconds
|
||||
val feedbackAggregationTime = meta["aggregationTime"]?.int ?: 300
|
||||
val feedbackAggregationTime = meta["feedback.aggregationTime"]?.int ?: 300
|
||||
|
||||
onopen = {
|
||||
feedbackJob = visionManager.context.launch {
|
||||
@ -144,18 +150,24 @@ public class VisionClient : AbstractPlugin() {
|
||||
change.reset()
|
||||
}
|
||||
}
|
||||
// // take channel for given vision name
|
||||
// eventCollector[name]?.let { channel ->
|
||||
// for (e in channel) {
|
||||
// send(visionManager.jsonFormat.encodeToString(VisionEvent.serializer(), e))
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
logger.info { "WebSocket update channel established for output '$name'" }
|
||||
logger.info { "WebSocket feedback channel established for output '$name'" }
|
||||
}
|
||||
|
||||
onclose = {
|
||||
feedbackJob?.cancel()
|
||||
logger.info { "WebSocket update channel closed for output '$name'" }
|
||||
logger.info { "WebSocket feedback channel closed for output '$name'" }
|
||||
}
|
||||
onerror = {
|
||||
feedbackJob?.cancel()
|
||||
logger.error { "WebSocket update channel error for output '$name'" }
|
||||
logger.error { "WebSocket feedback channel error for output '$name'" }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -248,20 +260,26 @@ public class VisionClient : AbstractPlugin() {
|
||||
}
|
||||
}
|
||||
|
||||
public fun VisionClient.visionPropertyChanged(visionName: Name, propertyName: String, item: Meta?) {
|
||||
visionPropertyChanged(visionName, propertyName.parseAsName(true), item)
|
||||
public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: Meta?) {
|
||||
notifyPropertyChanged(visionName, propertyName.parseAsName(true), item)
|
||||
}
|
||||
|
||||
public fun VisionClient.visionPropertyChanged(visionName: Name, propertyName: String, item: Number) {
|
||||
visionPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item))
|
||||
public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: Number) {
|
||||
notifyPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item))
|
||||
}
|
||||
|
||||
public fun VisionClient.visionPropertyChanged(visionName: Name, propertyName: String, item: String) {
|
||||
visionPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item))
|
||||
public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: String) {
|
||||
notifyPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item))
|
||||
}
|
||||
|
||||
public fun VisionClient.visionPropertyChanged(visionName: Name, propertyName: String, item: Boolean) {
|
||||
visionPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item))
|
||||
public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: Boolean) {
|
||||
notifyPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item))
|
||||
}
|
||||
|
||||
public fun VisionClient.sendEvent(visionName: Name, event: MetaRepr): Unit {
|
||||
context.launch {
|
||||
sendEvent(VisionMetaEvent(visionName, event.toMeta()))
|
||||
}
|
||||
}
|
||||
|
||||
private fun whenDocumentLoaded(block: Document.() -> Unit): Unit {
|
||||
|
@ -36,7 +36,7 @@ internal fun textVisionRenderer(
|
||||
value = it ?: ""
|
||||
}
|
||||
onChangeFunction = {
|
||||
client.visionPropertyChanged(name, VisionOfTextField::text.name, value)
|
||||
client.notifyPropertyChanged(name, VisionOfTextField::text.name, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -58,7 +58,7 @@ internal fun numberVisionRenderer(
|
||||
value = it?.toDouble() ?: 0.0
|
||||
}
|
||||
onChangeFunction = {
|
||||
client.visionPropertyChanged(name, VisionOfNumberField::value.name, value)
|
||||
client.notifyPropertyChanged(name, VisionOfNumberField::value.name, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -106,7 +106,7 @@ internal fun formVisionRenderer(
|
||||
form.onsubmit = { event ->
|
||||
event.preventDefault()
|
||||
val formData = FormData(form).toMeta()
|
||||
client.visionPropertyChanged(name, VisionOfHtmlForm::values.name, formData)
|
||||
client.notifyPropertyChanged(name, VisionOfHtmlForm::values.name, formData)
|
||||
console.info("Sent: ${formData.toMap()}")
|
||||
false
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.Transient
|
||||
import space.kscience.dataforge.meta.*
|
||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||
import space.kscience.dataforge.misc.DFExperimental
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.plotly.Plot
|
||||
import space.kscience.plotly.Plotly
|
||||
@ -34,7 +33,7 @@ public class VisionOfPlotly private constructor(
|
||||
|
||||
@Transient
|
||||
override val properties: MutableVisionProperties = object : MutableVisionProperties {
|
||||
override fun setProperty(name: Name, node: Meta?, notify: Boolean) {
|
||||
override fun setMeta(name: Name, node: Meta?, notify: Boolean) {
|
||||
meta.setMeta(name, node)
|
||||
}
|
||||
|
||||
@ -46,7 +45,7 @@ public class VisionOfPlotly private constructor(
|
||||
|
||||
override val descriptor: MetaDescriptor? get() = this@VisionOfPlotly.descriptor
|
||||
|
||||
override fun getProperty(
|
||||
override fun getMeta(
|
||||
name: Name,
|
||||
inherit: Boolean?,
|
||||
includeStyles: Boolean?,
|
||||
|
@ -23,10 +23,7 @@ import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.context.ContextAware
|
||||
import space.kscience.dataforge.meta.*
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.visionforge.Vision
|
||||
import space.kscience.visionforge.VisionChange
|
||||
import space.kscience.visionforge.VisionManager
|
||||
import space.kscience.visionforge.flowChanges
|
||||
import space.kscience.visionforge.*
|
||||
import space.kscience.visionforge.html.*
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
@ -77,6 +74,11 @@ public class VisionRoute(
|
||||
*/
|
||||
public fun Application.serveVisionData(
|
||||
configuration: VisionRoute,
|
||||
onEvent: suspend Vision.(VisionEvent) -> Unit = { event ->
|
||||
if (event is VisionChange) {
|
||||
update(event)
|
||||
}
|
||||
},
|
||||
resolveVision: (Name) -> Vision?,
|
||||
) {
|
||||
require(WebSockets)
|
||||
@ -96,11 +98,11 @@ public fun Application.serveVisionData(
|
||||
launch {
|
||||
for (frame in incoming) {
|
||||
val data = frame.data.decodeToString()
|
||||
application.log.debug("Received update for $name: \n$data")
|
||||
val change = configuration.visionManager.jsonFormat.decodeFromString(
|
||||
VisionChange.serializer(), data
|
||||
application.log.debug("Received event for $name: \n$data")
|
||||
val event = configuration.visionManager.jsonFormat.decodeFromString(
|
||||
VisionEvent.serializer(), data
|
||||
)
|
||||
vision.update(change)
|
||||
vision.onEvent(event)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,10 @@ package space.kscience.visionforge.solid
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.visionforge.*
|
||||
import space.kscience.visionforge.MutableVisionContainer
|
||||
import space.kscience.visionforge.VisionBuilder
|
||||
import space.kscience.visionforge.setChild
|
||||
import space.kscience.visionforge.static
|
||||
|
||||
public enum class CompositeType {
|
||||
GROUP, // Dumb sum of meshes
|
||||
@ -33,7 +36,7 @@ public inline fun MutableVisionContainer<Solid>.composite(
|
||||
}
|
||||
val res = Composite(type, children[0], children[1])
|
||||
|
||||
res.properties.setProperty(Name.EMPTY, group.properties.own)
|
||||
res.properties.setMeta(Name.EMPTY, group.properties.own)
|
||||
|
||||
setChild(name, res)
|
||||
return res
|
||||
|
@ -9,37 +9,8 @@ import space.kscience.kmath.geometry.component2
|
||||
import space.kscience.visionforge.MutableVisionContainer
|
||||
import space.kscience.visionforge.VisionBuilder
|
||||
import space.kscience.visionforge.setChild
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
||||
|
||||
public typealias Shape2D = List<Float32Vector2D>
|
||||
|
||||
@Serializable
|
||||
public class Shape2DBuilder(private val points: ArrayList<Float32Vector2D> = ArrayList()) {
|
||||
|
||||
public fun point(x: Number, y: Number) {
|
||||
points.add(Float32Vector2D(x, y))
|
||||
}
|
||||
|
||||
public fun build(): Shape2D = points
|
||||
}
|
||||
|
||||
public fun Shape2DBuilder.polygon(vertices: Int, radius: Number) {
|
||||
require(vertices > 2) { "Polygon must have more than 2 vertices" }
|
||||
val angle = 2 * PI / vertices
|
||||
for (i in 0 until vertices) {
|
||||
point(radius.toDouble() * cos(angle * i), radius.toDouble() * sin(angle * i))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A layer for extruded shape
|
||||
*/
|
||||
@Serializable
|
||||
public data class Layer(var x: Float, var y: Float, var z: Float, var scale: Float)
|
||||
|
||||
/**
|
||||
* An extruded shape with the same number of points on each layer.
|
||||
*/
|
||||
@ -50,6 +21,12 @@ public class Extruded(
|
||||
public val layers: List<Layer>,
|
||||
) : SolidBase<Extruded>(), GeometrySolid {
|
||||
|
||||
/**
|
||||
* A layer for extruded shape
|
||||
*/
|
||||
@Serializable
|
||||
public data class Layer(var x: Float, var y: Float, var z: Float, var scale: Float)
|
||||
|
||||
init {
|
||||
require(shape.size > 2) { "Extruded shape requires more than 2 points per layer" }
|
||||
}
|
||||
@ -72,6 +49,8 @@ public class Extruded(
|
||||
var lowerLayer = layers.first()
|
||||
var upperLayer: List<Float32Vector3D>
|
||||
|
||||
geometryBuilder.cap(layers.first().reversed())
|
||||
|
||||
for (i in (1 until layers.size)) {
|
||||
upperLayer = layers[i]
|
||||
for (j in (0 until shape.size - 1)) {
|
||||
@ -93,7 +72,7 @@ public class Extruded(
|
||||
)
|
||||
lowerLayer = upperLayer
|
||||
}
|
||||
geometryBuilder.cap(layers.first().reversed())
|
||||
|
||||
geometryBuilder.cap(layers.last())
|
||||
}
|
||||
|
||||
@ -102,16 +81,18 @@ public class Extruded(
|
||||
public var layers: MutableList<Layer> = ArrayList(),
|
||||
public val properties: MutableMeta = MutableMeta(),
|
||||
) {
|
||||
@VisionBuilder
|
||||
public fun shape(block: Shape2DBuilder.() -> Unit) {
|
||||
this.shape = Shape2DBuilder().apply(block).build()
|
||||
}
|
||||
|
||||
@VisionBuilder
|
||||
public fun layer(z: Number, x: Number = 0.0, y: Number = 0.0, scale: Number = 1.0) {
|
||||
layers.add(Layer(x.toFloat(), y.toFloat(), z.toFloat(), scale.toFloat()))
|
||||
}
|
||||
|
||||
internal fun build(): Extruded = Extruded(shape, layers).apply {
|
||||
this.properties.setProperty(Name.EMPTY, this@Builder.properties)
|
||||
this.properties.setMeta(Name.EMPTY, this@Builder.properties)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,10 @@ import space.kscience.visionforge.setChild
|
||||
public class PolyLine(public val points: List<Float32Vector3D>) : SolidBase<PolyLine>() {
|
||||
|
||||
//var lineType by string()
|
||||
public var thickness: Number by properties.root(inherit = false, includeStyles = true).number { DEFAULT_THICKNESS }
|
||||
public var thickness: Number by properties.root(
|
||||
inherit = false,
|
||||
includeStyles = true
|
||||
).number { DEFAULT_THICKNESS }
|
||||
|
||||
public companion object {
|
||||
public const val DEFAULT_THICKNESS: Double = 1.0
|
||||
|
@ -0,0 +1,26 @@
|
||||
package space.kscience.visionforge.solid
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
||||
public typealias Shape2D = List<Float32Vector2D>
|
||||
|
||||
@Serializable
|
||||
public class Shape2DBuilder(private val points: ArrayList<Float32Vector2D> = ArrayList()) {
|
||||
|
||||
public fun point(x: Number, y: Number) {
|
||||
points.add(Float32Vector2D(x, y))
|
||||
}
|
||||
|
||||
public fun build(): Shape2D = points
|
||||
}
|
||||
|
||||
public fun Shape2DBuilder.polygon(vertices: Int, radius: Number) {
|
||||
require(vertices > 2) { "Polygon must have more than 2 vertices" }
|
||||
val angle = 2 * PI / vertices
|
||||
for (i in 0 until vertices) {
|
||||
point(radius.toDouble() * cos(angle * i), radius.toDouble() * sin(angle * i))
|
||||
}
|
||||
}
|
@ -11,8 +11,10 @@ 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.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
|
||||
@ -182,7 +184,7 @@ internal fun point(
|
||||
|
||||
override fun setValue(thisRef: Solid, property: KProperty<*>, value: Float32Vector3D?) {
|
||||
if (value == null) {
|
||||
thisRef.properties.setProperty(name, null)
|
||||
thisRef.properties.setMeta(name, null)
|
||||
} else {
|
||||
thisRef.properties[name + X_KEY] = value.x
|
||||
thisRef.properties[name + Y_KEY] = value.y
|
||||
|
@ -107,12 +107,12 @@ public val Solid.color: ColorAccessor
|
||||
get() = ColorAccessor(properties.root(true), MATERIAL_COLOR_KEY)
|
||||
|
||||
public var Solid.material: SolidMaterial?
|
||||
get() = SolidMaterial.read(properties.getProperty(MATERIAL_KEY))
|
||||
set(value) = properties.setProperty(MATERIAL_KEY, value?.meta)
|
||||
get() = SolidMaterial.read(properties.getMeta(MATERIAL_KEY))
|
||||
set(value) = properties.setMeta(MATERIAL_KEY, value?.meta)
|
||||
|
||||
@VisionBuilder
|
||||
public fun Solid.material(builder: SolidMaterial.() -> Unit) {
|
||||
properties.getProperty(MATERIAL_KEY).updateWith(SolidMaterial, builder)
|
||||
properties.getMeta(MATERIAL_KEY).updateWith(SolidMaterial, builder)
|
||||
}
|
||||
|
||||
public var Solid.opacity: Number?
|
||||
@ -125,5 +125,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.getProperty(SolidMaterial.EDGES_MATERIAL_KEY)).apply(block)
|
||||
SolidMaterial.write(properties.getMeta(SolidMaterial.EDGES_MATERIAL_KEY)).apply(block)
|
||||
}
|
@ -14,7 +14,6 @@ import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||
import space.kscience.dataforge.meta.descriptors.get
|
||||
import space.kscience.dataforge.names.*
|
||||
import space.kscience.visionforge.*
|
||||
import space.kscience.visionforge.AbstractVisionGroup.Companion.updateProperties
|
||||
import space.kscience.visionforge.solid.SolidReference.Companion.REFERENCE_CHILD_PROPERTY_PREFIX
|
||||
|
||||
|
||||
@ -162,7 +161,7 @@ internal class SolidReferenceChild(
|
||||
override val properties: MutableVisionProperties = object : MutableVisionProperties {
|
||||
override val descriptor: MetaDescriptor get() = this@SolidReferenceChild.descriptor
|
||||
|
||||
override val own: MutableMeta by lazy { owner.properties.getProperty(childToken(childName).asName()) }
|
||||
override val own: MutableMeta by lazy { owner.properties.getMeta(childToken(childName).asName()) }
|
||||
|
||||
override fun getValue(
|
||||
name: Name,
|
||||
@ -170,7 +169,7 @@ internal class SolidReferenceChild(
|
||||
includeStyles: Boolean?,
|
||||
): Value? = own.getValue(name) ?: prototype.properties.getValue(name, inherit, includeStyles)
|
||||
|
||||
override fun setProperty(name: Name, node: Meta?, notify: Boolean) {
|
||||
override fun setMeta(name: Name, node: Meta?, notify: Boolean) {
|
||||
own.setMeta(name, node)
|
||||
}
|
||||
|
||||
@ -185,20 +184,6 @@ internal class SolidReferenceChild(
|
||||
}
|
||||
}
|
||||
|
||||
override fun update(change: VisionChange) {
|
||||
change.children?.forEach { (name, change) ->
|
||||
when {
|
||||
change.vision == NullVision -> error("Deleting children inside ref is not allowed.")
|
||||
change.vision != null -> error("Updating content of the ref is not allowed")
|
||||
else -> children.getChild(name)?.update(change)
|
||||
}
|
||||
}
|
||||
change.properties?.let {
|
||||
updateProperties(it, Name.EMPTY)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override val children: VisionChildren = object : VisionChildren {
|
||||
override val parent: Vision get() = this@SolidReferenceChild
|
||||
|
||||
|
@ -41,6 +41,7 @@ public class Solids(meta: Meta) : VisionPlugin(meta), MutableVisionContainer<Sol
|
||||
subclass(ConeSurface.serializer())
|
||||
subclass(Convex.serializer())
|
||||
subclass(Extruded.serializer())
|
||||
subclass(Surface.serializer())
|
||||
subclass(PolyLine.serializer())
|
||||
subclass(SolidLabel.serializer())
|
||||
subclass(Sphere.serializer())
|
||||
|
@ -2,9 +2,14 @@ package space.kscience.visionforge.solid
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import space.kscience.dataforge.meta.MutableMeta
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.kmath.geometry.component1
|
||||
import space.kscience.kmath.geometry.component2
|
||||
import space.kscience.kmath.structures.Float32
|
||||
import space.kscience.visionforge.MutableVisionContainer
|
||||
import space.kscience.visionforge.VisionBuilder
|
||||
import space.kscience.visionforge.setChild
|
||||
|
||||
|
||||
private inline fun <T> Iterable<T>.sumOf(selector: (T) -> Float32): Float32 {
|
||||
@ -20,9 +25,9 @@ private inline fun <T> Iterable<T>.sumOf(selector: (T) -> Float32): Float32 {
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName("solid.surface")
|
||||
public class LayersSurface(
|
||||
public class Surface(
|
||||
public val layers: List<Layer>,
|
||||
) : SolidBase<Extruded>(), GeometrySolid {
|
||||
) : SolidBase<Surface>(), GeometrySolid {
|
||||
|
||||
@Serializable
|
||||
public data class Layer(val z: Float32, val outer: Shape2D, val inner: Shape2D?) {
|
||||
@ -130,7 +135,39 @@ public class LayersSurface(
|
||||
}
|
||||
}
|
||||
|
||||
public class Builder(
|
||||
public var layers: MutableList<Layer> = ArrayList(),
|
||||
public val properties: MutableMeta = MutableMeta(),
|
||||
) {
|
||||
|
||||
public fun layer(
|
||||
z: Number,
|
||||
innerBuilder: (Shape2DBuilder.() -> Unit)? = null,
|
||||
outerBuilder: Shape2DBuilder.() -> Unit,
|
||||
) {
|
||||
layers.add(
|
||||
Layer(
|
||||
z.toFloat(),
|
||||
outer = Shape2DBuilder().apply(outerBuilder).build(),
|
||||
inner = innerBuilder?.let { Shape2DBuilder().apply(innerBuilder).build() }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
internal fun build(): Surface = Surface(layers).apply {
|
||||
properties.setMeta(Name.EMPTY, this@Builder.properties)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public companion object {
|
||||
public const val TYPE: String = "solid.surface"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@VisionBuilder
|
||||
public fun MutableVisionContainer<Solid>.surface(
|
||||
name: String? = null,
|
||||
action: Surface.Builder.() -> Unit = {},
|
||||
): Surface = Surface.Builder().apply(action).build().also { setChild(name, it) }
|
@ -19,7 +19,7 @@ internal fun Solid.updateFrom(other: Solid): Solid {
|
||||
scaleX *= other.scaleX
|
||||
scaleY *= other.scaleY
|
||||
scaleZ *= other.scaleZ
|
||||
properties.setProperty(Name.EMPTY, other.properties.root())
|
||||
properties.setMeta(Name.EMPTY, other.properties.root())
|
||||
return this
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.test.runTest
|
||||
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.*
|
||||
|
@ -24,7 +24,7 @@ public object ThreeLineFactory : ThreeFactory<PolyLine> {
|
||||
}
|
||||
|
||||
val material = ThreeMaterials.getLineMaterial(
|
||||
vision.properties.getProperty(SolidMaterial.MATERIAL_KEY),
|
||||
vision.properties.getMeta(SolidMaterial.MATERIAL_KEY),
|
||||
false
|
||||
)
|
||||
|
||||
|
@ -83,7 +83,7 @@ public object ThreeMaterials {
|
||||
private val visionMaterialCache = HashMap<Vision, Material>()
|
||||
|
||||
internal fun cacheMaterial(vision: Vision): Material = visionMaterialCache.getOrPut(vision) {
|
||||
buildMaterial(vision.properties.getProperty(SolidMaterial.MATERIAL_KEY)).apply {
|
||||
buildMaterial(vision.properties.getMeta(SolidMaterial.MATERIAL_KEY)).apply {
|
||||
cached = true
|
||||
}
|
||||
}
|
||||
@ -133,11 +133,11 @@ public fun Mesh.setMaterial(vision: Vision) {
|
||||
} else {
|
||||
material = vision.parent?.let { parent ->
|
||||
//TODO cache parent material
|
||||
ThreeMaterials.buildMaterial(parent.properties.getProperty(SolidMaterial.MATERIAL_KEY))
|
||||
ThreeMaterials.buildMaterial(parent.properties.getMeta(SolidMaterial.MATERIAL_KEY))
|
||||
} ?: ThreeMaterials.cacheMaterial(vision)
|
||||
}
|
||||
} else {
|
||||
material = ThreeMaterials.buildMaterial(vision.properties.getProperty(SolidMaterial.MATERIAL_KEY))
|
||||
material = ThreeMaterials.buildMaterial(vision.properties.getMeta(SolidMaterial.MATERIAL_KEY))
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,18 +153,18 @@ public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) {
|
||||
when (propertyName) {
|
||||
SolidMaterial.MATERIAL_COLOR_KEY -> {
|
||||
material.asDynamic().color =
|
||||
vision.properties.getProperty(SolidMaterial.MATERIAL_COLOR_KEY).threeColor()
|
||||
vision.properties.getMeta(SolidMaterial.MATERIAL_COLOR_KEY).threeColor()
|
||||
?: ThreeMaterials.DEFAULT_COLOR
|
||||
}
|
||||
|
||||
SolidMaterial.SPECULAR_COLOR_KEY -> {
|
||||
material.asDynamic().specular =
|
||||
vision.properties.getProperty(SolidMaterial.SPECULAR_COLOR_KEY).threeColor()
|
||||
vision.properties.getMeta(SolidMaterial.SPECULAR_COLOR_KEY).threeColor()
|
||||
?: ThreeMaterials.DEFAULT_COLOR
|
||||
}
|
||||
|
||||
SolidMaterial.MATERIAL_EMISSIVE_COLOR_KEY -> {
|
||||
material.asDynamic().emissive = vision.properties.getProperty(SolidMaterial.MATERIAL_EMISSIVE_COLOR_KEY)
|
||||
material.asDynamic().emissive = vision.properties.getMeta(SolidMaterial.MATERIAL_EMISSIVE_COLOR_KEY)
|
||||
.threeColor()
|
||||
?: ThreeMaterials.BLACK_COLOR
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ public fun Mesh.applyEdges(vision: Solid) {
|
||||
val edges = children.find { it.name == EDGES_OBJECT_NAME } as? LineSegments
|
||||
//inherited edges definition, enabled by default
|
||||
if (vision.properties.getValue(EDGES_ENABLED_KEY, inherit = false)?.boolean != false) {
|
||||
val material = ThreeMaterials.getLineMaterial(vision.properties.getProperty(EDGES_MATERIAL_KEY), true)
|
||||
val material = ThreeMaterials.getLineMaterial(vision.properties.getMeta(EDGES_MATERIAL_KEY), true)
|
||||
if (edges == null) {
|
||||
add(
|
||||
LineSegments(
|
||||
|
Loading…
Reference in New Issue
Block a user