forked from kscience/visionforge
[WIP] great refactoring in progress
This commit is contained in:
parent
4b1149b99b
commit
791d6d7a81
@ -3,7 +3,7 @@ plugins {
|
|||||||
// id("org.jetbrains.kotlinx.kover") version "0.5.0"
|
// id("org.jetbrains.kotlinx.kover") version "0.5.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
val dataforgeVersion by extra("0.6.0-dev-10")
|
val dataforgeVersion by extra("0.6.0-dev-12")
|
||||||
val fxVersion by extra("11")
|
val fxVersion by extra("11")
|
||||||
|
|
||||||
allprojects{
|
allprojects{
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
package ru.mipt.npm.root
|
package ru.mipt.npm.root
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.double
|
||||||
|
import space.kscience.dataforge.meta.get
|
||||||
|
import space.kscience.dataforge.meta.int
|
||||||
|
import space.kscience.dataforge.meta.isEmpty
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.plus
|
import space.kscience.dataforge.names.plus
|
||||||
import space.kscience.dataforge.values.doubleArray
|
import space.kscience.dataforge.values.doubleArray
|
||||||
import space.kscience.visionforge.isEmpty
|
import space.kscience.visionforge.isEmpty
|
||||||
|
import space.kscience.visionforge.setPropertyValue
|
||||||
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.*
|
import kotlin.math.*
|
||||||
@ -20,7 +24,7 @@ private fun degToRad(d: Double) = d * PI / 180.0
|
|||||||
private data class RootToSolidContext(
|
private data class RootToSolidContext(
|
||||||
val prototypeHolder: PrototypeHolder,
|
val prototypeHolder: PrototypeHolder,
|
||||||
val currentLayer: Int = 0,
|
val currentLayer: Int = 0,
|
||||||
val maxLayer: Int = 5
|
val maxLayer: Int = 5,
|
||||||
)
|
)
|
||||||
|
|
||||||
// converting to XYZ to Tait–Bryan angles according to https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
|
// converting to XYZ to Tait–Bryan angles according to https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
|
||||||
@ -42,14 +46,17 @@ private fun Solid.useMatrix(matrix: DGeoMatrix?) {
|
|||||||
"TGeoIdentity" -> {
|
"TGeoIdentity" -> {
|
||||||
//do nothing
|
//do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
"TGeoTranslation" -> {
|
"TGeoTranslation" -> {
|
||||||
val fTranslation by matrix.meta.doubleArray()
|
val fTranslation by matrix.meta.doubleArray()
|
||||||
translate(fTranslation)
|
translate(fTranslation)
|
||||||
}
|
}
|
||||||
|
|
||||||
"TGeoRotation" -> {
|
"TGeoRotation" -> {
|
||||||
val fRotationMatrix by matrix.meta.doubleArray()
|
val fRotationMatrix by matrix.meta.doubleArray()
|
||||||
rotate(fRotationMatrix)
|
rotate(fRotationMatrix)
|
||||||
}
|
}
|
||||||
|
|
||||||
"TGeoCombiTrans" -> {
|
"TGeoCombiTrans" -> {
|
||||||
val fTranslation by matrix.meta.doubleArray()
|
val fTranslation by matrix.meta.doubleArray()
|
||||||
|
|
||||||
@ -58,6 +65,7 @@ private fun Solid.useMatrix(matrix: DGeoMatrix?) {
|
|||||||
rotate(it.doubleArray)
|
rotate(it.doubleArray)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"TGeoHMatrix" -> {
|
"TGeoHMatrix" -> {
|
||||||
val fTranslation by matrix.meta.doubleArray()
|
val fTranslation by matrix.meta.doubleArray()
|
||||||
val fRotationMatrix by matrix.meta.doubleArray()
|
val fRotationMatrix by matrix.meta.doubleArray()
|
||||||
@ -73,7 +81,7 @@ private fun SolidGroup.addShape(
|
|||||||
shape: DGeoShape,
|
shape: DGeoShape,
|
||||||
context: RootToSolidContext,
|
context: RootToSolidContext,
|
||||||
name: String? = shape.fName.ifEmpty { null },
|
name: String? = shape.fName.ifEmpty { null },
|
||||||
block: Solid.() -> Unit = {}
|
block: Solid.() -> Unit = {},
|
||||||
) {
|
) {
|
||||||
when (shape.typename) {
|
when (shape.typename) {
|
||||||
"TGeoCompositeShape" -> {
|
"TGeoCompositeShape" -> {
|
||||||
@ -94,6 +102,7 @@ private fun SolidGroup.addShape(
|
|||||||
}
|
}
|
||||||
}.apply(block)
|
}.apply(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
"TGeoXtru" -> {
|
"TGeoXtru" -> {
|
||||||
val fNvert by shape.meta.int(0)
|
val fNvert by shape.meta.int(0)
|
||||||
val fX by shape.meta.doubleArray()
|
val fX by shape.meta.doubleArray()
|
||||||
@ -121,6 +130,7 @@ private fun SolidGroup.addShape(
|
|||||||
}
|
}
|
||||||
}.apply(block)
|
}.apply(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
"TGeoTube" -> {
|
"TGeoTube" -> {
|
||||||
val fRmax by shape.meta.double(0.0)
|
val fRmax by shape.meta.double(0.0)
|
||||||
val fDz by shape.meta.double(0.0)
|
val fDz by shape.meta.double(0.0)
|
||||||
@ -134,6 +144,7 @@ private fun SolidGroup.addShape(
|
|||||||
block = block
|
block = block
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
"TGeoTubeSeg" -> {
|
"TGeoTubeSeg" -> {
|
||||||
val fRmax by shape.meta.double(0.0)
|
val fRmax by shape.meta.double(0.0)
|
||||||
val fDz by shape.meta.double(0.0)
|
val fDz by shape.meta.double(0.0)
|
||||||
@ -151,6 +162,7 @@ private fun SolidGroup.addShape(
|
|||||||
block = block
|
block = block
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
"TGeoPcon" -> {
|
"TGeoPcon" -> {
|
||||||
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)
|
||||||
@ -176,6 +188,7 @@ private fun SolidGroup.addShape(
|
|||||||
TODO()
|
TODO()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"TGeoPgon" -> {
|
"TGeoPgon" -> {
|
||||||
//TODO add a inner polygone layer
|
//TODO add a inner polygone layer
|
||||||
val fDphi by shape.meta.double(0.0)
|
val fDphi by shape.meta.double(0.0)
|
||||||
@ -206,15 +219,18 @@ private fun SolidGroup.addShape(
|
|||||||
}
|
}
|
||||||
}.apply(block)
|
}.apply(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
"TGeoShapeAssembly" -> {
|
"TGeoShapeAssembly" -> {
|
||||||
val fVolume by shape.dObject(::DGeoVolume)
|
val fVolume by shape.dObject(::DGeoVolume)
|
||||||
fVolume?.let { volume ->
|
fVolume?.let { volume ->
|
||||||
addRootVolume(volume, context, block = block)
|
addRootVolume(volume, context, block = block)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"TGeoBBox" -> {
|
"TGeoBBox" -> {
|
||||||
box(shape.fDX * 2, shape.fDY * 2, shape.fDZ * 2, name = name, block = block)
|
box(shape.fDX * 2, shape.fDY * 2, shape.fDZ * 2, name = name, block = block)
|
||||||
}
|
}
|
||||||
|
|
||||||
"TGeoTrap" -> {
|
"TGeoTrap" -> {
|
||||||
val fTheta by shape.meta.double(0.0)
|
val fTheta by shape.meta.double(0.0)
|
||||||
val fPhi by shape.meta.double(0.0)
|
val fPhi by shape.meta.double(0.0)
|
||||||
@ -242,6 +258,7 @@ private fun SolidGroup.addShape(
|
|||||||
val node8 = Point3D(-fTl2, fH2, fDz)
|
val node8 = Point3D(-fTl2, fH2, fDz)
|
||||||
hexagon(node1, node2, node3, node4, node5, node6, node7, node8, name)
|
hexagon(node1, node2, node3, node4, node5, node6, node7, node8, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
"TGeoScaledShape" -> {
|
"TGeoScaledShape" -> {
|
||||||
val fShape by shape.dObject(::DGeoShape)
|
val fShape by shape.dObject(::DGeoShape)
|
||||||
val fScale by shape.dObject(::DGeoScale)
|
val fScale by shape.dObject(::DGeoScale)
|
||||||
@ -253,6 +270,7 @@ private fun SolidGroup.addShape(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
TODO("A shape with type ${shape.typename} not implemented")
|
TODO("A shape with type ${shape.typename} not implemented")
|
||||||
}
|
}
|
||||||
@ -267,6 +285,7 @@ private fun SolidGroup.addRootNode(obj: DGeoNode, context: RootToSolidContext) {
|
|||||||
val fMatrix by obj.dObject(::DGeoMatrix)
|
val fMatrix by obj.dObject(::DGeoMatrix)
|
||||||
this.useMatrix(fMatrix)
|
this.useMatrix(fMatrix)
|
||||||
}
|
}
|
||||||
|
|
||||||
"TGeoNodeOffset" -> {
|
"TGeoNodeOffset" -> {
|
||||||
val fOffset by obj.meta.double(0.0)
|
val fOffset by obj.meta.double(0.0)
|
||||||
x = fOffset
|
x = fOffset
|
||||||
@ -301,10 +320,10 @@ private fun buildVolume(volume: DGeoVolume, context: RootToSolidContext): Solid?
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return if (group.isEmpty()) {
|
return if (group.children.isEmpty()) {
|
||||||
null
|
null
|
||||||
} else if (group.children.size == 1 && group.meta.isEmpty()) {
|
} else if (group.items.size == 1 && group.meta.isEmpty()) {
|
||||||
(group.children.values.first() as Solid).apply { parent = null }
|
group.items.values.first().apply { parent = null }
|
||||||
} else {
|
} else {
|
||||||
group
|
group
|
||||||
}
|
}
|
||||||
@ -317,7 +336,7 @@ private fun SolidGroup.addRootVolume(
|
|||||||
context: RootToSolidContext,
|
context: RootToSolidContext,
|
||||||
name: String? = null,
|
name: String? = null,
|
||||||
cache: Boolean = true,
|
cache: Boolean = true,
|
||||||
block: Solid.() -> Unit = {}
|
block: Solid.() -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val combinedName = if (volume.fName.isEmpty()) {
|
val combinedName = if (volume.fName.isEmpty()) {
|
||||||
name
|
name
|
||||||
@ -330,7 +349,7 @@ private fun SolidGroup.addRootVolume(
|
|||||||
if (!cache) {
|
if (!cache) {
|
||||||
val group = buildVolume(volume, context)?.apply {
|
val group = buildVolume(volume, context)?.apply {
|
||||||
volume.fFillColor?.let {
|
volume.fFillColor?.let {
|
||||||
meta[MATERIAL_COLOR_KEY] = RootColors[it]
|
setPropertyValue(MATERIAL_COLOR_KEY, RootColors[it])
|
||||||
}
|
}
|
||||||
block()
|
block()
|
||||||
}
|
}
|
||||||
@ -347,7 +366,7 @@ private fun SolidGroup.addRootVolume(
|
|||||||
|
|
||||||
ref(templateName, name).apply {
|
ref(templateName, name).apply {
|
||||||
volume.fFillColor?.let {
|
volume.fFillColor?.let {
|
||||||
meta[MATERIAL_COLOR_KEY] = RootColors[it]
|
setPropertyValue(MATERIAL_COLOR_KEY, RootColors[it])
|
||||||
}
|
}
|
||||||
block()
|
block()
|
||||||
}
|
}
|
||||||
|
@ -160,7 +160,7 @@ private fun SolidGroup.volume(volume: TGeoVolume, name: String? = null, cache: B
|
|||||||
name = combinedName,
|
name = combinedName,
|
||||||
obj = group,
|
obj = group,
|
||||||
prototypeHolder = rootPrototypes,
|
prototypeHolder = rootPrototypes,
|
||||||
templateName = volumesName + Name.parse(combinedName ?: "volume[${group.hashCode()}]")
|
prototypeName = volumesName + Name.parse(combinedName ?: "volume[${group.hashCode()}]")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
package space.kscience.visionforge.gdml
|
package space.kscience.visionforge.gdml
|
||||||
|
|
||||||
|
import space.kscience.dataforge.meta.string
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.values.asValue
|
import space.kscience.dataforge.values.asValue
|
||||||
import space.kscience.dataforge.values.string
|
|
||||||
import space.kscience.gdml.GdmlShowCase
|
import space.kscience.gdml.GdmlShowCase
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.computeProperties
|
|
||||||
import space.kscience.visionforge.get
|
import space.kscience.visionforge.get
|
||||||
import space.kscience.visionforge.setProperty
|
import space.kscience.visionforge.getProperty
|
||||||
|
import space.kscience.visionforge.getPropertyValue
|
||||||
import space.kscience.visionforge.solid.Solid
|
import space.kscience.visionforge.solid.Solid
|
||||||
import space.kscience.visionforge.solid.SolidMaterial
|
import space.kscience.visionforge.solid.SolidMaterial
|
||||||
import space.kscience.visionforge.solid.material
|
import space.kscience.visionforge.solid.material
|
||||||
@ -20,8 +20,8 @@ class GDMLVisionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testCubesStyles(){
|
fun testCubesStyles(){
|
||||||
val segment = cubes["composite-000.segment-0"] as Solid
|
val segment = cubes.children["composite-000.segment-0"] as Solid
|
||||||
println(segment.computeProperties().getValue(Vision.STYLE_KEY))
|
println(segment.getPropertyValue(Vision.STYLE_KEY))
|
||||||
// println(segment.computePropertyNode(SolidMaterial.MATERIAL_KEY))
|
// println(segment.computePropertyNode(SolidMaterial.MATERIAL_KEY))
|
||||||
// println(segment.computeProperty(SolidMaterial.MATERIAL_COLOR_KEY))
|
// println(segment.computeProperty(SolidMaterial.MATERIAL_COLOR_KEY))
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ class GDMLVisionTest {
|
|||||||
fun testPrototypeProperty() {
|
fun testPrototypeProperty() {
|
||||||
val child = cubes[Name.of("composite-000","segment-0")]
|
val child = cubes[Name.of("composite-000","segment-0")]
|
||||||
assertNotNull(child)
|
assertNotNull(child)
|
||||||
child.setProperty(SolidMaterial.MATERIAL_COLOR_KEY, "red".asValue())
|
child.setPropertyValue(SolidMaterial.MATERIAL_COLOR_KEY, "red".asValue())
|
||||||
assertEquals("red", child.getPropertyValue(SolidMaterial.MATERIAL_COLOR_KEY)?.string)
|
assertEquals("red", child.getProperty(SolidMaterial.MATERIAL_COLOR_KEY).string)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -26,7 +26,6 @@ import space.kscience.visionforge.setAsRoot
|
|||||||
import space.kscience.visionforge.solid.Solid
|
import space.kscience.visionforge.solid.Solid
|
||||||
import space.kscience.visionforge.solid.Solids
|
import space.kscience.visionforge.solid.Solids
|
||||||
import space.kscience.visionforge.solid.ambientLight
|
import space.kscience.visionforge.solid.ambientLight
|
||||||
import space.kscience.visionforge.solid.invoke
|
|
||||||
import styled.css
|
import styled.css
|
||||||
import styled.styledDiv
|
import styled.styledDiv
|
||||||
|
|
||||||
|
@ -10,7 +10,6 @@ import space.kscience.visionforge.Colors
|
|||||||
import space.kscience.visionforge.gdml.toVision
|
import space.kscience.visionforge.gdml.toVision
|
||||||
import space.kscience.visionforge.react.render
|
import space.kscience.visionforge.react.render
|
||||||
import space.kscience.visionforge.solid.ambientLight
|
import space.kscience.visionforge.solid.ambientLight
|
||||||
import space.kscience.visionforge.solid.invoke
|
|
||||||
import space.kscience.visionforge.solid.three.ThreePlugin
|
import space.kscience.visionforge.solid.three.ThreePlugin
|
||||||
import space.kscience.visionforge.startApplication
|
import space.kscience.visionforge.startApplication
|
||||||
import styled.injectGlobal
|
import styled.injectGlobal
|
||||||
|
@ -75,7 +75,7 @@ private class JsPlaygroundApp : Application {
|
|||||||
context = playgroundContext
|
context = playgroundContext
|
||||||
solid {
|
solid {
|
||||||
ambientLight {
|
ambientLight {
|
||||||
color(Colors.white)
|
color.set(Colors.white)
|
||||||
}
|
}
|
||||||
repeat(100) {
|
repeat(100) {
|
||||||
sphere(5, name = "sphere[$it]") {
|
sphere(5, name = "sphere[$it]") {
|
||||||
@ -83,7 +83,7 @@ private class JsPlaygroundApp : Application {
|
|||||||
y = random.nextDouble(-300.0, 300.0)
|
y = random.nextDouble(-300.0, 300.0)
|
||||||
z = random.nextDouble(-300.0, 300.0)
|
z = random.nextDouble(-300.0, 300.0)
|
||||||
material {
|
material {
|
||||||
color(random.nextInt())
|
color.set(random.nextInt())
|
||||||
}
|
}
|
||||||
detail = 16
|
detail = 16
|
||||||
}
|
}
|
||||||
|
@ -43,13 +43,13 @@ val GravityDemo = fc<DemoProps> { props ->
|
|||||||
context = props.context
|
context = props.context
|
||||||
solid {
|
solid {
|
||||||
pointLight(200, 200, 200, name = "light"){
|
pointLight(200, 200, 200, name = "light"){
|
||||||
color(Colors.white)
|
color.set(Colors.white)
|
||||||
}
|
}
|
||||||
ambientLight()
|
ambientLight()
|
||||||
|
|
||||||
sphere(5.0, "ball") {
|
sphere(5.0, "ball") {
|
||||||
detail = 16
|
detail = 16
|
||||||
color("red")
|
color.set("red")
|
||||||
val h = 100.0
|
val h = 100.0
|
||||||
y = h
|
y = h
|
||||||
context.launch {
|
context.launch {
|
||||||
|
@ -3,24 +3,18 @@ package ru.mipt.npm.muon.monitor
|
|||||||
import ru.mipt.npm.muon.monitor.Monitor.CENTRAL_LAYER_Z
|
import ru.mipt.npm.muon.monitor.Monitor.CENTRAL_LAYER_Z
|
||||||
import ru.mipt.npm.muon.monitor.Monitor.LOWER_LAYER_Z
|
import ru.mipt.npm.muon.monitor.Monitor.LOWER_LAYER_Z
|
||||||
import ru.mipt.npm.muon.monitor.Monitor.UPPER_LAYER_Z
|
import ru.mipt.npm.muon.monitor.Monitor.UPPER_LAYER_Z
|
||||||
|
import space.kscience.visionforge.VisionContainerBuilder
|
||||||
import space.kscience.visionforge.VisionManager
|
import space.kscience.visionforge.VisionManager
|
||||||
import space.kscience.visionforge.removeAll
|
|
||||||
import space.kscience.visionforge.setAsRoot
|
import space.kscience.visionforge.setAsRoot
|
||||||
import space.kscience.visionforge.setProperty
|
|
||||||
import space.kscience.visionforge.solid.*
|
import space.kscience.visionforge.solid.*
|
||||||
import kotlin.collections.HashMap
|
|
||||||
import kotlin.collections.HashSet
|
|
||||||
import kotlin.collections.filter
|
|
||||||
import kotlin.collections.forEach
|
|
||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
import kotlin.collections.toTypedArray
|
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
|
|
||||||
class Model(val manager: VisionManager) {
|
class Model(val manager: VisionManager) {
|
||||||
private val map = HashMap<String, SolidGroup>()
|
private val map = HashMap<String, SolidGroup>()
|
||||||
private val events = HashSet<Event>()
|
private val events = HashSet<Event>()
|
||||||
|
|
||||||
private fun SolidGroup.pixel(pixel: SC1) {
|
private fun VisionContainerBuilder<Solid>.pixel(pixel: SC1) {
|
||||||
val group = group(pixel.name) {
|
val group = group(pixel.name) {
|
||||||
position = Point3D(pixel.center.x, pixel.center.y, pixel.center.z)
|
position = Point3D(pixel.center.x, pixel.center.y, pixel.center.z)
|
||||||
box(pixel.xSize, pixel.ySize, pixel.zSize)
|
box(pixel.xSize, pixel.ySize, pixel.zSize)
|
||||||
@ -45,7 +39,7 @@ class Model(val manager: VisionManager) {
|
|||||||
val root: SolidGroup = SolidGroup().apply {
|
val root: SolidGroup = SolidGroup().apply {
|
||||||
setAsRoot(this@Model.manager)
|
setAsRoot(this@Model.manager)
|
||||||
material {
|
material {
|
||||||
color("darkgreen")
|
color.set("darkgreen")
|
||||||
}
|
}
|
||||||
rotationX = PI / 2
|
rotationX = PI / 2
|
||||||
group("bottom") {
|
group("bottom") {
|
||||||
@ -70,14 +64,14 @@ class Model(val manager: VisionManager) {
|
|||||||
|
|
||||||
private fun highlight(pixel: String) {
|
private fun highlight(pixel: String) {
|
||||||
println("highlight $pixel")
|
println("highlight $pixel")
|
||||||
map[pixel]?.color?.invoke("blue")
|
map[pixel]?.color.set("blue")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun reset() {
|
fun reset() {
|
||||||
map.values.forEach {
|
map.values.forEach {
|
||||||
it.setProperty(SolidMaterial.MATERIAL_COLOR_KEY, null)
|
it.setPropertyValue(SolidMaterial.MATERIAL_COLOR_KEY, null)
|
||||||
}
|
}
|
||||||
tracks.removeAll()
|
tracks.children.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun displayEvent(event: Event) {
|
fun displayEvent(event: Event) {
|
||||||
@ -89,7 +83,7 @@ class Model(val manager: VisionManager) {
|
|||||||
event.track?.let {
|
event.track?.let {
|
||||||
tracks.polyline(*it.toTypedArray(), name = "track[${event.id}]") {
|
tracks.polyline(*it.toTypedArray(), name = "track[${event.id}]") {
|
||||||
thickness = 4
|
thickness = 4
|
||||||
color("red")
|
color.set("red")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,6 @@ import space.kscience.visionforge.react.flexRow
|
|||||||
import space.kscience.visionforge.ring.ThreeCanvasWithControls
|
import space.kscience.visionforge.ring.ThreeCanvasWithControls
|
||||||
import space.kscience.visionforge.ring.tab
|
import space.kscience.visionforge.ring.tab
|
||||||
import space.kscience.visionforge.solid.ambientLight
|
import space.kscience.visionforge.solid.ambientLight
|
||||||
import space.kscience.visionforge.solid.invoke
|
|
||||||
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
||||||
import space.kscience.visionforge.solid.three.edges
|
import space.kscience.visionforge.solid.three.edges
|
||||||
import styled.css
|
import styled.css
|
||||||
|
@ -7,7 +7,7 @@ import space.kscience.visionforge.gdml.toVision
|
|||||||
import space.kscience.visionforge.html.ResourceLocation
|
import space.kscience.visionforge.html.ResourceLocation
|
||||||
import space.kscience.visionforge.solid.Solids
|
import space.kscience.visionforge.solid.Solids
|
||||||
import space.kscience.visionforge.solid.color
|
import space.kscience.visionforge.solid.color
|
||||||
import space.kscience.visionforge.solid.invoke
|
import space.kscience.visionforge.solid.set
|
||||||
import space.kscience.visionforge.visible
|
import space.kscience.visionforge.visible
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
|
||||||
@ -229,7 +229,7 @@ fun main() = makeVisionFile(Path.of("curves.html"), resourceLocation = ResourceL
|
|||||||
visible = false
|
visible = false
|
||||||
}
|
}
|
||||||
if(solid.name.startsWith("gas")){
|
if(solid.name.startsWith("gas")){
|
||||||
color("green")
|
color.set("green")
|
||||||
} else {
|
} else {
|
||||||
//make all solids semi-transparent
|
//make all solids semi-transparent
|
||||||
transparent()
|
transparent()
|
||||||
|
@ -5,7 +5,7 @@ import space.kscience.visionforge.Colors
|
|||||||
import space.kscience.visionforge.gdml.gdml
|
import space.kscience.visionforge.gdml.gdml
|
||||||
import space.kscience.visionforge.solid.Solids
|
import space.kscience.visionforge.solid.Solids
|
||||||
import space.kscience.visionforge.solid.ambientLight
|
import space.kscience.visionforge.solid.ambientLight
|
||||||
import space.kscience.visionforge.solid.invoke
|
import space.kscience.visionforge.solid.set
|
||||||
import space.kscience.visionforge.solid.solid
|
import space.kscience.visionforge.solid.solid
|
||||||
|
|
||||||
fun main() = makeVisionFile {
|
fun main() = makeVisionFile {
|
||||||
@ -13,7 +13,7 @@ fun main() = makeVisionFile {
|
|||||||
requirePlugin(Solids)
|
requirePlugin(Solids)
|
||||||
solid {
|
solid {
|
||||||
ambientLight {
|
ambientLight {
|
||||||
color(Colors.white)
|
color.set(Colors.white)
|
||||||
}
|
}
|
||||||
gdml(GdmlShowCase.babyIaxo(), "D0")
|
gdml(GdmlShowCase.babyIaxo(), "D0")
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ fun main() = makeVisionFile(
|
|||||||
vision {
|
vision {
|
||||||
solid {
|
solid {
|
||||||
ambientLight {
|
ambientLight {
|
||||||
color(Colors.white)
|
color.set(Colors.white)
|
||||||
}
|
}
|
||||||
repeat(100) {
|
repeat(100) {
|
||||||
sphere(5, name = "sphere[$it]") {
|
sphere(5, name = "sphere[$it]") {
|
||||||
@ -27,7 +27,7 @@ fun main() = makeVisionFile(
|
|||||||
y = random.nextDouble(-300.0, 300.0)
|
y = random.nextDouble(-300.0, 300.0)
|
||||||
z = random.nextDouble(-300.0, 300.0)
|
z = random.nextDouble(-300.0, 300.0)
|
||||||
material {
|
material {
|
||||||
color(random.nextInt())
|
color.set(random.nextInt())
|
||||||
}
|
}
|
||||||
detail = 16
|
detail = 16
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,8 @@ package space.kscience.visionforge.examples
|
|||||||
|
|
||||||
import space.kscience.visionforge.html.ResourceLocation
|
import space.kscience.visionforge.html.ResourceLocation
|
||||||
import space.kscience.visionforge.solid.box
|
import space.kscience.visionforge.solid.box
|
||||||
import space.kscience.visionforge.solid.invoke
|
|
||||||
import space.kscience.visionforge.solid.material
|
import space.kscience.visionforge.solid.material
|
||||||
|
import space.kscience.visionforge.solid.set
|
||||||
import space.kscience.visionforge.solid.solid
|
import space.kscience.visionforge.solid.solid
|
||||||
|
|
||||||
fun main() = makeVisionFile(resourceLocation = ResourceLocation.SYSTEM) {
|
fun main() = makeVisionFile(resourceLocation = ResourceLocation.SYSTEM) {
|
||||||
@ -11,7 +11,7 @@ fun main() = makeVisionFile(resourceLocation = ResourceLocation.SYSTEM) {
|
|||||||
solid {
|
solid {
|
||||||
box(100, 100, 100)
|
box(100, 100, 100)
|
||||||
material {
|
material {
|
||||||
emissiveColor("red")
|
emissiveColor.set("red")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ internal fun visionOfSatellite(
|
|||||||
ySegmentSize: Number = xSegmentSize,
|
ySegmentSize: Number = xSegmentSize,
|
||||||
fiberDiameter: Number = 1.0,
|
fiberDiameter: Number = 1.0,
|
||||||
): SolidGroup = SolidGroup {
|
): SolidGroup = SolidGroup {
|
||||||
color("darkgreen")
|
color.set("darkgreen")
|
||||||
val transparent by style {
|
val transparent by style {
|
||||||
this[SolidMaterial.MATERIAL_OPACITY_KEY] = 0.3
|
this[SolidMaterial.MATERIAL_OPACITY_KEY] = 0.3
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ fun main() {
|
|||||||
val randomJ = Random.nextInt(1, 4)
|
val randomJ = Random.nextInt(1, 4)
|
||||||
val target = Name.parse("layer[$randomLayer].segment[$randomI,$randomJ]")
|
val target = Name.parse("layer[$randomLayer].segment[$randomI,$randomJ]")
|
||||||
val targetVision = sat[target] as Solid
|
val targetVision = sat[target] as Solid
|
||||||
targetVision.color("red")
|
targetVision.color.set("red")
|
||||||
delay(1000)
|
delay(1000)
|
||||||
targetVision.color.clear()
|
targetVision.color.clear()
|
||||||
delay(500)
|
delay(500)
|
||||||
|
@ -20,7 +20,7 @@ fun VisionLayout<Solid>.demo(name: String, title: String = name, block: SolidGro
|
|||||||
}
|
}
|
||||||
val vision = SolidGroup(block).apply {
|
val vision = SolidGroup(block).apply {
|
||||||
ambientLight{
|
ambientLight{
|
||||||
color(Colors.white)
|
color.set(Colors.white)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
render(Name.parse(name), vision, meta)
|
render(Name.parse(name), vision, meta)
|
||||||
@ -46,23 +46,23 @@ fun VisionLayout<Solid>.showcase() {
|
|||||||
ambientLight()
|
ambientLight()
|
||||||
box(100.0, 100.0, 100.0) {
|
box(100.0, 100.0, 100.0) {
|
||||||
z = -110.0
|
z = -110.0
|
||||||
color("teal")
|
color.set("teal")
|
||||||
}
|
}
|
||||||
sphere(50.0) {
|
sphere(50.0) {
|
||||||
x = 110
|
x = 110
|
||||||
detail = 16
|
detail = 16
|
||||||
color("red")
|
color.set("red")
|
||||||
}
|
}
|
||||||
tube(50, height = 10, innerRadius = 25, angle = PI) {
|
tube(50, height = 10, innerRadius = 25, angle = PI) {
|
||||||
y = 110
|
y = 110
|
||||||
detail = 16
|
detail = 16
|
||||||
rotationX = PI / 4
|
rotationX = PI / 4
|
||||||
color("blue")
|
color.set("blue")
|
||||||
}
|
}
|
||||||
sphereLayer(50, 40, theta = PI / 2) {
|
sphereLayer(50, 40, theta = PI / 2) {
|
||||||
rotationX = -PI * 3 / 4
|
rotationX = -PI * 3 / 4
|
||||||
z = 110
|
z = 110
|
||||||
color(Colors.pink)
|
color.set(Colors.pink)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ fun VisionLayout<Solid>.showcase() {
|
|||||||
visible = false
|
visible = false
|
||||||
x = 110.0
|
x = 110.0
|
||||||
//override color for this cube
|
//override color for this cube
|
||||||
color(1530)
|
color.set(1530)
|
||||||
|
|
||||||
GlobalScope.launch(Dispatchers.Main) {
|
GlobalScope.launch(Dispatchers.Main) {
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
@ -92,7 +92,7 @@ fun VisionLayout<Solid>.showcase() {
|
|||||||
val random = Random(111)
|
val random = Random(111)
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
delay(1000)
|
delay(1000)
|
||||||
group.color(random.nextInt(0, Int.MAX_VALUE))
|
group.color.set(random.nextInt(0, Int.MAX_VALUE))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,7 +104,7 @@ fun VisionLayout<Solid>.showcase() {
|
|||||||
rotationY = PI / 4
|
rotationY = PI / 4
|
||||||
box(100, 100, 100) {
|
box(100, 100, 100) {
|
||||||
rotationZ = PI / 4
|
rotationZ = PI / 4
|
||||||
color(Colors.red)
|
color.set(Colors.red)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -117,7 +117,7 @@ fun VisionLayout<Solid>.showcase() {
|
|||||||
for (i in 0..100) {
|
for (i in 0..100) {
|
||||||
layer(i * 5, 20 * sin(2 * PI / 100 * i), 20 * cos(2 * PI / 100 * i))
|
layer(i * 5, 20 * sin(2 * PI / 100 * i), 20 * cos(2 * PI / 100 * i))
|
||||||
}
|
}
|
||||||
color(Colors.teal)
|
color.set(Colors.teal)
|
||||||
rotationX = -PI / 2
|
rotationX = -PI / 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -126,13 +126,13 @@ fun VisionLayout<Solid>.showcase() {
|
|||||||
sphere(100) {
|
sphere(100) {
|
||||||
detail = 32
|
detail = 32
|
||||||
opacity = 0.4
|
opacity = 0.4
|
||||||
color(Colors.blue)
|
color.set(Colors.blue)
|
||||||
}
|
}
|
||||||
repeat(20) {
|
repeat(20) {
|
||||||
polyline(Point3D(100, 100, 100), Point3D(-100, -100, -100)) {
|
polyline(Point3D(100, 100, 100), Point3D(-100, -100, -100)) {
|
||||||
thickness = 3.0
|
thickness = 3.0
|
||||||
rotationX = it * PI2 / 20
|
rotationX = it * PI2 / 20
|
||||||
color(Colors.green)
|
color.set(Colors.green)
|
||||||
//rotationY = it * PI2 / 20
|
//rotationY = it * PI2 / 20
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -159,7 +159,7 @@ fun VisionLayout<Solid>.showcaseCSG() {
|
|||||||
detail = 32
|
detail = 32
|
||||||
}
|
}
|
||||||
material {
|
material {
|
||||||
color(Colors.pink)
|
color.set(Colors.pink)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
composite(CompositeType.UNION) {
|
composite(CompositeType.UNION) {
|
||||||
@ -169,7 +169,7 @@ fun VisionLayout<Solid>.showcaseCSG() {
|
|||||||
sphere(50) {
|
sphere(50) {
|
||||||
detail = 32
|
detail = 32
|
||||||
}
|
}
|
||||||
color("lightgreen")
|
color.set("lightgreen")
|
||||||
opacity = 0.7
|
opacity = 0.7
|
||||||
}
|
}
|
||||||
composite(CompositeType.SUBTRACT) {
|
composite(CompositeType.SUBTRACT) {
|
||||||
@ -180,7 +180,7 @@ fun VisionLayout<Solid>.showcaseCSG() {
|
|||||||
sphere(50) {
|
sphere(50) {
|
||||||
detail = 32
|
detail = 32
|
||||||
}
|
}
|
||||||
color("teal")
|
color.set("teal")
|
||||||
opacity = 0.7
|
opacity = 0.7
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -191,7 +191,7 @@ fun VisionLayout<Solid>.showcaseCSG() {
|
|||||||
detail = 32
|
detail = 32
|
||||||
}
|
}
|
||||||
box(100, 100, 100)
|
box(100, 100, 100)
|
||||||
color("red")
|
color.set("red")
|
||||||
opacity = 0.5
|
opacity = 0.5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,6 @@ import space.kscience.dataforge.names.startsWith
|
|||||||
import space.kscience.dataforge.values.asValue
|
import space.kscience.dataforge.values.asValue
|
||||||
import space.kscience.visionforge.onPropertyChange
|
import space.kscience.visionforge.onPropertyChange
|
||||||
import space.kscience.visionforge.set
|
import space.kscience.visionforge.set
|
||||||
import space.kscience.visionforge.setProperty
|
|
||||||
import space.kscience.visionforge.solid.SolidGroup
|
import space.kscience.visionforge.solid.SolidGroup
|
||||||
import space.kscience.visionforge.solid.layer
|
import space.kscience.visionforge.solid.layer
|
||||||
import space.kscience.visionforge.solid.three.*
|
import space.kscience.visionforge.solid.three.*
|
||||||
@ -72,7 +71,7 @@ internal class VariableBox(val xSize: Number, val ySize: Number) : ThreeJsVision
|
|||||||
var value: Int
|
var value: Int
|
||||||
get() = meta[VALUE].int ?: 0
|
get() = meta[VALUE].int ?: 0
|
||||||
set(value) {
|
set(value) {
|
||||||
setProperty(VALUE, value.asValue())
|
setPropertyValue(VALUE, value.asValue())
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
![](../docs/images/hierarchy.png)
|
![](../docs/images/hierarchy.png)
|
||||||
|
|
||||||
### Vision
|
### Vision
|
||||||
* function `getPropertyValue(name: Name, inherit: Boolean = false, includeStyles: Boolean = true, includeDefaults: Boolean = true)` - get property value with given layer flags.
|
* function `getProperty(name: Name, inherit: Boolean = false, includeStyles: Boolean = true, includeDefaults: Boolean = true)` - get property value with given layer flags.
|
||||||
|
|
||||||
* function `setProperty(name: Name, item: Any?)` - a convenient method to set property node or value. If `item` is null, then node is removed, not a value
|
* function `setProperty(name: Name, item: Any?)` - a convenient method to set property node or value. If `item` is null, then node is removed, not a value
|
||||||
Sets the `item` property to the element with the `name` identification.
|
Sets the `item` property to the element with the `name` identification.
|
||||||
|
@ -7,7 +7,7 @@ Properties, which can be inherited by objects, are `styles`, `prototypes` (if th
|
|||||||
All values of `styles` property are contained in class `StyleSheet`, where they all are defined at `Group`s level. The `prototypes` property tree is defined in `SolidGroup` class via `PrototypeHolder` interface, and
|
All values of `styles` property are contained in class `StyleSheet`, where they all are defined at `Group`s level. The `prototypes` property tree is defined in `SolidGroup` class via `PrototypeHolder` interface, and
|
||||||
`SolidReference` class helps to reuse a template object.
|
`SolidReference` class helps to reuse a template object.
|
||||||
|
|
||||||
The order of inheritance of properties is set in function `getPropertyValue` in `VisionBase` class.
|
The order of inheritance of properties is set in function `getProperty` in `VisionBase` class.
|
||||||
The order is this:
|
The order is this:
|
||||||
* own styles
|
* own styles
|
||||||
* prototypes
|
* prototypes
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
interface Vision{
|
interface Vision{
|
||||||
val parent: VisionGroup?
|
val parent: VisionGroup?
|
||||||
fun getPropertyValue(name,inherit,includeStyles,includeDefaults): Value?
|
fun getProperty(name,inherit,includeStyles,includeDefaults): Value?
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Solid{
|
interface Solid{
|
||||||
@ -81,7 +81,7 @@ Solid <--- Composite
|
|||||||
|
|
||||||
interface SolidReference{
|
interface SolidReference{
|
||||||
val prototype: Solid
|
val prototype: Solid
|
||||||
fun getPropertyValue(name,inherit,includeStyles,includeDefaults): Value?
|
fun getProperty(name,inherit,includeStyles,includeDefaults): Value?
|
||||||
}
|
}
|
||||||
VisionGroup <---- SolidReference
|
VisionGroup <---- SolidReference
|
||||||
SolidReferenceGroup -- SolidReference
|
SolidReferenceGroup -- SolidReference
|
||||||
@ -91,7 +91,7 @@ class SolidReferenceGroup{
|
|||||||
var properties: MutableMeta?
|
var properties: MutableMeta?
|
||||||
val prototype: Solid
|
val prototype: Solid
|
||||||
val children: Map<NameToken, Vision>
|
val children: Map<NameToken, Vision>
|
||||||
fun getPropertyValue(name,inherit,includeStyles,includeDefaults): Value?
|
fun getProperty(name,inherit,includeStyles,includeDefaults): Value?
|
||||||
}
|
}
|
||||||
VisionBase <-- SolidReferenceGroup
|
VisionBase <-- SolidReferenceGroup
|
||||||
VisionGroup <-- SolidReferenceGroup
|
VisionGroup <-- SolidReferenceGroup
|
||||||
|
@ -6,4 +6,4 @@ kotlin.jupyter.add.scanner=false
|
|||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
org.gradle.jvmargs=-Xmx4G
|
org.gradle.jvmargs=-Xmx4G
|
||||||
|
|
||||||
toolsVersion=0.11.7-kotlin-1.7.0
|
toolsVersion=0.11.8-kotlin-1.7.10
|
@ -10,8 +10,8 @@ import react.fc
|
|||||||
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.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.VisionGroup
|
|
||||||
import space.kscience.visionforge.react.visionTree
|
import space.kscience.visionforge.react.visionTree
|
||||||
|
import space.kscience.visionforge.solid.SolidGroup
|
||||||
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
||||||
import styled.css
|
import styled.css
|
||||||
import styled.styledDiv
|
import styled.styledDiv
|
||||||
@ -51,7 +51,7 @@ public val ThreeControls: FC<ThreeControlsProps> = fc { props ->
|
|||||||
val selectedObject: Vision? = when {
|
val selectedObject: Vision? = when {
|
||||||
selected == null -> null
|
selected == null -> null
|
||||||
selected.isEmpty() -> props.vision
|
selected.isEmpty() -> props.vision
|
||||||
else -> (props.vision as? VisionGroup)?.get(selected)
|
else -> (props.vision as? SolidGroup)?.get(selected)
|
||||||
}
|
}
|
||||||
if (selectedObject != null) {
|
if (selectedObject != null) {
|
||||||
visionPropertyEditor(selectedObject, key = selected)
|
visionPropertyEditor(selectedObject, key = selected)
|
||||||
|
@ -2,13 +2,14 @@ package space.kscience.visionforge.bootstrap
|
|||||||
|
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
import react.RBuilder
|
import react.RBuilder
|
||||||
import react.dom.render
|
import react.dom.client.createRoot
|
||||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.computeProperties
|
import space.kscience.visionforge.computeProperties
|
||||||
import space.kscience.visionforge.getStyle
|
import space.kscience.visionforge.getStyle
|
||||||
import space.kscience.visionforge.react.metaViewer
|
import space.kscience.visionforge.react.metaViewer
|
||||||
import space.kscience.visionforge.react.propertyEditor
|
import space.kscience.visionforge.react.propertyEditor
|
||||||
|
import space.kscience.visionforge.react.render
|
||||||
import space.kscience.visionforge.solid.SolidReference
|
import space.kscience.visionforge.solid.SolidReference
|
||||||
import space.kscience.visionforge.styles
|
import space.kscience.visionforge.styles
|
||||||
|
|
||||||
@ -50,6 +51,6 @@ public fun RBuilder.visionPropertyEditor(
|
|||||||
public fun Element.visionPropertyEditor(
|
public fun Element.visionPropertyEditor(
|
||||||
item: Vision,
|
item: Vision,
|
||||||
descriptor: MetaDescriptor? = item.descriptor,
|
descriptor: MetaDescriptor? = item.descriptor,
|
||||||
): Unit = render(this) {
|
): Unit = createRoot(this).render {
|
||||||
visionPropertyEditor(item, descriptor = descriptor)
|
visionPropertyEditor(item, descriptor = descriptor)
|
||||||
}
|
}
|
@ -59,9 +59,9 @@ private fun RBuilder.visionTree(props: ObjectTreeProps): Unit {
|
|||||||
val obj = props.obj
|
val obj = props.obj
|
||||||
|
|
||||||
//display as node if any child is visible
|
//display as node if any child is visible
|
||||||
if (obj is VisionGroup) {
|
if (obj is VisionGroup<*>) {
|
||||||
flexRow {
|
flexRow {
|
||||||
if (obj.children.any { !it.key.body.startsWith("@") }) {
|
if (obj.items.any { !it.key.body.startsWith("@") }) {
|
||||||
styledSpan {
|
styledSpan {
|
||||||
css {
|
css {
|
||||||
+TreeStyles.treeCaret
|
+TreeStyles.treeCaret
|
||||||
@ -81,9 +81,9 @@ private fun RBuilder.visionTree(props: ObjectTreeProps): Unit {
|
|||||||
css {
|
css {
|
||||||
+TreeStyles.tree
|
+TreeStyles.tree
|
||||||
}
|
}
|
||||||
obj.children.entries
|
obj.items.entries
|
||||||
.filter { !it.key.toString().startsWith("@") } // ignore statics and other hidden children
|
.filter { !it.key.toString().startsWith("@") } // ignore statics and other hidden children
|
||||||
.sortedBy { (it.value as? VisionGroup)?.isEmpty() ?: true } // ignore empty groups
|
.sortedBy { (it.value as? VisionGroup<*>)?.isEmpty() ?: true } // ignore empty groups
|
||||||
.forEach { (childToken, child) ->
|
.forEach { (childToken, child) ->
|
||||||
styledDiv {
|
styledDiv {
|
||||||
css {
|
css {
|
||||||
@ -92,7 +92,7 @@ private fun RBuilder.visionTree(props: ObjectTreeProps): Unit {
|
|||||||
child(ObjectTree) {
|
child(ObjectTree) {
|
||||||
attrs {
|
attrs {
|
||||||
this.name = props.name + childToken
|
this.name = props.name + childToken
|
||||||
this.obj = child
|
this.obj = child.vision
|
||||||
this.selected = props.selected
|
this.selected = props.selected
|
||||||
this.clickCallback = props.clickCallback
|
this.clickCallback = props.clickCallback
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ public val ThreeCanvasWithControls: FC<ThreeCanvasWithControlsProps> = fc("Three
|
|||||||
selected?.let {
|
selected?.let {
|
||||||
when {
|
when {
|
||||||
it.isEmpty() -> solid
|
it.isEmpty() -> solid
|
||||||
else -> (solid as? VisionGroup)?.get(it)
|
else -> (solid as? SolidGroup)?.get(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -165,7 +165,7 @@ public val ThreeCanvasWithControls: FC<ThreeCanvasWithControlsProps> = fc("Three
|
|||||||
}
|
}
|
||||||
IslandContent {
|
IslandContent {
|
||||||
propertyEditor(
|
propertyEditor(
|
||||||
ownProperties = vision.meta,
|
ownProperties = vision.properties(),
|
||||||
allProperties = vision.computeProperties(),
|
allProperties = vision.computeProperties(),
|
||||||
descriptor = vision.descriptor,
|
descriptor = vision.descriptor,
|
||||||
key = selected
|
key = selected
|
||||||
|
@ -183,7 +183,7 @@ public class space/kscience/visionforge/SimpleVisionPropertyContainer : space/ks
|
|||||||
public fun <init> (Lspace/kscience/dataforge/meta/ObservableMutableMeta;)V
|
public fun <init> (Lspace/kscience/dataforge/meta/ObservableMutableMeta;)V
|
||||||
public synthetic fun getMeta ()Lspace/kscience/dataforge/meta/MutableMeta;
|
public synthetic fun getMeta ()Lspace/kscience/dataforge/meta/MutableMeta;
|
||||||
public fun getMeta ()Lspace/kscience/dataforge/meta/ObservableMutableMeta;
|
public fun getMeta ()Lspace/kscience/dataforge/meta/ObservableMutableMeta;
|
||||||
public fun getPropertyValue (Lspace/kscience/dataforge/names/Name;ZZZ)Lspace/kscience/dataforge/values/Value;
|
public fun getProperty (Lspace/kscience/dataforge/names/Name;ZZZ)Lspace/kscience/dataforge/values/Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class space/kscience/visionforge/StyleReference {
|
public final class space/kscience/visionforge/StyleReference {
|
||||||
@ -241,8 +241,8 @@ public abstract interface class space/kscience/visionforge/Vision : space/kscien
|
|||||||
public fun getManager ()Lspace/kscience/visionforge/VisionManager;
|
public fun getManager ()Lspace/kscience/visionforge/VisionManager;
|
||||||
public abstract fun getMeta ()Lspace/kscience/dataforge/meta/ObservableMutableMeta;
|
public abstract fun getMeta ()Lspace/kscience/dataforge/meta/ObservableMutableMeta;
|
||||||
public abstract fun getParent ()Lspace/kscience/visionforge/VisionGroup;
|
public abstract fun getParent ()Lspace/kscience/visionforge/VisionGroup;
|
||||||
public abstract fun getPropertyValue (Lspace/kscience/dataforge/names/Name;ZZZ)Lspace/kscience/dataforge/values/Value;
|
public abstract fun getProperty (Lspace/kscience/dataforge/names/Name;ZZZ)Lspace/kscience/dataforge/values/Value;
|
||||||
public static synthetic fun getPropertyValue$default (Lspace/kscience/visionforge/Vision;Lspace/kscience/dataforge/names/Name;ZZZILjava/lang/Object;)Lspace/kscience/dataforge/values/Value;
|
public static synthetic fun getProperty$default (Lspace/kscience/visionforge/Vision;Lspace/kscience/dataforge/names/Name;ZZZILjava/lang/Object;)Lspace/kscience/dataforge/values/Value;
|
||||||
public abstract fun invalidateProperty (Lspace/kscience/dataforge/names/Name;)V
|
public abstract fun invalidateProperty (Lspace/kscience/dataforge/names/Name;)V
|
||||||
public abstract fun setParent (Lspace/kscience/visionforge/VisionGroup;)V
|
public abstract fun setParent (Lspace/kscience/visionforge/VisionGroup;)V
|
||||||
public abstract fun update (Lspace/kscience/visionforge/VisionChange;)V
|
public abstract fun update (Lspace/kscience/visionforge/VisionChange;)V
|
||||||
@ -266,7 +266,7 @@ public class space/kscience/visionforge/VisionBase : space/kscience/visionforge/
|
|||||||
protected final fun getOrCreateProperties ()Lspace/kscience/dataforge/meta/MutableMeta;
|
protected final fun getOrCreateProperties ()Lspace/kscience/dataforge/meta/MutableMeta;
|
||||||
public fun getParent ()Lspace/kscience/visionforge/VisionGroup;
|
public fun getParent ()Lspace/kscience/visionforge/VisionGroup;
|
||||||
protected final fun getProperties ()Lspace/kscience/dataforge/meta/MutableMeta;
|
protected final fun getProperties ()Lspace/kscience/dataforge/meta/MutableMeta;
|
||||||
public fun getPropertyValue (Lspace/kscience/dataforge/names/Name;ZZZ)Lspace/kscience/dataforge/values/Value;
|
public fun getProperty (Lspace/kscience/dataforge/names/Name;ZZZ)Lspace/kscience/dataforge/values/Value;
|
||||||
public fun invalidateProperty (Lspace/kscience/dataforge/names/Name;)V
|
public fun invalidateProperty (Lspace/kscience/dataforge/names/Name;)V
|
||||||
public fun setParent (Lspace/kscience/visionforge/VisionGroup;)V
|
public fun setParent (Lspace/kscience/visionforge/VisionGroup;)V
|
||||||
protected final fun setProperties (Lspace/kscience/dataforge/meta/MutableMeta;)V
|
protected final fun setProperties (Lspace/kscience/dataforge/meta/MutableMeta;)V
|
||||||
@ -446,8 +446,8 @@ public final class space/kscience/visionforge/VisionGroupKt {
|
|||||||
|
|
||||||
public final class space/kscience/visionforge/VisionKt {
|
public final class space/kscience/visionforge/VisionKt {
|
||||||
public static final fun getPropertyChanges (Lspace/kscience/visionforge/Vision;)Lkotlinx/coroutines/flow/Flow;
|
public static final fun getPropertyChanges (Lspace/kscience/visionforge/Vision;)Lkotlinx/coroutines/flow/Flow;
|
||||||
public static final fun getPropertyValue (Lspace/kscience/visionforge/Vision;Ljava/lang/String;ZZZ)Lspace/kscience/dataforge/values/Value;
|
public static final fun getProperty (Lspace/kscience/visionforge/Vision;Ljava/lang/String;ZZZ)Lspace/kscience/dataforge/values/Value;
|
||||||
public static synthetic fun getPropertyValue$default (Lspace/kscience/visionforge/Vision;Ljava/lang/String;ZZZILjava/lang/Object;)Lspace/kscience/dataforge/values/Value;
|
public static synthetic fun getProperty$default (Lspace/kscience/visionforge/Vision;Ljava/lang/String;ZZZILjava/lang/Object;)Lspace/kscience/dataforge/values/Value;
|
||||||
public static final fun getVisible (Lspace/kscience/visionforge/Vision;)Ljava/lang/Boolean;
|
public static final fun getVisible (Lspace/kscience/visionforge/Vision;)Ljava/lang/Boolean;
|
||||||
public static final fun onPropertyChange (Lspace/kscience/visionforge/Vision;Lkotlin/jvm/functions/Function2;)V
|
public static final fun onPropertyChange (Lspace/kscience/visionforge/Vision;Lkotlin/jvm/functions/Function2;)V
|
||||||
public static final fun setProperty (Lspace/kscience/visionforge/Vision;Lspace/kscience/dataforge/names/Name;Ljava/lang/Object;)V
|
public static final fun setProperty (Lspace/kscience/visionforge/Vision;Lspace/kscience/dataforge/names/Name;Ljava/lang/Object;)V
|
||||||
@ -499,8 +499,8 @@ public abstract class space/kscience/visionforge/VisionPlugin : space/kscience/d
|
|||||||
|
|
||||||
public abstract interface class space/kscience/visionforge/VisionPropertyContainer {
|
public abstract interface class space/kscience/visionforge/VisionPropertyContainer {
|
||||||
public abstract fun getMeta ()Lspace/kscience/dataforge/meta/MutableMeta;
|
public abstract fun getMeta ()Lspace/kscience/dataforge/meta/MutableMeta;
|
||||||
public abstract fun getPropertyValue (Lspace/kscience/dataforge/names/Name;ZZZ)Lspace/kscience/dataforge/values/Value;
|
public abstract fun getProperty (Lspace/kscience/dataforge/names/Name;ZZZ)Lspace/kscience/dataforge/values/Value;
|
||||||
public static synthetic fun getPropertyValue$default (Lspace/kscience/visionforge/VisionPropertyContainer;Lspace/kscience/dataforge/names/Name;ZZZILjava/lang/Object;)Lspace/kscience/dataforge/values/Value;
|
public static synthetic fun getProperty$default (Lspace/kscience/visionforge/VisionPropertyContainer;Lspace/kscience/dataforge/names/Name;ZZZILjava/lang/Object;)Lspace/kscience/dataforge/values/Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class space/kscience/visionforge/html/HeadersKt {
|
public final class space/kscience/visionforge/html/HeadersKt {
|
||||||
|
@ -0,0 +1,107 @@
|
|||||||
|
package space.kscience.visionforge
|
||||||
|
|
||||||
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.Transient
|
||||||
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
import space.kscience.dataforge.meta.MutableMeta
|
||||||
|
import space.kscience.dataforge.meta.asMutableMeta
|
||||||
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
|
import space.kscience.dataforge.meta.get
|
||||||
|
import space.kscience.dataforge.names.Name
|
||||||
|
import space.kscience.dataforge.names.asName
|
||||||
|
import space.kscience.dataforge.names.isEmpty
|
||||||
|
import space.kscience.dataforge.values.Value
|
||||||
|
import space.kscience.visionforge.VisionGroup.Companion.updateProperties
|
||||||
|
import kotlin.jvm.Synchronized
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
public abstract class AbstractVision : Vision {
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override var parent: Vision? = null
|
||||||
|
|
||||||
|
protected var properties: MutableMeta? = null
|
||||||
|
|
||||||
|
override val meta: Meta get() = properties ?: Meta.EMPTY
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
private fun getOrCreateProperties(): MutableMeta {
|
||||||
|
if (properties == null) {
|
||||||
|
//TODO check performance issues
|
||||||
|
val newProperties = MutableMeta()
|
||||||
|
properties = newProperties
|
||||||
|
}
|
||||||
|
return properties!!
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
private val _propertyChanges = MutableSharedFlow<Name>()
|
||||||
|
override val propertyChanges: SharedFlow<Name> get() = _propertyChanges
|
||||||
|
|
||||||
|
override fun getPropertyValue(
|
||||||
|
name: Name,
|
||||||
|
inherit: Boolean,
|
||||||
|
includeStyles: Boolean,
|
||||||
|
includeDefaults: Boolean,
|
||||||
|
): Value? {
|
||||||
|
properties?.get(name)?.value?.let { return it }
|
||||||
|
if (includeStyles) {
|
||||||
|
getStyleProperty(name)?.value?.let { return it }
|
||||||
|
}
|
||||||
|
if (inherit) {
|
||||||
|
parent?.getPropertyValue(name, inherit, includeStyles, includeDefaults)?.let { return it }
|
||||||
|
}
|
||||||
|
if (includeDefaults) {
|
||||||
|
descriptor?.defaultNode?.get(name)?.value?.let { return it }
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setProperty(name: Name, node: Meta?) {
|
||||||
|
//TODO check old value?
|
||||||
|
if (name.isEmpty()) {
|
||||||
|
properties = node?.asMutableMeta()
|
||||||
|
} else if (node == null) {
|
||||||
|
properties?.setMeta(name, node)
|
||||||
|
} else {
|
||||||
|
getOrCreateProperties().setMeta(name, node)
|
||||||
|
}
|
||||||
|
invalidateProperty(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setPropertyValue(name: Name, value: Value?) {
|
||||||
|
//TODO check old value?
|
||||||
|
if (value == null) {
|
||||||
|
properties?.getMeta(name)?.value = null
|
||||||
|
} else {
|
||||||
|
getOrCreateProperties().setValue(name, value)
|
||||||
|
}
|
||||||
|
invalidateProperty(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val descriptor: MetaDescriptor? get() = null
|
||||||
|
|
||||||
|
override fun invalidateProperty(propertyName: Name) {
|
||||||
|
if (propertyName == Vision.STYLE_KEY) {
|
||||||
|
styles.asSequence()
|
||||||
|
.mapNotNull { getStyle(it) }
|
||||||
|
.flatMap { it.items.asSequence() }
|
||||||
|
.distinctBy { it.key }
|
||||||
|
.forEach {
|
||||||
|
invalidateProperty(it.key.asName())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
manager.context.launch {
|
||||||
|
_propertyChanges.emit(propertyName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun update(change: VisionChange) {
|
||||||
|
change.properties?.let {
|
||||||
|
updateProperties(it, Name.EMPTY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,84 +0,0 @@
|
|||||||
package space.kscience.visionforge
|
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.Meta
|
|
||||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
|
||||||
import space.kscience.dataforge.meta.descriptors.get
|
|
||||||
import space.kscience.dataforge.meta.get
|
|
||||||
import space.kscience.dataforge.names.Name
|
|
||||||
import space.kscience.dataforge.names.NameToken
|
|
||||||
import space.kscience.dataforge.names.plus
|
|
||||||
import space.kscience.dataforge.values.MutableValueProvider
|
|
||||||
import space.kscience.dataforge.values.Value
|
|
||||||
|
|
||||||
private class ComputedVisionProperties(
|
|
||||||
val vision: Vision,
|
|
||||||
val pathName: Name,
|
|
||||||
val visionDescriptor: MetaDescriptor,
|
|
||||||
val parentInheritFlag: Boolean?,
|
|
||||||
val parentStylesFlag: Boolean?
|
|
||||||
) : Meta {
|
|
||||||
|
|
||||||
val descriptor: MetaDescriptor? by lazy { visionDescriptor[pathName] }
|
|
||||||
|
|
||||||
override val items: Map<NameToken, Meta>
|
|
||||||
get() {
|
|
||||||
val metaKeys = vision.meta.getMeta(pathName)?.items?.keys ?: emptySet()
|
|
||||||
val descriptorKeys = descriptor?.children?.map { NameToken(it.key) } ?: emptySet()
|
|
||||||
val inheritFlag = descriptor?.inherited ?: parentInheritFlag
|
|
||||||
val stylesFlag = descriptor?.usesStyles ?: parentStylesFlag
|
|
||||||
return (metaKeys + descriptorKeys).associateWith {
|
|
||||||
ComputedVisionProperties(
|
|
||||||
vision,
|
|
||||||
pathName + it,
|
|
||||||
visionDescriptor,
|
|
||||||
inheritFlag,
|
|
||||||
stylesFlag
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override val value: Value?
|
|
||||||
get() {
|
|
||||||
val inheritFlag = descriptor?.inherited ?: parentInheritFlag ?: false
|
|
||||||
val stylesFlag = descriptor?.usesStyles ?: parentStylesFlag ?: true
|
|
||||||
return vision.getPropertyValue(pathName, inheritFlag, stylesFlag, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString(): String = Meta.toString(this)
|
|
||||||
override fun equals(other: Any?): Boolean = Meta.equals(this, other as? Meta)
|
|
||||||
override fun hashCode(): Int = Meta.hashCode(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compute property node based on inheritance and style information from the descriptor
|
|
||||||
*/
|
|
||||||
public fun Vision.computeProperties(descriptor: MetaDescriptor? = this.descriptor): Meta =
|
|
||||||
if (descriptor == null) meta else ComputedVisionProperties(this, Name.EMPTY, descriptor, null, null)
|
|
||||||
|
|
||||||
public fun Vision.computePropertyNode(
|
|
||||||
name: Name,
|
|
||||||
descriptor: MetaDescriptor? = this.descriptor
|
|
||||||
): Meta? = computeProperties(descriptor)[name]
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compute the property based on the provided value descriptor. By default, use Vision own descriptor
|
|
||||||
*/
|
|
||||||
public fun Vision.computeProperty(name: Name, valueDescriptor: MetaDescriptor? = descriptor?.get(name)): Value? {
|
|
||||||
val inheritFlag = valueDescriptor?.inherited ?: false
|
|
||||||
val stylesFlag = valueDescriptor?.usesStyles ?: true
|
|
||||||
return getPropertyValue(name, inheritFlag, stylesFlag)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Accessor to all vision properties
|
|
||||||
*/
|
|
||||||
public fun Vision.computePropertyValues(
|
|
||||||
descriptor: MetaDescriptor? = this.descriptor
|
|
||||||
): MutableValueProvider = object : MutableValueProvider {
|
|
||||||
override fun getValue(name: Name): Value? = computeProperty(name, descriptor?.get(name))
|
|
||||||
|
|
||||||
override fun setValue(name: Name, value: Value?) {
|
|
||||||
setProperty(name, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -9,7 +9,7 @@ import kotlin.properties.ReadOnlyProperty
|
|||||||
/**
|
/**
|
||||||
* A reference to a style defined in a specific container
|
* A reference to a style defined in a specific container
|
||||||
*/
|
*/
|
||||||
public class StyleReference(public val owner: VisionGroup, public val name: String)
|
public class StyleReference(public val owner: Vision, public val name: String)
|
||||||
|
|
||||||
private tailrec fun styleIsDefined(vision: Vision, reference: StyleReference): Boolean = when {
|
private tailrec fun styleIsDefined(vision: Vision, reference: StyleReference): Boolean = when {
|
||||||
reference.owner === vision -> true
|
reference.owner === vision -> true
|
||||||
@ -25,7 +25,7 @@ public fun Vision.useStyle(reference: StyleReference) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@VisionBuilder
|
@VisionBuilder
|
||||||
public fun VisionGroup.style(
|
public fun Vision.style(
|
||||||
styleKey: String? = null,
|
styleKey: String? = null,
|
||||||
builder: MutableMeta.() -> Unit,
|
builder: MutableMeta.() -> Unit,
|
||||||
): ReadOnlyProperty<Any?, StyleReference> = ReadOnlyProperty { _, property ->
|
): ReadOnlyProperty<Any?, StyleReference> = ReadOnlyProperty { _, property ->
|
||||||
@ -35,7 +35,7 @@ public fun VisionGroup.style(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@VisionBuilder
|
@VisionBuilder
|
||||||
public fun <T : Scheme> VisionGroup.style(
|
public fun <T : Scheme> Vision.style(
|
||||||
spec: Specification<T>,
|
spec: Specification<T>,
|
||||||
styleKey: String? = null,
|
styleKey: String? = null,
|
||||||
builder: T.() -> Unit,
|
builder: T.() -> Unit,
|
||||||
|
@ -5,7 +5,6 @@ import space.kscience.dataforge.names.Name
|
|||||||
import space.kscience.dataforge.names.NameToken
|
import space.kscience.dataforge.names.NameToken
|
||||||
import space.kscience.dataforge.names.asName
|
import space.kscience.dataforge.names.asName
|
||||||
import space.kscience.dataforge.names.plus
|
import space.kscience.dataforge.names.plus
|
||||||
import space.kscience.dataforge.values.Value
|
|
||||||
import space.kscience.dataforge.values.asValue
|
import space.kscience.dataforge.values.asValue
|
||||||
import space.kscience.dataforge.values.stringList
|
import space.kscience.dataforge.values.stringList
|
||||||
import kotlin.jvm.JvmInline
|
import kotlin.jvm.JvmInline
|
||||||
@ -14,11 +13,11 @@ import kotlin.jvm.JvmInline
|
|||||||
* A container for styles
|
* A container for styles
|
||||||
*/
|
*/
|
||||||
@JvmInline
|
@JvmInline
|
||||||
public value class StyleSheet(private val owner: VisionGroup) {
|
public value class StyleSheet(private val owner: Vision) {
|
||||||
|
|
||||||
private val styleNode: Meta? get() = owner.meta[STYLESHEET_KEY]
|
private val styleNode: Meta get() = owner.getProperty(STYLESHEET_KEY)
|
||||||
|
|
||||||
public val items: Map<NameToken, Meta>? get() = styleNode?.items
|
public val items: Map<NameToken, Meta> get() = styleNode.items
|
||||||
|
|
||||||
public operator fun get(key: String): Meta? = owner.getStyle(key)
|
public operator fun get(key: String): Meta? = owner.getStyle(key)
|
||||||
|
|
||||||
@ -26,7 +25,7 @@ public value class StyleSheet(private val owner: VisionGroup) {
|
|||||||
* 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.meta.setMeta(STYLESHEET_KEY + key, style)
|
owner.setProperty(STYLESHEET_KEY + key, style)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -43,7 +42,7 @@ public value class StyleSheet(private val owner: VisionGroup) {
|
|||||||
/**
|
/**
|
||||||
* Create and set a style
|
* Create and set a style
|
||||||
*/
|
*/
|
||||||
public operator fun set(key: String, builder: MutableMeta.() -> Unit) {
|
public fun update(key: String, builder: MutableMeta.() -> Unit) {
|
||||||
val newStyle = get(key)?.toMutableMeta()?.apply(builder) ?: Meta(builder)
|
val newStyle = get(key)?.toMutableMeta()?.apply(builder) ?: Meta(builder)
|
||||||
set(key, newStyle.seal())
|
set(key, newStyle.seal())
|
||||||
}
|
}
|
||||||
@ -61,10 +60,8 @@ internal fun Vision.styleChanged(key: String, oldStyle: Meta?, newStyle: Meta?)
|
|||||||
.map { it.asName() }
|
.map { it.asName() }
|
||||||
tokens.forEach { parent?.invalidateProperty(it) }
|
tokens.forEach { parent?.invalidateProperty(it) }
|
||||||
}
|
}
|
||||||
if (this is VisionGroup) {
|
children.values.forEach { vision ->
|
||||||
for (obj in this) {
|
vision.styleChanged(key, oldStyle, newStyle)
|
||||||
obj.styleChanged(key, oldStyle, newStyle)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,35 +70,40 @@ internal fun Vision.styleChanged(key: String, oldStyle: Meta?, newStyle: Meta?)
|
|||||||
* List of names of styles applied to this object. Order matters. Not inherited.
|
* List of names of styles applied to this object. Order matters. Not inherited.
|
||||||
*/
|
*/
|
||||||
public var Vision.styles: List<String>
|
public var Vision.styles: List<String>
|
||||||
get() = meta.getValue(Vision.STYLE_KEY)?.stringList ?: emptyList()
|
get() = getPropertyValue(
|
||||||
|
Vision.STYLE_KEY,
|
||||||
|
inherit = true,
|
||||||
|
includeStyles = false,
|
||||||
|
includeDefaults = false
|
||||||
|
)?.stringList ?: emptyList()
|
||||||
set(value) {
|
set(value) {
|
||||||
meta.setValue(Vision.STYLE_KEY, value.map { it.asValue() }.asValue())
|
setPropertyValue(Vision.STYLE_KEY, value.map { it.asValue() }.asValue())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A stylesheet for this group and its descendants. Stylesheet is not applied directly,
|
* A stylesheet for this group and its descendants. Stylesheet is not applied directly,
|
||||||
* but instead is just a repository for named configurations.
|
* but instead is just a repository for named configurations.
|
||||||
*/
|
*/
|
||||||
public val VisionGroup.styleSheet: StyleSheet get() = StyleSheet(this)
|
public val Vision.styleSheet: StyleSheet get() = StyleSheet(this)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add style name to the list of styles to be resolved later. The style with given name does not necessary exist at the moment.
|
* Add style name to the list of styles to be resolved later. The style with given name does not necessary exist at the moment.
|
||||||
*/
|
*/
|
||||||
public fun Vision.useStyle(name: String) {
|
public fun Vision.useStyle(name: String) {
|
||||||
styles = (meta.getMeta(Vision.STYLE_KEY)?.stringList ?: emptyList()) + name
|
styles = (getPropertyValue(Vision.STYLE_KEY)?.stringList ?: emptyList()) + name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a style with given name for given [Vision]. The style is not necessary applied to this [Vision].
|
* Resolve a style with given name for given [Vision]. The style is not necessarily applied to this [Vision].
|
||||||
*/
|
*/
|
||||||
public tailrec fun Vision.getStyle(name: String): Meta? =
|
public fun Vision.getStyle(name: String): Meta? =
|
||||||
meta.getMeta(StyleSheet.STYLESHEET_KEY + name) ?: parent?.getStyle(name)
|
meta.getMeta(StyleSheet.STYLESHEET_KEY + name) ?: parent?.getStyle(name)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve a property from all styles
|
* Resolve a property from all styles
|
||||||
*/
|
*/
|
||||||
public fun Vision.getStyleProperty(name: Name): Value? = styles.firstNotNullOfOrNull { getStyle(it)?.get(name)?.value }
|
public fun Vision.getStyleProperty(name: Name): Meta? = styles.firstNotNullOfOrNull { getStyle(it)?.get(name) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve an item in all style layers
|
* Resolve an item in all style layers
|
||||||
|
@ -1,17 +1,20 @@
|
|||||||
package space.kscience.visionforge
|
package space.kscience.visionforge
|
||||||
|
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.channels.awaitClose
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.callbackFlow
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.launch
|
import space.kscience.dataforge.context.Global
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
import space.kscience.dataforge.meta.MutableMeta
|
||||||
|
import space.kscience.dataforge.meta.MutableMetaProvider
|
||||||
import space.kscience.dataforge.meta.descriptors.Described
|
import space.kscience.dataforge.meta.descriptors.Described
|
||||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.dataforge.misc.DFExperimental
|
import space.kscience.dataforge.meta.descriptors.get
|
||||||
import space.kscience.dataforge.misc.Type
|
import space.kscience.dataforge.misc.Type
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.asName
|
import space.kscience.dataforge.names.asName
|
||||||
|
import space.kscience.dataforge.names.parseAsName
|
||||||
import space.kscience.dataforge.names.startsWith
|
import space.kscience.dataforge.names.startsWith
|
||||||
import space.kscience.dataforge.values.Value
|
import space.kscience.dataforge.values.Value
|
||||||
import space.kscience.dataforge.values.asValue
|
import space.kscience.dataforge.values.asValue
|
||||||
@ -23,38 +26,59 @@ import kotlin.reflect.KProperty1
|
|||||||
* A root type for display hierarchy
|
* A root type for display hierarchy
|
||||||
*/
|
*/
|
||||||
@Type(TYPE)
|
@Type(TYPE)
|
||||||
public interface Vision : Described, Configurable {
|
public interface Vision : Described {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The parent object of this one. If null, this one is a root.
|
* The parent object of this one. If null, this one is a root.
|
||||||
*/
|
*/
|
||||||
public var parent: VisionGroup?
|
public var parent: Vision?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Owner [VisionManager]. Used to define coroutine scope a serialization
|
* Owner [VisionManager]. Used to define coroutine scope a serialization
|
||||||
*/
|
*/
|
||||||
public val manager: VisionManager? get() = parent?.manager
|
public val manager: VisionManager get() = parent?.manager ?: Global.visionManager
|
||||||
|
|
||||||
|
public val children: VisionChildren
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This Vision own properties (ignoring inheritance, styles and defaults)
|
* Own properties without inheritance or styles.
|
||||||
*/
|
*/
|
||||||
override val meta: ObservableMutableMeta
|
public val meta: Meta
|
||||||
|
|
||||||
/**
|
|
||||||
* Get property value with given layer flags.
|
|
||||||
* @param inherit toggles parent node property lookup. Null means inference from descriptor. Default is false.
|
|
||||||
* @param includeStyles toggles inclusion of properties from styles. default is true
|
|
||||||
*/
|
|
||||||
public fun getPropertyValue(
|
public fun getPropertyValue(
|
||||||
name: Name,
|
name: Name,
|
||||||
inherit: Boolean = false,
|
inherit: Boolean,
|
||||||
includeStyles: Boolean = true,
|
includeStyles: Boolean,
|
||||||
includeDefaults: Boolean = true,
|
includeDefaults: Boolean,
|
||||||
): Value?
|
): Value?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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(
|
||||||
|
name: Name,
|
||||||
|
inherit: Boolean,
|
||||||
|
includeStyles: Boolean,
|
||||||
|
includeDefaults: Boolean,
|
||||||
|
): MutableMeta = VisionProperties(this, name, descriptor?.get(name), inherit, includeStyles)
|
||||||
|
|
||||||
|
public fun setProperty(
|
||||||
|
name: Name,
|
||||||
|
node: Meta?,
|
||||||
|
)
|
||||||
|
|
||||||
|
public fun setPropertyValue(
|
||||||
|
name: Name,
|
||||||
|
value: Value?,
|
||||||
|
)
|
||||||
|
|
||||||
|
public val propertyChanges: SharedFlow<Name>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify all listeners that a property has been changed and should be invalidated
|
* Notify all listeners that a property has been changed and should be invalidated.
|
||||||
|
* This method does not check that the property has actually changed.
|
||||||
*/
|
*/
|
||||||
public fun invalidateProperty(propertyName: Name)
|
public fun invalidateProperty(propertyName: Name)
|
||||||
|
|
||||||
@ -68,80 +92,135 @@ public interface Vision : Described, Configurable {
|
|||||||
public companion object {
|
public companion object {
|
||||||
public const val TYPE: String = "vision"
|
public const val TYPE: String = "vision"
|
||||||
public val STYLE_KEY: Name = "@style".asName()
|
public val STYLE_KEY: Name = "@style".asName()
|
||||||
|
public const val STYLE_TARGET: String = "style"
|
||||||
|
|
||||||
public val VISIBLE_KEY: Name = "visible".asName()
|
public val VISIBLE_KEY: Name = "visible".asName()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public fun Vision.getPropertyValue(
|
||||||
* Flow of property invalidation events. It does not contain property values after invalidation since it is not clear
|
name: Name,
|
||||||
* if it should include inherited properties etc.
|
inherit: Boolean? = null,
|
||||||
*/
|
includeStyles: Boolean? = null,
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
includeDefaults: Boolean = true,
|
||||||
@DFExperimental
|
metaDescriptor: MetaDescriptor? = descriptor?.get(name),
|
||||||
public val Vision.propertyChanges: Flow<Name>
|
): Value? {
|
||||||
get() = callbackFlow {
|
val inheritFlag = inherit ?: metaDescriptor?.inherited ?: false
|
||||||
meta.onChange(this) { name ->
|
val stylesFlag = includeStyles ?: metaDescriptor?.usesStyles ?: true
|
||||||
launch {
|
return getPropertyValue(name, inheritFlag, stylesFlag, includeDefaults)
|
||||||
send(name)
|
}
|
||||||
}
|
|
||||||
}
|
public fun Vision.getPropertyValue(
|
||||||
awaitClose {
|
name: String,
|
||||||
meta.removeListener(this)
|
inherit: Boolean? = null,
|
||||||
}
|
includeStyles: Boolean? = null,
|
||||||
}
|
includeDefaults: Boolean = true,
|
||||||
|
metaDescriptor: MetaDescriptor? = descriptor?.get(name),
|
||||||
|
): Value? = getPropertyValue(name.parseAsName(), inherit, includeStyles, includeDefaults, metaDescriptor)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscribe on property updates. The subscription is bound to the given scope and canceled when the scope is canceled
|
* Compute the property based on the provided value descriptor. By default, use Vision own descriptor
|
||||||
*/
|
*/
|
||||||
public fun Vision.onPropertyChange(callback: Meta.(Name) -> Unit) {
|
public fun Vision.getProperty(
|
||||||
meta.onChange(null, callback)
|
name: Name,
|
||||||
|
inherit: Boolean? = null,
|
||||||
|
includeStyles: Boolean? = null,
|
||||||
|
includeDefaults: Boolean = true,
|
||||||
|
metaDescriptor: MetaDescriptor? = descriptor?.get(name),
|
||||||
|
): MutableMeta {
|
||||||
|
val inheritFlag = inherit ?: metaDescriptor?.inherited ?: false
|
||||||
|
val stylesFlag = includeStyles ?: metaDescriptor?.usesStyles ?: true
|
||||||
|
return getProperty(name, inheritFlag, stylesFlag, includeDefaults)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get [Vision] property using key as a String
|
* Get [Vision] property using key as a String
|
||||||
*/
|
*/
|
||||||
public fun Vision.getPropertyValue(
|
public fun Vision.getProperty(
|
||||||
key: String,
|
name: String,
|
||||||
inherit: Boolean = false,
|
inherit: Boolean? = null,
|
||||||
includeStyles: Boolean = true,
|
includeStyles: Boolean? = null,
|
||||||
includeDefaults: Boolean = true,
|
includeDefaults: Boolean = true,
|
||||||
): Value? = getPropertyValue(Name.parse(key), inherit, includeStyles, includeDefaults)
|
metaDescriptor: MetaDescriptor? = descriptor?.get(name),
|
||||||
|
): MutableMeta = getProperty(name.parseAsName(), inherit, includeStyles, includeDefaults, metaDescriptor)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A convenience method to set property node or value. If Item is null, then node is removed, not a value
|
* Vision's own non-inheritable, non-styleable properties
|
||||||
*/
|
*/
|
||||||
public fun Vision.setProperty(name: Name, item: Any?) {
|
public fun Vision.properties(
|
||||||
when (item) {
|
inherit: Boolean? = null,
|
||||||
null -> meta.remove(name)
|
useStyles: Boolean? = null,
|
||||||
is Meta -> meta.setMeta(name, item)
|
): MutableMetaProvider = VisionProperties(this, Name.EMPTY, inherit = inherit, useStyles = useStyles)
|
||||||
is Value -> meta.setValue(name, item)
|
|
||||||
else -> meta.setValue(name, Value.of(item))
|
public fun Vision.setPropertyValue(name: Name, value: Number?) {
|
||||||
|
if (value == null) {
|
||||||
|
setPropertyValue(name, null)
|
||||||
|
} else {
|
||||||
|
setPropertyValue(name, value.asValue())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun Vision.setPropertyNode(key: String, item: Any?) {
|
public fun Vision.setPropertyValue(name: String, value: Number?): Unit =
|
||||||
setProperty(Name.parse(key), item)
|
setPropertyValue(name.parseAsName(), value)
|
||||||
|
|
||||||
|
public fun Vision.setPropertyValue(name: Name, value: Boolean?) {
|
||||||
|
if (value == null) {
|
||||||
|
setPropertyValue(name, null)
|
||||||
|
} else {
|
||||||
|
setPropertyValue(name, value.asValue())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun Vision.setPropertyValue(name: String, value: Boolean?): Unit =
|
||||||
|
setPropertyValue(name.parseAsName(), value)
|
||||||
|
|
||||||
|
public fun Vision.setPropertyValue(name: Name, value: String?) {
|
||||||
|
if (value == null) {
|
||||||
|
setPropertyValue(name, null)
|
||||||
|
} else {
|
||||||
|
setPropertyValue(name, value.asValue())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun Vision.setPropertyValue(name: String, value: String?): Unit =
|
||||||
|
setPropertyValue(name.parseAsName(), value)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Control visibility of the element
|
* Control visibility of the element
|
||||||
*/
|
*/
|
||||||
public var Vision.visible: Boolean?
|
public var Vision.visible: Boolean?
|
||||||
get() = getPropertyValue(Vision.VISIBLE_KEY)?.boolean
|
get() = getPropertyValue(Vision.VISIBLE_KEY)?.boolean
|
||||||
set(value) = meta.setValue(Vision.VISIBLE_KEY, value?.asValue())
|
set(value) {
|
||||||
|
setPropertyValue(Vision.VISIBLE_KEY, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscribe on property updates. The subscription is bound to the given scope and canceled when the scope is canceled
|
||||||
|
*/
|
||||||
|
public fun Vision.onPropertyChange(callback: (Name) -> Unit): Job = propertyChanges.onEach {
|
||||||
|
callback(it)
|
||||||
|
}.launchIn(manager.context)
|
||||||
|
|
||||||
|
|
||||||
public fun <V : Vision, T> V.useProperty(
|
public fun <V : Vision, T> V.useProperty(
|
||||||
property: KProperty1<V, T>,
|
property: KProperty1<V, T>,
|
||||||
owner: Any? = null,
|
|
||||||
callBack: V.(T) -> Unit,
|
callBack: V.(T) -> Unit,
|
||||||
) {
|
): Job {
|
||||||
//Pass initial value.
|
//Pass initial value.
|
||||||
callBack(property.get(this))
|
callBack(property.get(this))
|
||||||
meta.onChange(owner) { name ->
|
return propertyChanges.onEach { name ->
|
||||||
if (name.startsWith(property.name.asName())) {
|
if (name.startsWith(property.name.asName())) {
|
||||||
callBack(property.get(this@useProperty))
|
callBack(property.get(this@useProperty))
|
||||||
}
|
}
|
||||||
}
|
}.launchIn(manager.context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public interface MutableVisionGroup : Vision {
|
||||||
|
|
||||||
|
override val children: MutableVisionChildren
|
||||||
|
|
||||||
|
public fun createGroup(): MutableVisionGroup
|
||||||
|
}
|
||||||
|
@ -1,176 +0,0 @@
|
|||||||
package space.kscience.visionforge
|
|
||||||
|
|
||||||
import kotlinx.serialization.EncodeDefault
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import kotlinx.serialization.Transient
|
|
||||||
import space.kscience.dataforge.meta.Meta
|
|
||||||
import space.kscience.dataforge.meta.MutableMeta
|
|
||||||
import space.kscience.dataforge.meta.ObservableMutableMeta
|
|
||||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
|
||||||
import space.kscience.dataforge.meta.descriptors.value
|
|
||||||
import space.kscience.dataforge.meta.get
|
|
||||||
import space.kscience.dataforge.misc.DFExperimental
|
|
||||||
import space.kscience.dataforge.names.*
|
|
||||||
import space.kscience.dataforge.values.Value
|
|
||||||
import space.kscience.dataforge.values.ValueType
|
|
||||||
import space.kscience.visionforge.Vision.Companion.STYLE_KEY
|
|
||||||
import kotlin.jvm.Synchronized
|
|
||||||
|
|
||||||
internal data class MetaListener(
|
|
||||||
val owner: Any? = null,
|
|
||||||
val callback: Meta.(name: Name) -> Unit,
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A full base implementation for a [Vision]
|
|
||||||
* @param parent the parent object for this vision. Could've set later. Not serialized.
|
|
||||||
*/
|
|
||||||
@Serializable
|
|
||||||
@SerialName("vision")
|
|
||||||
public open class VisionBase(
|
|
||||||
@Transient override var parent: VisionGroup? = null,
|
|
||||||
@EncodeDefault protected var properties: MutableMeta? = null,
|
|
||||||
) : Vision {
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
protected fun getOrCreateProperties(): MutableMeta {
|
|
||||||
if (properties == null) {
|
|
||||||
val newProperties = MutableMeta()
|
|
||||||
properties = newProperties
|
|
||||||
}
|
|
||||||
return properties!!
|
|
||||||
}
|
|
||||||
|
|
||||||
@Transient
|
|
||||||
private val listeners: MutableList<MetaListener> = mutableListOf()
|
|
||||||
|
|
||||||
private inner class VisionProperties(val pathName: Name) : ObservableMutableMeta {
|
|
||||||
|
|
||||||
override val items: Map<NameToken, ObservableMutableMeta>
|
|
||||||
get() = properties?.get(pathName)?.items?.mapValues { entry ->
|
|
||||||
VisionProperties(pathName + entry.key)
|
|
||||||
} ?: emptyMap()
|
|
||||||
|
|
||||||
override var value: Value?
|
|
||||||
get() = properties?.get(pathName)?.value
|
|
||||||
set(value) {
|
|
||||||
val oldValue = properties?.get(pathName)?.value
|
|
||||||
getOrCreateProperties().setValue(pathName, value)
|
|
||||||
if (oldValue != value) {
|
|
||||||
invalidate(Name.EMPTY)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getOrCreate(name: Name): ObservableMutableMeta = VisionProperties(pathName + name)
|
|
||||||
|
|
||||||
override fun setMeta(name: Name, node: Meta?) {
|
|
||||||
getOrCreateProperties().setMeta(pathName + name, node)
|
|
||||||
invalidate(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
@DFExperimental
|
|
||||||
override fun attach(name: Name, node: ObservableMutableMeta) {
|
|
||||||
val ownProperties = getOrCreateProperties()
|
|
||||||
if (ownProperties is ObservableMutableMeta) {
|
|
||||||
ownProperties.attach(pathName + name, node)
|
|
||||||
} else {
|
|
||||||
ownProperties.setMeta(pathName + name, node)
|
|
||||||
node.onChange(this) { childName ->
|
|
||||||
ownProperties.setMeta(pathName + name + childName, this[childName])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun invalidate(name: Name) {
|
|
||||||
invalidateProperty(pathName + name)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
override fun onChange(owner: Any?, callback: Meta.(name: Name) -> Unit) {
|
|
||||||
if (pathName.isEmpty()) {
|
|
||||||
listeners.add((MetaListener(owner, callback)))
|
|
||||||
} else {
|
|
||||||
listeners.add(MetaListener(owner) { name ->
|
|
||||||
if (name.startsWith(pathName)) {
|
|
||||||
(this@MetaListener[pathName] ?: Meta.EMPTY).callback(name.removeHeadOrNull(pathName)!!)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
override fun removeListener(owner: Any?) {
|
|
||||||
listeners.removeAll { it.owner === owner }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString(): String = Meta.toString(this)
|
|
||||||
override fun equals(other: Any?): Boolean = Meta.equals(this, other as? Meta)
|
|
||||||
override fun hashCode(): Int = Meta.hashCode(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
final override val meta: ObservableMutableMeta get() = VisionProperties(Name.EMPTY)
|
|
||||||
|
|
||||||
override fun getPropertyValue(
|
|
||||||
name: Name,
|
|
||||||
inherit: Boolean,
|
|
||||||
includeStyles: Boolean,
|
|
||||||
includeDefaults: Boolean,
|
|
||||||
): Value? {
|
|
||||||
properties?.get(name)?.value?.let { return it }
|
|
||||||
if (includeStyles) {
|
|
||||||
getStyleProperty(name)?.let { return it }
|
|
||||||
}
|
|
||||||
if (inherit) {
|
|
||||||
parent?.getPropertyValue(name, inherit, includeStyles, includeDefaults)?.let { return it }
|
|
||||||
}
|
|
||||||
if (includeDefaults) {
|
|
||||||
descriptor?.defaultNode?.get(name)?.value.let { return it }
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
override val descriptor: MetaDescriptor? get() = null
|
|
||||||
|
|
||||||
override fun invalidateProperty(propertyName: Name) {
|
|
||||||
if (propertyName == STYLE_KEY) {
|
|
||||||
styles.mapNotNull { getStyle(it) }.asSequence()
|
|
||||||
.flatMap { it.items.asSequence() }
|
|
||||||
.distinctBy { it.key }
|
|
||||||
.forEach {
|
|
||||||
invalidateProperty(it.key.asName())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
listeners.forEach { it.callback(properties ?: Meta.EMPTY, propertyName) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun update(change: VisionChange) {
|
|
||||||
change.properties?.let {
|
|
||||||
updateProperties(Name.EMPTY, it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public companion object {
|
|
||||||
public val descriptor: MetaDescriptor = MetaDescriptor {
|
|
||||||
value(STYLE_KEY, ValueType.STRING) {
|
|
||||||
multiple = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public fun Vision.updateProperties(at: Name, item: Meta) {
|
|
||||||
meta.setValue(at, item.value)
|
|
||||||
item.items.forEach { (token, item) ->
|
|
||||||
updateProperties(at + token, item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//fun VisualObject.findStyle(styleName: Name): Meta? {
|
|
||||||
// if (this is VisualGroup) {
|
|
||||||
// val style = resolveStyle(styleName)
|
|
||||||
// if (style != null) return style
|
|
||||||
// }
|
|
||||||
// return parent?.findStyle(styleName)
|
|
||||||
//}
|
|
@ -7,7 +7,6 @@ import kotlinx.coroutines.flow.launchIn
|
|||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.misc.DFExperimental
|
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.plus
|
import space.kscience.dataforge.names.plus
|
||||||
import space.kscience.dataforge.values.Null
|
import space.kscience.dataforge.values.Null
|
||||||
@ -19,14 +18,13 @@ import kotlin.time.Duration
|
|||||||
*/
|
*/
|
||||||
private fun Vision.deepCopy(): Vision {
|
private fun Vision.deepCopy(): Vision {
|
||||||
//Assuming that unrooted visions are already isolated
|
//Assuming that unrooted visions are already isolated
|
||||||
val manager = this.manager ?: return this
|
|
||||||
//TODO replace by efficient deep copy
|
//TODO replace by efficient deep copy
|
||||||
val json = manager.encodeToJsonElement(this)
|
val json = manager.encodeToJsonElement(this)
|
||||||
return manager.decodeFromJson(json)
|
return manager.decodeFromJson(json)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An update for a [Vision] or a [VisionGroup]
|
* An update for a [Vision]
|
||||||
*/
|
*/
|
||||||
public class VisionChangeBuilder : VisionContainerBuilder<Vision> {
|
public class VisionChangeBuilder : VisionContainerBuilder<Vision> {
|
||||||
|
|
||||||
@ -87,7 +85,6 @@ public inline fun VisionChange(block: VisionChangeBuilder.() -> Unit): VisionCha
|
|||||||
VisionChangeBuilder().apply(block).deepCopy()
|
VisionChangeBuilder().apply(block).deepCopy()
|
||||||
|
|
||||||
|
|
||||||
@OptIn(DFExperimental::class)
|
|
||||||
private fun CoroutineScope.collectChange(
|
private fun CoroutineScope.collectChange(
|
||||||
name: Name,
|
name: Name,
|
||||||
source: Vision,
|
source: Vision,
|
||||||
@ -96,28 +93,25 @@ private fun CoroutineScope.collectChange(
|
|||||||
|
|
||||||
//Collect properties change
|
//Collect properties change
|
||||||
source.onPropertyChange { propertyName ->
|
source.onPropertyChange { propertyName ->
|
||||||
val newItem = source.meta[propertyName]
|
val newItem = source.getProperty(propertyName, false, false, false)
|
||||||
collector().propertyChanged(name, propertyName, newItem)
|
collector().propertyChanged(name, propertyName, newItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source is VisionGroup) {
|
val children = source.children
|
||||||
//Subscribe for children changes
|
//Subscribe for children changes
|
||||||
source.children.forEach { (token, child) ->
|
for ((token, child) in children) {
|
||||||
collectChange(name + token, child, collector)
|
collectChange(name + token, child, collector)
|
||||||
}
|
|
||||||
|
|
||||||
//Subscribe for structure change
|
|
||||||
if (source is MutableVisionGroup) {
|
|
||||||
source.structureChanges.onEach { changedName ->
|
|
||||||
val after = source[changedName]
|
|
||||||
val fullName = name + changedName
|
|
||||||
if (after != null) {
|
|
||||||
collectChange(fullName, after, collector)
|
|
||||||
}
|
|
||||||
collector()[fullName] = after
|
|
||||||
}.launchIn(this)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Subscribe for structure change
|
||||||
|
children.changes.onEach { changedName ->
|
||||||
|
val after = children[changedName]
|
||||||
|
val fullName = name + changedName
|
||||||
|
if (after != null) {
|
||||||
|
collectChange(fullName, after, collector)
|
||||||
|
}
|
||||||
|
collector()[fullName] = after
|
||||||
|
}.launchIn(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,196 @@
|
|||||||
|
package space.kscience.visionforge
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.flow.*
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||||
|
import kotlinx.serialization.encoding.Decoder
|
||||||
|
import kotlinx.serialization.encoding.Encoder
|
||||||
|
import kotlinx.serialization.serializer
|
||||||
|
import space.kscience.dataforge.names.*
|
||||||
|
|
||||||
|
@DslMarker
|
||||||
|
public annotation class VisionBuilder
|
||||||
|
|
||||||
|
public interface VisionContainer<out V : Vision> {
|
||||||
|
public operator fun get(name: Name): V?
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface VisionContainerBuilder<in V : Vision> {
|
||||||
|
//TODO add documentation
|
||||||
|
public operator fun set(name: Name?, child: V?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A serializable representation of [Vision] children container
|
||||||
|
*/
|
||||||
|
public interface VisionChildren : VisionContainer<Vision> {
|
||||||
|
public val parent: Vision?
|
||||||
|
|
||||||
|
public val keys: Set<NameToken>
|
||||||
|
|
||||||
|
public val values: Iterable<Vision> get() = keys.map { get(it)!! }
|
||||||
|
|
||||||
|
public val changes: Flow<Name>
|
||||||
|
|
||||||
|
public operator fun get(token: NameToken): Vision?
|
||||||
|
|
||||||
|
override fun get(name: Name): Vision? = when (name.length) {
|
||||||
|
0 -> parent
|
||||||
|
1 -> get(name.first())
|
||||||
|
else -> get(name.first())?.children?.get(name.cutFirst())
|
||||||
|
}
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
public fun empty(owner: Vision): VisionChildren = object : VisionChildren {
|
||||||
|
override val parent: Vision get() = owner
|
||||||
|
override val keys: Set<NameToken> get() = emptySet()
|
||||||
|
override val changes: Flow<Name> get() = emptyFlow()
|
||||||
|
override fun get(token: NameToken): Vision? = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun VisionChildren.isEmpty(): Boolean = keys.isEmpty()
|
||||||
|
|
||||||
|
@Serializable(VisionChildrenContainerSerializer::class)
|
||||||
|
public interface MutableVisionChildren : VisionChildren, VisionContainerBuilder<Vision> {
|
||||||
|
public override val parent: MutableVisionGroup?
|
||||||
|
|
||||||
|
public operator fun set(token: NameToken, value: Vision?)
|
||||||
|
|
||||||
|
override fun set(name: Name?, child: Vision?) {
|
||||||
|
when {
|
||||||
|
name == null -> {
|
||||||
|
if (child != null) {
|
||||||
|
static(child)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
name.isEmpty() -> error("Empty names are not allowed in VisionGroup::set")
|
||||||
|
name.length == 1 -> {
|
||||||
|
val token = name.tokens.first()
|
||||||
|
set(token, child)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
val currentParent = get(name.first())
|
||||||
|
if (currentParent != null && currentParent !is MutableVisionGroup) error("Can't assign a child to $currentParent")
|
||||||
|
val parent: MutableVisionGroup = currentParent as? MutableVisionGroup ?: parent?.createGroup().also {
|
||||||
|
set(name.first(), it)
|
||||||
|
} ?: error("Container owner not set")
|
||||||
|
parent.children[name.cutFirst()] = child
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a static child. Statics could not be found by name, removed or replaced. Changing statics also do not trigger events.
|
||||||
|
*/
|
||||||
|
public fun MutableVisionChildren.static(child: Vision): Unit {
|
||||||
|
set(NameToken("@static", index = child.hashCode().toString()), child)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun VisionChildren.asSequence(): Sequence<Pair<NameToken, Vision>> = sequence {
|
||||||
|
keys.forEach { yield(it to get(it)!!) }
|
||||||
|
}
|
||||||
|
|
||||||
|
public operator fun VisionChildren.iterator(): Iterator<Pair<NameToken, Vision>> = asSequence().iterator()
|
||||||
|
|
||||||
|
public operator fun <V : Vision> VisionContainer<V>.get(str: String): V? = get(Name.parse(str))
|
||||||
|
|
||||||
|
public operator fun <V : Vision> VisionContainerBuilder<V>.set(
|
||||||
|
str: String?, vision: V?,
|
||||||
|
): Unit = set(str?.parseAsName(), vision)
|
||||||
|
|
||||||
|
internal class VisionChildrenImpl(
|
||||||
|
items: Map<NameToken, Vision>,
|
||||||
|
) : MutableVisionChildren {
|
||||||
|
|
||||||
|
override var parent: MutableVisionGroup? = null
|
||||||
|
internal set
|
||||||
|
|
||||||
|
private val items = LinkedHashMap(items)
|
||||||
|
private val updateJobs = HashMap<NameToken, Job>()
|
||||||
|
|
||||||
|
private val scope: CoroutineScope? get() = parent?.manager?.context
|
||||||
|
|
||||||
|
override val keys: Set<NameToken> get() = items.keys
|
||||||
|
|
||||||
|
override fun get(token: NameToken): Vision? = items[token]
|
||||||
|
|
||||||
|
private val _changes = MutableSharedFlow<Name>()
|
||||||
|
override val changes: SharedFlow<Name> get() = _changes
|
||||||
|
|
||||||
|
private fun onChange(name: Name) {
|
||||||
|
scope?.launch {
|
||||||
|
_changes.emit(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override operator fun set(token: NameToken, value: Vision?) {
|
||||||
|
//fast return if value equals existing
|
||||||
|
if (value == get(token)) return
|
||||||
|
|
||||||
|
val currentUpdateJob = updateJobs[token]
|
||||||
|
if (currentUpdateJob != null) {
|
||||||
|
currentUpdateJob.cancel()
|
||||||
|
updateJobs.remove(token)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value == null) {
|
||||||
|
items.remove(token)
|
||||||
|
} else {
|
||||||
|
items[token] = value
|
||||||
|
//check if parent already exists and is different from the current one
|
||||||
|
if (value.parent != null && value.parent != parent) error("Can't reassign parent Vision for $value")
|
||||||
|
//set parent
|
||||||
|
value.parent = parent
|
||||||
|
//start update jobs (only if the vision is rooted)
|
||||||
|
scope?.let { scope ->
|
||||||
|
val job = (value.children as? VisionChildrenImpl)?.changes?.onEach {
|
||||||
|
onChange(token + it)
|
||||||
|
}?.launchIn(scope)
|
||||||
|
if (job != null) {
|
||||||
|
updateJobs[token] = job
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onChange(token.asName())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clear() {
|
||||||
|
if (items.isNotEmpty()) {
|
||||||
|
updateJobs.values.forEach {
|
||||||
|
it.cancel()
|
||||||
|
}
|
||||||
|
updateJobs.clear()
|
||||||
|
items.clear()
|
||||||
|
onChange(Name.EMPTY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal object VisionChildrenContainerSerializer : KSerializer<MutableVisionChildren> {
|
||||||
|
private val mapSerializer = serializer<Map<NameToken,Vision>>()
|
||||||
|
|
||||||
|
override val descriptor: SerialDescriptor = mapSerializer.descriptor
|
||||||
|
|
||||||
|
override fun deserialize(decoder: Decoder): MutableVisionChildren {
|
||||||
|
val map = decoder.decodeSerializableValue(mapSerializer)
|
||||||
|
return VisionChildrenImpl(map)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: MutableVisionChildren) {
|
||||||
|
val map = value.keys.associateWith { value[it]!! }
|
||||||
|
encoder.encodeSerializableValue(mapSerializer, map)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,109 +1,99 @@
|
|||||||
package space.kscience.visionforge
|
package space.kscience.visionforge
|
||||||
|
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|
||||||
import kotlinx.coroutines.channels.awaitClose
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.callbackFlow
|
import kotlinx.coroutines.flow.emptyFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.serialization.SerialName
|
||||||
import space.kscience.dataforge.misc.DFExperimental
|
import kotlinx.serialization.Serializable
|
||||||
import space.kscience.dataforge.names.*
|
import kotlinx.serialization.Transient
|
||||||
import space.kscience.dataforge.provider.Provider
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
@DslMarker
|
import space.kscience.dataforge.meta.descriptors.value
|
||||||
public annotation class VisionBuilder
|
import space.kscience.dataforge.names.Name
|
||||||
|
import space.kscience.dataforge.names.NameToken
|
||||||
public interface VisionContainer<out V : Vision> {
|
import space.kscience.dataforge.names.plus
|
||||||
public operator fun get(name: Name): V?
|
import space.kscience.dataforge.values.ValueType
|
||||||
}
|
import space.kscience.visionforge.Vision.Companion.STYLE_KEY
|
||||||
|
import kotlin.jvm.Synchronized
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a group of [Vision] instances
|
* A full base implementation for a [Vision]
|
||||||
*/
|
*/
|
||||||
public interface VisionGroup : Provider, Vision, VisionContainer<Vision> {
|
@Serializable
|
||||||
/**
|
@SerialName("vision.group")
|
||||||
* A map of top level named children
|
public open class VisionGroup : AbstractVision(), MutableVisionGroup {
|
||||||
*/
|
|
||||||
public val children: Map<NameToken, Vision>
|
|
||||||
|
|
||||||
override val defaultTarget: String get() = Vision.TYPE
|
override fun update(change: VisionChange) {
|
||||||
|
change.children?.forEach { (name, change) ->
|
||||||
/**
|
when {
|
||||||
* A map of direct children for specific target
|
change.delete -> children.set(name, null)
|
||||||
* (currently "visual" or "style")
|
change.vision != null -> children.set(name, change.vision)
|
||||||
*/
|
else -> children[name]?.update(change)
|
||||||
override fun content(target: String): Map<Name, Any> =
|
|
||||||
when (target) {
|
|
||||||
Vision.TYPE -> children.flatMap { (key, value) ->
|
|
||||||
val res: Map<Name, Any> = if (value is VisionGroup) {
|
|
||||||
value.content(target).mapKeys { key + it.key }
|
|
||||||
} else {
|
|
||||||
mapOf(key.asName() to value)
|
|
||||||
}
|
|
||||||
res.entries
|
|
||||||
}.associate { it.toPair() }
|
|
||||||
STYLE_TARGET -> styleSheet.items?.mapKeys { it.key.asName() } ?: emptyMap()
|
|
||||||
else -> emptyMap()
|
|
||||||
}
|
|
||||||
|
|
||||||
public override operator fun get(name: Name): Vision? {
|
|
||||||
return when {
|
|
||||||
name.isEmpty() -> this
|
|
||||||
name.length == 1 -> children[name.tokens.first()]
|
|
||||||
else -> (children[name.tokens.first()] as? VisionGroup)?.get(name.cutFirst())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public companion object {
|
|
||||||
public const val STYLE_TARGET: String = "style"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterate over children of this group
|
|
||||||
*/
|
|
||||||
public operator fun VisionGroup.iterator(): Iterator<Vision> = children.values.iterator()
|
|
||||||
|
|
||||||
public fun VisionGroup.isEmpty(): Boolean = this.children.isEmpty()
|
|
||||||
|
|
||||||
public interface VisionContainerBuilder<in V : Vision> {
|
|
||||||
//TODO add documentation
|
|
||||||
public operator fun set(name: Name?, child: V?)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mutable version of [VisionGroup]
|
|
||||||
*/
|
|
||||||
public interface MutableVisionGroup : VisionGroup, VisionContainerBuilder<Vision> {
|
|
||||||
public fun onStructureChanged(owner: Any?, block: VisionGroup.(Name) -> Unit)
|
|
||||||
|
|
||||||
public fun removeStructureListener(owner: Any?)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flow structure changes of this group. Unconsumed changes are discarded
|
|
||||||
*/
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
|
||||||
@DFExperimental
|
|
||||||
public val MutableVisionGroup.structureChanges: Flow<Name>
|
|
||||||
get() = callbackFlow {
|
|
||||||
meta.onChange(this) { name ->
|
|
||||||
launch {
|
|
||||||
send(name)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
awaitClose {
|
change.properties?.let {
|
||||||
removeStructureListener(this)
|
updateProperties(it, Name.EMPTY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SerialName("children")
|
||||||
|
protected var _children: MutableVisionChildren? = null
|
||||||
|
|
||||||
public operator fun <V : Vision> VisionContainer<V>.get(str: String): V? = get(Name.parse(str))
|
@Transient
|
||||||
|
override val children: MutableVisionChildren = object : MutableVisionChildren {
|
||||||
|
|
||||||
public operator fun <V : Vision> VisionContainerBuilder<V>.set(token: NameToken, child: V?): Unit =
|
@Synchronized
|
||||||
set(token.asName(), child)
|
fun getOrCreateChildren(): MutableVisionChildren {
|
||||||
|
if (_children == null) {
|
||||||
|
_children = VisionChildrenImpl(emptyMap()).apply {
|
||||||
|
parent = this@VisionGroup
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _children!!
|
||||||
|
}
|
||||||
|
|
||||||
public operator fun <V : Vision> VisionContainerBuilder<V>.set(key: String?, child: V?): Unit =
|
override val parent: MutableVisionGroup get() = this@VisionGroup
|
||||||
set(key?.let(Name::parse), child)
|
|
||||||
|
|
||||||
public fun MutableVisionGroup.removeAll(): Unit = children.keys.map { it.asName() }.forEach { this[it] = null }
|
override val keys: Set<NameToken> get() = _children?.keys ?: emptySet()
|
||||||
|
override val changes: Flow<Name> get() = _children?.changes ?: emptyFlow()
|
||||||
|
|
||||||
|
override fun get(token: NameToken): Vision? = _children?.get(token)
|
||||||
|
|
||||||
|
override fun set(token: NameToken, value: Vision?) {
|
||||||
|
getOrCreateChildren()[token] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun set(name: Name?, child: Vision?) {
|
||||||
|
getOrCreateChildren()[name] = child
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clear() {
|
||||||
|
_children?.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createGroup(): VisionGroup = VisionGroup()
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
public val descriptor: MetaDescriptor = MetaDescriptor {
|
||||||
|
value(STYLE_KEY, ValueType.STRING) {
|
||||||
|
multiple = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun Vision.updateProperties(item: Meta, at: Name = Name.EMPTY) {
|
||||||
|
setPropertyValue(at, item.value)
|
||||||
|
item.items.forEach { (token, item) ->
|
||||||
|
updateProperties(item, at + token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//fun VisualObject.findStyle(styleName: Name): Meta? {
|
||||||
|
// if (this is VisualGroup) {
|
||||||
|
// val style = resolveStyle(styleName)
|
||||||
|
// if (style != null) return style
|
||||||
|
// }
|
||||||
|
// return parent?.findStyle(styleName)
|
||||||
|
//}
|
@ -1,168 +0,0 @@
|
|||||||
package space.kscience.visionforge
|
|
||||||
|
|
||||||
import kotlinx.serialization.EncodeDefault
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import kotlinx.serialization.Transient
|
|
||||||
import space.kscience.dataforge.names.*
|
|
||||||
import kotlin.jvm.Synchronized
|
|
||||||
|
|
||||||
private class StructureChangeListener(val owner: Any?, val callback: VisionGroup.(Name) -> Unit)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract implementation of mutable group of [Vision]
|
|
||||||
*
|
|
||||||
* @param childrenInternal Internal mutable container for group children
|
|
||||||
*/
|
|
||||||
@Serializable
|
|
||||||
@SerialName("vision.group")
|
|
||||||
public open class VisionGroupBase(
|
|
||||||
@EncodeDefault @SerialName("children") protected val childrenInternal: MutableMap<NameToken, Vision> = LinkedHashMap(),
|
|
||||||
) : VisionBase(), MutableVisionGroup {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A map of top level named children
|
|
||||||
*/
|
|
||||||
override val children: Map<NameToken, Vision> get() = childrenInternal
|
|
||||||
|
|
||||||
init {
|
|
||||||
childrenInternal.forEach { (token, child) ->
|
|
||||||
if (child.parent != null && child.parent != this) error("Can't reassign existing parent for child $token")
|
|
||||||
child.parent = this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun invalidateProperty(propertyName: Name) {
|
|
||||||
super.invalidateProperty(propertyName)
|
|
||||||
for (obj in this) {
|
|
||||||
obj.invalidateProperty(propertyName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Transient
|
|
||||||
private val structureListeners = HashSet<StructureChangeListener>()
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
override fun onStructureChanged(owner: Any?, block: VisionGroup.(Name) -> Unit) {
|
|
||||||
structureListeners.add(StructureChangeListener(owner, block))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
override fun removeStructureListener(owner: Any?) {
|
|
||||||
structureListeners.removeAll { it.owner == owner }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Propagate children change event upwards
|
|
||||||
*/
|
|
||||||
protected fun childrenChanged(name: Name) {
|
|
||||||
structureListeners.forEach {
|
|
||||||
it.callback(this, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a static child. Statics could not be found by name, removed or replaced. Changing statics also do not trigger events.
|
|
||||||
*/
|
|
||||||
protected open fun addStatic(child: Vision): Unit {
|
|
||||||
attachChild(NameToken("@static", index = child.hashCode().toString()), child)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a vision group of the same type as this vision group. Do not attach it.
|
|
||||||
*/
|
|
||||||
protected open fun createGroup(): VisionGroupBase = VisionGroupBase()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set parent for given child and attach it
|
|
||||||
*/
|
|
||||||
private fun attachChild(token: NameToken, child: Vision?) {
|
|
||||||
val before = childrenInternal[token]
|
|
||||||
when {
|
|
||||||
child == null -> {
|
|
||||||
childrenInternal.remove(token)
|
|
||||||
}
|
|
||||||
child.parent == null -> {
|
|
||||||
child.parent = this
|
|
||||||
childrenInternal[token] = child
|
|
||||||
}
|
|
||||||
child.parent !== this -> {
|
|
||||||
error("Can't reassign existing parent for child $token")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (before != child) {
|
|
||||||
childrenChanged(token.asName())
|
|
||||||
if (child is MutableVisionGroup) {
|
|
||||||
child.onStructureChanged(this) { changedName ->
|
|
||||||
this@VisionGroupBase.childrenChanged(token + changedName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Recursively create a child group
|
|
||||||
*/
|
|
||||||
private fun createGroups(name: Name): VisionGroupBase = when {
|
|
||||||
name.isEmpty() -> error("Should be unreachable")
|
|
||||||
name.length == 1 -> {
|
|
||||||
val token = name.tokens.first()
|
|
||||||
when (val current = children[token]) {
|
|
||||||
null -> createGroup().also { child ->
|
|
||||||
attachChild(token, child)
|
|
||||||
}
|
|
||||||
is VisionGroupBase -> current
|
|
||||||
else -> error("Can't create group with name $name because it exists and not a group")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> createGroups(name.tokens.first().asName()).createGroups(name.cutFirst())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add named or unnamed child to the group. If key is null the child is considered unnamed. Both key and value are not
|
|
||||||
* allowed to be null in the same time. If name is present and [child] is null, the appropriate element is removed.
|
|
||||||
*/
|
|
||||||
override fun set(name: Name?, child: Vision?): Unit {
|
|
||||||
when {
|
|
||||||
name == null -> {
|
|
||||||
if (child != null) {
|
|
||||||
addStatic(child)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
name.isEmpty() -> error("Empty names are not allowed in VisionGroup::set")
|
|
||||||
name.length == 1 -> {
|
|
||||||
val token = name.tokens.first()
|
|
||||||
attachChild(token, child)
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
//TODO add safety check
|
|
||||||
val parent = (get(name.cutLast()) as? MutableVisionGroup) ?: createGroups(name.cutLast())
|
|
||||||
parent[name.tokens.last().asName()] = child
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun update(change: VisionChange) {
|
|
||||||
change.children?.forEach { (name, change) ->
|
|
||||||
when {
|
|
||||||
change.delete -> set(name, null)
|
|
||||||
change.vision != null -> set(name, change.vision)
|
|
||||||
else -> get(name)?.update(change)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.update(change)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Non-serializable root group used to propagate manager to its children
|
|
||||||
*/
|
|
||||||
internal class RootVisionGroup(override val manager: VisionManager) : VisionGroupBase()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Designate this [VisionGroup] as a root and assign a [VisionManager] as its parent
|
|
||||||
*/
|
|
||||||
public fun Vision.setAsRoot(manager: VisionManager) {
|
|
||||||
if (parent != null) error("Vision $this already has a parent. It could not be set as root")
|
|
||||||
parent = RootVisionGroup(manager)
|
|
||||||
}
|
|
@ -25,13 +25,14 @@ public class VisionManager(meta: Meta) : AbstractPlugin(meta) {
|
|||||||
/**
|
/**
|
||||||
* Combined [SerializersModule] for all registered visions
|
* Combined [SerializersModule] for all registered visions
|
||||||
*/
|
*/
|
||||||
public val serializersModule: SerializersModule
|
public val serializersModule: SerializersModule by lazy {
|
||||||
get() = SerializersModule {
|
SerializersModule {
|
||||||
include(defaultSerialModule)
|
include(defaultSerialModule)
|
||||||
context.gather<SerializersModule>(VISION_SERIALIZER_MODULE_TARGET).values.forEach {
|
context.gather<SerializersModule>(VISION_SERIALIZER_MODULE_TARGET).values.forEach {
|
||||||
include(it)
|
include(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public val jsonFormat: Json
|
public val jsonFormat: Json
|
||||||
get() = Json(defaultJson) {
|
get() = Json(defaultJson) {
|
||||||
@ -67,9 +68,8 @@ public class VisionManager(meta: Meta) : AbstractPlugin(meta) {
|
|||||||
|
|
||||||
private val defaultSerialModule: SerializersModule = SerializersModule {
|
private val defaultSerialModule: SerializersModule = SerializersModule {
|
||||||
polymorphic(Vision::class) {
|
polymorphic(Vision::class) {
|
||||||
default { VisionBase.serializer() }
|
default { VisionGroup.serializer() }
|
||||||
subclass(VisionBase.serializer())
|
subclass(VisionGroup.serializer())
|
||||||
subclass(VisionGroupBase.serializer())
|
|
||||||
subclass(VisionOfNumberField.serializer())
|
subclass(VisionOfNumberField.serializer())
|
||||||
subclass(VisionOfTextField.serializer())
|
subclass(VisionOfTextField.serializer())
|
||||||
subclass(VisionOfCheckbox.serializer())
|
subclass(VisionOfCheckbox.serializer())
|
||||||
@ -107,5 +107,17 @@ public abstract class VisionPlugin(meta: Meta = Meta.EMPTY) : AbstractPlugin(met
|
|||||||
*/
|
*/
|
||||||
public val Context.visionManager: VisionManager get() = fetch(VisionManager)
|
public val Context.visionManager: VisionManager get() = fetch(VisionManager)
|
||||||
|
|
||||||
public fun Vision.encodeToString(): String =
|
public fun Vision.encodeToString(): String = manager.encodeToString(this)
|
||||||
manager?.encodeToString(this) ?: error("VisionManager not defined in Vision")
|
|
||||||
|
/**
|
||||||
|
* A root vision attached to [VisionManager]
|
||||||
|
*/
|
||||||
|
public class RootVision(override val manager: VisionManager) : VisionGroup()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Designate this [Vision] as a root and assign a [VisionManager] as its parent
|
||||||
|
*/
|
||||||
|
public fun Vision.setAsRoot(manager: VisionManager) {
|
||||||
|
if (parent != null) error("Vision $this already has a parent. It could not be set as root")
|
||||||
|
parent = RootVision(manager)
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
package space.kscience.visionforge
|
||||||
|
|
||||||
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
import space.kscience.dataforge.meta.MutableMeta
|
||||||
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
|
import space.kscience.dataforge.meta.descriptors.get
|
||||||
|
import space.kscience.dataforge.names.Name
|
||||||
|
import space.kscience.dataforge.names.NameToken
|
||||||
|
import space.kscience.dataforge.names.plus
|
||||||
|
import space.kscience.dataforge.values.Value
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper that emulates delegates reading and writing properties to Vision method
|
||||||
|
*/
|
||||||
|
internal class VisionProperties(
|
||||||
|
val vision: Vision,
|
||||||
|
val nodeName: Name,
|
||||||
|
val visionDescriptor: MetaDescriptor? = vision.descriptor,
|
||||||
|
val inherit: Boolean? = null,
|
||||||
|
val useStyles: Boolean? = null,
|
||||||
|
) : MutableMeta {
|
||||||
|
|
||||||
|
val descriptor: MetaDescriptor? by lazy { visionDescriptor?.get(nodeName) }
|
||||||
|
|
||||||
|
override val items: Map<NameToken, MutableMeta>
|
||||||
|
get() {
|
||||||
|
val metaKeys = vision.meta.getMeta(nodeName)?.items?.keys ?: emptySet()
|
||||||
|
val descriptorKeys = descriptor?.children?.map { NameToken(it.key) } ?: emptySet()
|
||||||
|
val inheritFlag = descriptor?.inherited ?: inherit
|
||||||
|
val stylesFlag = descriptor?.usesStyles ?: useStyles
|
||||||
|
return (metaKeys + descriptorKeys).associateWith {
|
||||||
|
VisionProperties(
|
||||||
|
vision,
|
||||||
|
nodeName + it,
|
||||||
|
visionDescriptor,
|
||||||
|
inheritFlag,
|
||||||
|
stylesFlag
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override var value: Value?
|
||||||
|
get() {
|
||||||
|
val inheritFlag = descriptor?.inherited ?: inherit ?: false
|
||||||
|
val stylesFlag = descriptor?.usesStyles ?: useStyles ?: true
|
||||||
|
return vision.getPropertyValue(nodeName, inheritFlag, stylesFlag, true)
|
||||||
|
}
|
||||||
|
set(value) {
|
||||||
|
vision.setPropertyValue(nodeName, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getOrCreate(name: Name): MutableMeta = VisionProperties(
|
||||||
|
vision,
|
||||||
|
nodeName + name,
|
||||||
|
visionDescriptor,
|
||||||
|
inherit,
|
||||||
|
useStyles
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun setMeta(name: Name, node: Meta?) {
|
||||||
|
vision.setProperty(nodeName + name, node)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String = Meta.toString(this)
|
||||||
|
override fun equals(other: Any?): Boolean = Meta.equals(this, other as? Meta)
|
||||||
|
override fun hashCode(): Int = Meta.hashCode(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
///**
|
||||||
|
// * Accessor to all vision properties
|
||||||
|
// */
|
||||||
|
//public fun Vision.computePropertyValues(
|
||||||
|
// descriptor: MetaDescriptor? = this.descriptor,
|
||||||
|
//): MutableValueProvider = object : MutableValueProvider {
|
||||||
|
// override fun getValue(name: Name): Value? = computeProperty(name, descriptor?.get(name))?.value
|
||||||
|
//
|
||||||
|
// override fun setValue(name: Name, value: Value?) {
|
||||||
|
// setProperty(name, value)
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
@ -1,34 +1,29 @@
|
|||||||
package space.kscience.visionforge
|
package space.kscience.visionforge
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.Configurable
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.MutableMeta
|
import space.kscience.dataforge.meta.MutableMeta
|
||||||
import space.kscience.dataforge.meta.ObservableMutableMeta
|
|
||||||
import space.kscience.dataforge.meta.get
|
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.values.Value
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property containers are used to create a symmetric behaviors for vision properties and style builders
|
* Property containers are used to create a symmetric behaviors for vision properties and style builders
|
||||||
*/
|
*/
|
||||||
public interface VisionPropertyContainer<out V : Vision> {
|
public interface VisionPropertyContainer<out V : Vision> {
|
||||||
|
|
||||||
public val meta: MutableMeta
|
public fun getProperty(
|
||||||
|
|
||||||
public fun getPropertyValue(
|
|
||||||
name: Name,
|
|
||||||
inherit: Boolean = false,
|
|
||||||
includeStyles: Boolean = true,
|
|
||||||
includeDefaults: Boolean = true,
|
|
||||||
): Value?
|
|
||||||
}
|
|
||||||
|
|
||||||
public open class SimpleVisionPropertyContainer<out V : Vision>(
|
|
||||||
override val meta: ObservableMutableMeta,
|
|
||||||
) : VisionPropertyContainer<V>, Configurable {
|
|
||||||
override fun getPropertyValue(
|
|
||||||
name: Name,
|
name: Name,
|
||||||
inherit: Boolean,
|
inherit: Boolean,
|
||||||
includeStyles: Boolean,
|
includeStyles: Boolean,
|
||||||
includeDefaults: Boolean
|
includeDefaults: Boolean,
|
||||||
): Value? = meta[name]?.value
|
): Meta?
|
||||||
|
}
|
||||||
|
|
||||||
|
public open class SimpleVisionPropertyContainer<out V : Vision>(
|
||||||
|
public val meta: MutableMeta,
|
||||||
|
) : VisionPropertyContainer<V> {
|
||||||
|
override fun getProperty(
|
||||||
|
name: Name,
|
||||||
|
inherit: Boolean,
|
||||||
|
includeStyles: Boolean,
|
||||||
|
includeDefaults: Boolean,
|
||||||
|
): Meta? = meta.getMeta(name)
|
||||||
}
|
}
|
@ -9,13 +9,14 @@ import kotlinx.serialization.Serializable
|
|||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.get
|
import space.kscience.dataforge.meta.get
|
||||||
import space.kscience.dataforge.meta.node
|
import space.kscience.dataforge.meta.node
|
||||||
|
import space.kscience.visionforge.properties
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("html.form")
|
@SerialName("html.form")
|
||||||
public class VisionOfHtmlForm(
|
public class VisionOfHtmlForm(
|
||||||
public val formId: String,
|
public val formId: String,
|
||||||
) : VisionOfHtmlInput() {
|
) : VisionOfHtmlInput() {
|
||||||
public var values: Meta? by meta.node()
|
public var values: Meta? by properties().node()
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HtmlFormFragment internal constructor(
|
public class HtmlFormFragment internal constructor(
|
||||||
|
@ -5,11 +5,12 @@ import kotlinx.serialization.Serializable
|
|||||||
import space.kscience.dataforge.meta.boolean
|
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.visionforge.VisionBase
|
import space.kscience.visionforge.VisionGroup
|
||||||
|
import space.kscience.visionforge.properties
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
public abstract class VisionOfHtmlInput : VisionBase() {
|
public abstract class VisionOfHtmlInput : VisionGroup() {
|
||||||
public var disabled: Boolean by meta.boolean(false)
|
public var disabled: Boolean by properties().boolean(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -18,7 +19,7 @@ public class VisionOfTextField(
|
|||||||
public val label: String? = null,
|
public val label: String? = null,
|
||||||
public val name: String? = null,
|
public val name: String? = null,
|
||||||
) : VisionOfHtmlInput() {
|
) : VisionOfHtmlInput() {
|
||||||
public var text: String? by meta.string()
|
public var text: String? by properties().string()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -27,7 +28,7 @@ public class VisionOfCheckbox(
|
|||||||
public val label: String? = null,
|
public val label: String? = null,
|
||||||
public val name: String? = null,
|
public val name: String? = null,
|
||||||
) : VisionOfHtmlInput() {
|
) : VisionOfHtmlInput() {
|
||||||
public var checked: Boolean? by meta.boolean()
|
public var checked: Boolean? by properties().boolean()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -36,7 +37,7 @@ public class VisionOfNumberField(
|
|||||||
public val label: String? = null,
|
public val label: String? = null,
|
||||||
public val name: String? = null,
|
public val name: String? = null,
|
||||||
) : VisionOfHtmlInput() {
|
) : VisionOfHtmlInput() {
|
||||||
public var value: Number? by meta.number()
|
public var value: Number? by properties().number()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -48,6 +49,6 @@ public class VisionOfRangeField(
|
|||||||
public val label: String? = null,
|
public val label: String? = null,
|
||||||
public val name: String? = null,
|
public val name: String? = null,
|
||||||
) : VisionOfHtmlInput() {
|
) : VisionOfHtmlInput() {
|
||||||
public var value: Number? by meta.number()
|
public var value: Number? by properties().number()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ public fun Vision.propertyValue(
|
|||||||
getPropertyValue(name ?: Name.parse(property.name), inherit, includeStyles, includeDefaults)
|
getPropertyValue(name ?: Name.parse(property.name), inherit, includeStyles, includeDefaults)
|
||||||
|
|
||||||
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Value?) {
|
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Value?) {
|
||||||
meta.setValue(name ?: Name.parse(property.name), value)
|
setPropertyValue(name ?: Name.parse(property.name), value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ public fun <T> Vision.propertyValue(
|
|||||||
).let(getter)
|
).let(getter)
|
||||||
|
|
||||||
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
|
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
|
||||||
meta.setValue(name ?: Name.parse(property.name), value?.let(setter))
|
setPropertyValue(name ?: Name.parse(property.name), value?.let(setter))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ package space.kscience.visionforge
|
|||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.meta.descriptors.*
|
import space.kscience.dataforge.meta.descriptors.*
|
||||||
import space.kscience.dataforge.values.asValue
|
import space.kscience.dataforge.values.asValue
|
||||||
|
import space.kscience.dataforge.values.set
|
||||||
|
|
||||||
private const val INHERITED_DESCRIPTOR_ATTRIBUTE = "inherited"
|
private const val INHERITED_DESCRIPTOR_ATTRIBUTE = "inherited"
|
||||||
private const val STYLE_DESCRIPTOR_ATTRIBUTE = "useStyles"
|
private const val STYLE_DESCRIPTOR_ATTRIBUTE = "useStyles"
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package space.kscience.visionforge.visitor
|
package space.kscience.visionforge.visitor
|
||||||
|
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.channels.awaitClose
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
@ -11,7 +10,6 @@ import space.kscience.visionforge.Vision
|
|||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
|
||||||
public suspend fun <T> Vision.flowStatistics(statistics: (Name, Vision) -> T): Flow<T> = callbackFlow<T> {
|
public suspend fun <T> Vision.flowStatistics(statistics: (Name, Vision) -> T): Flow<T> = callbackFlow<T> {
|
||||||
val visitor = object : VisionVisitor {
|
val visitor = object : VisionVisitor {
|
||||||
override suspend fun visit(name: Name, vision: Vision){
|
override suspend fun visit(name: Name, vision: Vision){
|
||||||
|
@ -6,7 +6,7 @@ import kotlinx.coroutines.launch
|
|||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.plus
|
import space.kscience.dataforge.names.plus
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.VisionGroup
|
import space.kscience.visionforge.iterator
|
||||||
|
|
||||||
public interface VisionVisitor {
|
public interface VisionVisitor {
|
||||||
/**
|
/**
|
||||||
@ -19,30 +19,30 @@ public interface VisionVisitor {
|
|||||||
/**
|
/**
|
||||||
* Rearrange children of given group
|
* Rearrange children of given group
|
||||||
*/
|
*/
|
||||||
public suspend fun visitChildren(name: Name, group: VisionGroup) {
|
public suspend fun visitChildren(name: Name, group: Vision) {
|
||||||
//Do nothing by default
|
//Do nothing by default
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun skip(name: Name, vision: Vision): Boolean = false
|
public fun skip(name: Name, vision: Vision): Boolean = false
|
||||||
|
|
||||||
public companion object{
|
public companion object {
|
||||||
private fun CoroutineScope.visitTreeAsync(
|
private fun CoroutineScope.visitTreeAsync(
|
||||||
visionVisitor: VisionVisitor,
|
visionVisitor: VisionVisitor,
|
||||||
name: Name,
|
name: Name,
|
||||||
vision: Vision
|
vision: Vision,
|
||||||
): Job = launch {
|
): Job = launch {
|
||||||
if (visionVisitor.skip(name, vision)) return@launch
|
if (visionVisitor.skip(name, vision)) return@launch
|
||||||
visionVisitor.visit(name, vision)
|
visionVisitor.visit(name, vision)
|
||||||
|
|
||||||
if (vision is VisionGroup) {
|
|
||||||
visionVisitor.visitChildren(name, vision)
|
|
||||||
|
|
||||||
for ((token, child) in vision.children) {
|
visionVisitor.visitChildren(name, vision)
|
||||||
visitTreeAsync(visionVisitor, name + token, child)
|
|
||||||
}
|
for ((token, child) in vision.children) {
|
||||||
|
visitTreeAsync(visionVisitor, name + token, child)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively visit this [Vision] and all children
|
* Recursively visit this [Vision] and all children
|
||||||
*/
|
*/
|
||||||
|
@ -4,13 +4,9 @@ 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.configure
|
|
||||||
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.Vision
|
import space.kscience.visionforge.*
|
||||||
import space.kscience.visionforge.VisionBase
|
|
||||||
import space.kscience.visionforge.VisionManager
|
|
||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
|
|
||||||
@ -36,7 +32,7 @@ fun FlowContent.renderVisionFragment(
|
|||||||
@DFExperimental
|
@DFExperimental
|
||||||
class HtmlTagTest {
|
class HtmlTagTest {
|
||||||
|
|
||||||
fun VisionOutput.base(block: VisionBase.() -> Unit) = VisionBase().apply(block)
|
fun VisionOutput.base(block: VisionGroup.() -> Unit) = VisionGroup().apply(block)
|
||||||
|
|
||||||
val fragment: HtmlVisionFragment = {
|
val fragment: HtmlVisionFragment = {
|
||||||
div {
|
div {
|
||||||
@ -46,10 +42,8 @@ class HtmlTagTest {
|
|||||||
"metaProperty" put 87
|
"metaProperty" put 87
|
||||||
}
|
}
|
||||||
base {
|
base {
|
||||||
configure {
|
setPropertyValue("myProp", 82)
|
||||||
set("myProp", 82)
|
setPropertyValue("otherProp", false)
|
||||||
set("otherProp", false)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,7 +53,7 @@ class HtmlTagTest {
|
|||||||
div {
|
div {
|
||||||
h2 { +"Properties" }
|
h2 { +"Properties" }
|
||||||
ul {
|
ul {
|
||||||
(vision as? VisionBase)?.meta?.items?.forEach {
|
vision.getProperty(Name.EMPTY).items.forEach {
|
||||||
li {
|
li {
|
||||||
a { +it.key.toString() }
|
a { +it.key.toString() }
|
||||||
p { +it.value.toString() }
|
p { +it.value.toString() }
|
||||||
|
@ -1,8 +1,16 @@
|
|||||||
package space.kscience.visionforge.meta
|
package space.kscience.visionforge.meta
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.Scheme
|
||||||
|
import space.kscience.dataforge.meta.SchemeSpec
|
||||||
|
import space.kscience.dataforge.meta.int
|
||||||
|
import space.kscience.dataforge.meta.updateWith
|
||||||
import space.kscience.dataforge.values.asValue
|
import space.kscience.dataforge.values.asValue
|
||||||
import space.kscience.visionforge.VisionBase
|
import space.kscience.dataforge.values.boolean
|
||||||
|
import space.kscience.dataforge.values.int
|
||||||
|
import space.kscience.visionforge.VisionGroup
|
||||||
|
import space.kscience.visionforge.getProperty
|
||||||
|
import space.kscience.visionforge.getPropertyValue
|
||||||
|
import space.kscience.visionforge.setPropertyValue
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertNotEquals
|
import kotlin.test.assertNotEquals
|
||||||
@ -10,22 +18,22 @@ import kotlin.test.assertNotEquals
|
|||||||
class VisionPropertyTest {
|
class VisionPropertyTest {
|
||||||
@Test
|
@Test
|
||||||
fun testPropertyWrite(){
|
fun testPropertyWrite(){
|
||||||
val vision = VisionBase()
|
val vision = VisionGroup()
|
||||||
vision.meta["fff"] = 2
|
vision.setPropertyValue("fff", 2)
|
||||||
vision.meta["fff.ddd"] = false
|
vision.setPropertyValue("fff.ddd", false)
|
||||||
|
|
||||||
assertEquals(2, vision.meta["fff"]?.int)
|
assertEquals(2, vision.getPropertyValue("fff")?.int)
|
||||||
assertEquals(false, vision.meta["fff.ddd"]?.boolean)
|
assertEquals(false, vision.getPropertyValue("fff.ddd")?.boolean)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testPropertyEdit(){
|
fun testPropertyEdit(){
|
||||||
val vision = VisionBase()
|
val vision = VisionGroup()
|
||||||
vision.meta.getOrCreate("fff.ddd").apply {
|
vision.getProperty("fff.ddd").apply {
|
||||||
value = 2.asValue()
|
value = 2.asValue()
|
||||||
}
|
}
|
||||||
assertEquals(2, vision.meta["fff.ddd"]?.int)
|
assertEquals(2, vision.getPropertyValue("fff.ddd")?.int)
|
||||||
assertNotEquals(true, vision.meta["fff.ddd"]?.boolean)
|
assertNotEquals(true, vision.getPropertyValue("fff.ddd")?.boolean)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class TestScheme: Scheme(){
|
internal class TestScheme: Scheme(){
|
||||||
@ -35,10 +43,10 @@ class VisionPropertyTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testPropertyUpdate(){
|
fun testPropertyUpdate(){
|
||||||
val vision = VisionBase()
|
val vision = VisionGroup()
|
||||||
vision.meta.getOrCreate("fff").updateWith(TestScheme){
|
vision.getProperty("fff").updateWith(TestScheme){
|
||||||
ddd = 2
|
ddd = 2
|
||||||
}
|
}
|
||||||
assertEquals(2, vision.meta["fff.ddd"]?.int)
|
assertEquals(2, vision.getPropertyValue("fff.ddd")?.int)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,11 +6,10 @@ import javafx.scene.Node
|
|||||||
import javafx.scene.Parent
|
import javafx.scene.Parent
|
||||||
import javafx.scene.layout.VBox
|
import javafx.scene.layout.VBox
|
||||||
import space.kscience.dataforge.meta.MutableMeta
|
import space.kscience.dataforge.meta.MutableMeta
|
||||||
import space.kscience.dataforge.meta.ObservableMutableMeta
|
|
||||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.computeProperties
|
import space.kscience.visionforge.getProperty
|
||||||
import space.kscience.visionforge.getStyle
|
import space.kscience.visionforge.getStyle
|
||||||
import space.kscience.visionforge.styles
|
import space.kscience.visionforge.styles
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
@ -21,8 +20,8 @@ public class VisionEditorFragment : Fragment() {
|
|||||||
public var vision: Vision? by visionProperty
|
public var vision: Vision? by visionProperty
|
||||||
public val descriptorProperty: SimpleObjectProperty<MetaDescriptor> = SimpleObjectProperty<MetaDescriptor>()
|
public val descriptorProperty: SimpleObjectProperty<MetaDescriptor> = SimpleObjectProperty<MetaDescriptor>()
|
||||||
|
|
||||||
private val configProperty: Binding<ObservableMutableMeta?> = visionProperty.objectBinding { vision ->
|
private val configProperty: Binding<MutableMeta?> = visionProperty.objectBinding { vision ->
|
||||||
vision?.meta
|
vision?.getProperty(Name.EMPTY)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val configEditorProperty: Binding<Node?> = configProperty.objectBinding(descriptorProperty) {
|
private val configEditorProperty: Binding<Node?> = configProperty.objectBinding(descriptorProperty) {
|
||||||
@ -30,7 +29,7 @@ public class VisionEditorFragment : Fragment() {
|
|||||||
val node:FXMetaModel<MutableMeta> = FXMetaModel(
|
val node:FXMetaModel<MutableMeta> = FXMetaModel(
|
||||||
meta,
|
meta,
|
||||||
vision?.descriptor,
|
vision?.descriptor,
|
||||||
vision?.computeProperties(),
|
vision?.meta,
|
||||||
Name.EMPTY,
|
Name.EMPTY,
|
||||||
"Vision properties"
|
"Vision properties"
|
||||||
)
|
)
|
||||||
|
@ -5,17 +5,17 @@ import javafx.scene.control.SelectionMode
|
|||||||
import javafx.scene.control.TreeItem
|
import javafx.scene.control.TreeItem
|
||||||
import javafx.scene.layout.VBox
|
import javafx.scene.layout.VBox
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.VisionGroup
|
import space.kscience.visionforge.solid.SolidGroup
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
|
||||||
private fun toTreeItem(vision: Vision, title: String): TreeItem<Pair<String, Vision>> {
|
private fun toTreeItem(vision: Vision, title: String): TreeItem<Pair<String, Vision>> {
|
||||||
return object : TreeItem<Pair<String, Vision>>(title to vision) {
|
return object : TreeItem<Pair<String, Vision>>(title to vision) {
|
||||||
init {
|
init {
|
||||||
if (vision is VisionGroup) {
|
if (vision is SolidGroup) {
|
||||||
//lazy populate the tree
|
//lazy populate the tree
|
||||||
expandedProperty().onChange { expanded ->
|
expandedProperty().onChange { expanded ->
|
||||||
if (expanded && children.isEmpty()) {
|
if (expanded && children.isEmpty()) {
|
||||||
children.setAll(vision.children.map {
|
children.setAll(vision.items.map {
|
||||||
toTreeItem(it.value, it.key.toString())
|
toTreeItem(it.value, it.key.toString())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -24,7 +24,7 @@ private fun toTreeItem(vision: Vision, title: String): TreeItem<Pair<String, Vis
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun isLeaf(): Boolean {
|
override fun isLeaf(): Boolean {
|
||||||
return !(vision is VisionGroup && vision.children.isNotEmpty())
|
return !(vision is SolidGroup && vision.items.isNotEmpty())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ import space.kscience.dataforge.context.*
|
|||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.boolean
|
import space.kscience.dataforge.meta.boolean
|
||||||
import space.kscience.dataforge.misc.Type
|
import space.kscience.dataforge.misc.Type
|
||||||
import space.kscience.visionforge.computePropertyNode
|
import space.kscience.visionforge.getProperty
|
||||||
import space.kscience.visionforge.solid.FX3DFactory.Companion.TYPE
|
import space.kscience.visionforge.solid.FX3DFactory.Companion.TYPE
|
||||||
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_KEY
|
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_KEY
|
||||||
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_WIREFRAME_KEY
|
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_WIREFRAME_KEY
|
||||||
@ -48,9 +48,9 @@ public class FX3DPlugin : AbstractPlugin() {
|
|||||||
public fun buildNode(obj: Solid): Node {
|
public fun buildNode(obj: Solid): Node {
|
||||||
val binding = VisualObjectFXBinding(this, obj)
|
val binding = VisualObjectFXBinding(this, obj)
|
||||||
return when (obj) {
|
return when (obj) {
|
||||||
is SolidReferenceGroup -> referenceFactory(obj, binding)
|
is SolidReference -> referenceFactory(obj, binding)
|
||||||
is SolidGroup -> {
|
is SolidGroup -> {
|
||||||
Group(obj.children.mapNotNull { (token, obj) ->
|
Group(obj.items.mapNotNull { (token, obj) ->
|
||||||
(obj as? Solid)?.let {
|
(obj as? Solid)?.let {
|
||||||
logger.info { token.toString() }
|
logger.info { token.toString() }
|
||||||
buildNode(it).apply {
|
buildNode(it).apply {
|
||||||
@ -77,7 +77,7 @@ public class FX3DPlugin : AbstractPlugin() {
|
|||||||
is PolyLine -> PolyLine3D(
|
is PolyLine -> PolyLine3D(
|
||||||
obj.points.map { Point3D(it.x, it.y, it.z) },
|
obj.points.map { Point3D(it.x, it.y, it.z) },
|
||||||
obj.thickness.toFloat(),
|
obj.thickness.toFloat(),
|
||||||
obj.computePropertyNode(SolidMaterial.MATERIAL_COLOR_KEY)?.color()
|
obj.getProperty(SolidMaterial.MATERIAL_COLOR_KEY).color()
|
||||||
).apply {
|
).apply {
|
||||||
this.meshView.cullFace = CullFace.FRONT
|
this.meshView.cullFace = CullFace.FRONT
|
||||||
}
|
}
|
||||||
|
@ -8,20 +8,21 @@ import space.kscience.dataforge.names.firstOrNull
|
|||||||
import space.kscience.dataforge.names.isEmpty
|
import space.kscience.dataforge.names.isEmpty
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.onPropertyChange
|
import space.kscience.visionforge.onPropertyChange
|
||||||
|
import space.kscience.visionforge.solid.SolidReference.Companion.REFERENCE_CHILD_PROPERTY_PREFIX
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
public class FXReferenceFactory(public val plugin: FX3DPlugin) : FX3DFactory<SolidReferenceGroup> {
|
public class FXReferenceFactory(public val plugin: FX3DPlugin) : FX3DFactory<SolidReference> {
|
||||||
override val type: KClass<in SolidReferenceGroup> get() = SolidReferenceGroup::class
|
override val type: KClass<in SolidReference> get() = SolidReference::class
|
||||||
|
|
||||||
override fun invoke(obj: SolidReferenceGroup, binding: VisualObjectFXBinding): Node {
|
override fun invoke(obj: SolidReference, binding: VisualObjectFXBinding): Node {
|
||||||
val prototype = obj.prototype
|
val prototype = obj.prototype
|
||||||
val node = plugin.buildNode(prototype)
|
val node = plugin.buildNode(prototype)
|
||||||
|
|
||||||
obj.onPropertyChange { name->
|
obj.onPropertyChange { name->
|
||||||
if (name.firstOrNull()?.body == SolidReferenceGroup.REFERENCE_CHILD_PROPERTY_PREFIX) {
|
if (name.firstOrNull()?.body == REFERENCE_CHILD_PROPERTY_PREFIX) {
|
||||||
val childName = name.firstOrNull()?.index?.let(Name::parse) ?: error("Wrong syntax for reference child property: '$name'")
|
val childName = name.firstOrNull()?.index?.let(Name::parse) ?: error("Wrong syntax for reference child property: '$name'")
|
||||||
val propertyName = name.cutFirst()
|
val propertyName = name.cutFirst()
|
||||||
val referenceChild = obj[childName] ?: error("Reference child with name '$childName' not found")
|
val referenceChild = obj.children[childName] ?: error("Reference child with name '$childName' not found")
|
||||||
val child = node.findChild(childName) ?: error("Object child with name '$childName' not found")
|
val child = node.findChild(childName) ?: error("Object child with name '$childName' not found")
|
||||||
child.updateProperty(referenceChild, propertyName)
|
child.updateProperty(referenceChild, propertyName)
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import space.kscience.dataforge.names.Name
|
|||||||
import space.kscience.dataforge.names.startsWith
|
import space.kscience.dataforge.names.startsWith
|
||||||
import space.kscience.dataforge.values.Value
|
import space.kscience.dataforge.values.Value
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.computePropertyNode
|
import space.kscience.visionforge.getProperty
|
||||||
import space.kscience.visionforge.onPropertyChange
|
import space.kscience.visionforge.onPropertyChange
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ public class VisualObjectFXBinding(public val fx: FX3DPlugin, public val obj: Vi
|
|||||||
public operator fun get(key: Name): ObjectBinding<Meta?> {
|
public operator fun get(key: Name): ObjectBinding<Meta?> {
|
||||||
return bindings.getOrPut(key) {
|
return bindings.getOrPut(key) {
|
||||||
object : ObjectBinding<Meta?>() {
|
object : ObjectBinding<Meta?>() {
|
||||||
override fun computeValue(): Meta? = obj.computePropertyNode(key)
|
override fun computeValue(): Meta = obj.getProperty(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import space.kscience.dataforge.names.Name
|
|||||||
import space.kscience.gdml.*
|
import space.kscience.gdml.*
|
||||||
import space.kscience.visionforge.solid.Solid
|
import space.kscience.visionforge.solid.Solid
|
||||||
import space.kscience.visionforge.solid.SolidMaterial
|
import space.kscience.visionforge.solid.SolidMaterial
|
||||||
import space.kscience.visionforge.solid.invoke
|
import space.kscience.visionforge.solid.set
|
||||||
import space.kscience.visionforge.useStyle
|
import space.kscience.visionforge.useStyle
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ public class GdmlLoaderOptions {
|
|||||||
* Configure paint for given solid with given [GdmlMaterial]
|
* Configure paint for given solid with given [GdmlMaterial]
|
||||||
*/
|
*/
|
||||||
public var configurePaint: SolidMaterial.(material: GdmlMaterial, solid: GdmlSolid) -> Unit =
|
public var configurePaint: SolidMaterial.(material: GdmlMaterial, solid: GdmlSolid) -> Unit =
|
||||||
{ material, _ -> color(randomColor(material)) }
|
{ material, _ -> color.set(randomColor(material)) }
|
||||||
private set
|
private set
|
||||||
|
|
||||||
public fun paint(block: SolidMaterial.(material: GdmlMaterial, solid: GdmlSolid) -> Unit) {
|
public fun paint(block: SolidMaterial.(material: GdmlMaterial, solid: GdmlSolid) -> Unit) {
|
||||||
|
@ -30,10 +30,10 @@ private class GdmlLoader(val settings: GdmlLoaderOptions) {
|
|||||||
private val proto = SolidGroup()
|
private val proto = SolidGroup()
|
||||||
|
|
||||||
private val solids = proto.group(solidsName) {
|
private val solids = proto.group(solidsName) {
|
||||||
setPropertyNode("edges.enabled", false)
|
setPropertyValue("edges.enabled", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val referenceStore = HashMap<Name, MutableList<SolidReferenceGroup>>()
|
private val referenceStore = HashMap<Name, MutableList<SolidReference>>()
|
||||||
|
|
||||||
fun Solid.configureSolid(root: Gdml, parent: GdmlVolume, solid: GdmlSolid) {
|
fun Solid.configureSolid(root: Gdml, parent: GdmlVolume, solid: GdmlSolid) {
|
||||||
val material = parent.materialref.resolve(root) ?: GdmlElement(parent.materialref.ref)
|
val material = parent.materialref.resolve(root) ?: GdmlElement(parent.materialref.ref)
|
||||||
@ -44,7 +44,7 @@ private class GdmlLoader(val settings: GdmlLoaderOptions) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun proxySolid(root: Gdml, group: SolidGroup, solid: GdmlSolid, name: String): SolidReferenceGroup {
|
private fun proxySolid(root: Gdml, group: SolidGroup, solid: GdmlSolid, name: String): SolidReference {
|
||||||
val templateName = solidsName + name
|
val templateName = solidsName + name
|
||||||
if (proto[templateName] == null) {
|
if (proto[templateName] == null) {
|
||||||
solids.addSolid(root, solid, name)
|
solids.addSolid(root, solid, name)
|
||||||
@ -59,7 +59,7 @@ private class GdmlLoader(val settings: GdmlLoaderOptions) {
|
|||||||
group: SolidGroup,
|
group: SolidGroup,
|
||||||
physVolume: GdmlPhysVolume,
|
physVolume: GdmlPhysVolume,
|
||||||
volume: GdmlGroup,
|
volume: GdmlGroup,
|
||||||
): SolidReferenceGroup {
|
): SolidReference {
|
||||||
val templateName = volumesName + volume.name.asName()
|
val templateName = volumesName + volume.name.asName()
|
||||||
if (proto[templateName] == null) {
|
if (proto[templateName] == null) {
|
||||||
proto[templateName] = volume(root, volume)
|
proto[templateName] = volume(root, volume)
|
||||||
@ -321,7 +321,7 @@ private class GdmlLoader(val settings: GdmlLoaderOptions) {
|
|||||||
?: error("Volume with ref ${divisionVolume.volumeref.ref} could not be resolved")
|
?: error("Volume with ref ${divisionVolume.volumeref.ref} could not be resolved")
|
||||||
|
|
||||||
//TODO add divisions
|
//TODO add divisions
|
||||||
set(null, volume(root, volume))
|
children.static(volume(root, volume))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun volume(
|
private fun volume(
|
||||||
@ -355,7 +355,7 @@ private class GdmlLoader(val settings: GdmlLoaderOptions) {
|
|||||||
final.useStyle(rootStyle)
|
final.useStyle(rootStyle)
|
||||||
|
|
||||||
final.prototypes {
|
final.prototypes {
|
||||||
proto.children.forEach { (token, item) ->
|
proto.items.forEach { (token, item) ->
|
||||||
item.parent = null
|
item.parent = null
|
||||||
set(token.asName(), item as? Solid)
|
set(token.asName(), item as? Solid)
|
||||||
}
|
}
|
||||||
@ -383,9 +383,9 @@ public fun Gdml.toVision(block: GdmlLoaderOptions.() -> Unit = {}): SolidGroup {
|
|||||||
* Append Gdml node to the group
|
* Append Gdml node to the group
|
||||||
*/
|
*/
|
||||||
public fun SolidGroup.gdml(gdml: Gdml, key: String? = null, transformer: GdmlLoaderOptions.() -> Unit = {}) {
|
public fun SolidGroup.gdml(gdml: Gdml, key: String? = null, transformer: GdmlLoaderOptions.() -> Unit = {}) {
|
||||||
val visual = gdml.toVision(transformer)
|
val vision = gdml.toVision(transformer)
|
||||||
//println(Visual3DPlugin.json.stringify(VisualGroup3D.serializer(), visual))
|
//println(Visual3DPlugin.json.stringify(VisualGroup3D.serializer(), visual))
|
||||||
set(key, visual)
|
children[key] = vision
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisionBuilder
|
@VisionBuilder
|
||||||
|
@ -6,10 +6,9 @@ import space.kscience.dataforge.names.Name
|
|||||||
import space.kscience.dataforge.names.NameToken
|
import space.kscience.dataforge.names.NameToken
|
||||||
import space.kscience.dataforge.names.length
|
import space.kscience.dataforge.names.length
|
||||||
import space.kscience.dataforge.names.plus
|
import space.kscience.dataforge.names.plus
|
||||||
import space.kscience.visionforge.VisionGroup
|
|
||||||
import space.kscience.visionforge.solid.Solid
|
import space.kscience.visionforge.solid.Solid
|
||||||
import space.kscience.visionforge.solid.SolidGroup
|
import space.kscience.visionforge.solid.SolidGroup
|
||||||
import space.kscience.visionforge.solid.SolidReferenceGroup
|
import space.kscience.visionforge.solid.SolidReference
|
||||||
import space.kscience.visionforge.solid.layer
|
import space.kscience.visionforge.solid.layer
|
||||||
|
|
||||||
|
|
||||||
@ -23,15 +22,15 @@ private class VisionCounterTree(
|
|||||||
var selfCount = 1
|
var selfCount = 1
|
||||||
|
|
||||||
val children: Map<NameToken, VisionCounterTree> by lazy {
|
val children: Map<NameToken, VisionCounterTree> by lazy {
|
||||||
(vision as? VisionGroup)?.children?.mapValues { (key, vision) ->
|
(vision as? SolidGroup)?.items?.mapValues { (key, vision) ->
|
||||||
if (vision is SolidReferenceGroup) {
|
if (vision is SolidReference) {
|
||||||
prototypes.getOrPut(vision.refName) {
|
prototypes.getOrPut(vision.prototypeName) {
|
||||||
VisionCounterTree(vision.refName, vision.prototype, prototypes)
|
VisionCounterTree(vision.prototypeName, vision.prototype, prototypes)
|
||||||
}.apply {
|
}.apply {
|
||||||
selfCount += 1
|
selfCount += 1
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
VisionCounterTree(name + key, vision as Solid, prototypes)
|
VisionCounterTree(name + key, vision, prototypes)
|
||||||
}
|
}
|
||||||
} ?: emptyMap()
|
} ?: emptyMap()
|
||||||
}
|
}
|
||||||
@ -51,10 +50,10 @@ private fun VisionCounterTree.topToBottom(): Sequence<VisionCounterTree> = seque
|
|||||||
}
|
}
|
||||||
|
|
||||||
public fun SolidGroup.markLayers(thresholds: List<Int> = listOf(500, 1000, 20000, 50000)) {
|
public fun SolidGroup.markLayers(thresholds: List<Int> = listOf(500, 1000, 20000, 50000)) {
|
||||||
val logger = manager?.context?.logger
|
val logger = manager.context.logger
|
||||||
val counterTree = VisionCounterTree(Name.EMPTY, this, hashMapOf())
|
val counterTree = VisionCounterTree(Name.EMPTY, this, hashMapOf())
|
||||||
val totalCount = counterTree.childrenCount
|
val totalCount = counterTree.childrenCount
|
||||||
if (totalCount > thresholds.firstOrNull() ?: 0) {
|
if (totalCount > (thresholds.firstOrNull() ?: 0)) {
|
||||||
val allNodes = counterTree.topToBottom().distinct().toMutableList()
|
val allNodes = counterTree.topToBottom().distinct().toMutableList()
|
||||||
//println("tree construction finished")
|
//println("tree construction finished")
|
||||||
allNodes.sortWith(
|
allNodes.sortWith(
|
||||||
|
@ -21,12 +21,12 @@ class TestCubes {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testCubesDirect() {
|
fun testCubesDirect() {
|
||||||
val vision = cubes.toVision()
|
val vision: SolidGroup = cubes.toVision()
|
||||||
// println(Solids.encodeToString(vision))
|
// println(Solids.encodeToString(vision))
|
||||||
val smallBoxPrototype = vision.getPrototype(Name.parse("solids.smallBox")) as? Box
|
val smallBoxPrototype = vision.getPrototype(Name.parse("solids.smallBox")) as? Box
|
||||||
assertNotNull(smallBoxPrototype)
|
assertNotNull(smallBoxPrototype)
|
||||||
assertEquals(30.0, smallBoxPrototype.xSize.toDouble())
|
assertEquals(30.0, smallBoxPrototype.xSize.toDouble())
|
||||||
val smallBoxVision = vision["composite-111.smallBox"]?.unref as? Box
|
val smallBoxVision = vision.children["composite-111.smallBox"]?.unref as? Box
|
||||||
assertNotNull(smallBoxVision)
|
assertNotNull(smallBoxVision)
|
||||||
assertEquals(30.0, smallBoxVision.xSize.toDouble())
|
assertEquals(30.0, smallBoxVision.xSize.toDouble())
|
||||||
}
|
}
|
||||||
@ -55,7 +55,7 @@ class TestCubes {
|
|||||||
assertNotNull(this.prototype)
|
assertNotNull(this.prototype)
|
||||||
}
|
}
|
||||||
if (this is SolidGroup) {
|
if (this is SolidGroup) {
|
||||||
children.forEach {
|
items.forEach {
|
||||||
it.value.checkPrototypes()
|
it.value.checkPrototypes()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,17 +9,18 @@ import space.kscience.dataforge.meta.string
|
|||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.asName
|
import space.kscience.dataforge.names.asName
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.VisionBase
|
import space.kscience.visionforge.VisionGroup
|
||||||
|
import space.kscience.visionforge.properties
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("vision.markup")
|
@SerialName("vision.markup")
|
||||||
public class VisionOfMarkup(
|
public class VisionOfMarkup(
|
||||||
public val format: String = COMMONMARK_FORMAT
|
public val format: String = COMMONMARK_FORMAT
|
||||||
) : VisionBase() {
|
) : VisionGroup() {
|
||||||
|
|
||||||
//TODO add templates
|
//TODO add templates
|
||||||
|
|
||||||
public var content: String? by meta.string(CONTENT_PROPERTY_KEY)
|
public var content: String? by properties().string(CONTENT_PROPERTY_KEY)
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
public val CONTENT_PROPERTY_KEY: Name = "content".asName()
|
public val CONTENT_PROPERTY_KEY: Name = "content".asName()
|
||||||
|
@ -2,21 +2,24 @@ package space.kscience.visionforge.plotly
|
|||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
import space.kscience.dataforge.meta.asObservable
|
||||||
import space.kscience.dataforge.misc.DFExperimental
|
import space.kscience.dataforge.misc.DFExperimental
|
||||||
|
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
|
||||||
import space.kscience.visionforge.VisionBase
|
import space.kscience.visionforge.VisionGroup
|
||||||
|
import space.kscience.visionforge.getProperty
|
||||||
import space.kscience.visionforge.html.VisionOutput
|
import space.kscience.visionforge.html.VisionOutput
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("vision.plotly")
|
@SerialName("vision.plotly")
|
||||||
public class VisionOfPlotly private constructor() : VisionBase() {
|
public class VisionOfPlotly private constructor() : VisionGroup() {
|
||||||
|
|
||||||
public constructor(plot: Plot) : this() {
|
public constructor(plot: Plot) : this() {
|
||||||
properties = plot.meta
|
setProperty(Name.EMPTY, plot.meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
public val plot: Plot get() = Plot(meta)
|
public val plot: Plot get() = Plot(getProperty(Name.EMPTY).asObservable())
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun Plot.asVision(): VisionOfPlotly = VisionOfPlotly(this)
|
public fun Plot.asVision(): VisionOfPlotly = VisionOfPlotly(this)
|
||||||
|
@ -8,7 +8,7 @@ import io.ktor.server.engine.embeddedServer
|
|||||||
import io.ktor.server.html.respondHtml
|
import io.ktor.server.html.respondHtml
|
||||||
import io.ktor.server.http.content.resources
|
import io.ktor.server.http.content.resources
|
||||||
import io.ktor.server.http.content.static
|
import io.ktor.server.http.content.static
|
||||||
import io.ktor.server.plugins.cors.CORS
|
import io.ktor.server.plugins.cors.routing.CORS
|
||||||
import io.ktor.server.response.respond
|
import io.ktor.server.response.respond
|
||||||
import io.ktor.server.response.respondText
|
import io.ktor.server.response.respondText
|
||||||
import io.ktor.server.routing.*
|
import io.ktor.server.routing.*
|
||||||
@ -18,7 +18,6 @@ import io.ktor.server.websocket.webSocket
|
|||||||
import io.ktor.websocket.Frame
|
import io.ktor.websocket.Frame
|
||||||
import kotlinx.coroutines.channels.consumeEach
|
import kotlinx.coroutines.channels.consumeEach
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
@ -717,7 +717,7 @@ public final class space/kscience/visionforge/solid/SolidMaterialKt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public abstract interface class space/kscience/visionforge/solid/SolidReference : space/kscience/visionforge/VisionGroup {
|
public abstract interface class space/kscience/visionforge/solid/SolidReference : space/kscience/visionforge/VisionGroup {
|
||||||
public fun getPropertyValue (Lspace/kscience/dataforge/names/Name;ZZZ)Lspace/kscience/dataforge/values/Value;
|
public fun getProperty (Lspace/kscience/dataforge/names/Name;ZZZ)Lspace/kscience/dataforge/values/Value;
|
||||||
public abstract fun getPrototype ()Lspace/kscience/visionforge/solid/Solid;
|
public abstract fun getPrototype ()Lspace/kscience/visionforge/solid/Solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -728,7 +728,7 @@ public final class space/kscience/visionforge/solid/SolidReferenceGroup : space/
|
|||||||
public fun <init> (Lspace/kscience/dataforge/names/Name;)V
|
public fun <init> (Lspace/kscience/dataforge/names/Name;)V
|
||||||
public fun getChildren ()Ljava/util/Map;
|
public fun getChildren ()Ljava/util/Map;
|
||||||
public fun getDescriptor ()Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;
|
public fun getDescriptor ()Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;
|
||||||
public fun getPropertyValue (Lspace/kscience/dataforge/names/Name;ZZZ)Lspace/kscience/dataforge/values/Value;
|
public fun getProperty (Lspace/kscience/dataforge/names/Name;ZZZ)Lspace/kscience/dataforge/values/Value;
|
||||||
public fun getPrototype ()Lspace/kscience/visionforge/solid/Solid;
|
public fun getPrototype ()Lspace/kscience/visionforge/solid/Solid;
|
||||||
public final fun getRefName ()Lspace/kscience/dataforge/names/Name;
|
public final fun getRefName ()Lspace/kscience/dataforge/names/Name;
|
||||||
public static final fun write$Self (Lspace/kscience/visionforge/solid/SolidReferenceGroup;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V
|
public static final fun write$Self (Lspace/kscience/visionforge/solid/SolidReferenceGroup;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
package space.kscience.visionforge.solid
|
package space.kscience.visionforge.solid
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.Configurable
|
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.asName
|
import space.kscience.dataforge.names.asName
|
||||||
import space.kscience.dataforge.names.plus
|
import space.kscience.dataforge.names.plus
|
||||||
import space.kscience.dataforge.values.*
|
import space.kscience.dataforge.values.*
|
||||||
import space.kscience.visionforge.Colors
|
import space.kscience.visionforge.Colors
|
||||||
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.VisionBuilder
|
import space.kscience.visionforge.VisionBuilder
|
||||||
|
import space.kscience.visionforge.getProperty
|
||||||
import kotlin.properties.ReadOnlyProperty
|
import kotlin.properties.ReadOnlyProperty
|
||||||
|
|
||||||
@VisionBuilder
|
@VisionBuilder
|
||||||
@ -27,8 +28,8 @@ public class ColorAccessor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun Configurable.color(): ReadOnlyProperty<Configurable, ColorAccessor> = ReadOnlyProperty { _, property ->
|
public fun Vision.color(): ReadOnlyProperty<Vision, ColorAccessor> = ReadOnlyProperty { _, property ->
|
||||||
ColorAccessor(meta, property.name.asName())
|
ColorAccessor(getProperty(Name.EMPTY), property.name.asName())
|
||||||
}
|
}
|
||||||
|
|
||||||
public var ColorAccessor?.string: String?
|
public var ColorAccessor?.string: String?
|
||||||
@ -40,21 +41,21 @@ public var ColorAccessor?.string: String?
|
|||||||
/**
|
/**
|
||||||
* Set [webcolor](https://en.wikipedia.org/wiki/Web_colors) as string
|
* Set [webcolor](https://en.wikipedia.org/wiki/Web_colors) as string
|
||||||
*/
|
*/
|
||||||
public operator fun ColorAccessor?.invoke(webColor: String) {
|
public fun ColorAccessor?.set(webColor: String) {
|
||||||
this?.value = webColor.asValue()
|
this?.value = webColor.asValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set color as RGB integer
|
* Set color as RGB integer
|
||||||
*/
|
*/
|
||||||
public operator fun ColorAccessor?.invoke(rgb: Int) {
|
public fun ColorAccessor?.set(rgb: Int) {
|
||||||
this?.value = Colors.rgbToString(rgb).asValue()
|
this?.value = Colors.rgbToString(rgb).asValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set color as RGB
|
* Set color as RGB
|
||||||
*/
|
*/
|
||||||
public operator fun ColorAccessor?.invoke(r: UByte, g: UByte, b: UByte) {
|
public fun ColorAccessor?.set(r: UByte, g: UByte, b: UByte) {
|
||||||
this?.value = Colors.rgbToString(r, g, b).asValue()
|
this?.value = Colors.rgbToString(r, g, b).asValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,11 +3,8 @@ 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.isEmpty
|
import space.kscience.dataforge.meta.isEmpty
|
||||||
import space.kscience.dataforge.meta.update
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.visionforge.VisionBuilder
|
import space.kscience.visionforge.*
|
||||||
import space.kscience.visionforge.VisionContainerBuilder
|
|
||||||
import space.kscience.visionforge.VisionPropertyContainer
|
|
||||||
import space.kscience.visionforge.set
|
|
||||||
|
|
||||||
public enum class CompositeType {
|
public enum class CompositeType {
|
||||||
GROUP, // Dumb sum of meshes
|
GROUP, // Dumb sum of meshes
|
||||||
@ -28,16 +25,16 @@ public class Composite(
|
|||||||
public inline fun VisionContainerBuilder<Solid>.composite(
|
public inline fun VisionContainerBuilder<Solid>.composite(
|
||||||
type: CompositeType,
|
type: CompositeType,
|
||||||
name: String? = null,
|
name: String? = null,
|
||||||
builder: SolidGroup.() -> Unit,
|
@VisionBuilder builder: SolidGroup.() -> Unit,
|
||||||
): Composite {
|
): Composite {
|
||||||
val group = SolidGroup().apply(builder)
|
val group = SolidGroup(builder)
|
||||||
val children = group.children.values.filterIsInstance<Solid>()
|
val children = group.items.values.toList()
|
||||||
if (children.size != 2){
|
if (children.size != 2) {
|
||||||
error("Composite requires exactly two children, but found ${children.size}")
|
error("Composite requires exactly two children, but found ${children.size}")
|
||||||
}
|
}
|
||||||
val res = Composite(type, children[0], children[1])
|
val res = Composite(type, children[0], children[1])
|
||||||
|
|
||||||
res.meta.update(group.meta)
|
res.setProperty(Name.EMPTY, group.getProperty(Name.EMPTY))
|
||||||
|
|
||||||
set(name, res)
|
set(name, res)
|
||||||
return res
|
return res
|
||||||
@ -50,34 +47,34 @@ public inline fun VisionContainerBuilder<Solid>.composite(
|
|||||||
public fun SolidGroup.smartComposite(
|
public fun SolidGroup.smartComposite(
|
||||||
type: CompositeType,
|
type: CompositeType,
|
||||||
name: String? = null,
|
name: String? = null,
|
||||||
builder: SolidGroup.() -> Unit,
|
@VisionBuilder builder: SolidGroup.() -> Unit,
|
||||||
): Solid = if (type == CompositeType.GROUP) {
|
): Solid = if (type == CompositeType.GROUP) {
|
||||||
val group = SolidGroup(builder)
|
val group = SolidGroup(builder)
|
||||||
if (name == null && group.meta.isEmpty()) {
|
if (name == null && group.meta.isEmpty()) {
|
||||||
//append directly to group if no properties are defined
|
//append directly to group if no properties are defined
|
||||||
group.children.forEach { (_, value) ->
|
group.items.forEach { (_, value) ->
|
||||||
value.parent = null
|
value.parent = null
|
||||||
set(null, value)
|
children.static(value)
|
||||||
}
|
}
|
||||||
this
|
this
|
||||||
} else {
|
} else {
|
||||||
set(name, group)
|
children[name] = group
|
||||||
group
|
group
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
composite(type, name, builder)
|
children.composite(type, name, builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisionBuilder
|
@VisionBuilder
|
||||||
public inline fun VisionContainerBuilder<Solid>.union(
|
public inline fun VisionContainerBuilder<Solid>.union(
|
||||||
name: String? = null,
|
name: String? = null,
|
||||||
builder: SolidGroup.() -> Unit
|
builder: SolidGroup.() -> Unit,
|
||||||
): Composite = composite(CompositeType.UNION, name, builder = builder)
|
): Composite = composite(CompositeType.UNION, name, builder = builder)
|
||||||
|
|
||||||
@VisionBuilder
|
@VisionBuilder
|
||||||
public inline fun VisionContainerBuilder<Solid>.subtract(
|
public inline fun VisionContainerBuilder<Solid>.subtract(
|
||||||
name: String? = null,
|
name: String? = null,
|
||||||
builder: SolidGroup.() -> Unit
|
builder: SolidGroup.() -> Unit,
|
||||||
): Composite = composite(CompositeType.SUBTRACT, name, builder = builder)
|
): Composite = composite(CompositeType.SUBTRACT, name, builder = builder)
|
||||||
|
|
||||||
@VisionBuilder
|
@VisionBuilder
|
||||||
|
@ -4,7 +4,7 @@ import kotlinx.serialization.SerialName
|
|||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import space.kscience.dataforge.meta.MutableMeta
|
import space.kscience.dataforge.meta.MutableMeta
|
||||||
import space.kscience.dataforge.meta.ObservableMutableMeta
|
import space.kscience.dataforge.meta.ObservableMutableMeta
|
||||||
import space.kscience.dataforge.meta.configure
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.*
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
import kotlin.math.cos
|
import kotlin.math.cos
|
||||||
@ -40,7 +40,7 @@ public data class Layer(var x: Float, var y: Float, var z: Float, var scale: Flo
|
|||||||
@SerialName("solid.extrude")
|
@SerialName("solid.extrude")
|
||||||
public class Extruded(
|
public class Extruded(
|
||||||
public val shape: List<Point2D>,
|
public val shape: List<Point2D>,
|
||||||
public val layers: List<Layer>
|
public val layers: List<Layer>,
|
||||||
) : SolidBase(), GeometrySolid, VisionPropertyContainer<Extruded> {
|
) : SolidBase(), GeometrySolid, VisionPropertyContainer<Extruded> {
|
||||||
|
|
||||||
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {
|
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {
|
||||||
@ -67,7 +67,7 @@ public class Extruded(
|
|||||||
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)) {
|
||||||
//counter clockwise
|
//counterclockwise
|
||||||
geometryBuilder.face4(
|
geometryBuilder.face4(
|
||||||
lowerLayer[j],
|
lowerLayer[j],
|
||||||
lowerLayer[j + 1],
|
lowerLayer[j + 1],
|
||||||
@ -99,7 +99,7 @@ public class ExtrudeBuilder(
|
|||||||
|
|
||||||
public var layers: MutableList<Layer> = ArrayList(),
|
public var layers: MutableList<Layer> = ArrayList(),
|
||||||
|
|
||||||
config: ObservableMutableMeta = MutableMeta()
|
config: ObservableMutableMeta = MutableMeta(),
|
||||||
) : SimpleVisionPropertyContainer<Extruded>(config) {
|
) : SimpleVisionPropertyContainer<Extruded>(config) {
|
||||||
public fun shape(block: Shape2DBuilder.() -> Unit) {
|
public fun shape(block: Shape2DBuilder.() -> Unit) {
|
||||||
this.shape = Shape2DBuilder().apply(block).build()
|
this.shape = Shape2DBuilder().apply(block).build()
|
||||||
@ -110,12 +110,12 @@ public class ExtrudeBuilder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun build(): Extruded = Extruded(shape, layers).apply {
|
internal fun build(): Extruded = Extruded(shape, layers).apply {
|
||||||
configure(this@ExtrudeBuilder.meta)
|
setProperty(Name.EMPTY, getProperty(Name.EMPTY))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisionBuilder
|
@VisionBuilder
|
||||||
public fun VisionContainerBuilder<Solid>.extruded(
|
public fun VisionContainerBuilder<Solid>.extruded(
|
||||||
name: String? = null,
|
name: String? = null,
|
||||||
action: ExtrudeBuilder.() -> Unit = {}
|
action: ExtrudeBuilder.() -> Unit = {},
|
||||||
): Extruded = ExtrudeBuilder().apply(action).build().also { set(name, it) }
|
): Extruded = ExtrudeBuilder().apply(action).build().also { set(name, it) }
|
@ -1,11 +0,0 @@
|
|||||||
package space.kscience.visionforge.solid
|
|
||||||
|
|
||||||
import kotlin.jvm.JvmInline
|
|
||||||
|
|
||||||
@JvmInline
|
|
||||||
public value class Quaternion(public val values: DoubleArray)
|
|
||||||
|
|
||||||
public operator fun Quaternion.component1(): Double = values[0]
|
|
||||||
public operator fun Quaternion.component2(): Double = values[1]
|
|
||||||
public operator fun Quaternion.component3(): Double = values[2]
|
|
||||||
public operator fun Quaternion.component4(): Double = values[3]
|
|
@ -6,16 +6,12 @@ import space.kscience.dataforge.meta.descriptors.node
|
|||||||
import space.kscience.dataforge.meta.descriptors.value
|
import space.kscience.dataforge.meta.descriptors.value
|
||||||
import space.kscience.dataforge.meta.float
|
import space.kscience.dataforge.meta.float
|
||||||
import space.kscience.dataforge.meta.get
|
import space.kscience.dataforge.meta.get
|
||||||
import space.kscience.dataforge.meta.number
|
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.asName
|
import space.kscience.dataforge.names.asName
|
||||||
import space.kscience.dataforge.names.plus
|
import space.kscience.dataforge.names.plus
|
||||||
import space.kscience.dataforge.values.*
|
import space.kscience.dataforge.values.*
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.*
|
||||||
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.setProperty
|
|
||||||
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
|
||||||
@ -38,7 +34,7 @@ import kotlin.properties.ReadWriteProperty
|
|||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for 3-dimensional [Vision]
|
* Interface for a [Vision] representing a 3D object
|
||||||
*/
|
*/
|
||||||
public interface Solid : Vision {
|
public interface Solid : Vision {
|
||||||
|
|
||||||
@ -121,7 +117,7 @@ public interface Solid : Vision {
|
|||||||
public var Solid.layer: Int
|
public var Solid.layer: Int
|
||||||
get() = getPropertyValue(LAYER_KEY, inherit = true)?.int ?: 0
|
get() = getPropertyValue(LAYER_KEY, inherit = true)?.int ?: 0
|
||||||
set(value) {
|
set(value) {
|
||||||
setProperty(LAYER_KEY, value)
|
setPropertyValue(LAYER_KEY, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Common properties
|
// Common properties
|
||||||
@ -140,23 +136,23 @@ public enum class RotationOrder {
|
|||||||
*/
|
*/
|
||||||
public var Solid.rotationOrder: RotationOrder
|
public var Solid.rotationOrder: RotationOrder
|
||||||
get() = getPropertyValue(Solid.ROTATION_ORDER_KEY)?.enum<RotationOrder>() ?: RotationOrder.XYZ
|
get() = getPropertyValue(Solid.ROTATION_ORDER_KEY)?.enum<RotationOrder>() ?: RotationOrder.XYZ
|
||||||
set(value) = meta.setValue(Solid.ROTATION_ORDER_KEY, value.name.asValue())
|
set(value) = setPropertyValue(Solid.ROTATION_ORDER_KEY, value.name.asValue())
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Preferred number of polygons for displaying the object. If not defined, uses shape or renderer default. Not inherited
|
* Preferred number of polygons for displaying the object. If not defined, uses shape or renderer default. Not inherited
|
||||||
*/
|
*/
|
||||||
public var Solid.detail: Int?
|
public var Solid.detail: Int?
|
||||||
get() = getPropertyValue(DETAIL_KEY, false)?.int
|
get() = getPropertyValue(DETAIL_KEY, inherit = false)?.int
|
||||||
set(value) = meta.setValue(DETAIL_KEY, value?.asValue())
|
set(value) = setPropertyValue(DETAIL_KEY, value?.asValue())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If this property is true, the object will be ignored on render.
|
* If this property is true, the object will be ignored on render.
|
||||||
* Property is not inherited.
|
* Property is not inherited.
|
||||||
*/
|
*/
|
||||||
public var Vision.ignore: Boolean?
|
public var Vision.ignore: Boolean?
|
||||||
get() = getPropertyValue(IGNORE_KEY, false)?.boolean
|
get() = getPropertyValue(IGNORE_KEY, inherit = false)?.boolean
|
||||||
set(value) = meta.setValue(IGNORE_KEY, value?.asValue())
|
set(value) = setPropertyValue(IGNORE_KEY, value?.asValue())
|
||||||
|
|
||||||
//var VisualObject.selected: Boolean?
|
//var VisualObject.selected: Boolean?
|
||||||
// get() = getProperty(SELECTED_KEY).boolean
|
// get() = getProperty(SELECTED_KEY).boolean
|
||||||
@ -165,18 +161,18 @@ public var Vision.ignore: Boolean?
|
|||||||
internal fun float(name: Name, default: Number): ReadWriteProperty<Solid, Number> =
|
internal fun float(name: Name, default: Number): ReadWriteProperty<Solid, Number> =
|
||||||
object : ReadWriteProperty<Solid, Number> {
|
object : ReadWriteProperty<Solid, Number> {
|
||||||
override fun getValue(thisRef: Solid, property: KProperty<*>): Number {
|
override fun getValue(thisRef: Solid, property: KProperty<*>): Number {
|
||||||
return thisRef.meta.getMeta(name)?.number ?: default
|
return thisRef.getPropertyValue(name)?.number ?: default
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setValue(thisRef: Solid, property: KProperty<*>, value: Number) {
|
override fun setValue(thisRef: Solid, property: KProperty<*>, value: Number) {
|
||||||
thisRef.setProperty(name, value)
|
thisRef.setPropertyValue(name, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun point(name: Name, default: Float): ReadWriteProperty<Solid, Point3D?> =
|
internal fun point(name: Name, default: Float): ReadWriteProperty<Solid, Point3D?> =
|
||||||
object : ReadWriteProperty<Solid, Point3D?> {
|
object : ReadWriteProperty<Solid, Point3D?> {
|
||||||
override fun getValue(thisRef: Solid, property: KProperty<*>): Point3D? {
|
override fun getValue(thisRef: Solid, property: KProperty<*>): Point3D? {
|
||||||
val item = thisRef.meta.getMeta(name) ?: return null
|
val item = thisRef.meta[name] ?: return null
|
||||||
return object : Point3D {
|
return object : Point3D {
|
||||||
override val x: Float get() = item[X_KEY]?.float ?: default
|
override val x: Float get() = item[X_KEY]?.float ?: default
|
||||||
override val y: Float get() = item[Y_KEY]?.float ?: default
|
override val y: Float get() = item[Y_KEY]?.float ?: default
|
||||||
@ -186,11 +182,11 @@ internal fun point(name: Name, default: Float): ReadWriteProperty<Solid, Point3D
|
|||||||
|
|
||||||
override fun setValue(thisRef: Solid, property: KProperty<*>, value: Point3D?) {
|
override fun setValue(thisRef: Solid, property: KProperty<*>, value: Point3D?) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
thisRef.meta.setMeta(name, null)
|
thisRef.setProperty(name, null)
|
||||||
} else {
|
} else {
|
||||||
thisRef.setProperty(name + X_KEY, value.x)
|
thisRef.setPropertyValue(name + X_KEY, value.x)
|
||||||
thisRef.setProperty(name + Y_KEY, value.y)
|
thisRef.setPropertyValue(name + Y_KEY, value.y)
|
||||||
thisRef.setProperty(name + Z_KEY, value.z)
|
thisRef.setPropertyValue(name + Z_KEY, value.z)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,24 @@ 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.meta.descriptors.MetaDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.visionforge.VisionBase
|
import space.kscience.dataforge.names.Name
|
||||||
|
import space.kscience.visionforge.AbstractVision
|
||||||
|
import space.kscience.visionforge.VisionChildren
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("solid")
|
@SerialName("solid")
|
||||||
public open class SolidBase : VisionBase(), Solid {
|
public open class SolidBase : AbstractVision(), Solid {
|
||||||
override val descriptor: MetaDescriptor get() = Solid.descriptor
|
override val descriptor: MetaDescriptor get() = Solid.descriptor
|
||||||
|
override val children: VisionChildren get() = VisionChildren.empty(this)
|
||||||
|
|
||||||
|
override fun getProperty(
|
||||||
|
name: Name,
|
||||||
|
inherit: Boolean,
|
||||||
|
includeStyles: Boolean,
|
||||||
|
includeDefaults: Boolean,
|
||||||
|
): MutableMeta {
|
||||||
|
return super<AbstractVision>.getProperty(name, inherit, includeStyles, includeDefaults)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import space.kscience.dataforge.names.Name
|
|||||||
import space.kscience.dataforge.names.NameToken
|
import space.kscience.dataforge.names.NameToken
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.*
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A container with prototype support
|
* A container with prototype support
|
||||||
*/
|
*/
|
||||||
@ -23,20 +24,26 @@ public interface PrototypeHolder {
|
|||||||
public fun getPrototype(name: Name): Solid?
|
public fun getPrototype(name: Name): Solid?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents 3-dimensional Visual Group
|
* A [Solid] group with additional accessor methods
|
||||||
* @param prototypes A container for templates visible inside this group
|
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("group.solid")
|
@SerialName("group.solid")
|
||||||
public class SolidGroup : VisionGroupBase(), Solid, PrototypeHolder {
|
public class SolidGroup : VisionGroup(), Solid, PrototypeHolder, MutableVisionGroup, VisionContainerBuilder<Solid> {
|
||||||
|
|
||||||
override val children: Map<NameToken, Vision> get() = super.childrenInternal.filter { it.key != PROTOTYPES_TOKEN }
|
public val items: Map<NameToken, Solid>
|
||||||
|
get() = children.keys.mapNotNull {
|
||||||
|
val value = children[it] as? Solid ?: return@mapNotNull null
|
||||||
|
it to value
|
||||||
|
}.toMap()
|
||||||
|
|
||||||
private var prototypes: MutableVisionGroup?
|
public operator fun get(name: Name): Solid? = children[name] as? Solid
|
||||||
get() = childrenInternal[PROTOTYPES_TOKEN] as? MutableVisionGroup
|
|
||||||
|
private var prototypes: SolidGroup?
|
||||||
|
get() = items[PROTOTYPES_TOKEN] as? SolidGroup
|
||||||
set(value) {
|
set(value) {
|
||||||
set(PROTOTYPES_TOKEN, value)
|
children[PROTOTYPES_TOKEN] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -53,36 +60,38 @@ public class SolidGroup : VisionGroupBase(), Solid, PrototypeHolder {
|
|||||||
* Create or edit prototype node as a group
|
* Create or edit prototype node as a group
|
||||||
*/
|
*/
|
||||||
override fun prototypes(builder: VisionContainerBuilder<Solid>.() -> Unit): Unit {
|
override fun prototypes(builder: VisionContainerBuilder<Solid>.() -> Unit): Unit {
|
||||||
(prototypes ?: SolidGroup().also {
|
(prototypes ?: SolidGroup().also { prototypes = it }).children.run(builder)
|
||||||
prototypes = it
|
|
||||||
}).run(builder)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createGroup(): SolidGroup = SolidGroup()
|
override fun createGroup(): SolidGroup = SolidGroup()
|
||||||
|
|
||||||
//
|
//
|
||||||
// override fun update(change: VisionChange) {
|
// override fun update(change: VisionChange) {
|
||||||
// updatePosition(change.properties)
|
// updatePosition(change.properties)
|
||||||
// super.update(change)
|
// super.update(change)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
override fun set(name: Name?, child: Solid?) {
|
||||||
|
children[name] = child
|
||||||
|
}
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
public val PROTOTYPES_TOKEN: NameToken = NameToken("@prototypes")
|
public val PROTOTYPES_TOKEN: NameToken = NameToken("@prototypes")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("FunctionName")
|
public inline fun SolidGroup(block: SolidGroup.() -> Unit): SolidGroup = SolidGroup().apply(block)
|
||||||
public fun SolidGroup(block: SolidGroup.() -> Unit): SolidGroup = SolidGroup().apply(block)
|
|
||||||
|
|
||||||
@VisionBuilder
|
@VisionBuilder
|
||||||
public fun VisionContainerBuilder<Vision>.group(
|
public fun VisionContainerBuilder<Solid>.group(
|
||||||
name: Name? = null,
|
name: Name? = null,
|
||||||
builder: SolidGroup.() -> Unit = {},
|
builder: SolidGroup.() -> Unit = {},
|
||||||
): SolidGroup = SolidGroup().apply(builder).also { set(name, it) }
|
): SolidGroup = SolidGroup(builder).also { set(name, it) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define a group with given [name], attach it to this parent and return it.
|
* Define a group with given [name], attach it to this parent and return it.
|
||||||
*/
|
*/
|
||||||
@VisionBuilder
|
@VisionBuilder
|
||||||
public fun VisionContainerBuilder<Vision>.group(name: String, action: SolidGroup.() -> Unit = {}): SolidGroup =
|
public fun VisionContainerBuilder<Solid>.group(
|
||||||
SolidGroup().apply(action).also { set(name, it) }
|
name: String,
|
||||||
|
action: SolidGroup.() -> Unit = {},
|
||||||
|
): SolidGroup = SolidGroup(action).also { set(name, it) }
|
||||||
|
@ -9,6 +9,7 @@ import space.kscience.dataforge.names.plus
|
|||||||
import space.kscience.dataforge.values.ValueType
|
import space.kscience.dataforge.values.ValueType
|
||||||
import space.kscience.dataforge.values.asValue
|
import space.kscience.dataforge.values.asValue
|
||||||
import space.kscience.dataforge.values.number
|
import space.kscience.dataforge.values.number
|
||||||
|
import space.kscience.dataforge.values.set
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.*
|
||||||
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY
|
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY
|
||||||
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_KEY
|
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_KEY
|
||||||
@ -101,19 +102,19 @@ public class SolidMaterial : Scheme() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public val Solid.color: ColorAccessor
|
public val Solid.color: ColorAccessor
|
||||||
get() = ColorAccessor(computePropertyValues(), MATERIAL_COLOR_KEY)
|
get() = ColorAccessor(getProperty(Name.EMPTY), MATERIAL_COLOR_KEY)
|
||||||
|
|
||||||
public var Solid.material: SolidMaterial?
|
public var Solid.material: SolidMaterial?
|
||||||
get() = computePropertyNode(MATERIAL_KEY)?.let { SolidMaterial.read(it) }
|
get() = SolidMaterial.read(getProperty(MATERIAL_KEY))
|
||||||
set(value) = meta.setMeta(MATERIAL_KEY, value?.meta)
|
set(value) = setProperty(MATERIAL_KEY, value?.meta)
|
||||||
|
|
||||||
@VisionBuilder
|
@VisionBuilder
|
||||||
public fun Solid.material(builder: SolidMaterial.() -> Unit) {
|
public fun Solid.material(builder: SolidMaterial.() -> Unit) {
|
||||||
meta.getOrCreate(MATERIAL_KEY).updateWith(SolidMaterial, builder)
|
getProperty(MATERIAL_KEY).updateWith(SolidMaterial, builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var Solid.opacity: Number?
|
public var Solid.opacity: Number?
|
||||||
get() = getPropertyValue(MATERIAL_OPACITY_KEY, inherit = true)?.number
|
get() = getPropertyValue(MATERIAL_OPACITY_KEY, inherit = true)?.number
|
||||||
set(value) {
|
set(value) {
|
||||||
meta.setValue(MATERIAL_OPACITY_KEY, value?.asValue())
|
setPropertyValue(MATERIAL_OPACITY_KEY, value?.asValue())
|
||||||
}
|
}
|
@ -1,38 +1,15 @@
|
|||||||
package space.kscience.visionforge.solid
|
package space.kscience.visionforge.solid
|
||||||
|
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
|
import kotlinx.coroutines.flow.emptyFlow
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import space.kscience.dataforge.meta.ObservableMutableMeta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
|
||||||
import space.kscience.dataforge.meta.get
|
|
||||||
import space.kscience.dataforge.names.*
|
import space.kscience.dataforge.names.*
|
||||||
import space.kscience.dataforge.values.Value
|
import space.kscience.dataforge.values.Value
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.*
|
||||||
|
import space.kscience.visionforge.solid.SolidReference.Companion.REFERENCE_CHILD_PROPERTY_PREFIX
|
||||||
|
|
||||||
public interface SolidReference : VisionGroup {
|
|
||||||
/**
|
|
||||||
* The prototype for this reference.
|
|
||||||
*/
|
|
||||||
public val prototype: Solid
|
|
||||||
|
|
||||||
override fun getPropertyValue(
|
|
||||||
name: Name,
|
|
||||||
inherit: Boolean,
|
|
||||||
includeStyles: Boolean,
|
|
||||||
includeDefaults: Boolean
|
|
||||||
): Value? {
|
|
||||||
meta[name]?.value?.let { return it }
|
|
||||||
if (includeStyles) {
|
|
||||||
getStyleProperty(name)?.let { return it }
|
|
||||||
}
|
|
||||||
prototype.getPropertyValue(name, inherit, includeStyles, includeDefaults)?.let { return it }
|
|
||||||
if (inherit) {
|
|
||||||
parent?.getPropertyValue(name, inherit, includeStyles, includeDefaults)?.let { return it }
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,103 +23,116 @@ public val Vision.unref: Solid
|
|||||||
else -> error("This Vision is neither Solid nor SolidReference")
|
else -> error("This Vision is neither Solid nor SolidReference")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun childToken(childName: Name): NameToken =
|
|
||||||
NameToken(SolidReferenceGroup.REFERENCE_CHILD_PROPERTY_PREFIX, childName.toString())
|
|
||||||
|
|
||||||
private fun childPropertyName(childName: Name, propertyName: Name): Name =
|
|
||||||
childToken(childName) + propertyName
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A reference [Solid] to reuse a template object
|
* @param name A name of reference child relative to prototype root
|
||||||
*/
|
*/
|
||||||
@Serializable
|
internal class SolidReferenceChild(
|
||||||
@SerialName("solid.ref")
|
val owner: SolidReference,
|
||||||
public class SolidReferenceGroup(
|
override var parent: Vision?,
|
||||||
public val refName: Name,
|
val childName: Name,
|
||||||
) : VisionBase(), SolidReference, VisionGroup, Solid {
|
) : Solid {
|
||||||
|
|
||||||
/**
|
val prototype: Solid
|
||||||
* Recursively search for defined template in the parent
|
get() = owner.prototype.children[childName] as? Solid
|
||||||
*/
|
?: error("Prototype with name $childName not found")
|
||||||
override val prototype: Solid by lazy {
|
|
||||||
if (parent == null) error("No parent is present for SolidReferenceGroup")
|
|
||||||
if (parent !is PrototypeHolder) error("Parent does not hold prototypes")
|
|
||||||
(parent as? PrototypeHolder)?.getPrototype(refName) ?: error("Prototype with name $refName not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
override val children: Map<NameToken, Vision>
|
override val meta: Meta get() = owner.getProperty(childToken(childName).asName())
|
||||||
get() = (prototype as? VisionGroup)?.children
|
|
||||||
?.filter { it.key != SolidGroup.PROTOTYPES_TOKEN }
|
|
||||||
?.mapValues {
|
|
||||||
ReferenceChild(this, it.key.asName())
|
|
||||||
} ?: emptyMap()
|
|
||||||
|
|
||||||
override fun getPropertyValue(
|
override fun getPropertyValue(
|
||||||
name: Name,
|
name: Name,
|
||||||
inherit: Boolean,
|
inherit: Boolean,
|
||||||
includeStyles: Boolean,
|
includeStyles: Boolean,
|
||||||
includeDefaults: Boolean
|
includeDefaults: Boolean,
|
||||||
): Value? = super<SolidReference>.getPropertyValue(name, inherit, includeStyles, includeDefaults)
|
): Value? {
|
||||||
|
owner.getPropertyValue(
|
||||||
override val descriptor: MetaDescriptor get() = prototype.descriptor
|
childPropertyName(childName, name), inherit, includeStyles, includeDefaults
|
||||||
|
)?.let { return it }
|
||||||
|
if (includeStyles) {
|
||||||
/**
|
getStyleProperty(name)?.value?.let { return it }
|
||||||
* A ProxyChild is created temporarily only to interact with properties, it does not store any values
|
|
||||||
* (properties are stored in external cache) and created and destroyed on-demand).
|
|
||||||
*/
|
|
||||||
private class ReferenceChild(
|
|
||||||
val owner: SolidReferenceGroup,
|
|
||||||
private val refName: Name
|
|
||||||
) : SolidReference, VisionGroup, Solid {
|
|
||||||
|
|
||||||
override val prototype: Solid by lazy {
|
|
||||||
if (refName.isEmpty()) {
|
|
||||||
owner.prototype
|
|
||||||
} else {
|
|
||||||
val proto = (owner.prototype as? VisionGroup)?.get(refName)
|
|
||||||
?: error("Prototype with name $refName not found in SolidReferenceGroup ${owner.refName}")
|
|
||||||
proto as? Solid ?: error("Prototype with name $refName is ${proto::class} but expected Solid")
|
|
||||||
// proto.unref as? Solid
|
|
||||||
// ?: error("Prototype with name $refName is ${proto::class} but expected Solid")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
prototype.getPropertyValue(name, inherit, includeStyles, includeDefaults)?.let { return it }
|
||||||
override val meta: ObservableMutableMeta by lazy {
|
if (inherit) {
|
||||||
owner.meta.getOrCreate(childToken(refName).asName())
|
parent?.getPropertyValue(name, inherit, includeStyles, includeDefaults)?.let { return it }
|
||||||
}
|
}
|
||||||
|
return null
|
||||||
override val children: Map<NameToken, Vision>
|
|
||||||
get() = (prototype as? VisionGroup)?.children
|
|
||||||
?.filter { it.key != SolidGroup.PROTOTYPES_TOKEN }
|
|
||||||
?.mapValues { (key, _) ->
|
|
||||||
ReferenceChild(owner, refName + key.asName())
|
|
||||||
} ?: emptyMap()
|
|
||||||
|
|
||||||
override var parent: VisionGroup?
|
|
||||||
get() {
|
|
||||||
val parentName = refName.cutLast()
|
|
||||||
return if (parentName.isEmpty()) owner else ReferenceChild(owner, parentName)
|
|
||||||
}
|
|
||||||
set(_) {
|
|
||||||
error("Setting a parent for a reference child is not possible")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun invalidateProperty(propertyName: Name) {
|
|
||||||
owner.invalidateProperty(childPropertyName(refName, propertyName))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun update(change: VisionChange) {
|
|
||||||
change.properties?.let {
|
|
||||||
updateProperties(Name.EMPTY, it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override val descriptor: MetaDescriptor get() = prototype.descriptor
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public companion object {
|
override fun setProperty(name: Name, node: Meta?) {
|
||||||
|
owner.setProperty(childPropertyName(childName, name), node)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setPropertyValue(name: Name, value: Value?) {
|
||||||
|
owner.setPropertyValue(childPropertyName(childName, name), value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val propertyChanges: SharedFlow<Name>
|
||||||
|
get() = TODO("Not yet implemented")
|
||||||
|
|
||||||
|
override fun invalidateProperty(propertyName: Name) {
|
||||||
|
owner.invalidateProperty(childPropertyName(childName, propertyName))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun update(change: VisionChange) {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override val children: VisionChildren = object : VisionChildren {
|
||||||
|
override val parent: Vision get() = this@SolidReferenceChild
|
||||||
|
|
||||||
|
override val keys: Set<NameToken> get() = prototype.children.keys
|
||||||
|
|
||||||
|
override val changes: Flow<Name> get() = emptyFlow()
|
||||||
|
|
||||||
|
override fun get(token: NameToken): SolidReferenceChild? {
|
||||||
|
if (token !in prototype.children.keys) return null
|
||||||
|
return SolidReferenceChild(this@SolidReferenceChild.owner, this@SolidReferenceChild, childName + token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private fun childToken(childName: Name): NameToken =
|
||||||
|
NameToken(REFERENCE_CHILD_PROPERTY_PREFIX, childName.toString())
|
||||||
|
|
||||||
|
private fun childPropertyName(childName: Name, propertyName: Name): Name =
|
||||||
|
childToken(childName) + propertyName
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("solid.ref")
|
||||||
|
public class SolidReference(
|
||||||
|
@SerialName("prototype") public val prototypeName: Name,
|
||||||
|
) : SolidBase() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The prototype for this reference.
|
||||||
|
*/
|
||||||
|
public val prototype: Solid by lazy {
|
||||||
|
//Recursively search for defined template in the parent
|
||||||
|
if (parent == null) error("No parent is present for SolidReference")
|
||||||
|
if (parent !is PrototypeHolder) error("Parent does not hold prototypes")
|
||||||
|
(parent as? PrototypeHolder)?.getPrototype(prototypeName)
|
||||||
|
?: error("Prototype with name $prototypeName not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
override val children: VisionChildren
|
||||||
|
get() = object : VisionChildren {
|
||||||
|
override val parent: Vision get() = this@SolidReference
|
||||||
|
|
||||||
|
override val keys: Set<NameToken> get() = prototype.children.keys
|
||||||
|
|
||||||
|
override val changes: Flow<Name> get() = emptyFlow()
|
||||||
|
|
||||||
|
override fun get(token: NameToken): SolidReferenceChild? {
|
||||||
|
if (token !in prototype.children.keys) return null
|
||||||
|
return SolidReferenceChild(this@SolidReference, this@SolidReference, token.asName())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public companion object{
|
||||||
public const val REFERENCE_CHILD_PROPERTY_PREFIX: String = "@child"
|
public const val REFERENCE_CHILD_PROPERTY_PREFIX: String = "@child"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -150,33 +140,123 @@ public class SolidReferenceGroup(
|
|||||||
/**
|
/**
|
||||||
* Create ref for existing prototype
|
* Create ref for existing prototype
|
||||||
*/
|
*/
|
||||||
public fun SolidGroup.ref(
|
public fun VisionContainerBuilder<Solid>.ref(
|
||||||
templateName: Name,
|
templateName: Name,
|
||||||
name: String? = null,
|
name: String? = null,
|
||||||
): SolidReferenceGroup = SolidReferenceGroup(templateName).also { set(name, it) }
|
): SolidReference = SolidReference(templateName).also { set(name, it) }
|
||||||
|
|
||||||
public fun SolidGroup.ref(
|
public fun VisionContainerBuilder<Solid>.ref(
|
||||||
templateName: String,
|
templateName: String,
|
||||||
name: String? = null,
|
name: String? = null,
|
||||||
): SolidReferenceGroup = ref(Name.parse(templateName), name)
|
): SolidReference = ref(Name.parse(templateName), name)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add new [SolidReferenceGroup] wrapping given object and automatically adding it to the prototypes.
|
* Add new [SolidReference] wrapping given object and automatically adding it to the prototypes.
|
||||||
* One must ensure that [prototypeHolder] is a parent of this group.
|
|
||||||
*/
|
*/
|
||||||
public fun SolidGroup.newRef(
|
public fun SolidGroup.newRef(
|
||||||
name: String?,
|
name: String?,
|
||||||
obj: Solid,
|
obj: Solid,
|
||||||
prototypeHolder: PrototypeHolder = this,
|
prototypeHolder: SolidGroup = this,
|
||||||
templateName: Name = Name.parse(name ?: obj.toString()),
|
prototypeName: Name = Name.parse(name ?: obj.toString()),
|
||||||
): SolidReferenceGroup {
|
): SolidReference {
|
||||||
val existing = getPrototype(templateName)
|
val existing = prototypeHolder.getPrototype(prototypeName)
|
||||||
if (existing == null) {
|
if (existing == null) {
|
||||||
prototypeHolder.prototypes {
|
prototypeHolder.prototypes {
|
||||||
set(templateName, obj)
|
set(prototypeName, obj)
|
||||||
}
|
}
|
||||||
} else if (existing != obj) {
|
} else if (existing != obj) {
|
||||||
error("Can't add different prototype on top of existing one")
|
error("Can't add different prototype on top of existing one")
|
||||||
}
|
}
|
||||||
return ref(templateName, name)
|
return children.ref(prototypeName, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
///**
|
||||||
|
// * A reference [Solid] to reuse a template object
|
||||||
|
// */
|
||||||
|
//@Serializable
|
||||||
|
//@SerialName("solid.ref")
|
||||||
|
//public class SolidReferenceGroup(
|
||||||
|
// public val refName: Name,
|
||||||
|
//) : VisionGroup(), SolidReference, VisionGroup<Solid>, Solid {
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Recursively search for defined template in the parent
|
||||||
|
// */
|
||||||
|
// override val prototype: Solid by lazy {
|
||||||
|
// if (parent == null) error("No parent is present for SolidReferenceGroup")
|
||||||
|
// if (parent !is PrototypeHolder) error("Parent does not hold prototypes")
|
||||||
|
// (parent as? PrototypeHolder)?.getPrototype(refName) ?: error("Prototype with name $refName not found")
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override val items: Map<NameToken, VisionGroupItem<Solid>>
|
||||||
|
// get() = (prototype as? VisionGroup<*>)?.items
|
||||||
|
// ?.filter { it.key != SolidGroup.PROTOTYPES_TOKEN }
|
||||||
|
// ?.mapValues {
|
||||||
|
// VisionGroupItem.Node(ReferenceChild(this, it.key.asName()))
|
||||||
|
// } ?: emptyMap()
|
||||||
|
//
|
||||||
|
// override val descriptor: MetaDescriptor get() = prototype.descriptor
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * A ProxyChild is created temporarily only to interact with properties, it does not store any values
|
||||||
|
// * (properties are stored in external cache) and created and destroyed on-demand).
|
||||||
|
// */
|
||||||
|
// private class ReferenceChild(
|
||||||
|
// val owner: SolidReferenceGroup,
|
||||||
|
// private val refName: Name,
|
||||||
|
// ) : SolidReference, VisionGroup<Solid>, Solid {
|
||||||
|
//
|
||||||
|
// override val prototype: Solid by lazy {
|
||||||
|
// if (refName.isEmpty()) {
|
||||||
|
// owner.prototype
|
||||||
|
// } else {
|
||||||
|
// val proto = (owner.prototype).children.get(refName)
|
||||||
|
// ?: error("Prototype with name $refName not found in SolidReferenceGroup ${owner.refName}")
|
||||||
|
// proto as? Solid ?: error("Prototype with name $refName is ${proto::class} but expected Solid")
|
||||||
|
//// proto.unref as? Solid
|
||||||
|
//// ?: error("Prototype with name $refName is ${proto::class} but expected Solid")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override val meta: ObservableMutableMeta by lazy {
|
||||||
|
// owner.meta.getOrCreate(childToken(refName).asName())
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override val items: Map<NameToken, VisionGroupItem<Solid>>
|
||||||
|
// get() = (prototype as? VisionGroup<*>)?.items
|
||||||
|
// ?.filter { it.key != SolidGroup.PROTOTYPES_TOKEN }
|
||||||
|
// ?.mapValues { (key, _) ->
|
||||||
|
// VisionGroupItem.Node(ReferenceChild(owner, refName + key.asName()))
|
||||||
|
// } ?: emptyMap()
|
||||||
|
//
|
||||||
|
// override var parent: VisionGroup<*>?
|
||||||
|
// get() {
|
||||||
|
// val parentName = refName.cutLast()
|
||||||
|
// return if (parentName.isEmpty()) owner else ReferenceChild(owner, parentName)
|
||||||
|
// }
|
||||||
|
// set(_) {
|
||||||
|
// error("Setting a parent for a reference child is not possible")
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun invalidateProperty(propertyName: Name) {
|
||||||
|
// owner.invalidateProperty(childPropertyName(refName, propertyName))
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun update(change: VisionChange) {
|
||||||
|
// change.properties?.let {
|
||||||
|
// updateProperties(it, Name.EMPTY)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override val descriptor: MetaDescriptor get() = prototype.descriptor
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public companion object {
|
||||||
|
// public const val REFERENCE_CHILD_PROPERTY_PREFIX: String = "@child"
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
@ -29,7 +29,7 @@ public class Solids(meta: Meta) : VisionPlugin(meta) {
|
|||||||
|
|
||||||
private fun PolymorphicModuleBuilder<Solid>.solids() {
|
private fun PolymorphicModuleBuilder<Solid>.solids() {
|
||||||
subclass(SolidGroup.serializer())
|
subclass(SolidGroup.serializer())
|
||||||
subclass(SolidReferenceGroup.serializer())
|
subclass(SolidReference.serializer())
|
||||||
subclass(Composite.serializer())
|
subclass(Composite.serializer())
|
||||||
subclass(Box.serializer())
|
subclass(Box.serializer())
|
||||||
subclass(GenericHexagon.serializer())
|
subclass(GenericHexagon.serializer())
|
||||||
@ -47,8 +47,7 @@ public class Solids(meta: Meta) : VisionPlugin(meta) {
|
|||||||
|
|
||||||
public val serializersModuleForSolids: SerializersModule = SerializersModule {
|
public val serializersModuleForSolids: SerializersModule = SerializersModule {
|
||||||
polymorphic(Vision::class) {
|
polymorphic(Vision::class) {
|
||||||
subclass(VisionBase.serializer())
|
subclass(VisionGroup.serializer())
|
||||||
subclass(VisionGroupBase.serializer())
|
|
||||||
solids()
|
solids()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ public class Sphere(
|
|||||||
) : SolidBase(), GeometrySolid, VisionPropertyContainer<Sphere> {
|
) : SolidBase(), GeometrySolid, VisionPropertyContainer<Sphere> {
|
||||||
|
|
||||||
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {
|
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {
|
||||||
fun point3DfromSphCoord(r: Float, theta: Float, phi: Float): Point3D {
|
fun point3dFromSphCoord(r: Float, theta: Float, phi: Float): Point3D {
|
||||||
// This transformation matches three.js sphere implementation
|
// This transformation matches three.js sphere implementation
|
||||||
val y = r * cos(theta)
|
val y = r * cos(theta)
|
||||||
val z = r * sin(theta) * sin(phi)
|
val z = r * sin(theta) * sin(phi)
|
||||||
@ -39,10 +39,10 @@ public class Sphere(
|
|||||||
for (j in 0 until segments) { // phi iteration
|
for (j in 0 until segments) { // phi iteration
|
||||||
val phi1 = phiStart + j * phiStep
|
val phi1 = phiStart + j * phiStep
|
||||||
val phi2 = phi1 + phiStep
|
val phi2 = phi1 + phiStep
|
||||||
val point1 = point3DfromSphCoord(radius, theta1, phi1)
|
val point1 = point3dFromSphCoord(radius, theta1, phi1)
|
||||||
val point2 = point3DfromSphCoord(radius, theta1, phi2)
|
val point2 = point3dFromSphCoord(radius, theta1, phi2)
|
||||||
val point3 = point3DfromSphCoord(radius, theta2, phi2)
|
val point3 = point3dFromSphCoord(radius, theta2, phi2)
|
||||||
val point4 = point3DfromSphCoord(radius, theta2, phi1)
|
val point4 = point3dFromSphCoord(radius, theta2, phi1)
|
||||||
geometryBuilder.apply {
|
geometryBuilder.apply {
|
||||||
// 1-2-3-4 gives the same face but with opposite orientation
|
// 1-2-3-4 gives the same face but with opposite orientation
|
||||||
face4(point1, point4, point3, point2)
|
face4(point1, point4, point3, point2)
|
||||||
|
@ -27,7 +27,7 @@ public class SphereLayer(
|
|||||||
require(outerRadius > 0) { "Outer radius must be positive" }
|
require(outerRadius > 0) { "Outer radius must be positive" }
|
||||||
require(innerRadius >= 0) { "inner radius must be non-negative" }
|
require(innerRadius >= 0) { "inner radius must be non-negative" }
|
||||||
|
|
||||||
fun point3DfromSphCoord(r: Float, theta: Float, phi: Float): Point3D {
|
fun point3dFromSphCoord(r: Float, theta: Float, phi: Float): Point3D {
|
||||||
// This transformation matches three.js sphere implementation
|
// This transformation matches three.js sphere implementation
|
||||||
val y = r * cos(theta)
|
val y = r * cos(theta)
|
||||||
val z = r * sin(theta) * sin(phi)
|
val z = r * sin(theta) * sin(phi)
|
||||||
@ -46,17 +46,17 @@ public class SphereLayer(
|
|||||||
val phi1 = phiStart + j * phiStep
|
val phi1 = phiStart + j * phiStep
|
||||||
val phi2 = phi1 + phiStep
|
val phi2 = phi1 + phiStep
|
||||||
//outer points
|
//outer points
|
||||||
val outerPoint1 = point3DfromSphCoord(outerRadius, theta1, phi1)
|
val outerPoint1 = point3dFromSphCoord(outerRadius, theta1, phi1)
|
||||||
val outerPoint2 = point3DfromSphCoord(outerRadius, theta1, phi2)
|
val outerPoint2 = point3dFromSphCoord(outerRadius, theta1, phi2)
|
||||||
val outerPoint3 = point3DfromSphCoord(outerRadius, theta2, phi2)
|
val outerPoint3 = point3dFromSphCoord(outerRadius, theta2, phi2)
|
||||||
val outerPoint4 = point3DfromSphCoord(outerRadius, theta2, phi1)
|
val outerPoint4 = point3dFromSphCoord(outerRadius, theta2, phi1)
|
||||||
// 1-2-3-4 gives the same face but with opposite orientation
|
// 1-2-3-4 gives the same face but with opposite orientation
|
||||||
face4(outerPoint1, outerPoint4, outerPoint3, outerPoint2)
|
face4(outerPoint1, outerPoint4, outerPoint3, outerPoint2)
|
||||||
if (innerRadius > 0) {
|
if (innerRadius > 0) {
|
||||||
val innerPoint1 = point3DfromSphCoord(innerRadius, theta1, phi1)
|
val innerPoint1 = point3dFromSphCoord(innerRadius, theta1, phi1)
|
||||||
val innerPoint2 = point3DfromSphCoord(innerRadius, theta1, phi2)
|
val innerPoint2 = point3dFromSphCoord(innerRadius, theta1, phi2)
|
||||||
val innerPoint3 = point3DfromSphCoord(innerRadius, theta2, phi2)
|
val innerPoint3 = point3dFromSphCoord(innerRadius, theta2, phi2)
|
||||||
val innerPoint4 = point3DfromSphCoord(innerRadius, theta2, phi1)
|
val innerPoint4 = point3dFromSphCoord(innerRadius, theta2, phi1)
|
||||||
face4(innerPoint1, innerPoint2, innerPoint3, innerPoint4)
|
face4(innerPoint1, innerPoint2, innerPoint3, innerPoint4)
|
||||||
//the cup
|
//the cup
|
||||||
if (i == segments - 1 && theta != PI.toFloat() && innerRadius != outerRadius) {
|
if (i == segments - 1 && theta != PI.toFloat() && innerRadius != outerRadius) {
|
||||||
|
@ -112,9 +112,9 @@ public fun Point3D.toMeta(): Meta = Meta {
|
|||||||
|
|
||||||
|
|
||||||
internal fun Meta.toVector(default: Float = 0f) = Point3D(
|
internal fun Meta.toVector(default: Float = 0f) = Point3D(
|
||||||
this[Solid.X_KEY].float ?: default,
|
this[X_KEY].float ?: default,
|
||||||
this[Solid.Y_KEY].float ?: default,
|
this[Y_KEY].float ?: default,
|
||||||
this[Solid.Z_KEY].float ?: default
|
this[Z_KEY].float ?: default
|
||||||
)
|
)
|
||||||
|
|
||||||
//internal fun Solid.updatePosition(meta: Meta?) {
|
//internal fun Solid.updatePosition(meta: Meta?) {
|
||||||
|
@ -5,6 +5,7 @@ import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
|||||||
import space.kscience.dataforge.meta.descriptors.scheme
|
import space.kscience.dataforge.meta.descriptors.scheme
|
||||||
import space.kscience.dataforge.meta.descriptors.value
|
import space.kscience.dataforge.meta.descriptors.value
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
|
import space.kscience.dataforge.values.set
|
||||||
import space.kscience.visionforge.hide
|
import space.kscience.visionforge.hide
|
||||||
import space.kscience.visionforge.widgetType
|
import space.kscience.visionforge.widgetType
|
||||||
|
|
||||||
|
@ -1,31 +1,26 @@
|
|||||||
package space.kscience.visionforge.solid.transform
|
package space.kscience.visionforge.solid.transform
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.configure
|
|
||||||
import space.kscience.dataforge.meta.update
|
|
||||||
import space.kscience.dataforge.misc.DFExperimental
|
import space.kscience.dataforge.misc.DFExperimental
|
||||||
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.asName
|
import space.kscience.dataforge.names.asName
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.getProperty
|
||||||
import space.kscience.visionforge.solid.*
|
import space.kscience.visionforge.solid.*
|
||||||
|
|
||||||
private operator fun Number.plus(other: Number) = toFloat() + other.toFloat()
|
private operator fun Number.plus(other: Number) = toFloat() + other.toFloat()
|
||||||
private operator fun Number.times(other: Number) = toFloat() * other.toFloat()
|
private operator fun Number.times(other: Number) = toFloat() * other.toFloat()
|
||||||
|
|
||||||
@DFExperimental
|
@DFExperimental
|
||||||
internal fun Vision.updateFrom(other: Vision): Vision {
|
internal fun Solid.updateFrom(other: Solid): Solid {
|
||||||
if (this is Solid && other is Solid) {
|
x += other.x
|
||||||
x += other.x
|
y += other.y
|
||||||
y += other.y
|
z += other.y
|
||||||
z += other.y
|
rotationX += other.rotationX
|
||||||
rotationX += other.rotationX
|
rotationY += other.rotationY
|
||||||
rotationY += other.rotationY
|
rotationZ += other.rotationZ
|
||||||
rotationZ += other.rotationZ
|
scaleX *= other.scaleX
|
||||||
scaleX *= other.scaleX
|
scaleY *= other.scaleY
|
||||||
scaleY *= other.scaleY
|
scaleZ *= other.scaleZ
|
||||||
scaleZ *= other.scaleZ
|
setProperty(Name.EMPTY, other.getProperty(Name.EMPTY))
|
||||||
configure{
|
|
||||||
update(other.meta)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,17 +29,17 @@ internal fun Vision.updateFrom(other: Vision): Vision {
|
|||||||
internal object RemoveSingleChild : VisualTreeTransform<SolidGroup>() {
|
internal object RemoveSingleChild : VisualTreeTransform<SolidGroup>() {
|
||||||
|
|
||||||
override fun SolidGroup.transformInPlace() {
|
override fun SolidGroup.transformInPlace() {
|
||||||
fun MutableVisionGroup.replaceChildren() {
|
fun SolidGroup.replaceChildren() {
|
||||||
children.forEach { (childName, parent) ->
|
items.forEach { (childName, parent) ->
|
||||||
if (parent is SolidReferenceGroup) return@forEach //ignore refs
|
if (parent is SolidReference) return@forEach //ignore refs
|
||||||
if (parent is MutableVisionGroup) {
|
if (parent is SolidGroup) {
|
||||||
parent.replaceChildren()
|
parent.replaceChildren()
|
||||||
}
|
}
|
||||||
if (parent is VisionGroup && parent.children.size == 1) {
|
if (parent is SolidGroup && parent.items.size == 1) {
|
||||||
val child = parent.children.values.first()
|
val child: Solid = parent.items.values.first()
|
||||||
val newParent = child.updateFrom(parent)
|
val newParent = child.updateFrom(parent)
|
||||||
newParent.parent = null
|
newParent.parent = null
|
||||||
set(childName.asName(), newParent)
|
children[childName.asName()] = newParent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,41 +2,47 @@ package space.kscience.visionforge.solid.transform
|
|||||||
|
|
||||||
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.dataforge.names.asName
|
|
||||||
import space.kscience.visionforge.MutableVisionGroup
|
|
||||||
import space.kscience.visionforge.VisionGroup
|
|
||||||
import space.kscience.visionforge.solid.SolidGroup
|
import space.kscience.visionforge.solid.SolidGroup
|
||||||
import space.kscience.visionforge.solid.SolidReferenceGroup
|
import space.kscience.visionforge.solid.SolidReference
|
||||||
|
import kotlin.collections.HashMap
|
||||||
|
import kotlin.collections.Map
|
||||||
|
import kotlin.collections.component1
|
||||||
|
import kotlin.collections.component2
|
||||||
|
import kotlin.collections.filter
|
||||||
|
import kotlin.collections.filterIsInstance
|
||||||
|
import kotlin.collections.fold
|
||||||
|
import kotlin.collections.forEach
|
||||||
|
import kotlin.collections.set
|
||||||
|
|
||||||
@DFExperimental
|
@DFExperimental
|
||||||
internal object UnRef : VisualTreeTransform<SolidGroup>() {
|
internal object UnRef : VisualTreeTransform<SolidGroup>() {
|
||||||
private fun VisionGroup.countRefs(): Map<Name, Int> {
|
private fun SolidGroup.countRefs(): Map<Name, Int> {
|
||||||
return children.values.fold(HashMap()) { reducer, obj ->
|
return items.values.fold(HashMap()) { reducer, vision ->
|
||||||
if (obj is VisionGroup) {
|
if (vision is SolidGroup) {
|
||||||
val counter = obj.countRefs()
|
val counter = vision.countRefs()
|
||||||
counter.forEach { (key, value) ->
|
counter.forEach { (key, value) ->
|
||||||
reducer[key] = (reducer[key] ?: 0) + value
|
reducer[key] = (reducer[key] ?: 0) + value
|
||||||
}
|
}
|
||||||
} else if (obj is SolidReferenceGroup) {
|
} else if (vision is SolidReference) {
|
||||||
reducer[obj.refName] = (reducer[obj.refName] ?: 0) + 1
|
reducer[vision.prototypeName] = (reducer[vision.prototypeName] ?: 0) + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
return reducer
|
return reducer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun MutableVisionGroup.unref(name: Name) {
|
private fun SolidGroup.unref(name: Name) {
|
||||||
(this as? SolidGroup)?.prototypes{
|
(this as? SolidGroup)?.prototypes{
|
||||||
set(name, null)
|
set(name, null)
|
||||||
}
|
}
|
||||||
children.filter { (it.value as? SolidReferenceGroup)?.refName == name }.forEach { (key, value) ->
|
items.filter { (it.value as? SolidReference)?.prototypeName == name }.forEach { (key, value) ->
|
||||||
val reference = value as SolidReferenceGroup
|
val reference = value as SolidReference
|
||||||
val newChild = reference.prototype.updateFrom(reference)
|
val newChild = reference.prototype.updateFrom(reference)
|
||||||
newChild.parent = null
|
newChild.parent = null
|
||||||
set(key.asName(), newChild) // replace proxy with merged object
|
children[key] = newChild // replace proxy with merged object
|
||||||
}
|
}
|
||||||
|
|
||||||
children.values.filterIsInstance<MutableVisionGroup>().forEach { it.unref(name) }
|
items.values.filterIsInstance<SolidGroup>().forEach { it.unref(name) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun SolidGroup.transformInPlace() {
|
override fun SolidGroup.transformInPlace() {
|
||||||
|
@ -18,7 +18,7 @@ class CompositeTest {
|
|||||||
detail = 32
|
detail = 32
|
||||||
}
|
}
|
||||||
material {
|
material {
|
||||||
color("pink")
|
color.set("pink")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package space.kscience.visionforge.solid
|
package space.kscience.visionforge.solid
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.getIndexed
|
import space.kscience.dataforge.meta.getIndexed
|
||||||
import space.kscience.dataforge.meta.node
|
|
||||||
import space.kscience.dataforge.meta.toMeta
|
import space.kscience.dataforge.meta.toMeta
|
||||||
import space.kscience.dataforge.misc.DFExperimental
|
import space.kscience.dataforge.misc.DFExperimental
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
@ -12,7 +11,7 @@ class ConvexTest {
|
|||||||
@Suppress("UNUSED_VARIABLE")
|
@Suppress("UNUSED_VARIABLE")
|
||||||
@Test
|
@Test
|
||||||
fun testConvexBuilder() {
|
fun testConvexBuilder() {
|
||||||
val group = SolidGroup().apply {
|
val group = SolidGroup{
|
||||||
convex {
|
convex {
|
||||||
point(50, 50, -50)
|
point(50, 50, -50)
|
||||||
point(50, -50, -50)
|
point(50, -50, -50)
|
||||||
@ -25,7 +24,7 @@ class ConvexTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val convex = group.children.values.first() as Convex
|
val convex = group.items.values.first() as Convex
|
||||||
|
|
||||||
val json = Solids.jsonForSolids.encodeToJsonElement(Convex.serializer(), convex)
|
val json = Solids.jsonForSolids.encodeToJsonElement(Convex.serializer(), convex)
|
||||||
val meta = json.toMeta()
|
val meta = json.toMeta()
|
||||||
|
@ -9,7 +9,7 @@ import kotlin.test.assertEquals
|
|||||||
class GroupTest {
|
class GroupTest {
|
||||||
@Test
|
@Test
|
||||||
fun testGroupWithComposite() {
|
fun testGroupWithComposite() {
|
||||||
val group = SolidGroup().apply {
|
val group = SolidGroup{
|
||||||
union("union") {
|
union("union") {
|
||||||
box(100, 100, 100) {
|
box(100, 100, 100) {
|
||||||
z = 100
|
z = 100
|
||||||
@ -18,7 +18,7 @@ class GroupTest {
|
|||||||
}
|
}
|
||||||
box(100, 100, 100)
|
box(100, 100, 100)
|
||||||
material {
|
material {
|
||||||
color(Colors.lightgreen)
|
color.set(Colors.lightgreen)
|
||||||
opacity = 0.3f
|
opacity = 0.3f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -30,7 +30,7 @@ class GroupTest {
|
|||||||
}
|
}
|
||||||
box(100, 100, 100)
|
box(100, 100, 100)
|
||||||
y = 300
|
y = 300
|
||||||
color(Colors.red)
|
color.set(Colors.red)
|
||||||
}
|
}
|
||||||
subtract("subtract") {
|
subtract("subtract") {
|
||||||
box(100, 100, 100) {
|
box(100, 100, 100) {
|
||||||
@ -40,12 +40,12 @@ class GroupTest {
|
|||||||
}
|
}
|
||||||
box(100, 100, 100)
|
box(100, 100, 100)
|
||||||
y = -300
|
y = -300
|
||||||
color(Colors.blue)
|
color.set(Colors.blue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assertEquals(3, group.children.count())
|
assertEquals(3, group.items.count())
|
||||||
assertEquals(300.0, (group["intersect"] as Solid).y.toDouble())
|
assertEquals(300.0, (group.children["intersect"] as Solid).y.toDouble())
|
||||||
assertEquals(-300.0, (group["subtract"] as Solid).y.toDouble())
|
assertEquals(-300.0, (group.children["subtract"] as Solid).y.toDouble())
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -15,7 +15,7 @@ class PropertyTest {
|
|||||||
val box = Box(10.0f, 10.0f,10.0f)
|
val box = Box(10.0f, 10.0f,10.0f)
|
||||||
box.material {
|
box.material {
|
||||||
//meta["color"] = "pink"
|
//meta["color"] = "pink"
|
||||||
color("pink")
|
color.set("pink")
|
||||||
}
|
}
|
||||||
assertEquals("pink", box.meta["material.color"]?.string)
|
assertEquals("pink", box.meta["material.color"]?.string)
|
||||||
assertEquals("pink", box.color.string)
|
assertEquals("pink", box.color.string)
|
||||||
@ -33,7 +33,7 @@ class PropertyTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
box.material {
|
box.material {
|
||||||
color("pink")
|
color.set("pink")
|
||||||
}
|
}
|
||||||
|
|
||||||
assertEquals("pink", c)
|
assertEquals("pink", c)
|
||||||
@ -43,7 +43,7 @@ class PropertyTest {
|
|||||||
fun testInheritedProperty() {
|
fun testInheritedProperty() {
|
||||||
var box: Box? = null
|
var box: Box? = null
|
||||||
val group = SolidGroup().apply {
|
val group = SolidGroup().apply {
|
||||||
setPropertyNode("test", 22)
|
setPropertyValue("test", 22)
|
||||||
group {
|
group {
|
||||||
box = box(100, 100, 100)
|
box = box(100, 100, 100)
|
||||||
}
|
}
|
||||||
@ -54,14 +54,14 @@ class PropertyTest {
|
|||||||
@Test
|
@Test
|
||||||
fun testStyleProperty() {
|
fun testStyleProperty() {
|
||||||
var box: Box? = null
|
var box: Box? = null
|
||||||
val group = SolidGroup().apply {
|
val group = SolidGroup{
|
||||||
styleSheet {
|
styleSheet {
|
||||||
set("testStyle") {
|
update("testStyle") {
|
||||||
"test" put 22
|
"test" put 22
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
group {
|
group {
|
||||||
box = box(100, 100, 100).apply {
|
box = box(100, 100, 100) {
|
||||||
useStyle("testStyle")
|
useStyle("testStyle")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,7 +74,7 @@ class PropertyTest {
|
|||||||
var box: Box? = null
|
var box: Box? = null
|
||||||
val group = SolidGroup().apply {
|
val group = SolidGroup().apply {
|
||||||
styleSheet {
|
styleSheet {
|
||||||
set("testStyle") {
|
update("testStyle") {
|
||||||
SolidMaterial.MATERIAL_COLOR_KEY put "#555555"
|
SolidMaterial.MATERIAL_COLOR_KEY put "#555555"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -89,10 +89,10 @@ class PropertyTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testReferenceStyleProperty() {
|
fun testReferenceStyleProperty() {
|
||||||
var box: SolidReferenceGroup? = null
|
var box: SolidReference? = null
|
||||||
val group = SolidGroup{
|
val group = SolidGroup{
|
||||||
styleSheet {
|
styleSheet {
|
||||||
set("testStyle") {
|
update("testStyle") {
|
||||||
SolidMaterial.MATERIAL_COLOR_KEY put "#555555"
|
SolidMaterial.MATERIAL_COLOR_KEY put "#555555"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,6 +105,6 @@ class PropertyTest {
|
|||||||
box = ref("box".asName())
|
box = ref("box".asName())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assertEquals("#555555", box?.color.string)
|
assertEquals("#555555", box!!.color.string)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,7 +2,6 @@ package space.kscience.visionforge.solid
|
|||||||
|
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.visionforge.Colors
|
import space.kscience.visionforge.Colors
|
||||||
import space.kscience.visionforge.MutableVisionGroup
|
|
||||||
import space.kscience.visionforge.get
|
import space.kscience.visionforge.get
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -14,10 +13,10 @@ import kotlin.test.assertEquals
|
|||||||
fun SolidGroup.refGroup(
|
fun SolidGroup.refGroup(
|
||||||
name: String,
|
name: String,
|
||||||
templateName: Name = Name.parse(name),
|
templateName: Name = Name.parse(name),
|
||||||
block: MutableVisionGroup.() -> Unit
|
block: SolidGroup.() -> Unit
|
||||||
): SolidReferenceGroup {
|
): SolidReference {
|
||||||
val group = SolidGroup().apply(block)
|
val group = SolidGroup().apply(block)
|
||||||
return newRef(name, group, templateName = templateName)
|
return newRef(name, group, prototypeName = templateName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -25,7 +24,7 @@ class SerializationTest {
|
|||||||
@Test
|
@Test
|
||||||
fun testCubeSerialization() {
|
fun testCubeSerialization() {
|
||||||
val cube = Box(100f, 100f, 100f).apply {
|
val cube = Box(100f, 100f, 100f).apply {
|
||||||
color(222)
|
color.set(222)
|
||||||
x = 100
|
x = 100
|
||||||
z = -100
|
z = -100
|
||||||
}
|
}
|
||||||
@ -38,7 +37,7 @@ class SerializationTest {
|
|||||||
@Test
|
@Test
|
||||||
fun testProxySerialization() {
|
fun testProxySerialization() {
|
||||||
val cube = Box(100f, 100f, 100f).apply {
|
val cube = Box(100f, 100f, 100f).apply {
|
||||||
color(222)
|
color.set(222)
|
||||||
x = 100
|
x = 100
|
||||||
z = -100
|
z = -100
|
||||||
}
|
}
|
||||||
@ -53,21 +52,21 @@ class SerializationTest {
|
|||||||
val string = Solids.encodeToString(group)
|
val string = Solids.encodeToString(group)
|
||||||
println(string)
|
println(string)
|
||||||
val reconstructed = Solids.decodeFromString(string) as SolidGroup
|
val reconstructed = Solids.decodeFromString(string) as SolidGroup
|
||||||
assertEquals(group["cube"]?.meta, reconstructed["cube"]?.meta)
|
assertEquals(group.children["cube"]?.meta, reconstructed.children["cube"]?.meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun lightSerialization(){
|
fun lightSerialization(){
|
||||||
val group = SolidGroup {
|
val group = SolidGroup {
|
||||||
ambientLight {
|
ambientLight {
|
||||||
color(Colors.white)
|
color.set(Colors.white)
|
||||||
intensity = 100.0
|
intensity = 100.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val serialized = Solids.encodeToString(group)
|
val serialized = Solids.encodeToString(group)
|
||||||
|
|
||||||
val reconstructed = Solids.decodeFromString(serialized) as SolidGroup
|
val reconstructed = Solids.decodeFromString(serialized) as SolidGroup
|
||||||
assertEquals(100.0, (reconstructed["@ambientLight"] as AmbientLightSource).intensity.toDouble())
|
assertEquals(100.0, (reconstructed.children["@ambientLight"] as AmbientLightSource).intensity.toDouble())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -24,6 +24,9 @@ class SolidPluginTest {
|
|||||||
|
|
||||||
val reconstructed = visionManager.decodeFromMeta(meta) as SolidGroup
|
val reconstructed = visionManager.decodeFromMeta(meta) as SolidGroup
|
||||||
|
|
||||||
assertEquals(visionManager.encodeToJsonElement(vision["aBox"]!!), visionManager.encodeToJsonElement(reconstructed["aBox"]!!))
|
assertEquals(
|
||||||
|
visionManager.encodeToJsonElement(vision.children["aBox"]!!),
|
||||||
|
visionManager.encodeToJsonElement(reconstructed.children["aBox"]!!)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -15,7 +15,7 @@ class SolidReferenceTest {
|
|||||||
SolidMaterial.MATERIAL_COLOR_KEY put "red"
|
SolidMaterial.MATERIAL_COLOR_KEY put "red"
|
||||||
}
|
}
|
||||||
newRef("test", Box(100f,100f,100f).apply {
|
newRef("test", Box(100f,100f,100f).apply {
|
||||||
color("blue")
|
color.set("blue")
|
||||||
useStyle(theStyle)
|
useStyle(theStyle)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -23,13 +23,13 @@ class SolidReferenceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testReferenceProperty(){
|
fun testReferenceProperty(){
|
||||||
assertEquals("blue", (groupWithReference["test"] as Solid).color.string)
|
assertEquals("blue", (groupWithReference.children["test"] as Solid).color.string)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testReferenceSerialization(){
|
fun testReferenceSerialization(){
|
||||||
val serialized = Solids.jsonForSolids.encodeToJsonElement(groupWithReference)
|
val serialized = Solids.jsonForSolids.encodeToJsonElement(groupWithReference)
|
||||||
val deserialized = Solids.jsonForSolids.decodeFromJsonElement(SolidGroup.serializer(), serialized)
|
val deserialized = Solids.jsonForSolids.decodeFromJsonElement(SolidGroup.serializer(), serialized)
|
||||||
assertEquals("blue", (deserialized["test"] as Solid).color.string)
|
assertEquals("blue", (deserialized.children["test"] as Solid).color.string)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -21,24 +21,24 @@ class VisionUpdateTest {
|
|||||||
box(200,200,200, name = "origin")
|
box(200,200,200, name = "origin")
|
||||||
}
|
}
|
||||||
val dif = VisionChange{
|
val dif = VisionChange{
|
||||||
group("top") {
|
group ("top") {
|
||||||
color(123)
|
color.set(123)
|
||||||
box(100,100,100)
|
box(100,100,100)
|
||||||
}
|
}
|
||||||
propertyChanged("top".asName(), SolidMaterial.MATERIAL_COLOR_KEY, Meta("red".asValue()))
|
propertyChanged("top".asName(), SolidMaterial.MATERIAL_COLOR_KEY, Meta("red".asValue()))
|
||||||
propertyChanged("origin".asName(), SolidMaterial.MATERIAL_COLOR_KEY, Meta("red".asValue()))
|
propertyChanged("origin".asName(), SolidMaterial.MATERIAL_COLOR_KEY, Meta("red".asValue()))
|
||||||
}
|
}
|
||||||
targetVision.update(dif)
|
targetVision.update(dif)
|
||||||
assertTrue { targetVision["top"] is SolidGroup }
|
assertTrue { targetVision.children["top"] is SolidGroup }
|
||||||
assertEquals("red", (targetVision["origin"] as Solid).color.string) // Should work
|
assertEquals("red", (targetVision.children["origin"] as Solid).color.string) // Should work
|
||||||
assertEquals("#00007b", (targetVision["top"] as Solid).color.string) // new item always takes precedence
|
assertEquals("#00007b", (targetVision.children["top"] as Solid).color.string) // new item always takes precedence
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testVisionChangeSerialization(){
|
fun testVisionChangeSerialization(){
|
||||||
val change = VisionChange{
|
val change = VisionChange{
|
||||||
group("top") {
|
group("top") {
|
||||||
color(123)
|
color.set(123)
|
||||||
box(100,100,100)
|
box(100,100,100)
|
||||||
}
|
}
|
||||||
propertyChanged("top".asName(), SolidMaterial.MATERIAL_COLOR_KEY, Meta("red".asValue()))
|
propertyChanged("top".asName(), SolidMaterial.MATERIAL_COLOR_KEY, Meta("red".asValue()))
|
||||||
|
@ -12,8 +12,9 @@ import space.kscience.dataforge.values.Null
|
|||||||
import space.kscience.dataforge.values.Value
|
import space.kscience.dataforge.values.Value
|
||||||
import space.kscience.dataforge.values.asValue
|
import space.kscience.dataforge.values.asValue
|
||||||
import space.kscience.tables.*
|
import space.kscience.tables.*
|
||||||
import space.kscience.visionforge.VisionBase
|
import space.kscience.visionforge.VisionGroup
|
||||||
import space.kscience.visionforge.html.VisionOutput
|
import space.kscience.visionforge.html.VisionOutput
|
||||||
|
import space.kscience.visionforge.properties
|
||||||
import kotlin.jvm.JvmName
|
import kotlin.jvm.JvmName
|
||||||
import kotlin.reflect.typeOf
|
import kotlin.reflect.typeOf
|
||||||
|
|
||||||
@ -41,12 +42,13 @@ public val ColumnHeader<Value>.properties: ValueColumnScheme get() = ValueColumn
|
|||||||
@SerialName("vision.table")
|
@SerialName("vision.table")
|
||||||
public class VisionOfTable(
|
public class VisionOfTable(
|
||||||
override val headers: List<@Serializable(ColumnHeaderSerializer::class) ColumnHeader<Value>>,
|
override val headers: List<@Serializable(ColumnHeaderSerializer::class) ColumnHeader<Value>>,
|
||||||
) : VisionBase(), Rows<Value> {
|
) : VisionGroup(), Rows<Value> {
|
||||||
|
|
||||||
public var data: List<Meta>
|
public var data: List<Meta>
|
||||||
get() = meta.getIndexed("rows").entries.sortedBy { it.key?.toInt() }.map { it.value }
|
get() = meta.getIndexed("rows").entries.sortedBy { it.key?.toInt() }.map { it.value }
|
||||||
set(value) {
|
set(value) {
|
||||||
meta["rows"] = value
|
//TODO Make it better
|
||||||
|
properties()["rows"] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
public val rows: List<MetaRow> get() = data.map(::MetaRow)
|
public val rows: List<MetaRow> get() = data.map(::MetaRow)
|
||||||
|
@ -4,16 +4,15 @@ import info.laht.threekt.core.BufferGeometry
|
|||||||
import info.laht.threekt.geometries.EdgesGeometry
|
import info.laht.threekt.geometries.EdgesGeometry
|
||||||
import info.laht.threekt.objects.LineSegments
|
import info.laht.threekt.objects.LineSegments
|
||||||
import info.laht.threekt.objects.Mesh
|
import info.laht.threekt.objects.Mesh
|
||||||
import space.kscience.dataforge.meta.updateWith
|
import space.kscience.dataforge.meta.boolean
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.asName
|
import space.kscience.dataforge.names.asName
|
||||||
import space.kscience.dataforge.names.plus
|
import space.kscience.dataforge.names.plus
|
||||||
import space.kscience.dataforge.names.startsWith
|
import space.kscience.dataforge.names.startsWith
|
||||||
import space.kscience.dataforge.values.boolean
|
|
||||||
import space.kscience.visionforge.VisionBuilder
|
import space.kscience.visionforge.VisionBuilder
|
||||||
import space.kscience.visionforge.computePropertyNode
|
import space.kscience.visionforge.getProperty
|
||||||
import space.kscience.visionforge.onPropertyChange
|
import space.kscience.visionforge.onPropertyChange
|
||||||
import space.kscience.visionforge.setProperty
|
import space.kscience.visionforge.setPropertyValue
|
||||||
import space.kscience.visionforge.solid.Solid
|
import space.kscience.visionforge.solid.Solid
|
||||||
import space.kscience.visionforge.solid.SolidMaterial
|
import space.kscience.visionforge.solid.SolidMaterial
|
||||||
import space.kscience.visionforge.solid.layer
|
import space.kscience.visionforge.solid.layer
|
||||||
@ -32,7 +31,7 @@ public abstract class MeshThreeFactory<in T : Solid>(
|
|||||||
*/
|
*/
|
||||||
public abstract fun buildGeometry(obj: T): BufferGeometry
|
public abstract fun buildGeometry(obj: T): BufferGeometry
|
||||||
|
|
||||||
override fun invoke(three: ThreePlugin, obj: T): Mesh {
|
override fun build(three: ThreePlugin, obj: T): Mesh {
|
||||||
val geometry = buildGeometry(obj)
|
val geometry = buildGeometry(obj)
|
||||||
|
|
||||||
//val meshMeta: Meta = obj.properties[Material3D.MATERIAL_KEY]?.node ?: Meta.empty
|
//val meshMeta: Meta = obj.properties[Material3D.MATERIAL_KEY]?.node ?: Meta.empty
|
||||||
@ -78,8 +77,8 @@ public abstract class MeshThreeFactory<in T : Solid>(
|
|||||||
|
|
||||||
@VisionBuilder
|
@VisionBuilder
|
||||||
public fun Solid.edges(enabled: Boolean = true, block: SolidMaterial.() -> Unit = {}) {
|
public fun Solid.edges(enabled: Boolean = true, block: SolidMaterial.() -> Unit = {}) {
|
||||||
setProperty(EDGES_ENABLED_KEY, enabled)
|
setPropertyValue(EDGES_ENABLED_KEY, enabled)
|
||||||
meta.getOrCreate(EDGES_MATERIAL_KEY).updateWith(SolidMaterial, block)
|
SolidMaterial.write(getProperty(EDGES_MATERIAL_KEY)).apply(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun Mesh.applyProperties(obj: Solid): Mesh = apply {
|
internal fun Mesh.applyProperties(obj: Solid): Mesh = apply {
|
||||||
@ -95,9 +94,9 @@ internal fun Mesh.applyProperties(obj: Solid): Mesh = apply {
|
|||||||
public fun Mesh.applyEdges(obj: Solid) {
|
public fun Mesh.applyEdges(obj: Solid) {
|
||||||
val edges = children.find { it.name == "@edges" } as? LineSegments
|
val edges = children.find { it.name == "@edges" } as? LineSegments
|
||||||
//inherited edges definition, enabled by default
|
//inherited edges definition, enabled by default
|
||||||
if (obj.getPropertyValue(EDGES_ENABLED_KEY, inherit = true)?.boolean != false) {
|
if (obj.getProperty(EDGES_ENABLED_KEY, inherit = true).boolean != false) {
|
||||||
val bufferGeometry = geometry as? BufferGeometry ?: return
|
val bufferGeometry = geometry as? BufferGeometry ?: return
|
||||||
val material = ThreeMaterials.getLineMaterial(obj.computePropertyNode(EDGES_MATERIAL_KEY), true)
|
val material = ThreeMaterials.getLineMaterial(obj.getProperty(EDGES_MATERIAL_KEY), true)
|
||||||
if (edges == null) {
|
if (edges == null) {
|
||||||
add(
|
add(
|
||||||
LineSegments(
|
LineSegments(
|
||||||
|
@ -8,7 +8,7 @@ import kotlin.reflect.KClass
|
|||||||
public object ThreeAmbientLightFactory : ThreeFactory<AmbientLightSource> {
|
public object ThreeAmbientLightFactory : ThreeFactory<AmbientLightSource> {
|
||||||
override val type: KClass<in AmbientLightSource> get() = AmbientLightSource::class
|
override val type: KClass<in AmbientLightSource> get() = AmbientLightSource::class
|
||||||
|
|
||||||
override fun invoke(three: ThreePlugin, obj: AmbientLightSource): AmbientLight {
|
override fun build(three: ThreePlugin, obj: AmbientLightSource): AmbientLight {
|
||||||
val res = AmbientLight().apply {
|
val res = AmbientLight().apply {
|
||||||
color = obj.color.threeColor() ?: Color(0x404040)
|
color = obj.color.threeColor() ?: Color(0x404040)
|
||||||
intensity = obj.intensity.toDouble()
|
intensity = obj.intensity.toDouble()
|
||||||
|
@ -11,6 +11,7 @@ import org.w3c.dom.CanvasRenderingContext2D
|
|||||||
import org.w3c.dom.CanvasTextBaseline
|
import org.w3c.dom.CanvasTextBaseline
|
||||||
import org.w3c.dom.HTMLCanvasElement
|
import org.w3c.dom.HTMLCanvasElement
|
||||||
import org.w3c.dom.MIDDLE
|
import org.w3c.dom.MIDDLE
|
||||||
|
import space.kscience.visionforge.getProperty
|
||||||
import space.kscience.visionforge.solid.SolidLabel
|
import space.kscience.visionforge.solid.SolidLabel
|
||||||
import space.kscience.visionforge.solid.SolidMaterial
|
import space.kscience.visionforge.solid.SolidMaterial
|
||||||
import space.kscience.visionforge.solid.three.ThreeCanvas.Companion.DO_NOT_HIGHLIGHT_TAG
|
import space.kscience.visionforge.solid.three.ThreeCanvas.Companion.DO_NOT_HIGHLIGHT_TAG
|
||||||
@ -22,11 +23,11 @@ import kotlin.reflect.KClass
|
|||||||
public object ThreeCanvasLabelFactory : ThreeFactory<SolidLabel> {
|
public object ThreeCanvasLabelFactory : ThreeFactory<SolidLabel> {
|
||||||
override val type: KClass<in SolidLabel> get() = SolidLabel::class
|
override val type: KClass<in SolidLabel> get() = SolidLabel::class
|
||||||
|
|
||||||
override fun invoke(three: ThreePlugin, obj: SolidLabel): Object3D {
|
override fun build(three: ThreePlugin, obj: SolidLabel): Object3D {
|
||||||
val canvas = document.createElement("canvas") as HTMLCanvasElement
|
val canvas = document.createElement("canvas") as HTMLCanvasElement
|
||||||
val context = canvas.getContext("2d") as CanvasRenderingContext2D
|
val context = canvas.getContext("2d") as CanvasRenderingContext2D
|
||||||
context.font = "Bold ${obj.fontSize}pt ${obj.fontFamily}"
|
context.font = "Bold ${obj.fontSize}pt ${obj.fontFamily}"
|
||||||
context.fillStyle = obj.getPropertyValue(SolidMaterial.MATERIAL_COLOR_KEY)?.value ?: "black"
|
context.fillStyle = obj.getProperty(SolidMaterial.MATERIAL_COLOR_KEY)?.value ?: "black"
|
||||||
context.textBaseline = CanvasTextBaseline.MIDDLE
|
context.textBaseline = CanvasTextBaseline.MIDDLE
|
||||||
val metrics = context.measureText(obj.text)
|
val metrics = context.measureText(obj.text)
|
||||||
//canvas.width = metrics.width.toInt()
|
//canvas.width = metrics.width.toInt()
|
||||||
|
@ -37,7 +37,7 @@ public class ThreeCompositeFactory(public val three: ThreePlugin) : ThreeFactory
|
|||||||
|
|
||||||
override val type: KClass<in Composite> get() = Composite::class
|
override val type: KClass<in Composite> get() = Composite::class
|
||||||
|
|
||||||
override fun invoke(three: ThreePlugin, obj: Composite): Mesh {
|
override fun build(three: ThreePlugin, obj: Composite): Mesh {
|
||||||
val first = three.buildObject3D(obj.first).takeIfMesh() ?: error("First part of composite is not a mesh")
|
val first = three.buildObject3D(obj.first).takeIfMesh() ?: error("First part of composite is not a mesh")
|
||||||
val second = three.buildObject3D(obj.second).takeIfMesh() ?: error("Second part of composite is not a mesh")
|
val second = three.buildObject3D(obj.second).takeIfMesh() ?: error("Second part of composite is not a mesh")
|
||||||
return when (obj.compositeType) {
|
return when (obj.compositeType) {
|
||||||
|
@ -22,7 +22,7 @@ public interface ThreeFactory<in T : Vision> {
|
|||||||
|
|
||||||
public val type: KClass<in T>
|
public val type: KClass<in T>
|
||||||
|
|
||||||
public operator fun invoke(three: ThreePlugin, obj: T): Object3D
|
public fun build(three: ThreePlugin, obj: T): Object3D
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
public const val TYPE: String = "threeFactory"
|
public const val TYPE: String = "threeFactory"
|
||||||
|
@ -17,7 +17,7 @@ import kotlin.reflect.KClass
|
|||||||
public object ThreeLabelFactory : ThreeFactory<SolidLabel> {
|
public object ThreeLabelFactory : ThreeFactory<SolidLabel> {
|
||||||
override val type: KClass<in SolidLabel> get() = SolidLabel::class
|
override val type: KClass<in SolidLabel> get() = SolidLabel::class
|
||||||
|
|
||||||
override fun invoke(three: ThreePlugin, obj: SolidLabel): Object3D {
|
override fun build(three: ThreePlugin, obj: SolidLabel): Object3D {
|
||||||
val textGeo = TextBufferGeometry(obj.text, jso {
|
val textGeo = TextBufferGeometry(obj.text, jso {
|
||||||
font = obj.fontFamily
|
font = obj.fontFamily
|
||||||
size = 20
|
size = 20
|
||||||
|
@ -4,7 +4,7 @@ import info.laht.threekt.core.BufferGeometry
|
|||||||
import info.laht.threekt.core.Object3D
|
import info.laht.threekt.core.Object3D
|
||||||
import info.laht.threekt.math.Color
|
import info.laht.threekt.math.Color
|
||||||
import info.laht.threekt.objects.LineSegments
|
import info.laht.threekt.objects.LineSegments
|
||||||
import space.kscience.visionforge.computePropertyNode
|
import space.kscience.visionforge.getProperty
|
||||||
import space.kscience.visionforge.onPropertyChange
|
import space.kscience.visionforge.onPropertyChange
|
||||||
import space.kscience.visionforge.solid.PolyLine
|
import space.kscience.visionforge.solid.PolyLine
|
||||||
import space.kscience.visionforge.solid.SolidMaterial
|
import space.kscience.visionforge.solid.SolidMaterial
|
||||||
@ -17,7 +17,7 @@ import kotlin.reflect.KClass
|
|||||||
public object ThreeLineFactory : ThreeFactory<PolyLine> {
|
public object ThreeLineFactory : ThreeFactory<PolyLine> {
|
||||||
override val type: KClass<PolyLine> get() = PolyLine::class
|
override val type: KClass<PolyLine> get() = PolyLine::class
|
||||||
|
|
||||||
override fun invoke(three: ThreePlugin, obj: PolyLine): Object3D {
|
override fun build(three: ThreePlugin, obj: PolyLine): Object3D {
|
||||||
val geometry = BufferGeometry().apply {
|
val geometry = BufferGeometry().apply {
|
||||||
setFromPoints(Array((obj.points.size - 1) * 2) {
|
setFromPoints(Array((obj.points.size - 1) * 2) {
|
||||||
obj.points[ceil(it / 2.0).toInt()].toVector()
|
obj.points[ceil(it / 2.0).toInt()].toVector()
|
||||||
@ -25,7 +25,7 @@ public object ThreeLineFactory : ThreeFactory<PolyLine> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val material = ThreeMaterials.getLineMaterial(
|
val material = ThreeMaterials.getLineMaterial(
|
||||||
obj.computePropertyNode(SolidMaterial.MATERIAL_KEY),
|
obj.getProperty(SolidMaterial.MATERIAL_KEY),
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -171,7 +171,7 @@ public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) {
|
|||||||
?: ThreeMaterials.BLACK_COLOR
|
?: ThreeMaterials.BLACK_COLOR
|
||||||
}
|
}
|
||||||
SolidMaterial.MATERIAL_OPACITY_KEY -> {
|
SolidMaterial.MATERIAL_OPACITY_KEY -> {
|
||||||
val opacity = vision.getPropertyValue(
|
val opacity = vision.getProperty(
|
||||||
SolidMaterial.MATERIAL_OPACITY_KEY,
|
SolidMaterial.MATERIAL_OPACITY_KEY,
|
||||||
inherit = true,
|
inherit = true,
|
||||||
)?.double ?: 1.0
|
)?.double ?: 1.0
|
||||||
@ -179,7 +179,7 @@ public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) {
|
|||||||
material.transparent = opacity < 1.0
|
material.transparent = opacity < 1.0
|
||||||
}
|
}
|
||||||
SolidMaterial.MATERIAL_WIREFRAME_KEY -> {
|
SolidMaterial.MATERIAL_WIREFRAME_KEY -> {
|
||||||
material.asDynamic().wireframe = vision.getPropertyValue(
|
material.asDynamic().wireframe = vision.getProperty(
|
||||||
SolidMaterial.MATERIAL_WIREFRAME_KEY,
|
SolidMaterial.MATERIAL_WIREFRAME_KEY,
|
||||||
inherit = true,
|
inherit = true,
|
||||||
)?.boolean ?: false
|
)?.boolean ?: false
|
||||||
|
@ -12,7 +12,6 @@ import space.kscience.visionforge.Vision
|
|||||||
import space.kscience.visionforge.onPropertyChange
|
import space.kscience.visionforge.onPropertyChange
|
||||||
import space.kscience.visionforge.solid.*
|
import space.kscience.visionforge.solid.*
|
||||||
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
||||||
import space.kscience.visionforge.solid.three.set
|
|
||||||
import space.kscience.visionforge.visible
|
import space.kscience.visionforge.visible
|
||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
@ -49,10 +48,10 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
|
|||||||
|
|
||||||
public fun buildObject3D(obj: Solid): Object3D = when (obj) {
|
public fun buildObject3D(obj: Solid): Object3D = when (obj) {
|
||||||
is ThreeJsVision -> obj.render(this)
|
is ThreeJsVision -> obj.render(this)
|
||||||
is SolidReferenceGroup -> ThreeReferenceFactory(this, obj)
|
is SolidReferenceGroup -> ThreeReferenceFactory.build(this, obj)
|
||||||
is SolidGroup -> {
|
is SolidGroup -> {
|
||||||
val group = ThreeGroup()
|
val group = ThreeGroup()
|
||||||
obj.children.forEach { (token, child) ->
|
obj.items.forEach { (token, child) ->
|
||||||
if (child is Solid && token != SolidGroup.PROTOTYPES_TOKEN && child.ignore != true) {
|
if (child is Solid && token != SolidGroup.PROTOTYPES_TOKEN && child.ignore != true) {
|
||||||
try {
|
try {
|
||||||
val object3D = buildObject3D(child)
|
val object3D = buildObject3D(child)
|
||||||
@ -101,13 +100,13 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is Composite -> compositeFactory(this, obj)
|
is Composite -> compositeFactory.build(this, obj)
|
||||||
else -> {
|
else -> {
|
||||||
//find specialized factory for this type if it is present
|
//find specialized factory for this type if it is present
|
||||||
val factory: ThreeFactory<Solid>? = findObjectFactory(obj::class)
|
val factory: ThreeFactory<Solid>? = findObjectFactory(obj::class)
|
||||||
when {
|
when {
|
||||||
factory != null -> factory(this, obj)
|
factory != null -> factory.build(this, obj)
|
||||||
obj is GeometrySolid -> ThreeShapeFactory(this, obj)
|
obj is GeometrySolid -> ThreeShapeFactory.build(this, obj)
|
||||||
else -> error("Renderer for ${obj::class} not found")
|
else -> error("Renderer for ${obj::class} not found")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,17 +11,19 @@ import kotlin.reflect.KClass
|
|||||||
public object ThreePointLightFactory : ThreeFactory<PointLightSource> {
|
public object ThreePointLightFactory : ThreeFactory<PointLightSource> {
|
||||||
override val type: KClass<in PointLightSource> get() = PointLightSource::class
|
override val type: KClass<in PointLightSource> get() = PointLightSource::class
|
||||||
|
|
||||||
override fun invoke(three: ThreePlugin, obj: PointLightSource): PointLight {
|
private val DEFAULT_COLOR = Color(0x404040)
|
||||||
|
|
||||||
|
override fun build(three: ThreePlugin, obj: PointLightSource): PointLight {
|
||||||
val res = PointLight().apply {
|
val res = PointLight().apply {
|
||||||
matrixAutoUpdate = false
|
matrixAutoUpdate = false
|
||||||
color = obj.color.threeColor() ?: Color(0x404040)
|
color = obj.color.threeColor() ?: DEFAULT_COLOR
|
||||||
intensity = obj.intensity.toDouble()
|
intensity = obj.intensity.toDouble()
|
||||||
updatePosition(obj)
|
updatePosition(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.onPropertyChange { name ->
|
obj.onPropertyChange { name ->
|
||||||
when (name) {
|
when (name) {
|
||||||
LightSource::color.name.asName() -> res.color = obj.color.threeColor() ?: Color(0x404040)
|
LightSource::color.name.asName() -> res.color = obj.color.threeColor() ?: DEFAULT_COLOR
|
||||||
LightSource::intensity.name.asName() -> res.intensity = obj.intensity.toDouble()
|
LightSource::intensity.name.asName() -> res.intensity = obj.intensity.toDouble()
|
||||||
else -> res.updateProperty(obj, name)
|
else -> res.updateProperty(obj, name)
|
||||||
}
|
}
|
||||||
@ -29,4 +31,5 @@ public object ThreePointLightFactory : ThreeFactory<PointLightSource> {
|
|||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -30,7 +30,7 @@ public object ThreeReferenceFactory : ThreeFactory<SolidReferenceGroup> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun invoke(three: ThreePlugin, obj: SolidReferenceGroup): Object3D {
|
override fun build(three: ThreePlugin, obj: SolidReferenceGroup): Object3D {
|
||||||
val template = obj.prototype
|
val template = obj.prototype
|
||||||
val cachedObject = cache.getOrPut(template) {
|
val cachedObject = cache.getOrPut(template) {
|
||||||
three.buildObject3D(template)
|
three.buildObject3D(template)
|
||||||
@ -50,7 +50,7 @@ public object ThreeReferenceFactory : ThreeFactory<SolidReferenceGroup> {
|
|||||||
if (name.firstOrNull()?.body == REFERENCE_CHILD_PROPERTY_PREFIX) {
|
if (name.firstOrNull()?.body == REFERENCE_CHILD_PROPERTY_PREFIX) {
|
||||||
val childName = name.firstOrNull()?.index?.let(Name::parse) ?: error("Wrong syntax for reference child property: '$name'")
|
val childName = name.firstOrNull()?.index?.let(Name::parse) ?: error("Wrong syntax for reference child property: '$name'")
|
||||||
val propertyName = name.cutFirst()
|
val propertyName = name.cutFirst()
|
||||||
val referenceChild = obj[childName] ?: error("Reference child with name '$childName' not found")
|
val referenceChild = obj.children[childName] ?: error("Reference child with name '$childName' not found")
|
||||||
val child = object3D.findChild(childName) ?: error("Object child with name '$childName' not found")
|
val child = object3D.findChild(childName) ?: error("Object child with name '$childName' not found")
|
||||||
child.updateProperty(referenceChild, propertyName)
|
child.updateProperty(referenceChild, propertyName)
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user