From 017995e04590596c05f21a431d7d2f150f658dd0 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 12 Oct 2019 17:17:05 +0300 Subject: [PATCH 01/25] Merged fx module into vis-common --- build.gradle.kts | 2 +- dataforge-vis-common/build.gradle.kts | 23 ++++++++++-- .../kotlin/hep/dataforge/vis/fx/FXPlugin.kt | 0 .../dataforge/vis/fx/demo/MetaEditorDemo.kt | 0 .../hep/dataforge/vis/fx/meta/ConfigEditor.kt | 0 .../hep/dataforge/vis/fx/meta/FXMeta.kt | 0 .../hep/dataforge/vis/fx/meta/MetaViewer.kt | 0 .../vis/fx/values/ColorValueChooser.kt | 0 .../vis/fx/values/ComboBoxValueChooser.kt | 0 .../vis/fx/values/TextValueChooser.kt | 0 .../dataforge/vis/fx/values/ValueCallback.kt | 0 .../dataforge/vis/fx/values/ValueChooser.kt | 0 .../vis/fx/values/ValueChooserBase.kt | 0 .../src/jvmMain}/resources/img/df.png | Bin dataforge-vis-fx/build.gradle.kts | 23 ------------ dataforge-vis-spatial-gdml/build.gradle.kts | 8 +++++ .../vis/spatial/three/MeshThreeFactory.kt | 4 +-- .../vis/spatial/three/ThreeFactory.kt | 9 +++-- .../vis/spatial/three/ThreeGeometryBuilder.kt | 3 ++ .../vis/spatial/three/ThreeLineFactory.kt | 2 +- .../vis/spatial/three/ThreeOutput.kt | 30 ++++++++++++++-- .../vis/spatial/three/ThreePlugin.kt | 33 +++--------------- 22 files changed, 73 insertions(+), 64 deletions(-) rename {dataforge-vis-fx/src/main => dataforge-vis-common/src/jvmMain}/kotlin/hep/dataforge/vis/fx/FXPlugin.kt (100%) rename {dataforge-vis-fx/src/main => dataforge-vis-common/src/jvmMain}/kotlin/hep/dataforge/vis/fx/demo/MetaEditorDemo.kt (100%) rename {dataforge-vis-fx/src/main => dataforge-vis-common/src/jvmMain}/kotlin/hep/dataforge/vis/fx/meta/ConfigEditor.kt (100%) rename {dataforge-vis-fx/src/main => dataforge-vis-common/src/jvmMain}/kotlin/hep/dataforge/vis/fx/meta/FXMeta.kt (100%) rename {dataforge-vis-fx/src/main => dataforge-vis-common/src/jvmMain}/kotlin/hep/dataforge/vis/fx/meta/MetaViewer.kt (100%) rename {dataforge-vis-fx/src/main => dataforge-vis-common/src/jvmMain}/kotlin/hep/dataforge/vis/fx/values/ColorValueChooser.kt (100%) rename {dataforge-vis-fx/src/main => dataforge-vis-common/src/jvmMain}/kotlin/hep/dataforge/vis/fx/values/ComboBoxValueChooser.kt (100%) rename {dataforge-vis-fx/src/main => dataforge-vis-common/src/jvmMain}/kotlin/hep/dataforge/vis/fx/values/TextValueChooser.kt (100%) rename {dataforge-vis-fx/src/main => dataforge-vis-common/src/jvmMain}/kotlin/hep/dataforge/vis/fx/values/ValueCallback.kt (100%) rename {dataforge-vis-fx/src/main => dataforge-vis-common/src/jvmMain}/kotlin/hep/dataforge/vis/fx/values/ValueChooser.kt (100%) rename {dataforge-vis-fx/src/main => dataforge-vis-common/src/jvmMain}/kotlin/hep/dataforge/vis/fx/values/ValueChooserBase.kt (100%) rename {dataforge-vis-fx/src/main => dataforge-vis-common/src/jvmMain}/resources/img/df.png (100%) delete mode 100644 dataforge-vis-fx/build.gradle.kts diff --git a/build.gradle.kts b/build.gradle.kts index 48899168..0822fa2f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,7 +2,7 @@ val dataforgeVersion by extra("0.1.3") plugins { val kotlinVersion = "1.3.50" - val toolsVersion = "0.2.0" + val toolsVersion = "0.2.1" kotlin("jvm") version kotlinVersion apply false id("kotlin-dce-js") version kotlinVersion apply false diff --git a/dataforge-vis-common/build.gradle.kts b/dataforge-vis-common/build.gradle.kts index 678a9e72..9306c687 100644 --- a/dataforge-vis-common/build.gradle.kts +++ b/dataforge-vis-common/build.gradle.kts @@ -1,5 +1,8 @@ +import org.openjfx.gradle.JavaFXOptions + plugins { id("scientifik.mpp") + id("org.openjfx.javafxplugin") } scientifik{ @@ -9,13 +12,23 @@ scientifik{ val dataforgeVersion: String by rootProject.extra kotlin { + jvm{ + withJava() + } + sourceSets { - val commonMain by getting { + commonMain{ dependencies { api("hep.dataforge:dataforge-output:$dataforgeVersion") } } - val jsMain by getting { + jvmMain{ + dependencies { + api("no.tornado:tornadofx:1.7.19") + api("no.tornado:tornadofx-controlsfx:0.1") + } + } + jsMain{ dependencies { api("hep.dataforge:dataforge-output-html:$dataforgeVersion") api(npm("text-encoding")) @@ -24,4 +37,8 @@ kotlin { } } } -} \ No newline at end of file +} + +configure { + modules("javafx.controls") +} diff --git a/dataforge-vis-fx/src/main/kotlin/hep/dataforge/vis/fx/FXPlugin.kt b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/FXPlugin.kt similarity index 100% rename from dataforge-vis-fx/src/main/kotlin/hep/dataforge/vis/fx/FXPlugin.kt rename to dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/FXPlugin.kt diff --git a/dataforge-vis-fx/src/main/kotlin/hep/dataforge/vis/fx/demo/MetaEditorDemo.kt b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/demo/MetaEditorDemo.kt similarity index 100% rename from dataforge-vis-fx/src/main/kotlin/hep/dataforge/vis/fx/demo/MetaEditorDemo.kt rename to dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/demo/MetaEditorDemo.kt diff --git a/dataforge-vis-fx/src/main/kotlin/hep/dataforge/vis/fx/meta/ConfigEditor.kt b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/meta/ConfigEditor.kt similarity index 100% rename from dataforge-vis-fx/src/main/kotlin/hep/dataforge/vis/fx/meta/ConfigEditor.kt rename to dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/meta/ConfigEditor.kt diff --git a/dataforge-vis-fx/src/main/kotlin/hep/dataforge/vis/fx/meta/FXMeta.kt b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/meta/FXMeta.kt similarity index 100% rename from dataforge-vis-fx/src/main/kotlin/hep/dataforge/vis/fx/meta/FXMeta.kt rename to dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/meta/FXMeta.kt diff --git a/dataforge-vis-fx/src/main/kotlin/hep/dataforge/vis/fx/meta/MetaViewer.kt b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/meta/MetaViewer.kt similarity index 100% rename from dataforge-vis-fx/src/main/kotlin/hep/dataforge/vis/fx/meta/MetaViewer.kt rename to dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/meta/MetaViewer.kt diff --git a/dataforge-vis-fx/src/main/kotlin/hep/dataforge/vis/fx/values/ColorValueChooser.kt b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/ColorValueChooser.kt similarity index 100% rename from dataforge-vis-fx/src/main/kotlin/hep/dataforge/vis/fx/values/ColorValueChooser.kt rename to dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/ColorValueChooser.kt diff --git a/dataforge-vis-fx/src/main/kotlin/hep/dataforge/vis/fx/values/ComboBoxValueChooser.kt b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/ComboBoxValueChooser.kt similarity index 100% rename from dataforge-vis-fx/src/main/kotlin/hep/dataforge/vis/fx/values/ComboBoxValueChooser.kt rename to dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/ComboBoxValueChooser.kt diff --git a/dataforge-vis-fx/src/main/kotlin/hep/dataforge/vis/fx/values/TextValueChooser.kt b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/TextValueChooser.kt similarity index 100% rename from dataforge-vis-fx/src/main/kotlin/hep/dataforge/vis/fx/values/TextValueChooser.kt rename to dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/TextValueChooser.kt diff --git a/dataforge-vis-fx/src/main/kotlin/hep/dataforge/vis/fx/values/ValueCallback.kt b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/ValueCallback.kt similarity index 100% rename from dataforge-vis-fx/src/main/kotlin/hep/dataforge/vis/fx/values/ValueCallback.kt rename to dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/ValueCallback.kt diff --git a/dataforge-vis-fx/src/main/kotlin/hep/dataforge/vis/fx/values/ValueChooser.kt b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/ValueChooser.kt similarity index 100% rename from dataforge-vis-fx/src/main/kotlin/hep/dataforge/vis/fx/values/ValueChooser.kt rename to dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/ValueChooser.kt diff --git a/dataforge-vis-fx/src/main/kotlin/hep/dataforge/vis/fx/values/ValueChooserBase.kt b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/ValueChooserBase.kt similarity index 100% rename from dataforge-vis-fx/src/main/kotlin/hep/dataforge/vis/fx/values/ValueChooserBase.kt rename to dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/ValueChooserBase.kt diff --git a/dataforge-vis-fx/src/main/resources/img/df.png b/dataforge-vis-common/src/jvmMain/resources/img/df.png similarity index 100% rename from dataforge-vis-fx/src/main/resources/img/df.png rename to dataforge-vis-common/src/jvmMain/resources/img/df.png diff --git a/dataforge-vis-fx/build.gradle.kts b/dataforge-vis-fx/build.gradle.kts deleted file mode 100644 index 6408a4ab..00000000 --- a/dataforge-vis-fx/build.gradle.kts +++ /dev/null @@ -1,23 +0,0 @@ -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile -import org.openjfx.gradle.JavaFXOptions - -plugins { - id("scientifik.jvm") - id("org.openjfx.javafxplugin") -} - -dependencies { - api(project(":dataforge-vis-common")) - api("no.tornado:tornadofx:1.7.19") - api("no.tornado:tornadofx-controlsfx:0.1") -} - -configure { - modules("javafx.controls") -} - -tasks.withType { - kotlinOptions{ - jvmTarget = "1.8" - } -} \ No newline at end of file diff --git a/dataforge-vis-spatial-gdml/build.gradle.kts b/dataforge-vis-spatial-gdml/build.gradle.kts index af7f99ad..d02c8258 100644 --- a/dataforge-vis-spatial-gdml/build.gradle.kts +++ b/dataforge-vis-spatial-gdml/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpack + plugins { id("scientifik.mpp") } @@ -21,4 +23,10 @@ kotlin { } } } +} + +tasks{ + val jsBrowserWebpack by getting(KotlinWebpack::class) { + sourceMaps = false + } } \ No newline at end of file diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/MeshThreeFactory.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/MeshThreeFactory.kt index 2b0c5d21..19745507 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/MeshThreeFactory.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/MeshThreeFactory.kt @@ -19,8 +19,8 @@ import kotlin.reflect.KClass /** * Basic geometry-based factory */ -abstract class MeshThreeFactory( - override val type: KClass +abstract class MeshThreeFactory( + override val type: KClass ) : ThreeFactory { /** * Build a geometry for an object diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeFactory.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeFactory.kt index 94e71f5e..23339ac7 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeFactory.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeFactory.kt @@ -16,9 +16,9 @@ import kotlin.reflect.KClass * Builder and updater for three.js object */ @Type(TYPE) -interface ThreeFactory { +interface ThreeFactory { - val type: KClass + val type: KClass operator fun invoke(obj: T): Object3D @@ -30,7 +30,7 @@ interface ThreeFactory { /** * Update position, rotation and visibility */ -internal fun Object3D.updatePosition(obj: VisualObject3D) { +fun Object3D.updatePosition(obj: VisualObject3D) { visible = obj.visible ?: true position.set(obj.x, obj.y, obj.z) setRotationFromEuler(obj.euler) @@ -50,6 +50,9 @@ operator fun ThreeFactory.invoke(obj: Any): Object3D { } } +/** + * Update non-position non-geometry property + */ fun Object3D.updateProperty(source: VisualObject, propertyName: Name) { if (this is Mesh && propertyName.startsWith(MATERIAL_KEY)) { //updated material diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeGeometryBuilder.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeGeometryBuilder.kt index a7a6b606..c45d6caa 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeGeometryBuilder.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeGeometryBuilder.kt @@ -10,6 +10,9 @@ import info.laht.threekt.core.Face3 import info.laht.threekt.core.Geometry import info.laht.threekt.math.Vector3 +/** + * An implementation of geometry builder for Three.js [BufferGeometry] + */ class ThreeGeometryBuilder : GeometryBuilder { private val vertices = ArrayList() diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeLineFactory.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeLineFactory.kt index cb109e8b..f3a46e1b 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeLineFactory.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeLineFactory.kt @@ -9,7 +9,7 @@ import info.laht.threekt.objects.LineSegments import kotlin.reflect.KClass object ThreeLineFactory : ThreeFactory { - override val type: KClass get() = PolyLine::class + override val type: KClass get() = PolyLine::class override fun invoke(obj: PolyLine): Object3D { val geometry = Geometry().apply { diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeOutput.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeOutput.kt index 0952f78e..1dd74ca3 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeOutput.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeOutput.kt @@ -5,11 +5,16 @@ import hep.dataforge.meta.* import hep.dataforge.output.Output import hep.dataforge.vis.common.Colors import hep.dataforge.vis.spatial.VisualObject3D +import hep.dataforge.vis.spatial.World import info.laht.threekt.WebGLRenderer +import info.laht.threekt.cameras.PerspectiveCamera +import info.laht.threekt.external.controls.OrbitControls +import info.laht.threekt.external.controls.TrackballControls import info.laht.threekt.helpers.AxesHelper import info.laht.threekt.lights.AmbientLight import info.laht.threekt.scenes.Scene import org.w3c.dom.HTMLElement +import org.w3c.dom.Node import kotlin.browser.window import kotlin.dom.clear import kotlin.math.max @@ -28,7 +33,28 @@ class ThreeOutput(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Output TrackballControls(camera, element) + else -> OrbitControls(camera, element) + } + } fun attach(element: HTMLElement) { element.clear() @@ -40,7 +66,7 @@ class ThreeOutput(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Output, ThreeFactory<*>>() + private val objectFactories = HashMap, ThreeFactory<*>>() private val compositeFactory = ThreeCompositeFactory(this) private val proxyFactory = ThreeProxyFactory(this) @@ -36,7 +32,7 @@ class ThreePlugin : AbstractPlugin() { objectFactories[PolyLine::class] = ThreeLineFactory } - private fun findObjectFactory(type: KClass): ThreeFactory<*>? { + private fun findObjectFactory(type: KClass): ThreeFactory<*>? { return objectFactories[type] ?: context.content>(ThreeFactory.TYPE).values.find { it.type == type } } @@ -89,27 +85,6 @@ class ThreePlugin : AbstractPlugin() { } } - fun buildCamera(meta: Meta) = PerspectiveCamera( - meta["fov"].int ?: 75, - meta["aspect"].double ?: 1.0, - meta["nearClip"].double ?: World.CAMERA_NEAR_CLIP, - meta["farClip"].double ?: World.CAMERA_FAR_CLIP - ).apply { - position.setZ(World.CAMERA_INITIAL_DISTANCE) - rotation.set( - World.CAMERA_INITIAL_X_ANGLE, - World.CAMERA_INITIAL_Y_ANGLE, - World.CAMERA_INITIAL_Z_ANGLE - ) - } - - fun addControls(camera: Camera, element: Node, meta: Meta) { - when (meta["type"].string) { - "trackball" -> TrackballControls(camera, element) - else -> OrbitControls(camera, element) - } - } - companion object : PluginFactory { override val tag = PluginTag("visual.three", PluginTag.DATAFORGE_GROUP) override val type = ThreePlugin::class From 1d5debb8a6db3b8e7266a40ade469766b41a7c41 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 13 Oct 2019 12:38:24 +0300 Subject: [PATCH 02/25] Tree viewer replacement --- build.gradle.kts | 3 + dataforge-vis-common/build.gradle.kts | 5 +- .../vis/common/MutableVisualGroup.kt | 2 + .../{vis/HMR.kt => js/Application.kt} | 40 ++++-- .../hep/dataforge/{vis => js}/jsExtra.kt | 4 +- .../src/jsMain/resources/css/common.css | 23 +++ .../vis/spatial/gdml/demo/GDMLDemoApp.kt | 18 ++- .../jsMain/web/css/inspire-tree-dark.min.css | 1 - .../jsMain/web/css/inspire-tree-light.min.css | 1 - .../src/jsMain/web/css/main.css | 35 +++++ .../src/jsMain/web/index.html | 11 -- .../dataforge/vis/spatial/editor/jsTree.kt | 75 ++++++++++ .../vis/spatial/editor/jsVisualTree.kt | 136 ------------------ .../vis/spatial/editor/propertyEditor.kt | 4 +- .../vis/spatial/demo/ThreeDemoApp.kt | 10 +- 15 files changed, 183 insertions(+), 185 deletions(-) rename dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/{vis/HMR.kt => js/Application.kt} (63%) rename dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/{vis => js}/jsExtra.kt (88%) create mode 100644 dataforge-vis-common/src/jsMain/resources/css/common.css delete mode 100644 dataforge-vis-spatial-gdml/src/jsMain/web/css/inspire-tree-dark.min.css delete mode 100644 dataforge-vis-spatial-gdml/src/jsMain/web/css/inspire-tree-light.min.css create mode 100644 dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/jsTree.kt delete mode 100644 dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/jsVisualTree.kt diff --git a/build.gradle.kts b/build.gradle.kts index 0822fa2f..73b88aa5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -17,6 +17,9 @@ allprojects { repositories { maven("https://dl.bintray.com/pdvrieze/maven") maven("http://maven.jzy3d.org/releases") + maven("https://kotlin.bintray.com/js-externals") +// maven("https://dl.bintray.com/gbaldeck/kotlin") +// maven("https://dl.bintray.com/rjaros/kotlin") } group = "hep.dataforge" diff --git a/dataforge-vis-common/build.gradle.kts b/dataforge-vis-common/build.gradle.kts index 9306c687..669fd43f 100644 --- a/dataforge-vis-common/build.gradle.kts +++ b/dataforge-vis-common/build.gradle.kts @@ -10,6 +10,7 @@ scientifik{ } val dataforgeVersion: String by rootProject.extra +//val kvisionVersion: String by rootProject.extra("2.0.0-M1") kotlin { jvm{ @@ -31,9 +32,9 @@ kotlin { jsMain{ dependencies { api("hep.dataforge:dataforge-output-html:$dataforgeVersion") + api("kotlin.js.externals:kotlin-js-jquery:3.2.0-0") api(npm("text-encoding")) - api("org.jetbrains:kotlin-extensions:1.0.1-pre.83-kotlin-1.3.50") - api(npm("core-js")) + api(npm("bootstrap","4.3.1")) } } } diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/MutableVisualGroup.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/MutableVisualGroup.kt index e2682817..1c99e6f6 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/MutableVisualGroup.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/MutableVisualGroup.kt @@ -52,6 +52,8 @@ interface VisualGroup : Provider, Iterable, VisualObject { } } +val VisualGroup.isEmpty: Boolean get() = this.children.isEmpty() + interface MutableVisualGroup : VisualGroup { /** diff --git a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/HMR.kt b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/js/Application.kt similarity index 63% rename from dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/HMR.kt rename to dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/js/Application.kt index 5353fb03..53734c31 100644 --- a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/HMR.kt +++ b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/js/Application.kt @@ -1,14 +1,10 @@ -package hep.dataforge.vis +package hep.dataforge.js import kotlin.browser.document import kotlin.dom.hasClass external val module: Module -external interface Module { - val hot: Hot? -} - external interface Hot { val data: dynamic @@ -19,17 +15,31 @@ external interface Hot { fun dispose(callback: (data: dynamic) -> Unit) } -external fun require(name: String): dynamic - -abstract class ApplicationBase { - open val stateKeys: List get() = emptyList() - - abstract fun start(state: Map) - open fun dispose(): Map = emptyMap() +external interface Module { + val hot: Hot? } -fun startApplication(builder: () -> ApplicationBase) { - fun start(state: dynamic): ApplicationBase? { +/** + * Base interface for applications. + * + * Base interface for applications supporting Hot Module Replacement (HMR). + */ +interface Application { + /** + * Starting point for an application. + * @param state Initial state between Hot Module Replacement (HMR). + */ + fun start(state: Map) + + /** + * Ending point for an application. + * @return final state for Hot Module Replacement (HMR). + */ + fun dispose(): Map = emptyMap() +} + +fun startApplication(builder: () -> Application) { + fun start(state: dynamic): Application? { return if (document.body?.hasClass("testApp") == true) { val application = builder() @@ -42,7 +52,7 @@ fun startApplication(builder: () -> ApplicationBase) { } } - var application: ApplicationBase? = null + var application: Application? = null val state: dynamic = module.hot?.let { hot -> hot.accept() diff --git a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/jsExtra.kt b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/js/jsExtra.kt similarity index 88% rename from dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/jsExtra.kt rename to dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/js/jsExtra.kt index 56751272..ad94873d 100644 --- a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/jsExtra.kt +++ b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/js/jsExtra.kt @@ -1,4 +1,6 @@ -package hep.dataforge.vis +package hep.dataforge.js + +external fun require(name: String): dynamic inline fun jsObject(builder: T.() -> Unit): T { val obj: T = js("({})") as T diff --git a/dataforge-vis-common/src/jsMain/resources/css/common.css b/dataforge-vis-common/src/jsMain/resources/css/common.css new file mode 100644 index 00000000..c5efcd40 --- /dev/null +++ b/dataforge-vis-common/src/jsMain/resources/css/common.css @@ -0,0 +1,23 @@ +/* Remove default bullets */ +ul, .objTree-subtree { + list-style-type: none; +} + +/* Style the caret/arrow */ +.objTree-caret { + cursor: pointer; + user-select: none; /* Prevent text selection */ +} + +/* Create the caret/arrow with a unicode, and style it */ +.objTree-caret::before { + content: "\25B6"; + color: black; + display: inline-block; + margin-right: 6px; +} + +/* Rotate the caret/arrow icon when clicked on (using JavaScript) */ +.objTree-caret-down::before { + transform: rotate(90deg); +} diff --git a/dataforge-vis-spatial-gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt b/dataforge-vis-spatial-gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt index cacc796b..0c1da7ed 100644 --- a/dataforge-vis-spatial-gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt +++ b/dataforge-vis-spatial-gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt @@ -1,7 +1,10 @@ package hep.dataforge.vis.spatial.gdml.demo import hep.dataforge.context.Global -import hep.dataforge.vis.ApplicationBase +import hep.dataforge.js.Application +import hep.dataforge.js.objectTree +import hep.dataforge.js.startApplication +import hep.dataforge.names.NameToken import hep.dataforge.vis.spatial.Material3D.Companion.OPACITY_KEY import hep.dataforge.vis.spatial.Visual3DPlugin import hep.dataforge.vis.spatial.VisualGroup3D @@ -9,13 +12,11 @@ import hep.dataforge.vis.spatial.VisualObject3D import hep.dataforge.vis.spatial.attachChildren import hep.dataforge.vis.spatial.editor.propertyEditor import hep.dataforge.vis.spatial.editor.threeOutputConfig -import hep.dataforge.vis.spatial.editor.visualObjectTree import hep.dataforge.vis.spatial.gdml.GDMLTransformer import hep.dataforge.vis.spatial.gdml.LUnit import hep.dataforge.vis.spatial.gdml.toVisual import hep.dataforge.vis.spatial.three.ThreePlugin import hep.dataforge.vis.spatial.three.output -import hep.dataforge.vis.startApplication import kotlinx.html.dom.append import kotlinx.html.js.p import org.w3c.dom.DragEvent @@ -29,7 +30,7 @@ import kotlin.browser.document import kotlin.browser.window import kotlin.dom.clear -private class GDMLDemoApp : ApplicationBase() { +private class GDMLDemoApp : Application { /** * Handle mouse drag according to https://www.html5rocks.com/en/tutorials/file/dndfiles/ */ @@ -46,7 +47,6 @@ private class GDMLDemoApp : ApplicationBase() { event.stopPropagation() event.preventDefault() - val file = (event.dataTransfer?.files as FileList)[0] ?: throw RuntimeException("Failed to load file") @@ -153,7 +153,9 @@ private class GDMLDemoApp : ApplicationBase() { output.camera.layers.set(0) layers.threeOutputConfig(output) - tree.visualObjectTree(visual, editor::propertyEditor) + //tree.visualObjectTree(visual, editor::propertyEditor) + tree.objectTree(NameToken("World"),visual, editor::propertyEditor) + output.render(visual) message(null) @@ -166,10 +168,6 @@ private class GDMLDemoApp : ApplicationBase() { } } - - override fun dispose(): Map { - return super.dispose() - } } fun main() { diff --git a/dataforge-vis-spatial-gdml/src/jsMain/web/css/inspire-tree-dark.min.css b/dataforge-vis-spatial-gdml/src/jsMain/web/css/inspire-tree-dark.min.css deleted file mode 100644 index ab9837b9..00000000 --- a/dataforge-vis-spatial-gdml/src/jsMain/web/css/inspire-tree-dark.min.css +++ /dev/null @@ -1 +0,0 @@ -.inspire-tree .btn{background-color:#fff;border:1px solid rgba(0,0,0,.2);border-radius:3px;display:inline-block;height:20px;transition:all .15s linear;width:20px}.inspire-tree .btn:hover{box-shadow:0 2px 3px rgba(0,0,0,.1)}.inspire-tree .btn+.btn{margin-left:5px}.inspire-tree .btn.icon{position:relative}.inspire-tree .btn.icon:before{display:block;height:14px;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);width:14px}.inspire-tree .btn-group{display:inline-block;height:25px;line-height:25px}.itree-menu{background:#ddd;border:1px solid #c4c4c4;border-radius:3px;font-family:sans-serif;list-style:none;margin:0;min-width:150px;padding:0;position:absolute;z-index:4}.itree-menu a{display:block;padding:3px 8px}.itree-menu a:hover{background:hsla(0,0%,39%,.5);color:rgba(74,110,116,.5)}.inspire-tree{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.inspire-tree:focus{outline:none}.inspire-tree,.inspire-tree *{box-sizing:border-box}.inspire-tree ol{list-style:none;margin:0;padding:0}.inspire-tree ol ol{padding-left:20px}.inspire-tree .collapsed>ol,.inspire-tree .hidden{display:none}.inspire-tree li>.title-wrap{min-height:25px;position:relative;z-index:2}.inspire-tree .toggle{height:25px;left:0;position:absolute;top:0;width:25px;z-index:2}.inspire-tree .toggle:before{display:block;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%)}.inspire-tree [type=checkbox]{left:18px;position:absolute;top:4px;vertical-align:middle;width:20px;z-index:2}.inspire-tree .title{cursor:default;display:block;height:25px;line-height:25px;overflow:hidden;padding-left:42px;position:relative;text-overflow:ellipsis;vertical-align:middle;white-space:nowrap;z-index:1}.inspire-tree .title.load-more{color:#476cb8;cursor:pointer}.inspire-tree .title.load-more:hover{text-decoration:underline}.inspire-tree .title:before{left:24px;position:absolute;top:50%;transform:translateY(-50%);vertical-align:top}.inspire-tree .title:focus{outline:none}.inspire-tree.drag-and-drop li:not(.drop-target){opacity:.5}.drag-targeting.drag-targeting-insert.inspire-tree,.drag-targeting.drag-targeting-insert>.title-wrap>.title{border:1px solid #2dadc5}.drag-targeting.drag-targeting-above>.title-wrap>.title{border-top:3px solid #2dadc5}.drag-targeting.drag-targeting-below>.title-wrap>.title{border-bottom:3px solid #2dadc5}.inspire-tree .editable form{display:inline-block;height:25px;line-height:25px;padding-top:2px}.inspire-tree .editable form input{height:20px}.inspire-tree .editable form .btn,.inspire-tree .editable form input{vertical-align:top}.inspire-tree .editable>.btn-group{display:none;padding-top:2px;position:absolute;right:10px;z-index:3}.inspire-tree .editable:hover>.btn-group{display:block}.inspire-tree input+.btn-group{margin-left:10px}.inspire-tree>.btn.icon{margin-left:2px}.inspire-tree>ol>.folder:first-child:not(:only-child){background-position:11px 13px}.inspire-tree .folder:last-child:not(:only-child),.inspire-tree>ol>.folder:first-child:not(:only-child),.inspire-tree li .folder:last-child{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAMCAYAAACji9dXAAAAFUlEQVQIW2M8d+HSf0YGBgYGRpJZAJ2uFKcp4HfpAAAAAElFTkSuQmCC");background-repeat:no-repeat}.inspire-tree .folder:last-child:not(:only-child),.inspire-tree li .folder:last-child{background-position:11px 0}.inspire-tree.editable-add>ol>.folder:last-child:not(:only-child){background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAYCAYAAAA7zJfaAAAAFUlEQVQIW2M8d+HSf0YGBgYGRrqyABKeKU0SV+t2AAAAAElFTkSuQmCC");background-repeat:repeat-y}.inspire-tree>ol .expanded:not(:last-child):not(:first-child),.inspire-tree li:not(:last-child){background-repeat:no-repeat}.inspire-tree>ol .expanded:not(:last-child):not(:first-child),.inspire-tree li.expanded:not(:last-child)>ol,.inspire-tree li:not(:last-child){background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAYCAYAAAA7zJfaAAAAFUlEQVQIW2M8d+HSf0YGBgYGRrqyABKeKU0SV+t2AAAAAElFTkSuQmCC");background-position:11px 0}.inspire-tree li.expanded:not(:last-child)>ol{background-repeat:repeat-y}.inspire-tree li.expanded.folder:not(.loading)>.title-wrap{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAMCAYAAACji9dXAAAAFUlEQVQIW2M8d+HSf0YGBgYGRpJZAJ2uFKcp4HfpAAAAAElFTkSuQmCC");background-position:31px 13px;background-repeat:no-repeat}.inspire-tree .leaf:not(:last-child):not(.detached){background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAYCAYAAAAh8HdUAAAAN0lEQVQ4T2M8d+HSfyMDPUYGEgBJimHmMo7aBAmK0dCDJgl4ioClDGLo0dBDDz0SMu5o2oMFFgBXbEeI0XwYIwAAAABJRU5ErkJgggAA");background-position:11px 0;background-repeat:no-repeat}.inspire-tree .leaf:last-child{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAANCAYAAABy6+R8AAAAKklEQVQoU2M8d+HSfyMDPUYGEgBJimHmMo7aBAmK0dCDJgl4ioClDGJoAGUZM32Z0U8tAAAAAElFTkSuQmCC");background-position:11px 0;background-repeat:no-repeat}.inspire-tree .leaf.detached:last-child{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAMCAYAAACji9dXAAAAFUlEQVQIW2M8d+HSf0YGBgYGRpJZAJ2uFKcp4HfpAAAAAElFTkSuQmCC");background-position:11px 0;background-repeat:no-repeat}.inspire-tree.editable-add>ol>.leaf:last-child{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAYCAYAAAAh8HdUAAAAN0lEQVQ4T2M8d+HSfyMDPUYGEgBJimHmMo7aBAmK0dCDJgl4ioClDGLo0dBDDz0SMu5o2oMFFgBXbEeI0XwYIwAAAABJRU5ErkJgggAA")}.inspire-tree .icon:before{background-position:0 0;background-repeat:no-repeat;content:"";display:inline-block;height:14px;width:14px}.inspire-tree .icon-check:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%236a6a6a%22%20d%3D%22M27%204l-15%2015-7-7-5%205%2012%2012%2020-20z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E")}.inspire-tree .icon-check:hover:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%230ccc0a%22%20d%3D%22M27%204l-15%2015-7-7-5%205%2012%2012%2020-20z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E")}.inspire-tree .icon-collapse:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20fill%3D%22%23aaa%22%20d%3D%22M4%201h16q1.242%200%202.121%200.879t0.879%202.121v16q0%201.242-0.879%202.121t-2.121%200.879h-16q-1.242%200-2.121-0.879t-0.879-2.121v-16q0-1.242%200.879-2.121t2.121-0.879zM20%203h-16q-0.414%200-0.707%200.293t-0.293%200.707v16q0%200.414%200.293%200.707t0.707%200.293h16q0.414%200%200.707-0.293t0.293-0.707v-16q0-0.414-0.293-0.707t-0.707-0.293zM8%2011h8q0.414%200%200.707%200.293t0.293%200.707-0.293%200.707-0.707%200.293h-8q-0.414%200-0.707-0.293t-0.293-0.707%200.293-0.707%200.707-0.293z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E");background-color:#000;border-radius:3px;margin-left:-1px}.inspire-tree .icon-cross:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%236a6a6a%22%20d%3D%22M31.708%2025.708c-0-0-0-0-0-0l-9.708-9.708%209.708-9.708c0-0%200-0%200-0%200.105-0.105%200.18-0.227%200.229-0.357%200.133-0.356%200.057-0.771-0.229-1.057l-4.586-4.586c-0.286-0.286-0.702-0.361-1.057-0.229-0.13%200.048-0.252%200.124-0.357%200.228%200%200-0%200-0%200l-9.708%209.708-9.708-9.708c-0-0-0-0-0-0-0.105-0.104-0.227-0.18-0.357-0.228-0.356-0.133-0.771-0.057-1.057%200.229l-4.586%204.586c-0.286%200.286-0.361%200.702-0.229%201.057%200.049%200.13%200.124%200.252%200.229%200.357%200%200%200%200%200%200l9.708%209.708-9.708%209.708c-0%200-0%200-0%200-0.104%200.105-0.18%200.227-0.229%200.357-0.133%200.355-0.057%200.771%200.229%201.057l4.586%204.586c0.286%200.286%200.702%200.361%201.057%200.229%200.13-0.049%200.252-0.124%200.357-0.229%200-0%200-0%200-0l9.708-9.708%209.708%209.708c0%200%200%200%200%200%200.105%200.105%200.227%200.18%200.357%200.229%200.356%200.133%200.771%200.057%201.057-0.229l4.586-4.586c0.286-0.286%200.362-0.702%200.229-1.057-0.049-0.13-0.124-0.252-0.229-0.357z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E")}.inspire-tree .icon-cross:hover:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%23c00%22%20d%3D%22M31.708%2025.708c-0-0-0-0-0-0l-9.708-9.708%209.708-9.708c0-0%200-0%200-0%200.105-0.105%200.18-0.227%200.229-0.357%200.133-0.356%200.057-0.771-0.229-1.057l-4.586-4.586c-0.286-0.286-0.702-0.361-1.057-0.229-0.13%200.048-0.252%200.124-0.357%200.228%200%200-0%200-0%200l-9.708%209.708-9.708-9.708c-0-0-0-0-0-0-0.105-0.104-0.227-0.18-0.357-0.228-0.356-0.133-0.771-0.057-1.057%200.229l-4.586%204.586c-0.286%200.286-0.361%200.702-0.229%201.057%200.049%200.13%200.124%200.252%200.229%200.357%200%200%200%200%200%200l9.708%209.708-9.708%209.708c-0%200-0%200-0%200-0.104%200.105-0.18%200.227-0.229%200.357-0.133%200.355-0.057%200.771%200.229%201.057l4.586%204.586c0.286%200.286%200.702%200.361%201.057%200.229%200.13-0.049%200.252-0.124%200.357-0.229%200-0%200-0%200-0l9.708-9.708%209.708%209.708c0%200%200%200%200%200%200.105%200.105%200.227%200.18%200.357%200.229%200.356%200.133%200.771%200.057%201.057-0.229l4.586-4.586c0.286-0.286%200.362-0.702%200.229-1.057-0.049-0.13-0.124-0.252-0.229-0.357z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E")}.inspire-tree .icon-expand:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20fill%3D%22%23aaa%22%20d%3D%22M4%201h16q1.242%200%202.121%200.879t0.879%202.121v16q0%201.242-0.879%202.121t-2.121%200.879h-16q-1.242%200-2.121-0.879t-0.879-2.121v-16q0-1.242%200.879-2.121t2.121-0.879zM20%203h-16q-0.414%200-0.707%200.293t-0.293%200.707v16q0%200.414%200.293%200.707t0.707%200.293h16q0.414%200%200.707-0.293t0.293-0.707v-16q0-0.414-0.293-0.707t-0.707-0.293zM12%207q0.414%200%200.707%200.293t0.293%200.707v3h3q0.414%200%200.707%200.293t0.293%200.707-0.293%200.707-0.707%200.293h-3v3q0%200.414-0.293%200.707t-0.707%200.293-0.707-0.293-0.293-0.707v-3h-3q-0.414%200-0.707-0.293t-0.293-0.707%200.293-0.707%200.707-0.293h3v-3q0-0.414%200.293-0.707t0.707-0.293z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E");background-color:#000;border-radius:3px;margin-left:-1px}.inspire-tree .icon-file-empty:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%23a5a5a5%22%20d%3D%22M28.681%207.159c-0.694-0.947-1.662-2.053-2.724-3.116s-2.169-2.030-3.116-2.724c-1.612-1.182-2.393-1.319-2.841-1.319h-15.5c-1.378%200-2.5%201.121-2.5%202.5v27c0%201.378%201.122%202.5%202.5%202.5h23c1.378%200%202.5-1.122%202.5-2.5v-19.5c0-0.448-0.137-1.23-1.319-2.841zM24.543%205.457c0.959%200.959%201.712%201.825%202.268%202.543h-4.811v-4.811c0.718%200.556%201.584%201.309%202.543%202.268zM28%2029.5c0%200.271-0.229%200.5-0.5%200.5h-23c-0.271%200-0.5-0.229-0.5-0.5v-27c0-0.271%200.229-0.5%200.5-0.5%200%200%2015.499-0%2015.5%200v7c0%200.552%200.448%201%201%201h7v19.5z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E")}.inspire-tree .icon-folder:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%236a6a6a%22%20d%3D%22M14%204l4%204h14v22h-32v-26z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E")}.inspire-tree .icon-folder-open:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%236a6a6a%22%20d%3D%22M26%2030l6-16h-26l-6%2016zM4%2012l-4%2018v-26h9l4%204h13v4z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E%0A")}.inspire-tree .icon-minus:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%236a6a6a%22%20d%3D%22M0%2013v6c0%200.552%200.448%201%201%201h30c0.552%200%201-0.448%201-1v-6c0-0.552-0.448-1-1-1h-30c-0.552%200-1%200.448-1%201z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E")}.inspire-tree .icon-minus:hover:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%23c00%22%20d%3D%22M0%2013v6c0%200.552%200.448%201%201%201h30c0.552%200%201-0.448%201-1v-6c0-0.552-0.448-1-1-1h-30c-0.552%200-1%200.448-1%201z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E")}.inspire-tree .icon-more:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20fill%3D%22%236a6a6a%22%20d%3D%22M12%209.984c1.078%200%202.016%200.938%202.016%202.016s-0.938%202.016-2.016%202.016-2.016-0.938-2.016-2.016%200.938-2.016%202.016-2.016zM18%209.984c1.078%200%202.016%200.938%202.016%202.016s-0.938%202.016-2.016%202.016-2.016-0.938-2.016-2.016%200.938-2.016%202.016-2.016zM6%209.984c1.078%200%202.016%200.938%202.016%202.016s-0.938%202.016-2.016%202.016-2.016-0.938-2.016-2.016%200.938-2.016%202.016-2.016z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E")}.inspire-tree .icon-pencil:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%236a6a6a%22%20d%3D%22M27%200c2.761%200%205%202.239%205%205%200%201.126-0.372%202.164-1%203l-2%202-7-7%202-2c0.836-0.628%201.874-1%203-1zM2%2023l-2%209%209-2%2018.5-18.5-7-7-18.5%2018.5zM22.362%2011.362l-14%2014-1.724-1.724%2014-14%201.724%201.724z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E%0A")}.inspire-tree .icon-pencil:hover:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%230ccc0a%22%20d%3D%22M27%200c2.761%200%205%202.239%205%205%200%201.126-0.372%202.164-1%203l-2%202-7-7%202-2c0.836-0.628%201.874-1%203-1zM2%2023l-2%209%209-2%2018.5-18.5-7-7-18.5%2018.5zM22.362%2011.362l-14%2014-1.724-1.724%2014-14%201.724%201.724z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E%0A")}.inspire-tree .icon-plus:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%236a6a6a%22%20d%3D%22M31%2012h-11v-11c0-0.552-0.448-1-1-1h-6c-0.552%200-1%200.448-1%201v11h-11c-0.552%200-1%200.448-1%201v6c0%200.552%200.448%201%201%201h11v11c0%200.552%200.448%201%201%201h6c0.552%200%201-0.448%201-1v-11h11c0.552%200%201-0.448%201-1v-6c0-0.552-0.448-1-1-1z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E")}.inspire-tree .icon-plus:hover:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%230ccc0a%22%20d%3D%22M31%2012h-11v-11c0-0.552-0.448-1-1-1h-6c-0.552%200-1%200.448-1%201v11h-11c-0.552%200-1%200.448-1%201v6c0%200.552%200.448%201%201%201h11v11c0%200.552%200.448%201%201%201h6c0.552%200%201-0.448%201-1v-11h11c0.552%200%201-0.448%201-1v-6c0-0.552-0.448-1-1-1z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E")}.inspire-tree .selected>.title-wrap .icon-folder:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%2366a0a9%22%20d%3D%22M14%204l4%204h14v22h-32v-26z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E")}.inspire-tree .selected>.title-wrap .icon-folder-open:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%2366a0a9%22%20d%3D%22M26%2030l6-16h-26l-6%2016zM4%2012l-4%2018v-26h9l4%204h13v4z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E%0A")}.inspire-tree .selected>.title-wrap .icon-file-empty:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%2366a0a9%22%20d%3D%22M28.681%207.159c-0.694-0.947-1.662-2.053-2.724-3.116s-2.169-2.030-3.116-2.724c-1.612-1.182-2.393-1.319-2.841-1.319h-15.5c-1.378%200-2.5%201.121-2.5%202.5v27c0%201.378%201.122%202.5%202.5%202.5h23c1.378%200%202.5-1.122%202.5-2.5v-19.5c0-0.448-0.137-1.23-1.319-2.841zM24.543%205.457c0.959%200.959%201.712%201.825%202.268%202.543h-4.811v-4.811c0.718%200.556%201.584%201.309%202.543%202.268zM28%2029.5c0%200.271-0.229%200.5-0.5%200.5h-23c-0.271%200-0.5-0.229-0.5-0.5v-27c0-0.271%200.229-0.5%200.5-0.5%200%200%2015.499-0%2015.5%200v7c0%200.552%200.448%201%201%201h7v19.5z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E")}.inspire-tree .loading>.title-wrap input{display:none}.inspire-tree .loading>.title-wrap .title:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2714px%27%20height%3D%2714px%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20100%20100%22%20preserveAspectRatio%3D%22xMidYMid%22%20class%3D%22uil-ring%22%3E%3Crect%20x%3D%220%22%20y%3D%220%22%20width%3D%22100%22%20height%3D%22100%22%20fill%3D%22none%22%20class%3D%22bk%22%3E%3C%2Frect%3E%3Cdefs%3E%3Cfilter%20id%3D%22uil-ring-shadow%22%20x%3D%22-100%25%22%20y%3D%22-100%25%22%20width%3D%22300%25%22%20height%3D%22300%25%22%3E%3CfeOffset%20result%3D%22offOut%22%20in%3D%22SourceGraphic%22%20dx%3D%220%22%20dy%3D%220%22%3E%3C%2FfeOffset%3E%3CfeGaussianBlur%20result%3D%22blurOut%22%20in%3D%22offOut%22%20stdDeviation%3D%220%22%3E%3C%2FfeGaussianBlur%3E%3CfeBlend%20in%3D%22SourceGraphic%22%20in2%3D%22blurOut%22%20mode%3D%22normal%22%3E%3C%2FfeBlend%3E%3C%2Ffilter%3E%3C%2Fdefs%3E%3Cpath%20d%3D%22M10%2C50c0%2C0%2C0%2C0.5%2C0.1%2C1.4c0%2C0.5%2C0.1%2C1%2C0.2%2C1.7c0%2C0.3%2C0.1%2C0.7%2C0.1%2C1.1c0.1%2C0.4%2C0.1%2C0.8%2C0.2%2C1.2c0.2%2C0.8%2C0.3%2C1.8%2C0.5%2C2.8%20c0.3%2C1%2C0.6%2C2.1%2C0.9%2C3.2c0.3%2C1.1%2C0.9%2C2.3%2C1.4%2C3.5c0.5%2C1.2%2C1.2%2C2.4%2C1.8%2C3.7c0.3%2C0.6%2C0.8%2C1.2%2C1.2%2C1.9c0.4%2C0.6%2C0.8%2C1.3%2C1.3%2C1.9%20c1%2C1.2%2C1.9%2C2.6%2C3.1%2C3.7c2.2%2C2.5%2C5%2C4.7%2C7.9%2C6.7c3%2C2%2C6.5%2C3.4%2C10.1%2C4.6c3.6%2C1.1%2C7.5%2C1.5%2C11.2%2C1.6c4-0.1%2C7.7-0.6%2C11.3-1.6%20c3.6-1.2%2C7-2.6%2C10-4.6c3-2%2C5.8-4.2%2C7.9-6.7c1.2-1.2%2C2.1-2.5%2C3.1-3.7c0.5-0.6%2C0.9-1.3%2C1.3-1.9c0.4-0.6%2C0.8-1.3%2C1.2-1.9%20c0.6-1.3%2C1.3-2.5%2C1.8-3.7c0.5-1.2%2C1-2.4%2C1.4-3.5c0.3-1.1%2C0.6-2.2%2C0.9-3.2c0.2-1%2C0.4-1.9%2C0.5-2.8c0.1-0.4%2C0.1-0.8%2C0.2-1.2%20c0-0.4%2C0.1-0.7%2C0.1-1.1c0.1-0.7%2C0.1-1.2%2C0.2-1.7C90%2C50.5%2C90%2C50%2C90%2C50s0%2C0.5%2C0%2C1.4c0%2C0.5%2C0%2C1%2C0%2C1.7c0%2C0.3%2C0%2C0.7%2C0%2C1.1%20c0%2C0.4-0.1%2C0.8-0.1%2C1.2c-0.1%2C0.9-0.2%2C1.8-0.4%2C2.8c-0.2%2C1-0.5%2C2.1-0.7%2C3.3c-0.3%2C1.2-0.8%2C2.4-1.2%2C3.7c-0.2%2C0.7-0.5%2C1.3-0.8%2C1.9%20c-0.3%2C0.7-0.6%2C1.3-0.9%2C2c-0.3%2C0.7-0.7%2C1.3-1.1%2C2c-0.4%2C0.7-0.7%2C1.4-1.2%2C2c-1%2C1.3-1.9%2C2.7-3.1%2C4c-2.2%2C2.7-5%2C5-8.1%2C7.1%20c-0.8%2C0.5-1.6%2C1-2.4%2C1.5c-0.8%2C0.5-1.7%2C0.9-2.6%2C1.3L66%2C87.7l-1.4%2C0.5c-0.9%2C0.3-1.8%2C0.7-2.8%2C1c-3.8%2C1.1-7.9%2C1.7-11.8%2C1.8L47%2C90.8%20c-1%2C0-2-0.2-3-0.3l-1.5-0.2l-0.7-0.1L41.1%2C90c-1-0.3-1.9-0.5-2.9-0.7c-0.9-0.3-1.9-0.7-2.8-1L34%2C87.7l-1.3-0.6%20c-0.9-0.4-1.8-0.8-2.6-1.3c-0.8-0.5-1.6-1-2.4-1.5c-3.1-2.1-5.9-4.5-8.1-7.1c-1.2-1.2-2.1-2.7-3.1-4c-0.5-0.6-0.8-1.4-1.2-2%20c-0.4-0.7-0.8-1.3-1.1-2c-0.3-0.7-0.6-1.3-0.9-2c-0.3-0.7-0.6-1.3-0.8-1.9c-0.4-1.3-0.9-2.5-1.2-3.7c-0.3-1.2-0.5-2.3-0.7-3.3%20c-0.2-1-0.3-2-0.4-2.8c-0.1-0.4-0.1-0.8-0.1-1.2c0-0.4%2C0-0.7%2C0-1.1c0-0.7%2C0-1.2%2C0-1.7C10%2C50.5%2C10%2C50%2C10%2C50z%22%20fill%3D%22%23013138%22%20filter%3D%22url(%23uil-ring-shadow)%22%3E%3CanimateTransform%20attributeName%3D%22transform%22%20type%3D%22rotate%22%20from%3D%220%2050%2050%22%20to%3D%22360%2050%2050%22%20repeatCount%3D%22indefinite%22%20dur%3D%221s%22%3E%3C%2FanimateTransform%3E%3C%2Fpath%3E%3C%2Fsvg%3E");content:"";height:14px;width:14px}.inspire-tree>ol{position:relative}.inspire-tree .wholerow{height:25px;left:0;margin-top:-25px;position:absolute;width:100%;z-index:1}.inspire-tree .focused>.wholerow{border:1px dotted #fff}.inspire-tree .title-wrap:hover+.wholerow,.inspire-tree .wholerow:hover{background-color:hsla(0,0%,39%,.5)}.inspire-tree .selected>.title-wrap:hover+.wholerow,.inspire-tree .selected>.wholerow,.inspire-tree .selected>.wholerow:hover{background-color:rgba(74,110,116,.5)}.inspire-tree .matched>.title-wrap:hover+.wholerow,.inspire-tree .matched>.wholerow,.inspire-tree .matched>.wholerow:hover{background-color:rgba(247,255,170,.5)} \ No newline at end of file diff --git a/dataforge-vis-spatial-gdml/src/jsMain/web/css/inspire-tree-light.min.css b/dataforge-vis-spatial-gdml/src/jsMain/web/css/inspire-tree-light.min.css deleted file mode 100644 index 2b6d5f51..00000000 --- a/dataforge-vis-spatial-gdml/src/jsMain/web/css/inspire-tree-light.min.css +++ /dev/null @@ -1 +0,0 @@ -.inspire-tree .btn{background-color:hsla(0,0%,100%,.4);border:1px solid rgba(0,0,0,.2);border-radius:3px;display:inline-block;height:20px;transition:all .15s linear;width:20px}.inspire-tree .btn:hover{box-shadow:0 2px 3px rgba(0,0,0,.1)}.inspire-tree .btn+.btn{margin-left:5px}.inspire-tree .btn.icon{position:relative}.inspire-tree .btn.icon:before{display:block;height:14px;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);width:14px}.inspire-tree .btn-group{display:inline-block;height:25px;line-height:25px}.itree-menu{background:#ddd;border:1px solid #c4c4c4;border-radius:3px;font-family:sans-serif;list-style:none;margin:0;min-width:150px;padding:0;position:absolute;z-index:4}.itree-menu a{display:block;padding:3px 8px}.itree-menu a:hover{background:rgba(218,250,255,.5);color:rgba(164,234,245,.5)}.inspire-tree{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.inspire-tree:focus{outline:none}.inspire-tree,.inspire-tree *{box-sizing:border-box}.inspire-tree ol{list-style:none;margin:0;padding:0}.inspire-tree ol ol{padding-left:20px}.inspire-tree .collapsed>ol,.inspire-tree .hidden{display:none}.inspire-tree li>.title-wrap{min-height:25px;position:relative;z-index:2}.inspire-tree .toggle{height:25px;left:0;position:absolute;top:0;width:25px;z-index:2}.inspire-tree .toggle:before{display:block;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%)}.inspire-tree [type=checkbox]{left:18px;position:absolute;top:4px;vertical-align:middle;width:20px;z-index:2}.inspire-tree .title{cursor:default;display:block;height:25px;line-height:25px;overflow:hidden;padding-left:42px;position:relative;text-overflow:ellipsis;vertical-align:middle;white-space:nowrap;z-index:1}.inspire-tree .title.load-more{color:#476cb8;cursor:pointer}.inspire-tree .title.load-more:hover{text-decoration:underline}.inspire-tree .title:before{left:24px;position:absolute;top:50%;transform:translateY(-50%);vertical-align:top}.inspire-tree .title:focus{outline:none}.inspire-tree.drag-and-drop li:not(.drop-target){opacity:.5}.drag-targeting.drag-targeting-insert.inspire-tree,.drag-targeting.drag-targeting-insert>.title-wrap>.title{border:1px solid #2dadc5}.drag-targeting.drag-targeting-above>.title-wrap>.title{border-top:3px solid #2dadc5}.drag-targeting.drag-targeting-below>.title-wrap>.title{border-bottom:3px solid #2dadc5}.inspire-tree .editable form{display:inline-block;height:25px;line-height:25px;padding-top:2px}.inspire-tree .editable form input{height:20px}.inspire-tree .editable form .btn,.inspire-tree .editable form input{vertical-align:top}.inspire-tree .editable>.btn-group{display:none;padding-top:2px;position:absolute;right:10px;z-index:3}.inspire-tree .editable:hover>.btn-group{display:block}.inspire-tree input+.btn-group{margin-left:10px}.inspire-tree>.btn.icon{margin-left:2px}.inspire-tree>ol>.folder:first-child:not(:only-child){background-position:11px 13px}.inspire-tree .folder:last-child:not(:only-child),.inspire-tree>ol>.folder:first-child:not(:only-child),.inspire-tree li .folder:last-child{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAMCAYAAACji9dXAAAAFUlEQVQIW2M8d+HSf0YGBgYGRpJZAJ2uFKcp4HfpAAAAAElFTkSuQmCC");background-repeat:no-repeat}.inspire-tree .folder:last-child:not(:only-child),.inspire-tree li .folder:last-child{background-position:11px 0}.inspire-tree.editable-add>ol>.folder:last-child:not(:only-child){background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAYCAYAAAA7zJfaAAAAFUlEQVQIW2M8d+HSf0YGBgYGRrqyABKeKU0SV+t2AAAAAElFTkSuQmCC");background-repeat:repeat-y}.inspire-tree>ol .expanded:not(:last-child):not(:first-child),.inspire-tree li:not(:last-child){background-repeat:no-repeat}.inspire-tree>ol .expanded:not(:last-child):not(:first-child),.inspire-tree li.expanded:not(:last-child)>ol,.inspire-tree li:not(:last-child){background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAYCAYAAAA7zJfaAAAAFUlEQVQIW2M8d+HSf0YGBgYGRrqyABKeKU0SV+t2AAAAAElFTkSuQmCC");background-position:11px 0}.inspire-tree li.expanded:not(:last-child)>ol{background-repeat:repeat-y}.inspire-tree li.expanded.folder:not(.loading)>.title-wrap{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAMCAYAAACji9dXAAAAFUlEQVQIW2M8d+HSf0YGBgYGRpJZAJ2uFKcp4HfpAAAAAElFTkSuQmCC");background-position:31px 13px;background-repeat:no-repeat}.inspire-tree .leaf:not(:last-child):not(.detached){background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAYCAYAAAAh8HdUAAAAN0lEQVQ4T2M8d+HSfyMDPUYGEgBJimHmMo7aBAmK0dCDJgl4ioClDGLo0dBDDz0SMu5o2oMFFgBXbEeI0XwYIwAAAABJRU5ErkJgggAA");background-position:11px 0;background-repeat:no-repeat}.inspire-tree .leaf:last-child{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAANCAYAAABy6+R8AAAAKklEQVQoU2M8d+HSfyMDPUYGEgBJimHmMo7aBAmK0dCDJgl4ioClDGJoAGUZM32Z0U8tAAAAAElFTkSuQmCC");background-position:11px 0;background-repeat:no-repeat}.inspire-tree .leaf.detached:last-child{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAMCAYAAACji9dXAAAAFUlEQVQIW2M8d+HSf0YGBgYGRpJZAJ2uFKcp4HfpAAAAAElFTkSuQmCC");background-position:11px 0;background-repeat:no-repeat}.inspire-tree.editable-add>ol>.leaf:last-child{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAYCAYAAAAh8HdUAAAAN0lEQVQ4T2M8d+HSfyMDPUYGEgBJimHmMo7aBAmK0dCDJgl4ioClDGLo0dBDDz0SMu5o2oMFFgBXbEeI0XwYIwAAAABJRU5ErkJgggAA")}.inspire-tree .icon:before{background-position:0 0;background-repeat:no-repeat;content:"";display:inline-block;height:14px;width:14px}.inspire-tree .icon-check:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%236a6a6a%22%20d%3D%22M27%204l-15%2015-7-7-5%205%2012%2012%2020-20z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E")}.inspire-tree .icon-check:hover:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%230ccc0a%22%20d%3D%22M27%204l-15%2015-7-7-5%205%2012%2012%2020-20z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E")}.inspire-tree .icon-collapse:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20fill%3D%22%23aaa%22%20d%3D%22M4%201h16q1.242%200%202.121%200.879t0.879%202.121v16q0%201.242-0.879%202.121t-2.121%200.879h-16q-1.242%200-2.121-0.879t-0.879-2.121v-16q0-1.242%200.879-2.121t2.121-0.879zM20%203h-16q-0.414%200-0.707%200.293t-0.293%200.707v16q0%200.414%200.293%200.707t0.707%200.293h16q0.414%200%200.707-0.293t0.293-0.707v-16q0-0.414-0.293-0.707t-0.707-0.293zM8%2011h8q0.414%200%200.707%200.293t0.293%200.707-0.293%200.707-0.707%200.293h-8q-0.414%200-0.707-0.293t-0.293-0.707%200.293-0.707%200.707-0.293z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E");background-color:#fff;border-radius:3px;margin-left:-1px}.inspire-tree .icon-cross:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%236a6a6a%22%20d%3D%22M31.708%2025.708c-0-0-0-0-0-0l-9.708-9.708%209.708-9.708c0-0%200-0%200-0%200.105-0.105%200.18-0.227%200.229-0.357%200.133-0.356%200.057-0.771-0.229-1.057l-4.586-4.586c-0.286-0.286-0.702-0.361-1.057-0.229-0.13%200.048-0.252%200.124-0.357%200.228%200%200-0%200-0%200l-9.708%209.708-9.708-9.708c-0-0-0-0-0-0-0.105-0.104-0.227-0.18-0.357-0.228-0.356-0.133-0.771-0.057-1.057%200.229l-4.586%204.586c-0.286%200.286-0.361%200.702-0.229%201.057%200.049%200.13%200.124%200.252%200.229%200.357%200%200%200%200%200%200l9.708%209.708-9.708%209.708c-0%200-0%200-0%200-0.104%200.105-0.18%200.227-0.229%200.357-0.133%200.355-0.057%200.771%200.229%201.057l4.586%204.586c0.286%200.286%200.702%200.361%201.057%200.229%200.13-0.049%200.252-0.124%200.357-0.229%200-0%200-0%200-0l9.708-9.708%209.708%209.708c0%200%200%200%200%200%200.105%200.105%200.227%200.18%200.357%200.229%200.356%200.133%200.771%200.057%201.057-0.229l4.586-4.586c0.286-0.286%200.362-0.702%200.229-1.057-0.049-0.13-0.124-0.252-0.229-0.357z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E")}.inspire-tree .icon-cross:hover:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%23c00%22%20d%3D%22M31.708%2025.708c-0-0-0-0-0-0l-9.708-9.708%209.708-9.708c0-0%200-0%200-0%200.105-0.105%200.18-0.227%200.229-0.357%200.133-0.356%200.057-0.771-0.229-1.057l-4.586-4.586c-0.286-0.286-0.702-0.361-1.057-0.229-0.13%200.048-0.252%200.124-0.357%200.228%200%200-0%200-0%200l-9.708%209.708-9.708-9.708c-0-0-0-0-0-0-0.105-0.104-0.227-0.18-0.357-0.228-0.356-0.133-0.771-0.057-1.057%200.229l-4.586%204.586c-0.286%200.286-0.361%200.702-0.229%201.057%200.049%200.13%200.124%200.252%200.229%200.357%200%200%200%200%200%200l9.708%209.708-9.708%209.708c-0%200-0%200-0%200-0.104%200.105-0.18%200.227-0.229%200.357-0.133%200.355-0.057%200.771%200.229%201.057l4.586%204.586c0.286%200.286%200.702%200.361%201.057%200.229%200.13-0.049%200.252-0.124%200.357-0.229%200-0%200-0%200-0l9.708-9.708%209.708%209.708c0%200%200%200%200%200%200.105%200.105%200.227%200.18%200.357%200.229%200.356%200.133%200.771%200.057%201.057-0.229l4.586-4.586c0.286-0.286%200.362-0.702%200.229-1.057-0.049-0.13-0.124-0.252-0.229-0.357z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E")}.inspire-tree .icon-expand:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20fill%3D%22%23aaa%22%20d%3D%22M4%201h16q1.242%200%202.121%200.879t0.879%202.121v16q0%201.242-0.879%202.121t-2.121%200.879h-16q-1.242%200-2.121-0.879t-0.879-2.121v-16q0-1.242%200.879-2.121t2.121-0.879zM20%203h-16q-0.414%200-0.707%200.293t-0.293%200.707v16q0%200.414%200.293%200.707t0.707%200.293h16q0.414%200%200.707-0.293t0.293-0.707v-16q0-0.414-0.293-0.707t-0.707-0.293zM12%207q0.414%200%200.707%200.293t0.293%200.707v3h3q0.414%200%200.707%200.293t0.293%200.707-0.293%200.707-0.707%200.293h-3v3q0%200.414-0.293%200.707t-0.707%200.293-0.707-0.293-0.293-0.707v-3h-3q-0.414%200-0.707-0.293t-0.293-0.707%200.293-0.707%200.707-0.293h3v-3q0-0.414%200.293-0.707t0.707-0.293z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E");background-color:#fff;border-radius:3px;margin-left:-1px}.inspire-tree .icon-file-empty:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%23a5a5a5%22%20d%3D%22M28.681%207.159c-0.694-0.947-1.662-2.053-2.724-3.116s-2.169-2.030-3.116-2.724c-1.612-1.182-2.393-1.319-2.841-1.319h-15.5c-1.378%200-2.5%201.121-2.5%202.5v27c0%201.378%201.122%202.5%202.5%202.5h23c1.378%200%202.5-1.122%202.5-2.5v-19.5c0-0.448-0.137-1.23-1.319-2.841zM24.543%205.457c0.959%200.959%201.712%201.825%202.268%202.543h-4.811v-4.811c0.718%200.556%201.584%201.309%202.543%202.268zM28%2029.5c0%200.271-0.229%200.5-0.5%200.5h-23c-0.271%200-0.5-0.229-0.5-0.5v-27c0-0.271%200.229-0.5%200.5-0.5%200%200%2015.499-0%2015.5%200v7c0%200.552%200.448%201%201%201h7v19.5z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E")}.inspire-tree .icon-folder:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%236a6a6a%22%20d%3D%22M14%204l4%204h14v22h-32v-26z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E")}.inspire-tree .icon-folder-open:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%236a6a6a%22%20d%3D%22M26%2030l6-16h-26l-6%2016zM4%2012l-4%2018v-26h9l4%204h13v4z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E%0A")}.inspire-tree .icon-minus:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%236a6a6a%22%20d%3D%22M0%2013v6c0%200.552%200.448%201%201%201h30c0.552%200%201-0.448%201-1v-6c0-0.552-0.448-1-1-1h-30c-0.552%200-1%200.448-1%201z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E")}.inspire-tree .icon-minus:hover:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%23c00%22%20d%3D%22M0%2013v6c0%200.552%200.448%201%201%201h30c0.552%200%201-0.448%201-1v-6c0-0.552-0.448-1-1-1h-30c-0.552%200-1%200.448-1%201z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E")}.inspire-tree .icon-more:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20fill%3D%22%236a6a6a%22%20d%3D%22M12%209.984c1.078%200%202.016%200.938%202.016%202.016s-0.938%202.016-2.016%202.016-2.016-0.938-2.016-2.016%200.938-2.016%202.016-2.016zM18%209.984c1.078%200%202.016%200.938%202.016%202.016s-0.938%202.016-2.016%202.016-2.016-0.938-2.016-2.016%200.938-2.016%202.016-2.016zM6%209.984c1.078%200%202.016%200.938%202.016%202.016s-0.938%202.016-2.016%202.016-2.016-0.938-2.016-2.016%200.938-2.016%202.016-2.016z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E")}.inspire-tree .icon-pencil:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%236a6a6a%22%20d%3D%22M27%200c2.761%200%205%202.239%205%205%200%201.126-0.372%202.164-1%203l-2%202-7-7%202-2c0.836-0.628%201.874-1%203-1zM2%2023l-2%209%209-2%2018.5-18.5-7-7-18.5%2018.5zM22.362%2011.362l-14%2014-1.724-1.724%2014-14%201.724%201.724z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E%0A")}.inspire-tree .icon-pencil:hover:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%230ccc0a%22%20d%3D%22M27%200c2.761%200%205%202.239%205%205%200%201.126-0.372%202.164-1%203l-2%202-7-7%202-2c0.836-0.628%201.874-1%203-1zM2%2023l-2%209%209-2%2018.5-18.5-7-7-18.5%2018.5zM22.362%2011.362l-14%2014-1.724-1.724%2014-14%201.724%201.724z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E%0A")}.inspire-tree .icon-plus:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%236a6a6a%22%20d%3D%22M31%2012h-11v-11c0-0.552-0.448-1-1-1h-6c-0.552%200-1%200.448-1%201v11h-11c-0.552%200-1%200.448-1%201v6c0%200.552%200.448%201%201%201h11v11c0%200.552%200.448%201%201%201h6c0.552%200%201-0.448%201-1v-11h11c0.552%200%201-0.448%201-1v-6c0-0.552-0.448-1-1-1z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E")}.inspire-tree .icon-plus:hover:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%230ccc0a%22%20d%3D%22M31%2012h-11v-11c0-0.552-0.448-1-1-1h-6c-0.552%200-1%200.448-1%201v11h-11c-0.552%200-1%200.448-1%201v6c0%200.552%200.448%201%201%201h11v11c0%200.552%200.448%201%201%201h6c0.552%200%201-0.448%201-1v-11h11c0.552%200%201-0.448%201-1v-6c0-0.552-0.448-1-1-1z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E")}.inspire-tree .selected>.title-wrap .icon-folder:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%23179bb9%22%20d%3D%22M14%204l4%204h14v22h-32v-26z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E")}.inspire-tree .selected>.title-wrap .icon-folder-open:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%23179bb9%22%20d%3D%22M26%2030l6-16h-26l-6%2016zM4%2012l-4%2018v-26h9l4%204h13v4z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E%0A")}.inspire-tree .selected>.title-wrap .icon-file-empty:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%23179bb9%22%20d%3D%22M28.681%207.159c-0.694-0.947-1.662-2.053-2.724-3.116s-2.169-2.030-3.116-2.724c-1.612-1.182-2.393-1.319-2.841-1.319h-15.5c-1.378%200-2.5%201.121-2.5%202.5v27c0%201.378%201.122%202.5%202.5%202.5h23c1.378%200%202.5-1.122%202.5-2.5v-19.5c0-0.448-0.137-1.23-1.319-2.841zM24.543%205.457c0.959%200.959%201.712%201.825%202.268%202.543h-4.811v-4.811c0.718%200.556%201.584%201.309%202.543%202.268zM28%2029.5c0%200.271-0.229%200.5-0.5%200.5h-23c-0.271%200-0.5-0.229-0.5-0.5v-27c0-0.271%200.229-0.5%200.5-0.5%200%200%2015.499-0%2015.5%200v7c0%200.552%200.448%201%201%201h7v19.5z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E")}.inspire-tree .loading>.title-wrap input{display:none}.inspire-tree .loading>.title-wrap .title:before{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2714px%27%20height%3D%2714px%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20100%20100%22%20preserveAspectRatio%3D%22xMidYMid%22%20class%3D%22uil-ring%22%3E%3Crect%20x%3D%220%22%20y%3D%220%22%20width%3D%22100%22%20height%3D%22100%22%20fill%3D%22none%22%20class%3D%22bk%22%3E%3C%2Frect%3E%3Cdefs%3E%3Cfilter%20id%3D%22uil-ring-shadow%22%20x%3D%22-100%25%22%20y%3D%22-100%25%22%20width%3D%22300%25%22%20height%3D%22300%25%22%3E%3CfeOffset%20result%3D%22offOut%22%20in%3D%22SourceGraphic%22%20dx%3D%220%22%20dy%3D%220%22%3E%3C%2FfeOffset%3E%3CfeGaussianBlur%20result%3D%22blurOut%22%20in%3D%22offOut%22%20stdDeviation%3D%220%22%3E%3C%2FfeGaussianBlur%3E%3CfeBlend%20in%3D%22SourceGraphic%22%20in2%3D%22blurOut%22%20mode%3D%22normal%22%3E%3C%2FfeBlend%3E%3C%2Ffilter%3E%3C%2Fdefs%3E%3Cpath%20d%3D%22M10%2C50c0%2C0%2C0%2C0.5%2C0.1%2C1.4c0%2C0.5%2C0.1%2C1%2C0.2%2C1.7c0%2C0.3%2C0.1%2C0.7%2C0.1%2C1.1c0.1%2C0.4%2C0.1%2C0.8%2C0.2%2C1.2c0.2%2C0.8%2C0.3%2C1.8%2C0.5%2C2.8%20c0.3%2C1%2C0.6%2C2.1%2C0.9%2C3.2c0.3%2C1.1%2C0.9%2C2.3%2C1.4%2C3.5c0.5%2C1.2%2C1.2%2C2.4%2C1.8%2C3.7c0.3%2C0.6%2C0.8%2C1.2%2C1.2%2C1.9c0.4%2C0.6%2C0.8%2C1.3%2C1.3%2C1.9%20c1%2C1.2%2C1.9%2C2.6%2C3.1%2C3.7c2.2%2C2.5%2C5%2C4.7%2C7.9%2C6.7c3%2C2%2C6.5%2C3.4%2C10.1%2C4.6c3.6%2C1.1%2C7.5%2C1.5%2C11.2%2C1.6c4-0.1%2C7.7-0.6%2C11.3-1.6%20c3.6-1.2%2C7-2.6%2C10-4.6c3-2%2C5.8-4.2%2C7.9-6.7c1.2-1.2%2C2.1-2.5%2C3.1-3.7c0.5-0.6%2C0.9-1.3%2C1.3-1.9c0.4-0.6%2C0.8-1.3%2C1.2-1.9%20c0.6-1.3%2C1.3-2.5%2C1.8-3.7c0.5-1.2%2C1-2.4%2C1.4-3.5c0.3-1.1%2C0.6-2.2%2C0.9-3.2c0.2-1%2C0.4-1.9%2C0.5-2.8c0.1-0.4%2C0.1-0.8%2C0.2-1.2%20c0-0.4%2C0.1-0.7%2C0.1-1.1c0.1-0.7%2C0.1-1.2%2C0.2-1.7C90%2C50.5%2C90%2C50%2C90%2C50s0%2C0.5%2C0%2C1.4c0%2C0.5%2C0%2C1%2C0%2C1.7c0%2C0.3%2C0%2C0.7%2C0%2C1.1%20c0%2C0.4-0.1%2C0.8-0.1%2C1.2c-0.1%2C0.9-0.2%2C1.8-0.4%2C2.8c-0.2%2C1-0.5%2C2.1-0.7%2C3.3c-0.3%2C1.2-0.8%2C2.4-1.2%2C3.7c-0.2%2C0.7-0.5%2C1.3-0.8%2C1.9%20c-0.3%2C0.7-0.6%2C1.3-0.9%2C2c-0.3%2C0.7-0.7%2C1.3-1.1%2C2c-0.4%2C0.7-0.7%2C1.4-1.2%2C2c-1%2C1.3-1.9%2C2.7-3.1%2C4c-2.2%2C2.7-5%2C5-8.1%2C7.1%20c-0.8%2C0.5-1.6%2C1-2.4%2C1.5c-0.8%2C0.5-1.7%2C0.9-2.6%2C1.3L66%2C87.7l-1.4%2C0.5c-0.9%2C0.3-1.8%2C0.7-2.8%2C1c-3.8%2C1.1-7.9%2C1.7-11.8%2C1.8L47%2C90.8%20c-1%2C0-2-0.2-3-0.3l-1.5-0.2l-0.7-0.1L41.1%2C90c-1-0.3-1.9-0.5-2.9-0.7c-0.9-0.3-1.9-0.7-2.8-1L34%2C87.7l-1.3-0.6%20c-0.9-0.4-1.8-0.8-2.6-1.3c-0.8-0.5-1.6-1-2.4-1.5c-3.1-2.1-5.9-4.5-8.1-7.1c-1.2-1.2-2.1-2.7-3.1-4c-0.5-0.6-0.8-1.4-1.2-2%20c-0.4-0.7-0.8-1.3-1.1-2c-0.3-0.7-0.6-1.3-0.9-2c-0.3-0.7-0.6-1.3-0.8-1.9c-0.4-1.3-0.9-2.5-1.2-3.7c-0.3-1.2-0.5-2.3-0.7-3.3%20c-0.2-1-0.3-2-0.4-2.8c-0.1-0.4-0.1-0.8-0.1-1.2c0-0.4%2C0-0.7%2C0-1.1c0-0.7%2C0-1.2%2C0-1.7C10%2C50.5%2C10%2C50%2C10%2C50z%22%20fill%3D%22%23013138%22%20filter%3D%22url(%23uil-ring-shadow)%22%3E%3CanimateTransform%20attributeName%3D%22transform%22%20type%3D%22rotate%22%20from%3D%220%2050%2050%22%20to%3D%22360%2050%2050%22%20repeatCount%3D%22indefinite%22%20dur%3D%221s%22%3E%3C%2FanimateTransform%3E%3C%2Fpath%3E%3C%2Fsvg%3E");content:"";height:14px;width:14px}.inspire-tree>ol{position:relative}.inspire-tree .wholerow{height:25px;left:0;margin-top:-25px;position:absolute;width:100%;z-index:1}.inspire-tree .focused>.wholerow{border:1px dotted #000}.inspire-tree .title-wrap:hover+.wholerow,.inspire-tree .wholerow:hover{background-color:rgba(218,250,255,.5)}.inspire-tree .selected>.title-wrap:hover+.wholerow,.inspire-tree .selected>.wholerow,.inspire-tree .selected>.wholerow:hover{background-color:rgba(164,234,245,.5)}.inspire-tree .matched>.title-wrap:hover+.wholerow,.inspire-tree .matched>.wholerow,.inspire-tree .matched>.wholerow:hover{background-color:rgba(247,255,170,.5)} \ No newline at end of file diff --git a/dataforge-vis-spatial-gdml/src/jsMain/web/css/main.css b/dataforge-vis-spatial-gdml/src/jsMain/web/css/main.css index b2bb1e78..e7f925df 100644 --- a/dataforge-vis-spatial-gdml/src/jsMain/web/css/main.css +++ b/dataforge-vis-spatial-gdml/src/jsMain/web/css/main.css @@ -11,3 +11,38 @@ 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } + +/* Remove default bullets */ +ul, .objTree-subtree { + list-style-type: none; +} + +/* Style the caret/arrow */ +.objTree-caret { + cursor: pointer; + user-select: none; /* Prevent text selection */ +} + +.objTree-label { + cursor: pointer; +} + +/* Create the caret/arrow with a unicode, and style it */ +.objTree-caret::before { + content: "\25B6"; + color: black; + display: inline-block; + margin-right: 6px; +} + +.objTree-leaf::before { + content: "\25C6"; + color: black; + display: inline-block; + margin-right: 6px; +} + +/* Rotate the caret/arrow icon when clicked on (using JavaScript) */ +.objTree-caret-down::before { + transform: rotate(90deg); +} diff --git a/dataforge-vis-spatial-gdml/src/jsMain/web/index.html b/dataforge-vis-spatial-gdml/src/jsMain/web/index.html index 22603bcf..3b2a99b2 100644 --- a/dataforge-vis-spatial-gdml/src/jsMain/web/index.html +++ b/dataforge-vis-spatial-gdml/src/jsMain/web/index.html @@ -4,13 +4,9 @@ Three js demo for particle physics - - @@ -37,12 +33,5 @@
- - - \ No newline at end of file diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/jsTree.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/jsTree.kt new file mode 100644 index 00000000..a45c1861 --- /dev/null +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/jsTree.kt @@ -0,0 +1,75 @@ +package hep.dataforge.js + +import hep.dataforge.names.NameToken +import hep.dataforge.vis.common.VisualGroup +import hep.dataforge.vis.common.VisualObject +import hep.dataforge.vis.common.isEmpty +import hep.dataforge.vis.spatial.editor.card +import kotlinx.html.TagConsumer +import kotlinx.html.dom.append +import kotlinx.html.js.* +import org.w3c.dom.Element +import org.w3c.dom.HTMLElement +import org.w3c.dom.HTMLSpanElement +import kotlin.dom.clear + +fun Element.objectTree( + token: NameToken, + obj: VisualObject, + clickCallback: (VisualObject) -> Unit = {} +) { + clear() + append { + card("Object tree") { + subTree(token, obj, clickCallback) + } + } +} + +private fun TagConsumer.subTree( + token: NameToken, + obj: VisualObject, + clickCallback: (VisualObject) -> Unit +) { + + if (obj is VisualGroup && !obj.isEmpty) { + lateinit var toggle: HTMLSpanElement + div("d-inline-block text-truncate") { + toggle = span("objTree-caret") + label("objTree-label") { + +token.toString() + onClickFunction = { clickCallback(obj) } + } + } + val subtree = ul("objTree-subtree") + toggle.onclick = { + toggle.classList.toggle("objTree-caret-down") + subtree.apply { + if (toggle.classList.contains("objTree-caret-down")) { + obj.children.entries + .filter { !it.key.toString().startsWith("@") } + .sortedBy { (it.value as? VisualGroup)?.isEmpty ?: true } + .forEach { (token, child) -> + append { + li().apply { + subTree(token, child, clickCallback) + } + } + } + } else { + this.clear() + } + } + //jQuery(subtree).asDynamic().collapse("toggle") + } + } else { + div("d-inline-block text-truncate") { + span("objTree-leaf") + label("objTree-label") { + +token.toString() + onClickFunction = { clickCallback(obj) } + } + } + } +} + diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/jsVisualTree.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/jsVisualTree.kt deleted file mode 100644 index 13868fdf..00000000 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/jsVisualTree.kt +++ /dev/null @@ -1,136 +0,0 @@ -@file:Suppress("UNCHECKED_CAST_TO_EXTERNAL_INTERFACE") - -package hep.dataforge.vis.spatial.editor - -import hep.dataforge.meta.string -import hep.dataforge.names.EmptyName -import hep.dataforge.names.Name -import hep.dataforge.names.NameToken -import hep.dataforge.vis.common.VisualGroup -import hep.dataforge.vis.common.VisualObject -import hep.dataforge.vis.common.getProperty -import hep.dataforge.vis.jsObject -import hep.dataforge.vis.spatial.Proxy -import hep.dataforge.vis.spatial.visible -import info.laht.threekt.loaders.Cache.clear -import kotlinx.html.div -import kotlinx.html.dom.append -import org.w3c.dom.Element -import kotlin.js.json - -operator fun Name.plus(other: NameToken): Name = Name(tokens + other) - - -private fun createInspireTree(block: Config.() -> Unit = {}): InspireTree { - val config = (json( - "checkbox" to json( - "autoCheckChildren" to false - ) - ) as Config).apply(block) - return InspireTree(config) -} - -private fun VisualObject.toTree(onFocus: (VisualObject?, String?) -> Unit = { _, _ -> }): InspireTree { - - val map = HashMap() - - fun generateNodeConfig(item: VisualObject, fullName: Name): NodeConfig { - val title = item.getProperty("title").string ?: fullName.last()?.toString() ?: "root" - val className = if (item is Proxy) { - item.prototype::class.toString() - } else { - item::class.toString() - }.replace("class ", "") - - val text: String = if (title.startsWith("@")) { - "[$className}]" - } else { - "$title[$className}]" - } - - return json( - "children" to if ((item as? VisualGroup)?.children?.isEmpty() != false) { - emptyArray() - } else { - true - }, - "text" to text, - "id" to fullName.toString(), - "itree" to json( - "state" to json( - "checked" to (item.visible ?: true) - ) - ) - ) as NodeConfig - - } - - fun TreeNode.fillChildren(group: VisualObject, groupName: Name) { - if(group is VisualGroup) { - group.children.forEach { (token, obj) -> - if (!token.body.startsWith("@")) { - val name = groupName + token - val nodeConfig = generateNodeConfig(obj, name) - val childNode = addChild(nodeConfig) - map[childNode.id] = obj - if (obj is VisualGroup) { - childNode.fillChildren(obj, name) - } - } - } - } - } - - val inspireTree = createInspireTree { - - } - val nodeConfig = generateNodeConfig(this, EmptyName) - val rootNode = inspireTree.addNode(nodeConfig) - map[rootNode.id] = this - rootNode.fillChildren(this, EmptyName) - -// inspireTree.on("node.selected") { node: TreeNode, isLoadEvent: Boolean -> -// if (!isLoadEvent) { -// map[node.id]?.selected = node.selected() -// } -// } -// -// inspireTree.on("node.deselect") { node: TreeNode -> -// map[node.id]?.selected = node.selected() -// } - - inspireTree.on("node.checked") { node: TreeNode, isLoadEvent: Boolean -> - if (!isLoadEvent) { - map[node.id]?.visible = node.checked() - } - } - - inspireTree.on("node.unchecked") { node: TreeNode -> - if (!node.indeterminate()) { - map[node.id]?.visible = node.checked() - } - } - - inspireTree.on("node.focused") { node: TreeNode, isLoadEvent: Boolean -> - if (!isLoadEvent) { - onFocus(map[node.id], node.id) - } - } - - inspireTree.collapseDeep() - - return inspireTree -} - -fun Element.visualObjectTree(group: VisualObject, onFocus: (VisualObject?, String?) -> Unit) { - clear() - append { - card("Visual object tree") { - val domConfig = jsObject { - target = div() - showCheckboxes = false - } - InspireTreeDOM(group.toTree(onFocus), domConfig) - } - } -} \ No newline at end of file diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/propertyEditor.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/propertyEditor.kt index d718127e..f123ad4d 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/propertyEditor.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/propertyEditor.kt @@ -1,10 +1,10 @@ package hep.dataforge.vis.spatial.editor import hep.dataforge.io.toJson +import hep.dataforge.js.jsObject import hep.dataforge.meta.* import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.common.findStyle -import hep.dataforge.vis.jsObject import hep.dataforge.vis.spatial.Material3D.Companion.COLOR_KEY import hep.dataforge.vis.spatial.Material3D.Companion.OPACITY_KEY import hep.dataforge.vis.spatial.VisualObject3D.Companion.VISIBLE_KEY @@ -22,7 +22,7 @@ import kotlin.dom.clear fun Meta.toDynamic() = JSON.parse(toJson().toString()) -fun Element.propertyEditor(item: VisualObject?, name: String?) { +fun Element.propertyEditor(item: VisualObject?) { clear() if (item != null) { append { diff --git a/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt b/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt index a35bf4c9..7841fb30 100644 --- a/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt +++ b/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt @@ -1,10 +1,10 @@ package hep.dataforge.vis.spatial.demo import hep.dataforge.context.ContextBuilder -import hep.dataforge.vis.ApplicationBase +import hep.dataforge.js.Application +import hep.dataforge.js.startApplication import hep.dataforge.vis.common.Colors import hep.dataforge.vis.spatial.* -import hep.dataforge.vis.startApplication import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.delay import kotlinx.coroutines.isActive @@ -15,9 +15,7 @@ import kotlin.math.sin import kotlin.random.Random -private class ThreeDemoApp : ApplicationBase() { - - override val stateKeys: List = emptyList() +private class ThreeDemoApp : Application { override fun start(state: Map) { @@ -141,7 +139,7 @@ private class ThreeDemoApp : ApplicationBase() { thickness = 208.0 rotationX = it * PI2 / 20 color(Colors.green) - //rotationY = it * PI2 / 20 + //rotationY = it * PI2 / 20 } } } From 9bf438749c394c3885088d8c9625d2d08b172a04 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 30 Oct 2019 16:39:01 +0300 Subject: [PATCH 03/25] Moved to DF 0.1.4 --- build.gradle.kts | 3 +- .../hep/dataforge/vis/common/VisualPlugin.kt | 3 +- .../kotlin/hep/dataforge/vis/fx/FXPlugin.kt | 2 +- .../hep/dataforge/vis/fx/meta/FXMeta.kt | 4 +- .../vis/fx/values/ColorValueChooser.kt | 6 ++- .../vis/fx/values/ComboBoxValueChooser.kt | 4 +- .../vis/fx/values/TextValueChooser.kt | 4 +- .../dataforge/vis/fx/values/ValueChooser.kt | 3 +- .../vis/spatial/gdml/GDMLTransformer.kt | 4 +- .../dataforge/vis/spatial/gdml/visualGDML.kt | 8 ++-- .../vis/spatial/gdml/demo/GDMLDemoApp.kt | 18 ++++----- .../dataforge/vis/spatial/gdml/testJson.kt | 16 ++++++++ dataforge-vis-spatial/build.gradle.kts | 1 - .../kotlin/hep/dataforge/vis/spatial/Proxy.kt | 39 +++++++++++++++---- .../dataforge/vis/spatial/Visual3DPlugin.kt | 5 ++- .../dataforge/vis/spatial/VisualGroup3D.kt | 27 ++++++++----- .../dataforge/vis/spatial/VisualObject3D.kt | 4 +- .../spatial/transform/RemoveSingleChild.kt | 2 +- .../dataforge/vis/spatial/transform/UnRef.kt | 2 +- .../vis/spatial/three/ThreePlugin.kt | 7 +--- .../vis/spatial/demo/ThreeDemoGrid.kt | 2 +- wrappers/build.gradle.kts | 4 +- 22 files changed, 112 insertions(+), 56 deletions(-) create mode 100644 dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/testJson.kt diff --git a/build.gradle.kts b/build.gradle.kts index 73b88aa5..edf19391 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,4 +1,4 @@ -val dataforgeVersion by extra("0.1.3") +val dataforgeVersion by extra("0.1.4") plugins { val kotlinVersion = "1.3.50" @@ -15,6 +15,7 @@ plugins { allprojects { repositories { + mavenLocal() maven("https://dl.bintray.com/pdvrieze/maven") maven("http://maven.jzy3d.org/releases") maven("https://kotlin.bintray.com/js-externals") diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualPlugin.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualPlugin.kt index 933e4736..39a1abc0 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualPlugin.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualPlugin.kt @@ -30,7 +30,8 @@ class VisualPlugin(meta: Meta) : AbstractPlugin(meta) { companion object : PluginFactory { override val tag: PluginTag = PluginTag(name = "visual", group = PluginTag.DATAFORGE_GROUP) override val type: KClass = VisualPlugin::class - override fun invoke(meta: Meta): VisualPlugin = VisualPlugin(meta) + + override fun invoke(meta: Meta, context: Context): VisualPlugin = VisualPlugin(meta) const val VISUAL_FACTORY_TYPE = "visual.factory" } diff --git a/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/FXPlugin.kt b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/FXPlugin.kt index 12e9c4a3..ffe2ef64 100644 --- a/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/FXPlugin.kt +++ b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/FXPlugin.kt @@ -96,7 +96,7 @@ class FXPlugin(meta: Meta = EmptyMeta) : AbstractPlugin(meta) { companion object : PluginFactory { override val type: KClass = FXPlugin::class override val tag: PluginTag = PluginTag("vis.fx", group = PluginTag.DATAFORGE_GROUP) - override fun invoke(meta: Meta): FXPlugin = FXPlugin(meta) + override fun invoke(meta: Meta, context: Context): FXPlugin = FXPlugin(meta) } } diff --git a/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/meta/FXMeta.kt b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/meta/FXMeta.kt index 82d48491..9a1929c8 100644 --- a/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/meta/FXMeta.kt +++ b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/meta/FXMeta.kt @@ -84,7 +84,7 @@ class FXMetaNode>( override val hasValue: ObservableBooleanValue = nodeProperty.booleanBinding { it != null } private val filter: (FXMeta) -> Boolean = { cfg -> - !(cfg.descriptor?.tags?.contains(ConfigEditor.NO_CONFIGURATOR_TAG) ?: false) + !(cfg.descriptor?.attributes?.get(ConfigEditor.NO_CONFIGURATOR_TAG)?.boolean ?: false) } val children = object : ListBinding>() { @@ -172,7 +172,7 @@ fun > FXMetaNode.remove(name: NameToken) { private fun > M.createEmptyNode(token: NameToken, append: Boolean): M { return if (append && token.index.isNotEmpty()) { val name = token.asName() - val index = (getAll(name).keys.mapNotNull { it.toIntOrNull() }.max() ?: -1) + 1 + val index = (getIndexed(name).keys.mapNotNull { it.toIntOrNull() }.max() ?: -1) + 1 val newName = name.withIndex(index.toString()) set(newName, EmptyMeta) get(newName).node!! diff --git a/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/ColorValueChooser.kt b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/ColorValueChooser.kt index e0e0f94a..e63ee25b 100644 --- a/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/ColorValueChooser.kt +++ b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/ColorValueChooser.kt @@ -1,6 +1,8 @@ package hep.dataforge.vis.fx.values import hep.dataforge.meta.Meta +import hep.dataforge.names.Name +import hep.dataforge.names.asName import hep.dataforge.values.Null import hep.dataforge.values.Value import hep.dataforge.values.asValue @@ -39,8 +41,8 @@ class ColorValueChooser : ValueChooserBase() { return node } - companion object: ValueChooser.Factory{ - override val name: String = "color" + companion object : ValueChooser.Factory { + override val name: Name = "color".asName() override fun invoke(meta: Meta): ValueChooser = ColorValueChooser() } diff --git a/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/ComboBoxValueChooser.kt b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/ComboBoxValueChooser.kt index 0f6460e0..f2a830d6 100644 --- a/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/ComboBoxValueChooser.kt +++ b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/ComboBoxValueChooser.kt @@ -8,6 +8,8 @@ package hep.dataforge.vis.fx.values import hep.dataforge.meta.Meta import hep.dataforge.meta.get import hep.dataforge.meta.value +import hep.dataforge.names.Name +import hep.dataforge.names.asName import hep.dataforge.values.Value import hep.dataforge.values.parseValue import javafx.collections.FXCollections @@ -50,7 +52,7 @@ class ComboBoxValueChooser(val values: Collection? = null) : ValueChooser } companion object : ValueChooser.Factory { - override val name: String = "combo" + override val name: Name = "combo".asName() override fun invoke(meta: Meta): ValueChooser = ComboBoxValueChooser(meta["values"].value?.list) } diff --git a/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/TextValueChooser.kt b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/TextValueChooser.kt index b273b71f..f1726fbf 100644 --- a/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/TextValueChooser.kt +++ b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/TextValueChooser.kt @@ -6,6 +6,8 @@ package hep.dataforge.vis.fx.values import hep.dataforge.meta.Meta +import hep.dataforge.names.Name +import hep.dataforge.names.asName import hep.dataforge.values.* import javafx.beans.value.ObservableValue import javafx.scene.control.TextField @@ -100,7 +102,7 @@ class TextValueChooser : ValueChooserBase() { } companion object : ValueChooser.Factory { - override val name: String = "text" + override val name: Name = "text".asName() override fun invoke(meta: Meta): ValueChooser = TextValueChooser() } } diff --git a/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/ValueChooser.kt b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/ValueChooser.kt index 77ec9f28..6624e653 100644 --- a/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/ValueChooser.kt +++ b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/values/ValueChooser.kt @@ -10,6 +10,7 @@ import hep.dataforge.context.Named import hep.dataforge.descriptors.ValueDescriptor import hep.dataforge.meta.EmptyMeta import hep.dataforge.meta.Meta +import hep.dataforge.names.toName import hep.dataforge.provider.Type import hep.dataforge.provider.provideByType import hep.dataforge.values.Null @@ -71,7 +72,7 @@ interface ValueChooser { companion object { private fun findWidgetByType(context: Context, type: String): Factory? { - return when (type) { + return when (type.toName()) { TextValueChooser.name -> TextValueChooser ColorValueChooser.name -> ColorValueChooser ComboBoxValueChooser.name -> ComboBoxValueChooser diff --git a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt index ee646f7a..f4671bcc 100644 --- a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt +++ b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt @@ -29,7 +29,7 @@ class GDMLTransformer(val root: GDML) { /** * A special group for local templates */ - val templates by lazy { VisualGroup3D() } + val proto by lazy { VisualGroup3D() } private val styleCache = HashMap() var lUnit: LUnit = LUnit.MM @@ -67,7 +67,7 @@ class GDMLTransformer(val root: GDML) { var onFinish: GDMLTransformer.() -> Unit = {} internal fun finalize(final: VisualGroup3D): VisualGroup3D { - final.templates = templates + final.prototypes = proto styleCache.forEach { final.addStyle(it.key, it.value, false) } diff --git a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDML.kt b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDML.kt index 3271fe38..97b6b474 100644 --- a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDML.kt +++ b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDML.kt @@ -161,8 +161,8 @@ private fun VisualGroup3D.addPhysicalVolume( } GDMLTransformer.Action.CACHE -> { val fullName = volumesName + volume.name.asName() - if (context.templates[fullName] == null) { - context.templates[fullName] = volume(context, volume) + if (context.proto[fullName] == null) { + context.proto[fullName] = volume(context, volume) } this[physVolume.name ?: ""] = Proxy(fullName).apply { @@ -215,8 +215,8 @@ private fun volume( } } GDMLTransformer.Action.CACHE -> { - if (context.templates[solid.name] == null) { - context.templates.addSolid(context, solid, solid.name) { + if (context.proto[solid.name] == null) { + context.proto.addSolid(context, solid, solid.name) { context.configureSolid(this, group, solid) } } diff --git a/dataforge-vis-spatial-gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt b/dataforge-vis-spatial-gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt index 0c1da7ed..67d4d184 100644 --- a/dataforge-vis-spatial-gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt +++ b/dataforge-vis-spatial-gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt @@ -119,14 +119,14 @@ private class GDMLDemoApp : Application { val three = context.plugins.load(ThreePlugin) //val url = URL("https://drive.google.com/open?id=1w5e7fILMN83JGgB8WANJUYm8OW2s0WVO") - val canvas = document.getElementById("canvas") ?: error("Element with id 'canvas' not found on page") - val layers = document.getElementById("layers") ?: error("Element with id 'layers' not found on page") - val tree = document.getElementById("tree") ?: error("Element with id 'tree' not found on page") - val editor = document.getElementById("editor") ?: error("Element with id 'editor' not found on page") - canvas.clear() + val canvasElement = document.getElementById("canvas") ?: error("Element with id 'canvas' not found on page") + val configElement = document.getElementById("layers") ?: error("Element with id 'layers' not found on page") + val treeElement = document.getElementById("tree") ?: error("Element with id 'tree' not found on page") + val editorElement = document.getElementById("editor") ?: error("Element with id 'editor' not found on page") + canvasElement.clear() val action: (name: String, data: String) -> Unit = { name, data -> - canvas.clear() + canvasElement.clear() spinner(true) message("Loading GDML") val gdml = GDML.format.parse(GDML.serializer(), data) @@ -149,12 +149,12 @@ private class GDMLDemoApp : Application { message("Rendering") //output.camera.layers.enable(1) - val output = three.output(canvas as HTMLElement) + val output = three.output(canvasElement as HTMLElement) output.camera.layers.set(0) - layers.threeOutputConfig(output) + configElement.threeOutputConfig(output) //tree.visualObjectTree(visual, editor::propertyEditor) - tree.objectTree(NameToken("World"),visual, editor::propertyEditor) + treeElement.objectTree(NameToken("World"),visual, editorElement::propertyEditor) output.render(visual) diff --git a/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/testJson.kt b/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/testJson.kt new file mode 100644 index 00000000..ad722578 --- /dev/null +++ b/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/testJson.kt @@ -0,0 +1,16 @@ +package hep.dataforge.vis.spatial.gdml + +import hep.dataforge.names.toName +import hep.dataforge.vis.spatial.* + +fun main() { + val vis = VisualGroup3D().apply { + val box = Box(100f, 100f, 20f).apply { + color(0u, 0u, 255u) + } + proxy("some.name".toName(), box, "obj") + } + + val string = Visual3DPlugin.json.stringify(VisualGroup3D.serializer(),vis) + println(string) +} \ No newline at end of file diff --git a/dataforge-vis-spatial/build.gradle.kts b/dataforge-vis-spatial/build.gradle.kts index 41672aee..1d562140 100644 --- a/dataforge-vis-spatial/build.gradle.kts +++ b/dataforge-vis-spatial/build.gradle.kts @@ -21,7 +21,6 @@ kotlin { } jvmMain { dependencies { - implementation(project(":dataforge-vis-fx")) implementation("org.fxyz3d:fxyz3d:0.5.2") } } diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt index e4125590..4dd11e79 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt @@ -3,7 +3,8 @@ package hep.dataforge.vis.spatial import hep.dataforge.io.ConfigSerializer -import hep.dataforge.io.NameSerializer + +import hep.dataforge.io.serialization.NameSerializer import hep.dataforge.meta.* import hep.dataforge.names.Name import hep.dataforge.names.NameToken @@ -36,7 +37,7 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua * Recursively search for defined template in the parent */ val prototype: VisualObject3D - get() = (parent as? VisualGroup3D)?.getTemplate(templateName) + get() = (parent as? VisualGroup3D)?.getPrototype(templateName) ?: error("Template with name $templateName not found in $parent") override fun getStyle(name: Name): Meta? = (parent as VisualGroup?)?.getStyle(name) @@ -65,9 +66,11 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua } override val children: Map - get() = (prototype as? MutableVisualGroup)?.children?.mapValues { - ProxyChild(it.key.asName()) - } ?: emptyMap() + get() = (prototype as? MutableVisualGroup)?.children + ?.filter { !it.key.toString().startsWith("@") } + ?.mapValues { + ProxyChild(it.key.asName()) + } ?: emptyMap() private val propertyCache: HashMap = HashMap() @@ -152,8 +155,30 @@ val VisualObject.prototype: VisualObject? else -> null } +/** + * Create ref for existing prototype + */ inline fun VisualGroup3D.ref( templateName: Name, name: String = "", - action: Proxy.() -> Unit = {} -) = Proxy(templateName).apply(action).also { set(name, it) } + block: Proxy.() -> Unit = {} +) = Proxy(templateName).apply(block).also { set(name, it) } + +/** + * Add new proxy wrapping given object and automatically adding it to the prototypes + */ +fun VisualGroup3D.proxy( + templateName: Name, + obj: VisualObject3D, + name: String = "", + attachToParent: Boolean = false, + block: Proxy.() -> Unit = {} +): Proxy { + val existing = getPrototype(templateName) + if (existing == null) { + setPrototype(templateName,obj, attachToParent) + } else if(existing != obj) { + error("Can't add different prototype on top of existing one") + } + return ref(templateName, name, block) +} diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Visual3DPlugin.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Visual3DPlugin.kt index 02886ed9..093c7cfe 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Visual3DPlugin.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Visual3DPlugin.kt @@ -1,11 +1,12 @@ package hep.dataforge.vis.spatial import hep.dataforge.context.AbstractPlugin +import hep.dataforge.context.Context import hep.dataforge.context.PluginFactory import hep.dataforge.context.PluginTag import hep.dataforge.io.ConfigSerializer import hep.dataforge.io.MetaSerializer -import hep.dataforge.io.NameSerializer +import hep.dataforge.io.serialization.NameSerializer import hep.dataforge.meta.* import hep.dataforge.names.Name import hep.dataforge.vis.common.VisualObject @@ -30,7 +31,7 @@ class Visual3DPlugin(meta: Meta) : AbstractPlugin(meta) { companion object : PluginFactory { override val tag: PluginTag = PluginTag(name = "visual.spatial", group = PluginTag.DATAFORGE_GROUP) override val type: KClass = Visual3DPlugin::class - override fun invoke(meta: Meta): Visual3DPlugin = Visual3DPlugin(meta) + override fun invoke(meta: Meta, context: Context): Visual3DPlugin = Visual3DPlugin(meta) val serialModule = SerializersModule { contextual(Point3DSerializer) diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt index 7d3050e3..fca6f7ed 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt @@ -10,7 +10,7 @@ package hep.dataforge.vis.spatial import hep.dataforge.io.ConfigSerializer import hep.dataforge.io.MetaSerializer -import hep.dataforge.io.NameSerializer +import hep.dataforge.io.serialization.NameSerializer import hep.dataforge.meta.Config import hep.dataforge.meta.Meta import hep.dataforge.meta.MetaBuilder @@ -32,7 +32,8 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D { /** * A container for templates visible inside this group */ - var templates: VisualGroup3D? = null + @SerialName(PROTOTYPES_KEY) + var prototypes: VisualGroup3D? = null set(value) { value?.parent = this field = value @@ -85,18 +86,26 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D { } } - fun getTemplate(name: Name): VisualObject3D? = - templates?.get(name) as? VisualObject3D - ?: (parent as? VisualGroup3D)?.getTemplate(name) + fun getPrototype(name: Name): VisualObject3D? = + prototypes?.get(name) as? VisualObject3D ?: (parent as? VisualGroup3D)?.getPrototype(name) + + fun setPrototype(name: Name, obj: VisualObject3D, attachToParent: Boolean = false) { + val parent = this.parent + if (attachToParent && parent is VisualGroup3D) { + parent.setPrototype(name, obj, attachToParent) + } else { + (prototypes ?: VisualGroup3D().also { this.prototypes = it }).set(name, obj) + } + } override fun MetaBuilder.updateMeta() { - set(TEMPLATES_KEY, templates?.toMeta()) + set(PROTOTYPES_KEY, prototypes?.toMeta()) updatePosition() updateChildren() } companion object { - const val TEMPLATES_KEY = "templates" + const val PROTOTYPES_KEY = "templates" } } @@ -109,7 +118,7 @@ fun VisualGroup.attachChildren() { (it as? VisualGroup)?.attachChildren() } if (this is VisualGroup3D) { - templates?.also { + prototypes?.also { it.parent = this it.attachChildren() } @@ -117,4 +126,4 @@ fun VisualGroup.attachChildren() { } fun VisualGroup3D.group(key: String = "", action: VisualGroup3D.() -> Unit = {}): VisualGroup3D = - VisualGroup3D().apply(action).also { set(key, it) } + VisualGroup3D().apply(action).also { set(key, it) } \ No newline at end of file diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt index 1e91dde9..1f26ff0b 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt @@ -2,15 +2,15 @@ package hep.dataforge.vis.spatial -import hep.dataforge.io.NameSerializer +import hep.dataforge.io.serialization.NameSerializer import hep.dataforge.meta.* import hep.dataforge.names.asName import hep.dataforge.names.plus import hep.dataforge.output.Output import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.spatial.VisualObject3D.Companion.DETAIL_KEY -import hep.dataforge.vis.spatial.VisualObject3D.Companion.LAYER_KEY import hep.dataforge.vis.spatial.VisualObject3D.Companion.IGNORE_KEY +import hep.dataforge.vis.spatial.VisualObject3D.Companion.LAYER_KEY import hep.dataforge.vis.spatial.VisualObject3D.Companion.SELECTED_KEY import hep.dataforge.vis.spatial.VisualObject3D.Companion.VISIBLE_KEY import kotlinx.serialization.UseSerializers diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/transform/RemoveSingleChild.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/transform/RemoveSingleChild.kt index e8135dc3..1fc1e52b 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/transform/RemoveSingleChild.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/transform/RemoveSingleChild.kt @@ -49,7 +49,7 @@ object RemoveSingleChild : VisualTreeTransform() { } replaceChildren() - templates?.replaceChildren() + prototypes?.replaceChildren() } override fun VisualGroup3D.clone(): VisualGroup3D { diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/transform/UnRef.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/transform/UnRef.kt index b09561e4..12681b24 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/transform/UnRef.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/transform/UnRef.kt @@ -24,7 +24,7 @@ object UnRef : VisualTreeTransform() { } private fun MutableVisualGroup.unref(name: Name) { - (this as? VisualGroup3D)?.templates?.set(name, null) + (this as? VisualGroup3D)?.prototypes?.set(name, null) children.filter { (it.value as? Proxy)?.templateName == name }.forEach { (key, value) -> val proxy = value as Proxy val newChild = mergeChild(proxy, proxy.prototype) diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreePlugin.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreePlugin.kt index 2d3c027f..2831a155 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreePlugin.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreePlugin.kt @@ -1,9 +1,6 @@ package hep.dataforge.vis.spatial.three -import hep.dataforge.context.AbstractPlugin -import hep.dataforge.context.PluginFactory -import hep.dataforge.context.PluginTag -import hep.dataforge.context.content +import hep.dataforge.context.* import hep.dataforge.meta.Meta import hep.dataforge.names.Name import hep.dataforge.names.asName @@ -88,7 +85,7 @@ class ThreePlugin : AbstractPlugin() { companion object : PluginFactory { override val tag = PluginTag("visual.three", PluginTag.DATAFORGE_GROUP) override val type = ThreePlugin::class - override fun invoke(meta: Meta) = ThreePlugin() + override fun invoke(meta: Meta,context: Context) = ThreePlugin() } } diff --git a/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoGrid.kt b/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoGrid.kt index 9eb190d8..0f2b8283 100644 --- a/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoGrid.kt +++ b/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoGrid.kt @@ -79,7 +79,7 @@ class ThreeDemoGrid(meta: Meta) : AbstractPlugin(meta), OutputManager { override val type: KClass = ThreeDemoGrid::class - override fun invoke(meta: Meta): ThreeDemoGrid = ThreeDemoGrid(meta) + override fun invoke(meta: Meta,context: Context): ThreeDemoGrid = ThreeDemoGrid(meta) } } diff --git a/wrappers/build.gradle.kts b/wrappers/build.gradle.kts index 177713d0..0d79fcc0 100644 --- a/wrappers/build.gradle.kts +++ b/wrappers/build.gradle.kts @@ -13,8 +13,8 @@ kotlin{ sourceSets["main"].apply{ dependencies{ api(npm("style-loader")) - api(npm("inspire-tree","6.0.1")) - api(npm("inspire-tree-dom","4.0.6")) +// api(npm("inspire-tree","6.0.1")) +// api(npm("inspire-tree-dom","4.0.6")) api(npm("jsoneditor")) api(npm("dat.gui")) //api("org.jetbrains:kotlin-extensions:1.0.1-pre.83-kotlin-1.3.50") From b72300bfaab358ef8de3d266f404fef86b542490 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 30 Oct 2019 17:22:29 +0300 Subject: [PATCH 04/25] Moved to DF 0.1.4 --- .../vis/common/AbstractVisualGroup.kt | 2 +- .../vis/common/AbstractVisualObject.kt | 4 +-- .../dataforge/vis/fx/demo/MetaEditorDemo.kt | 10 +++---- .../hep/dataforge/vis/jsroot/JSRootDemoApp.kt | 2 +- .../dataforge/vis/jsroot/JSRootGeometry.kt | 26 +++++++++---------- .../vis/spatial/gdml/GDMLTransformer.kt | 2 +- .../kotlin/hep/dataforge/vis/spatial/Box.kt | 6 ++--- .../hep/dataforge/vis/spatial/Composite.kt | 6 ++--- .../hep/dataforge/vis/spatial/Convex.kt | 4 +-- .../hep/dataforge/vis/spatial/Material3D.kt | 4 +-- .../hep/dataforge/vis/spatial/ConvexTest.kt | 5 ++-- .../hep/dataforge/vis/spatial/GroupTest.kt | 6 ++--- .../vis/spatial/demo/ThreeDemoApp.kt | 6 ++--- .../vis/spatial/demo/ThreeDemoGrid.kt | 12 +++++---- 14 files changed, 48 insertions(+), 47 deletions(-) diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualGroup.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualGroup.kt index a09db3ed..c8637618 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualGroup.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualGroup.kt @@ -151,7 +151,7 @@ abstract class AbstractVisualGroup : AbstractVisualObject(), MutableVisualGroup protected fun MetaBuilder.updateChildren() { //adding named children children.forEach { - "children[${it.key}]" to it.value.toMeta() + "children[${it.key}]" put it.value.toMeta() } } diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualObject.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualObject.kt index e63382ca..5a4a0639 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualObject.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualObject.kt @@ -86,8 +86,8 @@ abstract class AbstractVisualObject : VisualObject { protected open fun MetaBuilder.updateMeta() {} override fun toMeta(): Meta = buildMeta { - "type" to this::class.simpleName - "properties" to properties + "type" putValue this::class.simpleName + "properties" put properties updateMeta() } } diff --git a/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/demo/MetaEditorDemo.kt b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/demo/MetaEditorDemo.kt index 6ced3e79..4b12a3ff 100644 --- a/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/demo/MetaEditorDemo.kt +++ b/dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/demo/MetaEditorDemo.kt @@ -16,12 +16,12 @@ class MetaEditorDemoApp : App(MetaEditorDemo::class) class MetaEditorDemo : View("Meta editor demo") { val meta = buildMeta { - "aNode" to { - "innerNode" to { - "innerValue" to true + "aNode" put { + "innerNode" put { + "innerValue" put true } - "b" to 223 - "c" to "StringValue" + "b" put 223 + "c" put "StringValue" } }.toConfig() diff --git a/dataforge-vis-jsroot/src/main/kotlin/hep/dataforge/vis/jsroot/JSRootDemoApp.kt b/dataforge-vis-jsroot/src/main/kotlin/hep/dataforge/vis/jsroot/JSRootDemoApp.kt index aa6eb542..9775dbb7 100644 --- a/dataforge-vis-jsroot/src/main/kotlin/hep/dataforge/vis/jsroot/JSRootDemoApp.kt +++ b/dataforge-vis-jsroot/src/main/kotlin/hep/dataforge/vis/jsroot/JSRootDemoApp.kt @@ -74,5 +74,5 @@ class JSRootDemoApp : ApplicationBase() { } } - override fun dispose() = emptyMap()//mapOf("lines" to presenter.dispose()) + override fun dispose() = emptyMap()//mapOf("lines" put presenter.dispose()) } \ No newline at end of file diff --git a/dataforge-vis-jsroot/src/main/kotlin/hep/dataforge/vis/jsroot/JSRootGeometry.kt b/dataforge-vis-jsroot/src/main/kotlin/hep/dataforge/vis/jsroot/JSRootGeometry.kt index c23546a1..f4ee6c42 100644 --- a/dataforge-vis-jsroot/src/main/kotlin/hep/dataforge/vis/jsroot/JSRootGeometry.kt +++ b/dataforge-vis-jsroot/src/main/kotlin/hep/dataforge/vis/jsroot/JSRootGeometry.kt @@ -15,37 +15,37 @@ class JSRootGeometry(parent: VisualObject?, meta: Meta) : DisplayLeaf(parent, me var facesLimit by int(0) fun box(xSize: Number, ySize: Number, zSize: Number) = buildMeta { - "_typename" to "TGeoBBox" - "fDX" to xSize - "fDY" to ySize - "fDZ" to zSize + "_typename" put "TGeoBBox" + "fDX" put xSize + "fDY" put ySize + "fDZ" put zSize } /** * Create a GDML union */ operator fun Meta.plus(other: Meta) = buildMeta { - "fNode.fLeft" to this - "fNode.fRight" to other - "fNode._typename" to "TGeoUnion" + "fNode.fLeft" put this + "fNode.fRight" put other + "fNode._typename" put "TGeoUnion" } /** * Create a GDML subtraction */ operator fun Meta.minus(other: Meta) = buildMeta { - "fNode.fLeft" to this - "fNode.fRight" to other - "fNode._typename" to "TGeoSubtraction" + "fNode.fLeft" put this + "fNode.fRight" put other + "fNode._typename" put "TGeoSubtraction" } /** * Intersect two GDML geometries */ infix fun Meta.intersect(other: Meta) = buildMeta { - "fNode.fLeft" to this - "fNode.fRight" to other - "fNode._typename" to "TGeoIntersection" + "fNode.fLeft" put this + "fNode.fRight" put other + "fNode._typename" put "TGeoIntersection" } companion object { diff --git a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt index f4671bcc..6b11338c 100644 --- a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt +++ b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt @@ -54,7 +54,7 @@ class GDMLTransformer(val root: GDML) { obj.useStyle(styleName){ COLOR_KEY to Colors.rgbToString(random.nextInt(0, Int.MAX_VALUE)) - "gdml.material" to material.name + "gdml.material" put material.name } obj.solidConfiguration(parent, solid) diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Box.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Box.kt index 4d0f05be..e71803f1 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Box.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Box.kt @@ -47,9 +47,9 @@ class Box( } override fun MetaBuilder.updateMeta() { - "xSize" to xSize - "ySize" to ySize - "zSize" to ySize + "xSize" put xSize + "ySize" put ySize + "zSize" put ySize updatePosition() } diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt index 31f6f915..0b296fae 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt @@ -35,9 +35,9 @@ class Composite( override var properties: Config? = null override fun MetaBuilder.updateMeta() { - "compositeType" to compositeType - "first" to first.toMeta() - "second" to second.toMeta() + "compositeType" put compositeType + "first" put first.toMeta() + "second" put second.toMeta() updatePosition() } } diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Convex.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Convex.kt index 56062ca8..5f665bde 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Convex.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Convex.kt @@ -20,8 +20,8 @@ class Convex(val points: List) : AbstractVisualObject(), VisualObject3D override var scale: Point3D? = null override fun MetaBuilder.updateMeta() { - "points" to { - "point" to points.map { it.toMeta() } + "points" put { + "point" put points.map { it.toMeta() } } updatePosition() } diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Material3D.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Material3D.kt index aea1ed4c..e3947546 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Material3D.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Material3D.kt @@ -11,9 +11,9 @@ import hep.dataforge.vis.spatial.Material3D.Companion.OPACITY_KEY class Material3D(override val config: Config) : Specific { - val color by string() + var color by string() - val opacity by float(1f) + var opacity by float(1f) companion object : Specification { override fun wrap(config: Config): Material3D = Material3D(config) diff --git a/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/ConvexTest.kt b/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/ConvexTest.kt index beba580c..40cb4404 100644 --- a/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/ConvexTest.kt +++ b/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/ConvexTest.kt @@ -1,9 +1,8 @@ package hep.dataforge.vis.spatial import hep.dataforge.meta.get -import hep.dataforge.meta.getAll +import hep.dataforge.meta.getIndexed import hep.dataforge.meta.node -import hep.dataforge.names.toName import kotlin.test.Test import kotlin.test.assertEquals @@ -31,7 +30,7 @@ class ConvexTest { val pointsNode = convex.toMeta()["points"].node assertEquals(8, pointsNode?.items?.count()) - val points = pointsNode?.getAll("point".toName()) + val points = pointsNode?.getIndexed("points") assertEquals(8, convex.points.size) } diff --git a/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/GroupTest.kt b/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/GroupTest.kt index c1e81721..2608b53a 100644 --- a/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/GroupTest.kt +++ b/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/GroupTest.kt @@ -18,8 +18,8 @@ class GroupTest { } box(100, 100, 100) material { - "color" to Colors.lightgreen - "opacity" to 0.3 + color(Colors.lightgreen) + opacity = 0.3f } } intersect("intersect") { @@ -46,6 +46,6 @@ class GroupTest { assertEquals(3, group.count()) assertEquals(300.0, (group["intersect"] as VisualObject3D).y.toDouble()) - assertEquals(-300.0, (group["subtract"] as VisualObject3D).y.toDouble()) + assertEquals(-300.0, (group["subtract"] as VisualObject3D).y.toDouble()) } } \ No newline at end of file diff --git a/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt b/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt index 7841fb30..41751d9d 100644 --- a/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt +++ b/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt @@ -99,8 +99,8 @@ private class ThreeDemoApp : Application { } sphere(50) material { - "color" to Colors.lightgreen - "opacity" to 0.3 + color(Colors.lightgreen) + opacity = 0.3f } } composite(CompositeType.INTERSECT) { @@ -148,7 +148,7 @@ private class ThreeDemoApp : Application { } - override fun dispose() = emptyMap()//mapOf("lines" to presenter.dispose()) + override fun dispose() = emptyMap()//mapOf("lines" put presenter.dispose()) } fun main() { diff --git a/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoGrid.kt b/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoGrid.kt index 0f2b8283..ff8a2f88 100644 --- a/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoGrid.kt +++ b/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoGrid.kt @@ -35,7 +35,9 @@ class ThreeDemoGrid(meta: Meta) : AbstractPlugin(meta), OutputManager { private val gridRoot = document.create.div("row") private val outputs: MutableMap = HashMap() - override fun dependsOn(): List> = listOf(ThreePlugin) + init { + require(ThreePlugin) + } override fun attach(context: Context) { super.attach(context) @@ -52,9 +54,9 @@ class ThreeDemoGrid(meta: Meta) : AbstractPlugin(meta), OutputManager { return outputs.getOrPut(name) { if (type != VisualObject::class) error("Supports only DisplayObject") val output = three.output(meta = meta) { - "minSize" to 500 - "axis" to { - "size" to 500 + "minSize" put 500 + "axis" put { + "size" put 500 } } //TODO calculate cell width here using jquery @@ -85,7 +87,7 @@ class ThreeDemoGrid(meta: Meta) : AbstractPlugin(meta), OutputManager { fun ThreeDemoGrid.demo(name: String, title: String = name, block: VisualGroup3D.() -> Unit) { val meta = buildMeta { - "title" to title + "title" put title } val output = get(VisualObject::class, name.toName(), meta = meta) output.render(action = block) From 58e396f50c947eec733b3a84ed70210b02571c7b Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 3 Nov 2019 20:39:08 +0300 Subject: [PATCH 05/25] Updated serialization utils --- .../vis/spatial/gdml/generateSchema.kt | 169 ++++++++++++++++++ .../kotlin/hep/dataforge/vis/spatial/Box.kt | 2 +- .../hep/dataforge/vis/spatial/Composite.kt | 2 +- .../hep/dataforge/vis/spatial/ConeSegment.kt | 2 +- .../hep/dataforge/vis/spatial/Convex.kt | 2 +- .../hep/dataforge/vis/spatial/Extruded.kt | 2 +- .../hep/dataforge/vis/spatial/PolyLine.kt | 2 +- .../kotlin/hep/dataforge/vis/spatial/Proxy.kt | 4 +- .../hep/dataforge/vis/spatial/Sphere.kt | 2 +- .../kotlin/hep/dataforge/vis/spatial/Tube.kt | 2 +- .../dataforge/vis/spatial/Visual3DPlugin.kt | 4 +- .../dataforge/vis/spatial/VisualGroup3D.kt | 4 +- .../hep/dataforge/vis/spatial/serilization.kt | 80 +++++++-- .../vis/spatial/SerializationTest.kt | 2 + 14 files changed, 252 insertions(+), 27 deletions(-) create mode 100644 dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/generateSchema.kt diff --git a/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/generateSchema.kt b/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/generateSchema.kt new file mode 100644 index 00000000..fc417efb --- /dev/null +++ b/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/generateSchema.kt @@ -0,0 +1,169 @@ +package hep.dataforge.vis.spatial.gdml + +import hep.dataforge.meta.Meta +import hep.dataforge.vis.spatial.* +import kotlinx.serialization.* +import kotlinx.serialization.json.* +import kotlinx.serialization.modules.SerialModule +import kotlinx.serialization.modules.SerialModuleCollector +import kotlin.reflect.KClass + +internal val SerialDescriptor.jsonType + get() = when (this.kind) { + StructureKind.LIST -> "array" + PrimitiveKind.BYTE, PrimitiveKind.SHORT, PrimitiveKind.INT, PrimitiveKind.LONG, + PrimitiveKind.FLOAT, PrimitiveKind.DOUBLE -> "number" + PrimitiveKind.STRING, PrimitiveKind.CHAR, UnionKind.ENUM_KIND -> "string" + PrimitiveKind.BOOLEAN -> "boolean" + else -> "object" + } + + +private fun SerialModule.enumerate(type: KClass<*>): Sequence { + val list = ArrayList() + fun send(descriptor: SerialDescriptor) = list.add(descriptor) + + val enumerator = object : SerialModuleCollector { + override fun contextual(kClass: KClass, serializer: KSerializer) { + if (kClass == type) { + send(serializer.descriptor) + } + } + + override fun polymorphic( + baseClass: KClass, + actualClass: KClass, + actualSerializer: KSerializer + ) { + if (baseClass == type) { + send(actualSerializer.descriptor) + } + } + + } + dumpTo(enumerator) + return list.asSequence() +} + +/** + * Creates an [JsonObject] which contains Json Schema of given [descriptor]. + * + * Schema can contain following fields: + * `description`, `type` for all descriptors; + * `properties` and `required` for objects; + * `enum` for enums; + * `items` for arrays. + * + * User can modify this schema to add additional validation keywords + * (as per [https://json-schema.org/latest/json-schema-validation.html]) + * if they want. + */ +private fun jsonSchema(descriptor: SerialDescriptor, context: SerialModule): JsonObject { + + if (descriptor.name in arrayOf( + "hep.dataforge.vis.spatial.Point3D", + "hep.dataforge.vis.spatial.Point2D", + Meta::class.qualifiedName + ) + ) return json { + "\$ref" to "#/definitions/${descriptor.name}" + } + + + val properties: MutableMap = mutableMapOf() + val requiredProperties: MutableSet = mutableSetOf() + val isEnum = descriptor.kind == UnionKind.ENUM_KIND + val isPolymorphic = descriptor.kind == UnionKind.POLYMORPHIC + + + if (!isEnum && !isPolymorphic) descriptor.elementDescriptors().forEachIndexed { index, child -> + val elementName = descriptor.getElementName(index) + + properties[elementName] = when (elementName) { + "templates" -> json { + "\$ref" to "#/definitions/hep.dataforge.vis.spatial.VisualGroup3D" + } + "properties" -> json { + "\$ref" to "#/definitions/${Meta::class.qualifiedName}" + } + "first", "second" -> json{ + "\$ref" to "#/definitions/children" + } + "styleSheet" -> json { + "type" to "object" + "additionalProperties" to json { + "\$ref" to "#/definitions/${Meta::class.qualifiedName}" + } + } + in arrayOf("children") -> json { + "type" to "object" + "additionalProperties" to json { + "\$ref" to "#/definitions/children" + } + } + else -> jsonSchema(child, context) + } + + if (!descriptor.isElementOptional(index)) requiredProperties.add(elementName) + } + + val jsonType = descriptor.jsonType + val objectData: MutableMap = mutableMapOf( + "description" to JsonLiteral(descriptor.name), + "type" to JsonLiteral(jsonType) + ) + if (isEnum) { + val allElementNames = (0 until descriptor.elementsCount).map(descriptor::getElementName) + objectData += "enum" to JsonArray(allElementNames.map(::JsonLiteral)) + } + when (jsonType) { + "object" -> { + objectData["properties"] = JsonObject(properties) + val required = requiredProperties.map { JsonLiteral(it) } + if (required.isNotEmpty()) { + objectData["required"] = JsonArray(required) + } + } + "array" -> objectData["items"] = properties.values.let { + check(it.size == 1) { "Array descriptor has returned inconsistent number of elements: expected 1, found ${it.size}" } + it.first() + } + else -> { /* no-op */ + } + } + return JsonObject(objectData) +} + +fun main() { + val context = Visual3DPlugin.serialModule + val definitions = json { + "children" to json { + "anyOf" to jsonArray { + context.enumerate(VisualObject3D::class).forEach { + if (it.name == "hep.dataforge.vis.spatial.VisualGroup3D") { + +json { + "\$ref" to "#/definitions/${it.name}" + } + } else { + +jsonSchema(it, context) + } + } + } + } + "hep.dataforge.vis.spatial.Point3D" to jsonSchema(Point3DSerializer.descriptor, context) + "hep.dataforge.vis.spatial.Point2D" to jsonSchema(Point2DSerializer.descriptor, context) + "hep.dataforge.vis.spatial.VisualGroup3D" to jsonSchema(VisualGroup3D.serializer().descriptor, context) + + } + + println( + Json.indented.stringify( + JsonObjectSerializer, + json { + "definitions" to definitions + "\$ref" to "#/definitions/hep.dataforge.vis.spatial.VisualGroup3D" + } + ) + ) +} + diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Box.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Box.kt index e71803f1..8b78f991 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Box.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Box.kt @@ -2,7 +2,7 @@ package hep.dataforge.vis.spatial import hep.dataforge.context.Context -import hep.dataforge.io.ConfigSerializer +import hep.dataforge.io.serialization.ConfigSerializer import hep.dataforge.meta.* import hep.dataforge.vis.common.AbstractVisualObject import hep.dataforge.vis.common.VisualFactory diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt index 0b296fae..ba20b4b3 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt @@ -1,7 +1,7 @@ @file:UseSerializers(Point3DSerializer::class) package hep.dataforge.vis.spatial -import hep.dataforge.io.ConfigSerializer +import hep.dataforge.io.serialization.ConfigSerializer import hep.dataforge.meta.Config import hep.dataforge.meta.MetaBuilder import hep.dataforge.meta.update diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/ConeSegment.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/ConeSegment.kt index 26d4942f..db87acc7 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/ConeSegment.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/ConeSegment.kt @@ -2,7 +2,7 @@ package hep.dataforge.vis.spatial -import hep.dataforge.io.ConfigSerializer +import hep.dataforge.io.serialization.ConfigSerializer import hep.dataforge.meta.Config import hep.dataforge.vis.common.AbstractVisualObject import kotlinx.serialization.Serializable diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Convex.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Convex.kt index 5f665bde..7231f6c2 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Convex.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Convex.kt @@ -2,7 +2,7 @@ package hep.dataforge.vis.spatial -import hep.dataforge.io.ConfigSerializer +import hep.dataforge.io.serialization.ConfigSerializer import hep.dataforge.meta.Config import hep.dataforge.meta.MetaBuilder import hep.dataforge.vis.common.AbstractVisualObject diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Extruded.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Extruded.kt index 32e8082d..7255b7ef 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Extruded.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Extruded.kt @@ -1,7 +1,7 @@ @file:UseSerializers(Point2DSerializer::class, Point3DSerializer::class) package hep.dataforge.vis.spatial -import hep.dataforge.io.ConfigSerializer +import hep.dataforge.io.serialization.ConfigSerializer import hep.dataforge.meta.Config import hep.dataforge.vis.common.AbstractVisualObject import kotlinx.serialization.Serializable diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/PolyLine.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/PolyLine.kt index eb8b4699..3e0e554b 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/PolyLine.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/PolyLine.kt @@ -2,7 +2,7 @@ package hep.dataforge.vis.spatial -import hep.dataforge.io.ConfigSerializer +import hep.dataforge.io.serialization.ConfigSerializer import hep.dataforge.meta.Config import hep.dataforge.vis.common.AbstractVisualObject import hep.dataforge.vis.common.number diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt index 4dd11e79..60756f7a 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt @@ -2,7 +2,7 @@ package hep.dataforge.vis.spatial -import hep.dataforge.io.ConfigSerializer +import hep.dataforge.io.serialization.ConfigSerializer import hep.dataforge.io.serialization.NameSerializer import hep.dataforge.meta.* @@ -15,6 +15,7 @@ import hep.dataforge.vis.common.MutableVisualGroup import hep.dataforge.vis.common.VisualGroup import hep.dataforge.vis.common.VisualObject import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient import kotlinx.serialization.UseSerializers import kotlin.collections.component1 import kotlin.collections.component2 @@ -72,6 +73,7 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua ProxyChild(it.key.asName()) } ?: emptyMap() + @Transient private val propertyCache: HashMap = HashMap() fun childPropertyName(childName: Name, propertyName: Name): Name { diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Sphere.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Sphere.kt index 7cc2c411..ab7b79f9 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Sphere.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Sphere.kt @@ -2,7 +2,7 @@ package hep.dataforge.vis.spatial -import hep.dataforge.io.ConfigSerializer +import hep.dataforge.io.serialization.ConfigSerializer import hep.dataforge.meta.Config import hep.dataforge.vis.common.AbstractVisualObject import kotlinx.serialization.Serializable diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Tube.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Tube.kt index 77f707ee..384f3cfb 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Tube.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Tube.kt @@ -1,7 +1,7 @@ @file:UseSerializers(Point3DSerializer::class) package hep.dataforge.vis.spatial -import hep.dataforge.io.ConfigSerializer +import hep.dataforge.io.serialization.ConfigSerializer import hep.dataforge.meta.Config import hep.dataforge.vis.common.AbstractVisualObject import kotlinx.serialization.Serializable diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Visual3DPlugin.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Visual3DPlugin.kt index 093c7cfe..39c62bc2 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Visual3DPlugin.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Visual3DPlugin.kt @@ -4,8 +4,8 @@ import hep.dataforge.context.AbstractPlugin import hep.dataforge.context.Context import hep.dataforge.context.PluginFactory import hep.dataforge.context.PluginTag -import hep.dataforge.io.ConfigSerializer -import hep.dataforge.io.MetaSerializer +import hep.dataforge.io.serialization.ConfigSerializer +import hep.dataforge.io.serialization.MetaSerializer import hep.dataforge.io.serialization.NameSerializer import hep.dataforge.meta.* import hep.dataforge.names.Name diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt index fca6f7ed..622f345d 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt @@ -8,8 +8,8 @@ package hep.dataforge.vis.spatial -import hep.dataforge.io.ConfigSerializer -import hep.dataforge.io.MetaSerializer +import hep.dataforge.io.serialization.ConfigSerializer +import hep.dataforge.io.serialization.MetaSerializer import hep.dataforge.io.serialization.NameSerializer import hep.dataforge.meta.Config import hep.dataforge.meta.Meta diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/serilization.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/serilization.kt index c7b3cbfa..b4f87d39 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/serilization.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/serilization.kt @@ -1,45 +1,97 @@ package hep.dataforge.vis.spatial +import hep.dataforge.io.serialization.descriptor import hep.dataforge.names.NameToken import hep.dataforge.names.toName import kotlinx.serialization.* +import kotlinx.serialization.internal.DoubleSerializer import kotlinx.serialization.internal.StringDescriptor +import kotlinx.serialization.internal.nullable -@Serializable -private data class Point2DSerial(val x: Double, val y: Double) +inline fun Decoder.decodeStructure( + desc: SerialDescriptor, + vararg typeParams: KSerializer<*> = emptyArray(), + crossinline block: CompositeDecoder.() -> R +): R { + val decoder = beginStructure(desc, *typeParams) + val res = decoder.block() + decoder.endStructure(desc) + return res +} -@Serializable -private data class Point3DSerial(val x: Double, val y: Double, val z: Double) +inline fun Encoder.encodeStructure( + desc: SerialDescriptor, + vararg typeParams: KSerializer<*> = emptyArray(), + block: CompositeEncoder.() -> Unit +) { + val encoder = beginStructure(desc, *typeParams) + encoder.block() + encoder.endStructure(desc) +} @Serializer(Point3D::class) object Point3DSerializer : KSerializer { - private val serializer = Point3DSerial.serializer() - override val descriptor: SerialDescriptor get() = serializer.descriptor + override val descriptor: SerialDescriptor = descriptor("hep.dataforge.vis.spatial.Point3D") { + double("x", true) + double("y", true) + double("z", true) + } override fun deserialize(decoder: Decoder): Point3D { - return serializer.deserialize(decoder).let { - Point3D(it.x, it.y, it.z) + var x: Double? = null + var y: Double? = null + var z: Double? = null + decoder.decodeStructure(descriptor) { + loop@ while (true) { + when (val i = decodeElementIndex(descriptor)) { + CompositeDecoder.READ_DONE -> break@loop + 0 -> x = decodeNullableSerializableElement(descriptor, 0, DoubleSerializer.nullable) ?: 0.0 + 1 -> y = decodeNullableSerializableElement(descriptor, 0, DoubleSerializer.nullable) ?: 0.0 + 2 -> z = decodeNullableSerializableElement(descriptor, 0, DoubleSerializer.nullable) ?: 0.0 + else -> throw SerializationException("Unknown index $i") + } + } } + return Point3D(x?:0.0, y?:0.0, z?:0.0) } override fun serialize(encoder: Encoder, obj: Point3D) { - serializer.serialize(encoder, Point3DSerial(obj.x, obj.y, obj.z)) + encoder.encodeStructure(descriptor) { + if (obj.x != 0.0) encodeDoubleElement(descriptor, 0, obj.x) + if (obj.y != 0.0) encodeDoubleElement(descriptor, 1, obj.y) + if (obj.z != 0.0) encodeDoubleElement(descriptor, 2, obj.z) + } } } @Serializer(Point2D::class) object Point2DSerializer : KSerializer { - private val serializer = Point2DSerial.serializer() - override val descriptor: SerialDescriptor get() = serializer.descriptor + override val descriptor: SerialDescriptor = descriptor("hep.dataforge.vis.spatial.Point2D") { + double("x", true) + double("y", true) + } override fun deserialize(decoder: Decoder): Point2D { - return serializer.deserialize(decoder).let { - Point2D(it.x, it.y) + var x: Double? = null + var y: Double? = null + decoder.decodeStructure(descriptor) { + loop@ while (true) { + when (val i = decodeElementIndex(descriptor)) { + CompositeDecoder.READ_DONE -> break@loop + 0 -> x = decodeNullableSerializableElement(descriptor, 0, DoubleSerializer.nullable) ?: 0.0 + 1 -> y = decodeNullableSerializableElement(descriptor, 0, DoubleSerializer.nullable) ?: 0.0 + else -> throw SerializationException("Unknown index $i") + } + } } + return Point2D(x?:0.0, y?:0.0) } override fun serialize(encoder: Encoder, obj: Point2D) { - serializer.serialize(encoder, Point2DSerial(obj.x, obj.y)) + encoder.encodeStructure(descriptor) { + if (obj.x != 0.0) encodeDoubleElement(descriptor, 0, obj.x) + if (obj.y != 0.0) encodeDoubleElement(descriptor, 1, obj.y) + } } } diff --git a/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/SerializationTest.kt b/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/SerializationTest.kt index 09d59f29..958f98c3 100644 --- a/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/SerializationTest.kt +++ b/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/SerializationTest.kt @@ -11,6 +11,8 @@ class SerializationTest { fun testCubeSerialization(){ val cube = Box(100f,100f,100f).apply{ color(222) + x = 100 + z = -100 } val string = json.stringify(Box.serializer(),cube) println(string) From 3b6fd6692075a43e18505dd8d8dc6abc7ffe61c0 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 4 Nov 2019 22:45:00 +0300 Subject: [PATCH 06/25] Resizable boxes and optimizations --- build.gradle.kts | 2 +- .../vis/common/AbstractVisualGroup.kt | 14 --- .../vis/common/AbstractVisualObject.kt | 8 -- .../kotlin/hep/dataforge/vis/spatial/Box.kt | 23 ++-- .../hep/dataforge/vis/spatial/Composite.kt | 10 +- .../hep/dataforge/vis/spatial/ConeSegment.kt | 4 + .../hep/dataforge/vis/spatial/Convex.kt | 10 +- .../hep/dataforge/vis/spatial/Extruded.kt | 4 + .../hep/dataforge/vis/spatial/Material3D.kt | 2 +- .../hep/dataforge/vis/spatial/PolyLine.kt | 4 + .../kotlin/hep/dataforge/vis/spatial/Proxy.kt | 15 ++- .../hep/dataforge/vis/spatial/Sphere.kt | 4 + .../kotlin/hep/dataforge/vis/spatial/Tube.kt | 4 + .../dataforge/vis/spatial/VisualGroup3D.kt | 9 +- .../dataforge/vis/spatial/VisualObject3D.kt | 2 +- .../dataforge/vis/spatial/three/Materials.kt | 96 ---------------- .../vis/spatial/three/MeshThreeFactory.kt | 45 ++++++-- .../vis/spatial/three/ThreeFactory.kt | 3 +- .../vis/spatial/three/ThreeLineFactory.kt | 5 +- .../vis/spatial/three/ThreeMaterials.kt | 103 ++++++++++++++++++ .../vis/spatial/three/ThreePlugin.kt | 3 +- .../vis/spatial/three/ThreeVisualObject.kt | 39 +++++++ .../hep/dataforge/vis/spatial/three/three.kt | 24 +++- spatial-js-demo/build.gradle.kts | 10 ++ .../vis/spatial/demo/ThreeDemoApp.kt | 25 ++++- .../dataforge/vis/spatial/demo/VariableBox.kt | 69 ++++++++++++ 26 files changed, 355 insertions(+), 182 deletions(-) delete mode 100644 dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/Materials.kt create mode 100644 dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeMaterials.kt create mode 100644 dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeVisualObject.kt create mode 100644 spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/VariableBox.kt diff --git a/build.gradle.kts b/build.gradle.kts index edf19391..a8d57674 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,7 +2,7 @@ val dataforgeVersion by extra("0.1.4") plugins { val kotlinVersion = "1.3.50" - val toolsVersion = "0.2.1" + val toolsVersion = "0.2.2" kotlin("jvm") version kotlinVersion apply false id("kotlin-dce-js") version kotlinVersion apply false diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualGroup.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualGroup.kt index c8637618..921617c8 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualGroup.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualGroup.kt @@ -1,7 +1,6 @@ package hep.dataforge.vis.common import hep.dataforge.meta.Meta -import hep.dataforge.meta.MetaBuilder import hep.dataforge.meta.MetaItem import hep.dataforge.names.* import kotlinx.serialization.Transient @@ -145,17 +144,4 @@ abstract class AbstractVisualGroup : AbstractVisualObject(), MutableVisualGroup } else { set(key.asName(), child) } - -// operator fun set(key: String?, child: VisualObject?) = set(key ?: "", child) - - protected fun MetaBuilder.updateChildren() { - //adding named children - children.forEach { - "children[${it.key}]" put it.value.toMeta() - } - } - - override fun MetaBuilder.updateMeta() { - updateChildren() - } } \ No newline at end of file diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualObject.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualObject.kt index 5a4a0639..e0808e75 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualObject.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualObject.kt @@ -82,14 +82,6 @@ abstract class AbstractVisualObject : VisualObject { properties?.get(name) ?: mergedStyles[name] } } - - protected open fun MetaBuilder.updateMeta() {} - - override fun toMeta(): Meta = buildMeta { - "type" putValue this::class.simpleName - "properties" put properties - updateMeta() - } } fun VisualObject.findStyle(styleName: Name): Meta? { diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Box.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Box.kt index 8b78f991..571a1ff8 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Box.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Box.kt @@ -3,7 +3,11 @@ package hep.dataforge.vis.spatial import hep.dataforge.context.Context import hep.dataforge.io.serialization.ConfigSerializer -import hep.dataforge.meta.* +import hep.dataforge.io.toMeta +import hep.dataforge.meta.Config +import hep.dataforge.meta.Meta +import hep.dataforge.meta.float +import hep.dataforge.meta.get import hep.dataforge.vis.common.AbstractVisualObject import hep.dataforge.vis.common.VisualFactory import hep.dataforge.vis.common.VisualObject @@ -27,9 +31,9 @@ class Box( //TODO add helper for color configuration override fun toGeometry(geometryBuilder: GeometryBuilder) { - val dx = xSize.toFloat() / 2 - val dy = ySize.toFloat() / 2 - val dz = zSize.toFloat() / 2 + val dx = xSize / 2 + val dy = ySize / 2 + val dz = zSize / 2 val node1 = Point3D(-dx, -dy, -dz) val node2 = Point3D(dx, -dy, -dz) val node3 = Point3D(dx, dy, -dz) @@ -46,16 +50,7 @@ class Box( geometryBuilder.face4(node8, node5, node6, node7) } - override fun MetaBuilder.updateMeta() { - "xSize" put xSize - "ySize" put ySize - "zSize" put ySize - updatePosition() - } - -// override fun toMeta(): Meta { -// return (Visual3DPlugin.json.toJson(Box.serializer(), this) as JsonObject).toMeta() -// } + override fun toMeta(): Meta = Visual3DPlugin.json.toJson(serializer(), this).toMeta() companion object : VisualFactory { const val TYPE = "geometry.3d.box" diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt index ba20b4b3..4e920800 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt @@ -2,8 +2,9 @@ package hep.dataforge.vis.spatial import hep.dataforge.io.serialization.ConfigSerializer +import hep.dataforge.io.toMeta import hep.dataforge.meta.Config -import hep.dataforge.meta.MetaBuilder +import hep.dataforge.meta.Meta import hep.dataforge.meta.update import hep.dataforge.vis.common.AbstractVisualObject import kotlinx.serialization.Serializable @@ -34,12 +35,7 @@ class Composite( @Serializable(ConfigSerializer::class) override var properties: Config? = null - override fun MetaBuilder.updateMeta() { - "compositeType" put compositeType - "first" put first.toMeta() - "second" put second.toMeta() - updatePosition() - } + override fun toMeta(): Meta = Visual3DPlugin.json.toJson(serializer(), this).toMeta() } inline fun VisualGroup3D.composite( diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/ConeSegment.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/ConeSegment.kt index db87acc7..b1533a83 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/ConeSegment.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/ConeSegment.kt @@ -3,7 +3,9 @@ package hep.dataforge.vis.spatial import hep.dataforge.io.serialization.ConfigSerializer +import hep.dataforge.io.toMeta import hep.dataforge.meta.Config +import hep.dataforge.meta.Meta import hep.dataforge.vis.common.AbstractVisualObject import kotlinx.serialization.Serializable import kotlinx.serialization.UseSerializers @@ -26,6 +28,8 @@ class ConeSegment( override var position: Point3D? = null override var rotation: Point3D? = null override var scale: Point3D? = null + + override fun toMeta(): Meta = Visual3DPlugin.json.toJson(serializer(), this).toMeta() } inline fun VisualGroup3D.cylinder( diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Convex.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Convex.kt index 7231f6c2..3d9f03d5 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Convex.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Convex.kt @@ -3,8 +3,9 @@ package hep.dataforge.vis.spatial import hep.dataforge.io.serialization.ConfigSerializer +import hep.dataforge.io.toMeta import hep.dataforge.meta.Config -import hep.dataforge.meta.MetaBuilder +import hep.dataforge.meta.Meta import hep.dataforge.vis.common.AbstractVisualObject import kotlinx.serialization.Serializable import kotlinx.serialization.UseSerializers @@ -19,12 +20,7 @@ class Convex(val points: List) : AbstractVisualObject(), VisualObject3D override var rotation: Point3D? = null override var scale: Point3D? = null - override fun MetaBuilder.updateMeta() { - "points" put { - "point" put points.map { it.toMeta() } - } - updatePosition() - } + override fun toMeta(): Meta = Visual3DPlugin.json.toJson(serializer(), this).toMeta() companion object { const val TYPE = "geometry.3d.convex" diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Extruded.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Extruded.kt index 7255b7ef..c0bb0fb1 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Extruded.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Extruded.kt @@ -2,7 +2,9 @@ package hep.dataforge.vis.spatial import hep.dataforge.io.serialization.ConfigSerializer +import hep.dataforge.io.toMeta import hep.dataforge.meta.Config +import hep.dataforge.meta.Meta import hep.dataforge.vis.common.AbstractVisualObject import kotlinx.serialization.Serializable import kotlinx.serialization.UseSerializers @@ -105,6 +107,8 @@ class Extruded( geometryBuilder.cap(layers.last()) } + override fun toMeta(): Meta = Visual3DPlugin.json.toJson(serializer(), this).toMeta() + companion object { const val TYPE = "geometry.3d.extruded" } diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Material3D.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Material3D.kt index e3947546..645c0cf5 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Material3D.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Material3D.kt @@ -31,7 +31,7 @@ fun VisualObject.color(rgb: String) { fun VisualObject.color(rgb: Int) = color(Colors.rgbToString(rgb)) -fun VisualObject.color(r: UByte, g: UByte, b: UByte) = color( Colors.rgbToString(r,g,b)) +fun VisualObject.color(r: UByte, g: UByte, b: UByte) = color(Colors.rgbToString(r, g, b)) var VisualObject.color: String? get() = getProperty(COLOR_KEY).string diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/PolyLine.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/PolyLine.kt index 3e0e554b..001c1e40 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/PolyLine.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/PolyLine.kt @@ -3,7 +3,9 @@ package hep.dataforge.vis.spatial import hep.dataforge.io.serialization.ConfigSerializer +import hep.dataforge.io.toMeta import hep.dataforge.meta.Config +import hep.dataforge.meta.Meta import hep.dataforge.vis.common.AbstractVisualObject import hep.dataforge.vis.common.number import kotlinx.serialization.Serializable @@ -20,6 +22,8 @@ class PolyLine(var points: List) : AbstractVisualObject(), VisualObject //var lineType by string() var thickness by number(1.0, key = "material.thickness") + + override fun toMeta(): Meta = Visual3DPlugin.json.toJson(serializer(), this).toMeta() } fun VisualGroup3D.polyline(vararg points: Point3D, name: String = "", action: PolyLine.() -> Unit = {}) = diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt index 60756f7a..e5ea3be6 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt @@ -3,9 +3,12 @@ package hep.dataforge.vis.spatial import hep.dataforge.io.serialization.ConfigSerializer - import hep.dataforge.io.serialization.NameSerializer -import hep.dataforge.meta.* +import hep.dataforge.io.toMeta +import hep.dataforge.meta.Config +import hep.dataforge.meta.Meta +import hep.dataforge.meta.MetaItem +import hep.dataforge.meta.get import hep.dataforge.names.Name import hep.dataforge.names.NameToken import hep.dataforge.names.asName @@ -61,10 +64,7 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua } } - override fun MetaBuilder.updateMeta() { - //TODO add reference to child - updatePosition() - } + override fun toMeta(): Meta = Visual3DPlugin.json.toJson(serializer(), this).toMeta() override val children: Map get() = (prototype as? MutableVisualGroup)?.children @@ -94,6 +94,7 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua //override fun findAllStyles(): Laminate = Laminate((styles + prototype.styles).mapNotNull { findStyle(it) }) + @Serializable inner class ProxyChild(val name: Name) : AbstractVisualObject(), VisualGroup { val prototype: VisualObject by lazy { @@ -143,6 +144,8 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua } } + override fun toMeta(): Meta = Visual3DPlugin.json.toJson(serializer(), this).toMeta() + } companion object { diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Sphere.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Sphere.kt index ab7b79f9..1b210c75 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Sphere.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Sphere.kt @@ -3,7 +3,9 @@ package hep.dataforge.vis.spatial import hep.dataforge.io.serialization.ConfigSerializer +import hep.dataforge.io.toMeta import hep.dataforge.meta.Config +import hep.dataforge.meta.Meta import hep.dataforge.vis.common.AbstractVisualObject import kotlinx.serialization.Serializable import kotlinx.serialization.UseSerializers @@ -24,6 +26,8 @@ class Sphere( override var position: Point3D? = null override var rotation: Point3D? = null override var scale: Point3D? = null + + override fun toMeta(): Meta = Visual3DPlugin.json.toJson(serializer(), this).toMeta() } inline fun VisualGroup3D.sphere( diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Tube.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Tube.kt index 384f3cfb..ccf6a62f 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Tube.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Tube.kt @@ -2,7 +2,9 @@ package hep.dataforge.vis.spatial import hep.dataforge.io.serialization.ConfigSerializer +import hep.dataforge.io.toMeta import hep.dataforge.meta.Config +import hep.dataforge.meta.Meta import hep.dataforge.vis.common.AbstractVisualObject import kotlinx.serialization.Serializable import kotlinx.serialization.UseSerializers @@ -123,6 +125,8 @@ class Tube( } } } + + override fun toMeta(): Meta = Visual3DPlugin.json.toJson(serializer(), this).toMeta() } inline fun VisualGroup3D.tube( diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt index 622f345d..071623b7 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt @@ -11,10 +11,9 @@ package hep.dataforge.vis.spatial import hep.dataforge.io.serialization.ConfigSerializer import hep.dataforge.io.serialization.MetaSerializer import hep.dataforge.io.serialization.NameSerializer +import hep.dataforge.io.toMeta import hep.dataforge.meta.Config import hep.dataforge.meta.Meta -import hep.dataforge.meta.MetaBuilder -import hep.dataforge.meta.set import hep.dataforge.names.Name import hep.dataforge.names.NameToken import hep.dataforge.names.asName @@ -98,11 +97,7 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D { } } - override fun MetaBuilder.updateMeta() { - set(PROTOTYPES_KEY, prototypes?.toMeta()) - updatePosition() - updateChildren() - } + override fun toMeta(): Meta = Visual3DPlugin.json.toJson(serializer(), this).toMeta() companion object { const val PROTOTYPES_KEY = "templates" diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt index 1f26ff0b..6992e0ec 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt @@ -40,7 +40,7 @@ interface VisualObject3D : VisualObject { val LAYER_KEY = "layer".asName() val IGNORE_KEY = "ignore".asName() - val GEOMETRY_KEY = "geometey".asName() + val GEOMETRY_KEY = "geometry".asName() val x = "x".asName() val y = "y".asName() diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/Materials.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/Materials.kt deleted file mode 100644 index 8e575169..00000000 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/Materials.kt +++ /dev/null @@ -1,96 +0,0 @@ -package hep.dataforge.vis.spatial.three - -import hep.dataforge.meta.* -import hep.dataforge.values.ValueType -import hep.dataforge.vis.common.Colors -import hep.dataforge.vis.spatial.Material3D -import info.laht.threekt.materials.LineBasicMaterial -import info.laht.threekt.materials.Material -import info.laht.threekt.materials.MeshBasicMaterial -import info.laht.threekt.materials.MeshPhongMaterial -import info.laht.threekt.math.Color - - -object Materials { - val DEFAULT_COLOR = Color(Colors.darkgreen) - val DEFAULT = MeshPhongMaterial().apply { - color.set(DEFAULT_COLOR) - } - val DEFAULT_LINE_COLOR = Color(Colors.black) - val DEFAULT_LINE = LineBasicMaterial().apply { - color.set(DEFAULT_LINE_COLOR) - } - - - private val materialCache = HashMap() - private val lineMaterialCache = HashMap() - - fun getMaterial(meta: Meta): Material = materialCache.getOrPut(meta) { - MeshBasicMaterial().apply { - color = meta["color"]?.color() ?: DEFAULT_COLOR - opacity = meta["opacity"]?.double ?: 1.0 - transparent = meta["transparent"].boolean ?: (opacity < 1.0) - //node["specularColor"]?.let { specular = it.color() } - //side = 2 - } - } - - fun getLineMaterial(meta: Meta): Material = lineMaterialCache.getOrPut(meta) { - LineBasicMaterial().apply { - color = meta["color"]?.color() ?: DEFAULT_LINE_COLOR - opacity = meta["opacity"].double ?: 1.0 - transparent = meta["transparent"].boolean ?: (opacity < 1.0) - linewidth = meta["thickness"].double ?: 1.0 - } - } - - -} - -/** - * Infer color based on meta item - */ -fun MetaItem<*>.color(): Color { - return when (this) { - is MetaItem.ValueItem -> if (this.value.type == ValueType.STRING) { - Color(this.value.string) - } else { - val int = value.number.toInt() -// val red = int and 0x00ff0000 shr 16 -// val green = int and 0x0000ff00 shr 8 -// val blue = int and 0x000000ff - Color(int) - } - is MetaItem.NodeItem -> { - Color( - node["red"]?.int ?: 0, - node["green"]?.int ?: 0, - node["blue"]?.int ?: 0 - ) - } - } -} - -/** - * Infer Three material based on meta item - */ -fun Meta?.jsMaterial(): Material { - return if (this == null) { - Materials.DEFAULT - } else { - Materials.getMaterial(this) - } -} - -fun Meta?.jsLineMaterial(): Material { - return if (this == null) { - Materials.DEFAULT_LINE - } else{ - Materials.getLineMaterial(this) - } -} - - -fun Material3D?.jsMaterial(): Material = this?.config.jsMaterial() -fun Material3D?.jsLineMaterial(): Material = this?.config.jsLineMaterial() - diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/MeshThreeFactory.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/MeshThreeFactory.kt index 19745507..35898398 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/MeshThreeFactory.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/MeshThreeFactory.kt @@ -1,6 +1,8 @@ package hep.dataforge.vis.spatial.three +import hep.dataforge.meta.Meta import hep.dataforge.meta.boolean +import hep.dataforge.meta.get import hep.dataforge.meta.node import hep.dataforge.names.asName import hep.dataforge.names.plus @@ -8,10 +10,10 @@ import hep.dataforge.names.startsWith import hep.dataforge.vis.spatial.Material3D import hep.dataforge.vis.spatial.VisualObject3D import hep.dataforge.vis.spatial.layer -import hep.dataforge.vis.spatial.material import info.laht.threekt.core.BufferGeometry import info.laht.threekt.geometries.EdgesGeometry import info.laht.threekt.geometries.WireframeGeometry +import info.laht.threekt.materials.MeshBasicMaterial import info.laht.threekt.objects.LineSegments import info.laht.threekt.objects.Mesh import kotlin.reflect.KClass @@ -28,47 +30,63 @@ abstract class MeshThreeFactory( abstract fun buildGeometry(obj: T): BufferGeometry private fun Mesh.applyEdges(obj: T) { - children.find { it.name == "edges" }?.let { remove(it) } + children.find { it.name == "edges" }?.let { + remove(it) + (it as LineSegments).dispose() + } //inherited edges definition, enabled by default if (obj.getProperty(EDGES_ENABLED_KEY).boolean != false) { - val material = obj.getProperty(EDGES_MATERIAL_KEY).node.jsLineMaterial() + + val material = ThreeMaterials.getLineMaterial(obj.getProperty(EDGES_MATERIAL_KEY).node) add( LineSegments( EdgesGeometry(geometry as BufferGeometry), material - ) + ).apply { + name = "edges" + } ) } } private fun Mesh.applyWireFrame(obj: T) { - children.find { it.name == "wireframe" }?.let { remove(it) } + children.find { it.name == "wireframe" }?.let { + remove(it) + (it as LineSegments).dispose() + } //inherited wireframe definition, disabled by default if (obj.getProperty(WIREFRAME_ENABLED_KEY).boolean == true) { - val material = obj.getProperty(WIREFRAME_MATERIAL_KEY).node.jsLineMaterial() + val material = ThreeMaterials.getLineMaterial(obj.getProperty(WIREFRAME_MATERIAL_KEY).node) add( LineSegments( WireframeGeometry(geometry as BufferGeometry), material - ) + ).apply { + name = "wireframe" + } ) } } override fun invoke(obj: T): Mesh { - //TODO add caching for geometries using templates val geometry = buildGeometry(obj) //JS sometimes tries to pass Geometry as BufferGeometry @Suppress("USELESS_IS_CHECK") if (geometry !is BufferGeometry) error("BufferGeometry expected") - val mesh = Mesh(geometry, obj.material.jsMaterial()).apply { + val meshMeta: Meta = obj.properties[Material3D.MATERIAL_KEY]?.node ?: Meta.empty + + val mesh = Mesh(geometry, MeshBasicMaterial()).apply { matrixAutoUpdate = false applyEdges(obj) applyWireFrame(obj) + //set position for mesh updatePosition(obj) + //set color for mesh + updateMaterial(obj) + layers.enable(obj.layer) children.forEach { it.layers.enable(obj.layer) @@ -78,7 +96,14 @@ abstract class MeshThreeFactory( //add listener to object properties obj.onPropertyChange(this) { name, _, _ -> when { - name.startsWith(VisualObject3D.GEOMETRY_KEY) -> mesh.geometry = buildGeometry(obj) + name.startsWith(VisualObject3D.GEOMETRY_KEY) -> { + val oldGeometry = mesh.geometry as BufferGeometry + val newGeometry = buildGeometry(obj) + oldGeometry.attributes = newGeometry.attributes + mesh.applyWireFrame(obj) + mesh.applyEdges(obj) + newGeometry.dispose() + } name.startsWith(WIREFRAME_KEY) -> mesh.applyWireFrame(obj) name.startsWith(EDGES_KEY) -> mesh.applyEdges(obj) else -> mesh.updateProperty(obj, name) diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeFactory.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeFactory.kt index 23339ac7..bfd273c7 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeFactory.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeFactory.kt @@ -55,8 +55,7 @@ operator fun ThreeFactory.invoke(obj: Any): Object3D { */ fun Object3D.updateProperty(source: VisualObject, propertyName: Name) { if (this is Mesh && propertyName.startsWith(MATERIAL_KEY)) { - //updated material - material = source.material.jsMaterial() + updateMaterial(source) } else if ( source is VisualObject3D && (propertyName.startsWith(VisualObject3D.position) diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeLineFactory.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeLineFactory.kt index f3a46e1b..f2fba9ec 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeLineFactory.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeLineFactory.kt @@ -1,8 +1,8 @@ package hep.dataforge.vis.spatial.three +import hep.dataforge.meta.node import hep.dataforge.vis.spatial.PolyLine import hep.dataforge.vis.spatial.layer -import hep.dataforge.vis.spatial.material import info.laht.threekt.core.Geometry import info.laht.threekt.core.Object3D import info.laht.threekt.objects.LineSegments @@ -16,7 +16,8 @@ object ThreeLineFactory : ThreeFactory { vertices = obj.points.toTypedArray() } - val material = obj.material.jsLineMaterial() + val material = + ThreeMaterials.getLineMaterial(obj.getProperty(MeshThreeFactory.EDGES_MATERIAL_KEY).node) return LineSegments(geometry, material).apply { updatePosition(obj) diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeMaterials.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeMaterials.kt new file mode 100644 index 00000000..4b4309d8 --- /dev/null +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeMaterials.kt @@ -0,0 +1,103 @@ +package hep.dataforge.vis.spatial.three + +import hep.dataforge.meta.* +import hep.dataforge.values.ValueType +import hep.dataforge.vis.common.Colors +import hep.dataforge.vis.common.VisualObject +import hep.dataforge.vis.spatial.Material3D +import info.laht.threekt.materials.LineBasicMaterial +import info.laht.threekt.materials.Material +import info.laht.threekt.materials.MeshBasicMaterial +import info.laht.threekt.materials.MeshPhongMaterial +import info.laht.threekt.math.Color +import info.laht.threekt.objects.Mesh + + +object ThreeMaterials { + val DEFAULT_COLOR = Color(Colors.darkgreen) + val DEFAULT = MeshPhongMaterial().apply { + color.set(DEFAULT_COLOR) + } + val DEFAULT_LINE_COLOR = Color(Colors.black) + val DEFAULT_LINE = LineBasicMaterial().apply { + color.set(DEFAULT_LINE_COLOR) + } + + + // private val materialCache = HashMap() + private val lineMaterialCache = HashMap() + + +// fun buildMaterial(meta: Meta): Material = +// MeshBasicMaterial().apply { +// color = meta["color"]?.color() ?: DEFAULT_COLOR +// opacity = meta["opacity"]?.double ?: 1.0 +// transparent = meta["transparent"].boolean ?: (opacity < 1.0) +// //node["specularColor"]?.let { specular = it.color() } +// //side = 2 +// } + + fun getLineMaterial(meta: Meta?): Material = lineMaterialCache.getOrPut(meta) { + LineBasicMaterial().apply { + color = meta["color"]?.color() ?: DEFAULT_LINE_COLOR + opacity = meta["opacity"].double ?: 1.0 + transparent = meta["transparent"].boolean ?: (opacity < 1.0) + linewidth = meta["thickness"].double ?: 1.0 + } + } + +} + +/** + * Infer color based on meta item + */ +fun MetaItem<*>.color(): Color { + return when (this) { + is MetaItem.ValueItem -> if (this.value.type == ValueType.STRING) { + Color(this.value.string) + } else { + val int = value.number.toInt() + Color(int) + } + is MetaItem.NodeItem -> { + Color( + node["red"]?.int ?: 0, + node["green"]?.int ?: 0, + node["blue"]?.int ?: 0 + ) + } + } +} + +///** +// * Infer Three material based on meta item +// */ +//fun Meta?.jsMaterial(): Material { +// return if (this == null) { +// ThreeMaterials.DEFAULT +// } else { +// ThreeMaterials.buildMaterial(this) +// } +//} +// +//fun Meta?.jsLineMaterial(): Material { +// return if (this == null) { +// ThreeMaterials.DEFAULT_LINE +// } else { +// ThreeMaterials.buildLineMaterial(this) +// } +//} + + +//fun Material3D?.jsMaterial(): Material = this?.config.jsMaterial() +//fun Material3D?.jsLineMaterial(): Material = this?.config.jsLineMaterial() + +fun Mesh.updateMaterial(obj: VisualObject) { + val meta = obj.properties[Material3D.MATERIAL_KEY].node?:EmptyMeta + material = (material as? MeshBasicMaterial ?: MeshBasicMaterial()).apply { + color = meta["color"]?.color() ?: ThreeMaterials.DEFAULT_COLOR + opacity = meta["opacity"]?.double ?: 1.0 + transparent = meta["transparent"].boolean ?: (opacity < 1.0) + needsUpdate = true + } +} diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreePlugin.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreePlugin.kt index 2831a155..b3d6db64 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreePlugin.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreePlugin.kt @@ -36,6 +36,7 @@ class ThreePlugin : AbstractPlugin() { fun buildObject3D(obj: VisualObject3D): Object3D { return when (obj) { + is ThreeVisualObject -> obj.toObject3D() is Proxy -> proxyFactory(obj) is VisualGroup3D -> { val group = ThreeGroup() @@ -85,7 +86,7 @@ class ThreePlugin : AbstractPlugin() { companion object : PluginFactory { override val tag = PluginTag("visual.three", PluginTag.DATAFORGE_GROUP) override val type = ThreePlugin::class - override fun invoke(meta: Meta,context: Context) = ThreePlugin() + override fun invoke(meta: Meta, context: Context) = ThreePlugin() } } diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeVisualObject.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeVisualObject.kt new file mode 100644 index 00000000..36095377 --- /dev/null +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeVisualObject.kt @@ -0,0 +1,39 @@ +@file:UseSerializers(Point3DSerializer::class) + +package hep.dataforge.vis.spatial.three + +import hep.dataforge.io.serialization.ConfigSerializer +import hep.dataforge.io.toMeta +import hep.dataforge.meta.Config +import hep.dataforge.meta.Meta +import hep.dataforge.vis.common.AbstractVisualObject +import hep.dataforge.vis.spatial.Point3D +import hep.dataforge.vis.spatial.Point3DSerializer +import hep.dataforge.vis.spatial.Visual3DPlugin +import hep.dataforge.vis.spatial.VisualObject3D +import info.laht.threekt.core.Object3D +import kotlinx.serialization.Serializable +import kotlinx.serialization.UseSerializers + +/** + * A custom visual object that has its own Three.js renderer + */ +interface ThreeVisualObject : VisualObject3D { + fun toObject3D(): Object3D +} + +@Serializable +class CustomThreeVisualObject(val threeFactory: ThreeFactory) : AbstractVisualObject(), + ThreeVisualObject { + override var position: Point3D? = null + override var rotation: Point3D? = null + override var scale: Point3D? = null + + @Serializable(ConfigSerializer::class) + override var properties: Config? = null + + override fun toMeta(): Meta = Visual3DPlugin.json.toJson(serializer(), this).toMeta() + + override fun toObject3D(): Object3D = threeFactory(this) + +} \ No newline at end of file diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/three.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/three.kt index 730e7550..34e67764 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/three.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/three.kt @@ -5,12 +5,13 @@ import hep.dataforge.meta.float import hep.dataforge.meta.get import hep.dataforge.meta.node import hep.dataforge.vis.spatial.* -import info.laht.threekt.core.BufferGeometry -import info.laht.threekt.core.Face3 -import info.laht.threekt.core.Geometry -import info.laht.threekt.core.Object3D +import info.laht.threekt.core.* +import info.laht.threekt.external.controls.OrbitControls +import info.laht.threekt.materials.Material import info.laht.threekt.math.Euler import info.laht.threekt.math.Vector3 +import info.laht.threekt.objects.Mesh +import info.laht.threekt.textures.Texture /** * Utility methods for three.kt. @@ -64,4 +65,19 @@ fun CSG.toGeometry(): Geometry { geom.computeBoundingSphere() geom.computeBoundingBox() return geom +} + +internal fun Any.dispose() { + when (this) { + is Geometry -> dispose() + is BufferGeometry -> dispose() + is DirectGeometry -> dispose() + is Material -> dispose() + is Mesh -> { + geometry.dispose() + material.dispose() + } + is OrbitControls -> dispose() + is Texture -> dispose() + } } \ No newline at end of file diff --git a/spatial-js-demo/build.gradle.kts b/spatial-js-demo/build.gradle.kts index fa333f2d..e5021379 100644 --- a/spatial-js-demo/build.gradle.kts +++ b/spatial-js-demo/build.gradle.kts @@ -7,3 +7,13 @@ dependencies { api(project(":dataforge-vis-spatial")) testCompile(kotlin("test-js")) } + +kotlin{ + target { + browser{ + webpackTask { + sourceMaps = false + } + } + } +} \ No newline at end of file diff --git a/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt b/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt index 41751d9d..01e6f690 100644 --- a/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt +++ b/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt @@ -5,6 +5,8 @@ import hep.dataforge.js.Application import hep.dataforge.js.startApplication import hep.dataforge.vis.common.Colors import hep.dataforge.vis.spatial.* +import hep.dataforge.vis.spatial.three.MeshThreeFactory.Companion.EDGES_ENABLED_KEY +import hep.dataforge.vis.spatial.three.MeshThreeFactory.Companion.WIREFRAME_ENABLED_KEY import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.delay import kotlinx.coroutines.isActive @@ -14,7 +16,6 @@ import kotlin.math.cos import kotlin.math.sin import kotlin.random.Random - private class ThreeDemoApp : Application { override fun start(state: Map) { @@ -143,6 +144,28 @@ private class ThreeDemoApp : Application { } } } + + demo("dynamicBox", "Dancing boxes") { + val boxes = (-10..10).flatMap { i -> + (-10..10).map { j -> + varBox(10, 10, 0, name = "cell_${i}_${j}") { + x = i * 10 + y = j * 10 + value = 128 + setProperty(EDGES_ENABLED_KEY, false) + setProperty(WIREFRAME_ENABLED_KEY, false) + } + } + } + GlobalScope.launch { + while (isActive) { + delay(200) + boxes.forEach { box -> + box.value = (box.value + Random.nextInt(-15, 15)).coerceIn(0..255) + } + } + } + } } diff --git a/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/VariableBox.kt b/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/VariableBox.kt new file mode 100644 index 00000000..c1d8be33 --- /dev/null +++ b/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/VariableBox.kt @@ -0,0 +1,69 @@ +@file:UseSerializers(Point3DSerializer::class) + +package hep.dataforge.vis.spatial.demo + +import hep.dataforge.meta.int +import hep.dataforge.meta.number +import hep.dataforge.names.plus +import hep.dataforge.vis.common.getProperty +import hep.dataforge.vis.common.setProperty +import hep.dataforge.vis.spatial.* +import hep.dataforge.vis.spatial.VisualObject3D.Companion.GEOMETRY_KEY +import hep.dataforge.vis.spatial.demo.VariableBoxThreeFactory.X_SIZE_KEY +import hep.dataforge.vis.spatial.demo.VariableBoxThreeFactory.Y_SIZE_KEY +import hep.dataforge.vis.spatial.demo.VariableBoxThreeFactory.Z_SIZE_KEY +import hep.dataforge.vis.spatial.three.CustomThreeVisualObject +import hep.dataforge.vis.spatial.three.MeshThreeFactory +import info.laht.threekt.core.BufferGeometry +import info.laht.threekt.geometries.BoxBufferGeometry +import kotlinx.serialization.UseSerializers +import kotlin.math.max + +private val BOX_Z_SIZE_KEY = GEOMETRY_KEY + "zSize" + +internal var VisualObject3D.variableZSize: Number + get() = getProperty(BOX_Z_SIZE_KEY, false).number ?: 0f + set(value) { + setProperty(BOX_Z_SIZE_KEY, value) + } + +internal var VisualObject3D.value: Int + get() = getProperty("value", false).int ?: 0 + set(value) { + setProperty("value", value) + val size = value.toFloat() / 255f * 20f + variableZSize = size + z = -size / 2 + + val b = max(0, 255 - value) + val r = max(0, value - 255) + val g = 255 - b - r + color(r.toUByte(), g.toUByte(), b.toUByte()) + } + +fun VisualGroup3D.varBox( + xSize: Number, + ySize: Number, + zSize: Number, + name: String = "", + action: VisualObject3D.() -> Unit = {} +) = CustomThreeVisualObject(VariableBoxThreeFactory).apply { + setProperty(X_SIZE_KEY, xSize) + setProperty(Y_SIZE_KEY, ySize) + setProperty(Z_SIZE_KEY, zSize) +}.apply(action).also { set(name, it) } + +private object VariableBoxThreeFactory : MeshThreeFactory(VisualObject3D::class) { + val X_SIZE_KEY = GEOMETRY_KEY + "xSize" + val Y_SIZE_KEY = GEOMETRY_KEY + "ySize" + val Z_SIZE_KEY = GEOMETRY_KEY + "zSize" + + override fun buildGeometry(obj: VisualObject3D): BufferGeometry { + val xSize = obj.getProperty(X_SIZE_KEY, false).number ?: 0f + val ySize = obj.getProperty(Y_SIZE_KEY, false).number ?: 0f + val zSize = obj.getProperty(Z_SIZE_KEY, false).number ?: 0f + return obj.detail?.let { detail -> + BoxBufferGeometry(xSize, ySize, zSize, detail, detail, detail) + } ?: BoxBufferGeometry(xSize, ySize, zSize) + } +} \ No newline at end of file From 546f7e1fd0d9d3c4397b9940002cb0654428b119 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 6 Nov 2019 17:01:30 +0300 Subject: [PATCH 07/25] Optimized dancing boxes --- .../vis/spatial/three/MeshThreeFactory.kt | 78 +++++++++---------- spatial-js-demo/build.gradle.kts | 18 ++--- .../dataforge/vis/spatial/demo/VariableBox.kt | 78 ++++++++++++++----- 3 files changed, 106 insertions(+), 68 deletions(-) diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/MeshThreeFactory.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/MeshThreeFactory.kt index 35898398..e1101ab6 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/MeshThreeFactory.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/MeshThreeFactory.kt @@ -29,45 +29,6 @@ abstract class MeshThreeFactory( */ abstract fun buildGeometry(obj: T): BufferGeometry - private fun Mesh.applyEdges(obj: T) { - children.find { it.name == "edges" }?.let { - remove(it) - (it as LineSegments).dispose() - } - //inherited edges definition, enabled by default - if (obj.getProperty(EDGES_ENABLED_KEY).boolean != false) { - - val material = ThreeMaterials.getLineMaterial(obj.getProperty(EDGES_MATERIAL_KEY).node) - add( - LineSegments( - EdgesGeometry(geometry as BufferGeometry), - material - ).apply { - name = "edges" - } - ) - } - } - - private fun Mesh.applyWireFrame(obj: T) { - children.find { it.name == "wireframe" }?.let { - remove(it) - (it as LineSegments).dispose() - } - //inherited wireframe definition, disabled by default - if (obj.getProperty(WIREFRAME_ENABLED_KEY).boolean == true) { - val material = ThreeMaterials.getLineMaterial(obj.getProperty(WIREFRAME_MATERIAL_KEY).node) - add( - LineSegments( - WireframeGeometry(geometry as BufferGeometry), - material - ).apply { - name = "wireframe" - } - ) - } - } - override fun invoke(obj: T): Mesh { val geometry = buildGeometry(obj) @@ -121,4 +82,43 @@ abstract class MeshThreeFactory( val WIREFRAME_ENABLED_KEY = WIREFRAME_KEY + ENABLED_KEY val WIREFRAME_MATERIAL_KEY = WIREFRAME_KEY + Material3D.MATERIAL_KEY } +} + +fun Mesh.applyEdges(obj: VisualObject3D) { + children.find { it.name == "edges" }?.let { + remove(it) + (it as LineSegments).dispose() + } + //inherited edges definition, enabled by default + if (obj.getProperty(MeshThreeFactory.EDGES_ENABLED_KEY).boolean != false) { + + val material = ThreeMaterials.getLineMaterial(obj.getProperty(MeshThreeFactory.EDGES_MATERIAL_KEY).node) + add( + LineSegments( + EdgesGeometry(geometry as BufferGeometry), + material + ).apply { + name = "edges" + } + ) + } +} + +fun Mesh.applyWireFrame(obj: VisualObject3D) { + children.find { it.name == "wireframe" }?.let { + remove(it) + (it as LineSegments).dispose() + } + //inherited wireframe definition, disabled by default + if (obj.getProperty(MeshThreeFactory.WIREFRAME_ENABLED_KEY).boolean == true) { + val material = ThreeMaterials.getLineMaterial(obj.getProperty(MeshThreeFactory.WIREFRAME_MATERIAL_KEY).node) + add( + LineSegments( + WireframeGeometry(geometry as BufferGeometry), + material + ).apply { + name = "wireframe" + } + ) + } } \ No newline at end of file diff --git a/spatial-js-demo/build.gradle.kts b/spatial-js-demo/build.gradle.kts index e5021379..53f185b2 100644 --- a/spatial-js-demo/build.gradle.kts +++ b/spatial-js-demo/build.gradle.kts @@ -8,12 +8,12 @@ dependencies { testCompile(kotlin("test-js")) } -kotlin{ - target { - browser{ - webpackTask { - sourceMaps = false - } - } - } -} \ No newline at end of file +//kotlin{ +// target { +// browser{ +// webpackTask { +// sourceMaps = false +// } +// } +// } +//} \ No newline at end of file diff --git a/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/VariableBox.kt b/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/VariableBox.kt index c1d8be33..2827dcbd 100644 --- a/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/VariableBox.kt +++ b/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/VariableBox.kt @@ -5,26 +5,26 @@ package hep.dataforge.vis.spatial.demo import hep.dataforge.meta.int import hep.dataforge.meta.number import hep.dataforge.names.plus +import hep.dataforge.names.startsWith import hep.dataforge.vis.common.getProperty import hep.dataforge.vis.common.setProperty import hep.dataforge.vis.spatial.* import hep.dataforge.vis.spatial.VisualObject3D.Companion.GEOMETRY_KEY -import hep.dataforge.vis.spatial.demo.VariableBoxThreeFactory.X_SIZE_KEY -import hep.dataforge.vis.spatial.demo.VariableBoxThreeFactory.Y_SIZE_KEY import hep.dataforge.vis.spatial.demo.VariableBoxThreeFactory.Z_SIZE_KEY -import hep.dataforge.vis.spatial.three.CustomThreeVisualObject -import hep.dataforge.vis.spatial.three.MeshThreeFactory +import hep.dataforge.vis.spatial.three.* import info.laht.threekt.core.BufferGeometry +import info.laht.threekt.core.Object3D import info.laht.threekt.geometries.BoxBufferGeometry +import info.laht.threekt.materials.MeshBasicMaterial +import info.laht.threekt.objects.Mesh import kotlinx.serialization.UseSerializers import kotlin.math.max - -private val BOX_Z_SIZE_KEY = GEOMETRY_KEY + "zSize" +import kotlin.reflect.KClass internal var VisualObject3D.variableZSize: Number - get() = getProperty(BOX_Z_SIZE_KEY, false).number ?: 0f + get() = getProperty(Z_SIZE_KEY, false).number ?: 0f set(value) { - setProperty(BOX_Z_SIZE_KEY, value) + setProperty(Z_SIZE_KEY, value) } internal var VisualObject3D.value: Int @@ -32,7 +32,7 @@ internal var VisualObject3D.value: Int set(value) { setProperty("value", value) val size = value.toFloat() / 255f * 20f - variableZSize = size + scaleZ = size z = -size / 2 val b = max(0, 255 - value) @@ -48,22 +48,60 @@ fun VisualGroup3D.varBox( name: String = "", action: VisualObject3D.() -> Unit = {} ) = CustomThreeVisualObject(VariableBoxThreeFactory).apply { - setProperty(X_SIZE_KEY, xSize) - setProperty(Y_SIZE_KEY, ySize) - setProperty(Z_SIZE_KEY, zSize) + scaleX = xSize + scaleY = ySize + scaleZ = zSize }.apply(action).also { set(name, it) } -private object VariableBoxThreeFactory : MeshThreeFactory(VisualObject3D::class) { +private object VariableBoxThreeFactory : ThreeFactory { val X_SIZE_KEY = GEOMETRY_KEY + "xSize" val Y_SIZE_KEY = GEOMETRY_KEY + "ySize" val Z_SIZE_KEY = GEOMETRY_KEY + "zSize" - override fun buildGeometry(obj: VisualObject3D): BufferGeometry { - val xSize = obj.getProperty(X_SIZE_KEY, false).number ?: 0f - val ySize = obj.getProperty(Y_SIZE_KEY, false).number ?: 0f - val zSize = obj.getProperty(Z_SIZE_KEY, false).number ?: 0f - return obj.detail?.let { detail -> - BoxBufferGeometry(xSize, ySize, zSize, detail, detail, detail) - } ?: BoxBufferGeometry(xSize, ySize, zSize) + override val type: KClass get() = VisualObject3D::class + + override fun invoke(obj: VisualObject3D): Object3D { + val xSize = obj.getProperty(X_SIZE_KEY, false).number?.toDouble() ?: 1.0 + val ySize = obj.getProperty(Y_SIZE_KEY, false).number?.toDouble() ?: 1.0 + val zSize = obj.getProperty(Z_SIZE_KEY, false).number?.toDouble() ?: 1.0 + val geometry = BoxBufferGeometry(1, 1, 1) + + //JS sometimes tries to pass Geometry as BufferGeometry + @Suppress("USELESS_IS_CHECK") if (geometry !is BufferGeometry) error("BufferGeometry expected") + + val mesh = Mesh(geometry, MeshBasicMaterial()).apply { + applyEdges(obj) + applyWireFrame(obj) + + //set position for mesh + updatePosition(obj) + + //set color for mesh + updateMaterial(obj) + + layers.enable(obj.layer) + children.forEach { + it.layers.enable(obj.layer) + } + } + + mesh.scale.set(xSize, ySize, zSize) + + //add listener to object properties + obj.onPropertyChange(this) { name, _, _ -> + when { +// name.startsWith(GEOMETRY_KEY) -> { +// val newXSize = obj.getProperty(X_SIZE_KEY, false).number?.toDouble() ?: 1.0 +// val newYSize = obj.getProperty(Y_SIZE_KEY, false).number?.toDouble() ?: 1.0 +// val newZSize = obj.getProperty(Z_SIZE_KEY, false).number?.toDouble() ?: 1.0 +// mesh.scale.set(newXSize, newYSize, newZSize) +// mesh.updateMatrix() +// } + name.startsWith(MeshThreeFactory.WIREFRAME_KEY) -> mesh.applyWireFrame(obj) + name.startsWith(MeshThreeFactory.EDGES_KEY) -> mesh.applyEdges(obj) + else -> mesh.updateProperty(obj, name) + } + } + return mesh } } \ No newline at end of file From c964f80d73ff39af56955bcf25bf5bd208610380 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 11 Dec 2019 11:46:28 +0300 Subject: [PATCH 08/25] Update DataForge to 0.1.5-dev --- build.gradle.kts | 6 ++-- dataforge-vis-common/build.gradle.kts | 1 - dataforge-vis-spatial-gdml/build.gradle.kts | 2 +- .../vis/spatial/gdml/generateSchema.kt | 2 +- .../dataforge/vis/spatial/VisualObject3D.kt | 4 +-- .../vis/spatial/three/ThreeOutput.kt | 4 +-- .../dataforge/vis/spatial/fx/FX3DOutput.kt | 4 +-- gradle/wrapper/gradle-wrapper.jar | Bin 55616 -> 58702 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 29 ++++++++---------- settings.gradle.kts | 7 +---- spatial-js-demo/build.gradle.kts | 2 +- 12 files changed, 26 insertions(+), 37 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index a8d57674..61a73e71 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,8 +1,8 @@ -val dataforgeVersion by extra("0.1.4") +val dataforgeVersion by extra("0.1.5-dev-4") plugins { - val kotlinVersion = "1.3.50" - val toolsVersion = "0.2.2" + val kotlinVersion = "1.3.61" + val toolsVersion = "0.2.7" kotlin("jvm") version kotlinVersion apply false id("kotlin-dce-js") version kotlinVersion apply false diff --git a/dataforge-vis-common/build.gradle.kts b/dataforge-vis-common/build.gradle.kts index 669fd43f..aff8d7a0 100644 --- a/dataforge-vis-common/build.gradle.kts +++ b/dataforge-vis-common/build.gradle.kts @@ -33,7 +33,6 @@ kotlin { dependencies { api("hep.dataforge:dataforge-output-html:$dataforgeVersion") api("kotlin.js.externals:kotlin-js-jquery:3.2.0-0") - api(npm("text-encoding")) api(npm("bootstrap","4.3.1")) } } diff --git a/dataforge-vis-spatial-gdml/build.gradle.kts b/dataforge-vis-spatial-gdml/build.gradle.kts index d02c8258..31c0f223 100644 --- a/dataforge-vis-spatial-gdml/build.gradle.kts +++ b/dataforge-vis-spatial-gdml/build.gradle.kts @@ -13,7 +13,7 @@ kotlin { val commonMain by getting { dependencies { api(project(":dataforge-vis-spatial")) - api("scientifik:gdml:0.1.4") + api("scientifik:gdml:0.1.3") } } val jsMain by getting { diff --git a/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/generateSchema.kt b/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/generateSchema.kt index fc417efb..628a8651 100644 --- a/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/generateSchema.kt +++ b/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/generateSchema.kt @@ -73,7 +73,7 @@ private fun jsonSchema(descriptor: SerialDescriptor, context: SerialModule): Jso val properties: MutableMap = mutableMapOf() val requiredProperties: MutableSet = mutableSetOf() val isEnum = descriptor.kind == UnionKind.ENUM_KIND - val isPolymorphic = descriptor.kind == UnionKind.POLYMORPHIC + val isPolymorphic = descriptor.kind is PolymorphicKind if (!isEnum && !isPolymorphic) descriptor.elementDescriptors().forEachIndexed { index, child -> diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt index 6992e0ec..7d2a2cac 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt @@ -6,7 +6,7 @@ import hep.dataforge.io.serialization.NameSerializer import hep.dataforge.meta.* import hep.dataforge.names.asName import hep.dataforge.names.plus -import hep.dataforge.output.Output +import hep.dataforge.output.Renderer import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.spatial.VisualObject3D.Companion.DETAIL_KEY import hep.dataforge.vis.spatial.VisualObject3D.Companion.IGNORE_KEY @@ -77,7 +77,7 @@ var VisualObject3D.layer: Int setProperty(LAYER_KEY, value) } -fun Output.render(meta: Meta = EmptyMeta, action: VisualGroup3D.() -> Unit) = +fun Renderer.render(meta: Meta = EmptyMeta, action: VisualGroup3D.() -> Unit) = render(VisualGroup3D().apply(action), meta) // Common properties diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeOutput.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeOutput.kt index 1dd74ca3..0ea8989f 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeOutput.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeOutput.kt @@ -2,7 +2,7 @@ package hep.dataforge.vis.spatial.three import hep.dataforge.context.Context import hep.dataforge.meta.* -import hep.dataforge.output.Output +import hep.dataforge.output.Renderer import hep.dataforge.vis.common.Colors import hep.dataforge.vis.spatial.VisualObject3D import hep.dataforge.vis.spatial.World @@ -19,7 +19,7 @@ import kotlin.browser.window import kotlin.dom.clear import kotlin.math.max -class ThreeOutput(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Output { +class ThreeOutput(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Renderer { override val context: Context get() = three.context diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DOutput.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DOutput.kt index b910b17e..7497ead5 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DOutput.kt +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DOutput.kt @@ -2,7 +2,7 @@ package hep.dataforge.vis.spatial.fx import hep.dataforge.context.Context import hep.dataforge.meta.Meta -import hep.dataforge.output.Output +import hep.dataforge.output.Renderer import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.spatial.Box import hep.dataforge.vis.spatial.VisualGroup3D @@ -15,7 +15,7 @@ import tornadofx.* * https://github.com/miho/JCSG for operations * */ -class FX3DOutput(override val context: Context) : Output { +class FX3DOutput(override val context: Context) : Renderer { val canvas by lazy { Canvas3D() } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 5c2d1cf016b3885f6930543d57b744ea8c220a1a..cc4fdc293d0e50b0ad9b65c16e7ddd1db2f6025b 100644 GIT binary patch delta 16535 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 useModule("org.jetbrains.kotlinx:atomicfu-gradle-plugin:${requested.version}") - "kotlin-multiplatform" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${requested.version}") - "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${requested.version}") - "org.jetbrains.kotlin.js" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${requested.version}") "kotlin-dce-js" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${requested.version}") - "org.jetbrains.kotlin.frontend" -> useModule("org.jetbrains.kotlin:kotlin-frontend-plugin:${requested.version}") "scientifik.mpp", "scientifik.publish", "scientifik.jvm", "scientifik.js" -> useModule("scientifik:gradle-tools:${requested.version}") "org.openjfx.javafxplugin" -> useModule("org.openjfx:javafx-plugin:${requested.version}") } @@ -26,7 +21,7 @@ pluginManagement { } } -enableFeaturePreview("GRADLE_METADATA") +//enableFeaturePreview("GRADLE_METADATA") rootProject.name = "dataforge-vis" diff --git a/spatial-js-demo/build.gradle.kts b/spatial-js-demo/build.gradle.kts index 53f185b2..19b614fd 100644 --- a/spatial-js-demo/build.gradle.kts +++ b/spatial-js-demo/build.gradle.kts @@ -5,7 +5,7 @@ plugins { dependencies { api(project(":dataforge-vis-spatial")) - testCompile(kotlin("test-js")) + testImplementation(kotlin("test-js")) } //kotlin{ From cef1a1ee6d56f12a83485ac5feb3d6ff464c9a02 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 14 Dec 2019 21:45:41 +0300 Subject: [PATCH 09/25] FX backend in progress --- dataforge-vis-common/build.gradle.kts | 3 +- .../hep/dataforge/vis/common/VisualObject.kt | 9 +- dataforge-vis-spatial/build.gradle.kts | 3 +- .../kotlin/hep/dataforge/vis/spatial/Box.kt | 3 - .../hep/dataforge/vis/spatial/Composite.kt | 4 - .../hep/dataforge/vis/spatial/ConeSegment.kt | 49 +++++++- .../hep/dataforge/vis/spatial/Convex.kt | 4 - .../hep/dataforge/vis/spatial/Extruded.kt | 4 - .../hep/dataforge/vis/spatial/PolyLine.kt | 3 - .../kotlin/hep/dataforge/vis/spatial/Proxy.kt | 5 - .../hep/dataforge/vis/spatial/Sphere.kt | 8 +- .../hep/dataforge/vis/spatial/Text3D.kt | 23 ++++ .../kotlin/hep/dataforge/vis/spatial/Tube.kt | 3 - .../dataforge/vis/spatial/VisualGroup3D.kt | 3 - .../hep/dataforge/vis/spatial/ConvexTest.kt | 13 +- .../vis/spatial/SerializationTest.kt | 10 +- .../vis/spatial/editor/outputConfig.kt | 8 +- .../three/{ThreeOutput.kt => ThreeCanvas.kt} | 4 +- .../vis/spatial/three/ThreeFactory.kt | 22 ++-- .../vis/spatial/three/ThreePlugin.kt | 12 +- .../vis/spatial/three/ThreeVisualObject.kt | 5 - .../hep/dataforge/vis/spatial/fx/Canvas3D.kt | 14 ++- ...XListener.kt => DisplayObjectFXBinding.kt} | 2 +- .../dataforge/vis/spatial/fx/FX3DOutput.kt | 50 -------- .../dataforge/vis/spatial/fx/FX3DPlugin.kt | 113 ++++++++++++++++++ .../vis/spatial/fx/FXCompositeFactory.kt | 38 ++++++ .../vis/spatial/fx/FXConvexFactory.kt | 19 +++ .../vis/spatial/fx/FXProxyFactory.kt | 15 +++ .../vis/spatial/fx/FXShapeFactory.kt | 58 +++++++++ .../vis/spatial/fx/RendererDemoApp.kt | 7 +- .../hep/dataforge/vis/spatial/geometryJVM.kt | 28 ++++- .../vis/spatial/demo/ThreeDemoGrid.kt | 10 +- 32 files changed, 406 insertions(+), 146 deletions(-) create mode 100644 dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Text3D.kt rename dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/{ThreeOutput.kt => ThreeCanvas.kt} (95%) rename dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/{DisplayObjectFXListener.kt => DisplayObjectFXBinding.kt} (96%) delete mode 100644 dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DOutput.kt create mode 100644 dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DPlugin.kt create mode 100644 dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXCompositeFactory.kt create mode 100644 dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXConvexFactory.kt create mode 100644 dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXProxyFactory.kt create mode 100644 dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXShapeFactory.kt diff --git a/dataforge-vis-common/build.gradle.kts b/dataforge-vis-common/build.gradle.kts index aff8d7a0..e6fb3815 100644 --- a/dataforge-vis-common/build.gradle.kts +++ b/dataforge-vis-common/build.gradle.kts @@ -32,8 +32,7 @@ kotlin { jsMain{ dependencies { api("hep.dataforge:dataforge-output-html:$dataforgeVersion") - api("kotlin.js.externals:kotlin-js-jquery:3.2.0-0") - api(npm("bootstrap","4.3.1")) + api(npm("bootstrap","4.4.1")) } } } diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualObject.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualObject.kt index 5d54a98a..23d46683 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualObject.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualObject.kt @@ -1,6 +1,9 @@ package hep.dataforge.vis.common -import hep.dataforge.meta.* +import hep.dataforge.meta.Config +import hep.dataforge.meta.Configurable +import hep.dataforge.meta.Laminate +import hep.dataforge.meta.MetaItem import hep.dataforge.names.Name import hep.dataforge.names.asName import hep.dataforge.names.toName @@ -15,7 +18,7 @@ import kotlinx.serialization.Transient * A root type for display hierarchy */ @Type(TYPE) -interface VisualObject : MetaRepr, Configurable { +interface VisualObject : Configurable { /** * The parent object of this one. If null, this one is a root. @@ -54,7 +57,7 @@ interface VisualObject : MetaRepr, Configurable { fun removeChangeListener(owner: Any?) /** - * List of names of styles applied to this object + * List of names of styles applied to this object. Order matters. */ var styles: List diff --git a/dataforge-vis-spatial/build.gradle.kts b/dataforge-vis-spatial/build.gradle.kts index 1d562140..67352978 100644 --- a/dataforge-vis-spatial/build.gradle.kts +++ b/dataforge-vis-spatial/build.gradle.kts @@ -21,7 +21,8 @@ kotlin { } jvmMain { dependencies { - implementation("org.fxyz3d:fxyz3d:0.5.2") + api("org.fxyz3d:fxyz3d:0.5.2") + implementation("eu.mihosoft.vrl.jcsg:jcsg:0.5.7") } } jsMain { diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Box.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Box.kt index 571a1ff8..550430f3 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Box.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Box.kt @@ -3,7 +3,6 @@ package hep.dataforge.vis.spatial import hep.dataforge.context.Context import hep.dataforge.io.serialization.ConfigSerializer -import hep.dataforge.io.toMeta import hep.dataforge.meta.Config import hep.dataforge.meta.Meta import hep.dataforge.meta.float @@ -50,8 +49,6 @@ class Box( geometryBuilder.face4(node8, node5, node6, node7) } - override fun toMeta(): Meta = Visual3DPlugin.json.toJson(serializer(), this).toMeta() - companion object : VisualFactory { const val TYPE = "geometry.3d.box" diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt index 4e920800..e0ac521b 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt @@ -2,9 +2,7 @@ package hep.dataforge.vis.spatial import hep.dataforge.io.serialization.ConfigSerializer -import hep.dataforge.io.toMeta import hep.dataforge.meta.Config -import hep.dataforge.meta.Meta import hep.dataforge.meta.update import hep.dataforge.vis.common.AbstractVisualObject import kotlinx.serialization.Serializable @@ -34,8 +32,6 @@ class Composite( @Serializable(ConfigSerializer::class) override var properties: Config? = null - - override fun toMeta(): Meta = Visual3DPlugin.json.toJson(serializer(), this).toMeta() } inline fun VisualGroup3D.composite( diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/ConeSegment.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/ConeSegment.kt index b1533a83..9aa090ef 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/ConeSegment.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/ConeSegment.kt @@ -3,12 +3,12 @@ package hep.dataforge.vis.spatial import hep.dataforge.io.serialization.ConfigSerializer -import hep.dataforge.io.toMeta import hep.dataforge.meta.Config -import hep.dataforge.meta.Meta import hep.dataforge.vis.common.AbstractVisualObject import kotlinx.serialization.Serializable import kotlinx.serialization.UseSerializers +import kotlin.math.cos +import kotlin.math.sin /** * A cylinder or cut cone segment @@ -20,7 +20,7 @@ class ConeSegment( var upperRadius: Float, var startAngle: Float = 0f, var angle: Float = PI2 -) : AbstractVisualObject(), VisualObject3D { +) : AbstractVisualObject(), VisualObject3D, Shape { @Serializable(ConfigSerializer::class) override var properties: Config? = null @@ -29,7 +29,48 @@ class ConeSegment( override var rotation: Point3D? = null override var scale: Point3D? = null - override fun toMeta(): Meta = Visual3DPlugin.json.toJson(serializer(), this).toMeta() + override fun toGeometry(geometryBuilder: GeometryBuilder) { + val segments = detail ?: 8 + require(segments >= 4) { "The number of segments in cone segment is too small" } + val angleStep = angle / (segments - 1) + + fun shape(r: Float, z: Float): List { + return (0 until segments).map { i -> + Point3D(r * cos(startAngle + angleStep * i), r * sin(startAngle + angleStep * i), z) + } + } + + geometryBuilder.apply { + + //creating shape in x-y plane with z = 0 + val bottomOuterPoints = shape(upperRadius, -height / 2) + val upperOuterPoints = shape(radius, height / 2) + //outer face + (1 until segments).forEach { + face4(bottomOuterPoints[it - 1], bottomOuterPoints[it], upperOuterPoints[it], upperOuterPoints[it - 1]) + } + + if (angle == PI2) { + face4(bottomOuterPoints.last(), bottomOuterPoints[0], upperOuterPoints[0], upperOuterPoints.last()) + } + + val zeroBottom = Point3D(0f, 0f, 0f) + val zeroTop = Point3D(0f, 0f, height) + (1 until segments).forEach { + face(bottomOuterPoints[it - 1], zeroBottom, bottomOuterPoints[it]) + face(upperOuterPoints[it - 1], upperOuterPoints[it], zeroTop) + } + if (angle == PI2) { + face(bottomOuterPoints.last(), zeroBottom, bottomOuterPoints[0]) + face(upperOuterPoints.last(), upperOuterPoints[0], zeroTop) + } else { + face4(zeroTop, zeroBottom, bottomOuterPoints[0], upperOuterPoints[0]) + face4(zeroTop, zeroBottom, bottomOuterPoints.last(), upperOuterPoints.last()) + } + + } + } + } inline fun VisualGroup3D.cylinder( diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Convex.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Convex.kt index 3d9f03d5..1ca46886 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Convex.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Convex.kt @@ -3,9 +3,7 @@ package hep.dataforge.vis.spatial import hep.dataforge.io.serialization.ConfigSerializer -import hep.dataforge.io.toMeta import hep.dataforge.meta.Config -import hep.dataforge.meta.Meta import hep.dataforge.vis.common.AbstractVisualObject import kotlinx.serialization.Serializable import kotlinx.serialization.UseSerializers @@ -20,8 +18,6 @@ class Convex(val points: List) : AbstractVisualObject(), VisualObject3D override var rotation: Point3D? = null override var scale: Point3D? = null - override fun toMeta(): Meta = Visual3DPlugin.json.toJson(serializer(), this).toMeta() - companion object { const val TYPE = "geometry.3d.convex" } diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Extruded.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Extruded.kt index c0bb0fb1..7255b7ef 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Extruded.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Extruded.kt @@ -2,9 +2,7 @@ package hep.dataforge.vis.spatial import hep.dataforge.io.serialization.ConfigSerializer -import hep.dataforge.io.toMeta import hep.dataforge.meta.Config -import hep.dataforge.meta.Meta import hep.dataforge.vis.common.AbstractVisualObject import kotlinx.serialization.Serializable import kotlinx.serialization.UseSerializers @@ -107,8 +105,6 @@ class Extruded( geometryBuilder.cap(layers.last()) } - override fun toMeta(): Meta = Visual3DPlugin.json.toJson(serializer(), this).toMeta() - companion object { const val TYPE = "geometry.3d.extruded" } diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/PolyLine.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/PolyLine.kt index 001c1e40..75d00ab4 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/PolyLine.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/PolyLine.kt @@ -3,9 +3,7 @@ package hep.dataforge.vis.spatial import hep.dataforge.io.serialization.ConfigSerializer -import hep.dataforge.io.toMeta import hep.dataforge.meta.Config -import hep.dataforge.meta.Meta import hep.dataforge.vis.common.AbstractVisualObject import hep.dataforge.vis.common.number import kotlinx.serialization.Serializable @@ -23,7 +21,6 @@ class PolyLine(var points: List) : AbstractVisualObject(), VisualObject //var lineType by string() var thickness by number(1.0, key = "material.thickness") - override fun toMeta(): Meta = Visual3DPlugin.json.toJson(serializer(), this).toMeta() } fun VisualGroup3D.polyline(vararg points: Point3D, name: String = "", action: PolyLine.() -> Unit = {}) = diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt index e5ea3be6..e71186c7 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt @@ -4,7 +4,6 @@ package hep.dataforge.vis.spatial import hep.dataforge.io.serialization.ConfigSerializer import hep.dataforge.io.serialization.NameSerializer -import hep.dataforge.io.toMeta import hep.dataforge.meta.Config import hep.dataforge.meta.Meta import hep.dataforge.meta.MetaItem @@ -64,8 +63,6 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua } } - override fun toMeta(): Meta = Visual3DPlugin.json.toJson(serializer(), this).toMeta() - override val children: Map get() = (prototype as? MutableVisualGroup)?.children ?.filter { !it.key.toString().startsWith("@") } @@ -144,8 +141,6 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua } } - override fun toMeta(): Meta = Visual3DPlugin.json.toJson(serializer(), this).toMeta() - } companion object { diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Sphere.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Sphere.kt index 1b210c75..f762a48a 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Sphere.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Sphere.kt @@ -3,9 +3,7 @@ package hep.dataforge.vis.spatial import hep.dataforge.io.serialization.ConfigSerializer -import hep.dataforge.io.toMeta import hep.dataforge.meta.Config -import hep.dataforge.meta.Meta import hep.dataforge.vis.common.AbstractVisualObject import kotlinx.serialization.Serializable import kotlinx.serialization.UseSerializers @@ -18,7 +16,7 @@ class Sphere( var phi: Float = PI2, var thetaStart: Float = 0f, var theta: Float = PI.toFloat() -) : AbstractVisualObject(), VisualObject3D { +) : AbstractVisualObject(), VisualObject3D, Shape { @Serializable(ConfigSerializer::class) override var properties: Config? = null @@ -27,7 +25,9 @@ class Sphere( override var rotation: Point3D? = null override var scale: Point3D? = null - override fun toMeta(): Meta = Visual3DPlugin.json.toJson(serializer(), this).toMeta() + override fun toGeometry(geometryBuilder: GeometryBuilder) { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } } inline fun VisualGroup3D.sphere( diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Text3D.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Text3D.kt new file mode 100644 index 00000000..2fbecf1d --- /dev/null +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Text3D.kt @@ -0,0 +1,23 @@ +@file:UseSerializers(Point3DSerializer::class) + +package hep.dataforge.vis.spatial + +import hep.dataforge.io.serialization.ConfigSerializer +import hep.dataforge.meta.Config +import hep.dataforge.vis.common.AbstractVisualObject +import kotlinx.serialization.Serializable +import kotlinx.serialization.UseSerializers + +@Serializable +class Text3D(var text: String, var fontSize: Int) : AbstractVisualObject(), VisualObject3D { + @Serializable(ConfigSerializer::class) + override var properties: Config? = null + + override var position: Point3D? = null + override var rotation: Point3D? = null + override var scale: Point3D? = null + +} + +fun VisualGroup3D.text(text: String, fontSize: Int, name: String = "", action: Text3D.() -> Unit = {}) = + Text3D(text, fontSize).apply(action).also { set(name, it) } \ No newline at end of file diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Tube.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Tube.kt index ccf6a62f..248fbfce 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Tube.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Tube.kt @@ -2,9 +2,7 @@ package hep.dataforge.vis.spatial import hep.dataforge.io.serialization.ConfigSerializer -import hep.dataforge.io.toMeta import hep.dataforge.meta.Config -import hep.dataforge.meta.Meta import hep.dataforge.vis.common.AbstractVisualObject import kotlinx.serialization.Serializable import kotlinx.serialization.UseSerializers @@ -126,7 +124,6 @@ class Tube( } } - override fun toMeta(): Meta = Visual3DPlugin.json.toJson(serializer(), this).toMeta() } inline fun VisualGroup3D.tube( diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt index 071623b7..9c959e73 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt @@ -11,7 +11,6 @@ package hep.dataforge.vis.spatial import hep.dataforge.io.serialization.ConfigSerializer import hep.dataforge.io.serialization.MetaSerializer import hep.dataforge.io.serialization.NameSerializer -import hep.dataforge.io.toMeta import hep.dataforge.meta.Config import hep.dataforge.meta.Meta import hep.dataforge.names.Name @@ -97,8 +96,6 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D { } } - override fun toMeta(): Meta = Visual3DPlugin.json.toJson(serializer(), this).toMeta() - companion object { const val PROTOTYPES_KEY = "templates" } diff --git a/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/ConvexTest.kt b/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/ConvexTest.kt index 40cb4404..3358fe84 100644 --- a/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/ConvexTest.kt +++ b/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/ConvexTest.kt @@ -1,8 +1,8 @@ package hep.dataforge.vis.spatial -import hep.dataforge.meta.get +import hep.dataforge.io.toMeta +import hep.dataforge.meta.MetaItem import hep.dataforge.meta.getIndexed -import hep.dataforge.meta.node import kotlin.test.Test import kotlin.test.assertEquals @@ -25,12 +25,11 @@ class ConvexTest { val convex = group.first() as Convex - val meta = convex.toMeta() + val json = Visual3DPlugin.json.toJson(Convex.serializer(), convex) + val meta = json.toMeta() - val pointsNode = convex.toMeta()["points"].node - - assertEquals(8, pointsNode?.items?.count()) - val points = pointsNode?.getIndexed("points") + val points = meta.getIndexed("points").values.map { (it as MetaItem.NodeItem<*>).node.point3D()} + assertEquals(8, points.count()) assertEquals(8, convex.points.size) } diff --git a/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/SerializationTest.kt b/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/SerializationTest.kt index 958f98c3..128b507b 100644 --- a/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/SerializationTest.kt +++ b/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/SerializationTest.kt @@ -8,15 +8,15 @@ import kotlin.test.assertEquals class SerializationTest { @ImplicitReflectionSerializer @Test - fun testCubeSerialization(){ - val cube = Box(100f,100f,100f).apply{ + fun testCubeSerialization() { + val cube = Box(100f, 100f, 100f).apply { color(222) x = 100 z = -100 } - val string = json.stringify(Box.serializer(),cube) + val string = json.stringify(Box.serializer(), cube) println(string) - val newCube = json.parse(Box.serializer(),string) - assertEquals(cube.toMeta(),newCube.toMeta()) + val newCube = json.parse(Box.serializer(), string) + assertEquals(cube.config, newCube.config) } } \ No newline at end of file diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/outputConfig.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/outputConfig.kt index f667fc99..308a61bd 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/outputConfig.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/outputConfig.kt @@ -1,6 +1,6 @@ package hep.dataforge.vis.spatial.editor -import hep.dataforge.vis.spatial.three.ThreeOutput +import hep.dataforge.vis.spatial.three.ThreeCanvas import kotlinx.html.InputType import kotlinx.html.dom.append import kotlinx.html.js.div @@ -9,7 +9,7 @@ import kotlinx.html.js.label import org.w3c.dom.Element import kotlin.dom.clear -fun Element.threeOutputConfig(output: ThreeOutput) { +fun Element.threeOutputConfig(canvas: ThreeCanvas) { clear() append { card("Layers"){ @@ -23,9 +23,9 @@ fun Element.threeOutputConfig(output: ThreeOutput) { } onchange = { if (checked) { - output.camera.layers.enable(layer) + canvas.camera.layers.enable(layer) } else { - output.camera.layers.disable(layer) + canvas.camera.layers.disable(layer) } } } diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeOutput.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeCanvas.kt similarity index 95% rename from dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeOutput.kt rename to dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeCanvas.kt index 0ea8989f..a6f1d9be 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeOutput.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeCanvas.kt @@ -19,7 +19,7 @@ import kotlin.browser.window import kotlin.dom.clear import kotlin.math.max -class ThreeOutput(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Renderer { +class ThreeCanvas(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Renderer { override val context: Context get() = three.context @@ -95,7 +95,7 @@ class ThreeOutput(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Renderer } fun ThreePlugin.output(element: HTMLElement? = null, meta: Meta = EmptyMeta, override: MetaBuilder.() -> Unit = {}) = - ThreeOutput(this, buildMeta(meta, override)).apply { + ThreeCanvas(this, buildMeta(meta, override)).apply { if (element != null) { attach(element) } diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeFactory.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeFactory.kt index bfd273c7..b3e76a20 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeFactory.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeFactory.kt @@ -38,17 +38,17 @@ fun Object3D.updatePosition(obj: VisualObject3D) { updateMatrix() } -/** - * Unsafe invocation of a factory - */ -operator fun ThreeFactory.invoke(obj: Any): Object3D { - if (type.isInstance(obj)) { - @Suppress("UNCHECKED_CAST") - return invoke(obj as T) - } else { - error("The object of type ${obj::class} could not be rendered by this factory") - } -} +///** +// * Unsafe invocation of a factory +// */ +//operator fun ThreeFactory.invoke(obj: Any): Object3D { +// if (type.isInstance(obj)) { +// @Suppress("UNCHECKED_CAST") +// return invoke(obj as T) +// } else { +// error("The object of type ${obj::class} could not be rendered by this factory") +// } +//} /** * Update non-position non-geometry property diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreePlugin.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreePlugin.kt index b3d6db64..ddcff805 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreePlugin.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreePlugin.kt @@ -16,7 +16,7 @@ import info.laht.threekt.objects.Group as ThreeGroup class ThreePlugin : AbstractPlugin() { override val tag: PluginTag get() = Companion.tag - private val objectFactories = HashMap, ThreeFactory<*>>() + private val objectFactories = HashMap, ThreeFactory<*>>() private val compositeFactory = ThreeCompositeFactory(this) private val proxyFactory = ThreeProxyFactory(this) @@ -29,9 +29,11 @@ class ThreePlugin : AbstractPlugin() { objectFactories[PolyLine::class] = ThreeLineFactory } - private fun findObjectFactory(type: KClass): ThreeFactory<*>? { - return objectFactories[type] - ?: context.content>(ThreeFactory.TYPE).values.find { it.type == type } + @Suppress("UNCHECKED_CAST") + private fun findObjectFactory(type: KClass): ThreeFactory? { + return (objectFactories[type] + ?: context.content>(ThreeFactory.TYPE).values.find { it.type == type }) + as ThreeFactory? } fun buildObject3D(obj: VisualObject3D): Object3D { @@ -73,7 +75,7 @@ class ThreePlugin : AbstractPlugin() { is Composite -> compositeFactory(obj) else -> { //find specialized factory for this type if it is present - val factory = findObjectFactory(obj::class) + val factory: ThreeFactory? = findObjectFactory(obj::class) when { factory != null -> factory(obj) obj is Shape -> ThreeShapeFactory(obj) diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeVisualObject.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeVisualObject.kt index 36095377..5970a76d 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeVisualObject.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeVisualObject.kt @@ -3,13 +3,10 @@ package hep.dataforge.vis.spatial.three import hep.dataforge.io.serialization.ConfigSerializer -import hep.dataforge.io.toMeta import hep.dataforge.meta.Config -import hep.dataforge.meta.Meta import hep.dataforge.vis.common.AbstractVisualObject import hep.dataforge.vis.spatial.Point3D import hep.dataforge.vis.spatial.Point3DSerializer -import hep.dataforge.vis.spatial.Visual3DPlugin import hep.dataforge.vis.spatial.VisualObject3D import info.laht.threekt.core.Object3D import kotlinx.serialization.Serializable @@ -32,8 +29,6 @@ class CustomThreeVisualObject(val threeFactory: ThreeFactory) : @Serializable(ConfigSerializer::class) override var properties: Config? = null - override fun toMeta(): Meta = Visual3DPlugin.json.toJson(serializer(), this).toMeta() - override fun toObject3D(): Object3D = threeFactory(this) } \ No newline at end of file diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/Canvas3D.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/Canvas3D.kt index 211c0d41..bf95d931 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/Canvas3D.kt +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/Canvas3D.kt @@ -1,5 +1,11 @@ package hep.dataforge.vis.spatial.fx +import hep.dataforge.context.Context +import hep.dataforge.context.ContextAware +import hep.dataforge.meta.EmptyMeta +import hep.dataforge.meta.Meta +import hep.dataforge.output.Renderer +import hep.dataforge.vis.spatial.VisualObject3D import hep.dataforge.vis.spatial.World.CAMERA_FAR_CLIP import hep.dataforge.vis.spatial.World.CAMERA_INITIAL_DISTANCE import hep.dataforge.vis.spatial.World.CAMERA_INITIAL_X_ANGLE @@ -16,7 +22,9 @@ import javafx.scene.paint.Color import org.fxyz3d.utils.CameraTransformer import tornadofx.* -class Canvas3D : Fragment() { +class Canvas3D(val plugin: FX3DPlugin, val meta: Meta = EmptyMeta) : Fragment(), Renderer, ContextAware { + + override val context: Context get() = plugin.context val world: Group = Group() private val camera = PerspectiveCamera().apply { @@ -153,6 +161,10 @@ class Canvas3D : Fragment() { } } + override fun render(obj: VisualObject3D, meta: Meta) { + plugin.buildNode(obj)?.let { world.children.add(it) } + } + companion object { private const val AXIS_LENGTH = 2000.0 private const val CONTROL_MULTIPLIER = 0.1 diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/DisplayObjectFXListener.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/DisplayObjectFXBinding.kt similarity index 96% rename from dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/DisplayObjectFXListener.kt rename to dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/DisplayObjectFXBinding.kt index b0d3089e..b0d66ed8 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/DisplayObjectFXListener.kt +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/DisplayObjectFXBinding.kt @@ -10,7 +10,7 @@ import tornadofx.* /** * A caching binding collection for [VisualObject] properties */ -class DisplayObjectFXListener(val obj: VisualObject) { +class DisplayObjectFXBinding(val obj: VisualObject) { private val binndings = HashMap?>>() init { diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DOutput.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DOutput.kt deleted file mode 100644 index 7497ead5..00000000 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DOutput.kt +++ /dev/null @@ -1,50 +0,0 @@ -package hep.dataforge.vis.spatial.fx - -import hep.dataforge.context.Context -import hep.dataforge.meta.Meta -import hep.dataforge.output.Renderer -import hep.dataforge.vis.common.VisualObject -import hep.dataforge.vis.spatial.Box -import hep.dataforge.vis.spatial.VisualGroup3D -import javafx.scene.Group -import javafx.scene.Node -import org.fxyz3d.shapes.primitives.CuboidMesh -import tornadofx.* - -/** - * https://github.com/miho/JCSG for operations - * - */ -class FX3DOutput(override val context: Context) : Renderer { - val canvas by lazy { Canvas3D() } - - - private fun buildNode(obj: VisualObject): Node? { - val listener = DisplayObjectFXListener(obj) - val x = listener["pos.x"].float() - val y = listener["pos.y"].float() - val z = listener["pos.z"].float() - val center = objectBinding(x, y, z) { - org.fxyz3d.geometry.Point3D(x.value ?: 0f, y.value ?: 0f, z.value ?: 0f) - } - return when (obj) { - is VisualGroup3D -> Group(obj.map { buildNode(it) }).apply { - this.translateXProperty().bind(x) - this.translateYProperty().bind(y) - this.translateZProperty().bind(z) - } - is Box -> CuboidMesh(obj.xSize.toDouble(), obj.ySize.toDouble(), obj.zSize.toDouble()).apply { - this.centerProperty().bind(center) - this.materialProperty().bind(listener["color"].transform { it.material() }) - } - else -> { - logger.error { "No renderer defined for ${obj::class}" } - null - } - } - } - - override fun render(obj: VisualObject, meta: Meta) { - buildNode(obj)?.let { canvas.world.children.add(it) } - } -} \ No newline at end of file diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DPlugin.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DPlugin.kt new file mode 100644 index 00000000..4e28730a --- /dev/null +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DPlugin.kt @@ -0,0 +1,113 @@ +package hep.dataforge.vis.spatial.fx + +import hep.dataforge.context.* +import hep.dataforge.meta.Meta +import hep.dataforge.meta.get +import hep.dataforge.provider.Type +import hep.dataforge.vis.spatial.* +import hep.dataforge.vis.spatial.fx.FX3DFactory.Companion.TYPE +import javafx.scene.Group +import javafx.scene.Node +import javafx.scene.shape.Shape3D +import javafx.scene.transform.Rotate +import org.fxyz3d.shapes.composites.PolyLine3D +import org.fxyz3d.shapes.primitives.CuboidMesh +import kotlin.reflect.KClass + +class FX3DPlugin : AbstractPlugin() { + override val tag: PluginTag get() = Companion.tag + + private val objectFactories = HashMap, FX3DFactory<*>>() + private val compositeFactory = FXCompositeFactory(this) + private val proxyFactory = FXProxyFactory(this) + + init { + //Add specialized factories here + objectFactories[Convex::class] = FXConvexFactory + } + + + @Suppress("UNCHECKED_CAST") + private fun findObjectFactory(type: KClass): FX3DFactory? { + return (objectFactories[type] ?: context.content>(TYPE).values.find { it.type == type }) + as FX3DFactory? + } + + fun buildNode(obj: VisualObject3D): Node? { + val binding = DisplayObjectFXBinding(obj) + return when (obj) { + is Proxy -> proxyFactory(obj, binding) + is VisualGroup3D -> Group(obj.filterIsInstance().map { buildNode(it) }) + is Composite -> compositeFactory(obj, binding) + is Box -> CuboidMesh(obj.xSize.toDouble(), obj.ySize.toDouble(), obj.zSize.toDouble()) + is PolyLine -> PolyLine3D( + obj.points.map { it.point }, + obj.thickness.toFloat(), + obj.material?.get("color")?.color() + ) + else -> { + //find specialized factory for this type if it is present + val factory: FX3DFactory? = findObjectFactory(obj::class) + when { + factory != null -> factory(obj, binding) + obj is Shape -> FXShapeFactory(obj, binding) + else -> error("Renderer for ${obj::class} not found") + } + } + }.apply { + translateXProperty().bind(binding[VisualObject3D.xPos].float()) + translateYProperty().bind(binding[VisualObject3D.yPos].float()) + translateZProperty().bind(binding[VisualObject3D.zPos].float()) + scaleXProperty().bind(binding[VisualObject3D.xScale].float()) + scaleYProperty().bind(binding[VisualObject3D.yScale].float()) + scaleZProperty().bind(binding[VisualObject3D.zScale].float()) + + val rotateX = Rotate(0.0, Rotate.X_AXIS).apply { + angleProperty().bind(binding[VisualObject3D.xRotation].float()) + } + + val rotateY = Rotate(0.0, Rotate.Y_AXIS).apply { + angleProperty().bind(binding[VisualObject3D.yRotation].float()) + } + + val rotateZ = Rotate(0.0, Rotate.Z_AXIS).apply { + angleProperty().bind(binding[VisualObject3D.zRotation].float()) + } + + when (obj.rotationOrder) { + RotationOrder.ZYX -> transforms.addAll(rotateZ, rotateY, rotateX) + RotationOrder.XZY -> transforms.addAll(rotateY, rotateZ, rotateX) + RotationOrder.YXZ -> transforms.addAll(rotateZ, rotateX, rotateY) + RotationOrder.YZX -> transforms.addAll(rotateX, rotateZ, rotateY) + RotationOrder.ZXY -> transforms.addAll(rotateY, rotateX, rotateZ) + RotationOrder.XYZ -> transforms.addAll(rotateZ, rotateY, rotateX) + } + + if (this is Shape3D) { + materialProperty().bind(binding["color"].transform { it.material() }) + } + } + } + + companion object : PluginFactory { + override val tag = PluginTag("visual.fx3D", PluginTag.DATAFORGE_GROUP) + override val type = FX3DPlugin::class + override fun invoke(meta: Meta, context: Context) = FX3DPlugin() + } +} + +/** + * Builder and updater for three.js object + */ +@Type(TYPE) +interface FX3DFactory { + + val type: KClass + + operator fun invoke(obj: T, binding: DisplayObjectFXBinding): Node + + companion object { + const val TYPE = "fx3DFactory" + } +} + diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXCompositeFactory.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXCompositeFactory.kt new file mode 100644 index 00000000..e5efbf78 --- /dev/null +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXCompositeFactory.kt @@ -0,0 +1,38 @@ +package hep.dataforge.vis.spatial.fx + +import eu.mihosoft.jcsg.CSG +import hep.dataforge.vis.spatial.Composite +import hep.dataforge.vis.spatial.CompositeType +import javafx.scene.Group +import javafx.scene.Node +import javafx.scene.shape.MeshView +import org.fxyz3d.utils.MeshUtils +import kotlin.reflect.KClass + +class FXCompositeFactory(val plugin: FX3DPlugin) : + FX3DFactory { + override val type: KClass + get() = Composite::class + + override fun invoke(obj: Composite, binding: DisplayObjectFXBinding): Node { + val first = plugin.buildNode(obj.first) as? MeshView ?: error("Can't build node") + val second = plugin.buildNode(obj.second) as? MeshView ?: error("Can't build node") + val firstCSG = MeshUtils.mesh2CSG(first) + val secondCSG = MeshUtils.mesh2CSG(second) + val resultCSG = when(obj.compositeType){ + CompositeType.UNION -> firstCSG.union(secondCSG) + CompositeType.INTERSECT -> firstCSG.intersect(secondCSG) + CompositeType.SUBTRACT -> firstCSG.difference(secondCSG) + } + return resultCSG.toNode() + } +} + +internal fun CSG.toNode(): Node{ + val meshes = toJavaFXMesh().asMeshViews + return if(meshes.size == 1){ + meshes.first() + } else { + Group(meshes.map { it }) + } +} \ No newline at end of file diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXConvexFactory.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXConvexFactory.kt new file mode 100644 index 00000000..386cdf31 --- /dev/null +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXConvexFactory.kt @@ -0,0 +1,19 @@ +package hep.dataforge.vis.spatial.fx + +import eu.mihosoft.jcsg.PropertyStorage +import eu.mihosoft.jcsg.ext.quickhull3d.HullUtil +import eu.mihosoft.vvecmath.Vector3d +import hep.dataforge.vis.spatial.Convex +import javafx.scene.Node +import kotlin.reflect.KClass + + +object FXConvexFactory : FX3DFactory { + override val type: KClass get() = Convex::class + + override fun invoke(obj: Convex, binding: DisplayObjectFXBinding): Node { + val hull = HullUtil.hull(obj.points.map { Vector3d.xyz(it.x, it.y, it.z) }, PropertyStorage()) + return hull.toNode() + } + +} \ No newline at end of file diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXProxyFactory.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXProxyFactory.kt new file mode 100644 index 00000000..d42362b2 --- /dev/null +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXProxyFactory.kt @@ -0,0 +1,15 @@ +package hep.dataforge.vis.spatial.fx + +import hep.dataforge.vis.spatial.Proxy +import javafx.scene.Node +import kotlin.reflect.KClass + +class FXProxyFactory(val plugin: FX3DPlugin) : + FX3DFactory { + override val type: KClass get() = Proxy::class + + override fun invoke(obj: Proxy, binding: DisplayObjectFXBinding): Node { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + +} \ No newline at end of file diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXShapeFactory.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXShapeFactory.kt new file mode 100644 index 00000000..eb3f6925 --- /dev/null +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXShapeFactory.kt @@ -0,0 +1,58 @@ +package hep.dataforge.vis.spatial.fx + +import hep.dataforge.meta.Meta +import hep.dataforge.vis.spatial.GeometryBuilder +import hep.dataforge.vis.spatial.Point3D +import hep.dataforge.vis.spatial.Shape +import javafx.scene.shape.Mesh +import javafx.scene.shape.MeshView +import javafx.scene.shape.TriangleMesh +import kotlin.reflect.KClass + +object FXShapeFactory : FX3DFactory { + override val type: KClass get() = Shape::class + + override fun invoke(obj: Shape, binding: DisplayObjectFXBinding): MeshView { + val mesh = FXGeometryBuilder().apply { obj.toGeometry(this) }.build() + return MeshView(mesh) + } +} + +private typealias Face = IntArray + +private class FXGeometryBuilder : GeometryBuilder { + val vertices = ArrayList() + val faces = ArrayList() + private val vertexCache = HashMap() + + private fun append(vertex: Point3D): Int { + val index = vertexCache[vertex] ?: -1//vertices.indexOf(vertex) + return if (index > 0) { + index + } else { + vertices.add(vertex) + vertexCache[vertex] = vertices.size - 1 + vertices.size - 1 + } + } + + override fun face(vertex1: Point3D, vertex2: Point3D, vertex3: Point3D, normal: Point3D?, meta: Meta) { + //adding vertices + val face: Face = intArrayOf(append(vertex1), append(vertex2), append(vertex3)) + faces.add(face) + } + + override fun build(): Mesh { + val mesh = TriangleMesh() + vertices.forEach { + //TODO optimize copy + mesh.points.addAll(it.x.toFloat(), it.y.toFloat(), it.z.toFloat()) + } + faces.forEach { + mesh.faces.addAll(it[0], it[1], it[2]) + } + return mesh + } + +} + diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/RendererDemoApp.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/RendererDemoApp.kt index cd4bc32c..1349280c 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/RendererDemoApp.kt +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/RendererDemoApp.kt @@ -16,9 +16,10 @@ class RendererDemoApp : App(RendererDemoView::class) class RendererDemoView : View() { - val renderer = FX3DOutput(Global) + val plugin = Global.plugins.fetch(FX3DPlugin) + val renderer = Canvas3D(plugin) override val root: Parent = borderpane { - center = renderer.canvas.root + center = renderer.root } lateinit var group: VisualGroup3D @@ -44,7 +45,7 @@ class RendererDemoView : View() { } } - renderer.canvas.apply { + renderer.apply { angleY = -30.0 angleX = -15.0 } diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/geometryJVM.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/geometryJVM.kt index 3e56de87..affc7f8c 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/geometryJVM.kt +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/geometryJVM.kt @@ -5,8 +5,28 @@ actual class Point2D actual constructor(x: Number, y: Number) { actual var y = y.toDouble() } -actual class Point3D actual constructor(x: Number, y: Number, z: Number) { - actual var x = x.toDouble() - actual var y = y.toDouble() - actual var z = z.toDouble() +actual class Point3D(val point: org.fxyz3d.geometry.Point3D) { + actual constructor(x: Number, y: Number, z: Number) : this( + org.fxyz3d.geometry.Point3D( + x.toFloat(), + y.toFloat(), + z.toFloat() + ) + ) + + actual var x: Double + inline get() = point.x.toDouble() + inline set(value) { + point.x = value.toFloat() + } + actual var y: Double + inline get() = point.y.toDouble() + inline set(value) { + point.y = value.toFloat() + } + actual var z: Double + inline get() = point.z.toDouble() + inline set(value) { + point.z = value.toFloat() + } } \ No newline at end of file diff --git a/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoGrid.kt b/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoGrid.kt index ff8a2f88..94e9b709 100644 --- a/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoGrid.kt +++ b/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoGrid.kt @@ -10,12 +10,12 @@ import hep.dataforge.meta.get import hep.dataforge.meta.string import hep.dataforge.names.Name import hep.dataforge.names.toName -import hep.dataforge.output.Output import hep.dataforge.output.OutputManager +import hep.dataforge.output.Renderer import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.spatial.VisualGroup3D import hep.dataforge.vis.spatial.render -import hep.dataforge.vis.spatial.three.ThreeOutput +import hep.dataforge.vis.spatial.three.ThreeCanvas import hep.dataforge.vis.spatial.three.ThreePlugin import hep.dataforge.vis.spatial.three.output import kotlinx.html.dom.append @@ -33,7 +33,7 @@ class ThreeDemoGrid(meta: Meta) : AbstractPlugin(meta), OutputManager { override val tag: PluginTag get() = Companion.tag private val gridRoot = document.create.div("row") - private val outputs: MutableMap = HashMap() + private val outputs: MutableMap = HashMap() init { require(ThreePlugin) @@ -48,7 +48,7 @@ class ThreeDemoGrid(meta: Meta) : AbstractPlugin(meta), OutputManager { } @Suppress("UNCHECKED_CAST") - override fun get(type: KClass, name: Name, stage: Name, meta: Meta): Output { + override fun get(type: KClass, name: Name, stage: Name, meta: Meta): Renderer { val three = context.plugins.get()!! return outputs.getOrPut(name) { @@ -73,7 +73,7 @@ class ThreeDemoGrid(meta: Meta) : AbstractPlugin(meta), OutputManager { } output - } as Output + } as Renderer } companion object : PluginFactory { From fd43ea484303bd50d10b5e3c24e1796b18294373 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 15 Dec 2019 10:56:44 +0300 Subject: [PATCH 10/25] FX backend in progress --- .../SpatialDemoApp.kt} | 23 +++++++------- .../hep/dataforge/vis/spatial/fx/Canvas3D.kt | 31 ++++++++++++------- .../dataforge/vis/spatial/fx/FX3DPlugin.kt | 2 +- .../fx/{Materials.kt => FXMaterials.kt} | 15 +++++---- .../vis/spatial/fx/FXShapeFactory.kt | 9 +++--- 5 files changed, 46 insertions(+), 34 deletions(-) rename dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/{fx/RendererDemoApp.kt => demo/SpatialDemoApp.kt} (67%) rename dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/{Materials.kt => FXMaterials.kt} (82%) diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/RendererDemoApp.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/SpatialDemoApp.kt similarity index 67% rename from dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/RendererDemoApp.kt rename to dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/SpatialDemoApp.kt index 1349280c..0a9fc4b7 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/RendererDemoApp.kt +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/SpatialDemoApp.kt @@ -1,8 +1,10 @@ -package hep.dataforge.vis.spatial.fx +package hep.dataforge.vis.spatial.demo import hep.dataforge.context.Global import hep.dataforge.meta.number import hep.dataforge.vis.spatial.* +import hep.dataforge.vis.spatial.fx.Canvas3D +import hep.dataforge.vis.spatial.fx.FX3DPlugin import javafx.scene.Parent import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.delay @@ -11,22 +13,21 @@ import kotlinx.coroutines.launch import tornadofx.* import kotlin.random.Random +class SpatialDemoApp: App(SpatialDemoView::class) -class RendererDemoApp : App(RendererDemoView::class) +class SpatialDemoView: View(){ + private val plugin = Global.plugins.fetch(FX3DPlugin) + private val canvas = Canvas3D(plugin) - -class RendererDemoView : View() { - val plugin = Global.plugins.fetch(FX3DPlugin) - val renderer = Canvas3D(plugin) override val root: Parent = borderpane { - center = renderer.root + center = canvas.root } lateinit var group: VisualGroup3D init { - - renderer.render { + canvas.render { + box(100,100,100) group = group { box(100,100,100) box(100,100,100) { @@ -45,7 +46,7 @@ class RendererDemoView : View() { } } - renderer.apply { + canvas.apply { angleY = -30.0 angleX = -15.0 } @@ -54,5 +55,5 @@ class RendererDemoView : View() { fun main() { - launch() + launch() } \ No newline at end of file diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/Canvas3D.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/Canvas3D.kt index bf95d931..fd6cbc40 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/Canvas3D.kt +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/Canvas3D.kt @@ -19,13 +19,21 @@ import javafx.scene.input.KeyEvent import javafx.scene.input.MouseEvent import javafx.scene.input.ScrollEvent import javafx.scene.paint.Color +import org.fxyz3d.scene.Axes +import org.fxyz3d.scene.CubeWorld import org.fxyz3d.utils.CameraTransformer import tornadofx.* -class Canvas3D(val plugin: FX3DPlugin, val meta: Meta = EmptyMeta) : Fragment(), Renderer, ContextAware { +class Canvas3D(val plugin: FX3DPlugin, meta: Meta = EmptyMeta) : + Fragment(), Renderer, ContextAware { override val context: Context get() = plugin.context - val world: Group = Group() + val world = CubeWorld(true) + val axes = Axes().also { + it.setHeight(AXIS_LENGTH) + it.setRadius(LINE_WIDTH) + world.add(it) + } private val camera = PerspectiveCamera().apply { nearClip = CAMERA_NEAR_CLIP @@ -69,12 +77,12 @@ class Canvas3D(val plugin: FX3DPlugin, val meta: Meta = EmptyMeta) : Fragment(), 768.0, true, SceneAntialiasing.BALANCED - ).apply { - fill = Color.GREY - this.camera = this@Canvas3D.camera + ).also {scene-> + scene.fill = Color.GREY + scene.camera = camera id = "canvas" - handleKeyboard(this) - handleMouse(this) + handleKeyboard(scene) + handleMouse(scene) } } @@ -90,7 +98,7 @@ class Canvas3D(val plugin: FX3DPlugin, val meta: Meta = EmptyMeta) : Fragment(), cameraRotation.ry.angle = CAMERA_INITIAL_Y_ANGLE cameraRotation.rx.angle = CAMERA_INITIAL_X_ANGLE } -// KeyCode.X -> axisGroup.isVisible = !axisGroup.isVisible + KeyCode.X -> axes.isVisible = !axes.isVisible // KeyCode.S -> snapshot() // KeyCode.DIGIT1 -> pixelMap.filterKeys { it.getLayerNumber() == 1 }.values.forEach { // toggleTransparency( @@ -145,8 +153,8 @@ class Canvas3D(val plugin: FX3DPlugin, val meta: Meta = EmptyMeta) : Fragment(), } if (me.isPrimaryButtonDown) { - cameraRotation.rz.angle = - cameraRotation.rz.angle + mouseDeltaX * MOUSE_SPEED * modifier * ROTATION_SPEED + cameraRotation.ry.angle = + cameraRotation.ry.angle + mouseDeltaX * MOUSE_SPEED * modifier * ROTATION_SPEED cameraRotation.rx.angle = cameraRotation.rx.angle + mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED } else if (me.isSecondaryButtonDown) { @@ -162,7 +170,8 @@ class Canvas3D(val plugin: FX3DPlugin, val meta: Meta = EmptyMeta) : Fragment(), } override fun render(obj: VisualObject3D, meta: Meta) { - plugin.buildNode(obj)?.let { world.children.add(it) } + val node = plugin.buildNode(obj) ?: kotlin.error("Can't render FX node for object $obj") + world.add(node) } companion object { diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DPlugin.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DPlugin.kt index 4e28730a..1a1aa430 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DPlugin.kt +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DPlugin.kt @@ -84,7 +84,7 @@ class FX3DPlugin : AbstractPlugin() { } if (this is Shape3D) { - materialProperty().bind(binding["color"].transform { it.material() }) + materialProperty().bind(binding[Material3D.MATERIAL_KEY].transform { it.material() }) } } } diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/Materials.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXMaterials.kt similarity index 82% rename from dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/Materials.kt rename to dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXMaterials.kt index 626a3594..174c3559 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/Materials.kt +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXMaterials.kt @@ -9,7 +9,7 @@ import javafx.scene.paint.Color import javafx.scene.paint.Material import javafx.scene.paint.PhongMaterial -object Materials { +object FXMaterials { val RED = PhongMaterial().apply { diffuseColor = Color.DARKRED specularColor = Color.RED @@ -30,8 +30,9 @@ object Materials { /** * Infer color based on meta item + * @param opacity default opacity */ -fun MetaItem<*>.color(): Color { +fun MetaItem<*>.color(opacity: Double = 1.0): Color { return when (this) { is MetaItem.ValueItem -> if (this.value.type == ValueType.STRING) { Color.web(this.value.string) @@ -47,7 +48,7 @@ fun MetaItem<*>.color(): Color { node["red"]?.int ?: 0, node["green"]?.int ?: 0, node["blue"]?.int ?: 0, - node["opacity"]?.double ?: 1.0 + node["opacity"]?.double ?: opacity ) } } @@ -58,11 +59,13 @@ fun MetaItem<*>.color(): Color { */ fun MetaItem<*>?.material(): Material { return when (this) { - null -> Materials.GREY + null -> FXMaterials.GREY is MetaItem.ValueItem -> PhongMaterial(color()) is MetaItem.NodeItem -> PhongMaterial().apply { - (node["color"]?: this@material).let { diffuseColor = it.color() } - node["specularColor"]?.let { specularColor = it.color() } + val opacity = node["opacity"].double ?: 1.0 + (node["color"] ?: this@material).let { diffuseColor = it.color(opacity) } + node["specularColor"]?.let { specularColor = it.color(opacity) } + } } } diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXShapeFactory.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXShapeFactory.kt index eb3f6925..93868b54 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXShapeFactory.kt +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXShapeFactory.kt @@ -7,6 +7,7 @@ import hep.dataforge.vis.spatial.Shape import javafx.scene.shape.Mesh import javafx.scene.shape.MeshView import javafx.scene.shape.TriangleMesh +import org.fxyz3d.geometry.Face3 import kotlin.reflect.KClass object FXShapeFactory : FX3DFactory { @@ -18,11 +19,9 @@ object FXShapeFactory : FX3DFactory { } } -private typealias Face = IntArray - private class FXGeometryBuilder : GeometryBuilder { val vertices = ArrayList() - val faces = ArrayList() + val faces = ArrayList() private val vertexCache = HashMap() private fun append(vertex: Point3D): Int { @@ -38,7 +37,7 @@ private class FXGeometryBuilder : GeometryBuilder { override fun face(vertex1: Point3D, vertex2: Point3D, vertex3: Point3D, normal: Point3D?, meta: Meta) { //adding vertices - val face: Face = intArrayOf(append(vertex1), append(vertex2), append(vertex3)) + val face = Face3(append(vertex1), append(vertex2), append(vertex3)) faces.add(face) } @@ -49,7 +48,7 @@ private class FXGeometryBuilder : GeometryBuilder { mesh.points.addAll(it.x.toFloat(), it.y.toFloat(), it.z.toFloat()) } faces.forEach { - mesh.faces.addAll(it[0], it[1], it[2]) + mesh.faces.addAll(it.p0, it.p1, it.p2) } return mesh } From 0164534004ee0e102e43fcaae3ca4da2519d8960 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 15 Dec 2019 22:15:14 +0300 Subject: [PATCH 11/25] FX backend in progress --- .../kotlin/hep/dataforge/vis/common/Colors.kt | 7 - .../vis/spatial/gdml/GDMLTransformer.kt | 3 +- dataforge-vis-spatial/build.gradle.kts | 1 + .../hep/dataforge/vis/spatial/Material3D.kt | 15 +- .../hep/dataforge/vis/spatial/Sphere.kt | 11 +- .../vis/spatial/three/ThreeMaterials.kt | 12 +- .../dataforge/vis/spatial/demo/FXDemoApp.kt | 211 ++++++++++++++++++ .../dataforge/vis/spatial/demo/FXDemoGrid.kt | 58 +++++ .../vis/spatial/demo/SpatialDemoApp.kt | 59 ----- .../vis/spatial/fx/DisplayObjectFXBinding.kt | 42 ---- .../dataforge/vis/spatial/fx/FX3DPlugin.kt | 46 ++-- .../spatial/fx/{Canvas3D.kt => FXCanvas3D.kt} | 70 +++--- .../vis/spatial/fx/FXCompositeFactory.kt | 2 +- .../vis/spatial/fx/FXConvexFactory.kt | 2 +- .../dataforge/vis/spatial/fx/FXMaterials.kt | 15 +- .../vis/spatial/fx/FXProxyFactory.kt | 45 +++- .../vis/spatial/fx/FXShapeFactory.kt | 2 +- .../vis/spatial/fx/VisualObjectFXBinding.kt | 54 +++++ 18 files changed, 467 insertions(+), 188 deletions(-) create mode 100644 dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt create mode 100644 dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoGrid.kt delete mode 100644 dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/SpatialDemoApp.kt delete mode 100644 dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/DisplayObjectFXBinding.kt rename dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/{Canvas3D.kt => FXCanvas3D.kt} (70%) create mode 100644 dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/VisualObjectFXBinding.kt diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/Colors.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/Colors.kt index 1f42d87c..780a6874 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/Colors.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/Colors.kt @@ -1,7 +1,5 @@ package hep.dataforge.vis.common -import kotlin.math.max - /** * Taken from https://github.com/markaren/three.kt/blob/master/threejs-wrapper/src/main/kotlin/info/laht/threekt/math/ColorConstants.kt */ @@ -177,11 +175,6 @@ object Colors { const val yellow = 0xFFFF00 const val yellowgreen = 0x9ACD32 - fun rgbToString(rgb: Int): String { - val string = rgb.toString(16).padStart(6, '0') - return "#" + string.substring(max(0, string.length - 6)) - } - fun rgbToString(red: UByte, green: UByte, blue: UByte): String { fun colorToString(color: UByte): String{ return color.toString(16).padStart(2,'0') diff --git a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt index 6b11338c..698c5ada 100644 --- a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt +++ b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt @@ -5,7 +5,6 @@ import hep.dataforge.meta.MetaBuilder import hep.dataforge.meta.buildMeta import hep.dataforge.names.Name import hep.dataforge.names.toName -import hep.dataforge.vis.common.Colors import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.common.applyStyle import hep.dataforge.vis.spatial.Material3D.Companion.COLOR_KEY @@ -53,7 +52,7 @@ class GDMLTransformer(val root: GDML) { val styleName = "material[${material.name}]" obj.useStyle(styleName){ - COLOR_KEY to Colors.rgbToString(random.nextInt(0, Int.MAX_VALUE)) + COLOR_KEY to random.nextInt(0, Int.MAX_VALUE) "gdml.material" put material.name } diff --git a/dataforge-vis-spatial/build.gradle.kts b/dataforge-vis-spatial/build.gradle.kts index 67352978..203cd2b7 100644 --- a/dataforge-vis-spatial/build.gradle.kts +++ b/dataforge-vis-spatial/build.gradle.kts @@ -22,6 +22,7 @@ kotlin { jvmMain { dependencies { api("org.fxyz3d:fxyz3d:0.5.2") + api("org.jetbrains.kotlinx:kotlinx-coroutines-javafx:${Scientifik.coroutinesVersion}") implementation("eu.mihosoft.vrl.jcsg:jcsg:0.5.7") } } diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Material3D.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Material3D.kt index 645c0cf5..68913c55 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Material3D.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Material3D.kt @@ -3,7 +3,6 @@ package hep.dataforge.vis.spatial import hep.dataforge.meta.* import hep.dataforge.names.asName import hep.dataforge.names.plus -import hep.dataforge.vis.common.Colors import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.spatial.Material3D.Companion.COLOR_KEY import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_KEY @@ -20,6 +19,7 @@ class Material3D(override val config: Config) : Specific { val MATERIAL_KEY = "material".asName() val COLOR_KEY = MATERIAL_KEY + "color" + val SPECULAR_COLOR = MATERIAL_KEY + "specularColor" val OPACITY_KEY = MATERIAL_KEY + "opacity" } @@ -29,9 +29,18 @@ fun VisualObject.color(rgb: String) { setProperty(COLOR_KEY, rgb) } -fun VisualObject.color(rgb: Int) = color(Colors.rgbToString(rgb)) +fun VisualObject.color(rgb: Int) { + setProperty(COLOR_KEY, rgb) +} -fun VisualObject.color(r: UByte, g: UByte, b: UByte) = color(Colors.rgbToString(r, g, b)) +fun VisualObject.color(r: UByte, g: UByte, b: UByte) = setProperty( + COLOR_KEY, + buildMeta { + "red" put r.toInt() + "green" put g.toInt() + "blue" put b.toInt() + } +) var VisualObject.color: String? get() = getProperty(COLOR_KEY).string diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Sphere.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Sphere.kt index f762a48a..26a9e820 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Sphere.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Sphere.kt @@ -26,7 +26,16 @@ class Sphere( override var scale: Point3D? = null override fun toGeometry(geometryBuilder: GeometryBuilder) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") +// val segments = this.detail ?: 8 +// require(segments >= 4) { "The detail for sphere must be >= 4" } +// val phiStep = phi / segments +// val thetaStep = theta / segments +// for (i in 1 until segments - 1) { +// for (j in 0 until segments - 1) { +// val point1 = Point3D() +// } +// } } } diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeMaterials.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeMaterials.kt index 4b4309d8..4ac3d4a8 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeMaterials.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeMaterials.kt @@ -11,6 +11,7 @@ import info.laht.threekt.materials.MeshBasicMaterial import info.laht.threekt.materials.MeshPhongMaterial import info.laht.threekt.math.Color import info.laht.threekt.objects.Mesh +import kotlin.math.max object ThreeMaterials { @@ -46,6 +47,11 @@ object ThreeMaterials { } } + fun rgbToString(rgb: Int): String { + val string = rgb.toString(16).padStart(6, '0') + return "#" + string.substring(max(0, string.length - 6)) + } + } /** @@ -53,11 +59,11 @@ object ThreeMaterials { */ fun MetaItem<*>.color(): Color { return when (this) { - is MetaItem.ValueItem -> if (this.value.type == ValueType.STRING) { - Color(this.value.string) - } else { + is MetaItem.ValueItem -> if (this.value.type == ValueType.NUMBER) { val int = value.number.toInt() Color(int) + } else { + Color(this.value.string) } is MetaItem.NodeItem -> { Color( diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt new file mode 100644 index 00000000..489b536c --- /dev/null +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt @@ -0,0 +1,211 @@ +package hep.dataforge.vis.spatial.demo + +import hep.dataforge.vis.common.Colors +import hep.dataforge.vis.spatial.* +import javafx.stage.Stage +import kotlinx.coroutines.* +import kotlinx.coroutines.javafx.JavaFx +import tornadofx.* +import kotlin.math.PI +import kotlin.math.cos +import kotlin.math.sin +import kotlin.random.Random + +class FXDemoApp : App(FXDemoGrid::class) { + + val view: FXDemoGrid by inject() + + override fun start(stage: Stage) { + super.start(stage) + view.run { + demo("shapes", "Basic shapes") { + box(100.0, 100.0, 100.0) { + z = 110.0 + } + sphere(50.0) { + x = 110 + detail = 16 + } + tube(50, height = 10, innerRadius = 25, angle = PI) { + y = 110 + detail = 16 + rotationX = PI / 4 + } + } + + demo("dynamic", "Dynamic properties") { + val group = group { + box(100, 100, 100) { + z = 110.0 + } + + box(100, 100, 100) { + visible = false + x = 110.0 + //override color for this cube + color(1530) + + GlobalScope.launch(Dispatchers.JavaFx) { + while (isActive) { + delay(500) + visible = !(visible ?: false) + } + } + } + } + + GlobalScope.launch(Dispatchers.JavaFx) { + val random = Random(111) + while (isActive) { + delay(1000) + group.color(random.nextInt(0, Int.MAX_VALUE)) + } + } + } + + demo("rotation", "Rotations") { + box(100, 100, 100) + group { + x = 200 + rotationY = PI / 4 + box(100, 100, 100) { + rotationZ = PI / 4 + color(Colors.red) + } + } + } + + demo("extrude", "extruded shape") { + extrude { + shape { + polygon(8, 50) + } + for (i in 0..100) { + layer(i * 5, 20 * sin(2 * PI / 100 * i), 20 * cos(2 * PI / 100 * i)) + } + color(Colors.teal) + } + } + +// demo("CSG.simple", "CSG operations") { +// composite(CompositeType.UNION) { +// box(100, 100, 100) { +// z = 50 +// } +// sphere(50) +// material { +// color(Colors.lightgreen) +// opacity = 0.3f +// } +// } +// composite(CompositeType.INTERSECT) { +// y = 300 +// box(100, 100, 100) { +// z = 50 +// } +// sphere(50) +// color(Colors.red) +// } +// composite(CompositeType.SUBTRACT) { +// y = -300 +// box(100, 100, 100) { +// z = 50 +// } +// sphere(50) +// color(Colors.blue) +// } +// } + +// demo("CSG.custom", "CSG with manually created object") { +// intersect { +// box(100, 100, 100) +// tube(60, 10) { +// detail = 180 +// } +// } +// } + + demo("lines", "Track / line segments") { + sphere(100) { + color(Colors.blue) + detail = 50 + opacity = 0.4 + } + repeat(20) { + polyline(Point3D(100, 100, 100), Point3D(-100, -100, -100)) { + thickness = 208.0 + rotationX = it * PI2 / 20 + color(Colors.green) + //rotationY = it * PI2 / 20 + } + } + } + +// demo("dynamicBox", "Dancing boxes") { +// val boxes = (-10..10).flatMap { i -> +// (-10..10).map { j -> +// varBox(10, 10, 0, name = "cell_${i}_${j}") { +// x = i * 10 +// y = j * 10 +// value = 128 +// setProperty(EDGES_ENABLED_KEY, false) +// setProperty(WIREFRAME_ENABLED_KEY, false) +// } +// } +// } +// GlobalScope.launch { +// while (isActive) { +// delay(200) +// boxes.forEach { box -> +// box.value = (box.value + Random.nextInt(-15, 15)).coerceIn(0..255) +// } +// } +// } +// } + + } + } +} + +//class SpatialDemoView : View() { +// private val plugin = Global.plugins.fetch(FX3DPlugin) +// private val canvas = FXCanvas3D(plugin) +// +// override val root: Parent = borderpane { +// center = canvas.root +// } +// +// lateinit var group: VisualGroup3D +// +// init { +// canvas.render { +// group = group { +// box(100, 100, 100) +// box(100, 100, 100) { +// x = 110.0 +// color(Colors.blue) +// } +// } +// } +// +// //var color by group.config.number(1530) +// +// GlobalScope.launch { +// val random = Random(111) +// while (isActive) { +// delay(1000) +// group.color(random.nextInt(0, Int.MAX_VALUE)) +// } +// } +// +//// canvas.apply { +//// angleY = -30.0 +//// angleX = -15.0 +//// } +// } +//} + + +fun main() { + launch() +} \ No newline at end of file diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoGrid.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoGrid.kt new file mode 100644 index 00000000..e6b23039 --- /dev/null +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoGrid.kt @@ -0,0 +1,58 @@ +package hep.dataforge.vis.spatial.demo + +import hep.dataforge.context.Global +import hep.dataforge.meta.Meta +import hep.dataforge.meta.buildMeta +import hep.dataforge.names.Name +import hep.dataforge.names.toName +import hep.dataforge.output.OutputManager +import hep.dataforge.output.Renderer +import hep.dataforge.vis.common.VisualObject +import hep.dataforge.vis.spatial.VisualGroup3D +import hep.dataforge.vis.spatial.fx.FX3DPlugin +import hep.dataforge.vis.spatial.fx.FXCanvas3D +import hep.dataforge.vis.spatial.render +import javafx.collections.FXCollections +import javafx.scene.Parent +import javafx.scene.control.Tab +import tornadofx.* +import kotlin.reflect.KClass + +class FXDemoGrid : View(), OutputManager { + private val outputs = FXCollections.observableHashMap() + + override val root: Parent = borderpane { + center = tabpane { + tabs.bind(outputs) { key: Name, value: FXCanvas3D -> + Tab(key.toString(), value.root) + } + } + } + + private val fx3d = Global.plugins.fetch(FX3DPlugin) + + @Suppress("UNCHECKED_CAST") + override fun get(type: KClass, name: Name, stage: Name, meta: Meta): Renderer { + return outputs.getOrPut(name) { + if (type != VisualObject::class) kotlin.error("Supports only DisplayObject") + val customMeta = buildMeta(meta) { + "minSize" put 500 + "axis" put { + "size" put 500 + } + } + val output = FXCanvas3D(fx3d, customMeta) + + output + } as Renderer + } + +} + +fun FXDemoGrid.demo(name: String, title: String = name, block: VisualGroup3D.() -> Unit) { + val meta = buildMeta { + "title" put title + } + val output = get(VisualObject::class, name.toName(), meta = meta) + output.render(action = block) +} \ No newline at end of file diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/SpatialDemoApp.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/SpatialDemoApp.kt deleted file mode 100644 index 0a9fc4b7..00000000 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/SpatialDemoApp.kt +++ /dev/null @@ -1,59 +0,0 @@ -package hep.dataforge.vis.spatial.demo - -import hep.dataforge.context.Global -import hep.dataforge.meta.number -import hep.dataforge.vis.spatial.* -import hep.dataforge.vis.spatial.fx.Canvas3D -import hep.dataforge.vis.spatial.fx.FX3DPlugin -import javafx.scene.Parent -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.delay -import kotlinx.coroutines.isActive -import kotlinx.coroutines.launch -import tornadofx.* -import kotlin.random.Random - -class SpatialDemoApp: App(SpatialDemoView::class) - -class SpatialDemoView: View(){ - private val plugin = Global.plugins.fetch(FX3DPlugin) - private val canvas = Canvas3D(plugin) - - override val root: Parent = borderpane { - center = canvas.root - } - - lateinit var group: VisualGroup3D - - init { - canvas.render { - box(100,100,100) - group = group { - box(100,100,100) - box(100,100,100) { - x = 110.0 - } - } - } - - var color by group.config.number(1530) - - GlobalScope.launch { - val random = Random(111) - while (isActive) { - delay(1000) - color = random.nextInt(0, Int.MAX_VALUE) - } - } - - canvas.apply { - angleY = -30.0 - angleX = -15.0 - } - } -} - - -fun main() { - launch() -} \ No newline at end of file diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/DisplayObjectFXBinding.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/DisplayObjectFXBinding.kt deleted file mode 100644 index b0d66ed8..00000000 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/DisplayObjectFXBinding.kt +++ /dev/null @@ -1,42 +0,0 @@ -package hep.dataforge.vis.spatial.fx - -import hep.dataforge.meta.* -import hep.dataforge.names.Name -import hep.dataforge.names.toName -import hep.dataforge.vis.common.VisualObject -import javafx.beans.binding.ObjectBinding -import tornadofx.* - -/** - * A caching binding collection for [VisualObject] properties - */ -class DisplayObjectFXBinding(val obj: VisualObject) { - private val binndings = HashMap?>>() - - init { - obj.onPropertyChange(this) { name, _, _ -> - binndings[name]?.invalidate() - } - } - - operator fun get(key: Name): ObjectBinding?> { - return binndings.getOrPut(key) { - object : ObjectBinding?>() { - override fun computeValue(): MetaItem<*>? = obj.getProperty(key) - } - } - } - - operator fun get(key: String) = get(key.toName()) -} - -fun ObjectBinding?>.value() = this.objectBinding { it.value } -fun ObjectBinding?>.string() = this.stringBinding { it.string } -fun ObjectBinding?>.number() = this.objectBinding { it.number } -fun ObjectBinding?>.double() = this.objectBinding { it.double } -fun ObjectBinding?>.float() = this.objectBinding { it.number?.toFloat() } -fun ObjectBinding?>.int() = this.objectBinding { it.int } -fun ObjectBinding?>.long() = this.objectBinding { it.long } -fun ObjectBinding?>.node() = this.objectBinding { it.node } - -fun ObjectBinding?>.transform(transform: (MetaItem<*>) -> T) = this.objectBinding { it?.let(transform) } diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DPlugin.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DPlugin.kt index 1a1aa430..40f2a435 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DPlugin.kt +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DPlugin.kt @@ -12,6 +12,8 @@ import javafx.scene.shape.Shape3D import javafx.scene.transform.Rotate import org.fxyz3d.shapes.composites.PolyLine3D import org.fxyz3d.shapes.primitives.CuboidMesh +import org.fxyz3d.shapes.primitives.SpheroidMesh +import kotlin.math.PI import kotlin.reflect.KClass class FX3DPlugin : AbstractPlugin() { @@ -33,13 +35,27 @@ class FX3DPlugin : AbstractPlugin() { as FX3DFactory? } - fun buildNode(obj: VisualObject3D): Node? { - val binding = DisplayObjectFXBinding(obj) + fun buildNode(obj: VisualObject3D): Node { + val binding = VisualObjectFXBinding(obj) return when (obj) { is Proxy -> proxyFactory(obj, binding) - is VisualGroup3D -> Group(obj.filterIsInstance().map { buildNode(it) }) + is VisualGroup3D -> { + Group(obj.children.mapNotNull { (token, obj) -> + (obj as? VisualObject3D)?.let { + buildNode(it).apply { + properties["name"] = token.toString() + } + } + }) + } is Composite -> compositeFactory(obj, binding) is Box -> CuboidMesh(obj.xSize.toDouble(), obj.ySize.toDouble(), obj.zSize.toDouble()) + is Sphere -> if (obj.phi == PI2 && obj.theta == PI.toFloat()) { + //use sphere for orb + SpheroidMesh(obj.detail ?: 16, obj.radius.toDouble(), obj.radius.toDouble()) + } else { + FXShapeFactory(obj, binding) + } is PolyLine -> PolyLine3D( obj.points.map { it.point }, obj.thickness.toFloat(), @@ -55,23 +71,23 @@ class FX3DPlugin : AbstractPlugin() { } } }.apply { - translateXProperty().bind(binding[VisualObject3D.xPos].float()) - translateYProperty().bind(binding[VisualObject3D.yPos].float()) - translateZProperty().bind(binding[VisualObject3D.zPos].float()) - scaleXProperty().bind(binding[VisualObject3D.xScale].float()) - scaleYProperty().bind(binding[VisualObject3D.yScale].float()) - scaleZProperty().bind(binding[VisualObject3D.zScale].float()) + translateXProperty().bind(binding[VisualObject3D.xPos].float(obj.x.toFloat())) + translateYProperty().bind(binding[VisualObject3D.yPos].float(obj.y.toFloat())) + translateZProperty().bind(binding[VisualObject3D.zPos].float(obj.z.toFloat())) + scaleXProperty().bind(binding[VisualObject3D.xScale].float(obj.scaleX.toFloat())) + scaleYProperty().bind(binding[VisualObject3D.yScale].float(obj.scaleY.toFloat())) + scaleZProperty().bind(binding[VisualObject3D.zScale].float(obj.scaleZ.toFloat())) val rotateX = Rotate(0.0, Rotate.X_AXIS).apply { - angleProperty().bind(binding[VisualObject3D.xRotation].float()) + angleProperty().bind(binding[VisualObject3D.xRotation].float(obj.rotationX.toFloat())) } val rotateY = Rotate(0.0, Rotate.Y_AXIS).apply { - angleProperty().bind(binding[VisualObject3D.yRotation].float()) + angleProperty().bind(binding[VisualObject3D.yRotation].float(obj.rotationY.toFloat())) } val rotateZ = Rotate(0.0, Rotate.Z_AXIS).apply { - angleProperty().bind(binding[VisualObject3D.zRotation].float()) + angleProperty().bind(binding[VisualObject3D.zRotation].float(obj.rotationZ.toFloat())) } when (obj.rotationOrder) { @@ -84,7 +100,9 @@ class FX3DPlugin : AbstractPlugin() { } if (this is Shape3D) { - materialProperty().bind(binding[Material3D.MATERIAL_KEY].transform { it.material() }) + materialProperty().bind(binding[Material3D.MATERIAL_KEY].transform { + it.material() + }) } } } @@ -104,7 +122,7 @@ interface FX3DFactory { val type: KClass - operator fun invoke(obj: T, binding: DisplayObjectFXBinding): Node + operator fun invoke(obj: T, binding: VisualObjectFXBinding): Node companion object { const val TYPE = "fx3DFactory" diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/Canvas3D.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXCanvas3D.kt similarity index 70% rename from dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/Canvas3D.kt rename to dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXCanvas3D.kt index fd6cbc40..7c7663e0 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/Canvas3D.kt +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXCanvas3D.kt @@ -2,15 +2,13 @@ package hep.dataforge.vis.spatial.fx import hep.dataforge.context.Context import hep.dataforge.context.ContextAware -import hep.dataforge.meta.EmptyMeta -import hep.dataforge.meta.Meta +import hep.dataforge.meta.* import hep.dataforge.output.Renderer import hep.dataforge.vis.spatial.VisualObject3D import hep.dataforge.vis.spatial.World.CAMERA_FAR_CLIP import hep.dataforge.vis.spatial.World.CAMERA_INITIAL_DISTANCE import hep.dataforge.vis.spatial.World.CAMERA_INITIAL_X_ANGLE import hep.dataforge.vis.spatial.World.CAMERA_INITIAL_Y_ANGLE -import hep.dataforge.vis.spatial.World.CAMERA_INITIAL_Z_ANGLE import hep.dataforge.vis.spatial.World.CAMERA_NEAR_CLIP import javafx.event.EventHandler import javafx.scene.* @@ -20,19 +18,22 @@ import javafx.scene.input.MouseEvent import javafx.scene.input.ScrollEvent import javafx.scene.paint.Color import org.fxyz3d.scene.Axes -import org.fxyz3d.scene.CubeWorld import org.fxyz3d.utils.CameraTransformer import tornadofx.* -class Canvas3D(val plugin: FX3DPlugin, meta: Meta = EmptyMeta) : +class FXCanvas3D(val plugin: FX3DPlugin, meta: Meta = EmptyMeta) : Fragment(), Renderer, ContextAware { override val context: Context get() = plugin.context - val world = CubeWorld(true) + + val world = Group() + val axes = Axes().also { - it.setHeight(AXIS_LENGTH) - it.setRadius(LINE_WIDTH) + it.setHeight(meta["axis.size"].double ?: AXIS_LENGTH) + it.setRadius(meta["axis.width"].double ?: LINE_WIDTH) + it.isVisible = meta["axis.visible"].boolean ?: (meta["axis"] != null) world.add(it) + } private val camera = PerspectiveCamera().apply { @@ -41,43 +42,32 @@ class Canvas3D(val plugin: FX3DPlugin, meta: Meta = EmptyMeta) : translateZ = CAMERA_INITIAL_DISTANCE } - private val cameraShift = CameraTransformer().apply { - val cameraFlip = CameraTransformer() - cameraFlip.children.add(camera) - cameraFlip.setRotateZ(180.0) - children.add(cameraFlip) + val cameraTransform = CameraTransformer().also { + it.add(camera) } - val translationXProperty get() = cameraShift.t.xProperty() + val translationXProperty get() = cameraTransform.t.xProperty() var translateX by translationXProperty - val translationYProperty get() = cameraShift.t.yProperty() + val translationYProperty get() = cameraTransform.t.yProperty() var translateY by translationYProperty - val translationZProperty get() = cameraShift.t.zProperty() + val translationZProperty get() = cameraTransform.t.zProperty() var translateZ by translationZProperty - private 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 rotationXProperty get() = cameraRotation.rx.angleProperty() + val rotationXProperty get() = cameraTransform.rx.angleProperty() var angleX by rotationXProperty - val rotationYProperty get() = cameraRotation.ry.angleProperty() + val rotationYProperty get() = cameraTransform.ry.angleProperty() var angleY by rotationYProperty - val rotationZProperty get() = cameraRotation.rz.angleProperty() + val rotationZProperty get() = cameraTransform.rz.angleProperty() var angleZ by rotationZProperty - override val root = borderpane { center = SubScene( - Group(world, cameraRotation).apply { DepthTest.ENABLE }, + Group(world, cameraTransform).apply { DepthTest.ENABLE }, 1024.0, 768.0, true, SceneAntialiasing.BALANCED - ).also {scene-> + ).also { scene -> scene.fill = Color.GREY scene.camera = camera id = "canvas" @@ -92,11 +82,11 @@ class Canvas3D(val plugin: FX3DPlugin, meta: Meta = EmptyMeta) : if (event.isControlDown) { when (event.code) { KeyCode.Z -> { - cameraShift.t.x = 0.0 - cameraShift.t.y = 0.0 + translateX = 0.0 + translateY = 0.0 camera.translateZ = CAMERA_INITIAL_DISTANCE - cameraRotation.ry.angle = CAMERA_INITIAL_Y_ANGLE - cameraRotation.rx.angle = CAMERA_INITIAL_X_ANGLE + angleY = CAMERA_INITIAL_Y_ANGLE + angleX = CAMERA_INITIAL_X_ANGLE } KeyCode.X -> axes.isVisible = !axes.isVisible // KeyCode.S -> snapshot() @@ -153,13 +143,11 @@ class Canvas3D(val plugin: FX3DPlugin, meta: Meta = EmptyMeta) : } if (me.isPrimaryButtonDown) { - cameraRotation.ry.angle = - cameraRotation.ry.angle + mouseDeltaX * MOUSE_SPEED * modifier * ROTATION_SPEED - cameraRotation.rx.angle = - cameraRotation.rx.angle + mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED + angleY += mouseDeltaX * MOUSE_SPEED * modifier * ROTATION_SPEED + angleX += mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED } 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 + translateX -= mouseDeltaX * MOUSE_SPEED * modifier * TRACK_SPEED + translateY -= mouseDeltaY * MOUSE_SPEED * modifier * TRACK_SPEED } } scene.onScroll = EventHandler { event -> @@ -171,11 +159,11 @@ class Canvas3D(val plugin: FX3DPlugin, meta: Meta = EmptyMeta) : override fun render(obj: VisualObject3D, meta: Meta) { val node = plugin.buildNode(obj) ?: kotlin.error("Can't render FX node for object $obj") - world.add(node) + world.children.add(node) } companion object { - private const val AXIS_LENGTH = 2000.0 + private const val AXIS_LENGTH = 400.0 private const val CONTROL_MULTIPLIER = 0.1 private const val SHIFT_MULTIPLIER = 10.0 private const val MOUSE_SPEED = 0.1 diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXCompositeFactory.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXCompositeFactory.kt index e5efbf78..1b11f2c0 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXCompositeFactory.kt +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXCompositeFactory.kt @@ -14,7 +14,7 @@ class FXCompositeFactory(val plugin: FX3DPlugin) : override val type: KClass get() = Composite::class - override fun invoke(obj: Composite, binding: DisplayObjectFXBinding): Node { + override fun invoke(obj: Composite, binding: VisualObjectFXBinding): Node { val first = plugin.buildNode(obj.first) as? MeshView ?: error("Can't build node") val second = plugin.buildNode(obj.second) as? MeshView ?: error("Can't build node") val firstCSG = MeshUtils.mesh2CSG(first) diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXConvexFactory.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXConvexFactory.kt index 386cdf31..aeeb2cac 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXConvexFactory.kt +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXConvexFactory.kt @@ -11,7 +11,7 @@ import kotlin.reflect.KClass object FXConvexFactory : FX3DFactory { override val type: KClass get() = Convex::class - override fun invoke(obj: Convex, binding: DisplayObjectFXBinding): Node { + override fun invoke(obj: Convex, binding: VisualObjectFXBinding): Node { val hull = HullUtil.hull(obj.points.map { Vector3d.xyz(it.x, it.y, it.z) }, PropertyStorage()) return hull.toNode() } diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXMaterials.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXMaterials.kt index 174c3559..2237a46b 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXMaterials.kt +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXMaterials.kt @@ -12,7 +12,7 @@ import javafx.scene.paint.PhongMaterial object FXMaterials { val RED = PhongMaterial().apply { diffuseColor = Color.DARKRED - specularColor = Color.RED + specularColor = Color.WHITE } val WHITE = PhongMaterial().apply { @@ -22,7 +22,7 @@ object FXMaterials { val GREY = PhongMaterial().apply { diffuseColor = Color.DARKGREY - specularColor = Color.GREY + specularColor = Color.WHITE } val BLUE = PhongMaterial(Color.BLUE) @@ -34,14 +34,14 @@ object FXMaterials { */ fun MetaItem<*>.color(opacity: Double = 1.0): Color { return when (this) { - is MetaItem.ValueItem -> if (this.value.type == ValueType.STRING) { - Color.web(this.value.string) - } else { + is MetaItem.ValueItem -> if (this.value.type == ValueType.NUMBER) { val int = value.number.toInt() val red = int and 0x00ff0000 shr 16 val green = int and 0x0000ff00 shr 8 val blue = int and 0x000000ff Color.rgb(red, green, blue) + } else { + Color.web(this.value.string) } is MetaItem.NodeItem -> { Color.rgb( @@ -63,9 +63,8 @@ fun MetaItem<*>?.material(): Material { is MetaItem.ValueItem -> PhongMaterial(color()) is MetaItem.NodeItem -> PhongMaterial().apply { val opacity = node["opacity"].double ?: 1.0 - (node["color"] ?: this@material).let { diffuseColor = it.color(opacity) } - node["specularColor"]?.let { specularColor = it.color(opacity) } - + diffuseColor = node["color"]?.color(opacity) ?: Color.DARKGREY + specularColor = node["specularColor"]?.color(opacity) ?: Color.WHITE } } } diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXProxyFactory.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXProxyFactory.kt index d42362b2..7a7c11da 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXProxyFactory.kt +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXProxyFactory.kt @@ -1,15 +1,50 @@ package hep.dataforge.vis.spatial.fx +import hep.dataforge.names.Name +import hep.dataforge.names.isEmpty +import hep.dataforge.names.startsWith +import hep.dataforge.names.toName +import hep.dataforge.vis.common.VisualObject +import hep.dataforge.vis.spatial.Material3D import hep.dataforge.vis.spatial.Proxy +import javafx.scene.Group import javafx.scene.Node +import javafx.scene.shape.Shape3D import kotlin.reflect.KClass -class FXProxyFactory(val plugin: FX3DPlugin) : - FX3DFactory { +class FXProxyFactory(val plugin: FX3DPlugin) : FX3DFactory { override val type: KClass get() = Proxy::class - override fun invoke(obj: Proxy, binding: DisplayObjectFXBinding): Node { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } + override fun invoke(obj: Proxy, binding: VisualObjectFXBinding): Node { + val template = obj.prototype + val node = plugin.buildNode(template) + obj.onPropertyChange(this) { name, _, _ -> + if (name.first()?.body == Proxy.PROXY_CHILD_PROPERTY_PREFIX) { + val childName = name.first()?.index?.toName() ?: error("Wrong syntax for proxy child property: '$name'") + val propertyName = name.cutFirst() + val proxyChild = obj[childName] ?: error("Proxy child with name '$childName' not found") + val child = node.findChild(childName) ?: error("Object child with name '$childName' not found") + child.updateProperty(proxyChild, propertyName) + } + } + return node + } +} + +private fun Node.findChild(name: Name): Node? { + return if (name.isEmpty()) { + this + } else { + (this as? Group) + ?.children + ?.find { it.properties["name"] as String == name.first()?.toString() } + ?.findChild(name.cutFirst()) + } +} + +private fun Node.updateProperty(obj: VisualObject, propertyName: Name) { + if (propertyName.startsWith(Material3D.MATERIAL_KEY)) { + (this as? Shape3D)?.let { it.material = obj.getProperty(Material3D.MATERIAL_KEY).material() } + } } \ No newline at end of file diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXShapeFactory.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXShapeFactory.kt index 93868b54..cd851fe6 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXShapeFactory.kt +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXShapeFactory.kt @@ -13,7 +13,7 @@ import kotlin.reflect.KClass object FXShapeFactory : FX3DFactory { override val type: KClass get() = Shape::class - override fun invoke(obj: Shape, binding: DisplayObjectFXBinding): MeshView { + override fun invoke(obj: Shape, binding: VisualObjectFXBinding): MeshView { val mesh = FXGeometryBuilder().apply { obj.toGeometry(this) }.build() return MeshView(mesh) } diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/VisualObjectFXBinding.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/VisualObjectFXBinding.kt new file mode 100644 index 00000000..bc772892 --- /dev/null +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/VisualObjectFXBinding.kt @@ -0,0 +1,54 @@ +package hep.dataforge.vis.spatial.fx + +import hep.dataforge.meta.* +import hep.dataforge.names.Name +import hep.dataforge.names.isEmpty +import hep.dataforge.names.toName +import hep.dataforge.vis.common.VisualObject +import javafx.beans.binding.ObjectBinding +import tornadofx.* + +/** + * A caching binding collection for [VisualObject] properties + */ +class VisualObjectFXBinding(val obj: VisualObject) { + private val bindings = HashMap?>>() + + init { + obj.onPropertyChange(this) { name, _, _ -> + var currentName = name + while(!currentName.isEmpty()) { + //recursively update all upper level bindings + bindings[currentName]?.invalidate() + currentName = currentName.cutLast() + } + } + } + + operator fun get(key: Name): ObjectBinding?> { + return bindings.getOrPut(key) { + object : ObjectBinding?>() { + override fun computeValue(): MetaItem<*>? = obj.getProperty(key) + } + } + } + + operator fun get(key: String) = get(key.toName()) +} + +fun ObjectBinding?>.value() = objectBinding { it.value } +fun ObjectBinding?>.string() = stringBinding { it.string } +fun ObjectBinding?>.number() = objectBinding { it.number } +fun ObjectBinding?>.double() = objectBinding { it.double } +fun ObjectBinding?>.float() = objectBinding { it.float } +fun ObjectBinding?>.int() = objectBinding { it.int } +fun ObjectBinding?>.long() = objectBinding { it.long } +fun ObjectBinding?>.node() = objectBinding { it.node } + +fun ObjectBinding?>.string(default: String) = stringBinding { it.string ?: default } +fun ObjectBinding?>.double(default: Double) = objectBinding { it.double ?: default } +fun ObjectBinding?>.float(default: Float) = objectBinding { it.float ?: default } +fun ObjectBinding?>.int(default: Int) = objectBinding { it.int ?: default } +fun ObjectBinding?>.long(default: Long) = objectBinding { it.long ?:default } + +fun ObjectBinding?>.transform(transform: (MetaItem<*>) -> T) = objectBinding { it?.let(transform) } From 8189012b707077515928c46a6723dd88b1b7216d Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 22 Dec 2019 20:56:19 +0300 Subject: [PATCH 12/25] Large API update --- README.md | 2 + build.gradle.kts | 8 +- dataforge-vis-common/build.gradle.kts | 4 - .../vis/common/AbstractVisualGroup.kt | 47 +--- .../vis/common/AbstractVisualObject.kt | 45 ++-- .../kotlin/hep/dataforge/vis/common/Colors.kt | 44 +++- .../hep/dataforge/vis/common/StyleSheet.kt | 52 +++++ .../{MutableVisualGroup.kt => VisualGroup.kt} | 41 ++-- .../hep/dataforge/vis/common/VisualObject.kt | 58 +++-- dataforge-vis-spatial-gdml/build.gradle.kts | 24 +- .../vis/spatial/gdml/GDMLTransformer.kt | 10 +- .../dataforge/vis/spatial/gdml/visualGDML.kt | 7 + .../vis/spatial/gdml/demo/GDMLDemoApp.kt | 7 +- .../dataforge/vis/spatial/gdml/testCoil.kt | 26 --- .../dataforge/vis/spatial/gdml/testCubes.kt | 40 ---- .../dataforge/vis/spatial/gdml/testJson.kt | 16 -- .../dataforge/vis/spatial/gdml/testMain.kt | 62 ----- .../vis/spatial/gdml/visualGDMLJvm.kt | 13 ++ dataforge-vis-spatial/build.gradle.kts | 12 +- .../hep/dataforge/vis/spatial/Composite.kt | 8 +- .../vis/spatial/{Text3D.kt => Label3D.kt} | 13 +- .../hep/dataforge/vis/spatial/Material3D.kt | 75 ++++--- .../kotlin/hep/dataforge/vis/spatial/Proxy.kt | 43 ++-- .../dataforge/vis/spatial/VisualGroup3D.kt | 34 ++- .../dataforge/vis/spatial/VisualObject3D.kt | 18 +- .../hep/dataforge/vis/spatial/geometry.kt | 10 +- .../spatial/transform/RemoveSingleChild.kt | 4 +- .../hep/dataforge/vis/spatial/PropertyTest.kt | 55 +++++ .../vis/spatial/editor/propertyEditor.kt | 21 +- .../vis/spatial/three/MeshThreeFactory.kt | 2 +- .../vis/spatial/three/ThreeMaterials.kt | 22 +- .../vis/spatial/three/ThreePlugin.kt | 1 + .../vis/spatial/three/ThreeTextFactory.kt | 47 ++++ .../dataforge/vis/spatial/demo/FXDemoApp.kt | 211 ------------------ .../dataforge/vis/spatial/fx/FX3DPlugin.kt | 34 ++- .../dataforge/vis/spatial/fx/FXCanvas3D.kt | 39 ++-- .../vis/spatial/fx/FXCompositeFactory.kt | 48 +++- .../dataforge/vis/spatial/fx/FXMaterials.kt | 18 +- .../vis/spatial/fx/FXShapeFactory.kt | 8 +- .../vis/spatial/fx/VisualObjectFXBinding.kt | 26 ++- settings.gradle.kts | 3 +- spatial-demo/build.gradle.kts | 39 ++++ .../hep/dataforge/vis/spatial/demo/demo.kt | 158 +++++++++++++ .../vis/spatial/demo/ThreeDemoApp.kt | 59 +++++ .../vis/spatial/demo/ThreeDemoGrid.kt | 40 +--- .../dataforge/vis/spatial/demo/VariableBox.kt | 0 .../src/jsMain}/web/index.html | 0 .../dataforge/vis/spatial/demo/FXDemoApp.kt | 40 ++++ .../dataforge/vis/spatial/demo/FXDemoGrid.kt | 8 - spatial-js-demo/build.gradle.kts | 19 -- .../vis/spatial/demo/ThreeDemoApp.kt | 179 --------------- 51 files changed, 894 insertions(+), 906 deletions(-) create mode 100644 dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/StyleSheet.kt rename dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/{MutableVisualGroup.kt => VisualGroup.kt} (69%) delete mode 100644 dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/testCoil.kt delete mode 100644 dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/testCubes.kt delete mode 100644 dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/testJson.kt delete mode 100644 dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/testMain.kt create mode 100644 dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDMLJvm.kt rename dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/{Text3D.kt => Label3D.kt} (58%) create mode 100644 dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/PropertyTest.kt create mode 100644 dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeTextFactory.kt delete mode 100644 dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt create mode 100644 spatial-demo/build.gradle.kts create mode 100644 spatial-demo/src/commonMain/kotlin/hep/dataforge/vis/spatial/demo/demo.kt create mode 100644 spatial-demo/src/jsMain/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt rename {spatial-js-demo/src/main => spatial-demo/src/jsMain}/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoGrid.kt (55%) rename {spatial-js-demo/src/main => spatial-demo/src/jsMain}/kotlin/hep/dataforge/vis/spatial/demo/VariableBox.kt (100%) rename {spatial-js-demo/src/main => spatial-demo/src/jsMain}/web/index.html (100%) create mode 100644 spatial-demo/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt rename {dataforge-vis-spatial => spatial-demo}/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoGrid.kt (86%) delete mode 100644 spatial-js-demo/build.gradle.kts delete mode 100644 spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt diff --git a/README.md b/README.md index 783d9995..83021789 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +[![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) + # DataForge plugins for visualisation ## Common visualisation objects diff --git a/build.gradle.kts b/build.gradle.kts index 61a73e71..f396caad 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,8 +1,10 @@ +import scientifik.useSerialization + val dataforgeVersion by extra("0.1.5-dev-4") plugins { val kotlinVersion = "1.3.61" - val toolsVersion = "0.2.7" + val toolsVersion = "0.3.1" kotlin("jvm") version kotlinVersion apply false id("kotlin-dce-js") version kotlinVersion apply false @@ -27,6 +29,10 @@ allprojects { version = "0.1.0-dev" } +subprojects{ + useSerialization("0.13.0") +} + val githubProject by extra("dataforge-vis") val bintrayRepo by extra("dataforge") diff --git a/dataforge-vis-common/build.gradle.kts b/dataforge-vis-common/build.gradle.kts index e6fb3815..767364de 100644 --- a/dataforge-vis-common/build.gradle.kts +++ b/dataforge-vis-common/build.gradle.kts @@ -5,10 +5,6 @@ plugins { id("org.openjfx.javafxplugin") } -scientifik{ - withSerialization() -} - val dataforgeVersion: String by rootProject.extra //val kvisionVersion: String by rootProject.extra("2.0.0-M1") diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualGroup.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualGroup.kt index 921617c8..21edc5e8 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualGroup.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualGroup.kt @@ -1,8 +1,10 @@ package hep.dataforge.vis.common -import hep.dataforge.meta.Meta import hep.dataforge.meta.MetaItem -import hep.dataforge.names.* +import hep.dataforge.names.Name +import hep.dataforge.names.NameToken +import hep.dataforge.names.asName +import hep.dataforge.names.isEmpty import kotlinx.serialization.Transient @@ -16,46 +18,7 @@ abstract class AbstractVisualGroup : AbstractVisualObject(), MutableVisualGroup /** * A map of top level named children */ - abstract override val children: Map //get() = _children - - /** - * Styles, defined in this group. A style could be defined but not applied - * TODO replace by custom object with get/set functionality - */ - protected abstract val styleSheet: MutableMap - - override fun getStyle(name: Name): Meta? = styleSheet[name] - - override fun addStyle(name: Name, meta: Meta, apply: Boolean) { - fun VisualObject.applyStyle(name: Name, meta: Meta) { - if (styles.contains(name)) { - //full update - //TODO do a fine grained update - if (this is AbstractVisualObject) { - styleChanged() - } else { - propertyChanged(EmptyName) - } - } - if (this is VisualGroup) { - this.children.forEach { (_, child) -> - child.applyStyle(name, meta) - } - } - } - styleSheet[name] = meta - if (apply) { - applyStyle(name, meta) - } - } - - -// init { -// //Do after deserialization -// children.values.forEach { -// it.parent = this -// } -// } + abstract override val children: Map override fun propertyChanged(name: Name, before: MetaItem<*>?, after: MetaItem<*>?) { super.propertyChanged(name, before, after) diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualObject.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualObject.kt index e0808e75..b59f2564 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualObject.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualObject.kt @@ -1,9 +1,8 @@ package hep.dataforge.vis.common import hep.dataforge.meta.* -import hep.dataforge.names.EmptyName import hep.dataforge.names.Name -import hep.dataforge.names.toName +import hep.dataforge.names.asName import hep.dataforge.vis.common.VisualObject.Companion.STYLE_KEY import kotlinx.serialization.Transient @@ -17,15 +16,25 @@ abstract class AbstractVisualObject : VisualObject { @Transient override var parent: VisualObject? = null - abstract override var properties: Config? + protected abstract var properties: Config? - override var styles: List - get() = properties?.get(STYLE_KEY).stringList.map(String::toName) + override var styles: List + get() = properties?.get(STYLE_KEY).stringList set(value) { - setProperty(STYLE_KEY, value.map { it.toString() }) - styleChanged() + //val allStyles = (field + value).distinct() + setProperty(STYLE_KEY, value) + updateStyles(value) } + protected fun updateStyles(names: List) { + names.mapNotNull { findStyle(it) }.asSequence() + .flatMap { it.items.asSequence() } + .distinctBy { it.key } + .forEach { + propertyChanged(it.key.asName(), null, it.value) + } + } + /** * The config is initialized and assigned on-demand. * To avoid unnecessary allocations, one should access [properties] via [getProperty] instead. @@ -67,14 +76,6 @@ abstract class AbstractVisualObject : VisualObject { } - /** - * Helper to reset style cache - */ - protected fun styleChanged() { - styleCache = null - propertyChanged(EmptyName) - } - override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? { return if (inherit) { properties?.get(name) ?: mergedStyles[name] ?: parent?.getProperty(name, inherit) @@ -84,10 +85,10 @@ abstract class AbstractVisualObject : VisualObject { } } -fun VisualObject.findStyle(styleName: Name): Meta? { - if (this is VisualGroup) { - val style = getStyle(styleName) - if (style != null) return style - } - return parent?.findStyle(styleName) -} \ No newline at end of file +//fun VisualObject.findStyle(styleName: Name): Meta? { +// if (this is VisualGroup) { +// val style = resolveStyle(styleName) +// if (style != null) return style +// } +// return parent?.findStyle(styleName) +//} \ No newline at end of file diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/Colors.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/Colors.kt index 780a6874..7577fa33 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/Colors.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/Colors.kt @@ -1,5 +1,10 @@ package hep.dataforge.vis.common +import hep.dataforge.meta.* +import hep.dataforge.values.ValueType +import hep.dataforge.values.int +import kotlin.math.max + /** * Taken from https://github.com/markaren/three.kt/blob/master/threejs-wrapper/src/main/kotlin/info/laht/threekt/math/ColorConstants.kt */ @@ -175,9 +180,38 @@ object Colors { const val yellow = 0xFFFF00 const val yellowgreen = 0x9ACD32 + const val RED_KEY = "red" + const val GREEN_KEY = "green" + const val BLUE_KEY = "blue" + + fun fromMeta(item: MetaItem<*>): String { + return when (item) { + is MetaItem.NodeItem<*> -> { + val node = item.node + rgbToString( + node[RED_KEY].number?.toByte()?.toUByte() ?: 0u, + node[GREEN_KEY].number?.toByte()?.toUByte() ?: 0u, + node[BLUE_KEY].number?.toByte()?.toUByte() ?: 0u + ) + } + is MetaItem.ValueItem -> { + if (item.value.type == ValueType.NUMBER) { + rgbToString(item.value.int) + } else { + item.value.string + } + } + } + } + + fun rgbToString(rgb: Int): String { + val string = rgb.toString(16).padStart(6, '0') + return "#" + string.substring(max(0, string.length - 6)) + } + fun rgbToString(red: UByte, green: UByte, blue: UByte): String { - fun colorToString(color: UByte): String{ - return color.toString(16).padStart(2,'0') + fun colorToString(color: UByte): String { + return color.toString(16).padStart(2, '0') } return buildString { append("#") @@ -186,4 +220,10 @@ object Colors { append(colorToString(blue)) } } + + fun rgbToMeta(r: UByte, g: UByte, b: UByte): Meta = buildMeta { + RED_KEY put r.toInt() + GREEN_KEY put g.toInt() + BLUE_KEY put b.toInt() + } } \ No newline at end of file diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/StyleSheet.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/StyleSheet.kt new file mode 100644 index 00000000..d6803562 --- /dev/null +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/StyleSheet.kt @@ -0,0 +1,52 @@ +@file:UseSerializers(MetaSerializer::class) + +package hep.dataforge.vis.common + +import hep.dataforge.io.serialization.MetaSerializer +import hep.dataforge.meta.Meta +import hep.dataforge.meta.get +import hep.dataforge.names.Name +import hep.dataforge.names.asName +import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient +import kotlinx.serialization.UseSerializers + +@Serializable +class StyleSheet() { + @Transient + internal var owner: VisualObject? = null + + constructor(owner: VisualObject) : this() { + this.owner = owner + } + + private val styleMap = HashMap() + + val items: Map get() = styleMap + + operator fun get(key: String): Meta? { + return styleMap[key] ?: (owner?.parent as? VisualGroup)?.styleSheet?.get(key) + } + + operator fun set(key: String, style: Meta?) { + val oldStyle = styleMap[key] + if (style == null) { + styleMap.remove(key) + } else { + styleMap[key] = style + } + owner?.styleChanged(key, oldStyle, style) + } +} + +private fun VisualObject.styleChanged(key: String, oldStyle: Meta?, newStyle: Meta?) { + if (styles.contains(key)) { + //TODO optimize set concatenation + val tokens: Collection = ((oldStyle?.items?.keys ?: emptySet()) + (newStyle?.items?.keys ?: emptySet())) + .map { it.asName() } + tokens.forEach { parent?.propertyChanged(it, oldStyle?.get(it), newStyle?.get(it)) } + } + if (this is VisualGroup) { + this.forEach { it.styleChanged(key, oldStyle, newStyle) } + } +} \ No newline at end of file diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/MutableVisualGroup.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualGroup.kt similarity index 69% rename from dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/MutableVisualGroup.kt rename to dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualGroup.kt index 1c99e6f6..5baa6262 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/MutableVisualGroup.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualGroup.kt @@ -1,6 +1,8 @@ package hep.dataforge.vis.common -import hep.dataforge.meta.Meta +import hep.dataforge.meta.MetaBuilder +import hep.dataforge.meta.buildMeta +import hep.dataforge.meta.seal import hep.dataforge.names.* import hep.dataforge.provider.Provider @@ -12,6 +14,8 @@ interface VisualGroup : Provider, Iterable, VisualObject { override val defaultTarget: String get() = VisualObject.TYPE + val styleSheet: StyleSheet + override fun provideTop(target: String): Map = when (target) { VisualObject.TYPE -> children.flatMap { (key, value) -> @@ -22,7 +26,7 @@ interface VisualGroup : Provider, Iterable, VisualObject { } res.entries }.associate { it.toPair() } - //TODO add styles + STYLE_TARGET -> styleSheet.items.mapKeys { it.key.toName() } else -> emptyMap() } @@ -32,17 +36,6 @@ interface VisualGroup : Provider, Iterable, VisualObject { */ override fun iterator(): Iterator = children.values.iterator() - /** - * Resolve style by its name - * TODO change to Config? - */ - fun getStyle(name: Name): Meta? - - /** - * Add or replace style with given name - */ - fun addStyle(name: Name, meta: Meta, apply: Boolean = true) - operator fun get(name: Name): VisualObject? { return when { name.isEmpty() -> this @@ -50,8 +43,30 @@ interface VisualGroup : Provider, Iterable, VisualObject { else -> (children[name.first()!!] as? VisualGroup)?.get(name.cutFirst()) } } + + /** + * A fix for serialization bug that writes all proper parents inside the tree after deserialization + */ + fun attachChildren(){ + styleSheet.owner = this + this.children.values.forEach { + it.parent = this + (it as? VisualGroup)?.attachChildren() + } + } + + companion object { + const val STYLE_TARGET = "style" + } } +fun VisualGroup.updateStyle(key: String, builder: MetaBuilder.() -> Unit) { + val newStyle = styleSheet[key]?.let { buildMeta(it, builder) } ?: buildMeta(builder) + styleSheet[key] = newStyle.seal() +} + +data class StyleRef(val group: VisualGroup, val styleName: Name) + val VisualGroup.isEmpty: Boolean get() = this.children.isEmpty() interface MutableVisualGroup : VisualGroup { diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualObject.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualObject.kt index 23d46683..008ecd9d 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualObject.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualObject.kt @@ -1,9 +1,6 @@ package hep.dataforge.vis.common -import hep.dataforge.meta.Config -import hep.dataforge.meta.Configurable -import hep.dataforge.meta.Laminate -import hep.dataforge.meta.MetaItem +import hep.dataforge.meta.* import hep.dataforge.names.Name import hep.dataforge.names.asName import hep.dataforge.names.toName @@ -26,11 +23,6 @@ interface VisualObject : Configurable { @Transient var parent: VisualObject? - /** - * Direct properties access - */ - val properties: Config? - /** * Set property for this object */ @@ -42,9 +34,11 @@ interface VisualObject : Configurable { fun getProperty(name: Name, inherit: Boolean = true): MetaItem<*>? /** - * Manually trigger property changed event. If [name] is empty, notify that the whole object is changed + * Trigger property invalidation event. If [name] is empty, notify that the whole object is changed */ - fun propertyChanged(name: Name, before: MetaItem<*>? = null, after: MetaItem<*>? = null): Unit + fun propertyChanged(name: Name, before: MetaItem<*>?, after: MetaItem<*>?): Unit + + fun propertyInvalidated(name: Name) = propertyChanged(name, null, null) /** * Add listener triggering on property change @@ -57,11 +51,9 @@ interface VisualObject : Configurable { fun removeChangeListener(owner: Any?) /** - * List of names of styles applied to this object. Order matters. + * List of names of styles applied to this object. Order matters. Not inherited */ - var styles: List - - fun findAllStyles(): Laminate = Laminate(styles.distinct().mapNotNull(::findStyle)) + var styles: List companion object { const val TYPE = "visual" @@ -69,12 +61,42 @@ interface VisualObject : Configurable { //const val META_KEY = "@meta" //const val TAGS_KEY = "@tags" + + } } fun VisualObject.getProperty(key: String, inherit: Boolean = true): MetaItem<*>? = getProperty(key.toName(), inherit) fun VisualObject.setProperty(key: String, value: Any?) = setProperty(key.toName(), value) -fun VisualObject.applyStyle(name: String) { - styles = styles + name.toName() -} \ No newline at end of file +/** + * Add style name to the list of styles to be resolved later. The style with given name does not necessary exist at the moment. + */ +fun VisualObject.useStyle(name: String) { + styles = styles + name +} + +//private tailrec fun VisualObject.topGroup(): VisualGroup? { +// val parent = this.parent +// return if (parent == null) { +// this as? VisualGroup +// } +// else { +// parent.topGroup() +// } +//} +// +///** +// * Add or update given style on a top-most reachable parent group and apply it to this object +// */ +//fun VisualObject.useStyle(name: String, builder: MetaBuilder.() -> Unit) { +// val styleName = name.toName() +// topGroup()?.updateStyle(styleName, builder) ?: error("Can't find parent group for $this") +// useStyle(styleName) +//} + +tailrec fun VisualObject.findStyle(name: String): Meta? = + (this as? VisualGroup)?.styleSheet?.get(name) ?: parent?.findStyle(name) + +fun VisualObject.findAllStyles(): Laminate = Laminate(styles.mapNotNull(::findStyle)) + diff --git a/dataforge-vis-spatial-gdml/build.gradle.kts b/dataforge-vis-spatial-gdml/build.gradle.kts index 31c0f223..2d8a4200 100644 --- a/dataforge-vis-spatial-gdml/build.gradle.kts +++ b/dataforge-vis-spatial-gdml/build.gradle.kts @@ -1,32 +1,20 @@ -import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpack - plugins { id("scientifik.mpp") } -scientifik{ - withSerialization() -} - kotlin { sourceSets { val commonMain by getting { dependencies { api(project(":dataforge-vis-spatial")) - api("scientifik:gdml:0.1.3") - } - } - val jsMain by getting { - dependencies { - api(project(":dataforge-vis-spatial")) - //api("kotlin.js.externals:kotlin-js-jquery:3.2.0-0") + api("scientifik:gdml:0.1.4") } } } } -tasks{ - val jsBrowserWebpack by getting(KotlinWebpack::class) { - sourceMaps = false - } -} \ No newline at end of file +//tasks{ +// val jsBrowserWebpack by getting(KotlinWebpack::class) { +// sourceMaps = false +// } +//} \ No newline at end of file diff --git a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt index 698c5ada..3b529780 100644 --- a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt +++ b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt @@ -6,8 +6,8 @@ import hep.dataforge.meta.buildMeta import hep.dataforge.names.Name import hep.dataforge.names.toName import hep.dataforge.vis.common.VisualObject -import hep.dataforge.vis.common.applyStyle -import hep.dataforge.vis.spatial.Material3D.Companion.COLOR_KEY +import hep.dataforge.vis.common.useStyle +import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_COLOR_KEY import hep.dataforge.vis.spatial.RotationOrder import hep.dataforge.vis.spatial.VisualGroup3D import hep.dataforge.vis.spatial.VisualObject3D @@ -43,7 +43,7 @@ class GDMLTransformer(val root: GDML) { styleCache.getOrPut(name.toName()){ buildMeta(builder) } - applyStyle(name) + useStyle(name) } internal fun configureSolid(obj: VisualObject3D, parent: GDMLVolume, solid: GDMLSolid) { @@ -52,7 +52,7 @@ class GDMLTransformer(val root: GDML) { val styleName = "material[${material.name}]" obj.useStyle(styleName){ - COLOR_KEY to random.nextInt(0, Int.MAX_VALUE) + MATERIAL_COLOR_KEY put random.nextInt(16777216) "gdml.material" put material.name } @@ -68,7 +68,7 @@ class GDMLTransformer(val root: GDML) { internal fun finalize(final: VisualGroup3D): VisualGroup3D { final.prototypes = proto styleCache.forEach { - final.addStyle(it.key, it.value, false) + final.styleSheet[it.key.toString()] = it.value } final.rotationOrder = RotationOrder.ZXY onFinish(this@GDMLTransformer) diff --git a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDML.kt b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDML.kt index 97b6b474..42c3d1c6 100644 --- a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDML.kt +++ b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDML.kt @@ -244,4 +244,11 @@ fun GDML.toVisual(block: GDMLTransformer.() -> Unit = {}): VisualGroup3D { val context = GDMLTransformer(this).apply(block) return context.finalize(volume(context, world)) +} + +/** + * Append gdml node to the group + */ +fun VisualGroup3D.gdml(gdml: GDML, key: String = "", transformer: GDMLTransformer.() -> Unit = {}) { + set(key, gdml.toVisual(transformer)) } \ No newline at end of file diff --git a/dataforge-vis-spatial-gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt b/dataforge-vis-spatial-gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt index 67d4d184..1c270083 100644 --- a/dataforge-vis-spatial-gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt +++ b/dataforge-vis-spatial-gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt @@ -5,11 +5,10 @@ import hep.dataforge.js.Application import hep.dataforge.js.objectTree import hep.dataforge.js.startApplication import hep.dataforge.names.NameToken -import hep.dataforge.vis.spatial.Material3D.Companion.OPACITY_KEY +import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_OPACITY_KEY import hep.dataforge.vis.spatial.Visual3DPlugin import hep.dataforge.vis.spatial.VisualGroup3D import hep.dataforge.vis.spatial.VisualObject3D -import hep.dataforge.vis.spatial.attachChildren import hep.dataforge.vis.spatial.editor.propertyEditor import hep.dataforge.vis.spatial.editor.threeOutputConfig import hep.dataforge.vis.spatial.gdml.GDMLTransformer @@ -106,7 +105,7 @@ private class GDMLDemoApp : Application { || parent.physVolumes.isNotEmpty() ) { useStyle("opaque") { - OPACITY_KEY to 0.3 + MATERIAL_OPACITY_KEY put 0.3 } } } @@ -154,7 +153,7 @@ private class GDMLDemoApp : Application { output.camera.layers.set(0) configElement.threeOutputConfig(output) //tree.visualObjectTree(visual, editor::propertyEditor) - treeElement.objectTree(NameToken("World"),visual, editorElement::propertyEditor) + treeElement.objectTree(NameToken("World"), visual, editorElement::propertyEditor) output.render(visual) diff --git a/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/testCoil.kt b/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/testCoil.kt deleted file mode 100644 index 567f0e7c..00000000 --- a/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/testCoil.kt +++ /dev/null @@ -1,26 +0,0 @@ -package hep.dataforge.vis.spatial.gdml - -import hep.dataforge.vis.spatial.Visual3DPlugin -import hep.dataforge.vis.spatial.VisualGroup3D -import nl.adaptivity.xmlutil.StAXReader -import scientifik.gdml.GDML -import java.io.File - - -fun main() { - val file = File("D:\\Work\\Projects\\gdml.kt\\gdml-source\\BM@N_coil.gdml") - - val xmlReader = StAXReader(file.inputStream(), "UTF-8") - val xml = GDML.format.parse(GDML.serializer(), xmlReader) - val visual = xml.toVisual { - lUnit = LUnit.CM - } - - //val meta = visual.toMeta() - - val str = Visual3DPlugin.json.stringify(VisualGroup3D.serializer(), visual) - - println(str) - - //println(Json.indented.stringify(meta.toJson())) -} \ No newline at end of file diff --git a/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/testCubes.kt b/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/testCubes.kt deleted file mode 100644 index b0ff5b38..00000000 --- a/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/testCubes.kt +++ /dev/null @@ -1,40 +0,0 @@ -package hep.dataforge.vis.spatial.gdml - -import hep.dataforge.vis.spatial.Material3D -import hep.dataforge.vis.spatial.Visual3DPlugin -import hep.dataforge.vis.spatial.VisualGroup3D -import hep.dataforge.vis.spatial.VisualObject3D -import hep.dataforge.vis.spatial.transform.RemoveSingleChild -import hep.dataforge.vis.spatial.transform.UnRef -import nl.adaptivity.xmlutil.StAXReader -import scientifik.gdml.GDML -import java.io.File - -fun main() { - val file = File("D:\\Work\\Projects\\gdml.kt\\gdml-source\\cubes.gdml") - - val xmlReader = StAXReader(file.inputStream(), "UTF-8") - val xml = GDML.format.parse(GDML.serializer(), xmlReader) - val visual = xml.toVisual { - lUnit = LUnit.CM - - solidConfiguration = { parent, solid -> - if (parent.physVolumes.isNotEmpty()) { - useStyle("opaque") { - Material3D.OPACITY_KEY to 0.3 - VisualObject3D.LAYER_KEY to 2 - } - } - } - } - - (visual as? VisualGroup3D)?.let { UnRef(it) }?.let { RemoveSingleChild(it) } - - val string = Visual3DPlugin.json.stringify(VisualGroup3D.serializer(), visual) - - val tmpFile = File.createTempFile("dataforge-visual", ".json") - - tmpFile.writeText(string) - - println(tmpFile.canonicalPath) -} \ No newline at end of file diff --git a/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/testJson.kt b/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/testJson.kt deleted file mode 100644 index ad722578..00000000 --- a/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/testJson.kt +++ /dev/null @@ -1,16 +0,0 @@ -package hep.dataforge.vis.spatial.gdml - -import hep.dataforge.names.toName -import hep.dataforge.vis.spatial.* - -fun main() { - val vis = VisualGroup3D().apply { - val box = Box(100f, 100f, 20f).apply { - color(0u, 0u, 255u) - } - proxy("some.name".toName(), box, "obj") - } - - val string = Visual3DPlugin.json.stringify(VisualGroup3D.serializer(),vis) - println(string) -} \ No newline at end of file diff --git a/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/testMain.kt b/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/testMain.kt deleted file mode 100644 index 7ef8a918..00000000 --- a/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/testMain.kt +++ /dev/null @@ -1,62 +0,0 @@ -package hep.dataforge.vis.spatial.gdml - -import hep.dataforge.vis.spatial.Material3D -import hep.dataforge.vis.spatial.Visual3DPlugin -import hep.dataforge.vis.spatial.VisualGroup3D -import hep.dataforge.vis.spatial.opacity -import hep.dataforge.vis.spatial.transform.RemoveSingleChild -import hep.dataforge.vis.spatial.transform.UnRef -import nl.adaptivity.xmlutil.StAXReader -import scientifik.gdml.GDML -import java.io.File - -fun main() { - val file = File("D:\\Work\\Projects\\gdml.kt\\gdml-source\\BM@N.gdml") - - val xmlReader = StAXReader(file.inputStream(), "UTF-8") - val xml = GDML.format.parse(GDML.serializer(), xmlReader) - val visual = xml.toVisual { - lUnit = LUnit.CM - - volumeAction = { volume -> - when { - volume.name.startsWith("ecal01lay") -> GDMLTransformer.Action.REJECT - else -> GDMLTransformer.Action.CACHE - } - } - - solidConfiguration = { parent, solid -> - if (parent.physVolumes.isNotEmpty() - || solid.name.startsWith("Coil") - || solid.name.startsWith("Yoke") - || solid.name.startsWith("Magnet") - || solid.name.startsWith("Pole") - ) { - useStyle("opaque") { - Material3D.OPACITY_KEY to 0.3 - } - } - } - } - - // (visual as? VisualGroup3D)?.let { UnRef(it) }?.let { RemoveSingleChild(it) } - - val string = Visual3DPlugin.json.stringify(VisualGroup3D.serializer(), visual) - - val tmpFile = File.createTempFile("dataforge-visual", ".json") - - tmpFile.writeText(string) - - println(tmpFile.canonicalPath) - -// val template = visual.getTemplate("volumes.ecal01mod".toName()) -// println(template) -// visual.flatMap { (it as? VisualGroup3D) ?: listOf(it) }.forEach { -// if(it.parent==null) error("") -// } - //readLine() - //val meta = visual.toMeta() -// val tmpFile = File.createTempFile("dataforge-visual", "json") - //tmpFile.writeText(meta.toString()) - //println(tmpFile.absoluteFile) -} \ No newline at end of file diff --git a/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDMLJvm.kt b/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDMLJvm.kt new file mode 100644 index 00000000..e6095e47 --- /dev/null +++ b/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDMLJvm.kt @@ -0,0 +1,13 @@ +package hep.dataforge.vis.spatial.gdml + +import hep.dataforge.vis.spatial.VisualGroup3D +import nl.adaptivity.xmlutil.StAXReader +import scientifik.gdml.GDML +import java.nio.file.Files +import java.nio.file.Path + +fun VisualGroup3D.gdml(file: Path, key: String = "", transformer: GDMLTransformer.() -> Unit = {}) { + val xmlReader = StAXReader(Files.newInputStream(file), "UTF-8") + val gdml = GDML.format.parse(GDML.serializer(), xmlReader) + gdml(gdml, key, transformer) +} \ No newline at end of file diff --git a/dataforge-vis-spatial/build.gradle.kts b/dataforge-vis-spatial/build.gradle.kts index 203cd2b7..92033405 100644 --- a/dataforge-vis-spatial/build.gradle.kts +++ b/dataforge-vis-spatial/build.gradle.kts @@ -5,10 +5,6 @@ plugins { id("org.openjfx.javafxplugin") } -scientifik { - withSerialization() -} - kotlin { jvm { withJava() @@ -21,9 +17,13 @@ kotlin { } jvmMain { dependencies { - api("org.fxyz3d:fxyz3d:0.5.2") + implementation("org.fxyz3d:fxyz3d:0.5.2") { + exclude(module = "slf4j-simple") + } api("org.jetbrains.kotlinx:kotlinx-coroutines-javafx:${Scientifik.coroutinesVersion}") - implementation("eu.mihosoft.vrl.jcsg:jcsg:0.5.7") + implementation("eu.mihosoft.vrl.jcsg:jcsg:0.5.7") { + exclude(module = "slf4j-simple") + } } } jsMain { diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt index e0ac521b..2ea3fc31 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt @@ -1,4 +1,5 @@ @file:UseSerializers(Point3DSerializer::class) + package hep.dataforge.vis.spatial import hep.dataforge.io.serialization.ConfigSerializer @@ -43,10 +44,9 @@ inline fun VisualGroup3D.composite( val children = group.filterIsInstance() if (children.size != 2) error("Composite requires exactly two children") return Composite(type, children[0], children[1]).also { - if (group.properties != null) { - it.config.update(group.config) - it.material = group.material - } + it.config.update(group.config) + //it.material = group.material + it.position = group.position it.rotation = group.rotation it.scale = group.scale diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Text3D.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Label3D.kt similarity index 58% rename from dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Text3D.kt rename to dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Label3D.kt index 2fbecf1d..01ff005e 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Text3D.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Label3D.kt @@ -9,7 +9,8 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.UseSerializers @Serializable -class Text3D(var text: String, var fontSize: Int) : AbstractVisualObject(), VisualObject3D { +class Label3D(var text: String, var fontSize: Double, var fontFamily: String) : AbstractVisualObject(), + VisualObject3D { @Serializable(ConfigSerializer::class) override var properties: Config? = null @@ -19,5 +20,11 @@ class Text3D(var text: String, var fontSize: Int) : AbstractVisualObject(), Visu } -fun VisualGroup3D.text(text: String, fontSize: Int, name: String = "", action: Text3D.() -> Unit = {}) = - Text3D(text, fontSize).apply(action).also { set(name, it) } \ No newline at end of file +fun VisualGroup3D.label( + text: String, + fontSize: Number = 20, + fontFamily: String = "Arial", + name: String = "", + action: Label3D.() -> Unit = {} +) = + Label3D(text, fontSize.toDouble(), fontFamily).apply(action).also { set(name, it) } \ No newline at end of file diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Material3D.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Material3D.kt index 68913c55..40520f0f 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Material3D.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Material3D.kt @@ -3,63 +3,72 @@ package hep.dataforge.vis.spatial import hep.dataforge.meta.* import hep.dataforge.names.asName import hep.dataforge.names.plus -import hep.dataforge.vis.common.VisualObject -import hep.dataforge.vis.spatial.Material3D.Companion.COLOR_KEY -import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_KEY -import hep.dataforge.vis.spatial.Material3D.Companion.OPACITY_KEY +import hep.dataforge.vis.common.Colors +import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_COLOR_KEY +import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_OPACITY_KEY class Material3D(override val config: Config) : Specific { - var color by string() + var color by string(key = COLOR_KEY) - var opacity by float(1f) + var specularColor by string() + + var opacity by float(1f, key = OPACITY_KEY) + + var wireframe by boolean(false, WIREFRAME_KEY) companion object : Specification { override fun wrap(config: Config): Material3D = Material3D(config) val MATERIAL_KEY = "material".asName() - val COLOR_KEY = MATERIAL_KEY + "color" - val SPECULAR_COLOR = MATERIAL_KEY + "specularColor" - val OPACITY_KEY = MATERIAL_KEY + "opacity" + internal val COLOR_KEY = "color".asName() + val MATERIAL_COLOR_KEY = MATERIAL_KEY + COLOR_KEY + val SPECULAR_COLOR ="specularColor".asName() + internal val OPACITY_KEY = "opacity".asName() + val MATERIAL_OPACITY_KEY = MATERIAL_KEY + OPACITY_KEY + internal val WIREFRAME_KEY = "wireframe".asName() + val MATERIAL_WIREFRAME_KEY = MATERIAL_KEY + WIREFRAME_KEY } } -fun VisualObject.color(rgb: String) { - setProperty(COLOR_KEY, rgb) +fun VisualObject3D.color(rgb: String) { + setProperty(MATERIAL_COLOR_KEY, rgb) } -fun VisualObject.color(rgb: Int) { - setProperty(COLOR_KEY, rgb) +fun VisualObject3D.color(rgb: Int) { + setProperty(MATERIAL_COLOR_KEY, rgb) } -fun VisualObject.color(r: UByte, g: UByte, b: UByte) = setProperty( - COLOR_KEY, - buildMeta { - "red" put r.toInt() - "green" put g.toInt() - "blue" put b.toInt() - } +fun VisualObject3D.color(r: UByte, g: UByte, b: UByte) = setProperty( + MATERIAL_COLOR_KEY, + Colors.rgbToMeta(r, g, b) ) -var VisualObject.color: String? - get() = getProperty(COLOR_KEY).string +/** + * Web colors representation of the color in `#rrggbb` format or HTML name + */ +var VisualObject3D.color: String? + get() = getProperty(MATERIAL_COLOR_KEY)?.let { Colors.fromMeta(it) } set(value) { - if (value != null) { - color(value) - } + setProperty(MATERIAL_COLOR_KEY, value) } -var VisualObject.material: Material3D? - get() = getProperty(MATERIAL_KEY).node?.let { Material3D.wrap(it) } - set(value) = setProperty(MATERIAL_KEY, value?.config) +//var VisualObject3D.material: Material3D? +// get() = getProperty(MATERIAL_KEY).node?.let { Material3D.wrap(it) } +// set(value) = setProperty(MATERIAL_KEY, value?.config) -fun VisualObject.material(builder: Material3D.() -> Unit) { - material = Material3D.build(builder) +fun VisualObject3D.material(builder: Material3D.() -> Unit) { + val node = config[Material3D.MATERIAL_KEY].node + if (node != null) { + Material3D.update(node, builder) + } else { + config[Material3D.MATERIAL_KEY] = Material3D.build(builder) + } } -var VisualObject.opacity: Double? - get() = getProperty(OPACITY_KEY).double +var VisualObject3D.opacity: Double? + get() = getProperty(MATERIAL_OPACITY_KEY).double set(value) { - setProperty(OPACITY_KEY, value) + setProperty(MATERIAL_OPACITY_KEY, value) } \ No newline at end of file diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt index e71186c7..b3b04cd0 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt @@ -5,17 +5,13 @@ package hep.dataforge.vis.spatial import hep.dataforge.io.serialization.ConfigSerializer import hep.dataforge.io.serialization.NameSerializer import hep.dataforge.meta.Config -import hep.dataforge.meta.Meta import hep.dataforge.meta.MetaItem import hep.dataforge.meta.get import hep.dataforge.names.Name import hep.dataforge.names.NameToken import hep.dataforge.names.asName import hep.dataforge.names.plus -import hep.dataforge.vis.common.AbstractVisualObject -import hep.dataforge.vis.common.MutableVisualGroup -import hep.dataforge.vis.common.VisualGroup -import hep.dataforge.vis.common.VisualObject +import hep.dataforge.vis.common.* import kotlinx.serialization.Serializable import kotlinx.serialization.Transient import kotlinx.serialization.UseSerializers @@ -43,12 +39,8 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua get() = (parent as? VisualGroup3D)?.getPrototype(templateName) ?: error("Template with name $templateName not found in $parent") - override fun getStyle(name: Name): Meta? = (parent as VisualGroup?)?.getStyle(name) - - override fun addStyle(name: Name, meta: Meta, apply: Boolean) { - (parent as VisualGroup?)?.addStyle(name, meta, apply) - //do nothing - } + override val styleSheet: StyleSheet + get() = (parent as? VisualGroup)?.styleSheet ?: StyleSheet(this) override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? { return if (inherit) { @@ -77,16 +69,17 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua return NameToken(PROXY_CHILD_PROPERTY_PREFIX, childName.toString()) + propertyName } - private fun prototypeFor(name: Name): VisualObject = - (prototype as? VisualGroup)?.get(name) - ?: error("Prototype with name $name not found in ${this@Proxy}") + private fun prototypeFor(name: Name): VisualObject { + return (prototype as? VisualGroup)?.get(name) + ?: error("Prototype with name $name not found in $this") + } - override var styles: List + override var styles: List get() = super.styles + prototype.styles set(value) { - setProperty(VisualObject.STYLE_KEY, value.map { it.toString() }) - styleChanged() + setProperty(VisualObject.STYLE_KEY, value) + updateStyles(value) } //override fun findAllStyles(): Laminate = Laminate((styles + prototype.styles).mapNotNull { findStyle(it) }) @@ -94,9 +87,9 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua @Serializable inner class ProxyChild(val name: Name) : AbstractVisualObject(), VisualGroup { - val prototype: VisualObject by lazy { - prototypeFor(name) - } + val prototype: VisualObject get() = prototypeFor(name) + + override val styleSheet: StyleSheet get() = this@Proxy.styleSheet override val children: Map get() = (prototype as? VisualGroup)?.children?.mapValues { (key, _) -> @@ -105,12 +98,6 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua ) } ?: emptyMap() - override fun getStyle(name: Name): Meta? = this@Proxy.getStyle(name) - - override fun addStyle(name: Name, meta: Meta, apply: Boolean) { - this@Proxy.addStyle(name, meta, apply) - } - override var properties: Config? get() = propertyCache[name] set(value) { @@ -176,8 +163,8 @@ fun VisualGroup3D.proxy( ): Proxy { val existing = getPrototype(templateName) if (existing == null) { - setPrototype(templateName,obj, attachToParent) - } else if(existing != obj) { + setPrototype(templateName, obj, attachToParent) + } else if (existing != obj) { error("Can't add different prototype on top of existing one") } return ref(templateName, name, block) diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt index 9c959e73..bb76d972 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt @@ -12,12 +12,12 @@ import hep.dataforge.io.serialization.ConfigSerializer import hep.dataforge.io.serialization.MetaSerializer import hep.dataforge.io.serialization.NameSerializer import hep.dataforge.meta.Config -import hep.dataforge.meta.Meta import hep.dataforge.names.Name import hep.dataforge.names.NameToken import hep.dataforge.names.asName import hep.dataforge.names.isEmpty import hep.dataforge.vis.common.AbstractVisualGroup +import hep.dataforge.vis.common.StyleSheet import hep.dataforge.vis.common.VisualGroup import hep.dataforge.vis.common.VisualObject import kotlinx.serialization.SerialName @@ -37,9 +37,10 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D { field = value } + override val styleSheet: StyleSheet = StyleSheet(this) + //FIXME to be lifted to AbstractVisualGroup after https://github.com/Kotlin/kotlinx.serialization/issues/378 is fixed override var properties: Config? = null - override val styleSheet = HashMap() override var position: Point3D? = null override var rotation: Point3D? = null @@ -49,6 +50,11 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D { private val _children = HashMap() override val children: Map get() = _children + init { + //Do after deserialization + attachChildren() + } + override fun removeChild(token: NameToken) { _children.remove(token) childrenChanged(token.asName(), null) @@ -96,26 +102,18 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D { } } + override fun attachChildren() { + super.attachChildren() + prototypes?.run { + parent = this + attachChildren() + } + } + companion object { const val PROTOTYPES_KEY = "templates" } } -/** - * A fix for serialization bug that writes all proper parents inside the tree after deserialization - */ -fun VisualGroup.attachChildren() { - this.children.values.forEach { - it.parent = this - (it as? VisualGroup)?.attachChildren() - } - if (this is VisualGroup3D) { - prototypes?.also { - it.parent = this - it.attachChildren() - } - } -} - fun VisualGroup3D.group(key: String = "", action: VisualGroup3D.() -> Unit = {}): VisualGroup3D = VisualGroup3D().apply(action).also { set(key, it) } \ No newline at end of file diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt index 7d2a2cac..4a07c260 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt @@ -129,21 +129,21 @@ var VisualObject3D.x: Number get() = position?.x ?: 0f set(value) { position().x = value.toDouble() - propertyChanged(VisualObject3D.xPos) + propertyInvalidated(VisualObject3D.xPos) } var VisualObject3D.y: Number get() = position?.y ?: 0f set(value) { position().y = value.toDouble() - propertyChanged(VisualObject3D.yPos) + propertyInvalidated(VisualObject3D.yPos) } var VisualObject3D.z: Number get() = position?.z ?: 0f set(value) { position().z = value.toDouble() - propertyChanged(VisualObject3D.zPos) + propertyInvalidated(VisualObject3D.zPos) } private fun VisualObject3D.rotation(): Point3D = @@ -153,21 +153,21 @@ var VisualObject3D.rotationX: Number get() = rotation?.x ?: 0f set(value) { rotation().x = value.toDouble() - propertyChanged(VisualObject3D.xRotation) + propertyInvalidated(VisualObject3D.xRotation) } var VisualObject3D.rotationY: Number get() = rotation?.y ?: 0f set(value) { rotation().y = value.toDouble() - propertyChanged(VisualObject3D.yRotation) + propertyInvalidated(VisualObject3D.yRotation) } var VisualObject3D.rotationZ: Number get() = rotation?.z ?: 0f set(value) { rotation().z = value.toDouble() - propertyChanged(VisualObject3D.zRotation) + propertyInvalidated(VisualObject3D.zRotation) } private fun VisualObject3D.scale(): Point3D = @@ -177,19 +177,19 @@ var VisualObject3D.scaleX: Number get() = scale?.x ?: 1f set(value) { scale().x = value.toDouble() - propertyChanged(VisualObject3D.xScale) + propertyInvalidated(VisualObject3D.xScale) } var VisualObject3D.scaleY: Number get() = scale?.y ?: 1f set(value) { scale().y = value.toDouble() - propertyChanged(VisualObject3D.yScale) + propertyInvalidated(VisualObject3D.yScale) } var VisualObject3D.scaleZ: Number get() = scale?.z ?: 1f set(value) { scale().z = value.toDouble() - propertyChanged(VisualObject3D.zScale) + propertyInvalidated(VisualObject3D.zScale) } \ No newline at end of file diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/geometry.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/geometry.kt index 4ef1510c..e9fab6ab 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/geometry.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/geometry.kt @@ -14,8 +14,8 @@ operator fun Point2D.component1() = x operator fun Point2D.component2() = y fun Point2D.toMeta() = buildMeta { - VisualObject3D.x to x - VisualObject3D.y to y + VisualObject3D.x put x + VisualObject3D.y put y } fun Meta.point2D() = Point2D(this["x"].number ?: 0, this["y"].number ?: 0) @@ -53,7 +53,7 @@ fun Meta.point3D() = Point3D(this["x"].number ?: 0, this["y"].number ?: 0, this[ val zero = Point3D(0, 0, 0) fun Point3D.toMeta() = buildMeta { - VisualObject3D.x to x - VisualObject3D.y to y - VisualObject3D.z to z + VisualObject3D.x put x + VisualObject3D.y put y + VisualObject3D.z put z } \ No newline at end of file diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/transform/RemoveSingleChild.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/transform/RemoveSingleChild.kt index 1fc1e52b..f8003b2c 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/transform/RemoveSingleChild.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/transform/RemoveSingleChild.kt @@ -10,7 +10,9 @@ import hep.dataforge.vis.spatial.* internal fun mergeChild(parent: VisualGroup, child: VisualObject): VisualObject { return child.apply { - parent.properties?.let { config.update(it) } + config.update(parent.config) + + //parent.properties?.let { config.update(it) } if (this is VisualObject3D && parent is VisualObject3D) { position += parent.position diff --git a/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/PropertyTest.kt b/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/PropertyTest.kt new file mode 100644 index 00000000..dcece5bd --- /dev/null +++ b/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/PropertyTest.kt @@ -0,0 +1,55 @@ +package hep.dataforge.vis.spatial + +import hep.dataforge.meta.int +import hep.dataforge.meta.set +import hep.dataforge.names.asName +import hep.dataforge.vis.common.updateStyle +import hep.dataforge.vis.common.useStyle +import kotlin.test.Test +import kotlin.test.assertEquals + +class PropertyTest { + @Test + fun testInheritedProperty(){ + var box: Box? = null + val group = VisualGroup3D().apply { + config["test"] = 22 + group { + box = box(100,100,100) + } + } + assertEquals(22, box?.getProperty("test".asName()).int) + } + + @Test + fun testStyleProperty(){ + var box: Box? = null + val group = VisualGroup3D().apply { + updateStyle("testStyle"){ + "test" put 22 + } + group { + box = box(100,100,100).apply { + useStyle("testStyle") + } + } + } + assertEquals(22, box?.getProperty("test".asName()).int) + } + + @Test + fun testColor(){ + var box: Box? = null + val group = VisualGroup3D().apply { + updateStyle("testStyle"){ + Material3D.MATERIAL_COLOR_KEY put "#555555" + } + group { + box = box(100,100,100){ + useStyle("testStyle") + } + } + } + assertEquals("#555555", box?.color) + } +} \ No newline at end of file diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/propertyEditor.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/propertyEditor.kt index f123ad4d..0aaaa1d9 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/propertyEditor.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/propertyEditor.kt @@ -5,13 +5,10 @@ import hep.dataforge.js.jsObject import hep.dataforge.meta.* import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.common.findStyle -import hep.dataforge.vis.spatial.Material3D.Companion.COLOR_KEY -import hep.dataforge.vis.spatial.Material3D.Companion.OPACITY_KEY +import hep.dataforge.vis.spatial.* +import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_COLOR_KEY +import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_OPACITY_KEY import hep.dataforge.vis.spatial.VisualObject3D.Companion.VISIBLE_KEY -import hep.dataforge.vis.spatial.color -import hep.dataforge.vis.spatial.opacity -import hep.dataforge.vis.spatial.prototype -import hep.dataforge.vis.spatial.visible import kotlinx.html.dom.append import kotlinx.html.js.div import kotlinx.html.js.h4 @@ -27,11 +24,17 @@ fun Element.propertyEditor(item: VisualObject?) { if (item != null) { append { card("Properties") { - val config = (item.properties ?: item.prototype?.properties) ?: EmptyMeta + val config: Meta = if (item is Proxy || item is Proxy.ProxyChild) { + item.prototype?.config ?: EmptyMeta + } else { + item.config + } val metaToEdit = config.builder().apply { VISIBLE_KEY to (item.visible ?: true) - COLOR_KEY to (item.color ?: "#ffffff") - OPACITY_KEY to (item.opacity ?: 1.0) + if (item is VisualObject3D) { + MATERIAL_COLOR_KEY to (item.color ?: "#ffffff") + MATERIAL_OPACITY_KEY to (item.opacity ?: 1.0) + } } val dMeta: dynamic = metaToEdit.toDynamic() val options: JSONEditorOptions = jsObject { diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/MeshThreeFactory.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/MeshThreeFactory.kt index e1101ab6..7c3ead15 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/MeshThreeFactory.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/MeshThreeFactory.kt @@ -35,7 +35,7 @@ abstract class MeshThreeFactory( //JS sometimes tries to pass Geometry as BufferGeometry @Suppress("USELESS_IS_CHECK") if (geometry !is BufferGeometry) error("BufferGeometry expected") - val meshMeta: Meta = obj.properties[Material3D.MATERIAL_KEY]?.node ?: Meta.empty + //val meshMeta: Meta = obj.properties[Material3D.MATERIAL_KEY]?.node ?: Meta.empty val mesh = Mesh(geometry, MeshBasicMaterial()).apply { matrixAutoUpdate = false diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeMaterials.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeMaterials.kt index 4ac3d4a8..edc760c7 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeMaterials.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeMaterials.kt @@ -11,7 +11,6 @@ import info.laht.threekt.materials.MeshBasicMaterial import info.laht.threekt.materials.MeshPhongMaterial import info.laht.threekt.math.Color import info.laht.threekt.objects.Mesh -import kotlin.math.max object ThreeMaterials { @@ -46,12 +45,6 @@ object ThreeMaterials { linewidth = meta["thickness"].double ?: 1.0 } } - - fun rgbToString(rgb: Int): String { - val string = rgb.toString(16).padStart(6, '0') - return "#" + string.substring(max(0, string.length - 6)) - } - } /** @@ -67,9 +60,9 @@ fun MetaItem<*>.color(): Color { } is MetaItem.NodeItem -> { Color( - node["red"]?.int ?: 0, - node["green"]?.int ?: 0, - node["blue"]?.int ?: 0 + node[Colors.RED_KEY]?.int ?: 0, + node[Colors.GREEN_KEY]?.int ?: 0, + node[Colors.BLUE_KEY]?.int ?: 0 ) } } @@ -99,11 +92,12 @@ fun MetaItem<*>.color(): Color { //fun Material3D?.jsLineMaterial(): Material = this?.config.jsLineMaterial() fun Mesh.updateMaterial(obj: VisualObject) { - val meta = obj.properties[Material3D.MATERIAL_KEY].node?:EmptyMeta + val meta = obj.getProperty(Material3D.MATERIAL_KEY).node?:EmptyMeta material = (material as? MeshBasicMaterial ?: MeshBasicMaterial()).apply { - color = meta["color"]?.color() ?: ThreeMaterials.DEFAULT_COLOR - opacity = meta["opacity"]?.double ?: 1.0 - transparent = meta["transparent"].boolean ?: (opacity < 1.0) + color = meta[Material3D.COLOR_KEY]?.color() ?: ThreeMaterials.DEFAULT_COLOR + opacity = meta[Material3D.OPACITY_KEY]?.double ?: 1.0 + transparent = opacity < 1.0 + wireframe = meta[Material3D.WIREFRAME_KEY].boolean?:false needsUpdate = true } } diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreePlugin.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreePlugin.kt index ddcff805..b1356d3b 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreePlugin.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreePlugin.kt @@ -27,6 +27,7 @@ class ThreePlugin : AbstractPlugin() { objectFactories[Sphere::class] = ThreeSphereFactory objectFactories[ConeSegment::class] = ThreeCylinderFactory objectFactories[PolyLine::class] = ThreeLineFactory + objectFactories[Label3D::class] = ThreeTextFactory } @Suppress("UNCHECKED_CAST") diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeTextFactory.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeTextFactory.kt new file mode 100644 index 00000000..8ab3e8bc --- /dev/null +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeTextFactory.kt @@ -0,0 +1,47 @@ +package hep.dataforge.vis.spatial.three + +import hep.dataforge.vis.spatial.Label3D +import info.laht.threekt.DoubleSide +import info.laht.threekt.core.Object3D +import info.laht.threekt.geometries.PlaneGeometry +import info.laht.threekt.materials.MeshBasicMaterial +import info.laht.threekt.objects.Mesh +import info.laht.threekt.textures.Texture +import org.w3c.dom.CanvasRenderingContext2D +import org.w3c.dom.HTMLCanvasElement +import kotlin.browser.document +import kotlin.reflect.KClass + +/** + * Using example from http://stemkoski.github.io/Three.js/Texture-From-Canvas.html + */ +object ThreeTextFactory : ThreeFactory { + override val type: KClass get() = Label3D::class + + override fun invoke(obj: Label3D): Object3D { + val canvas = document.createElement("canvas") as HTMLCanvasElement + val context = canvas.getContext("2d") as CanvasRenderingContext2D + context.font = "${obj.fontSize}pt ${obj.fontFamily}" + context.fillStyle = "rgba(255,0,0,0.95)"//obj.material?.color ?: "black" + context.fillText(obj.text, 0.0, 0.0) + + // canvas contents will be used for a texture + val texture = Texture(canvas) + texture.needsUpdate = true + + val material = MeshBasicMaterial().apply { + map = texture + side = DoubleSide + } + material.transparent = true; + + val mesh = Mesh( + PlaneGeometry(canvas.clientWidth, canvas.clientHeight), + material + ) + + mesh.updatePosition(obj) + + return mesh + } +} \ No newline at end of file diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt deleted file mode 100644 index 489b536c..00000000 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt +++ /dev/null @@ -1,211 +0,0 @@ -package hep.dataforge.vis.spatial.demo - -import hep.dataforge.vis.common.Colors -import hep.dataforge.vis.spatial.* -import javafx.stage.Stage -import kotlinx.coroutines.* -import kotlinx.coroutines.javafx.JavaFx -import tornadofx.* -import kotlin.math.PI -import kotlin.math.cos -import kotlin.math.sin -import kotlin.random.Random - -class FXDemoApp : App(FXDemoGrid::class) { - - val view: FXDemoGrid by inject() - - override fun start(stage: Stage) { - super.start(stage) - view.run { - demo("shapes", "Basic shapes") { - box(100.0, 100.0, 100.0) { - z = 110.0 - } - sphere(50.0) { - x = 110 - detail = 16 - } - tube(50, height = 10, innerRadius = 25, angle = PI) { - y = 110 - detail = 16 - rotationX = PI / 4 - } - } - - demo("dynamic", "Dynamic properties") { - val group = group { - box(100, 100, 100) { - z = 110.0 - } - - box(100, 100, 100) { - visible = false - x = 110.0 - //override color for this cube - color(1530) - - GlobalScope.launch(Dispatchers.JavaFx) { - while (isActive) { - delay(500) - visible = !(visible ?: false) - } - } - } - } - - GlobalScope.launch(Dispatchers.JavaFx) { - val random = Random(111) - while (isActive) { - delay(1000) - group.color(random.nextInt(0, Int.MAX_VALUE)) - } - } - } - - demo("rotation", "Rotations") { - box(100, 100, 100) - group { - x = 200 - rotationY = PI / 4 - box(100, 100, 100) { - rotationZ = PI / 4 - color(Colors.red) - } - } - } - - demo("extrude", "extruded shape") { - extrude { - shape { - polygon(8, 50) - } - for (i in 0..100) { - layer(i * 5, 20 * sin(2 * PI / 100 * i), 20 * cos(2 * PI / 100 * i)) - } - color(Colors.teal) - } - } - -// demo("CSG.simple", "CSG operations") { -// composite(CompositeType.UNION) { -// box(100, 100, 100) { -// z = 50 -// } -// sphere(50) -// material { -// color(Colors.lightgreen) -// opacity = 0.3f -// } -// } -// composite(CompositeType.INTERSECT) { -// y = 300 -// box(100, 100, 100) { -// z = 50 -// } -// sphere(50) -// color(Colors.red) -// } -// composite(CompositeType.SUBTRACT) { -// y = -300 -// box(100, 100, 100) { -// z = 50 -// } -// sphere(50) -// color(Colors.blue) -// } -// } - -// demo("CSG.custom", "CSG with manually created object") { -// intersect { -// box(100, 100, 100) -// tube(60, 10) { -// detail = 180 -// } -// } -// } - - demo("lines", "Track / line segments") { - sphere(100) { - color(Colors.blue) - detail = 50 - opacity = 0.4 - } - repeat(20) { - polyline(Point3D(100, 100, 100), Point3D(-100, -100, -100)) { - thickness = 208.0 - rotationX = it * PI2 / 20 - color(Colors.green) - //rotationY = it * PI2 / 20 - } - } - } - -// demo("dynamicBox", "Dancing boxes") { -// val boxes = (-10..10).flatMap { i -> -// (-10..10).map { j -> -// varBox(10, 10, 0, name = "cell_${i}_${j}") { -// x = i * 10 -// y = j * 10 -// value = 128 -// setProperty(EDGES_ENABLED_KEY, false) -// setProperty(WIREFRAME_ENABLED_KEY, false) -// } -// } -// } -// GlobalScope.launch { -// while (isActive) { -// delay(200) -// boxes.forEach { box -> -// box.value = (box.value + Random.nextInt(-15, 15)).coerceIn(0..255) -// } -// } -// } -// } - - } - } -} - -//class SpatialDemoView : View() { -// private val plugin = Global.plugins.fetch(FX3DPlugin) -// private val canvas = FXCanvas3D(plugin) -// -// override val root: Parent = borderpane { -// center = canvas.root -// } -// -// lateinit var group: VisualGroup3D -// -// init { -// canvas.render { -// group = group { -// box(100, 100, 100) -// box(100, 100, 100) { -// x = 110.0 -// color(Colors.blue) -// } -// } -// } -// -// //var color by group.config.number(1530) -// -// GlobalScope.launch { -// val random = Random(111) -// while (isActive) { -// delay(1000) -// group.color(random.nextInt(0, Int.MAX_VALUE)) -// } -// } -// -//// canvas.apply { -//// angleY = -30.0 -//// angleX = -15.0 -//// } -// } -//} - - -fun main() { - launch() -} \ No newline at end of file diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DPlugin.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DPlugin.kt index 40f2a435..7c44d47f 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DPlugin.kt +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DPlugin.kt @@ -2,13 +2,20 @@ package hep.dataforge.vis.spatial.fx import hep.dataforge.context.* import hep.dataforge.meta.Meta +import hep.dataforge.meta.boolean import hep.dataforge.meta.get import hep.dataforge.provider.Type import hep.dataforge.vis.spatial.* +import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_KEY +import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_WIREFRAME_KEY import hep.dataforge.vis.spatial.fx.FX3DFactory.Companion.TYPE import javafx.scene.Group import javafx.scene.Node +import javafx.scene.shape.CullFace +import javafx.scene.shape.DrawMode import javafx.scene.shape.Shape3D +import javafx.scene.text.Font +import javafx.scene.text.Text import javafx.scene.transform.Rotate import org.fxyz3d.shapes.composites.PolyLine3D import org.fxyz3d.shapes.primitives.CuboidMesh @@ -56,11 +63,18 @@ class FX3DPlugin : AbstractPlugin() { } else { FXShapeFactory(obj, binding) } + is Label3D -> Text(obj.text).apply { + font = Font.font(obj.fontFamily, obj.fontSize) + x = -layoutBounds.width / 2 + y = layoutBounds.height / 2 + } is PolyLine -> PolyLine3D( obj.points.map { it.point }, obj.thickness.toFloat(), - obj.material?.get("color")?.color() - ) + obj.getProperty(Material3D.MATERIAL_COLOR_KEY)?.color() + ).apply { + this.meshView.cullFace = CullFace.FRONT + } else -> { //find specialized factory for this type if it is present val factory: FX3DFactory? = findObjectFactory(obj::class) @@ -79,15 +93,15 @@ class FX3DPlugin : AbstractPlugin() { scaleZProperty().bind(binding[VisualObject3D.zScale].float(obj.scaleZ.toFloat())) val rotateX = Rotate(0.0, Rotate.X_AXIS).apply { - angleProperty().bind(binding[VisualObject3D.xRotation].float(obj.rotationX.toFloat())) + angleProperty().bind(binding[VisualObject3D.xRotation].float(obj.rotationX.toFloat()).multiply(180.0 / PI)) } val rotateY = Rotate(0.0, Rotate.Y_AXIS).apply { - angleProperty().bind(binding[VisualObject3D.yRotation].float(obj.rotationY.toFloat())) + angleProperty().bind(binding[VisualObject3D.yRotation].float(obj.rotationY.toFloat()).multiply(180.0 / PI)) } val rotateZ = Rotate(0.0, Rotate.Z_AXIS).apply { - angleProperty().bind(binding[VisualObject3D.zRotation].float(obj.rotationZ.toFloat())) + angleProperty().bind(binding[VisualObject3D.zRotation].float(obj.rotationZ.toFloat()).multiply(180.0 / PI)) } when (obj.rotationOrder) { @@ -100,9 +114,17 @@ class FX3DPlugin : AbstractPlugin() { } if (this is Shape3D) { - materialProperty().bind(binding[Material3D.MATERIAL_KEY].transform { + materialProperty().bind(binding[MATERIAL_KEY].transform { it.material() }) + + drawModeProperty().bind(binding[MATERIAL_WIREFRAME_KEY].transform { + if (it.boolean == true) { + DrawMode.LINE + } else { + DrawMode.FILL + } + }) } } } diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXCanvas3D.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXCanvas3D.kt index 7c7663e0..a8f38b73 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXCanvas3D.kt +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXCanvas3D.kt @@ -33,13 +33,15 @@ class FXCanvas3D(val plugin: FX3DPlugin, meta: Meta = EmptyMeta) : it.setRadius(meta["axis.width"].double ?: LINE_WIDTH) it.isVisible = meta["axis.visible"].boolean ?: (meta["axis"] != null) world.add(it) - } + val light = AmbientLight() + private val camera = PerspectiveCamera().apply { nearClip = CAMERA_NEAR_CLIP farClip = CAMERA_FAR_CLIP translateZ = CAMERA_INITIAL_DISTANCE + this.add(light) } val cameraTransform = CameraTransformer().also { @@ -60,20 +62,27 @@ class FXCanvas3D(val plugin: FX3DPlugin, meta: Meta = EmptyMeta) : val rotationZProperty get() = cameraTransform.rz.angleProperty() var angleZ by rotationZProperty + private val canvas = SubScene( + Group(world, cameraTransform).apply { DepthTest.ENABLE }, + 400.0, + 400.0, + true, + SceneAntialiasing.BALANCED + ).also { scene -> + scene.fill = Color.GREY + scene.camera = camera + //id = "canvas" + handleKeyboard(scene) + handleMouse(scene) + } + override val root = borderpane { - center = SubScene( - Group(world, cameraTransform).apply { DepthTest.ENABLE }, - 1024.0, - 768.0, - true, - SceneAntialiasing.BALANCED - ).also { scene -> - scene.fill = Color.GREY - scene.camera = camera - id = "canvas" - handleKeyboard(scene) - handleMouse(scene) - } + center = canvas + } + + init { + canvas.widthProperty().bind(root.widthProperty()) + canvas.heightProperty().bind(root.heightProperty()) } @@ -170,6 +179,6 @@ class FXCanvas3D(val plugin: FX3DPlugin, meta: Meta = EmptyMeta) : 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 const val LINE_WIDTH = 1.0 } } \ No newline at end of file diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXCompositeFactory.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXCompositeFactory.kt index 1b11f2c0..a4af60f6 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXCompositeFactory.kt +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXCompositeFactory.kt @@ -1,25 +1,57 @@ package hep.dataforge.vis.spatial.fx import eu.mihosoft.jcsg.CSG +import eu.mihosoft.jcsg.Polygon +import eu.mihosoft.vvecmath.Vector3d import hep.dataforge.vis.spatial.Composite import hep.dataforge.vis.spatial.CompositeType import javafx.scene.Group import javafx.scene.Node import javafx.scene.shape.MeshView -import org.fxyz3d.utils.MeshUtils +import javafx.scene.shape.TriangleMesh +import javafx.scene.shape.VertexFormat +import java.util.* +import kotlin.collections.HashMap import kotlin.reflect.KClass -class FXCompositeFactory(val plugin: FX3DPlugin) : - FX3DFactory { +private fun MeshView.toCSG(): CSG { + val mesh = this.mesh as TriangleMesh + if (mesh.vertexFormat != VertexFormat.POINT_TEXCOORD) error("Not POINT_TEXCOORD") + val polygons: MutableList = ArrayList() + val faces = mesh.faces + val points = mesh.points + + val vectorCache = HashMap() + fun getVector(index: Int) = vectorCache.getOrPut(index) { + Vector3d.xyz( + points[3 * index].toDouble(), + points[3 * index + 1].toDouble(), + points[3 * index + 2].toDouble() + ) + } + + for (i in 0 until faces.size() / 6) { + val polygon = Polygon.fromPoints( + getVector(faces[6 * i]), + getVector(faces[6 * i + 2]), + getVector(faces[6 * i + 4]) + ) + polygons.add(polygon) + } + + return CSG.fromPolygons(polygons) +} + +class FXCompositeFactory(val plugin: FX3DPlugin) : FX3DFactory { override val type: KClass get() = Composite::class override fun invoke(obj: Composite, binding: VisualObjectFXBinding): Node { val first = plugin.buildNode(obj.first) as? MeshView ?: error("Can't build node") val second = plugin.buildNode(obj.second) as? MeshView ?: error("Can't build node") - val firstCSG = MeshUtils.mesh2CSG(first) - val secondCSG = MeshUtils.mesh2CSG(second) - val resultCSG = when(obj.compositeType){ + val firstCSG = first.toCSG() + val secondCSG = second.toCSG() + val resultCSG = when (obj.compositeType) { CompositeType.UNION -> firstCSG.union(secondCSG) CompositeType.INTERSECT -> firstCSG.intersect(secondCSG) CompositeType.SUBTRACT -> firstCSG.difference(secondCSG) @@ -28,9 +60,9 @@ class FXCompositeFactory(val plugin: FX3DPlugin) : } } -internal fun CSG.toNode(): Node{ +internal fun CSG.toNode(): Node { val meshes = toJavaFXMesh().asMeshViews - return if(meshes.size == 1){ + return if (meshes.size == 1) { meshes.first() } else { Group(meshes.map { it }) diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXMaterials.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXMaterials.kt index 2237a46b..af8cb2ee 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXMaterials.kt +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXMaterials.kt @@ -5,6 +5,8 @@ import hep.dataforge.meta.double import hep.dataforge.meta.get import hep.dataforge.meta.int import hep.dataforge.values.ValueType +import hep.dataforge.vis.common.Colors +import hep.dataforge.vis.spatial.Material3D import javafx.scene.paint.Color import javafx.scene.paint.Material import javafx.scene.paint.PhongMaterial @@ -39,16 +41,16 @@ fun MetaItem<*>.color(opacity: Double = 1.0): Color { val red = int and 0x00ff0000 shr 16 val green = int and 0x0000ff00 shr 8 val blue = int and 0x000000ff - Color.rgb(red, green, blue) + Color.rgb(red, green, blue, opacity) } else { Color.web(this.value.string) } is MetaItem.NodeItem -> { Color.rgb( - node["red"]?.int ?: 0, - node["green"]?.int ?: 0, - node["blue"]?.int ?: 0, - node["opacity"]?.double ?: opacity + node[Colors.RED_KEY]?.int ?: 0, + node[Colors.GREEN_KEY]?.int ?: 0, + node[Colors.BLUE_KEY]?.int ?: 0, + node[Material3D.OPACITY_KEY]?.double ?: opacity ) } } @@ -62,9 +64,9 @@ fun MetaItem<*>?.material(): Material { null -> FXMaterials.GREY is MetaItem.ValueItem -> PhongMaterial(color()) is MetaItem.NodeItem -> PhongMaterial().apply { - val opacity = node["opacity"].double ?: 1.0 - diffuseColor = node["color"]?.color(opacity) ?: Color.DARKGREY - specularColor = node["specularColor"]?.color(opacity) ?: Color.WHITE + val opacity = node[Material3D.OPACITY_KEY].double ?: 1.0 + diffuseColor = node[Material3D.COLOR_KEY]?.color(opacity) ?: Color.DARKGREY + specularColor = node[Material3D.SPECULAR_COLOR]?.color(opacity) ?: Color.WHITE } } } diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXShapeFactory.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXShapeFactory.kt index cd851fe6..0dd58c45 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXShapeFactory.kt +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FXShapeFactory.kt @@ -7,6 +7,7 @@ import hep.dataforge.vis.spatial.Shape import javafx.scene.shape.Mesh import javafx.scene.shape.MeshView import javafx.scene.shape.TriangleMesh +import javafx.scene.shape.VertexFormat import org.fxyz3d.geometry.Face3 import kotlin.reflect.KClass @@ -42,13 +43,16 @@ private class FXGeometryBuilder : GeometryBuilder { } override fun build(): Mesh { - val mesh = TriangleMesh() + val mesh = TriangleMesh(VertexFormat.POINT_TEXCOORD) vertices.forEach { //TODO optimize copy mesh.points.addAll(it.x.toFloat(), it.y.toFloat(), it.z.toFloat()) } + + mesh.texCoords.addAll(0f, 0f) + faces.forEach { - mesh.faces.addAll(it.p0, it.p1, it.p2) + mesh.faces.addAll(it.p0, 0, it.p1, 0, it.p2, 0) } return mesh } diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/VisualObjectFXBinding.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/VisualObjectFXBinding.kt index bc772892..faa7b843 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/VisualObjectFXBinding.kt +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/VisualObjectFXBinding.kt @@ -2,9 +2,10 @@ package hep.dataforge.vis.spatial.fx import hep.dataforge.meta.* import hep.dataforge.names.Name -import hep.dataforge.names.isEmpty +import hep.dataforge.names.startsWith import hep.dataforge.names.toName import hep.dataforge.vis.common.VisualObject +import javafx.application.Platform import javafx.beans.binding.ObjectBinding import tornadofx.* @@ -16,12 +17,17 @@ class VisualObjectFXBinding(val obj: VisualObject) { init { obj.onPropertyChange(this) { name, _, _ -> - var currentName = name - while(!currentName.isEmpty()) { - //recursively update all upper level bindings - bindings[currentName]?.invalidate() - currentName = currentName.cutLast() + bindings.filter { it.key.startsWith(name) }.forEach { entry -> + Platform.runLater { + entry.value.invalidate() + } } +// var currentName = name +// while (!currentName.isEmpty()) { +// //recursively update all upper level bindings +// bindings[currentName]?.invalidate() +// currentName = currentName.cutLast() +// } } } @@ -46,9 +52,9 @@ fun ObjectBinding?>.long() = objectBinding { it.long } fun ObjectBinding?>.node() = objectBinding { it.node } fun ObjectBinding?>.string(default: String) = stringBinding { it.string ?: default } -fun ObjectBinding?>.double(default: Double) = objectBinding { it.double ?: default } -fun ObjectBinding?>.float(default: Float) = objectBinding { it.float ?: default } -fun ObjectBinding?>.int(default: Int) = objectBinding { it.int ?: default } -fun ObjectBinding?>.long(default: Long) = objectBinding { it.long ?:default } +fun ObjectBinding?>.double(default: Double) = doubleBinding { it.double ?: default } +fun ObjectBinding?>.float(default: Float) = floatBinding { it.float ?: default } +fun ObjectBinding?>.int(default: Int) = integerBinding { it.int ?: default } +fun ObjectBinding?>.long(default: Long) = longBinding { it.long ?: default } fun ObjectBinding?>.transform(transform: (MetaItem<*>) -> T) = objectBinding { it?.let(transform) } diff --git a/settings.gradle.kts b/settings.gradle.kts index f3511af6..9827167d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -28,10 +28,9 @@ rootProject.name = "dataforge-vis" include( ":dataforge-vis-common", ":wrappers", - ":dataforge-vis-fx", ":dataforge-vis-spatial", ":dataforge-vis-spatial-gdml", - ":spatial-js-demo" + ":spatial-demo" ) //if(file("../dataforge-core").exists()) { diff --git a/spatial-demo/build.gradle.kts b/spatial-demo/build.gradle.kts new file mode 100644 index 00000000..46d63633 --- /dev/null +++ b/spatial-demo/build.gradle.kts @@ -0,0 +1,39 @@ +import org.openjfx.gradle.JavaFXOptions + +plugins { + id("scientifik.mpp") + id("org.openjfx.javafxplugin") + id("application") +} + +kotlin { + + jvm { + withJava() + } + + js { + browser { + webpackTask { + sourceMaps = false + } + } + } + + sourceSets { + commonMain { + dependencies { + api(project(":dataforge-vis-spatial")) + api(project(":dataforge-vis-spatial-gdml")) + } + } + } +} + +application { + mainClassName = "hep.dataforge.vis.spatial.demo.FXDemoAppKt" +} + +configure { + modules("javafx.controls") +} \ No newline at end of file diff --git a/spatial-demo/src/commonMain/kotlin/hep/dataforge/vis/spatial/demo/demo.kt b/spatial-demo/src/commonMain/kotlin/hep/dataforge/vis/spatial/demo/demo.kt new file mode 100644 index 00000000..09728066 --- /dev/null +++ b/spatial-demo/src/commonMain/kotlin/hep/dataforge/vis/spatial/demo/demo.kt @@ -0,0 +1,158 @@ +package hep.dataforge.vis.spatial.demo + +import hep.dataforge.meta.buildMeta +import hep.dataforge.names.toName +import hep.dataforge.output.OutputManager +import hep.dataforge.vis.common.Colors +import hep.dataforge.vis.common.VisualObject +import hep.dataforge.vis.spatial.* +import kotlinx.coroutines.* +import kotlin.math.PI +import kotlin.math.cos +import kotlin.math.sin +import kotlin.random.Random + + +fun OutputManager.demo(name: String, title: String = name, block: VisualGroup3D.() -> Unit) { + val meta = buildMeta { + "title" put title + } + val output = get(VisualObject::class, name.toName(), meta = meta) + output.render(action = block) +} + +fun OutputManager.showcase() { + demo("shapes", "Basic shapes") { + box(100.0, 100.0, 100.0) { + z = 110.0 + } + sphere(50.0) { + x = 110 + detail = 16 + } + tube(50, height = 10, innerRadius = 25, angle = PI) { + y = 110 + detail = 16 + rotationX = PI / 4 + } + } + + demo("dynamic", "Dynamic properties") { + val group = group { + box(100, 100, 100) { + z = 110.0 + } + + box(100, 100, 100) { + visible = false + x = 110.0 + //override color for this cube + color(1530) + + GlobalScope.launch(Dispatchers.Main) { + while (isActive) { + delay(500) + visible = !(visible ?: false) + } + } + } + } + + GlobalScope.launch(Dispatchers.Main) { + val random = Random(111) + while (isActive) { + delay(1000) + group.color(random.nextInt(0, Int.MAX_VALUE)) + } + } + } + + demo("rotation", "Rotations") { + box(100, 100, 100) + group { + x = 200 + rotationY = PI / 4 + box(100, 100, 100) { + rotationZ = PI / 4 + color(Colors.red) + } + } + } + + demo("extrude", "extruded shape") { + extrude { + shape { + polygon(8, 50) + } + for (i in 0..100) { + layer(i * 5, 20 * sin(2 * PI / 100 * i), 20 * cos(2 * PI / 100 * i)) + } + color(Colors.teal) + } + } + + demo("lines", "Track / line segments") { + sphere(100) { + detail = 32 + opacity = 0.4 + color(Colors.blue) + } + repeat(20) { + polyline(Point3D(100, 100, 100), Point3D(-100, -100, -100)) { + thickness = 3.0 + rotationX = it * PI2 / 20 + color(Colors.green) + //rotationY = it * PI2 / 20 + } + } + } + + demo("text", "Box with a label") { + box(100, 100, 50) { + opacity = 0.3 + } + label("Hello, world!",fontSize = 15) { + z = -26 + } + } +} + +fun OutputManager.showcaseCSG(){ + demo("CSG.simple", "CSG operations") { + composite(CompositeType.UNION) { + box(100, 100, 100) { + z = 50 + } + sphere(50) + material { + color(Colors.lightgreen) + opacity = 0.3f + } + } + composite(CompositeType.INTERSECT) { + y = 300 + box(100, 100, 100) { + z = 50 + } + sphere(50) + color(Colors.red) + } + composite(CompositeType.SUBTRACT) { + y = -300 + box(100, 100, 100) { + z = 50 + } + sphere(50) + color(Colors.blue) + } + } + + demo("CSG.custom", "CSG with manually created object") { + intersect { + tube(60, 10) { + detail = 64 + } + box(100, 100, 100) + } + } +} \ No newline at end of file diff --git a/spatial-demo/src/jsMain/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt b/spatial-demo/src/jsMain/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt new file mode 100644 index 00000000..e55a3ccb --- /dev/null +++ b/spatial-demo/src/jsMain/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt @@ -0,0 +1,59 @@ +package hep.dataforge.vis.spatial.demo + +import hep.dataforge.context.ContextBuilder +import hep.dataforge.context.Global +import hep.dataforge.js.Application +import hep.dataforge.js.startApplication +import hep.dataforge.vis.spatial.three.MeshThreeFactory.Companion.EDGES_ENABLED_KEY +import hep.dataforge.vis.spatial.three.MeshThreeFactory.Companion.WIREFRAME_ENABLED_KEY +import hep.dataforge.vis.spatial.three.ThreePlugin +import hep.dataforge.vis.spatial.x +import hep.dataforge.vis.spatial.y +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch +import kotlin.browser.document +import kotlin.random.Random + +private class ThreeDemoApp : Application { + + override fun start(state: Map) { + + val element = document.getElementById("canvas") ?: error("Element with id 'canvas' not found on page") + + ThreeDemoGrid(element).run { + showcase() + showcaseCSG() + demo("dynamicBox", "Dancing boxes") { + val boxes = (-10..10).flatMap { i -> + (-10..10).map { j -> + varBox(10, 10, 0, name = "cell_${i}_${j}") { + x = i * 10 + y = j * 10 + value = 128 + setProperty(EDGES_ENABLED_KEY, false) + setProperty(WIREFRAME_ENABLED_KEY, false) + } + } + } + GlobalScope.launch { + while (isActive) { + delay(500) + boxes.forEach { box -> + box.value = (box.value + Random.nextInt(-15, 15)).coerceIn(0..255) + } + } + } + } + } + + + } + + override fun dispose() = emptyMap()//mapOf("lines" put presenter.dispose()) +} + +fun main() { + startApplication(::ThreeDemoApp) +} \ No newline at end of file diff --git a/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoGrid.kt b/spatial-demo/src/jsMain/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoGrid.kt similarity index 55% rename from spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoGrid.kt rename to spatial-demo/src/jsMain/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoGrid.kt index 94e9b709..8d1aadc4 100644 --- a/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoGrid.kt +++ b/spatial-demo/src/jsMain/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoGrid.kt @@ -1,20 +1,13 @@ package hep.dataforge.vis.spatial.demo -import hep.dataforge.context.AbstractPlugin -import hep.dataforge.context.Context -import hep.dataforge.context.PluginFactory -import hep.dataforge.context.PluginTag +import hep.dataforge.context.Global import hep.dataforge.meta.Meta -import hep.dataforge.meta.buildMeta import hep.dataforge.meta.get import hep.dataforge.meta.string import hep.dataforge.names.Name -import hep.dataforge.names.toName import hep.dataforge.output.OutputManager import hep.dataforge.output.Renderer import hep.dataforge.vis.common.VisualObject -import hep.dataforge.vis.spatial.VisualGroup3D -import hep.dataforge.vis.spatial.render import hep.dataforge.vis.spatial.three.ThreeCanvas import hep.dataforge.vis.spatial.three.ThreePlugin import hep.dataforge.vis.spatial.three.output @@ -25,31 +18,25 @@ import kotlinx.html.hr import kotlinx.html.id import kotlinx.html.js.div import kotlinx.html.span +import org.w3c.dom.Element import kotlin.browser.document import kotlin.dom.clear import kotlin.reflect.KClass -class ThreeDemoGrid(meta: Meta) : AbstractPlugin(meta), OutputManager { - override val tag: PluginTag get() = Companion.tag +class ThreeDemoGrid(element: Element, meta: Meta = Meta.empty) : OutputManager { private val gridRoot = document.create.div("row") private val outputs: MutableMap = HashMap() - init { - require(ThreePlugin) - } + private val three = Global.plugins.fetch(ThreePlugin) - override fun attach(context: Context) { - super.attach(context) - val elementId = meta["elementID"].string ?: "canvas" - val element = document.getElementById(elementId) ?: error("Element with id $elementId not found on page") + init { element.clear() element.append(gridRoot) } @Suppress("UNCHECKED_CAST") override fun get(type: KClass, name: Name, stage: Name, meta: Meta): Renderer { - val three = context.plugins.get()!! return outputs.getOrPut(name) { if (type != VisualObject::class) error("Supports only DisplayObject") @@ -63,7 +50,7 @@ class ThreeDemoGrid(meta: Meta) : AbstractPlugin(meta), OutputManager { gridRoot.append { span("border") { div("col-6") { - div { id = "output-$name" }.also{ + div { id = "output-$name" }.also { output.attach(it) } hr() @@ -75,20 +62,5 @@ class ThreeDemoGrid(meta: Meta) : AbstractPlugin(meta), OutputManager { output } as Renderer } - - companion object : PluginFactory { - override val tag: PluginTag = PluginTag(group = "hep.dataforge", name = "vis.js.spatial.demo") - - override val type: KClass = ThreeDemoGrid::class - - override fun invoke(meta: Meta,context: Context): ThreeDemoGrid = ThreeDemoGrid(meta) - } } -fun ThreeDemoGrid.demo(name: String, title: String = name, block: VisualGroup3D.() -> Unit) { - val meta = buildMeta { - "title" put title - } - val output = get(VisualObject::class, name.toName(), meta = meta) - output.render(action = block) -} \ No newline at end of file diff --git a/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/VariableBox.kt b/spatial-demo/src/jsMain/kotlin/hep/dataforge/vis/spatial/demo/VariableBox.kt similarity index 100% rename from spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/VariableBox.kt rename to spatial-demo/src/jsMain/kotlin/hep/dataforge/vis/spatial/demo/VariableBox.kt diff --git a/spatial-js-demo/src/main/web/index.html b/spatial-demo/src/jsMain/web/index.html similarity index 100% rename from spatial-js-demo/src/main/web/index.html rename to spatial-demo/src/jsMain/web/index.html diff --git a/spatial-demo/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt b/spatial-demo/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt new file mode 100644 index 00000000..3fbaff04 --- /dev/null +++ b/spatial-demo/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt @@ -0,0 +1,40 @@ +package hep.dataforge.vis.spatial.demo + +import hep.dataforge.vis.spatial.Material3D +import hep.dataforge.vis.spatial.gdml.LUnit +import hep.dataforge.vis.spatial.gdml.gdml +import javafx.stage.Stage +import tornadofx.* +import java.nio.file.Paths + +class FXDemoApp : App(FXDemoGrid::class) { + + val view: FXDemoGrid by inject() + + override fun start(stage: Stage) { + super.start(stage) + + stage.width = 400.0 + stage.height = 400.0 + + //view.showcase() + view.demo("gdml", "gdml") { + gdml(Paths.get("D:\\Work\\Projects\\gdml.kt\\gdml-source\\cubes.gdml")) { + lUnit = LUnit.CM + + solidConfiguration = { parent, solid -> + if (parent.physVolumes.isNotEmpty()) { + useStyle("opaque") { + Material3D.MATERIAL_OPACITY_KEY put 0.3 + } + } + } + } + //setProperty(Material3D.MATERIAL_WIREFRAME_KEY, true) + } + } +} + +fun main() { + launch() +} \ No newline at end of file diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoGrid.kt b/spatial-demo/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoGrid.kt similarity index 86% rename from dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoGrid.kt rename to spatial-demo/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoGrid.kt index e6b23039..21d98b8e 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoGrid.kt +++ b/spatial-demo/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoGrid.kt @@ -47,12 +47,4 @@ class FXDemoGrid : View(), OutputManager { } as Renderer } -} - -fun FXDemoGrid.demo(name: String, title: String = name, block: VisualGroup3D.() -> Unit) { - val meta = buildMeta { - "title" put title - } - val output = get(VisualObject::class, name.toName(), meta = meta) - output.render(action = block) } \ No newline at end of file diff --git a/spatial-js-demo/build.gradle.kts b/spatial-js-demo/build.gradle.kts deleted file mode 100644 index 19b614fd..00000000 --- a/spatial-js-demo/build.gradle.kts +++ /dev/null @@ -1,19 +0,0 @@ -plugins { - id("scientifik.js") - //id("kotlin-dce-js") -} - -dependencies { - api(project(":dataforge-vis-spatial")) - testImplementation(kotlin("test-js")) -} - -//kotlin{ -// target { -// browser{ -// webpackTask { -// sourceMaps = false -// } -// } -// } -//} \ No newline at end of file diff --git a/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt b/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt deleted file mode 100644 index 01e6f690..00000000 --- a/spatial-js-demo/src/main/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt +++ /dev/null @@ -1,179 +0,0 @@ -package hep.dataforge.vis.spatial.demo - -import hep.dataforge.context.ContextBuilder -import hep.dataforge.js.Application -import hep.dataforge.js.startApplication -import hep.dataforge.vis.common.Colors -import hep.dataforge.vis.spatial.* -import hep.dataforge.vis.spatial.three.MeshThreeFactory.Companion.EDGES_ENABLED_KEY -import hep.dataforge.vis.spatial.three.MeshThreeFactory.Companion.WIREFRAME_ENABLED_KEY -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.delay -import kotlinx.coroutines.isActive -import kotlinx.coroutines.launch -import kotlin.math.PI -import kotlin.math.cos -import kotlin.math.sin -import kotlin.random.Random - -private class ThreeDemoApp : Application { - - override fun start(state: Map) { - - //TODO replace by optimized builder after dataforge 0.1.3-dev-8 - val context = ContextBuilder("three-demo").build() - - context.plugins.load(ThreeDemoGrid()).run { - demo("shapes", "Basic shapes") { - box(100.0, 100.0, 100.0) { - z = 110.0 - } - sphere(50.0) { - x = 110 - detail = 16 - } - tube(50, height = 10, innerRadius = 25, angle = PI) { - y = 110 - detail = 16 - rotationX = PI / 4 - } - } - - demo("dynamic", "Dynamic properties") { - val group = group { - box(100, 100, 100) { - z = 110.0 - } - - box(100, 100, 100) { - visible = false - x = 110.0 - //override color for this cube - color(1530) - - GlobalScope.launch { - while (isActive) { - delay(500) - visible = !(visible ?: false) - } - } - } - } - - GlobalScope.launch { - val random = Random(111) - while (isActive) { - delay(1000) - group.color(random.nextInt(0, Int.MAX_VALUE)) - } - } - } - - demo("rotation", "Rotations") { - box(100, 100, 100) - group { - x = 200 - rotationY = PI / 4 - box(100, 100, 100) { - rotationZ = PI / 4 - color(Colors.red) - } - } - } - - demo("extrude", "extruded shape") { - extrude { - shape { - polygon(8, 50) - } - for (i in 0..100) { - layer(i * 5, 20 * sin(2 * PI / 100 * i), 20 * cos(2 * PI / 100 * i)) - } - color(Colors.teal) - } - } - - demo("CSG.simple", "CSG operations") { - composite(CompositeType.UNION) { - box(100, 100, 100) { - z = 50 - } - sphere(50) - material { - color(Colors.lightgreen) - opacity = 0.3f - } - } - composite(CompositeType.INTERSECT) { - y = 300 - box(100, 100, 100) { - z = 50 - } - sphere(50) - color(Colors.red) - } - composite(CompositeType.SUBTRACT) { - y = -300 - box(100, 100, 100) { - z = 50 - } - sphere(50) - color(Colors.blue) - } - } - demo("CSG.custom", "CSG with manually created object") { - intersect { - box(100, 100, 100) - tube(60, 10) { - detail = 180 - } - } - } - demo("lines", "Track / line segments") { - sphere(100) { - color(Colors.blue) - detail = 50 - opacity = 0.4 - } - repeat(20) { - polyline(Point3D(100, 100, 100), Point3D(-100, -100, -100)) { - thickness = 208.0 - rotationX = it * PI2 / 20 - color(Colors.green) - //rotationY = it * PI2 / 20 - } - } - } - - demo("dynamicBox", "Dancing boxes") { - val boxes = (-10..10).flatMap { i -> - (-10..10).map { j -> - varBox(10, 10, 0, name = "cell_${i}_${j}") { - x = i * 10 - y = j * 10 - value = 128 - setProperty(EDGES_ENABLED_KEY, false) - setProperty(WIREFRAME_ENABLED_KEY, false) - } - } - } - GlobalScope.launch { - while (isActive) { - delay(200) - boxes.forEach { box -> - box.value = (box.value + Random.nextInt(-15, 15)).coerceIn(0..255) - } - } - } - } - } - - - } - - override fun dispose() = emptyMap()//mapOf("lines" put presenter.dispose()) -} - -fun main() { - startApplication(::ThreeDemoApp) -} \ No newline at end of file From a5a03f1c029889f59171a108d06e11622173dcc5 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 23 Dec 2019 15:53:47 +0300 Subject: [PATCH 13/25] Style cleanup Fix rotation order --- .../hep/dataforge/vis/common/StyleSheet.kt | 12 ++++- .../hep/dataforge/vis/common/VisualGroup.kt | 16 ++---- .../vis/spatial/gdml/GDMLTransformer.kt | 8 +-- .../dataforge/vis/spatial/gdml/visualGDML.kt | 4 +- .../hep/dataforge/vis/spatial/Composite.kt | 12 +++-- .../kotlin/hep/dataforge/vis/spatial/Proxy.kt | 18 +++---- .../dataforge/vis/spatial/VisualGroup3D.kt | 49 +++++++++++++------ .../hep/dataforge/vis/spatial/PropertyTest.kt | 46 ++++++++++++----- .../vis/spatial/editor/propertyEditor.kt | 11 ++--- .../dataforge/vis/spatial/fx/FX3DPlugin.kt | 18 ++++--- .../dataforge/vis/spatial/demo/FXDemoApp.kt | 2 +- 11 files changed, 126 insertions(+), 70 deletions(-) diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/StyleSheet.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/StyleSheet.kt index d6803562..2fcc1bed 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/StyleSheet.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/StyleSheet.kt @@ -3,8 +3,7 @@ package hep.dataforge.vis.common import hep.dataforge.io.serialization.MetaSerializer -import hep.dataforge.meta.Meta -import hep.dataforge.meta.get +import hep.dataforge.meta.* import hep.dataforge.names.Name import hep.dataforge.names.asName import kotlinx.serialization.Serializable @@ -37,6 +36,15 @@ class StyleSheet() { } owner?.styleChanged(key, oldStyle, style) } + + infix fun String.put(style: Meta?) { + set(this, style) + } + + operator fun set(key: String, builder: MetaBuilder.() -> Unit) { + val newStyle = get(key)?.let { buildMeta(it, builder) } ?: buildMeta(builder) + set(key, newStyle.seal()) + } } private fun VisualObject.styleChanged(key: String, oldStyle: Meta?, newStyle: Meta?) { diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualGroup.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualGroup.kt index 5baa6262..11d3dcab 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualGroup.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualGroup.kt @@ -1,8 +1,5 @@ package hep.dataforge.vis.common -import hep.dataforge.meta.MetaBuilder -import hep.dataforge.meta.buildMeta -import hep.dataforge.meta.seal import hep.dataforge.names.* import hep.dataforge.provider.Provider @@ -14,7 +11,7 @@ interface VisualGroup : Provider, Iterable, VisualObject { override val defaultTarget: String get() = VisualObject.TYPE - val styleSheet: StyleSheet + val styleSheet: StyleSheet? override fun provideTop(target: String): Map = when (target) { @@ -26,7 +23,7 @@ interface VisualGroup : Provider, Iterable, VisualObject { } res.entries }.associate { it.toPair() } - STYLE_TARGET -> styleSheet.items.mapKeys { it.key.toName() } + STYLE_TARGET -> styleSheet?.items?.mapKeys { it.key.toName() } ?: emptyMap() else -> emptyMap() } @@ -47,8 +44,8 @@ interface VisualGroup : Provider, Iterable, VisualObject { /** * A fix for serialization bug that writes all proper parents inside the tree after deserialization */ - fun attachChildren(){ - styleSheet.owner = this + fun attachChildren() { + styleSheet?.owner = this this.children.values.forEach { it.parent = this (it as? VisualGroup)?.attachChildren() @@ -60,11 +57,6 @@ interface VisualGroup : Provider, Iterable, VisualObject { } } -fun VisualGroup.updateStyle(key: String, builder: MetaBuilder.() -> Unit) { - val newStyle = styleSheet[key]?.let { buildMeta(it, builder) } ?: buildMeta(builder) - styleSheet[key] = newStyle.seal() -} - data class StyleRef(val group: VisualGroup, val styleName: Name) val VisualGroup.isEmpty: Boolean get() = this.children.isEmpty() diff --git a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt index 3b529780..d59d1a3f 100644 --- a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt +++ b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt @@ -40,7 +40,7 @@ class GDMLTransformer(val root: GDML) { var solidConfiguration: VisualObject3D.(parent: GDMLVolume, solid: GDMLSolid) -> Unit = { _, _ -> } fun VisualObject.useStyle(name: String, builder: MetaBuilder.() -> Unit) { - styleCache.getOrPut(name.toName()){ + styleCache.getOrPut(name.toName()) { buildMeta(builder) } useStyle(name) @@ -51,7 +51,7 @@ class GDMLTransformer(val root: GDML) { val styleName = "material[${material.name}]" - obj.useStyle(styleName){ + obj.useStyle(styleName) { MATERIAL_COLOR_KEY put random.nextInt(16777216) "gdml.material" put material.name } @@ -68,7 +68,9 @@ class GDMLTransformer(val root: GDML) { internal fun finalize(final: VisualGroup3D): VisualGroup3D { final.prototypes = proto styleCache.forEach { - final.styleSheet[it.key.toString()] = it.value + final.styleSheet { + this[it.key.toString()] = it.value + } } final.rotationOrder = RotationOrder.ZXY onFinish(this@GDMLTransformer) diff --git a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDML.kt b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDML.kt index 42c3d1c6..9134989b 100644 --- a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDML.kt +++ b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDML.kt @@ -250,5 +250,7 @@ fun GDML.toVisual(block: GDMLTransformer.() -> Unit = {}): VisualGroup3D { * Append gdml node to the group */ fun VisualGroup3D.gdml(gdml: GDML, key: String = "", transformer: GDMLTransformer.() -> Unit = {}) { - set(key, gdml.toVisual(transformer)) + val visual = gdml.toVisual(transformer) + println(Visual3DPlugin.json.stringify(VisualGroup3D.serializer(),visual)) + set(key, visual) } \ No newline at end of file diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt index 2ea3fc31..ed6f087b 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt @@ -47,9 +47,15 @@ inline fun VisualGroup3D.composite( it.config.update(group.config) //it.material = group.material - it.position = group.position - it.rotation = group.rotation - it.scale = group.scale + if(group.position!=null) { + it.position = group.position + } + if(group.rotation!=null) { + it.rotation = group.rotation + } + if(group.scale!=null) { + it.scale = group.scale + } set(name, it) } } diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt index b3b04cd0..95da3d1a 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt @@ -46,8 +46,8 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua return if (inherit) { properties?.get(name) ?: mergedStyles[name] - ?: prototype.getProperty(name, false) - ?: parent?.getProperty(name, inherit) + ?: prototype.getProperty(name) + ?: parent?.getProperty(name) } else { properties?.get(name) ?: mergedStyles[name] @@ -74,7 +74,6 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua ?: error("Prototype with name $name not found in $this") } - override var styles: List get() = super.styles + prototype.styles set(value) { @@ -119,12 +118,12 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua return if (inherit) { properties?.get(name) ?: mergedStyles[name] - ?: prototype.getProperty(name, inherit) - ?: parent?.getProperty(name, inherit) + ?: prototype.getProperty(name) + ?: parent?.getProperty(name) } else { properties?.get(name) ?: mergedStyles[name] - ?: prototype.getProperty(name, inherit) + ?: prototype.getProperty(name, false) } } @@ -135,11 +134,11 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua } } -val VisualObject.prototype: VisualObject? +val VisualObject.prototype: VisualObject get() = when (this) { is Proxy -> prototype is Proxy.ProxyChild -> prototype - else -> null + else -> this } /** @@ -158,12 +157,11 @@ fun VisualGroup3D.proxy( templateName: Name, obj: VisualObject3D, name: String = "", - attachToParent: Boolean = false, block: Proxy.() -> Unit = {} ): Proxy { val existing = getPrototype(templateName) if (existing == null) { - setPrototype(templateName, obj, attachToParent) + setPrototype(templateName, obj) } else if (existing != obj) { error("Can't add different prototype on top of existing one") } diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt index bb76d972..4bacdd79 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt @@ -18,7 +18,6 @@ import hep.dataforge.names.asName import hep.dataforge.names.isEmpty import hep.dataforge.vis.common.AbstractVisualGroup import hep.dataforge.vis.common.StyleSheet -import hep.dataforge.vis.common.VisualGroup import hep.dataforge.vis.common.VisualObject import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -37,7 +36,8 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D { field = value } - override val styleSheet: StyleSheet = StyleSheet(this) + override var styleSheet: StyleSheet? = null + private set //FIXME to be lifted to AbstractVisualGroup after https://github.com/Kotlin/kotlinx.serialization/issues/378 is fixed override var properties: Config? = null @@ -55,6 +55,14 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D { attachChildren() } + /** + * Update or create stylesheet + */ + fun styleSheet(block: StyleSheet.() -> Unit) { + val res = this.styleSheet ?: StyleSheet(this).also { this.styleSheet = it } + res.block() + } + override fun removeChild(token: NameToken) { _children.remove(token) childrenChanged(token.asName(), null) @@ -90,18 +98,6 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D { } } - fun getPrototype(name: Name): VisualObject3D? = - prototypes?.get(name) as? VisualObject3D ?: (parent as? VisualGroup3D)?.getPrototype(name) - - fun setPrototype(name: Name, obj: VisualObject3D, attachToParent: Boolean = false) { - val parent = this.parent - if (attachToParent && parent is VisualGroup3D) { - parent.setPrototype(name, obj, attachToParent) - } else { - (prototypes ?: VisualGroup3D().also { this.prototypes = it }).set(name, obj) - } - } - override fun attachChildren() { super.attachChildren() prototypes?.run { @@ -115,5 +111,28 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D { } } +/** + * Ger a prototype redirecting the request to the parent if prototype is not found + */ +fun VisualGroup3D.getPrototype(name: Name): VisualObject3D? = + prototypes?.get(name) as? VisualObject3D ?: (parent as? VisualGroup3D)?.getPrototype(name) + +/** + * Defined a prototype inside current group + */ +fun VisualGroup3D.setPrototype(name: Name, obj: VisualObject3D) { + (prototypes ?: VisualGroup3D().also { this.prototypes = it })[name] = obj +} + +/** + * Define a group with given [key], attach it to this parent and return it. + */ fun VisualGroup3D.group(key: String = "", action: VisualGroup3D.() -> Unit = {}): VisualGroup3D = - VisualGroup3D().apply(action).also { set(key, it) } \ No newline at end of file + VisualGroup3D().apply(action).also { set(key, it) } + +/** + * Create or edit prototype node as a group + */ +inline fun VisualGroup3D.prototypes(builder: VisualGroup3D.() -> Unit): Unit { + (prototypes ?: VisualGroup3D().also { this.prototypes = it }).run(builder) +} \ No newline at end of file diff --git a/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/PropertyTest.kt b/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/PropertyTest.kt index dcece5bd..fa15b905 100644 --- a/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/PropertyTest.kt +++ b/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/PropertyTest.kt @@ -3,33 +3,34 @@ package hep.dataforge.vis.spatial import hep.dataforge.meta.int import hep.dataforge.meta.set import hep.dataforge.names.asName -import hep.dataforge.vis.common.updateStyle import hep.dataforge.vis.common.useStyle import kotlin.test.Test import kotlin.test.assertEquals class PropertyTest { @Test - fun testInheritedProperty(){ + fun testInheritedProperty() { var box: Box? = null val group = VisualGroup3D().apply { config["test"] = 22 group { - box = box(100,100,100) + box = box(100, 100, 100) } } assertEquals(22, box?.getProperty("test".asName()).int) } @Test - fun testStyleProperty(){ + fun testStyleProperty() { var box: Box? = null val group = VisualGroup3D().apply { - updateStyle("testStyle"){ - "test" put 22 + styleSheet { + set("testStyle") { + "test" put 22 + } } group { - box = box(100,100,100).apply { + box = box(100, 100, 100).apply { useStyle("testStyle") } } @@ -38,18 +39,41 @@ class PropertyTest { } @Test - fun testColor(){ + fun testColor() { var box: Box? = null val group = VisualGroup3D().apply { - updateStyle("testStyle"){ - Material3D.MATERIAL_COLOR_KEY put "#555555" + styleSheet { + set("testStyle") { + Material3D.MATERIAL_COLOR_KEY put "#555555" + } } group { - box = box(100,100,100){ + box = box(100, 100, 100) { useStyle("testStyle") } } } assertEquals("#555555", box?.color) } + + @Test + fun testProxyStyleProperty() { + var box: Proxy? = null + val group = VisualGroup3D().apply { + styleSheet { + set("testStyle") { + Material3D.MATERIAL_COLOR_KEY put "#555555" + } + } + prototypes { + box(100, 100, 100, name = "box") { + styles = listOf("testStyle") + } + } + group { + box = ref("box".asName()) + } + } + assertEquals("#555555", box?.color) + } } \ No newline at end of file diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/propertyEditor.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/propertyEditor.kt index 0aaaa1d9..db40d616 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/propertyEditor.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/propertyEditor.kt @@ -2,7 +2,10 @@ package hep.dataforge.vis.spatial.editor import hep.dataforge.io.toJson import hep.dataforge.js.jsObject -import hep.dataforge.meta.* +import hep.dataforge.meta.DynamicMeta +import hep.dataforge.meta.Meta +import hep.dataforge.meta.builder +import hep.dataforge.meta.update import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.common.findStyle import hep.dataforge.vis.spatial.* @@ -24,11 +27,7 @@ fun Element.propertyEditor(item: VisualObject?) { if (item != null) { append { card("Properties") { - val config: Meta = if (item is Proxy || item is Proxy.ProxyChild) { - item.prototype?.config ?: EmptyMeta - } else { - item.config - } + val config: Meta = item.prototype.config val metaToEdit = config.builder().apply { VISIBLE_KEY to (item.visible ?: true) if (item is VisualObject3D) { diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DPlugin.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DPlugin.kt index 7c44d47f..288174ea 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DPlugin.kt +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DPlugin.kt @@ -3,7 +3,6 @@ package hep.dataforge.vis.spatial.fx import hep.dataforge.context.* import hep.dataforge.meta.Meta import hep.dataforge.meta.boolean -import hep.dataforge.meta.get import hep.dataforge.provider.Type import hep.dataforge.vis.spatial.* import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_KEY @@ -20,6 +19,13 @@ import javafx.scene.transform.Rotate import org.fxyz3d.shapes.composites.PolyLine3D import org.fxyz3d.shapes.primitives.CuboidMesh import org.fxyz3d.shapes.primitives.SpheroidMesh +import kotlin.collections.HashMap +import kotlin.collections.component1 +import kotlin.collections.component2 +import kotlin.collections.find +import kotlin.collections.map +import kotlin.collections.mapNotNull +import kotlin.collections.set import kotlin.math.PI import kotlin.reflect.KClass @@ -106,11 +112,11 @@ class FX3DPlugin : AbstractPlugin() { when (obj.rotationOrder) { RotationOrder.ZYX -> transforms.addAll(rotateZ, rotateY, rotateX) - RotationOrder.XZY -> transforms.addAll(rotateY, rotateZ, rotateX) - RotationOrder.YXZ -> transforms.addAll(rotateZ, rotateX, rotateY) - RotationOrder.YZX -> transforms.addAll(rotateX, rotateZ, rotateY) - RotationOrder.ZXY -> transforms.addAll(rotateY, rotateX, rotateZ) - RotationOrder.XYZ -> transforms.addAll(rotateZ, rotateY, rotateX) + RotationOrder.XZY -> transforms.addAll(rotateX, rotateZ, rotateY) + RotationOrder.YXZ -> transforms.addAll(rotateY, rotateX, rotateZ) + RotationOrder.YZX -> transforms.addAll(rotateY, rotateZ, rotateX) + RotationOrder.ZXY -> transforms.addAll(rotateZ, rotateX, rotateY) + RotationOrder.XYZ -> transforms.addAll(rotateX, rotateY, rotateZ) } if (this is Shape3D) { diff --git a/spatial-demo/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt b/spatial-demo/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt index 3fbaff04..1808c43f 100644 --- a/spatial-demo/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt +++ b/spatial-demo/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt @@ -17,7 +17,7 @@ class FXDemoApp : App(FXDemoGrid::class) { stage.width = 400.0 stage.height = 400.0 - //view.showcase() + view.showcase() view.demo("gdml", "gdml") { gdml(Paths.get("D:\\Work\\Projects\\gdml.kt\\gdml-source\\cubes.gdml")) { lUnit = LUnit.CM From a564e078e596ef02187424a0022d361055ab185d Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 23 Dec 2019 21:38:28 +0300 Subject: [PATCH 14/25] Fix proxy display --- .../vis/spatial/gdml/GDMLTransformer.kt | 2 +- .../dataforge/vis/spatial/gdml/visualGDML.kt | 37 +++++++++++-------- .../kotlin/hep/dataforge/vis/spatial/Box.kt | 2 + .../kotlin/hep/dataforge/vis/spatial/Proxy.kt | 9 +++++ .../dataforge/vis/spatial/VisualGroup3D.kt | 1 + .../hep/dataforge/vis/spatial/geometry.kt | 7 +++- .../hep/dataforge/vis/spatial/three/three.kt | 1 + .../hep/dataforge/vis/spatial/geometryJVM.kt | 17 +++++++-- .../dataforge/vis/spatial/demo/FXDemoApp.kt | 2 +- 9 files changed, 55 insertions(+), 23 deletions(-) diff --git a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt index d59d1a3f..bb60b8b6 100644 --- a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt +++ b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt @@ -17,7 +17,7 @@ import kotlin.random.Random class GDMLTransformer(val root: GDML) { private val materialCache = HashMap() - private val random = Random(111) + private val random = Random(222) enum class Action { ACCEPT, diff --git a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDML.kt b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDML.kt index 9134989b..6c9f9baf 100644 --- a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDML.kt +++ b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDML.kt @@ -5,6 +5,8 @@ import hep.dataforge.names.asName import hep.dataforge.names.plus import hep.dataforge.vis.common.get import hep.dataforge.vis.spatial.* +import hep.dataforge.vis.spatial.GeometryConstants.one +import hep.dataforge.vis.spatial.GeometryConstants.zero import scientifik.gdml.* import kotlin.math.cos import kotlin.math.sin @@ -12,25 +14,28 @@ import kotlin.math.sin private fun VisualObject3D.withPosition( lUnit: LUnit, - pos: GDMLPosition? = null, - rotation: GDMLRotation? = null, - scale: GDMLScale? = null + newPos: GDMLPosition? = null, + newRotation: GDMLRotation? = null, + newScale: GDMLScale? = null ): VisualObject3D = apply { - pos?.let { - this@withPosition.x = pos.x(lUnit) - this@withPosition.y = pos.y(lUnit) - this@withPosition.z = pos.z(lUnit) + newPos?.let { + val point = Point3D(it.x(lUnit), it.y(lUnit), it.z(lUnit)) + if (position != null || point != zero) { + position = point + } } - rotation?.let { - this@withPosition.rotationX = rotation.x() - this@withPosition.rotationY = rotation.y() - this@withPosition.rotationZ = rotation.z() + newRotation?.let { + val point = Point3D(it.x(), it.y(), it.z()) + if (rotation != null || point != zero) { + rotation = point + } //this@withPosition.rotationOrder = RotationOrder.ZXY } - scale?.let { - this@withPosition.scaleX = scale.x.toFloat() - this@withPosition.scaleY = scale.y.toFloat() - this@withPosition.scaleZ = scale.z.toFloat() + newScale?.let { + val point = Point3D(it.x, it.y, it.z) + if (scale != null || point != one) { + scale = point + } } //TODO convert units if needed } @@ -251,6 +256,6 @@ fun GDML.toVisual(block: GDMLTransformer.() -> Unit = {}): VisualGroup3D { */ fun VisualGroup3D.gdml(gdml: GDML, key: String = "", transformer: GDMLTransformer.() -> Unit = {}) { val visual = gdml.toVisual(transformer) - println(Visual3DPlugin.json.stringify(VisualGroup3D.serializer(),visual)) + println(Visual3DPlugin.json.stringify(VisualGroup3D.serializer(), visual)) set(key, visual) } \ No newline at end of file diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Box.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Box.kt index 550430f3..fd6358a2 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Box.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Box.kt @@ -10,11 +10,13 @@ import hep.dataforge.meta.get import hep.dataforge.vis.common.AbstractVisualObject import hep.dataforge.vis.common.VisualFactory import hep.dataforge.vis.common.VisualObject +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.UseSerializers import kotlin.reflect.KClass @Serializable +@SerialName("3d.box") class Box( val xSize: Float, val ySize: Float, diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt index 95da3d1a..c74e2236 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt @@ -12,6 +12,7 @@ import hep.dataforge.names.NameToken import hep.dataforge.names.asName import hep.dataforge.names.plus import hep.dataforge.vis.common.* +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.Transient import kotlinx.serialization.UseSerializers @@ -23,6 +24,7 @@ import kotlin.collections.set * A proxy [VisualObject3D] to reuse a template object */ @Serializable +@SerialName("3d.proxy") class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, VisualObject3D { override var position: Point3D? = null @@ -90,6 +92,13 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua override val styleSheet: StyleSheet get() = this@Proxy.styleSheet + override var styles: List + get() = super.styles + prototype.styles + set(value) { + setProperty(VisualObject.STYLE_KEY, value) + updateStyles(value) + } + override val children: Map get() = (prototype as? VisualGroup)?.children?.mapValues { (key, _) -> ProxyChild( diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt index 4bacdd79..51e06062 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt @@ -25,6 +25,7 @@ import kotlinx.serialization.UseSerializers import kotlin.collections.set @Serializable +@SerialName("group.3d") class VisualGroup3D : AbstractVisualGroup(), VisualObject3D { /** * A container for templates visible inside this group diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/geometry.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/geometry.kt index e9fab6ab..cd739046 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/geometry.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/geometry.kt @@ -50,10 +50,13 @@ operator fun Point3D.component3() = z fun Meta.point3D() = Point3D(this["x"].number ?: 0, this["y"].number ?: 0, this["y"].number ?: 0) -val zero = Point3D(0, 0, 0) - fun Point3D.toMeta() = buildMeta { VisualObject3D.x put x VisualObject3D.y put y VisualObject3D.z put z +} + +object GeometryConstants{ + val zero = Point3D(0.0, 0.0, 0.0) + val one = Point3D(1.0, 1.0, 1.0) } \ No newline at end of file diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/three.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/three.kt index 34e67764..a203d1f5 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/three.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/three.kt @@ -5,6 +5,7 @@ import hep.dataforge.meta.float import hep.dataforge.meta.get import hep.dataforge.meta.node import hep.dataforge.vis.spatial.* +import hep.dataforge.vis.spatial.GeometryConstants.zero import info.laht.threekt.core.* import info.laht.threekt.external.controls.OrbitControls import info.laht.threekt.materials.Material diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/geometryJVM.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/geometryJVM.kt index affc7f8c..46707c0c 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/geometryJVM.kt +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/geometryJVM.kt @@ -1,8 +1,7 @@ package hep.dataforge.vis.spatial -actual class Point2D actual constructor(x: Number, y: Number) { - actual var x = x.toDouble() - actual var y = y.toDouble() +actual data class Point2D(actual var x: Double, actual var y: Double){ + actual constructor(x: Number, y: Number): this(x.toDouble(),y.toDouble()) } actual class Point3D(val point: org.fxyz3d.geometry.Point3D) { @@ -29,4 +28,16 @@ actual class Point3D(val point: org.fxyz3d.geometry.Point3D) { inline set(value) { point.z = value.toFloat() } + + override fun equals(other: Any?): Boolean { + return this.point == (other as? hep.dataforge.vis.spatial.Point3D)?.point + } + + override fun hashCode(): Int { + return point.hashCode() + } + + override fun toString(): String { + return point.toString() + } } \ No newline at end of file diff --git a/spatial-demo/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt b/spatial-demo/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt index 1808c43f..3fbaff04 100644 --- a/spatial-demo/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt +++ b/spatial-demo/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt @@ -17,7 +17,7 @@ class FXDemoApp : App(FXDemoGrid::class) { stage.width = 400.0 stage.height = 400.0 - view.showcase() + //view.showcase() view.demo("gdml", "gdml") { gdml(Paths.get("D:\\Work\\Projects\\gdml.kt\\gdml-source\\cubes.gdml")) { lUnit = LUnit.CM From 8d39a3efa5bcecfd8e57f89f998057e3c6746f6c Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 24 Dec 2019 14:14:10 +0300 Subject: [PATCH 15/25] Demo structure change and fx update --- dataforge-vis-common/build.gradle.kts | 1 + .../hep/dataforge/vis/common/StyleSheet.kt | 13 +- .../jsMain/kotlin/hep/dataforge/js/jsExtra.kt | 3 +- .../hep/dataforge/vis/js}/editor/bootstrap.kt | 2 +- .../hep/dataforge/vis/js}/editor/jsTree.kt | 2 +- .../hep/dataforge/vis/js/editor/jsoneditor.kt | 185 ++++++++++++++++++ .../vis/js}/editor/propertyEditor.kt | 31 ++- .../{values => editor}/ColorValueChooser.kt | 5 +- .../ComboBoxValueChooser.kt | 5 +- .../vis/fx/{meta => editor}/ConfigEditor.kt | 6 +- .../vis/fx/{meta => editor}/FXMeta.kt | 2 +- .../vis/fx/{meta => editor}/MetaViewer.kt | 2 +- .../fx/{values => editor}/TextValueChooser.kt | 5 +- .../fx/{values => editor}/ValueCallback.kt | 2 +- .../vis/fx/{values => editor}/ValueChooser.kt | 16 +- .../fx/{values => editor}/ValueChooserBase.kt | 2 +- .../fx/editor/VisualObjectEditorFragment.kt | 59 ++++++ .../vis/fx/editor/VisualObjectTreeFragment.kt | 33 ++++ .../dataforge/vis/fx/demo/MetaEditorDemo.kt | 6 +- .../vis/spatial/gdml/GDMLTransformer.kt | 8 +- .../dataforge/vis/spatial/gdml/visualGDML.kt | 2 +- .../src/jsMain/web/css/jsoneditor.min.css | 6 - .../vis/spatial/gdml/visualGDMLJvm.kt | 11 +- dataforge-vis-spatial/build.gradle.kts | 2 +- .../spatial/{editor => three}/outputConfig.kt | 4 +- .../dataforge/vis/spatial/fx/FXCanvas3D.kt | 23 ++- demo/build.gradle.kts | 0 demo/gdml/build.gradle.kts | 39 ++++ .../vis/spatial/gdml/demo/GDMLDemoApp.kt | 25 ++- .../src/jsMain/web/css/jsoneditor.min.css | 6 + .../gdml}/src/jsMain/web/css/main.css | 0 .../src/jsMain/web}/img/jsoneditor-icons.svg | 0 .../gdml}/src/jsMain/web/index.html | 0 .../vis/spatial/gdml/demo/GDMLDemoApp.kt | 78 ++++++++ .../spatial-showcase}/build.gradle.kts | 0 .../hep/dataforge/vis/spatial/demo/demo.kt | 0 .../vis/spatial/demo/ThreeDemoApp.kt | 3 - .../vis/spatial/demo/ThreeDemoGrid.kt | 0 .../dataforge/vis/spatial/demo/VariableBox.kt | 0 .../src/jsMain/web/index.html | 0 .../dataforge/vis/spatial/demo/FXDemoApp.kt | 0 .../dataforge/vis/spatial/demo/FXDemoGrid.kt | 3 - settings.gradle.kts | 5 +- 43 files changed, 514 insertions(+), 81 deletions(-) rename {dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial => dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/js}/editor/bootstrap.kt (89%) rename {dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial => dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/js}/editor/jsTree.kt (98%) create mode 100644 dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/js/editor/jsoneditor.kt rename {dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial => dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/js}/editor/propertyEditor.kt (59%) rename dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/{values => editor}/ColorValueChooser.kt (91%) rename dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/{values => editor}/ComboBoxValueChooser.kt (92%) rename dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/{meta => editor}/ConfigEditor.kt (97%) rename dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/{meta => editor}/FXMeta.kt (99%) rename dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/{meta => editor}/MetaViewer.kt (98%) rename dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/{values => editor}/TextValueChooser.kt (96%) rename dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/{values => editor}/ValueCallback.kt (94%) rename dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/{values => editor}/ValueChooser.kt (89%) rename dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/{values => editor}/ValueChooserBase.kt (98%) create mode 100644 dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/editor/VisualObjectEditorFragment.kt create mode 100644 dataforge-vis-common/src/jvmMain/kotlin/hep/dataforge/vis/fx/editor/VisualObjectTreeFragment.kt rename dataforge-vis-common/src/{jvmMain => jvmTest}/kotlin/hep/dataforge/vis/fx/demo/MetaEditorDemo.kt (90%) delete mode 100644 dataforge-vis-spatial-gdml/src/jsMain/web/css/jsoneditor.min.css rename dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/{editor => three}/outputConfig.kt (92%) create mode 100644 demo/build.gradle.kts create mode 100644 demo/gdml/build.gradle.kts rename {dataforge-vis-spatial-gdml => demo/gdml}/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt (86%) create mode 100644 demo/gdml/src/jsMain/web/css/jsoneditor.min.css rename {dataforge-vis-spatial-gdml => demo/gdml}/src/jsMain/web/css/main.css (100%) rename {dataforge-vis-spatial-gdml/src/jsMain/web/css => demo/gdml/src/jsMain/web}/img/jsoneditor-icons.svg (100%) rename {dataforge-vis-spatial-gdml => demo/gdml}/src/jsMain/web/index.html (100%) create mode 100644 demo/gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt rename {spatial-demo => demo/spatial-showcase}/build.gradle.kts (100%) rename {spatial-demo => demo/spatial-showcase}/src/commonMain/kotlin/hep/dataforge/vis/spatial/demo/demo.kt (100%) rename {spatial-demo => demo/spatial-showcase}/src/jsMain/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt (93%) rename {spatial-demo => demo/spatial-showcase}/src/jsMain/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoGrid.kt (100%) rename {spatial-demo => demo/spatial-showcase}/src/jsMain/kotlin/hep/dataforge/vis/spatial/demo/VariableBox.kt (100%) rename {spatial-demo => demo/spatial-showcase}/src/jsMain/web/index.html (100%) rename {spatial-demo => demo/spatial-showcase}/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt (100%) rename {spatial-demo => demo/spatial-showcase}/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoGrid.kt (92%) diff --git a/dataforge-vis-common/build.gradle.kts b/dataforge-vis-common/build.gradle.kts index 767364de..87b03571 100644 --- a/dataforge-vis-common/build.gradle.kts +++ b/dataforge-vis-common/build.gradle.kts @@ -29,6 +29,7 @@ kotlin { dependencies { api("hep.dataforge:dataforge-output-html:$dataforgeVersion") api(npm("bootstrap","4.4.1")) + implementation(npm("jsoneditor")) } } } diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/StyleSheet.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/StyleSheet.kt index 2fcc1bed..fce0b422 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/StyleSheet.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/StyleSheet.kt @@ -27,18 +27,21 @@ class StyleSheet() { return styleMap[key] ?: (owner?.parent as? VisualGroup)?.styleSheet?.get(key) } - operator fun set(key: String, style: Meta?) { - val oldStyle = styleMap[key] + /** + * Define a style without notifying + */ + fun define(key: String, style: Meta?) { if (style == null) { styleMap.remove(key) } else { styleMap[key] = style } - owner?.styleChanged(key, oldStyle, style) } - infix fun String.put(style: Meta?) { - set(this, style) + operator fun set(key: String, style: Meta?) { + val oldStyle = styleMap[key] + define(key, style) + owner?.styleChanged(key, oldStyle, style) } operator fun set(key: String, builder: MetaBuilder.() -> Unit) { diff --git a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/js/jsExtra.kt b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/js/jsExtra.kt index ad94873d..6354a61c 100644 --- a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/js/jsExtra.kt +++ b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/js/jsExtra.kt @@ -1,6 +1,7 @@ package hep.dataforge.js -external fun require(name: String): dynamic +@JsName("require") +external fun requireJS(name: String): dynamic inline fun jsObject(builder: T.() -> Unit): T { val obj: T = js("({})") as T diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/bootstrap.kt b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/js/editor/bootstrap.kt similarity index 89% rename from dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/bootstrap.kt rename to dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/js/editor/bootstrap.kt index 7be121b1..2f1e4595 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/bootstrap.kt +++ b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/js/editor/bootstrap.kt @@ -1,4 +1,4 @@ -package hep.dataforge.vis.spatial.editor +package hep.dataforge.vis.js.editor import kotlinx.html.TagConsumer import kotlinx.html.js.div diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/jsTree.kt b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/js/editor/jsTree.kt similarity index 98% rename from dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/jsTree.kt rename to dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/js/editor/jsTree.kt index a45c1861..ba9b7dd8 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/jsTree.kt +++ b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/js/editor/jsTree.kt @@ -4,7 +4,7 @@ import hep.dataforge.names.NameToken import hep.dataforge.vis.common.VisualGroup import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.common.isEmpty -import hep.dataforge.vis.spatial.editor.card +import hep.dataforge.vis.js.editor.card import kotlinx.html.TagConsumer import kotlinx.html.dom.append import kotlinx.html.js.* diff --git a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/js/editor/jsoneditor.kt b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/js/editor/jsoneditor.kt new file mode 100644 index 00000000..8bfaf93a --- /dev/null +++ b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/js/editor/jsoneditor.kt @@ -0,0 +1,185 @@ +@file:Suppress( + "INTERFACE_WITH_SUPERCLASS", + "OVERRIDING_FINAL_MEMBER", + "RETURN_TYPE_MISMATCH_ON_OVERRIDE", + "CONFLICTING_OVERLOADS", + "EXTERNAL_DELEGATION" +) + +package hep.dataforge.vis.js.editor + +import org.w3c.dom.HTMLElement + +external interface Node { + var field: String + var value: String? get() = definedExternally; set(value) = definedExternally + var path: dynamic +} + +external interface NodeName { + var path: Array + var type: dynamic /* 'object' | 'array' */ + var size: Number +} + +external interface ValidationError { + var path: dynamic + var message: String +} + +external interface Template { + var text: String + var title: String + var className: String? get() = definedExternally; set(value) = definedExternally + var field: String + var value: Any +} + +external interface `T$6` { + var startFrom: Number + var options: Array +} + +external interface AutoCompleteOptions { + var confirmKeys: Array? get() = definedExternally; set(value) = definedExternally + var caseSensitive: Boolean? get() = definedExternally; set(value) = definedExternally +// var getOptions: AutoCompleteOptionsGetter? get() = definedExternally; set(value) = definedExternally +} + +external interface SelectionPosition { + var row: Number + var column: Number +} + +external interface SerializableNode { + var value: Any + var path: dynamic +} + +external interface Color { + var rgba: Array + var hsla: Array + var rgbString: String + var rgbaString: String + var hslString: String + var hslaString: String + var hex: String +} + +//external interface `T$0` { +// var field: Boolean +// var value: Boolean +//} +// +//external interface `T$1` { +// @nativeGetter +// operator fun get(key: String): String? +// +// @nativeSetter +// operator fun set(key: String, value: String) +//} + +//external interface Languages { +// @nativeGetter +// operator fun get(lang: String): `T$1`? +// +// @nativeSetter +// operator fun set(lang: String, value: `T$1`) +//} + +external interface JSONEditorOptions { +// var ace: AceAjax.Ace? get() = definedExternally; set(value) = definedExternally +// var ajv: Ajv? get() = definedExternally; set(value) = definedExternally + var onChange: (() -> Unit)? get() = definedExternally; set(value) = definedExternally + var onChangeJSON: ((json: Any) -> Unit)? get() = definedExternally; set(value) = definedExternally + var onChangeText: ((jsonString: String) -> Unit)? get() = definedExternally; set(value) = definedExternally + var onEditable: ((node: Node) -> dynamic)? get() = definedExternally; set(value) = definedExternally + var onError: ((error: Error) -> Unit)? get() = definedExternally; set(value) = definedExternally + var onModeChange: ((newMode: dynamic /* 'tree' | 'view' | 'form' | 'code' | 'text' */, oldMode: dynamic /* 'tree' | 'view' | 'form' | 'code' | 'text' */) -> Unit)? get() = definedExternally; set(value) = definedExternally + var onNodeName: ((nodeName: NodeName) -> String?)? get() = definedExternally; set(value) = definedExternally + var onValidate: ((json: Any) -> dynamic)? get() = definedExternally; set(value) = definedExternally + var escapeUnicode: Boolean? get() = definedExternally; set(value) = definedExternally + var sortObjectKeys: Boolean? get() = definedExternally; set(value) = definedExternally + var history: Boolean? get() = definedExternally; set(value) = definedExternally + var mode: dynamic /* 'tree' | 'view' | 'form' | 'code' | 'text' */ + var modes: Array? get() = definedExternally; set(value) = definedExternally + var name: String? get() = definedExternally; set(value) = definedExternally + var schema: Any? get() = definedExternally; set(value) = definedExternally + var schemaRefs: Any? get() = definedExternally; set(value) = definedExternally + var search: Boolean? get() = definedExternally; set(value) = definedExternally + var indentation: Number? get() = definedExternally; set(value) = definedExternally + var theme: String? get() = definedExternally; set(value) = definedExternally + var templates: Array