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