Readme update #25 #26
120
README.md
@ -1,41 +1,99 @@
|
|||||||
[![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
|
[![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
|
||||||
|
|
||||||
# DataForge Visualisation Platform
|
# DataForge Visualization Platform
|
||||||
|
|
||||||
This repository contains [DataForge](http://npm.mipt.ru/dataforge/)
|
## Table of contents
|
||||||
(also [here](https://github.com/mipt-npm/dataforge-core)) components useful for visualization in
|
|
||||||
various scientific applications. The main application for now is 3D visualization for particle
|
|
||||||
physics experiments. Other applications including 2D plots are planned for future.
|
|
||||||
|
|
||||||
The project is developed as a Kotlin multiplatform application, currently
|
* [Introduction](#introduction)
|
||||||
targeting browser JavaScript and JVM.
|
* [Features](#features)
|
||||||
|
* [About DataForge](#about-dataforge)
|
||||||
|
* [Modules contained in this repository](#modules-contained-in-this-repository)
|
||||||
|
* [dataforge-vis-common](#dataforge-vis-common)
|
||||||
|
* [dataforge-vis-spatial](#dataforge-vis-spatial)
|
||||||
|
* [dataforge-vis-spatial-gdml](#dataforge-vis-spatial-gdml)
|
||||||
|
* [dataforge-vis-jsroot](#dataforge-vis-jsroot)
|
||||||
|
* [Demonstrations](#demonstrations)
|
||||||
|
* [Spatial Showcase](#spatial-showcase)
|
||||||
|
* [Muon Monitor](#muon-monitor-visualization)
|
||||||
|
* [GDML Example](#gdml-example)
|
||||||
|
|
||||||
Main features:
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
This repository contains a [DataForge](#about-dataforge)\-based framework
|
||||||
|
used for visualization in various scientific applications.
|
||||||
|
|
||||||
|
The main framework's use case for now is 3D visualization for particle physics experiments.
|
||||||
|
Other applications including 2D plots are planned for the future.
|
||||||
|
|
||||||
|
The project is being developed as a Kotlin multiplatform application, currently targeting browser
|
||||||
|
JavaScript and JVM.
|
||||||
|
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
The main framework's features for now include:
|
||||||
- 3D visualization of complex experimental set-ups
|
- 3D visualization of complex experimental set-ups
|
||||||
- Event display such as particle tracks, etc.
|
- Event display such as particle tracks, etc.
|
||||||
- Scales up to few hundred thousands of elements
|
- Scales up to few hundred thousands of elements
|
||||||
- Camera move, rotate, zoom-in and zoom-out
|
- Camera move, rotate, zoom-in and zoom-out
|
||||||
- Object tree with property editor
|
- Scene graph as an object tree with property editor
|
||||||
- Settings export and import
|
- Settings export and import
|
||||||
- Multiple platform support
|
- Multiple platform support
|
||||||
|
|
||||||
|
|
||||||
## Modules contained in this repository:
|
## About DataForge
|
||||||
|
|
||||||
|
DataForge is a software framework for automated scientific data processing. DataForge Visualization
|
||||||
|
Platform uses some of the concepts and modules of DataForge, including: `Meta`, `Configuration`, `Context`,
|
||||||
|
`Provider`, and some others.
|
||||||
|
|
||||||
|
To learn more about DataForge, please consult the following URLs:
|
||||||
|
* [Kotlin multiplatform implementation of DataForge](https://github.com/mipt-npm/dataforge-core)
|
||||||
|
* [DataForge documentation](http://npm.mipt.ru/dataforge/)
|
||||||
|
* [Original implementation of DataForge](https://bitbucket.org/Altavir/dataforge/src/default/)
|
||||||
|
|
||||||
|
|
||||||
|
## Modules contained in this repository
|
||||||
|
|
||||||
### dataforge-vis-common
|
### dataforge-vis-common
|
||||||
|
|
||||||
Common visualisation objects such as VisualObject and VisualGroup.
|
Contains a general hierarchy of classes and interfaces useful for visualization.
|
||||||
|
This module is not specific to 3D-visualization.
|
||||||
|
|
||||||
|
The `dataforge-vis-common` module also includes configuration editors for JS (in `jsMain`) and JVM (in `jvmMain`).
|
||||||
|
|
||||||
|
##### Class diagram:
|
||||||
|
|
||||||
|
![](doc/resources/class-diag-common.png)
|
||||||
|
|
||||||
|
|
||||||
### dataforge-vis-spatial
|
### dataforge-vis-spatial
|
||||||
|
|
||||||
Includes common description and serializers for 3D visualisation, JavaFX and Three.js implementations.
|
Includes common classes and serializers for 3D visualization, Three.js and JavaFX implementations.
|
||||||
|
|
||||||
|
##### Class diagram:
|
||||||
|
|
||||||
|
![](doc/resources/class-diag-3d.png)
|
||||||
|
|
||||||
|
##### Prototypes
|
||||||
|
|
||||||
|
One of the important features of the framework is support for 3D object prototypes (sometimes
|
||||||
|
also referred to as templates). The idea is that prototype geometry can be rendered once and reused
|
||||||
|
for multiple objects. This helps to significantly decrease memory usage.
|
||||||
|
|
||||||
|
The `prototypes` property tree is defined in `VisualGroup3D` class, and `Proxy` class helps to reuse a template object.
|
||||||
|
|
||||||
|
##### Styles
|
||||||
|
|
||||||
|
`VisualGroup3D` has a `styleSheet` property that can optionally define styles at the Group's
|
||||||
|
level. Styles are applied to child (descendant) objects using `styles: List<String>` property defined
|
||||||
|
in `VisualObject`.
|
||||||
|
|
||||||
|
|
||||||
### dataforge-vis-spatial-gdml
|
### dataforge-vis-spatial-gdml
|
||||||
|
|
||||||
GDML bindings for 3D visualisation (to be moved to gdml project).
|
GDML bindings for 3D visualization (to be moved to gdml project).
|
||||||
|
|
||||||
|
|
||||||
### dataforge-vis-jsroot
|
### dataforge-vis-jsroot
|
||||||
@ -45,20 +103,23 @@ Some JSROOT bindings.
|
|||||||
Note: Currently, this part is experimental and put here for completeness. This module may not build.
|
Note: Currently, this part is experimental and put here for completeness. This module may not build.
|
||||||
|
|
||||||
|
|
||||||
### demo
|
## Demonstrations
|
||||||
|
|
||||||
Several demonstrations of using the dataforge-vis framework:
|
The `demo` module contains several demonstrations of using the `dataforge-vis` framework:
|
||||||
|
|
||||||
##### spatial-showcase
|
### Spatial Showcase
|
||||||
|
|
||||||
Contains a simple demonstration (grid with a few shapes that you can rotate, move camera, etc.).
|
Contains a simple demonstration with a grid including a few shapes that you can rotate, move camera, and so on.
|
||||||
|
Some shapes will also periodically change their color and visibility.
|
||||||
|
|
||||||
To see the demo: run `demo/spatial-showcase/distribution/installJsDist` Gradle task, then open
|
To see the demo: run `demo/spatial-showcase/Tasks/distribution/installJsDist` Gradle task, then open
|
||||||
`build/distribuions/spatial-showcase-js-0.1.0-dev/index.html` file in your browser.
|
`build/distribuions/spatial-showcase-js-0.1.0-dev/index.html` file in your browser.
|
||||||
|
|
||||||
Other demos can be built similarly.
|
##### Example view:
|
||||||
|
|
||||||
##### muon-monitor
|
![](doc/resources/spatial-showcase.png)
|
||||||
|
|
||||||
|
### Muon Monitor Visualization
|
||||||
|
|
||||||
A full-stack application example, showing the
|
A full-stack application example, showing the
|
||||||
[Muon Monitor](http://npm.mipt.ru/projects/physics.html#mounMonitor) experiment set-up.
|
[Muon Monitor](http://npm.mipt.ru/projects/physics.html#mounMonitor) experiment set-up.
|
||||||
@ -68,8 +129,19 @@ Includes server back-end generating events, as well as visualization front-end.
|
|||||||
To run full-stack app (both server and browser front-end), run
|
To run full-stack app (both server and browser front-end), run
|
||||||
`demo/muon-monitor/application/run` task.
|
`demo/muon-monitor/application/run` task.
|
||||||
|
|
||||||
##### gdml
|
##### Example view:
|
||||||
|
|
||||||
Visualization example for geometry defined as GDML file. Once you open Web application,
|
![](doc/resources/muon-monitor.png)
|
||||||
drag-and-drop GDML file to the window to see visualization. For example file, use
|
|
||||||
`demo\gdml\src\jsMain\resources\cubes.gdml`.
|
### GDML Example
|
||||||
|
|
||||||
|
Visualization example for geometry defined as GDML file.
|
||||||
|
|
||||||
|
To build the app, run `demo/gdml/Tasks/distribution/installJsDist` task, then open
|
||||||
|
`build/distribuions/gdml-js-0.1.0-dev/index.html` file in your browser, and
|
||||||
|
drag-and-drop GDML file to the window to see visualization. For an example file, use
|
||||||
|
`demo/gdml/src/jsMain/resources/cubes.gdml`.
|
||||||
|
|
||||||
|
##### Example view:
|
||||||
|
|
||||||
|
![](doc/resources/gdml-demo.png)
|
||||||
|
@ -26,7 +26,7 @@ allprojects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group = "hep.dataforge"
|
group = "hep.dataforge"
|
||||||
version = "0.1.0-dev"
|
version = "0.1.1-dev"
|
||||||
}
|
}
|
||||||
|
|
||||||
subprojects{
|
subprojects{
|
||||||
|
@ -37,7 +37,7 @@ kotlin {
|
|||||||
jsMain{
|
jsMain{
|
||||||
dependencies {
|
dependencies {
|
||||||
api("hep.dataforge:dataforge-output-html:$dataforgeVersion")
|
api("hep.dataforge:dataforge-output-html:$dataforgeVersion")
|
||||||
api(npm("bootstrap","4.4.1"))
|
//api(npm("bootstrap","4.4.1"))
|
||||||
implementation(npm("jsoneditor"))
|
implementation(npm("jsoneditor"))
|
||||||
implementation(npm("file-saver"))
|
implementation(npm("file-saver"))
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
package hep.dataforge.vis.common
|
package hep.dataforge.vis.common
|
||||||
|
|
||||||
import hep.dataforge.meta.MetaItem
|
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
|
import kotlinx.serialization.Transient
|
||||||
|
|
||||||
|
|
||||||
@ -76,7 +79,7 @@ abstract class AbstractVisualGroup : AbstractVisualObject(), MutableVisualGroup
|
|||||||
* Add named or unnamed child to the group. If key is null the child is considered unnamed. Both key and value are not
|
* Add named or unnamed child to the group. If key is null the child is considered unnamed. Both key and value are not
|
||||||
* allowed to be null in the same time. If name is present and [child] is null, the appropriate element is removed.
|
* allowed to be null in the same time. If name is present and [child] is null, the appropriate element is removed.
|
||||||
*/
|
*/
|
||||||
override fun set(name: Name, child: VisualObject?) {
|
override fun set(name: Name, child: VisualObject?): Unit {
|
||||||
when {
|
when {
|
||||||
name.isEmpty() -> {
|
name.isEmpty() -> {
|
||||||
if (child != null) {
|
if (child != null) {
|
||||||
@ -100,13 +103,4 @@ abstract class AbstractVisualGroup : AbstractVisualObject(), MutableVisualGroup
|
|||||||
structureChangeListeners.forEach { it.callback(name, child) }
|
structureChangeListeners.forEach { it.callback(name, child) }
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun set(key: String, child: VisualObject?): Unit {
|
|
||||||
if (key.isBlank()) {
|
|
||||||
if(child!= null) {
|
|
||||||
addStatic(child)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
set(key.toName(), child)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -73,6 +73,9 @@ abstract class AbstractVisualObject : VisualObject {
|
|||||||
styleCache = it
|
styleCache = it
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All available properties in a layered form
|
||||||
|
*/
|
||||||
override fun allProperties(): Laminate = Laminate(properties, mergedStyles)
|
override fun allProperties(): Laminate = Laminate(properties, mergedStyles)
|
||||||
|
|
||||||
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {
|
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {
|
||||||
|
@ -6,10 +6,11 @@ import hep.dataforge.io.serialization.MetaSerializer
|
|||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.*
|
||||||
import kotlinx.serialization.Transient
|
|
||||||
import kotlinx.serialization.UseSerializers
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A container for styles
|
||||||
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
class StyleSheet() {
|
class StyleSheet() {
|
||||||
@Transient
|
@Transient
|
||||||
@ -28,7 +29,7 @@ class StyleSheet() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define a style without notifying
|
* Define a style without notifying owner
|
||||||
*/
|
*/
|
||||||
fun define(key: String, style: Meta?) {
|
fun define(key: String, style: Meta?) {
|
||||||
if (style == null) {
|
if (style == null) {
|
||||||
@ -48,6 +49,20 @@ class StyleSheet() {
|
|||||||
val newStyle = get(key)?.let { buildMeta(it, builder) } ?: buildMeta(builder)
|
val newStyle = get(key)?.let { buildMeta(it, builder) } ?: buildMeta(builder)
|
||||||
set(key, newStyle.seal())
|
set(key, newStyle.seal())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object: KSerializer<StyleSheet>{
|
||||||
|
override val descriptor: SerialDescriptor
|
||||||
|
get() = TODO("Not yet implemented")
|
||||||
|
|
||||||
|
override fun deserialize(decoder: Decoder): StyleSheet {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, obj: StyleSheet) {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun VisualObject.styleChanged(key: String, oldStyle: Meta?, newStyle: Meta?) {
|
private fun VisualObject.styleChanged(key: String, oldStyle: Meta?, newStyle: Meta?) {
|
||||||
|
@ -13,7 +13,7 @@ interface VisualFactory<T : VisualObject> {
|
|||||||
): T
|
): T
|
||||||
}
|
}
|
||||||
|
|
||||||
class VisualPlugin(meta: Meta) : AbstractPlugin(meta) {
|
class Visual(meta: Meta) : AbstractPlugin(meta) {
|
||||||
override val tag: PluginTag get() = Companion.tag
|
override val tag: PluginTag get() = Companion.tag
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,11 +27,11 @@ class VisualPlugin(meta: Meta) : AbstractPlugin(meta) {
|
|||||||
return visualFactories[T::class]?.invoke(context, parent, meta) as T?
|
return visualFactories[T::class]?.invoke(context, parent, meta) as T?
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : PluginFactory<VisualPlugin> {
|
companion object : PluginFactory<Visual> {
|
||||||
override val tag: PluginTag = PluginTag(name = "visual", group = PluginTag.DATAFORGE_GROUP)
|
override val tag: PluginTag = PluginTag(name = "visual", group = PluginTag.DATAFORGE_GROUP)
|
||||||
override val type: KClass<out VisualPlugin> = VisualPlugin::class
|
override val type: KClass<out Visual> = Visual::class
|
||||||
|
|
||||||
override fun invoke(meta: Meta, context: Context): VisualPlugin = VisualPlugin(meta)
|
override fun invoke(meta: Meta, context: Context): Visual = Visual(meta)
|
||||||
|
|
||||||
const val VISUAL_FACTORY_TYPE = "visual.factory"
|
const val VISUAL_FACTORY_TYPE = "visual.factory"
|
||||||
}
|
}
|
@ -16,6 +16,10 @@ interface VisualGroup : Provider, Iterable<VisualObject>, VisualObject {
|
|||||||
|
|
||||||
val styleSheet: StyleSheet?
|
val styleSheet: StyleSheet?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A map of direct children for specific target
|
||||||
|
* (currently "visual" or "style")
|
||||||
|
*/
|
||||||
override fun provideTop(target: String): Map<Name, Any> =
|
override fun provideTop(target: String): Map<Name, Any> =
|
||||||
when (target) {
|
when (target) {
|
||||||
VisualObject.TYPE -> children.flatMap { (key, value) ->
|
VisualObject.TYPE -> children.flatMap { (key, value) ->
|
||||||
@ -49,7 +53,7 @@ interface VisualGroup : Provider, Iterable<VisualObject>, VisualObject {
|
|||||||
*/
|
*/
|
||||||
fun attachChildren() {
|
fun attachChildren() {
|
||||||
styleSheet?.owner = this
|
styleSheet?.owner = this
|
||||||
this.children.values.forEach {
|
children.values.forEach {
|
||||||
it.parent = this
|
it.parent = this
|
||||||
(it as? VisualGroup)?.attachChildren()
|
(it as? VisualGroup)?.attachChildren()
|
||||||
}
|
}
|
||||||
@ -84,6 +88,10 @@ interface MutableVisualGroup : VisualGroup {
|
|||||||
operator fun set(name: Name, child: VisualObject?)
|
operator fun set(name: Name, child: VisualObject?)
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun VisualGroup.get(str: String?) = get(str?.toName() ?: Name.EMPTY)
|
operator fun VisualGroup.get(str: String?): VisualObject? = get(str?.toName() ?: Name.EMPTY)
|
||||||
|
|
||||||
|
operator fun MutableVisualGroup.set(key: String, child: VisualObject?) {
|
||||||
|
set(key.toName(), child)
|
||||||
|
}
|
||||||
|
|
||||||
fun MutableVisualGroup.removeAll() = children.keys.map { it.asName() }.forEach { this[it] = null }
|
fun MutableVisualGroup.removeAll() = children.keys.map { it.asName() }.forEach { this[it] = null }
|
@ -2,9 +2,7 @@ package hep.dataforge.vis.common
|
|||||||
|
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.NameToken
|
|
||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
import hep.dataforge.names.toName
|
|
||||||
import hep.dataforge.values.Value
|
import hep.dataforge.values.Value
|
||||||
import kotlin.jvm.JvmName
|
import kotlin.jvm.JvmName
|
||||||
import kotlin.properties.ReadOnlyProperty
|
import kotlin.properties.ReadOnlyProperty
|
||||||
@ -48,7 +46,7 @@ class VisualObjectDelegateWrapper<T>(
|
|||||||
|
|
||||||
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
|
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
|
||||||
val name = key ?: property.name.asName()
|
val name = key ?: property.name.asName()
|
||||||
return read(obj.getProperty(name,inherited))?:default
|
return read(obj.getProperty(name, inherited)) ?: default
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
|
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
|
||||||
@ -58,75 +56,72 @@ class VisualObjectDelegateWrapper<T>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun VisualObject.value(default: Value? = null, key: String? = null, inherited: Boolean = false) =
|
fun VisualObject.value(default: Value? = null, name: Name? = null, inherited: Boolean = false) =
|
||||||
VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.value }
|
VisualObjectDelegateWrapper(this, name, default, inherited) { it.value }
|
||||||
|
|
||||||
fun VisualObject.string(default: String? = null, key: String? = null, inherited: Boolean = false) =
|
fun VisualObject.string(default: String? = null, name: Name? = null, inherited: Boolean = false) =
|
||||||
VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.string }
|
VisualObjectDelegateWrapper(this, name, default, inherited) { it.string }
|
||||||
|
|
||||||
fun VisualObject.boolean(default: Boolean? = null, key: String? = null, inherited: Boolean = false) =
|
fun VisualObject.boolean(default: Boolean? = null, name: Name? = null, inherited: Boolean = false) =
|
||||||
VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.boolean }
|
VisualObjectDelegateWrapper(this, name, default, inherited) { it.boolean }
|
||||||
|
|
||||||
fun VisualObject.number(default: Number? = null, key: String? = null, inherited: Boolean = false) =
|
fun VisualObject.number(default: Number? = null, name: Name? = null, inherited: Boolean = false) =
|
||||||
VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.number }
|
VisualObjectDelegateWrapper(this, name, default, inherited) { it.number }
|
||||||
|
|
||||||
fun VisualObject.double(default: Double? = null, key: String? = null, inherited: Boolean = false) =
|
fun VisualObject.double(default: Double? = null, name: Name? = null, inherited: Boolean = false) =
|
||||||
VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.double }
|
VisualObjectDelegateWrapper(this, name, default, inherited) { it.double }
|
||||||
|
|
||||||
fun VisualObject.int(default: Int? = null, key: String? = null, inherited: Boolean = false) =
|
fun VisualObject.int(default: Int? = null, name: Name? = null, inherited: Boolean = false) =
|
||||||
VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.int }
|
VisualObjectDelegateWrapper(this, name, default, inherited) { it.int }
|
||||||
|
|
||||||
|
|
||||||
fun VisualObject.node(key: String? = null, inherited: Boolean = true) =
|
fun VisualObject.node(name: Name? = null, inherited: Boolean = true) =
|
||||||
VisualObjectDelegateWrapper(this, key?.toName(), null, inherited) { it.node }
|
VisualObjectDelegateWrapper(this, name, null, inherited) { it.node }
|
||||||
|
|
||||||
fun VisualObject.item(key: String? = null, inherited: Boolean = true) =
|
fun VisualObject.item(name: Name? = null, inherited: Boolean = true) =
|
||||||
VisualObjectDelegateWrapper(this, key?.toName(), null, inherited) { it }
|
VisualObjectDelegateWrapper(this, name, null, inherited) { it }
|
||||||
|
|
||||||
//fun <T : Configurable> Configurable.spec(spec: Specification<T>, key: String? = null) = ChildConfigDelegate<T>(key) { spec.wrap(this) }
|
//fun <T : Configurable> Configurable.spec(spec: Specification<T>, key: String? = null) = ChildConfigDelegate<T>(key) { spec.wrap(this) }
|
||||||
|
|
||||||
@JvmName("safeString")
|
@JvmName("safeString")
|
||||||
fun VisualObject.string(default: String, key: String? = null, inherited: Boolean = false) =
|
fun VisualObject.string(default: String, name: Name? = null, inherited: Boolean = false) =
|
||||||
VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.string }
|
VisualObjectDelegateWrapper(this, name, default, inherited) { it.string }
|
||||||
|
|
||||||
@JvmName("safeBoolean")
|
@JvmName("safeBoolean")
|
||||||
fun VisualObject.boolean(default: Boolean, key: String? = null, inherited: Boolean = false) =
|
fun VisualObject.boolean(default: Boolean, name: Name? = null, inherited: Boolean = false) =
|
||||||
VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.boolean }
|
VisualObjectDelegateWrapper(this, name, default, inherited) { it.boolean }
|
||||||
|
|
||||||
@JvmName("safeNumber")
|
@JvmName("safeNumber")
|
||||||
fun VisualObject.number(default: Number, key: String? = null, inherited: Boolean = false) =
|
fun VisualObject.number(default: Number, name: Name? = null, inherited: Boolean = false) =
|
||||||
VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.number }
|
VisualObjectDelegateWrapper(this, name, default, inherited) { it.number }
|
||||||
|
|
||||||
@JvmName("safeDouble")
|
@JvmName("safeDouble")
|
||||||
fun VisualObject.double(default: Double, key: String? = null, inherited: Boolean = false) =
|
fun VisualObject.double(default: Double, name: Name? = null, inherited: Boolean = false) =
|
||||||
VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.double }
|
VisualObjectDelegateWrapper(this, name, default, inherited) { it.double }
|
||||||
|
|
||||||
@JvmName("safeInt")
|
@JvmName("safeInt")
|
||||||
fun VisualObject.int(default: Int, key: String? = null, inherited: Boolean = false) =
|
fun VisualObject.int(default: Int, name: Name? = null, inherited: Boolean = false) =
|
||||||
VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.int }
|
VisualObjectDelegateWrapper(this, name, default, inherited) { it.int }
|
||||||
|
|
||||||
|
|
||||||
inline fun <reified E : Enum<E>> VisualObject.enum(default: E, key: String? = null, inherited: Boolean = false) =
|
inline fun <reified E : Enum<E>> VisualObject.enum(default: E, name: Name? = null, inherited: Boolean = false) =
|
||||||
VisualObjectDelegateWrapper(
|
VisualObjectDelegateWrapper(this, name, default, inherited) {
|
||||||
this,
|
item -> item.string?.let { enumValueOf<E>(it) }
|
||||||
key?.let { NameToken(it).asName() },
|
}
|
||||||
default,
|
|
||||||
inherited
|
|
||||||
) { item -> item.string?.let { enumValueOf<E>(it) } }
|
|
||||||
|
|
||||||
//merge properties
|
//merge properties
|
||||||
|
|
||||||
fun <T> VisualObject.merge(
|
fun <T> VisualObject.merge(
|
||||||
key: String? = null,
|
name: Name? = null,
|
||||||
transformer: (Sequence<MetaItem<*>>) -> T
|
transformer: (Sequence<MetaItem<*>>) -> T
|
||||||
): ReadOnlyProperty<VisualObject, T> {
|
): ReadOnlyProperty<VisualObject, T> {
|
||||||
return object : ReadOnlyProperty<Any?, T> {
|
return object : ReadOnlyProperty<Any?, T> {
|
||||||
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
|
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
|
||||||
val name = key?.toName() ?: property.name.asName()
|
val actualName = name ?: property.name.asName()
|
||||||
val sequence = sequence<MetaItem<*>> {
|
val sequence = sequence<MetaItem<*>> {
|
||||||
var thisObj: VisualObject? = this@merge
|
var thisObj: VisualObject? = this@merge
|
||||||
while (thisObj != null) {
|
while (thisObj != null) {
|
||||||
thisObj.config[name]?.let { yield(it) }
|
thisObj.config[actualName]?.let { yield(it) }
|
||||||
thisObj = thisObj.parent
|
thisObj = thisObj.parent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
package hep.dataforge.vis.js.editor
|
package hep.dataforge.vis.js.editor
|
||||||
|
|
||||||
import kotlinx.html.TagConsumer
|
import kotlinx.html.*
|
||||||
import kotlinx.html.js.div
|
import kotlinx.html.js.div
|
||||||
import kotlinx.html.js.h3
|
|
||||||
import org.w3c.dom.HTMLElement
|
import org.w3c.dom.HTMLElement
|
||||||
|
|
||||||
inline fun TagConsumer<HTMLElement>.card(title: String, crossinline block: TagConsumer<HTMLElement>.() -> Unit) {
|
inline fun TagConsumer<HTMLElement>.card(title: String, crossinline block: TagConsumer<HTMLElement>.() -> Unit) {
|
||||||
@ -13,3 +12,50 @@ inline fun TagConsumer<HTMLElement>.card(title: String, crossinline block: TagCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun TagConsumer<HTMLElement>.accordion(id: String, elements: Map<String, DIV.() -> Unit>) {
|
||||||
|
div("container-fluid") {
|
||||||
|
div("accordion") {
|
||||||
|
this.id = id
|
||||||
|
elements.entries.forEachIndexed { index, (title, builder) ->
|
||||||
|
val headerID = "${id}-${index}-heading"
|
||||||
|
val collapseID = "${id}-${index}-collapse"
|
||||||
|
div("card") {
|
||||||
|
div("card-header") {
|
||||||
|
this.id = headerID
|
||||||
|
h5("mb-0") {
|
||||||
|
button(classes = "btn btn-link collapsed", type = ButtonType.button) {
|
||||||
|
attributes["data-toggle"] = "collapse"
|
||||||
|
attributes["data-target"] = "#$collapseID"
|
||||||
|
attributes["aria-expanded"] = "false"
|
||||||
|
attributes["aria-controls"] = collapseID
|
||||||
|
+title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div("collapse") {
|
||||||
|
this.id = collapseID
|
||||||
|
attributes["aria-labelledby"] = headerID
|
||||||
|
attributes["data-parent"] = "#$id"
|
||||||
|
div("card-body", block = builder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AccordionBuilder {
|
||||||
|
private val map = HashMap<String, DIV.() -> Unit>()
|
||||||
|
fun entry(title: String, block: DIV.() -> Unit) {
|
||||||
|
map[title] = block
|
||||||
|
}
|
||||||
|
|
||||||
|
fun build(consumer: TagConsumer<HTMLElement>, id: String) {
|
||||||
|
consumer.accordion(id, map)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun TagConsumer<HTMLElement>.accordion(id: String, block: AccordionBuilder.() -> Unit) {
|
||||||
|
AccordionBuilder().apply(block).build(this, id)
|
||||||
|
}
|
@ -26,12 +26,11 @@ fun Element.displayObjectTree(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun TagConsumer<HTMLElement>.subTree(
|
private fun TagConsumer<HTMLElement>.subTree(
|
||||||
fullName: Name,
|
name: Name,
|
||||||
obj: VisualObject,
|
obj: VisualObject,
|
||||||
clickCallback: (Name) -> Unit
|
clickCallback: (Name) -> Unit
|
||||||
) {
|
) {
|
||||||
// val fullName = parentName + token
|
val token = name.last()?.toString()?:"World"
|
||||||
val token = fullName.last()?.toString()?:"World"
|
|
||||||
|
|
||||||
//display as node if any child is visible
|
//display as node if any child is visible
|
||||||
if (obj is VisualGroup && obj.children.keys.any { !it.body.startsWith("@") }) {
|
if (obj is VisualGroup && obj.children.keys.any { !it.body.startsWith("@") }) {
|
||||||
@ -40,7 +39,7 @@ private fun TagConsumer<HTMLElement>.subTree(
|
|||||||
toggle = span("objTree-caret")
|
toggle = span("objTree-caret")
|
||||||
label("objTree-label") {
|
label("objTree-label") {
|
||||||
+token
|
+token
|
||||||
onClickFunction = { clickCallback(fullName) }
|
onClickFunction = { clickCallback(name) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val subtree = ul("objTree-subtree")
|
val subtree = ul("objTree-subtree")
|
||||||
@ -55,7 +54,7 @@ private fun TagConsumer<HTMLElement>.subTree(
|
|||||||
.forEach { (childToken, child) ->
|
.forEach { (childToken, child) ->
|
||||||
append {
|
append {
|
||||||
li().apply {
|
li().apply {
|
||||||
subTree(fullName + childToken, child, clickCallback)
|
subTree(name + childToken, child, clickCallback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -70,7 +69,7 @@ private fun TagConsumer<HTMLElement>.subTree(
|
|||||||
span("objTree-leaf")
|
span("objTree-leaf")
|
||||||
label("objTree-label") {
|
label("objTree-label") {
|
||||||
+token
|
+token
|
||||||
onClickFunction = { clickCallback(fullName) }
|
onClickFunction = { clickCallback(name) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ kotlin {
|
|||||||
val commonMain by getting {
|
val commonMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
api(project(":dataforge-vis-spatial"))
|
api(project(":dataforge-vis-spatial"))
|
||||||
api("scientifik:gdml:0.1.4")
|
api("scientifik:gdml:0.1.6")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import hep.dataforge.names.Name
|
|||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
import hep.dataforge.names.plus
|
import hep.dataforge.names.plus
|
||||||
import hep.dataforge.vis.common.get
|
import hep.dataforge.vis.common.get
|
||||||
|
import hep.dataforge.vis.common.set
|
||||||
import hep.dataforge.vis.spatial.*
|
import hep.dataforge.vis.spatial.*
|
||||||
import hep.dataforge.vis.spatial.World.ONE
|
import hep.dataforge.vis.spatial.World.ONE
|
||||||
import hep.dataforge.vis.spatial.World.ZERO
|
import hep.dataforge.vis.spatial.World.ZERO
|
||||||
@ -66,6 +67,12 @@ private fun VisualGroup3D.addSolid(
|
|||||||
solid.deltaphi * aScale,
|
solid.deltaphi * aScale,
|
||||||
name
|
name
|
||||||
)
|
)
|
||||||
|
is GDMLCone -> cone(solid.rmax1, solid.z, solid.rmax2, name = name) {
|
||||||
|
require(solid.rmin1 == 0.0) { "Empty cones are not supported" }
|
||||||
|
require(solid.rmin2 == 0.0) { "Empty cones are not supported" }
|
||||||
|
startAngle = solid.startphi.toFloat()
|
||||||
|
angle = solid.deltaphi.toFloat()
|
||||||
|
}
|
||||||
is GDMLXtru -> extrude(name) {
|
is GDMLXtru -> extrude(name) {
|
||||||
shape {
|
shape {
|
||||||
solid.vertices.forEach {
|
solid.vertices.forEach {
|
||||||
@ -171,7 +178,7 @@ private fun VisualGroup3D.addPhysicalVolume(
|
|||||||
context.proto[fullName] = volume(context, volume)
|
context.proto[fullName] = volume(context, volume)
|
||||||
}
|
}
|
||||||
|
|
||||||
this[physVolume.name ?: ""] = Proxy(fullName).apply {
|
this[physVolume.name ?: ""] = Proxy(this, fullName).apply {
|
||||||
withPosition(
|
withPosition(
|
||||||
context.lUnit,
|
context.lUnit,
|
||||||
physVolume.resolvePosition(context.root),
|
physVolume.resolvePosition(context.root),
|
||||||
|
@ -135,7 +135,7 @@ private fun jsonSchema(descriptor: SerialDescriptor, context: SerialModule): Jso
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
val context = Visual3DPlugin.serialModule
|
val context = Visual3D.serialModule
|
||||||
val definitions = json {
|
val definitions = json {
|
||||||
"children" to json {
|
"children" to json {
|
||||||
"anyOf" to jsonArray {
|
"anyOf" to jsonArray {
|
||||||
|
@ -8,7 +8,7 @@ import java.nio.file.Path
|
|||||||
|
|
||||||
fun GDML.Companion.readFile(file: Path): GDML {
|
fun GDML.Companion.readFile(file: Path): GDML {
|
||||||
val xmlReader = StAXReader(Files.newInputStream(file), "UTF-8")
|
val xmlReader = StAXReader(Files.newInputStream(file), "UTF-8")
|
||||||
return GDML.format.parse(GDML.serializer(), xmlReader)
|
return format.parse(GDML.serializer(), xmlReader)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun VisualGroup3D.gdml(file: Path, key: String = "", transformer: GDMLTransformer.() -> Unit = {}) {
|
fun VisualGroup3D.gdml(file: Path, key: String = "", transformer: GDMLTransformer.() -> Unit = {}) {
|
||||||
|
@ -20,7 +20,7 @@ kotlin {
|
|||||||
}
|
}
|
||||||
jvmMain {
|
jvmMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("org.fxyz3d:fxyz3d:0.5.2") {
|
api("org.fxyz3d:fxyz3d:0.5.2") {
|
||||||
exclude(module = "slf4j-simple")
|
exclude(module = "slf4j-simple")
|
||||||
}
|
}
|
||||||
api("org.jetbrains.kotlinx:kotlinx-coroutines-javafx:${Scientifik.coroutinesVersion}")
|
api("org.jetbrains.kotlinx:kotlinx-coroutines-javafx:${Scientifik.coroutinesVersion}")
|
||||||
|
@ -10,13 +10,15 @@ import hep.dataforge.meta.get
|
|||||||
import hep.dataforge.vis.common.AbstractVisualObject
|
import hep.dataforge.vis.common.AbstractVisualObject
|
||||||
import hep.dataforge.vis.common.VisualFactory
|
import hep.dataforge.vis.common.VisualFactory
|
||||||
import hep.dataforge.vis.common.VisualObject
|
import hep.dataforge.vis.common.VisualObject
|
||||||
|
import hep.dataforge.vis.common.set
|
||||||
|
import hep.dataforge.vis.spatial.Box.Companion.TYPE_NAME
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.UseSerializers
|
import kotlinx.serialization.UseSerializers
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("3d.box")
|
@SerialName(TYPE_NAME)
|
||||||
class Box(
|
class Box(
|
||||||
val xSize: Float,
|
val xSize: Float,
|
||||||
val ySize: Float,
|
val ySize: Float,
|
||||||
@ -52,7 +54,8 @@ class Box(
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object : VisualFactory<Box> {
|
companion object : VisualFactory<Box> {
|
||||||
const val TYPE = "geometry.3d.box"
|
|
||||||
|
const val TYPE_NAME = "3d.box"
|
||||||
|
|
||||||
override val type: KClass<Box> get() = Box::class
|
override val type: KClass<Box> get() = Box::class
|
||||||
|
|
||||||
|
@ -6,6 +6,8 @@ import hep.dataforge.io.serialization.ConfigSerializer
|
|||||||
import hep.dataforge.meta.Config
|
import hep.dataforge.meta.Config
|
||||||
import hep.dataforge.meta.update
|
import hep.dataforge.meta.update
|
||||||
import hep.dataforge.vis.common.AbstractVisualObject
|
import hep.dataforge.vis.common.AbstractVisualObject
|
||||||
|
import hep.dataforge.vis.common.set
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.UseSerializers
|
import kotlinx.serialization.UseSerializers
|
||||||
|
|
||||||
@ -16,6 +18,7 @@ enum class CompositeType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
@SerialName("3d.composite")
|
||||||
class Composite(
|
class Composite(
|
||||||
val compositeType: CompositeType,
|
val compositeType: CompositeType,
|
||||||
val first: VisualObject3D,
|
val first: VisualObject3D,
|
||||||
|
@ -5,6 +5,8 @@ package hep.dataforge.vis.spatial
|
|||||||
import hep.dataforge.io.serialization.ConfigSerializer
|
import hep.dataforge.io.serialization.ConfigSerializer
|
||||||
import hep.dataforge.meta.Config
|
import hep.dataforge.meta.Config
|
||||||
import hep.dataforge.vis.common.AbstractVisualObject
|
import hep.dataforge.vis.common.AbstractVisualObject
|
||||||
|
import hep.dataforge.vis.common.set
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.UseSerializers
|
import kotlinx.serialization.UseSerializers
|
||||||
import kotlin.math.cos
|
import kotlin.math.cos
|
||||||
@ -14,6 +16,7 @@ import kotlin.math.sin
|
|||||||
* A cylinder or cut cone segment
|
* A cylinder or cut cone segment
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
|
@SerialName("3d.cone")
|
||||||
class ConeSegment(
|
class ConeSegment(
|
||||||
var radius: Float,
|
var radius: Float,
|
||||||
var height: Float,
|
var height: Float,
|
||||||
@ -83,3 +86,16 @@ inline fun VisualGroup3D.cylinder(
|
|||||||
height.toFloat(),
|
height.toFloat(),
|
||||||
r.toFloat()
|
r.toFloat()
|
||||||
).apply(block).also { set(name, it) }
|
).apply(block).also { set(name, it) }
|
||||||
|
|
||||||
|
|
||||||
|
inline fun VisualGroup3D.cone(
|
||||||
|
bottomRadius: Number,
|
||||||
|
height: Number,
|
||||||
|
upperRadius: Number = 0.0,
|
||||||
|
name: String = "",
|
||||||
|
block: ConeSegment.() -> Unit = {}
|
||||||
|
): ConeSegment = ConeSegment(
|
||||||
|
bottomRadius.toFloat(),
|
||||||
|
height.toFloat(),
|
||||||
|
upperRadius = upperRadius.toFloat()
|
||||||
|
).apply(block).also { set(name, it) }
|
@ -5,10 +5,13 @@ package hep.dataforge.vis.spatial
|
|||||||
import hep.dataforge.io.serialization.ConfigSerializer
|
import hep.dataforge.io.serialization.ConfigSerializer
|
||||||
import hep.dataforge.meta.Config
|
import hep.dataforge.meta.Config
|
||||||
import hep.dataforge.vis.common.AbstractVisualObject
|
import hep.dataforge.vis.common.AbstractVisualObject
|
||||||
|
import hep.dataforge.vis.common.set
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.UseSerializers
|
import kotlinx.serialization.UseSerializers
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
@SerialName("3d.convex")
|
||||||
class Convex(val points: List<Point3D>) : AbstractVisualObject(), VisualObject3D {
|
class Convex(val points: List<Point3D>) : AbstractVisualObject(), VisualObject3D {
|
||||||
|
|
||||||
@Serializable(ConfigSerializer::class)
|
@Serializable(ConfigSerializer::class)
|
||||||
|
@ -4,6 +4,8 @@ package hep.dataforge.vis.spatial
|
|||||||
import hep.dataforge.io.serialization.ConfigSerializer
|
import hep.dataforge.io.serialization.ConfigSerializer
|
||||||
import hep.dataforge.meta.Config
|
import hep.dataforge.meta.Config
|
||||||
import hep.dataforge.vis.common.AbstractVisualObject
|
import hep.dataforge.vis.common.AbstractVisualObject
|
||||||
|
import hep.dataforge.vis.common.set
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.UseSerializers
|
import kotlinx.serialization.UseSerializers
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
@ -37,6 +39,7 @@ fun Shape2DBuilder.polygon(vertices: Int, radius: Number) {
|
|||||||
data class Layer(var x: Float, var y: Float, var z: Float, var scale: Float)
|
data class Layer(var x: Float, var y: Float, var z: Float, var scale: Float)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
@SerialName("3d.extrude")
|
||||||
class Extruded(
|
class Extruded(
|
||||||
var shape: List<Point2D> = ArrayList(),
|
var shape: List<Point2D> = ArrayList(),
|
||||||
var layers: MutableList<Layer> = ArrayList()
|
var layers: MutableList<Layer> = ArrayList()
|
||||||
|
@ -31,6 +31,9 @@ fun GeometryBuilder<*>.face4(
|
|||||||
face(vertex1, vertex3, vertex4, normal, meta)
|
face(vertex1, vertex3, vertex4, normal, meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [Shape] is a [VisualObject3D] that can represent its own geometry as a set of polygons.
|
||||||
|
*/
|
||||||
interface Shape : VisualObject3D {
|
interface Shape : VisualObject3D {
|
||||||
fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>)
|
fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>)
|
||||||
}
|
}
|
||||||
|
@ -5,10 +5,13 @@ package hep.dataforge.vis.spatial
|
|||||||
import hep.dataforge.io.serialization.ConfigSerializer
|
import hep.dataforge.io.serialization.ConfigSerializer
|
||||||
import hep.dataforge.meta.Config
|
import hep.dataforge.meta.Config
|
||||||
import hep.dataforge.vis.common.AbstractVisualObject
|
import hep.dataforge.vis.common.AbstractVisualObject
|
||||||
|
import hep.dataforge.vis.common.set
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.UseSerializers
|
import kotlinx.serialization.UseSerializers
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
@SerialName("3d.label")
|
||||||
class Label3D(var text: String, var fontSize: Double, var fontFamily: String) : AbstractVisualObject(),
|
class Label3D(var text: String, var fontSize: Double, var fontFamily: String) : AbstractVisualObject(),
|
||||||
VisualObject3D {
|
VisualObject3D {
|
||||||
@Serializable(ConfigSerializer::class)
|
@Serializable(ConfigSerializer::class)
|
||||||
|
@ -7,16 +7,29 @@ import hep.dataforge.names.plus
|
|||||||
import hep.dataforge.values.ValueType
|
import hep.dataforge.values.ValueType
|
||||||
import hep.dataforge.vis.common.Colors
|
import hep.dataforge.vis.common.Colors
|
||||||
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_COLOR_KEY
|
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_COLOR_KEY
|
||||||
|
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_KEY
|
||||||
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_OPACITY_KEY
|
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_OPACITY_KEY
|
||||||
|
|
||||||
class Material3D(override val config: Config) : Specific {
|
class Material3D(override val config: Config) : Specific {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Primary web-color for the material
|
||||||
|
*/
|
||||||
var color by string(key = COLOR_KEY)
|
var color by string(key = COLOR_KEY)
|
||||||
|
|
||||||
var specularColor by string()
|
/**
|
||||||
|
* Specular color for phong material
|
||||||
|
*/
|
||||||
|
var specularColor by string(key = SPECULAR_COLOR_KEY)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opacity
|
||||||
|
*/
|
||||||
var opacity by float(1f, key = OPACITY_KEY)
|
var opacity by float(1f, key = OPACITY_KEY)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace material by wire frame
|
||||||
|
*/
|
||||||
var wireframe by boolean(false, WIREFRAME_KEY)
|
var wireframe by boolean(false, WIREFRAME_KEY)
|
||||||
|
|
||||||
companion object : Specification<Material3D> {
|
companion object : Specification<Material3D> {
|
||||||
@ -25,7 +38,7 @@ class Material3D(override val config: Config) : Specific {
|
|||||||
val MATERIAL_KEY = "material".asName()
|
val MATERIAL_KEY = "material".asName()
|
||||||
internal val COLOR_KEY = "color".asName()
|
internal val COLOR_KEY = "color".asName()
|
||||||
val MATERIAL_COLOR_KEY = MATERIAL_KEY + COLOR_KEY
|
val MATERIAL_COLOR_KEY = MATERIAL_KEY + COLOR_KEY
|
||||||
val SPECULAR_COLOR = "specularColor".asName()
|
val SPECULAR_COLOR_KEY = "specularColor".asName()
|
||||||
internal val OPACITY_KEY = "opacity".asName()
|
internal val OPACITY_KEY = "opacity".asName()
|
||||||
val MATERIAL_OPACITY_KEY = MATERIAL_KEY + OPACITY_KEY
|
val MATERIAL_OPACITY_KEY = MATERIAL_KEY + OPACITY_KEY
|
||||||
internal val WIREFRAME_KEY = "wireframe".asName()
|
internal val WIREFRAME_KEY = "wireframe".asName()
|
||||||
@ -54,10 +67,16 @@ class Material3D(override val config: Config) : Specific {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun VisualObject3D.color(rgb: String) {
|
/**
|
||||||
setProperty(MATERIAL_COLOR_KEY, rgb)
|
* Set color as web-color
|
||||||
|
*/
|
||||||
|
fun VisualObject3D.color(webColor: String) {
|
||||||
|
setProperty(MATERIAL_COLOR_KEY, webColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set color as integer
|
||||||
|
*/
|
||||||
fun VisualObject3D.color(rgb: Int) {
|
fun VisualObject3D.color(rgb: Int) {
|
||||||
setProperty(MATERIAL_COLOR_KEY, rgb)
|
setProperty(MATERIAL_COLOR_KEY, rgb)
|
||||||
}
|
}
|
||||||
@ -76,16 +95,15 @@ var VisualObject3D.color: String?
|
|||||||
setProperty(MATERIAL_COLOR_KEY, value)
|
setProperty(MATERIAL_COLOR_KEY, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
//var VisualObject3D.material: Material3D?
|
val VisualObject3D.material: Material3D?
|
||||||
// get() = getProperty(MATERIAL_KEY).node?.let { Material3D.wrap(it) }
|
get() = getProperty(MATERIAL_KEY).node?.let { Material3D.wrap(it) }
|
||||||
// set(value) = setProperty(MATERIAL_KEY, value?.config)
|
|
||||||
|
|
||||||
fun VisualObject3D.material(builder: Material3D.() -> Unit) {
|
fun VisualObject3D.material(builder: Material3D.() -> Unit) {
|
||||||
val node = config[Material3D.MATERIAL_KEY].node
|
val node = config[MATERIAL_KEY].node
|
||||||
if (node != null) {
|
if (node != null) {
|
||||||
Material3D.update(node, builder)
|
Material3D.update(node, builder)
|
||||||
} else {
|
} else {
|
||||||
config[Material3D.MATERIAL_KEY] = Material3D(builder)
|
config[MATERIAL_KEY] = Material3D(builder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,12 +4,17 @@ package hep.dataforge.vis.spatial
|
|||||||
|
|
||||||
import hep.dataforge.io.serialization.ConfigSerializer
|
import hep.dataforge.io.serialization.ConfigSerializer
|
||||||
import hep.dataforge.meta.Config
|
import hep.dataforge.meta.Config
|
||||||
|
import hep.dataforge.meta.number
|
||||||
|
import hep.dataforge.names.asName
|
||||||
|
import hep.dataforge.names.plus
|
||||||
import hep.dataforge.vis.common.AbstractVisualObject
|
import hep.dataforge.vis.common.AbstractVisualObject
|
||||||
import hep.dataforge.vis.common.number
|
import hep.dataforge.vis.common.set
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.UseSerializers
|
import kotlinx.serialization.UseSerializers
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
@SerialName("3d.line")
|
||||||
class PolyLine(var points: List<Point3D>) : AbstractVisualObject(), VisualObject3D {
|
class PolyLine(var points: List<Point3D>) : AbstractVisualObject(), VisualObject3D {
|
||||||
@Serializable(ConfigSerializer::class)
|
@Serializable(ConfigSerializer::class)
|
||||||
override var properties: Config? = null
|
override var properties: Config? = null
|
||||||
@ -19,7 +24,11 @@ class PolyLine(var points: List<Point3D>) : AbstractVisualObject(), VisualObject
|
|||||||
override var scale: Point3D? = null
|
override var scale: Point3D? = null
|
||||||
|
|
||||||
//var lineType by string()
|
//var lineType by string()
|
||||||
var thickness by number(1.0, key = "material.thickness")
|
var thickness by number(1.0, key = Material3D.MATERIAL_KEY + THICKNESS_KEY)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val THICKNESS_KEY = "thickness".asName()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,11 @@ import kotlin.collections.set
|
|||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("3d.proxy")
|
@SerialName("3d.proxy")
|
||||||
class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, VisualObject3D {
|
class Proxy private constructor(val templateName: Name) : AbstractVisualObject(), VisualGroup, VisualObject3D {
|
||||||
|
|
||||||
|
constructor(parent: VisualGroup3D, templateName: Name) : this(templateName) {
|
||||||
|
this.parent = parent
|
||||||
|
}
|
||||||
|
|
||||||
override var position: Point3D? = null
|
override var position: Point3D? = null
|
||||||
override var rotation: Point3D? = null
|
override var rotation: Point3D? = null
|
||||||
@ -59,7 +63,7 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua
|
|||||||
}
|
}
|
||||||
|
|
||||||
override val children: Map<NameToken, ProxyChild>
|
override val children: Map<NameToken, ProxyChild>
|
||||||
get() = (prototype as? MutableVisualGroup)?.children
|
get() = (prototype as? VisualGroup)?.children
|
||||||
?.filter { !it.key.toString().startsWith("@") }
|
?.filter { !it.key.toString().startsWith("@") }
|
||||||
?.mapValues {
|
?.mapValues {
|
||||||
ProxyChild(it.key.asName())
|
ProxyChild(it.key.asName())
|
||||||
@ -79,9 +83,12 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua
|
|||||||
|
|
||||||
override fun allProperties(): Laminate = Laminate(properties, mergedStyles, prototype.allProperties())
|
override fun allProperties(): Laminate = Laminate(properties, mergedStyles, prototype.allProperties())
|
||||||
|
|
||||||
|
override fun attachChildren() {
|
||||||
|
//do nothing
|
||||||
|
}
|
||||||
|
|
||||||
//override fun findAllStyles(): Laminate = Laminate((styles + prototype.styles).mapNotNull { findStyle(it) })
|
//override fun findAllStyles(): Laminate = Laminate((styles + prototype.styles).mapNotNull { findStyle(it) })
|
||||||
|
|
||||||
@Serializable
|
|
||||||
inner class ProxyChild(val name: Name) : AbstractVisualObject(), VisualGroup {
|
inner class ProxyChild(val name: Name) : AbstractVisualObject(), VisualGroup {
|
||||||
|
|
||||||
val prototype: VisualObject get() = prototypeFor(name)
|
val prototype: VisualObject get() = prototypeFor(name)
|
||||||
@ -125,6 +132,9 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun attachChildren() {
|
||||||
|
//do nothing
|
||||||
|
}
|
||||||
|
|
||||||
override fun allProperties(): Laminate = Laminate(properties, mergedStyles, prototype.allProperties())
|
override fun allProperties(): Laminate = Laminate(properties, mergedStyles, prototype.allProperties())
|
||||||
|
|
||||||
@ -149,7 +159,7 @@ inline fun VisualGroup3D.ref(
|
|||||||
templateName: Name,
|
templateName: Name,
|
||||||
name: String = "",
|
name: String = "",
|
||||||
block: Proxy.() -> Unit = {}
|
block: Proxy.() -> Unit = {}
|
||||||
) = Proxy(templateName).apply(block).also { set(name, it) }
|
) = Proxy(this, templateName).apply(block).also { set(name, it) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add new proxy wrapping given object and automatically adding it to the prototypes
|
* Add new proxy wrapping given object and automatically adding it to the prototypes
|
||||||
@ -162,7 +172,9 @@ fun VisualGroup3D.proxy(
|
|||||||
): Proxy {
|
): Proxy {
|
||||||
val existing = getPrototype(templateName)
|
val existing = getPrototype(templateName)
|
||||||
if (existing == null) {
|
if (existing == null) {
|
||||||
setPrototype(templateName, obj)
|
prototypes {
|
||||||
|
this[templateName] = obj
|
||||||
|
}
|
||||||
} else if (existing != obj) {
|
} else if (existing != obj) {
|
||||||
error("Can't add different prototype on top of existing one")
|
error("Can't add different prototype on top of existing one")
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,8 @@ package hep.dataforge.vis.spatial
|
|||||||
import hep.dataforge.io.serialization.ConfigSerializer
|
import hep.dataforge.io.serialization.ConfigSerializer
|
||||||
import hep.dataforge.meta.Config
|
import hep.dataforge.meta.Config
|
||||||
import hep.dataforge.vis.common.AbstractVisualObject
|
import hep.dataforge.vis.common.AbstractVisualObject
|
||||||
|
import hep.dataforge.vis.common.set
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.UseSerializers
|
import kotlinx.serialization.UseSerializers
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
@ -12,6 +14,7 @@ import kotlin.math.cos
|
|||||||
import kotlin.math.sin
|
import kotlin.math.sin
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
@SerialName("3d.sphere")
|
||||||
class Sphere(
|
class Sphere(
|
||||||
var radius: Float,
|
var radius: Float,
|
||||||
var phiStart: Float = 0f,
|
var phiStart: Float = 0f,
|
||||||
|
@ -4,6 +4,8 @@ package hep.dataforge.vis.spatial
|
|||||||
import hep.dataforge.io.serialization.ConfigSerializer
|
import hep.dataforge.io.serialization.ConfigSerializer
|
||||||
import hep.dataforge.meta.Config
|
import hep.dataforge.meta.Config
|
||||||
import hep.dataforge.vis.common.AbstractVisualObject
|
import hep.dataforge.vis.common.AbstractVisualObject
|
||||||
|
import hep.dataforge.vis.common.set
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.UseSerializers
|
import kotlinx.serialization.UseSerializers
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
@ -14,6 +16,7 @@ import kotlin.math.sin
|
|||||||
* Straight tube segment
|
* Straight tube segment
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
|
@SerialName("3d.tube")
|
||||||
class Tube(
|
class Tube(
|
||||||
var radius: Float,
|
var radius: Float,
|
||||||
var height: Float,
|
var height: Float,
|
||||||
|
@ -9,29 +9,32 @@ import hep.dataforge.io.serialization.MetaSerializer
|
|||||||
import hep.dataforge.io.serialization.NameSerializer
|
import hep.dataforge.io.serialization.NameSerializer
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
|
import hep.dataforge.names.toName
|
||||||
|
import hep.dataforge.vis.common.Visual
|
||||||
import hep.dataforge.vis.common.VisualObject
|
import hep.dataforge.vis.common.VisualObject
|
||||||
import hep.dataforge.vis.common.VisualPlugin
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.json.JsonConfiguration
|
import kotlinx.serialization.json.JsonConfiguration
|
||||||
import kotlinx.serialization.modules.SerializersModule
|
import kotlinx.serialization.modules.SerializersModule
|
||||||
import kotlinx.serialization.modules.contextual
|
import kotlinx.serialization.modules.contextual
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
class Visual3DPlugin(meta: Meta) : AbstractPlugin(meta) {
|
class Visual3D(meta: Meta) : AbstractPlugin(meta) {
|
||||||
|
|
||||||
|
val visual by require(Visual)
|
||||||
|
|
||||||
override val tag: PluginTag get() = Companion.tag
|
override val tag: PluginTag get() = Companion.tag
|
||||||
|
|
||||||
override fun provideTop(target: String): Map<Name, Any> {
|
override fun provideTop(target: String): Map<Name, Any> = if (target == Visual.VISUAL_FACTORY_TYPE) {
|
||||||
return if (target == VisualPlugin.VISUAL_FACTORY_TYPE) {
|
mapOf(Box.TYPE_NAME.toName() to Box)
|
||||||
mapOf()
|
|
||||||
} else {
|
} else {
|
||||||
emptyMap()
|
super.provideTop(target)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : PluginFactory<Visual3DPlugin> {
|
|
||||||
|
companion object : PluginFactory<Visual3D> {
|
||||||
override val tag: PluginTag = PluginTag(name = "visual.spatial", group = PluginTag.DATAFORGE_GROUP)
|
override val tag: PluginTag = PluginTag(name = "visual.spatial", group = PluginTag.DATAFORGE_GROUP)
|
||||||
override val type: KClass<out Visual3DPlugin> = Visual3DPlugin::class
|
override val type: KClass<out Visual3D> = Visual3D::class
|
||||||
override fun invoke(meta: Meta, context: Context): Visual3DPlugin = Visual3DPlugin(meta)
|
override fun invoke(meta: Meta, context: Context): Visual3D = Visual3D(meta)
|
||||||
|
|
||||||
val serialModule = SerializersModule {
|
val serialModule = SerializersModule {
|
||||||
contextual(Point3DSerializer)
|
contextual(Point3DSerializer)
|
@ -19,6 +19,7 @@ import hep.dataforge.names.isEmpty
|
|||||||
import hep.dataforge.vis.common.AbstractVisualGroup
|
import hep.dataforge.vis.common.AbstractVisualGroup
|
||||||
import hep.dataforge.vis.common.StyleSheet
|
import hep.dataforge.vis.common.StyleSheet
|
||||||
import hep.dataforge.vis.common.VisualObject
|
import hep.dataforge.vis.common.VisualObject
|
||||||
|
import hep.dataforge.vis.common.set
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.UseSerializers
|
import kotlinx.serialization.UseSerializers
|
||||||
@ -30,19 +31,19 @@ import kotlin.collections.set
|
|||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("group.3d")
|
@SerialName("group.3d")
|
||||||
class VisualGroup3D : AbstractVisualGroup(), VisualObject3D {
|
class VisualGroup3D : AbstractVisualGroup(), VisualObject3D {
|
||||||
|
|
||||||
|
override var styleSheet: StyleSheet? = null
|
||||||
|
private set
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A container for templates visible inside this group
|
* A container for templates visible inside this group
|
||||||
*/
|
*/
|
||||||
@SerialName(PROTOTYPES_KEY)
|
|
||||||
var prototypes: VisualGroup3D? = null
|
var prototypes: VisualGroup3D? = null
|
||||||
set(value) {
|
set(value) {
|
||||||
value?.parent = this
|
value?.parent = this
|
||||||
field = value
|
field = value
|
||||||
}
|
}
|
||||||
|
|
||||||
override var styleSheet: StyleSheet? = null
|
|
||||||
private set
|
|
||||||
|
|
||||||
//FIXME to be lifted to AbstractVisualGroup after https://github.com/Kotlin/kotlinx.serialization/issues/378 is fixed
|
//FIXME to be lifted to AbstractVisualGroup after https://github.com/Kotlin/kotlinx.serialization/issues/378 is fixed
|
||||||
override var properties: Config? = null
|
override var properties: Config? = null
|
||||||
|
|
||||||
@ -54,28 +55,34 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D {
|
|||||||
private val _children = HashMap<NameToken, VisualObject>()
|
private val _children = HashMap<NameToken, VisualObject>()
|
||||||
override val children: Map<NameToken, VisualObject> get() = _children
|
override val children: Map<NameToken, VisualObject> get() = _children
|
||||||
|
|
||||||
init {
|
// init {
|
||||||
//Do after deserialization
|
// //Do after deserialization
|
||||||
attachChildren()
|
// attachChildren()
|
||||||
|
// }
|
||||||
|
|
||||||
|
override fun attachChildren() {
|
||||||
|
prototypes?.parent = this
|
||||||
|
prototypes?.attachChildren()
|
||||||
|
super.attachChildren()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update or create stylesheet
|
* Update or create stylesheet
|
||||||
*/
|
*/
|
||||||
fun styleSheet(block: StyleSheet.() -> Unit) {
|
fun styleSheet(block: StyleSheet.() -> Unit) {
|
||||||
val res = this.styleSheet ?: StyleSheet(this).also { this.styleSheet = it }
|
val res = styleSheet ?: StyleSheet(this).also { styleSheet = it }
|
||||||
res.block()
|
res.block()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun removeChild(token: NameToken) {
|
override fun removeChild(token: NameToken) {
|
||||||
_children.remove(token)
|
_children.remove(token)?.run { parent = null }
|
||||||
childrenChanged(token.asName(), null)
|
childrenChanged(token.asName(), null)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setChild(token: NameToken, child: VisualObject) {
|
override fun setChild(token: NameToken, child: VisualObject) {
|
||||||
if (child.parent == null) {
|
if (child.parent == null) {
|
||||||
child.parent = this
|
child.parent = this
|
||||||
} else {
|
} else if (child.parent !== this) {
|
||||||
error("Can't reassign existing parent for $child")
|
error("Can't reassign existing parent for $child")
|
||||||
}
|
}
|
||||||
_children[token] = child
|
_children[token] = child
|
||||||
@ -102,42 +109,32 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun attachChildren() {
|
|
||||||
super.attachChildren()
|
|
||||||
prototypes?.run {
|
|
||||||
parent = this
|
|
||||||
attachChildren()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val PROTOTYPES_KEY = "templates"
|
// val PROTOTYPES_KEY = NameToken("@prototypes")
|
||||||
|
|
||||||
|
fun fromJson(json: String): VisualGroup3D =
|
||||||
|
Visual3D.json.parse(serializer(), json).also { it.attachChildren() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ger a prototype redirecting the request to the parent if prototype is not found
|
* Ger a prototype redirecting the request to the parent if prototype is not found
|
||||||
*/
|
*/
|
||||||
fun VisualGroup3D.getPrototype(name: Name): VisualObject3D? =
|
tailrec fun VisualGroup3D.getPrototype(name: Name): VisualObject3D? =
|
||||||
prototypes?.get(name) as? VisualObject3D ?: (parent as? VisualGroup3D)?.getPrototype(name)
|
prototypes?.get(name) as? VisualObject3D ?: (parent as? VisualGroup3D)?.getPrototype(name)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defined a prototype inside current group
|
* Create or edit prototype node as a group
|
||||||
*/
|
*/
|
||||||
fun VisualGroup3D.setPrototype(name: Name, obj: VisualObject3D) {
|
inline fun VisualGroup3D.prototypes(builder: VisualGroup3D.() -> Unit): Unit {
|
||||||
(prototypes ?: VisualGroup3D().also { this.prototypes = it })[name] = obj
|
(prototypes ?: VisualGroup3D().also { prototypes = it }).run(builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define a group with given [key], attach it to this parent and return it.
|
* Define a group with given [key], attach it to this parent and return it.
|
||||||
*/
|
*/
|
||||||
fun VisualGroup3D.group(key: String = "", action: VisualGroup3D.() -> Unit = {}): VisualGroup3D =
|
fun VisualGroup3D.group(key: String = "", action: VisualGroup3D.() -> Unit = {}): VisualGroup3D =
|
||||||
VisualGroup3D().apply(action).also { set(key, it) }
|
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -22,22 +22,10 @@ interface VisualObject3D : VisualObject {
|
|||||||
var rotation: Point3D?
|
var rotation: Point3D?
|
||||||
var scale: Point3D?
|
var scale: Point3D?
|
||||||
|
|
||||||
fun MetaBuilder.updatePosition() {
|
|
||||||
xPos to position?.x
|
|
||||||
yPos to position?.y
|
|
||||||
zPos to position?.z
|
|
||||||
xRotation to rotation?.x
|
|
||||||
yRotation to rotation?.y
|
|
||||||
zRotation to rotation?.z
|
|
||||||
xScale to scale?.x
|
|
||||||
yScale to scale?.y
|
|
||||||
zScale to scale?.z
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
val VISIBLE_KEY = "visible".asName()
|
val VISIBLE_KEY = "visible".asName()
|
||||||
val SELECTED_KEY = "selected".asName()
|
// val SELECTED_KEY = "selected".asName()
|
||||||
val DETAIL_KEY = "detail".asName()
|
val DETAIL_KEY = "detail".asName()
|
||||||
val LAYER_KEY = "layer".asName()
|
val LAYER_KEY = "layer".asName()
|
||||||
val IGNORE_KEY = "ignore".asName()
|
val IGNORE_KEY = "ignore".asName()
|
||||||
|
@ -46,8 +46,8 @@ object Point3DSerializer : KSerializer<Point3D> {
|
|||||||
when (val i = decodeElementIndex(descriptor)) {
|
when (val i = decodeElementIndex(descriptor)) {
|
||||||
CompositeDecoder.READ_DONE -> break@loop
|
CompositeDecoder.READ_DONE -> break@loop
|
||||||
0 -> x = decodeNullableSerializableElement(descriptor, 0, DoubleSerializer.nullable) ?: 0.0
|
0 -> x = decodeNullableSerializableElement(descriptor, 0, DoubleSerializer.nullable) ?: 0.0
|
||||||
1 -> y = decodeNullableSerializableElement(descriptor, 0, DoubleSerializer.nullable) ?: 0.0
|
1 -> y = decodeNullableSerializableElement(descriptor, 1, DoubleSerializer.nullable) ?: 0.0
|
||||||
2 -> z = decodeNullableSerializableElement(descriptor, 0, DoubleSerializer.nullable) ?: 0.0
|
2 -> z = decodeNullableSerializableElement(descriptor, 2, DoubleSerializer.nullable) ?: 0.0
|
||||||
else -> throw SerializationException("Unknown index $i")
|
else -> throw SerializationException("Unknown index $i")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,7 +79,7 @@ object Point2DSerializer : KSerializer<Point2D> {
|
|||||||
when (val i = decodeElementIndex(descriptor)) {
|
when (val i = decodeElementIndex(descriptor)) {
|
||||||
CompositeDecoder.READ_DONE -> break@loop
|
CompositeDecoder.READ_DONE -> break@loop
|
||||||
0 -> x = decodeNullableSerializableElement(descriptor, 0, DoubleSerializer.nullable) ?: 0.0
|
0 -> x = decodeNullableSerializableElement(descriptor, 0, DoubleSerializer.nullable) ?: 0.0
|
||||||
1 -> y = decodeNullableSerializableElement(descriptor, 0, DoubleSerializer.nullable) ?: 0.0
|
1 -> y = decodeNullableSerializableElement(descriptor, 1, DoubleSerializer.nullable) ?: 0.0
|
||||||
else -> throw SerializationException("Unknown index $i")
|
else -> throw SerializationException("Unknown index $i")
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -51,7 +51,9 @@ object RemoveSingleChild : VisualTreeTransform<VisualGroup3D>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
replaceChildren()
|
replaceChildren()
|
||||||
prototypes?.replaceChildren()
|
prototypes {
|
||||||
|
replaceChildren()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun VisualGroup3D.clone(): VisualGroup3D {
|
override fun VisualGroup3D.clone(): VisualGroup3D {
|
||||||
|
@ -6,6 +6,7 @@ import hep.dataforge.vis.common.MutableVisualGroup
|
|||||||
import hep.dataforge.vis.common.VisualGroup
|
import hep.dataforge.vis.common.VisualGroup
|
||||||
import hep.dataforge.vis.spatial.Proxy
|
import hep.dataforge.vis.spatial.Proxy
|
||||||
import hep.dataforge.vis.spatial.VisualGroup3D
|
import hep.dataforge.vis.spatial.VisualGroup3D
|
||||||
|
import hep.dataforge.vis.spatial.prototypes
|
||||||
|
|
||||||
object UnRef : VisualTreeTransform<VisualGroup3D>() {
|
object UnRef : VisualTreeTransform<VisualGroup3D>() {
|
||||||
private fun VisualGroup.countRefs(): Map<Name, Int> {
|
private fun VisualGroup.countRefs(): Map<Name, Int> {
|
||||||
|
@ -25,7 +25,7 @@ class ConvexTest {
|
|||||||
|
|
||||||
val convex = group.first() as Convex
|
val convex = group.first() as Convex
|
||||||
|
|
||||||
val json = Visual3DPlugin.json.toJson(Convex.serializer(), convex)
|
val json = Visual3D.json.toJson(Convex.serializer(), convex)
|
||||||
val meta = json.toMeta()
|
val meta = json.toMeta()
|
||||||
|
|
||||||
val points = meta.getIndexed("points").values.map { (it as MetaItem.NodeItem<*>).node.point3D()}
|
val points = meta.getIndexed("points").values.map { (it as MetaItem.NodeItem<*>).node.point3D()}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.vis.spatial.Visual3DPlugin.Companion.json
|
import hep.dataforge.vis.spatial.Visual3D.Companion.json
|
||||||
import kotlinx.serialization.ImplicitReflectionSerializer
|
import kotlinx.serialization.ImplicitReflectionSerializer
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
@ -31,12 +31,14 @@ interface ThreeFactory<in T : VisualObject> {
|
|||||||
/**
|
/**
|
||||||
* Update position, rotation and visibility
|
* Update position, rotation and visibility
|
||||||
*/
|
*/
|
||||||
fun Object3D.updatePosition(obj: VisualObject3D) {
|
fun Object3D.updatePosition(obj: VisualObject) {
|
||||||
visible = obj.visible ?: true
|
visible = obj.visible ?: true
|
||||||
|
if(obj is VisualObject3D) {
|
||||||
position.set(obj.x, obj.y, obj.z)
|
position.set(obj.x, obj.y, obj.z)
|
||||||
setRotationFromEuler(obj.euler)
|
setRotationFromEuler(obj.euler)
|
||||||
scale.set(obj.scaleX, obj.scaleY, obj.scaleZ)
|
scale.set(obj.scaleX, obj.scaleY, obj.scaleZ)
|
||||||
updateMatrix()
|
updateMatrix()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///**
|
///**
|
||||||
@ -54,7 +56,7 @@ fun Object3D.updatePosition(obj: VisualObject3D) {
|
|||||||
/**
|
/**
|
||||||
* Update non-position non-geometry property
|
* Update non-position non-geometry property
|
||||||
*/
|
*/
|
||||||
fun Object3D.updateProperty(source: VisualObject3D, propertyName: Name) {
|
fun Object3D.updateProperty(source: VisualObject, propertyName: Name) {
|
||||||
if (this is Mesh && propertyName.startsWith(MATERIAL_KEY)) {
|
if (this is Mesh && propertyName.startsWith(MATERIAL_KEY)) {
|
||||||
this.material = getMaterial(source)
|
this.material = getMaterial(source)
|
||||||
} else if (
|
} else if (
|
||||||
|
@ -25,7 +25,7 @@ object ThreeLabelFactory : ThreeFactory<Label3D> {
|
|||||||
} )
|
} )
|
||||||
return Mesh(textGeo, getMaterial(obj)).apply {
|
return Mesh(textGeo, getMaterial(obj)).apply {
|
||||||
updatePosition(obj)
|
updatePosition(obj)
|
||||||
obj.onPropertyChange(this@ThreeLabelFactory){name: Name, before: MetaItem<*>?, after: MetaItem<*>? ->
|
obj.onPropertyChange(this@ThreeLabelFactory){ _: Name, _: MetaItem<*>?, _: MetaItem<*>? ->
|
||||||
//TODO
|
//TODO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,11 +18,10 @@ object ThreeLineFactory : ThreeFactory<PolyLine> {
|
|||||||
vertices = obj.points.toTypedArray()
|
vertices = obj.points.toTypedArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
val material =
|
val material = ThreeMaterials.getLineMaterial(obj.getProperty(MeshThreeFactory.EDGES_MATERIAL_KEY).node)
|
||||||
ThreeMaterials.getLineMaterial(obj.getProperty(MeshThreeFactory.EDGES_MATERIAL_KEY).node)
|
|
||||||
|
|
||||||
material.linewidth = obj.thickness.toDouble()
|
material.linewidth = obj.thickness.toDouble()
|
||||||
material.color = obj.color?.let { Color(it) }?: DEFAULT_LINE_COLOR
|
material.color = obj.color?.let { Color(it) } ?: DEFAULT_LINE_COLOR
|
||||||
|
|
||||||
return LineSegments(geometry, material).apply {
|
return LineSegments(geometry, material).apply {
|
||||||
updatePosition(obj)
|
updatePosition(obj)
|
||||||
|
@ -3,8 +3,8 @@ package hep.dataforge.vis.spatial.three
|
|||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
import hep.dataforge.values.ValueType
|
import hep.dataforge.values.ValueType
|
||||||
import hep.dataforge.vis.common.Colors
|
import hep.dataforge.vis.common.Colors
|
||||||
|
import hep.dataforge.vis.common.VisualObject
|
||||||
import hep.dataforge.vis.spatial.Material3D
|
import hep.dataforge.vis.spatial.Material3D
|
||||||
import hep.dataforge.vis.spatial.VisualObject3D
|
|
||||||
import info.laht.threekt.materials.LineBasicMaterial
|
import info.laht.threekt.materials.LineBasicMaterial
|
||||||
import info.laht.threekt.materials.Material
|
import info.laht.threekt.materials.Material
|
||||||
import info.laht.threekt.materials.MeshBasicMaterial
|
import info.laht.threekt.materials.MeshBasicMaterial
|
||||||
@ -37,12 +37,12 @@ object ThreeMaterials {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getMaterial(visualObject3D: VisualObject3D): Material {
|
fun getMaterial(visualObject3D: VisualObject): Material {
|
||||||
val meta = visualObject3D.getProperty(Material3D.MATERIAL_KEY).node ?: return ThreeMaterials.DEFAULT
|
val meta = visualObject3D.getProperty(Material3D.MATERIAL_KEY).node ?: return ThreeMaterials.DEFAULT
|
||||||
return if (meta[Material3D.SPECULAR_COLOR] != null) {
|
return if (meta[Material3D.SPECULAR_COLOR_KEY] != null) {
|
||||||
MeshPhongMaterial().apply {
|
MeshPhongMaterial().apply {
|
||||||
color = meta[Material3D.COLOR_KEY]?.getColor() ?: DEFAULT_COLOR
|
color = meta[Material3D.COLOR_KEY]?.getColor() ?: DEFAULT_COLOR
|
||||||
specular = meta[Material3D.SPECULAR_COLOR]!!.getColor()
|
specular = meta[Material3D.SPECULAR_COLOR_KEY]!!.getColor()
|
||||||
opacity = meta[Material3D.OPACITY_KEY]?.double ?: 1.0
|
opacity = meta[Material3D.OPACITY_KEY]?.double ?: 1.0
|
||||||
transparent = opacity < 1.0
|
transparent = opacity < 1.0
|
||||||
wireframe = meta[Material3D.WIREFRAME_KEY].boolean ?: false
|
wireframe = meta[Material3D.WIREFRAME_KEY].boolean ?: false
|
||||||
|
@ -74,8 +74,8 @@ class ThreePlugin : AbstractPlugin() {
|
|||||||
return@onChildrenChange
|
return@onChildrenChange
|
||||||
}
|
}
|
||||||
|
|
||||||
val parentName = name.cutLast()
|
// val parentName = name.cutLast()
|
||||||
val childName = name.last()!!
|
// val childName = name.last()!!
|
||||||
|
|
||||||
//removing old object
|
//removing old object
|
||||||
findChild(name)?.let { oldChild ->
|
findChild(name)?.let { oldChild ->
|
||||||
|
@ -25,7 +25,7 @@ class ThreeProxyFactory(val three: ThreePlugin) : ThreeFactory<Proxy> {
|
|||||||
if (name.first()?.body == PROXY_CHILD_PROPERTY_PREFIX) {
|
if (name.first()?.body == PROXY_CHILD_PROPERTY_PREFIX) {
|
||||||
val childName = name.first()?.index?.toName() ?: error("Wrong syntax for proxy child property: '$name'")
|
val childName = name.first()?.index?.toName() ?: error("Wrong syntax for proxy child property: '$name'")
|
||||||
val propertyName = name.cutFirst()
|
val propertyName = name.cutFirst()
|
||||||
val proxyChild = obj[childName] as? VisualObject3D ?: error("Proxy child with name '$childName' not found or not a 3D object")
|
val proxyChild = obj[childName] ?: error("Proxy child with name '$childName' not found")
|
||||||
val child = object3D.findChild(childName)?: error("Object child with name '$childName' not found")
|
val child = object3D.findChild(childName)?: error("Object child with name '$childName' not found")
|
||||||
child.updateProperty(proxyChild, propertyName)
|
child.updateProperty(proxyChild, propertyName)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package hep.dataforge.vis.spatial.three
|
package hep.dataforge.vis.spatial.three
|
||||||
|
|
||||||
import hep.dataforge.js.requireJS
|
import hep.dataforge.js.requireJS
|
||||||
import hep.dataforge.vis.js.editor.card
|
import hep.dataforge.vis.js.editor.accordion
|
||||||
import hep.dataforge.vis.spatial.Visual3DPlugin
|
import hep.dataforge.vis.spatial.Visual3D
|
||||||
import hep.dataforge.vis.spatial.VisualGroup3D
|
import hep.dataforge.vis.spatial.VisualGroup3D
|
||||||
import kotlinx.html.InputType
|
import kotlinx.html.InputType
|
||||||
import kotlinx.html.TagConsumer
|
import kotlinx.html.TagConsumer
|
||||||
@ -28,7 +28,8 @@ private fun saveData(event: Event, fileName: String, mimeType: String = "text/pl
|
|||||||
fun Element.displayCanvasControls(canvas: ThreeCanvas, block: TagConsumer<HTMLElement>.() -> Unit = {}) {
|
fun Element.displayCanvasControls(canvas: ThreeCanvas, block: TagConsumer<HTMLElement>.() -> Unit = {}) {
|
||||||
clear()
|
clear()
|
||||||
append {
|
append {
|
||||||
card("Settings") {
|
accordion("controls") {
|
||||||
|
entry("Settings") {
|
||||||
div("row") {
|
div("row") {
|
||||||
div("col-2") {
|
div("col-2") {
|
||||||
label("checkbox-inline") {
|
label("checkbox-inline") {
|
||||||
@ -46,7 +47,63 @@ fun Element.displayCanvasControls(canvas: ThreeCanvas, block: TagConsumer<HTMLEl
|
|||||||
+"Export"
|
+"Export"
|
||||||
onClickFunction = {
|
onClickFunction = {
|
||||||
val json = (canvas.content as? VisualGroup3D)?.let { group ->
|
val json = (canvas.content as? VisualGroup3D)?.let { group ->
|
||||||
Visual3DPlugin.json.stringify(
|
Visual3D.json.stringify(
|
||||||
|
VisualGroup3D.serializer(),
|
||||||
|
group
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (json != null) {
|
||||||
|
saveData(it, "object.json", "text/json") {
|
||||||
|
json
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entry("Layers") {
|
||||||
|
div("row") {
|
||||||
|
(0..11).forEach { layer ->
|
||||||
|
div("col-1") {
|
||||||
|
label { +layer.toString() }
|
||||||
|
input(type = InputType.checkBox).apply {
|
||||||
|
if (layer == 0) {
|
||||||
|
checked = true
|
||||||
|
}
|
||||||
|
onChangeFunction = {
|
||||||
|
if (checked) {
|
||||||
|
canvas.camera.layers.enable(layer)
|
||||||
|
} else {
|
||||||
|
canvas.camera.layers.disable(layer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 ->
|
||||||
|
Visual3D.json.stringify(
|
||||||
VisualGroup3D.serializer(),
|
VisualGroup3D.serializer(),
|
||||||
group
|
group
|
||||||
)
|
)
|
||||||
@ -81,7 +138,7 @@ fun Element.displayCanvasControls(canvas: ThreeCanvas, block: TagConsumer<HTMLEl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
block()
|
block()
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -66,7 +66,7 @@ fun MetaItem<*>?.material(): Material {
|
|||||||
is MetaItem.NodeItem -> PhongMaterial().apply {
|
is MetaItem.NodeItem -> PhongMaterial().apply {
|
||||||
val opacity = node[Material3D.OPACITY_KEY].double ?: 1.0
|
val opacity = node[Material3D.OPACITY_KEY].double ?: 1.0
|
||||||
diffuseColor = node[Material3D.COLOR_KEY]?.color(opacity) ?: Color.DARKGREY
|
diffuseColor = node[Material3D.COLOR_KEY]?.color(opacity) ?: Color.DARKGREY
|
||||||
specularColor = node[Material3D.SPECULAR_COLOR]?.color(opacity) ?: Color.WHITE
|
specularColor = node[Material3D.SPECULAR_COLOR_KEY]?.color(opacity) ?: Color.WHITE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,8 @@ class FXProxyFactory(val plugin: FX3DPlugin) : FX3DFactory<Proxy> {
|
|||||||
override val type: KClass<in Proxy> get() = Proxy::class
|
override val type: KClass<in Proxy> get() = Proxy::class
|
||||||
|
|
||||||
override fun invoke(obj: Proxy, binding: VisualObjectFXBinding): Node {
|
override fun invoke(obj: Proxy, binding: VisualObjectFXBinding): Node {
|
||||||
val template = obj.prototype
|
val prototype = obj.prototype
|
||||||
val node = plugin.buildNode(template)
|
val node = plugin.buildNode(prototype)
|
||||||
|
|
||||||
obj.onPropertyChange(this) { name, _, _ ->
|
obj.onPropertyChange(this) { name, _, _ ->
|
||||||
if (name.first()?.body == Proxy.PROXY_CHILD_PROPERTY_PREFIX) {
|
if (name.first()?.body == Proxy.PROXY_CHILD_PROPERTY_PREFIX) {
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
import org.fxyz3d.geometry.Point3D as FXPoint3D
|
||||||
|
|
||||||
actual data class Point2D(actual var x: Double, actual var y: Double) {
|
actual data class Point2D(actual var x: Double, actual var y: Double) {
|
||||||
actual constructor(x: Number, y: Number) : this(x.toDouble(), y.toDouble())
|
actual constructor(x: Number, y: Number) : this(x.toDouble(), y.toDouble())
|
||||||
}
|
}
|
||||||
|
|
||||||
actual class Point3D(val point: org.fxyz3d.geometry.Point3D) {
|
actual class Point3D(val point: FXPoint3D) {
|
||||||
actual constructor(x: Number, y: Number, z: Number) : this(
|
actual constructor(x: Number, y: Number, z: Number) : this(
|
||||||
org.fxyz3d.geometry.Point3D(
|
FXPoint3D(
|
||||||
x.toFloat(),
|
x.toFloat(),
|
||||||
y.toFloat(),
|
y.toFloat(),
|
||||||
z.toFloat()
|
z.toFloat()
|
||||||
@ -32,7 +33,7 @@ actual class Point3D(val point: org.fxyz3d.geometry.Point3D) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
return this.point == (other as? hep.dataforge.vis.spatial.Point3D)?.point
|
return this.point == (other as? Point3D)?.point
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
|
@ -27,6 +27,11 @@ kotlin {
|
|||||||
api(project(":dataforge-vis-spatial-gdml"))
|
api(project(":dataforge-vis-spatial-gdml"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
jvmMain{
|
||||||
|
dependencies {
|
||||||
|
api("org.fxyz3d:fxyz3d:0.5.2")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
package hep.dataforge.vis.spatial.gdml.demo
|
||||||
|
|
||||||
|
import scientifik.gdml.*
|
||||||
|
|
||||||
|
|
||||||
|
fun cubes(): GDML = GDML {
|
||||||
|
val center = define.position("center")
|
||||||
|
structure {
|
||||||
|
val air = ref<GDMLMaterial>("G4_AIR")
|
||||||
|
val tubeMaterial = ref<GDMLMaterial>("tube")
|
||||||
|
val boxMaterial = ref<GDMLMaterial>("box")
|
||||||
|
val segment = solids.tube("segment", 20, 5.0) {
|
||||||
|
rmin = 17
|
||||||
|
deltaphi = 60
|
||||||
|
aunit = DEG
|
||||||
|
}
|
||||||
|
val worldBox = solids.box("LargeBox", 200, 200, 200)
|
||||||
|
val smallBox = solids.box("smallBox", 30, 30, 30)
|
||||||
|
val segmentVolume = volume("segment", tubeMaterial, segment.ref()) {}
|
||||||
|
val circle = volume("composite", boxMaterial, smallBox.ref()) {
|
||||||
|
for (i in 0 until 6) {
|
||||||
|
physVolume(segmentVolume) {
|
||||||
|
name = "segment$i"
|
||||||
|
positionref = center.ref()
|
||||||
|
rotation {
|
||||||
|
z = 60 * i
|
||||||
|
unit = DEG
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
world = volume("world", air, worldBox.ref()) {
|
||||||
|
for (i in 0 until 3) {
|
||||||
|
for (j in 0 until 3) {
|
||||||
|
for (k in 0 until 3) {
|
||||||
|
physVolume(circle) {
|
||||||
|
name = "composite$i$j$k"
|
||||||
|
position {
|
||||||
|
x = (-50 + i * 50)
|
||||||
|
y = (-50 + j * 50)
|
||||||
|
z = (-50 + k * 50)
|
||||||
|
}
|
||||||
|
rotation {
|
||||||
|
x = i * 120
|
||||||
|
y = j * 120
|
||||||
|
z = 120 * k
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package hep.dataforge.vis.spatial.gdml
|
||||||
|
|
||||||
|
import hep.dataforge.meta.string
|
||||||
|
import hep.dataforge.names.toName
|
||||||
|
import hep.dataforge.vis.spatial.Material3D
|
||||||
|
import hep.dataforge.vis.spatial.gdml.demo.cubes
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class GDMLVisualTest {
|
||||||
|
@Test
|
||||||
|
fun testPrototypeProperty() {
|
||||||
|
val gdml = cubes()
|
||||||
|
val visual = gdml.toVisual()
|
||||||
|
visual["composite000.segment0".toName()]?.setProperty(Material3D.MATERIAL_COLOR_KEY, "red")
|
||||||
|
assertEquals("red", visual["composite000.segment0".toName()]?.getProperty(Material3D.MATERIAL_COLOR_KEY).string)
|
||||||
|
}
|
||||||
|
}
|
@ -14,7 +14,6 @@ import hep.dataforge.vis.js.editor.displayPropertyEditor
|
|||||||
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_COLOR_KEY
|
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.Material3D.Companion.MATERIAL_OPACITY_KEY
|
||||||
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_WIREFRAME_KEY
|
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_WIREFRAME_KEY
|
||||||
import hep.dataforge.vis.spatial.Visual3DPlugin
|
|
||||||
import hep.dataforge.vis.spatial.VisualGroup3D
|
import hep.dataforge.vis.spatial.VisualGroup3D
|
||||||
import hep.dataforge.vis.spatial.VisualObject3D
|
import hep.dataforge.vis.spatial.VisualObject3D
|
||||||
import hep.dataforge.vis.spatial.VisualObject3D.Companion.VISIBLE_KEY
|
import hep.dataforge.vis.spatial.VisualObject3D.Companion.VISIBLE_KEY
|
||||||
@ -25,11 +24,7 @@ import hep.dataforge.vis.spatial.three.ThreePlugin
|
|||||||
import hep.dataforge.vis.spatial.three.displayCanvasControls
|
import hep.dataforge.vis.spatial.three.displayCanvasControls
|
||||||
import hep.dataforge.vis.spatial.three.output
|
import hep.dataforge.vis.spatial.three.output
|
||||||
import hep.dataforge.vis.spatial.visible
|
import hep.dataforge.vis.spatial.visible
|
||||||
import kotlinx.html.dom.append
|
import org.w3c.dom.*
|
||||||
import kotlinx.html.js.p
|
|
||||||
import org.w3c.dom.DragEvent
|
|
||||||
import org.w3c.dom.HTMLDivElement
|
|
||||||
import org.w3c.dom.HTMLElement
|
|
||||||
import org.w3c.files.FileList
|
import org.w3c.files.FileList
|
||||||
import org.w3c.files.FileReader
|
import org.w3c.files.FileReader
|
||||||
import org.w3c.files.get
|
import org.w3c.files.get
|
||||||
@ -81,17 +76,18 @@ private class GDMLDemoApp : Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun message(message: String?) {
|
private fun message(message: String?) {
|
||||||
document.getElementById("messages")?.let { element ->
|
console.log(message)
|
||||||
if (message == null) {
|
// document.getElementById("messages")?.let { element ->
|
||||||
element.clear()
|
// if (message == null) {
|
||||||
} else {
|
// element.clear()
|
||||||
element.append {
|
// } else {
|
||||||
p {
|
// element.append {
|
||||||
+message
|
// p {
|
||||||
}
|
// +message
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
private val gdmlConfiguration: GDMLTransformer.() -> Unit = {
|
private val gdmlConfiguration: GDMLTransformer.() -> Unit = {
|
||||||
@ -128,7 +124,7 @@ private class GDMLDemoApp : Application {
|
|||||||
//val url = URL("https://drive.google.com/open?id=1w5e7fILMN83JGgB8WANJUYm8OW2s0WVO")
|
//val url = URL("https://drive.google.com/open?id=1w5e7fILMN83JGgB8WANJUYm8OW2s0WVO")
|
||||||
|
|
||||||
val canvasElement = document.getElementById("canvas") ?: error("Element with id 'canvas' not found on page")
|
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 configElement = document.getElementById("config") ?: error("Element with id 'layers' not found on page")
|
||||||
val treeElement = document.getElementById("tree") ?: error("Element with id 'tree' 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")
|
val editorElement = document.getElementById("editor") ?: error("Element with id 'editor' not found on page")
|
||||||
canvasElement.clear()
|
canvasElement.clear()
|
||||||
@ -136,15 +132,14 @@ private class GDMLDemoApp : Application {
|
|||||||
val action: (name: String, data: String) -> Unit = { name, data ->
|
val action: (name: String, data: String) -> Unit = { name, data ->
|
||||||
canvasElement.clear()
|
canvasElement.clear()
|
||||||
spinner(true)
|
spinner(true)
|
||||||
|
val visual: VisualObject3D = when {
|
||||||
|
name.endsWith(".gdml") || name.endsWith(".xml") -> {
|
||||||
message("Loading GDML")
|
message("Loading GDML")
|
||||||
val gdml = GDML.format.parse(GDML.serializer(), data)
|
val gdml = GDML.format.parse(GDML.serializer(), data)
|
||||||
message("Converting GDML into DF-VIS format")
|
message("Converting GDML into DF-VIS format")
|
||||||
|
gdml.toVisual(gdmlConfiguration)
|
||||||
val visual: VisualObject3D = when {
|
|
||||||
name.endsWith(".gdml") || name.endsWith(".xml") -> gdml.toVisual(gdmlConfiguration)
|
|
||||||
name.endsWith(".json") -> {
|
|
||||||
Visual3DPlugin.json.parse(VisualGroup3D.serializer(), data).apply { attachChildren() }
|
|
||||||
}
|
}
|
||||||
|
name.endsWith(".json") -> VisualGroup3D.fromJson(data)
|
||||||
else -> {
|
else -> {
|
||||||
window.alert("File extension is not recognized: $name")
|
window.alert("File extension is not recognized: $name")
|
||||||
error("File extension is not recognized: $name")
|
error("File extension is not recognized: $name")
|
||||||
@ -187,9 +182,9 @@ private class GDMLDemoApp : Application {
|
|||||||
// canvas.clickListener = ::selectElement
|
// canvas.clickListener = ::selectElement
|
||||||
|
|
||||||
//tree.visualObjectTree(visual, editor::propertyEditor)
|
//tree.visualObjectTree(visual, editor::propertyEditor)
|
||||||
treeElement.displayObjectTree(visual) { name ->
|
treeElement.displayObjectTree(visual) { treeName ->
|
||||||
selectElement(name)
|
selectElement(treeName)
|
||||||
canvas.highlight(name)
|
canvas.highlight(treeName)
|
||||||
}
|
}
|
||||||
canvas.render(visual)
|
canvas.render(visual)
|
||||||
|
|
||||||
@ -204,6 +199,19 @@ private class GDMLDemoApp : Application {
|
|||||||
addEventListener("dragover", { handleDragOver(it as DragEvent) }, false)
|
addEventListener("dragover", { handleDragOver(it as DragEvent) }, false)
|
||||||
addEventListener("drop", { loadData(it as DragEvent, action) }, false)
|
addEventListener("drop", { loadData(it as DragEvent, action) }, false)
|
||||||
}
|
}
|
||||||
|
(document.getElementById("file_load_button") as? HTMLInputElement)?.apply {
|
||||||
|
addEventListener("change", {
|
||||||
|
(it.target as HTMLInputElement).files?.asList()?.first()?.let { file ->
|
||||||
|
FileReader().apply {
|
||||||
|
onload = {
|
||||||
|
val string = result as String
|
||||||
|
action(file.name, string)
|
||||||
|
}
|
||||||
|
readAsText(file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, false)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
.drop_zone {
|
||||||
|
outline: 1px solid orange;
|
||||||
|
}
|
||||||
|
|
||||||
.loader {
|
.loader {
|
||||||
border: 16px solid #f3f3f3; /* Light grey */
|
border: 16px solid #f3f3f3; /* Light grey */
|
||||||
border-top: 16px solid #3498db; /* Blue */
|
border-top: 16px solid #3498db; /* Blue */
|
||||||
|
@ -4,34 +4,45 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<!-- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">-->
|
<!-- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">-->
|
||||||
<title>Three js demo for particle physics</title>
|
<title>Three js demo for particle physics</title>
|
||||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
|
|
||||||
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
|
|
||||||
<link rel="stylesheet" href="css/main.css">
|
|
||||||
<link rel="stylesheet" href="css/jsoneditor.min.css">
|
|
||||||
<script type="text/javascript" src="main.bundle.js"></script>
|
<script type="text/javascript" src="main.bundle.js"></script>
|
||||||
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
|
||||||
|
<link rel="stylesheet" href="css/jsoneditor.min.css">
|
||||||
|
<link rel="stylesheet" href="css/main.css">
|
||||||
</head>
|
</head>
|
||||||
<body class="testApp">
|
<body class="testApp">
|
||||||
<div class="container" id="drop_zone" data-toggle="tooltip" data-placement="right"
|
|
||||||
title="To load data in text format, drag-and-drop file here">
|
|
||||||
Load data
|
|
||||||
<br/>
|
|
||||||
(drag file here)
|
|
||||||
</div>
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>GDML demo</h1>
|
<h1>GDML demo</h1>
|
||||||
</div>
|
</div>
|
||||||
<!--<div class="container loader" id="loader" style="display:none;"></div>-->
|
|
||||||
<div class="container animate-bottom" id="messages"></div>
|
|
||||||
|
|
||||||
<div class="container-fluid">
|
<div class="container-fluid h-100">
|
||||||
<div class="row">
|
<div class="row h-100">
|
||||||
<div class="col-lg-3" id="tree"></div>
|
<div class="col-lg-3">
|
||||||
<div class="col-lg-6">
|
<div class="card">
|
||||||
<div class="row" id="layers"></div>
|
<div class="card-body">
|
||||||
<div class="row container" id="canvas"></div>
|
<a>Load file:</a>
|
||||||
|
<input type="file" id="file_load_button" accept=".gdml, application/xml, application/json"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body" id="drop_zone">
|
||||||
|
Load data
|
||||||
|
<br/>
|
||||||
|
(drag file here)
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="overflow-auto" id="tree"></div>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<div id="canvas"></div>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-3">
|
||||||
|
<div class="row" id="config"></div>
|
||||||
|
<div class="row" id="editor"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-3" id="editor"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script></body>
|
||||||
</html>
|
</html>
|
@ -4,15 +4,13 @@ import hep.dataforge.context.Global
|
|||||||
import hep.dataforge.vis.fx.editor.VisualObjectEditorFragment
|
import hep.dataforge.vis.fx.editor.VisualObjectEditorFragment
|
||||||
import hep.dataforge.vis.fx.editor.VisualObjectTreeFragment
|
import hep.dataforge.vis.fx.editor.VisualObjectTreeFragment
|
||||||
import hep.dataforge.vis.spatial.Material3D
|
import hep.dataforge.vis.spatial.Material3D
|
||||||
|
import hep.dataforge.vis.spatial.Visual3D
|
||||||
|
import hep.dataforge.vis.spatial.VisualGroup3D
|
||||||
import hep.dataforge.vis.spatial.fx.FX3DPlugin
|
import hep.dataforge.vis.spatial.fx.FX3DPlugin
|
||||||
import hep.dataforge.vis.spatial.fx.FXCanvas3D
|
import hep.dataforge.vis.spatial.fx.FXCanvas3D
|
||||||
import hep.dataforge.vis.spatial.gdml.LUnit
|
|
||||||
import hep.dataforge.vis.spatial.gdml.readFile
|
|
||||||
import hep.dataforge.vis.spatial.gdml.toVisual
|
|
||||||
import javafx.geometry.Orientation
|
import javafx.geometry.Orientation
|
||||||
import javafx.scene.Parent
|
import javafx.scene.Parent
|
||||||
import javafx.stage.FileChooser
|
import javafx.stage.FileChooser
|
||||||
import scientifik.gdml.GDML
|
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
|
||||||
class GDMLDemoApp : App(GDMLView::class)
|
class GDMLDemoApp : App(GDMLView::class)
|
||||||
@ -36,26 +34,12 @@ class GDMLView : View() {
|
|||||||
override val root: Parent = borderpane {
|
override val root: Parent = borderpane {
|
||||||
top {
|
top {
|
||||||
buttonbar {
|
buttonbar {
|
||||||
button("Load GDML") {
|
button("Load GDML/json") {
|
||||||
action {
|
action {
|
||||||
val file = chooseFile("Select a GDML file", filters = gdmlFilter).firstOrNull()
|
val file = chooseFile("Select a GDML/json file", filters = fileNameFilter).firstOrNull()
|
||||||
if (file != null) {
|
?: return@action
|
||||||
val obj = GDML.readFile(file.toPath()).toVisual {
|
val visual: VisualGroup3D = Visual3D.readFile(file)
|
||||||
lUnit = LUnit.CM
|
canvas.render(visual)
|
||||||
|
|
||||||
solidConfiguration = { parent, solid ->
|
|
||||||
if (solid.name == "cave") {
|
|
||||||
setProperty(Material3D.MATERIAL_WIREFRAME_KEY, true)
|
|
||||||
}
|
|
||||||
if (parent.physVolumes.isNotEmpty()) {
|
|
||||||
useStyle("opaque") {
|
|
||||||
Material3D.MATERIAL_OPACITY_KEY put 0.3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
canvas.render(obj)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -68,8 +52,11 @@ class GDMLView : View() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val gdmlFilter = arrayOf(
|
private val fileNameFilter = arrayOf(
|
||||||
FileChooser.ExtensionFilter("GDML", "*.gdml", "*.xml")
|
FileChooser.ExtensionFilter("GDML", "*.gdml", "*.xml"),
|
||||||
|
FileChooser.ExtensionFilter("JSON", "*.json"),
|
||||||
|
FileChooser.ExtensionFilter("JSON.ZIP", "*.json.zip"),
|
||||||
|
FileChooser.ExtensionFilter("JSON.GZ", "*.json.gz")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
package hep.dataforge.vis.spatial.gdml.demo
|
||||||
|
|
||||||
|
import hep.dataforge.vis.spatial.Material3D
|
||||||
|
import hep.dataforge.vis.spatial.Visual3D
|
||||||
|
import hep.dataforge.vis.spatial.VisualGroup3D
|
||||||
|
import hep.dataforge.vis.spatial.gdml.LUnit
|
||||||
|
import hep.dataforge.vis.spatial.gdml.readFile
|
||||||
|
import hep.dataforge.vis.spatial.gdml.toVisual
|
||||||
|
import scientifik.gdml.GDML
|
||||||
|
import java.io.File
|
||||||
|
import java.util.zip.GZIPInputStream
|
||||||
|
import java.util.zip.ZipInputStream
|
||||||
|
|
||||||
|
fun Visual3D.Companion.readFile(file: File): VisualGroup3D = when {
|
||||||
|
file.extension == "gdml" || file.extension == "xml" -> {
|
||||||
|
GDML.readFile(file.toPath()).toVisual {
|
||||||
|
lUnit = LUnit.CM
|
||||||
|
|
||||||
|
solidConfiguration = { parent, solid ->
|
||||||
|
if (solid.name == "cave") {
|
||||||
|
setProperty(Material3D.MATERIAL_WIREFRAME_KEY, true)
|
||||||
|
}
|
||||||
|
if (parent.physVolumes.isNotEmpty()) {
|
||||||
|
useStyle("opaque") {
|
||||||
|
Material3D.MATERIAL_OPACITY_KEY put 0.3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file.extension == "json" -> VisualGroup3D.fromJson(file.readText())
|
||||||
|
file.name.endsWith("json.zip") -> {
|
||||||
|
file.inputStream().use {
|
||||||
|
val unzip = ZipInputStream(it, Charsets.UTF_8)
|
||||||
|
val text = unzip.readAllBytes().decodeToString()
|
||||||
|
VisualGroup3D.fromJson(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file.name.endsWith("json.gz") -> {
|
||||||
|
file.inputStream().use {
|
||||||
|
val unzip = GZIPInputStream(it)
|
||||||
|
val text = unzip.readAllBytes().decodeToString()
|
||||||
|
VisualGroup3D.fromJson(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> error("Unknown extension ${file.extension}")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Visual3D.Companion.readFile(fileName: String): VisualGroup3D = readFile(File(fileName))
|
@ -0,0 +1,19 @@
|
|||||||
|
package hep.dataforge.vis.spatial.gdml.demo
|
||||||
|
|
||||||
|
import hep.dataforge.vis.spatial.Visual3D
|
||||||
|
import hep.dataforge.vis.spatial.VisualGroup3D
|
||||||
|
import hep.dataforge.vis.spatial.gdml.LUnit
|
||||||
|
import hep.dataforge.vis.spatial.gdml.readFile
|
||||||
|
import hep.dataforge.vis.spatial.gdml.toVisual
|
||||||
|
import scientifik.gdml.GDML
|
||||||
|
import java.io.File
|
||||||
|
import java.nio.file.Paths
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val gdml = GDML.readFile(Paths.get("D:\\Work\\Projects\\gdml.kt\\gdml-source\\cubes.gdml"))
|
||||||
|
val visual = gdml.toVisual {
|
||||||
|
lUnit = LUnit.CM
|
||||||
|
}
|
||||||
|
val json = Visual3D.json.stringify(VisualGroup3D.serializer(), visual)
|
||||||
|
File("D:\\Work\\Projects\\gdml.kt\\gdml-source\\cubes.json").writeText(json)
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
|
import hep.dataforge.names.asName
|
||||||
|
import org.junit.Test
|
||||||
|
import kotlin.test.Ignore
|
||||||
|
|
||||||
|
class FileSerializationTest {
|
||||||
|
@Test
|
||||||
|
@Ignore
|
||||||
|
fun testFileRead(){
|
||||||
|
val text = this::class.java.getResourceAsStream("/cubes.json").readAllBytes().decodeToString()
|
||||||
|
val visual = VisualGroup3D.fromJson(text)
|
||||||
|
visual["composite_001".asName()]
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,7 @@ import hep.dataforge.vis.js.editor.displayPropertyEditor
|
|||||||
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_COLOR_KEY
|
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.Material3D.Companion.MATERIAL_OPACITY_KEY
|
||||||
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_WIREFRAME_KEY
|
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_WIREFRAME_KEY
|
||||||
import hep.dataforge.vis.spatial.Visual3DPlugin
|
import hep.dataforge.vis.spatial.Visual3D
|
||||||
import hep.dataforge.vis.spatial.VisualObject3D
|
import hep.dataforge.vis.spatial.VisualObject3D
|
||||||
import hep.dataforge.vis.spatial.VisualObject3D.Companion.VISIBLE_KEY
|
import hep.dataforge.vis.spatial.VisualObject3D.Companion.VISIBLE_KEY
|
||||||
import hep.dataforge.vis.spatial.three.ThreePlugin
|
import hep.dataforge.vis.spatial.three.ThreePlugin
|
||||||
@ -35,13 +35,13 @@ import org.w3c.dom.HTMLElement
|
|||||||
import kotlin.browser.document
|
import kotlin.browser.document
|
||||||
import kotlin.dom.clear
|
import kotlin.dom.clear
|
||||||
|
|
||||||
private class GDMLDemoApp : Application {
|
private class MMDemoApp : Application {
|
||||||
|
|
||||||
private val model = Model()
|
private val model = Model()
|
||||||
|
|
||||||
private val connection = HttpClient {
|
private val connection = HttpClient {
|
||||||
install(JsonFeature) {
|
install(JsonFeature) {
|
||||||
serializer = KotlinxSerializer(Visual3DPlugin.json)
|
serializer = KotlinxSerializer(Visual3D.json)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,5 +122,5 @@ private class GDMLDemoApp : Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
startApplication(::GDMLDemoApp)
|
startApplication(::MMDemoApp)
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package ru.mipt.npm.muon.monitor.server
|
package ru.mipt.npm.muon.monitor.server
|
||||||
|
|
||||||
|
|
||||||
import hep.dataforge.vis.spatial.Visual3DPlugin
|
import hep.dataforge.vis.spatial.Visual3D
|
||||||
import io.ktor.application.Application
|
import io.ktor.application.Application
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
import io.ktor.application.install
|
import io.ktor.application.install
|
||||||
@ -35,7 +35,7 @@ fun Application.module() {
|
|||||||
install(DefaultHeaders)
|
install(DefaultHeaders)
|
||||||
install(CallLogging)
|
install(CallLogging)
|
||||||
install(ContentNegotiation) {
|
install(ContentNegotiation) {
|
||||||
serialization(json = Visual3DPlugin.json)
|
serialization(json = Visual3D.json)
|
||||||
}
|
}
|
||||||
install(Routing) {
|
install(Routing) {
|
||||||
get("/event") {
|
get("/event") {
|
||||||
|
@ -7,6 +7,7 @@ import hep.dataforge.meta.number
|
|||||||
import hep.dataforge.names.plus
|
import hep.dataforge.names.plus
|
||||||
import hep.dataforge.names.startsWith
|
import hep.dataforge.names.startsWith
|
||||||
import hep.dataforge.vis.common.getProperty
|
import hep.dataforge.vis.common.getProperty
|
||||||
|
import hep.dataforge.vis.common.set
|
||||||
import hep.dataforge.vis.common.setProperty
|
import hep.dataforge.vis.common.setProperty
|
||||||
import hep.dataforge.vis.spatial.*
|
import hep.dataforge.vis.spatial.*
|
||||||
import hep.dataforge.vis.spatial.VisualObject3D.Companion.GEOMETRY_KEY
|
import hep.dataforge.vis.spatial.VisualObject3D.Companion.GEOMETRY_KEY
|
||||||
|
BIN
doc/resources/class-diag-3d.png
Normal file
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
BIN
doc/resources/class-diag-common.png
Normal file
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
BIN
doc/resources/gdml-demo.png
Normal file
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 97 KiB |
BIN
doc/resources/muon-monitor.png
Normal file
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
BIN
doc/resources/spatial-showcase.png
Normal file
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |