forked from kscience/visionforge
GDML model in progress
This commit is contained in:
parent
9a7fcfe9c6
commit
953bafb02e
@ -13,7 +13,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.2-dev-2")
|
||||
val dataforgeVersion: String by rootProject.extra("0.1.2-dev-3")
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
|
@ -8,11 +8,16 @@ plugins {
|
||||
id("org.jetbrains.kotlin.frontend")
|
||||
}
|
||||
|
||||
repositories{
|
||||
maven ("https://dl.bintray.com/orangy/maven" )
|
||||
}
|
||||
|
||||
val kotlinVersion: String by rootProject.extra
|
||||
|
||||
dependencies {
|
||||
api(project(":dataforge-vis-spatial"))
|
||||
implementation(project(":dataforge-vis-spatial"))
|
||||
implementation("info.laht.threekt:threejs-wrapper:0.88-npm-2")
|
||||
//implementation("org.jetbrains.kotlinx:kotlinx-files-js:0.1.0-dev-27")
|
||||
testCompile("org.jetbrains.kotlin:kotlin-test-js:$kotlinVersion")
|
||||
}
|
||||
|
||||
@ -22,6 +27,9 @@ configure<KotlinFrontendExtension> {
|
||||
configure<NpmExtension> {
|
||||
dependency("three-full")
|
||||
dependency("style-loader")
|
||||
// dependency("fs-remote")
|
||||
// dependency("path")
|
||||
// dependency("text-encoding")
|
||||
devDependency("karma")
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,8 @@ import hep.dataforge.vis.ApplicationBase
|
||||
import hep.dataforge.vis.DisplayGroup
|
||||
import hep.dataforge.vis.require
|
||||
import hep.dataforge.vis.spatial.jsroot.JSRootPlugin
|
||||
import hep.dataforge.vis.spatial.jsroot.jsRoot
|
||||
import hep.dataforge.vis.spatial.jsroot.jsRootGeometry
|
||||
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.isActive
|
||||
@ -65,7 +66,7 @@ class ThreeDemoApp : ApplicationBase() {
|
||||
point(-50, 50, -50)
|
||||
point(50, -50, -50)
|
||||
}
|
||||
jsRoot {
|
||||
jsRootGeometry {
|
||||
y = 110.0
|
||||
shape = box(50, 50, 50)
|
||||
color(12285)
|
||||
|
@ -0,0 +1,40 @@
|
||||
package hep.dataforge.vis.spatial.gdml
|
||||
|
||||
import hep.dataforge.meta.Config
|
||||
|
||||
class GDML {
|
||||
private var defines: List<GDMLDefine> = emptyList()
|
||||
private var solids: Map<String, GDMLSolid> = emptyMap()
|
||||
|
||||
fun define(block: GDMLDefineBuilder.() -> Unit) {
|
||||
defines = GDMLDefineBuilder().apply(block).defines
|
||||
}
|
||||
|
||||
fun solids(block: GDMLSolidBuilder.() -> Unit) {
|
||||
solids = GDMLSolidBuilder().apply(block).solids
|
||||
}
|
||||
}
|
||||
|
||||
class GDMLDefineBuilder {
|
||||
internal val defines = ArrayList<GDMLDefine>()
|
||||
|
||||
fun position(block: GDMLPosition.() -> Unit) {
|
||||
defines.add(GDMLPosition(Config()).apply(block))
|
||||
}
|
||||
|
||||
fun rotation(block: GDMLRotation.() -> Unit) {
|
||||
defines.add(GDMLRotation(Config()).apply(block))
|
||||
}
|
||||
}
|
||||
|
||||
class GDMLSolidBuilder {
|
||||
internal val solids = HashMap<String, GDMLSolid>()
|
||||
|
||||
private fun put(solid: GDMLSolid) {
|
||||
solids[solid.pName!!] = solid
|
||||
}
|
||||
|
||||
fun box(block: GDMLBox.() -> Unit) = put(GDMLBox.build(block))
|
||||
fun tube(block: GDMLTube.() -> Unit) = put(GDMLTube.build(block))
|
||||
fun xtru(block: GDMLXtru.() -> Unit) = put(GDMLXtru.build(block))
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
package hep.dataforge.vis.spatial.gdml
|
||||
|
||||
import hep.dataforge.meta.*
|
||||
|
||||
sealed class GDMLNode(override val config: Config) : Specification {
|
||||
var pName by string()
|
||||
}
|
||||
|
||||
sealed class GDMLDefine(config: Config) : GDMLNode(config)
|
||||
|
||||
class GDMLPosition(config: Config) : GDMLDefine(config) {
|
||||
var x by number(0f).float
|
||||
var y by number(0f).float
|
||||
var z by number(0f).float
|
||||
var unit by string("cm")
|
||||
}
|
||||
|
||||
class GDMLRotation(config: Config) : GDMLDefine(config) {
|
||||
var x by number(0f).float
|
||||
var y by number(0f).float
|
||||
var z by number(0f).float
|
||||
var unit by string("deg")
|
||||
}
|
||||
|
||||
|
||||
|
||||
sealed class GDMLSolid(config: Config) : GDMLNode(config) {
|
||||
abstract val type: String
|
||||
}
|
||||
|
||||
class GDMLBox(config: Config) : GDMLSolid(config) {
|
||||
override val type: String = "box"
|
||||
|
||||
var pDx by number().double
|
||||
var pDy by number().double
|
||||
var pDz by number().double
|
||||
|
||||
companion object : SpecificationCompanion<GDMLBox> {
|
||||
override fun wrap(config: Config): GDMLBox = GDMLBox(config)
|
||||
}
|
||||
}
|
||||
|
||||
class GDMLTube(config: Config) : GDMLSolid(config) {
|
||||
override val type: String = "tube"
|
||||
|
||||
var pRMin by number().double
|
||||
var pRMax by number().double
|
||||
var pDz by number().double
|
||||
var pSPhi by number().double
|
||||
var pDPhi by number().double
|
||||
|
||||
companion object : SpecificationCompanion<GDMLTube> {
|
||||
override fun wrap(config: Config): GDMLTube = GDMLTube(config)
|
||||
}
|
||||
}
|
||||
|
||||
class GDMLXtru(config: Config) : GDMLSolid(config) {
|
||||
override val type: String = "xtru"
|
||||
|
||||
class TwoDimVertex(val x: Double, val y: Double)
|
||||
|
||||
class Section(override val config: Config) : Specification {
|
||||
var zOrder by number().int
|
||||
var zPosition by number().double
|
||||
var xOffsset by number(0.0).double
|
||||
var yOffset by number(0.0).double
|
||||
var scalingFactor by number(1.0).double
|
||||
|
||||
companion object : SpecificationCompanion<Section> {
|
||||
override fun wrap(config: Config): Section = Section(config)
|
||||
}
|
||||
}
|
||||
|
||||
val verteces
|
||||
get() = config.getAll("twoDimVertex").values.map {
|
||||
val x = it.node["x"].double!!
|
||||
val y = it.node["y"].double!!
|
||||
TwoDimVertex(x, y)
|
||||
}
|
||||
|
||||
val sections get() = config.getAll("section").values.map { Section(it.node!!) }
|
||||
|
||||
fun vertex(x: Double, y: Double) {
|
||||
config.append("twoDimVertex", TwoDimVertex(x, y))
|
||||
}
|
||||
|
||||
fun section(index: Int, z: Double, block: Section.() -> Unit) {
|
||||
config["section[$index]"] = Section.build(block).apply { zOrder = index; zPosition = z }
|
||||
}
|
||||
|
||||
companion object : SpecificationCompanion<GDMLXtru> {
|
||||
override fun wrap(config: Config): GDMLXtru = GDMLXtru(config)
|
||||
}
|
||||
}
|
||||
|
||||
class GDMLUnion(config: Config) : GDMLSolid(config) {
|
||||
override val type: String = "union"
|
||||
|
||||
val first by node()
|
||||
val second by node()
|
||||
|
||||
companion object : SpecificationCompanion<GDMLUnion> {
|
||||
override fun wrap(config: Config): GDMLUnion = GDMLUnion(config)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
package hep.dataforge.vis.spatial.gdml
|
||||
|
||||
import hep.dataforge.context.AbstractPlugin
|
||||
import hep.dataforge.context.Context
|
||||
import hep.dataforge.context.PluginFactory
|
||||
import hep.dataforge.context.PluginTag
|
||||
import hep.dataforge.vis.spatial.ThreePlugin
|
||||
|
||||
class GDMLPlugin : AbstractPlugin() {
|
||||
override val tag: PluginTag get() = GDMLPlugin.tag
|
||||
|
||||
override fun dependsOn() = listOf(ThreePlugin)
|
||||
|
||||
override fun attach(context: Context) {
|
||||
super.attach(context)
|
||||
// context.plugins.get<ThreePlugin>()?.factories?.apply {
|
||||
// this["jsRoot.geometry".toName()] = ThreeJSRootGeometryFactory
|
||||
// this["jsRoot.object".toName()] = ThreeJSRootObjectFactory
|
||||
// }
|
||||
}
|
||||
|
||||
override fun detach() {
|
||||
// context.plugins.get<ThreePlugin>()?.factories?.apply {
|
||||
// remove("jsRoot.geometry".toName())
|
||||
// remove("jsRoot.object".toName())
|
||||
// }
|
||||
super.detach()
|
||||
}
|
||||
|
||||
companion object : PluginFactory<GDMLPlugin> {
|
||||
override val tag = PluginTag("vis.gdml", "hep.dataforge")
|
||||
override val type = GDMLPlugin::class
|
||||
override fun invoke() = GDMLPlugin()
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package hep.dataforge.vis.spatial.gdml
|
||||
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.buildMeta
|
||||
import hep.dataforge.meta.toDynamic
|
||||
import hep.dataforge.meta.values
|
||||
import hep.dataforge.vis.DisplayLeaf
|
||||
import hep.dataforge.vis.DisplayObject
|
||||
import hep.dataforge.vis.int
|
||||
import hep.dataforge.vis.spatial.MeshThreeFactory
|
||||
import hep.dataforge.vis.spatial.jsroot.createGeometry
|
||||
import hep.dataforge.vis.spatial.jsroot.createTubeBuffer
|
||||
import info.laht.threekt.core.BufferGeometry
|
||||
|
||||
|
||||
class GDMLShape(parent: DisplayObject?, meta: Meta, val shape: GDMLSolid) :
|
||||
DisplayLeaf(parent, "$TYPE.${shape.type}", meta) {
|
||||
|
||||
var facesLimit by int(0)
|
||||
|
||||
companion object {
|
||||
const val TYPE = "geometry.3d.gdml"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
object ThreeGDMLFactory : MeshThreeFactory<GDMLShape>(GDMLShape::class) {
|
||||
//TODO fix ineffective conversion
|
||||
private fun Meta?.toJsRoot() = this?.let {
|
||||
buildMeta {
|
||||
values().forEach { (name, value) ->
|
||||
name.toString().replaceFirst("p", "f") to value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun buildGeometry(obj: GDMLShape): BufferGeometry {
|
||||
return when (obj.shape) {
|
||||
is GDMLBox -> createTubeBuffer(
|
||||
obj.shape.config.toJsRoot(),
|
||||
obj.facesLimit
|
||||
)
|
||||
is GDMLTube -> createTubeBuffer(
|
||||
obj.shape.config.toJsRoot(),
|
||||
obj.facesLimit
|
||||
)
|
||||
is GDMLXtru -> {
|
||||
val meta = buildMeta {
|
||||
val vertices = obj.shape.verteces
|
||||
val zs = obj.shape.sections.sortedBy { it.zOrder!! }
|
||||
"fNz" to zs.size
|
||||
"fNvert" to vertices.size
|
||||
"_typename" to "TGeoXtru"
|
||||
"fX" to vertices.map { it.x }
|
||||
"fY" to vertices.map { it.y }
|
||||
"fX0" to zs.map { it.xOffsset }
|
||||
"fY0" to zs.map { it.yOffset }
|
||||
"fZ" to zs.map { it.zPosition!! }
|
||||
"fScale" to zs.map { it.scalingFactor }
|
||||
}
|
||||
createGeometry(meta.toDynamic(), obj.facesLimit)
|
||||
}
|
||||
// is GDMLUnion -> {
|
||||
// val meta = buildMeta {
|
||||
// "fNode.fLeft" to obj.shape.first.toJsRoot()
|
||||
// "fNode.fRight" to obj.shape.second.toJsRoot()
|
||||
// "fNode._typename" to "TGeoUnion"
|
||||
// }
|
||||
// createGeometry(meta.toDynamic(), obj.facesLimit)
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +1,18 @@
|
||||
package hep.dataforge.vis.spatial.jsroot
|
||||
|
||||
import hep.dataforge.context.Global
|
||||
import hep.dataforge.meta.EmptyMeta
|
||||
import hep.dataforge.vis.ApplicationBase
|
||||
import hep.dataforge.vis.DisplayGroup
|
||||
import hep.dataforge.vis.require
|
||||
import hep.dataforge.vis.spatial.ThreeOutput
|
||||
import hep.dataforge.vis.spatial.render
|
||||
import org.w3c.dom.HTMLDivElement
|
||||
import org.w3c.dom.events.Event
|
||||
import org.w3c.files.FileList
|
||||
import org.w3c.files.FileReader
|
||||
import org.w3c.files.get
|
||||
import kotlin.browser.document
|
||||
import kotlin.dom.clear
|
||||
|
||||
|
||||
class JSRootDemoApp : ApplicationBase() {
|
||||
@ -23,16 +29,52 @@ class JSRootDemoApp : ApplicationBase() {
|
||||
|
||||
Global.plugins.load(JSRootPlugin)
|
||||
|
||||
val renderer = ThreeOutput(Global)
|
||||
renderer.start(document.getElementById("canvas")!!)
|
||||
println("started")
|
||||
|
||||
lateinit var group: DisplayGroup
|
||||
|
||||
renderer.render {
|
||||
jsRoot ("./geofile_full.json")
|
||||
(document.getElementById("drop_zone") as? HTMLDivElement)?.apply {
|
||||
addEventListener("dragover", { handleDragOver(it) }, false)
|
||||
addEventListener("drop", { loadData(it) }, false)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle mouse drag according to https://www.html5rocks.com/en/tutorials/file/dndfiles/
|
||||
*/
|
||||
private fun handleDragOver(event: Event) {
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
event.asDynamic().dataTransfer.dropEffect = "copy"
|
||||
}
|
||||
|
||||
/**
|
||||
* Load data from text file
|
||||
*/
|
||||
private fun loadData(event: Event) {
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
|
||||
|
||||
val file = (event.asDynamic().dataTransfer.files as FileList)[0]
|
||||
?: throw RuntimeException("Failed to load file");
|
||||
FileReader().apply {
|
||||
onload = {
|
||||
val string = result as String
|
||||
val renderer = ThreeOutput(Global)
|
||||
val canvas = document.getElementById("canvas")!!
|
||||
canvas.clear()
|
||||
renderer.start(canvas)
|
||||
println("started")
|
||||
|
||||
renderer.render {
|
||||
val json = JSON.parse<Any>(string).asDynamic()
|
||||
val obj = json.fVolumes.arr[0]
|
||||
JSRootObject(this, EmptyMeta, obj).also { addChild(it) }
|
||||
}
|
||||
}
|
||||
readAsText(file)
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispose() = emptyMap<String, Any>()//mapOf("lines" to presenter.dispose())
|
||||
|
@ -8,4 +8,10 @@ import info.laht.threekt.core.Object3D
|
||||
|
||||
external fun createGeometry(shape: dynamic, limit: Int): BufferGeometry
|
||||
|
||||
external fun createCubeBuffer(shape: dynamic, limit: Int): BufferGeometry
|
||||
|
||||
external fun createTubeBuffer(shape: dynamic, limit: Int): BufferGeometry
|
||||
|
||||
external fun createXtruBuffer(shape: dynamic, limit: Int): BufferGeometry
|
||||
|
||||
external fun build(obj: dynamic, opt: dynamic): Object3D
|
||||
|
@ -53,7 +53,7 @@ class JSRootGeometry(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, T
|
||||
}
|
||||
}
|
||||
|
||||
fun DisplayGroup.jsRoot(meta: Meta = EmptyMeta, action: JSRootGeometry.() -> Unit = {}) =
|
||||
fun DisplayGroup.jsRootGeometry(meta: Meta = EmptyMeta, action: JSRootGeometry.() -> Unit = {}) =
|
||||
JSRootGeometry(this, meta).apply(action).also { addChild(it) }
|
||||
|
||||
//fun Meta.toDynamic(): dynamic {
|
||||
@ -74,7 +74,7 @@ fun DisplayGroup.jsRoot(meta: Meta = EmptyMeta, action: JSRootGeometry.() -> Uni
|
||||
//}
|
||||
|
||||
|
||||
object ThreeJSRootFactory : MeshThreeFactory<JSRootGeometry>(JSRootGeometry::class) {
|
||||
object ThreeJSRootGeometryFactory : MeshThreeFactory<JSRootGeometry>(JSRootGeometry::class) {
|
||||
override fun buildGeometry(obj: JSRootGeometry): BufferGeometry {
|
||||
val shapeMeta = obj.shape?.toDynamic() ?: error("The shape not defined")
|
||||
return createGeometry(shapeMeta, obj.facesLimit)
|
||||
|
@ -1,6 +1,5 @@
|
||||
package hep.dataforge.vis.spatial.jsroot
|
||||
|
||||
import hep.dataforge.meta.DynamicMeta
|
||||
import hep.dataforge.meta.EmptyMeta
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.toDynamic
|
||||
@ -11,9 +10,8 @@ import hep.dataforge.vis.node
|
||||
import hep.dataforge.vis.spatial.ThreeFactory
|
||||
import info.laht.threekt.core.Object3D
|
||||
|
||||
class JSRootObject(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, TYPE, meta) {
|
||||
class JSRootObject(parent: DisplayObject?, meta: Meta, val data: dynamic) : DisplayLeaf(parent, TYPE, meta) {
|
||||
|
||||
var data by node()
|
||||
var options by node()
|
||||
|
||||
companion object {
|
||||
@ -21,17 +19,16 @@ class JSRootObject(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, TYP
|
||||
}
|
||||
}
|
||||
|
||||
object JSRootObjectFactory : ThreeFactory<JSRootObject> {
|
||||
object ThreeJSRootObjectFactory : ThreeFactory<JSRootObject> {
|
||||
|
||||
override val type = JSRootObject::class
|
||||
|
||||
override fun invoke(obj: JSRootObject): Object3D {
|
||||
return build(obj.data?.toDynamic(), obj.options?.toDynamic())
|
||||
return build(obj.data, obj.options?.toDynamic())
|
||||
}
|
||||
}
|
||||
|
||||
fun DisplayGroup.jsRoot(path: String) {
|
||||
JSRootObject(this, EmptyMeta).apply{
|
||||
data = DynamicMeta(hep.dataforge.vis.require(path))
|
||||
}.also { addChild(it) }
|
||||
fun DisplayGroup.jsRootObject(str: String) {
|
||||
val json = JSON.parse<Any>(str)
|
||||
JSRootObject(this, EmptyMeta, json).also { addChild(it) }
|
||||
}
|
@ -14,7 +14,18 @@ class JSRootPlugin : AbstractPlugin() {
|
||||
|
||||
override fun attach(context: Context) {
|
||||
super.attach(context)
|
||||
context.plugins.get<ThreePlugin>()?.factories?.set("ThreeJSRootFactory".toName(), ThreeJSRootFactory)
|
||||
context.plugins.get<ThreePlugin>()?.factories?.apply {
|
||||
this["jsRoot.geometry".toName()] = ThreeJSRootGeometryFactory
|
||||
this["jsRoot.object".toName()] = ThreeJSRootObjectFactory
|
||||
}
|
||||
}
|
||||
|
||||
override fun detach() {
|
||||
context.plugins.get<ThreePlugin>()?.factories?.apply {
|
||||
remove("jsRoot.geometry".toName())
|
||||
remove("jsRoot.object".toName())
|
||||
}
|
||||
super.detach()
|
||||
}
|
||||
|
||||
companion object: PluginFactory<JSRootPlugin> {
|
||||
|
@ -3428,7 +3428,7 @@
|
||||
obj = null;
|
||||
}
|
||||
|
||||
if (opt.composite && shape && (shape._typename == 'TGeoCompositeShape') && shape.fNode)
|
||||
if (opt.composite && shape && (shape._typename === 'TGeoCompositeShape') && shape.fNode)
|
||||
obj = GEO.buildCompositeVolume(shape);
|
||||
|
||||
if (!obj && shape)
|
||||
|
@ -4,7 +4,7 @@
|
||||
<title>Three js demo for particle physics</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0px;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
@ -14,9 +14,15 @@
|
||||
<!--<script type="text/javascript" src="js/ThreeCSG.js"></script>-->
|
||||
<!--<script type="text/javascript" src="js/JSRootCore.js"></script>-->
|
||||
<!--<script type="text/javascript" src="js/JSRootGeoBase.js"></script>-->
|
||||
<script type="text/javascript" language="JavaScript" src="main.bundle.js"></script>
|
||||
<script type="text/javascript" src="main.bundle.js"></script>
|
||||
</head>
|
||||
<body class="testApp">
|
||||
<div id="drop_zone" data-toggle="tooltip" data-placement="right"
|
||||
title="Для загрузки данных в текстовом формате, надо перетащить файл сюда">
|
||||
Загрузить данные
|
||||
<br/>
|
||||
(перетащить файл сюда)
|
||||
</div>
|
||||
<h1>Demo canvas</h1>
|
||||
<div id="canvas"></div>
|
||||
</body>
|
||||
|
@ -25,3 +25,5 @@ include(
|
||||
":dataforge-vis-spatial-fx",
|
||||
":dataforge-vis-spatial-js"
|
||||
)
|
||||
|
||||
includeBuild("../dataforge-core")
|
Loading…
Reference in New Issue
Block a user