Update architecture
This commit is contained in:
parent
4865c76158
commit
d874c3cdd6
@ -9,7 +9,7 @@ buildscript {
|
||||
val dokkaVersion: String by rootProject.extra("0.9.17")
|
||||
val serializationVersion: String by rootProject.extra("0.10.0")
|
||||
|
||||
val dataforgeVersion: String by rootProject.extra("0.1.1-dev-5")
|
||||
val dataforgeVersion: String by rootProject.extra("0.1.2-dev-1")
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
@ -40,6 +40,7 @@ allprojects {
|
||||
jcenter()
|
||||
maven("https://kotlin.bintray.com/kotlinx")
|
||||
maven("http://npm.mipt.ru:8081/artifactory/gradle-dev")
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
group = "hep.dataforge"
|
||||
|
@ -11,19 +11,19 @@ kotlin {
|
||||
sourceSets {
|
||||
val commonMain by getting {
|
||||
dependencies {
|
||||
api("hep.dataforge:dataforge-io:$dataforgeVersion")
|
||||
api("hep.dataforge:dataforge-io-metadata:$dataforgeVersion")
|
||||
api("hep.dataforge:dataforge-output:$dataforgeVersion")
|
||||
//api("hep.dataforge:dataforge-output-metadata:$dataforgeVersion")
|
||||
}
|
||||
}
|
||||
val jvmMain by getting {
|
||||
dependencies {
|
||||
api("hep.dataforge:dataforge-io-jvm:$dataforgeVersion")
|
||||
api("hep.dataforge:dataforge-output-jvm:$dataforgeVersion")
|
||||
//api("no.tornado:tornadofx:1.7.18")
|
||||
}
|
||||
}
|
||||
val jsMain by getting {
|
||||
dependencies {
|
||||
api("hep.dataforge:dataforge-io-js:$dataforgeVersion")
|
||||
api("hep.dataforge:dataforge-output-js:$dataforgeVersion")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,14 @@
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.context.Global
|
||||
import hep.dataforge.context.members
|
||||
import hep.dataforge.meta.number
|
||||
import hep.dataforge.meta.set
|
||||
import hep.dataforge.vis.ApplicationBase
|
||||
import hep.dataforge.vis.DisplayGroup
|
||||
import hep.dataforge.vis.require
|
||||
import hep.dataforge.vis.spatial.gdml.gdml
|
||||
import hep.dataforge.vis.spatial.jsroot.JSRootPlugin
|
||||
import hep.dataforge.vis.spatial.jsroot.jsRoot
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.isActive
|
||||
@ -22,6 +24,23 @@ class ThreeDemoApp : ApplicationBase() {
|
||||
override fun start(state: Map<String, Any>) {
|
||||
require("JSRootGeoBase.js")
|
||||
|
||||
|
||||
//TODO remove after DI fix
|
||||
Global.plugins.load(ThreePlugin())
|
||||
Global.plugins.load(JSRootPlugin())
|
||||
|
||||
// Global.plugins.load(JSRootPlugin)
|
||||
|
||||
println(Global.plugins.count())
|
||||
|
||||
Global.plugins.forEach {
|
||||
println(it)
|
||||
}
|
||||
|
||||
Global.members<ThreeFactory<*>>(ThreeFactory.TYPE).forEach {
|
||||
println(it)
|
||||
}
|
||||
|
||||
val renderer = ThreeOutput(Global)
|
||||
renderer.start(document.getElementById("canvas")!!)
|
||||
println("started")
|
||||
@ -53,7 +72,7 @@ class ThreeDemoApp : ApplicationBase() {
|
||||
// point(-50, -50, 50)
|
||||
// point(-50, 50, 50)
|
||||
// }
|
||||
gdml {
|
||||
jsRoot {
|
||||
y = 110.0
|
||||
shape = box(50, 50, 50)
|
||||
}
|
||||
|
@ -0,0 +1,100 @@
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.meta.boolean
|
||||
import hep.dataforge.provider.Type
|
||||
import hep.dataforge.vis.DisplayObject
|
||||
import hep.dataforge.vis.get
|
||||
import hep.dataforge.vis.onChange
|
||||
import hep.dataforge.vis.spatial.ThreeFactory.Companion.TYPE
|
||||
import hep.dataforge.vis.spatial.ThreeFactory.Companion.buildMesh
|
||||
import hep.dataforge.vis.spatial.ThreeFactory.Companion.updateMesh
|
||||
import hep.dataforge.vis.spatial.three.ConvexGeometry
|
||||
import hep.dataforge.vis.spatial.three.EdgesGeometry
|
||||
import hep.dataforge.vis.spatial.three.euler
|
||||
import info.laht.threekt.core.BufferGeometry
|
||||
import info.laht.threekt.core.Object3D
|
||||
import info.laht.threekt.geometries.BoxBufferGeometry
|
||||
import info.laht.threekt.geometries.WireframeGeometry
|
||||
import info.laht.threekt.math.Vector3
|
||||
import info.laht.threekt.objects.LineSegments
|
||||
import info.laht.threekt.objects.Mesh
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
internal val DisplayObject.material get() = this["color"].material()
|
||||
|
||||
/**
|
||||
* Builder and updater for three.js object
|
||||
*/
|
||||
@Type(TYPE)
|
||||
interface ThreeFactory<T : DisplayObject> {
|
||||
|
||||
val type: KClass<out T>
|
||||
|
||||
operator fun invoke(obj: T): Object3D
|
||||
|
||||
companion object {
|
||||
const val TYPE = "threeFactory"
|
||||
|
||||
/**
|
||||
* Update position, rotation and visibility
|
||||
*/
|
||||
internal fun updatePosition(obj: DisplayObject, target: Object3D) {
|
||||
target.apply {
|
||||
position.set(obj.x, obj.y, obj.z)
|
||||
setRotationFromEuler(obj.euler)
|
||||
scale.set(obj.scaleX, obj.scaleY, obj.scaleZ)
|
||||
visible = obj.visible
|
||||
}
|
||||
}
|
||||
|
||||
internal fun buildMesh(obj: DisplayObject, geometry: BufferGeometry): Mesh {
|
||||
val mesh = Mesh(geometry, obj.material)
|
||||
if (obj["edges.enabled"]?.boolean != false) {
|
||||
val material = obj["edges.material"]?.material() ?: Materials.DEFAULT
|
||||
mesh.add(LineSegments(EdgesGeometry(mesh.geometry as BufferGeometry), material))
|
||||
}
|
||||
|
||||
if (obj["wireframe.enabled"]?.boolean == true) {
|
||||
val material = obj["edges.material"]?.material() ?: Materials.DEFAULT
|
||||
mesh.add(LineSegments(WireframeGeometry(mesh.geometry as BufferGeometry), material))
|
||||
}
|
||||
return mesh
|
||||
}
|
||||
|
||||
internal fun updateMesh(obj: DisplayObject, geometry: BufferGeometry, mesh: Mesh) {
|
||||
mesh.geometry = geometry
|
||||
mesh.material = obj.material
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class MeshThreeFactory<T : DisplayObject>(override val type: KClass<out T>) : ThreeFactory<T> {
|
||||
/**
|
||||
* Build an object
|
||||
*/
|
||||
abstract fun buildGeometry(obj: T): BufferGeometry
|
||||
|
||||
|
||||
override fun invoke(obj: T): Mesh {
|
||||
val geometry = buildGeometry(obj)
|
||||
val mesh = buildMesh(obj, geometry)
|
||||
ThreeFactory.updatePosition(obj, mesh)
|
||||
obj.onChange(this) { _, _, _ ->
|
||||
ThreeFactory.updatePosition(obj, mesh)
|
||||
updateMesh(obj, buildGeometry(obj), mesh)
|
||||
}
|
||||
return mesh
|
||||
}
|
||||
}
|
||||
|
||||
object ThreeBoxFactory : MeshThreeFactory<Box>(Box::class) {
|
||||
override fun buildGeometry(obj: Box) =
|
||||
BoxBufferGeometry(obj.xSize, obj.ySize, obj.zSize)
|
||||
}
|
||||
|
||||
fun Point3D.asVector(): Vector3 = this.asDynamic() as Vector3
|
||||
|
||||
object ThreeConvexFactory : MeshThreeFactory<Convex>(Convex::class) {
|
||||
override fun buildGeometry(obj: Convex) =
|
||||
ConvexGeometry(obj.points.map { it.asVector() }.toTypedArray())
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.vis.DisplayObject
|
||||
import hep.dataforge.vis.get
|
||||
import hep.dataforge.vis.onChange
|
||||
import hep.dataforge.vis.spatial.three.ConvexGeometry
|
||||
import hep.dataforge.vis.spatial.three.EdgesGeometry
|
||||
import hep.dataforge.vis.spatial.three.euler
|
||||
import info.laht.threekt.core.Object3D
|
||||
import info.laht.threekt.geometries.BoxBufferGeometry
|
||||
import info.laht.threekt.math.Vector3
|
||||
import info.laht.threekt.objects.LineSegments
|
||||
import info.laht.threekt.objects.Mesh
|
||||
|
||||
/**
|
||||
* Builder and updater for three.js object
|
||||
*/
|
||||
interface ThreeObjectBuilder<in T : DisplayObject> {
|
||||
|
||||
operator fun invoke(obj: T): Object3D
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Update position, rotation and visibility
|
||||
*/
|
||||
internal fun updatePosition(obj: DisplayObject, target: Object3D) {
|
||||
target.apply {
|
||||
position.set(obj.x, obj.y, obj.z)
|
||||
setRotationFromEuler(obj.euler)
|
||||
scale.set(obj.scaleX, obj.scaleY, obj.scaleZ)
|
||||
visible = obj.visible
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class GenericThreeBuilder<in T : DisplayObject, R : Object3D> : ThreeObjectBuilder<T> {
|
||||
/**
|
||||
* Build an object
|
||||
*/
|
||||
abstract fun build(obj: T): R
|
||||
|
||||
/**
|
||||
* Update an object
|
||||
*/
|
||||
abstract fun update(obj: T, target: R)
|
||||
|
||||
override fun invoke(obj: T): R {
|
||||
val target = build(obj)
|
||||
ThreeObjectBuilder.updatePosition(obj, target)
|
||||
obj.onChange(this) { _, _, _ ->
|
||||
ThreeObjectBuilder.updatePosition(obj, target)
|
||||
update(obj, target)
|
||||
}
|
||||
return target
|
||||
}
|
||||
}
|
||||
|
||||
object ThreeBoxBuilder : GenericThreeBuilder<Box, Mesh>() {
|
||||
override fun build(obj: Box): Mesh {
|
||||
val geometry = BoxBufferGeometry(obj.xSize, obj.ySize, obj.zSize)
|
||||
return Mesh(geometry, obj["color"].material()).also { mesh ->
|
||||
mesh.add(LineSegments(EdgesGeometry(geometry), Materials.DEFAULT))
|
||||
}
|
||||
}
|
||||
|
||||
override fun update(obj: Box, target: Mesh) {
|
||||
target.geometry = BoxBufferGeometry(obj.xSize, obj.ySize, obj.zSize)
|
||||
target.material = obj["color"].material()
|
||||
}
|
||||
}
|
||||
|
||||
fun Point3D.asVector(): Vector3 = this.asDynamic() as Vector3
|
||||
|
||||
object ThreeConvexBuilder: GenericThreeBuilder<Convex,Mesh>(){
|
||||
override fun build(obj: Convex): Mesh {
|
||||
val geometry = ConvexGeometry(obj.points.map { it.asVector() }.toTypedArray())
|
||||
return Mesh(geometry, obj["color"].material()).also { mesh ->
|
||||
mesh.add(LineSegments(EdgesGeometry(geometry), Materials.DEFAULT))
|
||||
}
|
||||
}
|
||||
|
||||
override fun update(obj: Convex, target: Mesh) {
|
||||
target.geometry = ConvexGeometry(obj.points.map { it.asVector() }.toTypedArray())
|
||||
target.material = obj["color"].material()
|
||||
}
|
||||
}
|
@ -1,12 +1,11 @@
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.context.Context
|
||||
import hep.dataforge.io.Output
|
||||
import hep.dataforge.context.members
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.output.Output
|
||||
import hep.dataforge.vis.DisplayGroup
|
||||
import hep.dataforge.vis.DisplayObject
|
||||
import hep.dataforge.vis.spatial.gdml.GDMLObject
|
||||
import hep.dataforge.vis.spatial.gdml.ThreeGDMLBuilder
|
||||
import hep.dataforge.vis.spatial.three.Group
|
||||
import info.laht.threekt.WebGLRenderer
|
||||
import info.laht.threekt.cameras.PerspectiveCamera
|
||||
@ -17,6 +16,7 @@ import info.laht.threekt.math.ColorConstants
|
||||
import info.laht.threekt.scenes.Scene
|
||||
import org.w3c.dom.Element
|
||||
import kotlin.browser.window
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
class ThreeOutput(override val context: Context) : Output<DisplayObject> {
|
||||
|
||||
@ -65,15 +65,19 @@ class ThreeOutput(override val context: Context) : Output<DisplayObject> {
|
||||
private fun buildNode(obj: DisplayObject): Object3D? {
|
||||
return when (obj) {
|
||||
is DisplayGroup -> Group(obj.children.mapNotNull { buildNode(it) }).apply {
|
||||
ThreeObjectBuilder.updatePosition(obj, this)
|
||||
ThreeFactory.updatePosition(obj, this)
|
||||
}
|
||||
is Box -> ThreeBoxBuilder(obj)
|
||||
is GDMLObject -> ThreeGDMLBuilder(obj)
|
||||
//is Convex -> ThreeConvexBuilder(obj)
|
||||
else -> null
|
||||
//is Box -> ThreeBoxFactory(obj)
|
||||
//is JSRootObject -> ThreeJSRootFactory(obj)
|
||||
//is Convex -> ThreeConvexFactory(obj)
|
||||
else -> findFactory(obj::class)?.invoke(obj)?: error("Factory not found")
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T : DisplayObject> findFactory(type: KClass<out T>): ThreeFactory<T>? {
|
||||
return context.members<ThreeFactory<*>>(ThreeFactory.TYPE).find { it.type == type } as? ThreeFactory<T>?
|
||||
}
|
||||
|
||||
override fun render(obj: DisplayObject, meta: Meta) {
|
||||
buildNode(obj)?.let {
|
||||
scene.add(it)
|
||||
|
@ -0,0 +1,38 @@
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.context.AbstractPlugin
|
||||
import hep.dataforge.context.PluginFactory
|
||||
import hep.dataforge.context.PluginTag
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.toName
|
||||
|
||||
class ThreePlugin : AbstractPlugin() {
|
||||
override val tag: PluginTag get() = ThreePlugin.tag
|
||||
|
||||
val factories = HashMap<Name, ThreeFactory<*>>()
|
||||
|
||||
init {
|
||||
factories["box".toName()] = ThreeBoxFactory
|
||||
factories["convex".toName()] = ThreeConvexFactory
|
||||
}
|
||||
|
||||
override fun listTop(target: String): Sequence<Name> {
|
||||
return when (target) {
|
||||
ThreeFactory.TYPE -> factories.keys.asSequence()
|
||||
else -> return super.listTop(target)
|
||||
}
|
||||
}
|
||||
|
||||
override fun provideTop(target: String, name: Name): Any? {
|
||||
return when (target) {
|
||||
ThreeFactory.TYPE -> factories[name]
|
||||
else -> return super.provideTop(target, name)
|
||||
}
|
||||
}
|
||||
|
||||
companion object : PluginFactory<ThreePlugin> {
|
||||
override val tag = PluginTag("vis.three", "hep.dataforge")
|
||||
override val type = ThreePlugin::class
|
||||
override fun build() = ThreePlugin()
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
@file:JsModule("JSRootGeoBase.js")
|
||||
@file:JsNonModule
|
||||
package hep.dataforge.vis.spatial.gdml
|
||||
|
||||
import info.laht.threekt.core.Geometry
|
||||
|
||||
external fun createGeometry(shape: dynamic, limit: Int): Geometry
|
@ -0,0 +1,8 @@
|
||||
@file:JsModule("JSRootGeoBase.js")
|
||||
@file:JsNonModule
|
||||
|
||||
package hep.dataforge.vis.spatial.jsroot
|
||||
|
||||
import info.laht.threekt.core.BufferGeometry
|
||||
|
||||
external fun createGeometry(shape: dynamic, limit: Int): BufferGeometry
|
@ -1,18 +1,14 @@
|
||||
package hep.dataforge.vis.spatial.gdml
|
||||
package hep.dataforge.vis.spatial.jsroot
|
||||
|
||||
import hep.dataforge.meta.EmptyMeta
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.MetaItem
|
||||
import hep.dataforge.meta.buildMeta
|
||||
import hep.dataforge.vis.*
|
||||
import hep.dataforge.vis.spatial.GenericThreeBuilder
|
||||
import hep.dataforge.vis.spatial.Materials
|
||||
import hep.dataforge.vis.spatial.material
|
||||
import hep.dataforge.vis.spatial.three.EdgesGeometry
|
||||
import info.laht.threekt.objects.LineSegments
|
||||
import info.laht.threekt.objects.Mesh
|
||||
import hep.dataforge.vis.spatial.MeshThreeFactory
|
||||
import info.laht.threekt.core.BufferGeometry
|
||||
|
||||
class GDMLObject(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, TYPE, meta) {
|
||||
class JSRootObject(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, TYPE, meta) {
|
||||
|
||||
var shape by node()
|
||||
|
||||
@ -45,6 +41,9 @@ class GDMLObject(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, TYPE,
|
||||
"fNode._typename" to "TGeoSubtraction"
|
||||
}
|
||||
|
||||
/**
|
||||
* Intersect two GDML geometries
|
||||
*/
|
||||
infix fun Meta.intersect(other: Meta) = buildMeta {
|
||||
"fNode.fLeft" to this
|
||||
"fNode.fRight" to other
|
||||
@ -52,13 +51,12 @@ class GDMLObject(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, TYPE,
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TYPE = "geometry.spatial.gdml"
|
||||
const val TYPE = "geometry.spatial.jsRoot"
|
||||
}
|
||||
}
|
||||
|
||||
//TODO add Zelenyy GDML builder here
|
||||
fun DisplayGroup.gdml(meta: Meta = EmptyMeta, action: GDMLObject.() -> Unit = {}) =
|
||||
GDMLObject(this, meta).apply(action).also { addChild(it) }
|
||||
fun DisplayGroup.jsRoot(meta: Meta = EmptyMeta, action: JSRootObject.() -> Unit = {}) =
|
||||
JSRootObject(this, meta).apply(action).also { addChild(it) }
|
||||
|
||||
fun Meta.toDynamic(): dynamic {
|
||||
fun MetaItem<*>.toDynamic(): dynamic = when (this) {
|
||||
@ -78,19 +76,9 @@ fun Meta.toDynamic(): dynamic {
|
||||
}
|
||||
|
||||
|
||||
object ThreeGDMLBuilder : GenericThreeBuilder<GDMLObject, Mesh>() {
|
||||
override fun build(obj: GDMLObject): Mesh {
|
||||
object ThreeJSRootFactory : MeshThreeFactory<JSRootObject>(JSRootObject::class) {
|
||||
override fun buildGeometry(obj: JSRootObject): BufferGeometry {
|
||||
val shapeMeta = obj.shape?.toDynamic() ?: error("The shape not defined")
|
||||
println(shapeMeta)
|
||||
val geometry = createGeometry(shapeMeta, obj.facesLimit)
|
||||
return Mesh(geometry, obj.color.material()).also { mesh ->
|
||||
mesh.add(LineSegments(EdgesGeometry(geometry), Materials.DEFAULT))
|
||||
}
|
||||
}
|
||||
|
||||
override fun update(obj: GDMLObject, target: Mesh) {
|
||||
val shapeMeta: dynamic = obj.shape?.toDynamic()
|
||||
target.geometry = createGeometry(shapeMeta, obj.facesLimit)
|
||||
target.material = obj.color.material()
|
||||
return createGeometry(shapeMeta, obj.facesLimit)
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package hep.dataforge.vis.spatial.jsroot
|
||||
|
||||
import hep.dataforge.context.AbstractPlugin
|
||||
import hep.dataforge.context.Context
|
||||
import hep.dataforge.context.PluginFactory
|
||||
import hep.dataforge.context.PluginTag
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.vis.spatial.ThreePlugin
|
||||
|
||||
class JSRootPlugin : AbstractPlugin() {
|
||||
override val tag: PluginTag get() = JSRootPlugin.tag
|
||||
|
||||
override fun dependsOn() = listOf(ThreePlugin)
|
||||
|
||||
override fun attach(context: Context) {
|
||||
super.attach(context)
|
||||
context.plugins.get<ThreePlugin>()?.factories?.set("ThreeJSRootFactory".toName(), ThreeJSRootFactory)
|
||||
}
|
||||
|
||||
companion object: PluginFactory<JSRootPlugin> {
|
||||
override val tag = PluginTag("vis.jsroot", "hep.dataforge")
|
||||
override val type = JSRootPlugin::class
|
||||
override fun build() = JSRootPlugin()
|
||||
}
|
||||
}
|
@ -15,7 +15,7 @@ class Box(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, TYPE, meta)
|
||||
//TODO add helper for color configuration
|
||||
|
||||
companion object {
|
||||
const val TYPE = "geometry.spatial.box"
|
||||
const val TYPE = "geometry.3d.box"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ class Convex(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, TYPE, met
|
||||
val points = points(properties["points"] ?: error("Vertices not defined"))
|
||||
|
||||
companion object {
|
||||
const val TYPE = "geometry.spatial.convex"
|
||||
const val TYPE = "geometry.3d.convex"
|
||||
|
||||
fun points(item: MetaItem<*>): List<Point3D> {
|
||||
return item.node?.getAll("point".toName())?.map { (_, value) ->
|
||||
|
@ -11,7 +11,7 @@ class Extruded(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, TYPE, m
|
||||
val shape get() = shape(properties["shape"] ?: error("Shape not defined"))
|
||||
|
||||
companion object {
|
||||
const val TYPE = "geometry.spatial.extruded"
|
||||
const val TYPE = "geometry.3d.extruded"
|
||||
|
||||
fun shape(item: MetaItem<*>): Shape2D {
|
||||
return item.node?.getAll("xyPoint".toName())?.map { (_, value) ->
|
||||
|
@ -1,7 +1,7 @@
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.io.Output
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.output.Output
|
||||
import hep.dataforge.vis.DisplayGroup
|
||||
import hep.dataforge.vis.DisplayNode
|
||||
import hep.dataforge.vis.DisplayObject
|
||||
|
Loading…
Reference in New Issue
Block a user