diff --git a/build.gradle.kts b/build.gradle.kts index a19fe8ff..30aa28a9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,6 +1,6 @@ import scientifik.useSerialization -val dataforgeVersion by extra("0.1.5-dev-5") +val dataforgeVersion by extra("0.1.5-dev-6") plugins { val kotlinVersion = "1.3.61" diff --git a/dataforge-vis-common/build.gradle.kts b/dataforge-vis-common/build.gradle.kts index 4ac0092e..02471a02 100644 --- a/dataforge-vis-common/build.gradle.kts +++ b/dataforge-vis-common/build.gradle.kts @@ -35,6 +35,7 @@ kotlin { api("hep.dataforge:dataforge-output-html:$dataforgeVersion") api(npm("bootstrap","4.4.1")) implementation(npm("jsoneditor")) + implementation(npm("file-saver")) } } } diff --git a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/js/editor/jsTree.kt b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/js/editor/jsTree.kt index ba9b7dd8..f45727b9 100644 --- a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/js/editor/jsTree.kt +++ b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/js/editor/jsTree.kt @@ -1,10 +1,9 @@ -package hep.dataforge.js +package hep.dataforge.vis.js.editor 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.js.editor.card import kotlinx.html.TagConsumer import kotlinx.html.dom.append import kotlinx.html.js.* 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 c90760e0..f645c3c8 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,13 +5,9 @@ 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.VisualObject import hep.dataforge.vis.common.useStyle +import hep.dataforge.vis.spatial.* 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 -import hep.dataforge.vis.spatial.rotationOrder import scientifik.gdml.* import kotlin.random.Random @@ -37,7 +33,14 @@ class GDMLTransformer(val root: GDML) { var volumeAction: (GDMLGroup) -> Action = { Action.CACHE } - var solidConfiguration: VisualObject3D.(parent: GDMLVolume, solid: GDMLSolid) -> Unit = { _, _ -> } + var solidConfiguration: VisualObject3D.(parent: GDMLVolume, solid: GDMLSolid) -> Unit = { parent, solid -> + lUnit = LUnit.CM + if (parent.physVolumes.isNotEmpty()) { + useStyle("opaque") { + Material3D.MATERIAL_OPACITY_KEY put 0.3 + } + } + } fun VisualObject3D.useStyle(name: String, builder: MetaBuilder.() -> Unit) { styleCache.getOrPut(name.toName()) { 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 95c316bf..8fc395e1 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 @@ -6,8 +6,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 hep.dataforge.vis.spatial.World.ONE +import hep.dataforge.vis.spatial.World.ZERO import scientifik.gdml.* import kotlin.math.cos import kotlin.math.sin @@ -21,20 +21,20 @@ private fun VisualObject3D.withPosition( ): VisualObject3D = apply { newPos?.let { val point = Point3D(it.x(lUnit), it.y(lUnit), it.z(lUnit)) - if (position != null || point != zero) { + if (position != null || point != ZERO) { position = point } } newRotation?.let { val point = Point3D(it.x(), it.y(), it.z()) - if (rotation != null || point != zero) { + if (rotation != null || point != ZERO) { rotation = point } //this@withPosition.rotationOrder = RotationOrder.ZXY } newScale?.let { val point = Point3D(it.x, it.y, it.z) - if (scale != null || point != one) { + if (scale != null || point != ONE) { scale = point } } 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 39c62bc2..b09e2ea2 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 @@ -38,7 +38,7 @@ class Visual3DPlugin(meta: Meta) : AbstractPlugin(meta) { contextual(Point2DSerializer) contextual(NameSerializer) contextual(NameTokenSerializer) - contextual(Meta::class, MetaSerializer) + contextual(MetaSerializer) contextual(ConfigSerializer) polymorphic(VisualObject::class, VisualObject3D::class) { @@ -48,7 +48,8 @@ class Visual3DPlugin(meta: Meta) : AbstractPlugin(meta) { Tube::class with Tube.serializer() Box::class with Box.serializer() Convex::class with Convex.serializer() - addSubclass(Extruded.serializer()) + Extruded::class with Extruded.serializer() + addSubclass(Label3D.serializer()) } } diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/World.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/World.kt index 0743357d..bc946987 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/World.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/World.kt @@ -3,12 +3,8 @@ package hep.dataforge.vis.spatial import kotlin.math.PI object World { - const val CAMERA_INITIAL_DISTANCE = -500.0 - const val CAMERA_INITIAL_X_ANGLE = -50.0 - const val CAMERA_INITIAL_Y_ANGLE = 0.0 - const val CAMERA_INITIAL_Z_ANGLE = -210.0 - const val CAMERA_NEAR_CLIP = 0.1 - const val CAMERA_FAR_CLIP = 10000.0 + val ZERO = Point3D(0.0, 0.0, 0.0) + val ONE = Point3D(1.0, 1.0, 1.0) } const val PI2: Float = 2 * PI.toFloat() \ 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 e3cbcc3d..75336e60 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 @@ -38,9 +38,4 @@ 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/commonMain/kotlin/hep/dataforge/vis/spatial/specifications/AxesSpec.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/specifications/AxesSpec.kt new file mode 100644 index 00000000..b46b9f4d --- /dev/null +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/specifications/AxesSpec.kt @@ -0,0 +1,17 @@ +package hep.dataforge.vis.spatial.specifications + +import hep.dataforge.meta.* + +class AxesSpec(override val config: Config) : Specific { + var visible by boolean(!config.isEmpty()) + var size by double(AXIS_SIZE) + var width by double(AXIS_WIDTH) + + companion object : Specification { + override fun wrap(config: Config): AxesSpec = AxesSpec(config) + + const val AXIS_SIZE = 1000.0 + const val AXIS_WIDTH = 3.0 + + } +} \ No newline at end of file diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/specifications/CameraSpec.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/specifications/CameraSpec.kt new file mode 100644 index 00000000..eb23472f --- /dev/null +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/specifications/CameraSpec.kt @@ -0,0 +1,26 @@ +package hep.dataforge.vis.spatial.specifications + +import hep.dataforge.meta.* +import kotlin.math.PI + +class CameraSpec(override val config: Config) : Specific { + var fov by int(FIELD_OF_VIEW) + //var aspect by double(1.0) + var nearClip by double(NEAR_CLIP) + var farClip by double(FAR_CLIP) + + var distance by double(INITIAL_DISTANCE) + var azimuth by double(INITIAL_AZIMUTH) + var latitude by double(INITIAL_LATITUDE) + val zenith: Double get() = PI / 2 - latitude + + companion object : Specification { + override fun wrap(config: Config): CameraSpec = CameraSpec(config) + const val INITIAL_DISTANCE = 300.0 + const val INITIAL_AZIMUTH = 0.0 + const val INITIAL_LATITUDE = PI/6 + const val NEAR_CLIP = 0.1 + const val FAR_CLIP = 10000.0 + const val FIELD_OF_VIEW = 75 + } +} \ No newline at end of file diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/specifications/CanvasSpec.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/specifications/CanvasSpec.kt new file mode 100644 index 00000000..d9cbded6 --- /dev/null +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/specifications/CanvasSpec.kt @@ -0,0 +1,15 @@ +package hep.dataforge.vis.spatial.specifications + +import hep.dataforge.meta.* + +class CanvasSpec(override val config: Config) : Specific { + var axes by spec(AxesSpec) + var camera by spec(CameraSpec) + var controls by spec(ControlsSpec) + var minSize by int(300) + + companion object: Specification{ + override fun wrap(config: Config): CanvasSpec = CanvasSpec(config) + + } +} \ No newline at end of file diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/specifications/ControlsSpec.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/specifications/ControlsSpec.kt new file mode 100644 index 00000000..2a828766 --- /dev/null +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/specifications/ControlsSpec.kt @@ -0,0 +1,11 @@ +package hep.dataforge.vis.spatial.specifications + +import hep.dataforge.meta.Config +import hep.dataforge.meta.Specific +import hep.dataforge.meta.Specification + +class ControlsSpec(override val config: Config) : Specific { + companion object : Specification { + override fun wrap(config: Config): ControlsSpec = ControlsSpec(config) + } +} \ 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 7426658c..70db5c75 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 @@ -15,8 +15,8 @@ internal fun mergeChild(parent: VisualGroup, child: VisualObject): VisualObject //parent.properties?.let { config.update(it) } if (this is VisualObject3D && parent is VisualObject3D) { - position = (position ?: GeometryConstants.zero) + (parent.position ?: GeometryConstants.zero) - rotation = (parent.rotation ?: GeometryConstants.zero) + (parent.rotation ?: GeometryConstants.zero) + position = (position ?: World.ZERO) + (parent.position ?: World.ZERO) + rotation = (parent.rotation ?: World.ZERO) + (parent.rotation ?: World.ZERO) scale = when { scale == null && parent.scale == null -> null scale == null -> parent.scale diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeCanvas.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeCanvas.kt index 9d3f418e..bc15df9c 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeCanvas.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeCanvas.kt @@ -1,59 +1,61 @@ package hep.dataforge.vis.spatial.three import hep.dataforge.context.Context -import hep.dataforge.meta.* +import hep.dataforge.meta.Meta +import hep.dataforge.meta.get +import hep.dataforge.meta.string import hep.dataforge.output.Renderer import hep.dataforge.vis.common.Colors +import hep.dataforge.vis.spatial.Point3D import hep.dataforge.vis.spatial.VisualObject3D -import hep.dataforge.vis.spatial.World +import hep.dataforge.vis.spatial.specifications.AxesSpec +import hep.dataforge.vis.spatial.specifications.CameraSpec +import hep.dataforge.vis.spatial.specifications.CanvasSpec +import hep.dataforge.vis.spatial.specifications.ControlsSpec 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.cos import kotlin.math.max +import kotlin.math.sin -class ThreeCanvas(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Renderer { +class ThreeCanvas(val three: ThreePlugin, val spec: CanvasSpec) : Renderer { override val context: Context get() = three.context - var data: VisualObject3D? = null + var content: VisualObject3D? = null private set - val axes = AxesHelper(meta["axes.size"].int ?: 50).apply { visible = false } + val axes = AxesHelper(spec.axes.size.toInt()).apply { + visible = spec.axes.visible + } val scene: Scene = Scene().apply { - add(AmbientLight()) - if (meta["axes.visible"].boolean == true) { - axes.visible = true - } add(axes) } - private 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 + val camera = buildCamera(spec.camera) + + private fun buildCamera(spec: CameraSpec) = PerspectiveCamera( + spec.fov, + 1.0, + spec.nearClip, + spec.farClip ).apply { - position.setZ(World.CAMERA_INITIAL_DISTANCE) - rotation.set( - World.CAMERA_INITIAL_X_ANGLE, - World.CAMERA_INITIAL_Y_ANGLE, - World.CAMERA_INITIAL_Z_ANGLE - ) + translateX(spec.distance* sin(spec.zenith) * sin(spec.azimuth)) + translateY(spec.distance* cos(spec.zenith)) + translateZ(spec.distance * sin(spec.zenith) * cos(spec.azimuth)) } - val camera = buildCamera(meta["camera"].node ?: EmptyMeta) - - private fun addControls(element: Node, meta: Meta) { - when (meta["type"].string) { + private fun addControls(element: Node, controlsSpec: ControlsSpec) { + when (controlsSpec["type"].string) { "trackball" -> TrackballControls(camera, element) else -> OrbitControls(camera, element) } @@ -69,7 +71,7 @@ class ThreeCanvas(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Renderer } - addControls(renderer.domElement, meta["controls"].node ?: EmptyMeta) + addControls(renderer.domElement, spec.controls ?: ControlsSpec.empty()) fun animate() { window.requestAnimationFrame { @@ -80,9 +82,7 @@ class ThreeCanvas(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Renderer element.appendChild(renderer.domElement) - val minSize by meta.number(0).int - - renderer.setSize(max(minSize, element.offsetWidth), max(minSize, element.offsetWidth)) + renderer.setSize(max(spec.minSize, element.offsetWidth), max(spec.minSize, element.offsetWidth)) element.onresize = { renderer.setSize(element.offsetWidth, element.offsetWidth) @@ -93,13 +93,13 @@ class ThreeCanvas(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Renderer } override fun render(obj: VisualObject3D, meta: Meta) { - data = obj + content = obj scene.add(three.buildObject3D(obj)) } } -fun ThreePlugin.output(element: HTMLElement? = null, meta: Meta = EmptyMeta, override: MetaBuilder.() -> Unit = {}) = - ThreeCanvas(this, buildMeta(meta, override)).apply { +fun ThreePlugin.output(element: HTMLElement? = null, spec: CanvasSpec = CanvasSpec.empty()): ThreeCanvas = + ThreeCanvas(this, spec).apply { if (element != null) { attach(element) } 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/ThreeLabelFactory.kt similarity index 61% rename from dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeTextFactory.kt rename to dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeLabelFactory.kt index 8ab3e8bc..b7d292c7 100644 --- 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/ThreeLabelFactory.kt @@ -1,29 +1,35 @@ package hep.dataforge.vis.spatial.three import hep.dataforge.vis.spatial.Label3D +import hep.dataforge.vis.spatial.color import info.laht.threekt.DoubleSide import info.laht.threekt.core.Object3D -import info.laht.threekt.geometries.PlaneGeometry +import info.laht.threekt.geometries.PlaneBufferGeometry 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 org.w3c.dom.* import kotlin.browser.document +import kotlin.math.PI import kotlin.reflect.KClass /** * Using example from http://stemkoski.github.io/Three.js/Texture-From-Canvas.html */ -object ThreeTextFactory : ThreeFactory { +object ThreeLabelFactory : 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) + context.font = "Bold ${obj.fontSize}pt ${obj.fontFamily}" + context.fillStyle = obj.color ?: "black" + context.textAlign = CanvasTextAlign.CENTER + //context.textBaseline = CanvasTextBaseline.MIDDLE + val metrics = context.measureText(obj.text) + + context.fillText(obj.text, 0.5*metrics.width, 0.5*metrics.width) + // canvas contents will be used for a texture val texture = Texture(canvas) @@ -32,14 +38,16 @@ object ThreeTextFactory : ThreeFactory { val material = MeshBasicMaterial().apply { map = texture side = DoubleSide + transparent = true } - material.transparent = true; val mesh = Mesh( - PlaneGeometry(canvas.clientWidth, canvas.clientHeight), + PlaneBufferGeometry(canvas.width, canvas.height), material ) + //mesh.rotateX(PI) + mesh.updatePosition(obj) return mesh 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 b1356d3b..15a19515 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,7 +27,7 @@ class ThreePlugin : AbstractPlugin() { objectFactories[Sphere::class] = ThreeSphereFactory objectFactories[ConeSegment::class] = ThreeCylinderFactory objectFactories[PolyLine::class] = ThreeLineFactory - objectFactories[Label3D::class] = ThreeTextFactory + objectFactories[Label3D::class] = ThreeLabelFactory } @Suppress("UNCHECKED_CAST") diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/outputConfig.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/outputConfig.kt index f2177fda..1c582ee2 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/outputConfig.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/outputConfig.kt @@ -1,51 +1,67 @@ package hep.dataforge.vis.spatial.three +import hep.dataforge.js.requireJS import hep.dataforge.vis.js.editor.card +import hep.dataforge.vis.spatial.Visual3DPlugin +import hep.dataforge.vis.spatial.VisualGroup3D import kotlinx.html.InputType +import kotlinx.html.TagConsumer import kotlinx.html.button import kotlinx.html.dom.append import kotlinx.html.js.* import org.w3c.dom.Element +import org.w3c.dom.HTMLElement +import org.w3c.dom.events.Event +import org.w3c.files.Blob +import org.w3c.files.BlobPropertyBag import kotlin.dom.clear -//private fun download(filename: String, text: String) { -// var element = document.createElement("a"); -// element.setAttribute("href", "data:text/json;charset=utf-8," + encodeURIComponent(text)); -// element.setAttribute("download", filename); -// -// element.style.display = 'none'; -// document.body.appendChild(element); -// -// element.click(); -// -// document.body.removeChild(element); -//} +private fun saveData(event: Event, fileName: String, mimeType: String = "text/plain", dataBuilder: () -> String) { + event.stopPropagation(); + event.preventDefault(); -fun Element.threeOutputConfig(canvas: ThreeCanvas) { + val fileSaver = requireJS("file-saver") + val blob = Blob(arrayOf(dataBuilder()), BlobPropertyBag("$mimeType;charset=utf-8")) + fileSaver.saveAs(blob, fileName) +} + +fun Element.threeSettings(canvas: ThreeCanvas, block: TagConsumer.() -> Unit = {}) { clear() append { - card("Settings"){ - div("row"){ - div("col-1") { - label { +"Axes" } - input(type = InputType.checkBox).apply { - checked = canvas.axes.visible - onChangeFunction = { - canvas.axes.visible = checked + card("Settings") { + div("row") { + div("col-2") { + label("checkbox-inline") { + input(type = InputType.checkBox).apply { + checked = canvas.axes.visible + onChangeFunction = { + canvas.axes.visible = checked + } } + +"Axes" } } div("col-1") { button { +"Export" onClickFunction = { - + val json = (canvas.content as? VisualGroup3D)?.let { group -> + Visual3DPlugin.json.stringify( + VisualGroup3D.serializer(), + group + ) + } + if (json != null) { + saveData(it, "object.json", "text/json"){ + json + } + } } } } } } - card("Layers"){ + card("Layers") { div("row") { (0..11).forEach { layer -> div("col-1") { @@ -66,5 +82,6 @@ fun Element.threeOutputConfig(canvas: ThreeCanvas) { } } } + block() } } \ 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 a203d1f5..318989ca 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,7 +5,6 @@ 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 @@ -13,6 +12,7 @@ import info.laht.threekt.math.Euler import info.laht.threekt.math.Vector3 import info.laht.threekt.objects.Mesh import info.laht.threekt.textures.Texture +import kotlin.math.PI /** * Utility methods for three.kt. @@ -30,6 +30,8 @@ val MetaItem<*>.vector get() = Vector3(node["x"].float ?: 0f, node["y"].float ?: fun Geometry.toBufferGeometry(): BufferGeometry = BufferGeometry().apply { fromGeometry(this@toBufferGeometry) } +internal fun Double.toRadians() = this * PI / 180 + fun CSG.toGeometry(): Geometry { val geom = Geometry() @@ -45,7 +47,7 @@ fun CSG.toGeometry(): Geometry { } for (j in 3..polygon.vertices.size) { - val fc = Face3(v0, v0 + j - 2, v0 + j - 1, zero) + val fc = Face3(v0, v0 + j - 2, v0 + j - 1, World.ZERO) fc.vertexNormals = arrayOf( Vector3().copy(pvs[0].normal), Vector3().copy(pvs[j - 2].normal), 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 184c31aa..15718d3c 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 @@ -2,29 +2,20 @@ package hep.dataforge.vis.spatial.fx import hep.dataforge.context.Context import hep.dataforge.context.ContextAware -import hep.dataforge.meta.* +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 -import hep.dataforge.vis.spatial.World.CAMERA_INITIAL_Y_ANGLE -import hep.dataforge.vis.spatial.World.CAMERA_NEAR_CLIP +import hep.dataforge.vis.spatial.specifications.CanvasSpec import javafx.application.Platform import javafx.beans.property.ObjectProperty import javafx.beans.property.SimpleObjectProperty -import javafx.event.EventHandler import javafx.scene.* -import javafx.scene.input.KeyCode -import javafx.scene.input.KeyEvent -import javafx.scene.input.MouseEvent -import javafx.scene.input.ScrollEvent +import javafx.scene.layout.BorderPane import javafx.scene.paint.Color import org.fxyz3d.scene.Axes -import org.fxyz3d.utils.CameraTransformer import tornadofx.* -class FXCanvas3D(val plugin: FX3DPlugin, meta: Meta = EmptyMeta) : +class FXCanvas3D(val plugin: FX3DPlugin, val spec: CanvasSpec) : Fragment(), Renderer, ContextAware { override val context: Context get() = plugin.context @@ -32,41 +23,23 @@ class FXCanvas3D(val plugin: FX3DPlugin, meta: Meta = EmptyMeta) : val world = Group() val axes = Axes().also { - 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) + it.setHeight(spec.axes.size) + it.setRadius(spec.axes.width) + it.isVisible = spec.axes.visible world.add(it) } val light = AmbientLight() private val camera = PerspectiveCamera().apply { - nearClip = CAMERA_NEAR_CLIP - farClip = CAMERA_FAR_CLIP - translateZ = CAMERA_INITIAL_DISTANCE + nearClip = spec.camera.nearClip + farClip = spec.camera.farClip + fieldOfView = spec.camera.fov.toDouble() this.add(light) } - val cameraTransform = CameraTransformer().also { - it.add(camera) - } - - val translationXProperty get() = cameraTransform.t.xProperty() - var translateX by translationXProperty - val translationYProperty get() = cameraTransform.t.yProperty() - var translateY by translationYProperty - val translationZProperty get() = cameraTransform.t.zProperty() - var translateZ by translationZProperty - - val rotationXProperty get() = cameraTransform.rx.angleProperty() - var angleX by rotationXProperty - val rotationYProperty get() = cameraTransform.ry.angleProperty() - var angleY by rotationYProperty - val rotationZProperty get() = cameraTransform.rz.angleProperty() - var angleZ by rotationZProperty - private val canvas = SubScene( - Group(world, cameraTransform).apply { DepthTest.ENABLE }, + Group(world, camera).apply { DepthTest.ENABLE }, 400.0, 400.0, true, @@ -74,15 +47,16 @@ class FXCanvas3D(val plugin: FX3DPlugin, meta: Meta = EmptyMeta) : ).also { scene -> scene.fill = Color.GREY scene.camera = camera - //id = "canvas" - handleKeyboard(scene) - handleMouse(scene) } override val root = borderpane { center = canvas } + val controls = camera.orbitControls(canvas, spec.camera).also { + world.add(it.centerMarker) + } + val rootObjectProperty: ObjectProperty = SimpleObjectProperty() var rootObject: VisualObject3D? by rootObjectProperty @@ -105,99 +79,7 @@ class FXCanvas3D(val plugin: FX3DPlugin, meta: Meta = EmptyMeta) : } } - - private fun handleKeyboard(scene: SubScene) { - scene.onKeyPressed = EventHandler { event -> - if (event.isControlDown) { - when (event.code) { - KeyCode.Z -> { - translateX = 0.0 - translateY = 0.0 - camera.translateZ = CAMERA_INITIAL_DISTANCE - angleY = CAMERA_INITIAL_Y_ANGLE - angleX = CAMERA_INITIAL_X_ANGLE - } - KeyCode.X -> axes.isVisible = !axes.isVisible -// KeyCode.S -> snapshot() -// KeyCode.DIGIT1 -> pixelMap.filterKeys { it.getLayerNumber() == 1 }.values.forEach { -// toggleTransparency( -// it -// ) -// } -// KeyCode.DIGIT2 -> pixelMap.filterKeys { it.getLayerNumber() == 2 }.values.forEach { -// toggleTransparency( -// it -// ) -// } -// KeyCode.DIGIT3 -> pixelMap.filterKeys { it.getLayerNumber() == 3 }.values.forEach { -// toggleTransparency( -// it -// ) -// } - else -> { - }//do nothing - } - } - } - } - - private fun handleMouse(scene: SubScene) { - - var mousePosX: Double = 0.0 - var mousePosY: Double = 0.0 - var mouseOldX: Double = 0.0 - var mouseOldY: Double = 0.0 - var mouseDeltaX: Double = 0.0 - var mouseDeltaY: Double = 0.0 - - scene.onMousePressed = EventHandler { me -> - mousePosX = me.sceneX - mousePosY = me.sceneY - mouseOldX = me.sceneX - mouseOldY = me.sceneY - } - - scene.onMouseDragged = EventHandler { me -> - mouseOldX = mousePosX - mouseOldY = mousePosY - mousePosX = me.sceneX - mousePosY = me.sceneY - mouseDeltaX = mousePosX - mouseOldX - mouseDeltaY = mousePosY - mouseOldY - - val modifier = when { - me.isControlDown -> CONTROL_MULTIPLIER - me.isShiftDown -> SHIFT_MULTIPLIER - else -> 1.0 - } - - if (me.isPrimaryButtonDown) { - angleY += mouseDeltaX * MOUSE_SPEED * modifier * ROTATION_SPEED - angleX += mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED - } else if (me.isSecondaryButtonDown) { - translateX -= mouseDeltaX * MOUSE_SPEED * modifier * TRACK_SPEED - translateY -= mouseDeltaY * MOUSE_SPEED * modifier * TRACK_SPEED - } - } - scene.onScroll = EventHandler { event -> - val z = camera.translateZ - val newZ = z + MOUSE_SPEED * event.deltaY * RESIZE_SPEED - camera.translateZ = newZ - } - } - override fun render(obj: VisualObject3D, meta: Meta) { rootObject = obj } - - companion object { - 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 - 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 = 1.0 - } } \ No newline at end of file diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/OrbitControls.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/OrbitControls.kt new file mode 100644 index 00000000..0a5a84ad --- /dev/null +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/OrbitControls.kt @@ -0,0 +1,174 @@ +package hep.dataforge.vis.spatial.fx + +import hep.dataforge.vis.spatial.specifications.CameraSpec +import javafx.beans.InvalidationListener +import javafx.beans.property.SimpleDoubleProperty +import javafx.event.EventHandler +import javafx.geometry.Point3D +import javafx.scene.Camera +import javafx.scene.Node +import javafx.scene.SubScene +import javafx.scene.input.MouseEvent +import javafx.scene.input.ScrollEvent +import javafx.scene.shape.Sphere +import javafx.scene.transform.Rotate +import javafx.scene.transform.Translate +import tornadofx.* +import kotlin.math.* + + +class OrbitControls internal constructor(camera: Camera, canvas: SubScene, spec: CameraSpec) { + + val distanceProperty = SimpleDoubleProperty(spec.distance) + var distance by distanceProperty + + val azimuthProperty = SimpleDoubleProperty(spec.azimuth) + var azimuth by azimuthProperty + + val zenithProperty = SimpleDoubleProperty(PI/2 - spec.latitude) + var zenith by zenithProperty + + val latitudeProperty = zenithProperty.unaryMinus().plus(PI/2) + val latitude by latitudeProperty + + val baseXProperty = SimpleDoubleProperty(0.0) + var x by baseXProperty + val baseYProperty = SimpleDoubleProperty(0.0) + var y by baseYProperty + val baseZProperty = SimpleDoubleProperty(0.0) + var z by baseZProperty + +// val basePositionProperty: ObjectBinding = +// nonNullObjectBinding(baseXProperty, baseYProperty, baseZProperty) { +// Point3D(x, y, z) +// } +// +// val basePosition by basePositionProperty + + val centerMarker by lazy { + Sphere(10.0).also { + it.translateXProperty().bind(baseXProperty) + it.translateYProperty().bind(baseYProperty) + it.translateZProperty().bind(baseZProperty) + } + } + + private val rx = Rotate(0.0, Rotate.X_AXIS) + + private val ry = Rotate(0.0, Rotate.Y_AXIS) + + private val translate = Translate() + + private val rz = Rotate(180.0, Rotate.Z_AXIS) + + + init { + camera.transforms.setAll(ry, rx, translate,rz) + update() + val listener = InvalidationListener { + update() + } + distanceProperty.addListener(listener) + azimuthProperty.addListener(listener) + zenithProperty.addListener(listener) + baseXProperty.addListener(listener) + baseYProperty.addListener(listener) + baseZProperty.addListener(listener) + + canvas.apply { + camera.translateXProperty().bind(widthProperty().divide(2)) + camera.translateZProperty().bind(heightProperty().divide(2)) + handleMouse() + } +// coordinateContainer?.vbox { +// label(distanceProperty.asString()) +// label(azimuthProperty.asString()) +// label(zenithProperty.asString()) +// } + } + + private fun update() { + val spherePosition = Point3D( + sin(zenith) * sin(azimuth), + cos(zenith), + sin(zenith) * cos(azimuth) + ).times(distance) + val basePosition = Point3D(x, y, z) + //Create direction vector + val cameraPosition = basePosition + spherePosition + val camDirection: Point3D = (-spherePosition).normalize() + + val xRotation = Math.toDegrees(asin(-camDirection.y)) + val yRotation = Math.toDegrees(atan2(camDirection.x, camDirection.z)) + + rx.pivotX = cameraPosition.x + rx.pivotY = cameraPosition.y + rx.pivotZ = cameraPosition.z + rx.angle = xRotation + + ry.pivotX = cameraPosition.x + ry.pivotY = cameraPosition.y + ry.pivotZ = cameraPosition.z + ry.angle = yRotation + + translate.x = cameraPosition.x + translate.y = cameraPosition.y + translate.z = cameraPosition.z + } + + + private fun Node.handleMouse() { + + var mousePosX = 0.0 + var mousePosY = 0.0 + var mouseOldX: Double + var mouseOldY: Double + var mouseDeltaX: Double + var mouseDeltaY: Double + + onMousePressed = EventHandler { me -> + mousePosX = me.sceneX + mousePosY = me.sceneY + mouseOldX = me.sceneX + mouseOldY = me.sceneY + } + + onMouseDragged = EventHandler { me -> + mouseOldX = mousePosX + mouseOldY = mousePosY + mousePosX = me.sceneX + mousePosY = me.sceneY + mouseDeltaX = mousePosX - mouseOldX + mouseDeltaY = mousePosY - mouseOldY + + val modifier = when { + me.isControlDown -> CONTROL_MULTIPLIER + me.isShiftDown -> SHIFT_MULTIPLIER + else -> 1.0 + } + + if (me.isPrimaryButtonDown) { + azimuth -= mouseDeltaX * MOUSE_SPEED * modifier * ROTATION_SPEED + zenith -= mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED + } else if (me.isSecondaryButtonDown) { + x += mouseDeltaX * MOUSE_SPEED * modifier * TRACK_SPEED + z -= mouseDeltaY * MOUSE_SPEED * modifier * TRACK_SPEED + } + } + onScroll = EventHandler { event -> + distance = max(1.0, distance - MOUSE_SPEED * event.deltaY * RESIZE_SPEED) + } + } + + companion object { + private const val CONTROL_MULTIPLIER = 0.1 + private const val SHIFT_MULTIPLIER = 10.0 + private const val MOUSE_SPEED = 0.1 + private const val ROTATION_SPEED = 0.02 + private const val TRACK_SPEED = 6.0 + private const val RESIZE_SPEED = 10.0 + } +} + +fun Camera.orbitControls(canvas: SubScene, spec: CameraSpec) = + OrbitControls(this, canvas, spec) \ No newline at end of file diff --git a/demo/gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt b/demo/gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt index 0f459235..928fd24a 100644 --- a/demo/gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt +++ b/demo/gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt @@ -2,7 +2,7 @@ package hep.dataforge.vis.spatial.gdml.demo import hep.dataforge.context.Global import hep.dataforge.js.Application -import hep.dataforge.js.objectTree +import hep.dataforge.vis.js.editor.objectTree import hep.dataforge.js.startApplication import hep.dataforge.meta.buildMeta import hep.dataforge.meta.withBottom @@ -20,7 +20,7 @@ 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.spatial.three.threeOutputConfig +import hep.dataforge.vis.spatial.three.threeSettings import hep.dataforge.vis.spatial.visible import kotlinx.html.dom.append import kotlinx.html.js.p @@ -157,7 +157,7 @@ private class GDMLDemoApp : Application { val output = three.output(canvasElement as HTMLElement) output.camera.layers.set(0) - configElement.threeOutputConfig(output) + configElement.threeSettings(output) //tree.visualObjectTree(visual, editor::propertyEditor) treeElement.objectTree(NameToken("World"), visual) { editorElement.propertyEditor(it) { item -> diff --git a/demo/gdml/src/jsMain/web/index.html b/demo/gdml/src/jsMain/web/index.html index b742dbcc..3b2a99b2 100644 --- a/demo/gdml/src/jsMain/web/index.html +++ b/demo/gdml/src/jsMain/web/index.html @@ -6,9 +6,9 @@ Three js demo for particle physics - + - +
diff --git a/demo/muon-monitor/src/jsMain/web/index.html b/demo/muon-monitor/src/jsMain/web/index.html index ee1b1197..3f8315fa 100644 --- a/demo/muon-monitor/src/jsMain/web/index.html +++ b/demo/muon-monitor/src/jsMain/web/index.html @@ -27,8 +27,8 @@
-
-
+
+
diff --git a/demo/spatial-showcase/src/commonMain/kotlin/hep/dataforge/vis/spatial/demo/demo.kt b/demo/spatial-showcase/src/commonMain/kotlin/hep/dataforge/vis/spatial/demo/demo.kt index 09728066..ddb92491 100644 --- a/demo/spatial-showcase/src/commonMain/kotlin/hep/dataforge/vis/spatial/demo/demo.kt +++ b/demo/spatial-showcase/src/commonMain/kotlin/hep/dataforge/vis/spatial/demo/demo.kt @@ -1,11 +1,13 @@ package hep.dataforge.vis.spatial.demo import hep.dataforge.meta.buildMeta +import hep.dataforge.meta.invoke 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 hep.dataforge.vis.spatial.specifications.CanvasSpec import kotlinx.coroutines.* import kotlin.math.PI import kotlin.math.cos @@ -21,10 +23,22 @@ fun OutputManager.demo(name: String, title: String = name, block: VisualGroup3D. output.render(action = block) } +val canvasOptions = CanvasSpec { + minSize = 500 + axes { + size = 500.0 + visible = true + } + camera { + distance = 600.0 + latitude = PI/6 + } +} + fun OutputManager.showcase() { demo("shapes", "Basic shapes") { box(100.0, 100.0, 100.0) { - z = 110.0 + z = -110.0 } sphere(50.0) { x = 110 @@ -88,6 +102,7 @@ fun OutputManager.showcase() { layer(i * 5, 20 * sin(2 * PI / 100 * i), 20 * cos(2 * PI / 100 * i)) } color(Colors.teal) + rotationX = -PI / 2 } } @@ -111,13 +126,13 @@ fun OutputManager.showcase() { box(100, 100, 50) { opacity = 0.3 } - label("Hello, world!",fontSize = 15) { - z = -26 + label("Hello, world!", fontSize = 12) { + z = 26 } } } -fun OutputManager.showcaseCSG(){ +fun OutputManager.showcaseCSG() { demo("CSG.simple", "CSG operations") { composite(CompositeType.UNION) { box(100, 100, 100) { diff --git a/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt b/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt index 7d5c152c..7d9adc3e 100644 --- a/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt +++ b/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoApp.kt @@ -22,27 +22,27 @@ private class ThreeDemoApp : Application { 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) - } - } - } - } +// 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) +// } +// } +// } +// } } diff --git a/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoGrid.kt b/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoGrid.kt index b236c602..44a71b5a 100644 --- a/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoGrid.kt +++ b/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vis/spatial/demo/ThreeDemoGrid.kt @@ -3,11 +3,15 @@ package hep.dataforge.vis.spatial.demo import hep.dataforge.context.Global import hep.dataforge.meta.Meta import hep.dataforge.meta.get +import hep.dataforge.meta.invoke import hep.dataforge.meta.string import hep.dataforge.names.Name import hep.dataforge.output.OutputManager import hep.dataforge.output.Renderer import hep.dataforge.vis.common.VisualObject +import hep.dataforge.vis.spatial.specifications.AxesSpec +import hep.dataforge.vis.spatial.specifications.CameraSpec +import hep.dataforge.vis.spatial.specifications.CanvasSpec import hep.dataforge.vis.spatial.three.ThreeCanvas import hep.dataforge.vis.spatial.three.ThreePlugin import hep.dataforge.vis.spatial.three.output @@ -40,18 +44,14 @@ class ThreeDemoGrid(element: Element, meta: Meta = Meta.EMPTY) : OutputManager { return outputs.getOrPut(name) { if (type != VisualObject::class) error("Supports only DisplayObject") - val output = three.output(meta = meta) { - "minSize" put 500 - "axis" put { - "size" put 500 - } - } + lateinit var output: ThreeCanvas //TODO calculate cell width here using jquery gridRoot.append { span("border") { div("col-6") { div { id = "output-$name" }.also { - output.attach(it) + output = three.output(it, canvasOptions) + //output.attach(it) } hr() h2 { +(meta["title"].string ?: name.toString()) } diff --git a/demo/spatial-showcase/src/jsMain/web/index.html b/demo/spatial-showcase/src/jsMain/web/index.html index bea2b47f..e76b2dd4 100644 --- a/demo/spatial-showcase/src/jsMain/web/index.html +++ b/demo/spatial-showcase/src/jsMain/web/index.html @@ -4,32 +4,14 @@ Three js demo for particle physics - - + + -

Demo grid

- - - - \ No newline at end of file diff --git a/demo/spatial-showcase/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt b/demo/spatial-showcase/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt index 3fbaff04..109ed1da 100644 --- a/demo/spatial-showcase/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt +++ b/demo/spatial-showcase/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt @@ -1,7 +1,5 @@ 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.* @@ -14,22 +12,12 @@ class FXDemoApp : App(FXDemoGrid::class) { override fun start(stage: Stage) { super.start(stage) - stage.width = 400.0 - stage.height = 400.0 + stage.width = 600.0 + stage.height = 600.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 - } - } - } - } + view.showcase() + view.demo("gdml", "gdml-cubes") { + gdml(Paths.get("D:\\Work\\Projects\\gdml.kt\\gdml-source\\cubes.gdml")) //setProperty(Material3D.MATERIAL_WIREFRAME_KEY, true) } } diff --git a/demo/spatial-showcase/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoGrid.kt b/demo/spatial-showcase/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoGrid.kt index 800180e7..9357e5de 100644 --- a/demo/spatial-showcase/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoGrid.kt +++ b/demo/spatial-showcase/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoGrid.kt @@ -9,13 +9,15 @@ import hep.dataforge.output.Renderer import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.spatial.fx.FX3DPlugin import hep.dataforge.vis.spatial.fx.FXCanvas3D +import hep.dataforge.vis.spatial.specifications.AxesSpec +import hep.dataforge.vis.spatial.specifications.CanvasSpec import javafx.collections.FXCollections import javafx.scene.Parent import javafx.scene.control.Tab import tornadofx.* import kotlin.reflect.KClass -class FXDemoGrid : View(), OutputManager { +class FXDemoGrid : View(title = "DataForge-vis FX demo"), OutputManager { private val outputs = FXCollections.observableHashMap() override val root: Parent = borderpane { @@ -32,13 +34,7 @@ class FXDemoGrid : View(), OutputManager { 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) + val output = FXCanvas3D(fx3d, canvasOptions) output } as Renderer