Minors fixes to Meta and JsonMetaFormat. Visualization moving forward
This commit is contained in:
parent
54b30e9260
commit
0d15bc1d0b
@ -20,8 +20,13 @@ object JsonMetaFormat : MetaFormat {
|
|||||||
|
|
||||||
override fun read(input: Input): Meta {
|
override fun read(input: Input): Meta {
|
||||||
val str = input.readText()
|
val str = input.readText()
|
||||||
val json = JsonTreeParser.parse(str)
|
val json = Json.plain.parseJson(str)
|
||||||
|
|
||||||
|
if(json is JsonObject) {
|
||||||
return json.toMeta()
|
return json.toMeta()
|
||||||
|
} else {
|
||||||
|
TODO("non-object root")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,6 +50,20 @@ fun Meta.toJson(): JsonObject {
|
|||||||
return JsonObject(map)
|
return JsonObject(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun JsonElement.toMetaItem() = when (this) {
|
||||||
|
is JsonPrimitive -> MetaItem.ValueItem<JsonMeta>(this.toValue())
|
||||||
|
is JsonObject -> MetaItem.NodeItem(this.toMeta())
|
||||||
|
is JsonArray -> {
|
||||||
|
if (this.all { it is JsonPrimitive }) {
|
||||||
|
val value = ListValue(this.map { (it as JsonPrimitive).toValue() })
|
||||||
|
MetaItem.ValueItem<JsonMeta>(value)
|
||||||
|
} else {
|
||||||
|
TODO("mixed nodes json")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun JsonObject.toMeta() = JsonMeta(this)
|
fun JsonObject.toMeta() = JsonMeta(this)
|
||||||
|
|
||||||
private fun JsonPrimitive.toValue(): Value {
|
private fun JsonPrimitive.toValue(): Value {
|
||||||
@ -57,19 +76,7 @@ private fun JsonPrimitive.toValue(): Value {
|
|||||||
class JsonMeta(val json: JsonObject) : Meta {
|
class JsonMeta(val json: JsonObject) : Meta {
|
||||||
override val items: Map<NameToken, MetaItem<out Meta>> by lazy {
|
override val items: Map<NameToken, MetaItem<out Meta>> by lazy {
|
||||||
json.mapKeys { NameToken(it.key) }.mapValues { entry ->
|
json.mapKeys { NameToken(it.key) }.mapValues { entry ->
|
||||||
val element = entry.value
|
entry.value.toMetaItem()
|
||||||
when (element) {
|
|
||||||
is JsonPrimitive -> MetaItem.ValueItem<JsonMeta>(element.toValue())
|
|
||||||
is JsonObject -> MetaItem.NodeItem(element.toMeta())
|
|
||||||
is JsonArray -> {
|
|
||||||
if (element.all { it is JsonPrimitive }) {
|
|
||||||
val value = ListValue(element.map { (it as JsonPrimitive).toValue() })
|
|
||||||
MetaItem.ValueItem<JsonMeta>(value)
|
|
||||||
} else {
|
|
||||||
TODO("mixed nodes json")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ class Laminate(layers: List<Meta>) : Meta {
|
|||||||
first().seal()
|
first().seal()
|
||||||
all { it is MetaItem.NodeItem } -> {
|
all { it is MetaItem.NodeItem } -> {
|
||||||
//list nodes in item
|
//list nodes in item
|
||||||
val nodes = map { it.node }
|
val nodes = map { (it as MetaItem.NodeItem).node }
|
||||||
//represent as key->value entries
|
//represent as key->value entries
|
||||||
val entries = nodes.flatMap { it.items.entries.asSequence() }
|
val entries = nodes.flatMap { it.items.entries.asSequence() }
|
||||||
//group by keys
|
//group by keys
|
||||||
|
@ -174,8 +174,9 @@ val MetaItem<*>?.short get() = number?.toShort()
|
|||||||
|
|
||||||
val MetaItem<*>?.stringList get() = value?.list?.map { it.string } ?: emptyList()
|
val MetaItem<*>?.stringList get() = value?.list?.map { it.string } ?: emptyList()
|
||||||
|
|
||||||
val <M : Meta> MetaItem<M>.node: M
|
val <M : Meta> MetaItem<M>?.node: M?
|
||||||
get() = when (this) {
|
get() = when (this) {
|
||||||
|
null -> null
|
||||||
is MetaItem.ValueItem -> error("Trying to interpret value meta item as node item")
|
is MetaItem.ValueItem -> error("Trying to interpret value meta item as node item")
|
||||||
is MetaItem.NodeItem -> node
|
is MetaItem.NodeItem -> node
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
package hep.dataforge.vis
|
||||||
|
|
||||||
|
import hep.dataforge.meta.*
|
||||||
|
import hep.dataforge.names.Name
|
||||||
|
import hep.dataforge.names.toName
|
||||||
|
import javafx.beans.binding.ObjectBinding
|
||||||
|
import tornadofx.*
|
||||||
|
|
||||||
|
class DisplayObjectPropertyListener(val obj: DisplayObject) {
|
||||||
|
private val binndings = HashMap<Name, ObjectBinding<MetaItem<*>?>>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
obj.onChange(this) { name, _, _ ->
|
||||||
|
binndings[name]?.invalidate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun get(key: Name): ObjectBinding<MetaItem<*>?> {
|
||||||
|
return binndings.getOrPut(key) {
|
||||||
|
object : ObjectBinding<MetaItem<*>?>() {
|
||||||
|
override fun computeValue(): MetaItem<*>? = obj.getProperty(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun get(key: String) = get(key.toName())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ObjectBinding<MetaItem<*>?>.value() = this.objectBinding { it.value }
|
||||||
|
fun ObjectBinding<MetaItem<*>?>.string() = this.stringBinding { it.string }
|
||||||
|
fun ObjectBinding<MetaItem<*>?>.number() = this.objectBinding { it.number }
|
||||||
|
fun ObjectBinding<MetaItem<*>?>.double() = this.objectBinding { it.double }
|
||||||
|
fun ObjectBinding<MetaItem<*>?>.float() = this.objectBinding { it.number?.toFloat() }
|
||||||
|
fun ObjectBinding<MetaItem<*>?>.int() = this.objectBinding { it.int }
|
||||||
|
fun ObjectBinding<MetaItem<*>?>.long() = this.objectBinding { it.long }
|
||||||
|
fun ObjectBinding<MetaItem<*>?>.node() = this.objectBinding { it.node }
|
||||||
|
|
||||||
|
fun <T> ObjectBinding<MetaItem<*>?>.transform(transform: (MetaItem<*>) -> T) = this.objectBinding { it?.let(transform) }
|
@ -3,24 +3,56 @@ package hep.dataforge.vis.spatial
|
|||||||
import hep.dataforge.context.Context
|
import hep.dataforge.context.Context
|
||||||
import hep.dataforge.io.Output
|
import hep.dataforge.io.Output
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.meta.int
|
||||||
|
import hep.dataforge.vis.DisplayGroup
|
||||||
|
import hep.dataforge.vis.DisplayObject
|
||||||
|
import hep.dataforge.vis.DisplayObjectPropertyListener
|
||||||
|
import hep.dataforge.vis.transform
|
||||||
|
import javafx.event.EventHandler
|
||||||
import javafx.scene.*
|
import javafx.scene.*
|
||||||
|
import javafx.scene.input.KeyCode
|
||||||
|
import javafx.scene.input.KeyEvent
|
||||||
|
import javafx.scene.input.MouseEvent
|
||||||
|
import javafx.scene.input.ScrollEvent
|
||||||
import javafx.scene.paint.Color
|
import javafx.scene.paint.Color
|
||||||
|
import javafx.scene.paint.PhongMaterial
|
||||||
import org.fxyz3d.geometry.Point3D
|
import org.fxyz3d.geometry.Point3D
|
||||||
import org.fxyz3d.shapes.primitives.CuboidMesh
|
import org.fxyz3d.shapes.primitives.CuboidMesh
|
||||||
import org.fxyz3d.utils.CameraTransformer
|
import org.fxyz3d.utils.CameraTransformer
|
||||||
|
|
||||||
class FXSpatialRenderer(override val context: Context) : Output<DisplayObject3D> {
|
|
||||||
|
/**
|
||||||
|
* https://github.com/miho/JCSG for operations
|
||||||
|
*
|
||||||
|
* TODO move world and camera boilerplate to another class
|
||||||
|
*/
|
||||||
|
class FXSpatialRenderer(override val context: Context) : Output<DisplayObject> {
|
||||||
|
|
||||||
private val world: Group = Group()
|
private val world: Group = Group()
|
||||||
|
|
||||||
val camera = PerspectiveCamera()
|
private val camera = PerspectiveCamera().apply {
|
||||||
|
nearClip = CAMERA_NEAR_CLIP
|
||||||
val cameraTransform = CameraTransformer().apply {
|
farClip = CAMERA_FAR_CLIP
|
||||||
children.add(camera)
|
translateZ = CAMERA_INITIAL_DISTANCE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val cameraShift = CameraTransformer().apply {
|
||||||
|
val cameraFlip = CameraTransformer()
|
||||||
|
cameraFlip.children.add(camera)
|
||||||
|
cameraFlip.setRotateZ(180.0)
|
||||||
|
children.add(cameraFlip)
|
||||||
|
}
|
||||||
|
|
||||||
|
val cameraRotation = CameraTransformer().apply {
|
||||||
|
children.add(cameraShift)
|
||||||
|
ry.angle = CAMERA_INITIAL_Y_ANGLE
|
||||||
|
rx.angle = CAMERA_INITIAL_X_ANGLE
|
||||||
|
rz.angle = CAMERA_INITIAL_Z_ANGLE
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
val canvas: SubScene = SubScene(
|
val canvas: SubScene = SubScene(
|
||||||
Group(world, cameraTransform).apply { DepthTest.ENABLE },
|
Group(world, cameraRotation).apply { DepthTest.ENABLE },
|
||||||
1024.0,
|
1024.0,
|
||||||
768.0,
|
768.0,
|
||||||
true,
|
true,
|
||||||
@ -29,17 +61,150 @@ class FXSpatialRenderer(override val context: Context) : Output<DisplayObject3D>
|
|||||||
fill = Color.GREY
|
fill = Color.GREY
|
||||||
this.camera = this@FXSpatialRenderer.camera
|
this.camera = this@FXSpatialRenderer.camera
|
||||||
id = "canvas"
|
id = "canvas"
|
||||||
|
handleKeyboard(this)
|
||||||
|
handleMouse(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildObject(obj: DisplayObject3D): Node {
|
private fun buildObject(obj: DisplayObject): Node {
|
||||||
val center = Point3D(obj.x.toFloat(), obj.y.toFloat(), obj.z.toFloat())
|
|
||||||
return when (obj) {
|
return when (obj) {
|
||||||
is Box3D -> CuboidMesh(obj.xSize, obj.ySize, obj.zSize).apply { this.center = center }
|
is DisplayGroup -> Group(obj.children.map { buildObject(it) })
|
||||||
|
is Box -> CuboidMesh(obj.xSize, obj.ySize, obj.zSize).apply {
|
||||||
|
val listener = DisplayObjectPropertyListener(obj)
|
||||||
|
this.center = Point3D(obj.x.toFloat(), obj.y.toFloat(), obj.z.toFloat())
|
||||||
|
this.diffuseColorProperty().bind(listener["color"].transform {
|
||||||
|
val int = it.int ?: 0
|
||||||
|
val red = int and 0x00ff0000 shr 16
|
||||||
|
val green = int and 0x0000ff00 shr 8
|
||||||
|
val blue = int and 0x000000ff
|
||||||
|
return@transform Color.rgb(red, green, blue)
|
||||||
|
})
|
||||||
|
}
|
||||||
else -> TODO()
|
else -> TODO()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun render(obj: DisplayObject3D, meta: Meta) {
|
override fun render(obj: DisplayObject, meta: Meta) {
|
||||||
world.children.add(buildObject(obj))
|
world.children.add(buildObject(obj))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handleKeyboard(scene: SubScene) {
|
||||||
|
scene.onKeyPressed = EventHandler<KeyEvent> { event ->
|
||||||
|
if (event.isControlDown) {
|
||||||
|
when (event.code) {
|
||||||
|
KeyCode.Z -> {
|
||||||
|
cameraShift.t.x = 0.0
|
||||||
|
cameraShift.t.y = 0.0
|
||||||
|
camera.translateZ = CAMERA_INITIAL_DISTANCE
|
||||||
|
cameraRotation.ry.angle = CAMERA_INITIAL_Y_ANGLE
|
||||||
|
cameraRotation.rx.angle = CAMERA_INITIAL_X_ANGLE
|
||||||
|
}
|
||||||
|
// KeyCode.X -> axisGroup.isVisible = !axisGroup.isVisible
|
||||||
|
// KeyCode.S -> snapshot()
|
||||||
|
// KeyCode.DIGIT1 -> pixelMap.filterKeys { it.getLayerNumber() == 1 }.values.forEach {
|
||||||
|
// toggleTransparency(
|
||||||
|
// it
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// KeyCode.DIGIT2 -> pixelMap.filterKeys { it.getLayerNumber() == 2 }.values.forEach {
|
||||||
|
// toggleTransparency(
|
||||||
|
// it
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// KeyCode.DIGIT3 -> pixelMap.filterKeys { it.getLayerNumber() == 3 }.values.forEach {
|
||||||
|
// toggleTransparency(
|
||||||
|
// it
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
else -> {
|
||||||
|
}//do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleMouse(scene: SubScene) {
|
||||||
|
|
||||||
|
var mousePosX: Double = 0.0
|
||||||
|
var mousePosY: Double = 0.0
|
||||||
|
var mouseOldX: Double = 0.0
|
||||||
|
var mouseOldY: Double = 0.0
|
||||||
|
var mouseDeltaX: Double = 0.0
|
||||||
|
var mouseDeltaY: Double = 0.0
|
||||||
|
|
||||||
|
scene.onMousePressed = EventHandler<MouseEvent> { me ->
|
||||||
|
mousePosX = me.sceneX
|
||||||
|
mousePosY = me.sceneY
|
||||||
|
mouseOldX = me.sceneX
|
||||||
|
mouseOldY = me.sceneY
|
||||||
|
}
|
||||||
|
|
||||||
|
scene.onMouseDragged = EventHandler<MouseEvent> { me ->
|
||||||
|
mouseOldX = mousePosX
|
||||||
|
mouseOldY = mousePosY
|
||||||
|
mousePosX = me.sceneX
|
||||||
|
mousePosY = me.sceneY
|
||||||
|
mouseDeltaX = mousePosX - mouseOldX
|
||||||
|
mouseDeltaY = mousePosY - mouseOldY
|
||||||
|
|
||||||
|
val modifier = when {
|
||||||
|
me.isControlDown -> CONTROL_MULTIPLIER
|
||||||
|
me.isShiftDown -> SHIFT_MULTIPLIER
|
||||||
|
else -> 1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
if (me.isPrimaryButtonDown) {
|
||||||
|
cameraRotation.rz.angle =
|
||||||
|
cameraRotation.rz.angle + mouseDeltaX * MOUSE_SPEED * modifier * ROTATION_SPEED
|
||||||
|
cameraRotation.rx.angle =
|
||||||
|
cameraRotation.rx.angle + mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED
|
||||||
|
// } else if (me.isSecondaryButtonDown()) {
|
||||||
|
// double z = camera.getTranslateZ();
|
||||||
|
// double newZ = z + mouseDeltaX * MOUSE_SPEED * modifier*100;
|
||||||
|
// camera.setTranslateZ(newZ);
|
||||||
|
} else if (me.isSecondaryButtonDown) {
|
||||||
|
cameraShift.t.x = cameraShift.t.x + mouseDeltaX * MOUSE_SPEED * modifier * TRACK_SPEED
|
||||||
|
cameraShift.t.y = cameraShift.t.y + mouseDeltaY * MOUSE_SPEED * modifier * TRACK_SPEED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scene.onScroll = EventHandler<ScrollEvent> { event ->
|
||||||
|
val z = camera.translateZ
|
||||||
|
val newZ = z + MOUSE_SPEED * event.deltaY * RESIZE_SPEED
|
||||||
|
camera.translateZ = newZ
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val CAMERA_INITIAL_DISTANCE = -4500.0
|
||||||
|
private const val CAMERA_INITIAL_X_ANGLE = -50.0
|
||||||
|
private const val CAMERA_INITIAL_Y_ANGLE = 0.0
|
||||||
|
private const val CAMERA_INITIAL_Z_ANGLE = -210.0
|
||||||
|
private const val CAMERA_NEAR_CLIP = 0.1
|
||||||
|
private const val CAMERA_FAR_CLIP = 10000.0
|
||||||
|
private const val AXIS_LENGTH = 2000.0
|
||||||
|
private const val CONTROL_MULTIPLIER = 0.1
|
||||||
|
private const val SHIFT_MULTIPLIER = 10.0
|
||||||
|
private const val MOUSE_SPEED = 0.1
|
||||||
|
private const val ROTATION_SPEED = 2.0
|
||||||
|
private const val TRACK_SPEED = 6.0
|
||||||
|
private const val RESIZE_SPEED = 50.0
|
||||||
|
private const val LINE_WIDTH = 3.0
|
||||||
|
|
||||||
|
private val redMaterial = PhongMaterial().apply {
|
||||||
|
diffuseColor = Color.DARKRED
|
||||||
|
specularColor = Color.RED
|
||||||
|
}
|
||||||
|
|
||||||
|
private val whiteMaterial = PhongMaterial().apply {
|
||||||
|
diffuseColor = Color.WHITE
|
||||||
|
specularColor = Color.LIGHTBLUE
|
||||||
|
}
|
||||||
|
|
||||||
|
private val greyMaterial = PhongMaterial().apply {
|
||||||
|
diffuseColor = Color.DARKGREY
|
||||||
|
specularColor = Color.GREY
|
||||||
|
}
|
||||||
|
|
||||||
|
private val blueMaterial = PhongMaterial(Color.BLUE)
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,9 +1,15 @@
|
|||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.context.Global
|
import hep.dataforge.context.Global
|
||||||
import hep.dataforge.meta.EmptyMeta
|
import hep.dataforge.meta.number
|
||||||
|
import hep.dataforge.vis.DisplayGroup
|
||||||
import javafx.scene.Parent
|
import javafx.scene.Parent
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.isActive
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
|
||||||
class RendererDemoApp : App(RendererDemoView::class)
|
class RendererDemoApp : App(RendererDemoView::class)
|
||||||
@ -15,23 +21,37 @@ class RendererDemoView: View(){
|
|||||||
center = renderer.canvas
|
center = renderer.canvas
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lateinit var group: DisplayGroup
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val cube = Box3D(null, EmptyMeta).apply {
|
|
||||||
|
renderer.render {
|
||||||
|
group = group {
|
||||||
|
box {
|
||||||
xSize = 100.0
|
xSize = 100.0
|
||||||
ySize = 100.0
|
ySize = 100.0
|
||||||
zSize = 100.0
|
zSize = 100.0
|
||||||
}
|
}
|
||||||
renderer.render(cube)
|
box {
|
||||||
|
x = 110.0
|
||||||
renderer.camera.apply {
|
xSize = 100.0
|
||||||
nearClip = 0.1
|
ySize = 100.0
|
||||||
farClip = 10000.0
|
zSize = 100.0
|
||||||
translateX = -200.0
|
}
|
||||||
translateY = -200.0
|
}
|
||||||
fieldOfView = 20.0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer.cameraTransform.apply{
|
var color by group.properties.number(1530).int
|
||||||
|
|
||||||
|
GlobalScope.launch {
|
||||||
|
val random = Random(111)
|
||||||
|
while (isActive) {
|
||||||
|
delay(1000)
|
||||||
|
color = random.nextInt(0, Int.MAX_VALUE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.cameraRotation.apply {
|
||||||
ry.angle = -30.0
|
ry.angle = -30.0
|
||||||
rx.angle = -15.0
|
rx.angle = -15.0
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
|
import hep.dataforge.meta.EmptyMeta
|
||||||
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.vis.DisplayGroup
|
||||||
|
import hep.dataforge.vis.DisplayObject
|
||||||
|
import hep.dataforge.vis.double
|
||||||
|
|
||||||
|
class Box(parent: DisplayObject?, meta: Meta) : DisplayObject3D(parent, TYPE, meta) {
|
||||||
|
var xSize by double(1.0)
|
||||||
|
var ySize by double(1.0)
|
||||||
|
var zSize by double(1.0)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TYPE = "geometry.spatial.box"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DisplayGroup.box(meta: Meta = EmptyMeta, action: Box.() -> Unit = {}) =
|
||||||
|
Box(this, meta).apply(action).also { addChild(it) }
|
@ -1,9 +1,10 @@
|
|||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
|
import hep.dataforge.io.Output
|
||||||
|
import hep.dataforge.meta.EmptyMeta
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.vis.DisplayLeaf
|
import hep.dataforge.vis.*
|
||||||
import hep.dataforge.vis.DisplayObject
|
import hep.dataforge.vis.DisplayObject.Companion.DEFAULT_TYPE
|
||||||
import hep.dataforge.vis.double
|
|
||||||
|
|
||||||
|
|
||||||
open class DisplayObject3D(parent: DisplayObject?, type: String, meta: Meta) : DisplayLeaf(parent, type, meta) {
|
open class DisplayObject3D(parent: DisplayObject?, type: String, meta: Meta) : DisplayLeaf(parent, type, meta) {
|
||||||
@ -16,13 +17,9 @@ open class DisplayObject3D(parent: DisplayObject?, type: String, meta: Meta) : D
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Box3D(parent: DisplayObject?, meta: Meta) : DisplayObject3D(parent,
|
fun DisplayGroup.group(meta: Meta = EmptyMeta, action: DisplayGroup.() -> Unit = {}) =
|
||||||
TYPE, meta) {
|
DisplayNode(this, DEFAULT_TYPE, meta).apply(action).also{addChild(it)}
|
||||||
var xSize by double(1.0)
|
|
||||||
var ySize by double(1.0)
|
|
||||||
var zSize by double(1.0)
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val TYPE = "geometry.spatial.box"
|
fun Output<DisplayObject>.render(meta: Meta = EmptyMeta, action: DisplayGroup.() -> Unit) =
|
||||||
}
|
render(DisplayNode(null, DEFAULT_TYPE, EmptyMeta).apply(action), meta)
|
||||||
}
|
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
|
//TODO replace by platform optimized version
|
||||||
|
data class Point3D(
|
||||||
|
val x: Float,
|
||||||
|
val y: Float,
|
||||||
|
val z: Float
|
||||||
|
)
|
@ -66,14 +66,18 @@ tailrec fun DisplayObject.getProperty(name: Name): MetaItem<*>? = properties[nam
|
|||||||
/**
|
/**
|
||||||
* A change listener for [DisplayObject] configuration.
|
* A change listener for [DisplayObject] configuration.
|
||||||
*/
|
*/
|
||||||
fun DisplayObject.onChange(owner: Any?, action: (Name, before: MetaItem<*>?, after: MetaItem<*>?) -> Unit) =
|
fun DisplayObject.onChange(owner: Any?, action: (Name, before: MetaItem<*>?, after: MetaItem<*>?) -> Unit) {
|
||||||
properties.style.onChange(owner, action)
|
properties.style.onChange(owner, action)
|
||||||
|
parent?.onChange(owner, action)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove all meta listeners with matching owners
|
* Remove all meta listeners with matching owners
|
||||||
*/
|
*/
|
||||||
fun DisplayObject.removeChangeListener(owner: Any?) =
|
fun DisplayObject.removeChangeListener(owner: Any?) {
|
||||||
properties.style.removeListener(owner)
|
properties.style.removeListener(owner)
|
||||||
|
parent?.removeChangeListener(owner)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -92,7 +96,7 @@ internal data class ObjectListener(
|
|||||||
* Basic group of display objects
|
* Basic group of display objects
|
||||||
*/
|
*/
|
||||||
open class DisplayNode(
|
open class DisplayNode(
|
||||||
override val parent: DisplayObject?,
|
override val parent: DisplayObject? = null,
|
||||||
override val type: String = DEFAULT_TYPE,
|
override val type: String = DEFAULT_TYPE,
|
||||||
meta: Meta = EmptyMeta
|
meta: Meta = EmptyMeta
|
||||||
) : DisplayGroup {
|
) : DisplayGroup {
|
||||||
|
@ -1,48 +1,98 @@
|
|||||||
package hep.dataforge.vis
|
package hep.dataforge.vis
|
||||||
|
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
import hep.dataforge.values.Null
|
import hep.dataforge.names.Name
|
||||||
|
import hep.dataforge.names.toName
|
||||||
import hep.dataforge.values.Value
|
import hep.dataforge.values.Value
|
||||||
import kotlin.jvm.JvmName
|
import kotlin.jvm.JvmName
|
||||||
|
import kotlin.properties.ReadWriteProperty
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
fun DisplayObject.value(default: Value = Null, key: String? = null) =
|
/**
|
||||||
ValueConfigDelegate(properties, key, default)
|
* A delegate for display object properties
|
||||||
|
*/
|
||||||
|
class DisplayObjectDelegate(
|
||||||
|
val key: Name?,
|
||||||
|
val default: MetaItem<*>?,
|
||||||
|
val inherited: Boolean
|
||||||
|
) : ReadWriteProperty<DisplayObject, MetaItem<*>?> {
|
||||||
|
override fun getValue(thisRef: DisplayObject, property: KProperty<*>): MetaItem<*>? {
|
||||||
|
val name = key ?: property.name.toName()
|
||||||
|
return if (inherited) {
|
||||||
|
thisRef.getProperty(name)
|
||||||
|
} else {
|
||||||
|
thisRef.properties[name]
|
||||||
|
} ?: default
|
||||||
|
}
|
||||||
|
|
||||||
fun DisplayObject.string(default: String? = null, key: String? = null) =
|
override fun setValue(thisRef: DisplayObject, property: KProperty<*>, value: MetaItem<*>?) {
|
||||||
StringConfigDelegate(properties, key, default)
|
val name = key ?: property.name.toName()
|
||||||
|
thisRef.properties.style[name] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun DisplayObject.boolean(default: Boolean? = null, key: String? = null) =
|
class DisplayObjectDelegateWrapper<T>(
|
||||||
BooleanConfigDelegate(properties, key, default)
|
val key: Name?,
|
||||||
|
val default: T,
|
||||||
|
val inherited: Boolean,
|
||||||
|
val write: Config.(name: Name, value: T) -> Unit = { name, value -> set(name, value) },
|
||||||
|
val read: (MetaItem<*>?) -> T?
|
||||||
|
) : ReadWriteProperty<DisplayObject, T> {
|
||||||
|
override fun getValue(thisRef: DisplayObject, property: KProperty<*>): T {
|
||||||
|
val name = key ?: property.name.toName()
|
||||||
|
return if (inherited) {
|
||||||
|
read(thisRef.getProperty(name))
|
||||||
|
} else {
|
||||||
|
read(thisRef.properties[name])
|
||||||
|
} ?: default
|
||||||
|
}
|
||||||
|
|
||||||
fun DisplayObject.number(default: Number? = null, key: String? = null) =
|
override fun setValue(thisRef: DisplayObject, property: KProperty<*>, value: T) {
|
||||||
NumberConfigDelegate(properties, key, default)
|
val name = key ?: property.name.toName()
|
||||||
|
thisRef.properties.style.write(name, value)
|
||||||
fun DisplayObject.double(default: Double? = null, key: String? = null) =
|
}
|
||||||
NumberConfigDelegate(properties, key, default).double
|
}
|
||||||
|
|
||||||
fun DisplayObject.int(default: Int? = null, key: String? = null) =
|
|
||||||
NumberConfigDelegate(properties, key, default).int
|
|
||||||
|
|
||||||
|
|
||||||
fun DisplayObject.node(key: String? = null) = StyledNodeDelegate(properties, key)
|
fun DisplayObject.value(default: Value? = null, key: String? = null, inherited: Boolean = true) =
|
||||||
|
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.value }
|
||||||
|
|
||||||
|
fun DisplayObject.string(default: String? = null, key: String? = null, inherited: Boolean = true) =
|
||||||
|
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.string }
|
||||||
|
|
||||||
|
fun DisplayObject.boolean(default: Boolean? = null, key: String? = null, inherited: Boolean = true) =
|
||||||
|
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.boolean }
|
||||||
|
|
||||||
|
fun DisplayObject.number(default: Number? = null, key: String? = null, inherited: Boolean = true) =
|
||||||
|
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.number }
|
||||||
|
|
||||||
|
fun DisplayObject.double(default: Double? = null, key: String? = null, inherited: Boolean = true) =
|
||||||
|
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.double }
|
||||||
|
|
||||||
|
fun DisplayObject.int(default: Int? = null, key: String? = null, inherited: Boolean = true) =
|
||||||
|
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.int }
|
||||||
|
|
||||||
|
|
||||||
|
fun DisplayObject.node(key: String? = null, inherited: Boolean = true) =
|
||||||
|
DisplayObjectDelegateWrapper(key?.toName(), null, inherited) { it.node }
|
||||||
|
|
||||||
//fun <T : Configurable> Configurable.spec(spec: Specification<T>, key: String? = null) = ChildConfigDelegate<T>(key) { spec.wrap(this) }
|
//fun <T : Configurable> Configurable.spec(spec: Specification<T>, key: String? = null) = ChildConfigDelegate<T>(key) { spec.wrap(this) }
|
||||||
|
|
||||||
@JvmName("safeString")
|
@JvmName("safeString")
|
||||||
fun DisplayObject.string(default: String, key: String? = null) =
|
fun DisplayObject.string(default: String, key: String? = null, inherited: Boolean = true) =
|
||||||
SafeStringConfigDelegate(properties, key, default)
|
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.string }
|
||||||
|
|
||||||
@JvmName("safeBoolean")
|
@JvmName("safeBoolean")
|
||||||
fun DisplayObject.boolean(default: Boolean, key: String? = null) =
|
fun DisplayObject.boolean(default: Boolean, key: String? = null, inherited: Boolean = true) =
|
||||||
SafeBooleanConfigDelegate(properties, key, default)
|
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.boolean }
|
||||||
|
|
||||||
@JvmName("safeNumber")
|
@JvmName("safeNumber")
|
||||||
fun DisplayObject.number(default: Number, key: String? = null) =
|
fun DisplayObject.number(default: Number, key: String? = null, inherited: Boolean = true) =
|
||||||
SafeNumberConfigDelegate(properties, key, default)
|
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.number }
|
||||||
|
|
||||||
@JvmName("safeDouble")
|
@JvmName("safeDouble")
|
||||||
fun DisplayObject.double(default: Double, key: String? = null) =
|
fun DisplayObject.double(default: Double, key: String? = null, inherited: Boolean = true) =
|
||||||
SafeNumberConfigDelegate(properties, key, default).double
|
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.double }
|
||||||
|
|
||||||
inline fun <reified E : Enum<E>> DisplayObject.enum(default: E, key: String? = null) =
|
inline fun <reified E : Enum<E>> DisplayObject.enum(default: E, key: String? = null, inherited: Boolean = true) =
|
||||||
SafeEnumvConfigDelegate(properties, key, default) { enumValueOf(it) }
|
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { item -> item.string?.let { enumValueOf<E>(it) } }
|
Loading…
Reference in New Issue
Block a user