Finalizing GDML

This commit is contained in:
Alexander Nozik 2019-07-24 20:22:23 +03:00
parent effa19a95e
commit 687393c243
19 changed files with 313 additions and 154 deletions

View File

@ -39,6 +39,9 @@ class DisplayObjectDelegateWrapper<T>(
val write: Config.(name: Name, value: T) -> Unit = { name, value -> set(name, value) }, val write: Config.(name: Name, value: T) -> Unit = { name, value -> set(name, value) },
val read: (MetaItem<*>?) -> T? val read: (MetaItem<*>?) -> T?
) : ReadWriteProperty<VisualObject, T> { ) : ReadWriteProperty<VisualObject, T> {
//private var cachedName: Name? = null
override fun getValue(thisRef: VisualObject, property: KProperty<*>): T { override fun getValue(thisRef: VisualObject, property: KProperty<*>): T {
val name = key ?: property.name.toName() val name = key ?: property.name.toName()
return if (inherited) { return if (inherited) {

View File

@ -0,0 +1,64 @@
package hep.dataforge.vis.hmr
import kotlin.browser.document
import kotlin.dom.hasClass
external val module: Module
external interface Module {
val hot: Hot?
}
external interface Hot {
val data: dynamic
fun accept()
fun accept(dependency: String, callback: () -> Unit)
fun accept(dependencies: Array<String>, callback: (updated: Array<String>) -> Unit)
fun dispose(callback: (data: dynamic) -> Unit)
}
external fun require(name: String): dynamic
abstract class ApplicationBase {
open val stateKeys: List<String> get() = emptyList()
abstract fun start(state: Map<String, Any>)
open fun dispose(): Map<String, Any> = emptyMap()
}
fun startApplication(builder: () -> ApplicationBase) {
fun start(state: dynamic): ApplicationBase? {
return if (document.body?.hasClass("testApp") == true) {
val application = builder()
@Suppress("UnsafeCastFromDynamic")
application.start(state?.appState ?: emptyMap())
application
} else {
null
}
}
var application: ApplicationBase? = null
val state: dynamic = module.hot?.let { hot ->
hot.accept()
hot.dispose { data ->
data.appState = application?.dispose()
application = null
}
hot.data
}
if (document.body != null) {
application = start(state)
} else {
application = null
document.addEventListener("DOMContentLoaded", { application = start(state) })
}
}

View File

@ -6,7 +6,7 @@
<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" <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"> integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script type="text/javascript" src="main.bundle.js"></script> <script type="text/javascript" src="dataforge-vis-spatial-gdml-0.1.0-dev.js"></script>
</head> </head>
<body class="testApp"> <body class="testApp">
<div class="container" id="drop_zone" data-toggle="tooltip" data-placement="right" <div class="container" id="drop_zone" data-toggle="tooltip" data-placement="right"

View File

@ -7,7 +7,12 @@ 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.2") api("scientifik:gdml:0.1.3")
}
}
val jsMain by getting{
dependencies{
api(project(":dataforge-vis-spatial-js"))
} }
} }
} }

View File

@ -86,7 +86,7 @@ private fun VisualGroup.addSolid(root: GDML, solid: GDMLSolid, block: VisualObje
solid.resolveFirstPosition(root)?.let { applyPosition(it) } solid.resolveFirstPosition(root)?.let { applyPosition(it) }
solid.resolveFirstRotation(root)?.let { applyRotation(it) } solid.resolveFirstRotation(root)?.let { applyRotation(it) }
} }
addSolid(root, second) {} addSolid(root, second)
solid.resolvePosition(root)?.let { applyPosition(it) } solid.resolvePosition(root)?.let { applyPosition(it) }
solid.resolveRotation(root)?.let { applyRotation(it) } solid.resolveRotation(root)?.let { applyRotation(it) }
} }
@ -96,22 +96,24 @@ private fun VisualGroup.addSolid(root: GDML, solid: GDMLSolid, block: VisualObje
private fun VisualGroup.addVolume( private fun VisualGroup.addVolume(
root: GDML, root: GDML,
gdmlVolume: GDMLVolume, group: GDMLGroup,
resolveColor: GDMLMaterial.() -> Meta resolveColor: GDMLMaterial.() -> Meta
): VisualGroup { ): VisualGroup {
val solid = if (group is GDMLVolume) {
gdmlVolume.solidref.resolve(root) val solid = group.solidref.resolve(root)
?: error("Solid with tag ${gdmlVolume.solidref.ref} for volume ${gdmlVolume.name} not defined") ?: error("Solid with tag ${group.solidref.ref} for volume ${group.name} not defined")
val material = val material = group.materialref.resolve(root)
gdmlVolume.materialref.resolve(root) ?: error("Material with tag ${group.materialref.ref} for volume ${group.name} not defined")
?: error("Material with tag ${gdmlVolume.materialref.ref} for volume ${gdmlVolume.name} not defined")
addSolid(root, solid) { addSolid(root, solid) {
color(material.resolveColor()) color(material.resolveColor())
}
//TODO render placements
} }
gdmlVolume.physVolumes.forEach { group.physVolumes.forEach {
val volume = it.volumeref.resolve(root) ?: error("Volume with ref ${it.volumeref.ref} could not be resolved") val volume: GDMLGroup =
it.volumeref.resolve(root) ?: error("Volume with ref ${it.volumeref.ref} could not be resolved")
addVolume(root, volume, resolveColor).apply { addVolume(root, volume, resolveColor).apply {
it.resolvePosition(root)?.let { pos -> applyPosition(pos) } it.resolvePosition(root)?.let { pos -> applyPosition(pos) }
it.resolveRotation(root)?.let { rot -> applyRotation(rot) } it.resolveRotation(root)?.let { rot -> applyRotation(rot) }

View File

@ -0,0 +1,82 @@
package hep.dataforge.vis.spatial.gdml.demo
import hep.dataforge.context.Global
import hep.dataforge.vis.hmr.ApplicationBase
import hep.dataforge.vis.hmr.startApplication
import hep.dataforge.vis.spatial.gdml.toVisual
import hep.dataforge.vis.spatial.three.ThreePlugin
import hep.dataforge.vis.spatial.three.output
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
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 scientifik.gdml.GDML
import kotlin.browser.document
import kotlin.dom.clear
class GDMLDemoApp : ApplicationBase() {
/**
* 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, block: suspend (String) -> Unit) {
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
GlobalScope.launch {
block(string)
}
}
readAsText(file)
}
}
override fun start(state: Map<String, Any>) {
val context = Global.context("demo") {}
val three = context.plugins.load(ThreePlugin)
val canvas = document.getElementById("canvas") ?: error("Element with id canvas not found on page")
canvas.clear()
val output = three.output(canvas)
//val url = URL("https://drive.google.com/open?id=1w5e7fILMN83JGgB8WANJUYm8OW2s0WVO")
val action: suspend (String) -> Unit = {
val gdml = GDML.format.parse(GDML.serializer(), it)
val visual = gdml.toVisual()
output.render(visual)
}
(document.getElementById("drop_zone") as? HTMLDivElement)?.apply {
addEventListener("dragover", { handleDragOver(it) }, false)
addEventListener("drop", { loadData(it, action) }, false)
}
}
}
fun main() {
startApplication(::GDMLDemoApp)
}

View File

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<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">
<script type="text/javascript" src="main.bundle.js"></script>
</head>
<body class="testApp">
<div class="container" id="drop_zone" data-toggle="tooltip" data-placement="right"
title="Для загрузки данных в текстовом формате, надо перетащить файл сюда">
Загрузить данные
<br/>
(перетащить файл сюда)
</div>
<div class="container">
<h1>GDML demo</h1>
</div>
<div class="container" id="canvas"></div>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
crossorigin="anonymous"></script>
</body>
</html>

View File

@ -0,0 +1,28 @@
package hep.dataforge.vis.spatial.gdml
import nl.adaptivity.xmlutil.StAXReader
import org.junit.Test
import scientifik.gdml.GDML
import java.io.File
import java.net.URL
class BMNTest {
@Test
fun testRead() {
val url = URL("https://drive.google.com/open?id=1w5e7fILMN83JGgB8WANJUYm8OW2s0WVO")
val file = File("D:\\Work\\Projects\\gdml.kt\\src\\commonTest\\resources\\gdml\\geofile_full.xml")
val stream = if(file.exists()){
file.inputStream()
} else {
url.openStream()
}
val xmlReader = StAXReader(stream, "UTF-8")
val xml = GDML.format.parse(GDML.serializer(), xmlReader)
repeat(5) {
xml.toVisual()
}
}
}

View File

@ -1,69 +1,21 @@
plugins { plugins {
id("scientifik.js") id("scientifik.js")
id("kotlin-dce-js") //id("kotlin-dce-js")
} }
//val kotlinVersion: String by rootProject.extra //val kotlinVersion: String by rootProject.extra
dependencies { dependencies {
api(project(":dataforge-vis-spatial")) api(project(":dataforge-vis-spatial"))
api(project(":dataforge-vis-spatial-gdml")) api("info.laht.threekt:threejs-wrapper:0.106-npm-3")
api("info.laht.threekt:threejs-wrapper:0.106-npm-2")
testCompile(kotlin("test-js")) testCompile(kotlin("test-js"))
} }
kotlin{ kotlin{
sourceSets["main"].dependencies{ sourceSets["main"].dependencies{
api(npm("three","0.106.2")) implementation(npm("three","0.106.2"))
implementation(npm("@hi-level/three-csg")) implementation(npm("@hi-level/three-csg"))
implementation(npm("style-loader")) implementation(npm("style-loader"))
implementation(npm("element-resize-event")) implementation(npm("element-resize-event"))
} }
} }
//
//configure<KotlinFrontendExtension> {
// downloadNodeJsVersion = "latest"
//
// configure<NpmExtension> {
// dependency("three","0.106.2")
// dependency("@hi-level/three-csg")
// dependency("style-loader")
// dependency("element-resize-event")
// devDependency("karma")
// }
//
// sourceMaps = true
//
// bundle<WebPackExtension>("webpack") {
// this as WebPackExtension
// bundleName = "main"
// contentPath = file("src/main/web")
// sourceMapEnabled = true
// //mode = "production"
// mode = "development"
// }
//}
//
//tasks {
// "compileKotlin2Js"(Kotlin2JsCompile::class) {
// kotlinOptions {
// metaInfo = true
// outputFile = "${project.buildDir.path}/js/${project.name}.js"
// sourceMap = true
// moduleKind = "commonjs"
// main = "call"
// kotlinOptions.sourceMapEmbedSources = "always"
// }
// }
//
// "compileTestKotlin2Js"(Kotlin2JsCompile::class) {
// kotlinOptions {
// metaInfo = true
// outputFile = "${project.buildDir.path}/js/${project.name}-test.js"
// sourceMap = true
// moduleKind = "commonjs"
// kotlinOptions.sourceMapEmbedSources = "always"
// }
// }
//}

View File

@ -1,19 +0,0 @@
package hep.dataforge.vis.spatial.demo
external val module: Module
external interface Module {
val hot: Hot?
}
external interface Hot {
val data: dynamic
fun accept()
fun accept(dependency: String, callback: () -> Unit)
fun accept(dependencies: Array<String>, callback: (updated: Array<String>) -> Unit)
fun dispose(callback: (data: dynamic) -> Unit)
}
external fun require(name: String): dynamic

View File

@ -4,6 +4,8 @@ import hep.dataforge.context.ContextBuilder
import hep.dataforge.meta.number import hep.dataforge.meta.number
import hep.dataforge.vis.common.Colors import hep.dataforge.vis.common.Colors
import hep.dataforge.vis.common.color import hep.dataforge.vis.common.color
import hep.dataforge.vis.hmr.ApplicationBase
import hep.dataforge.vis.hmr.startApplication
import hep.dataforge.vis.spatial.* import hep.dataforge.vis.spatial.*
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@ -135,4 +137,8 @@ class ThreeDemoApp : ApplicationBase() {
} }
override fun dispose() = emptyMap<String, Any>()//mapOf("lines" to presenter.dispose()) override fun dispose() = emptyMap<String, Any>()//mapOf("lines" to presenter.dispose())
}
fun main() {
startApplication(::ThreeDemoApp)
} }

View File

@ -50,7 +50,7 @@ class ThreeDemoGrid(meta: Meta) : AbstractPlugin(meta), OutputManager {
return outputs.getOrPut(name) { return outputs.getOrPut(name) {
if (type != VisualObject::class) error("Supports only DisplayObject") if (type != VisualObject::class) error("Supports only DisplayObject")
val output = three.output(meta) { val output = three.output(meta = meta) {
"axis" to { "axis" to {
"size" to 500 "size" to 500
} }

View File

@ -1,48 +0,0 @@
package hep.dataforge.vis.spatial.demo
import kotlin.browser.document
import kotlin.dom.hasClass
abstract class ApplicationBase {
abstract val stateKeys: List<String>
abstract fun start(state: Map<String, Any>)
abstract fun dispose(): Map<String, Any>
}
fun main() {
var application: ApplicationBase? = null
val state: dynamic = module.hot?.let { hot ->
hot.accept()
hot.dispose { data ->
data.appState = application?.dispose()
application = null
}
hot.data
}
if (document.body != null) {
application = start(state)
} else {
application = null
document.addEventListener("DOMContentLoaded", { application = start(state) })
}
}
fun start(state: dynamic): ApplicationBase? {
return if (document.body?.hasClass("testApp") == true) {
val application = ThreeDemoApp()
@Suppress("UnsafeCastFromDynamic")
application.start(state?.appState ?: emptyMap<String, Any>())
application
} else {
null
}
}

View File

@ -0,0 +1,32 @@
package hep.dataforge.vis.spatial.three
import hep.dataforge.vis.spatial.Cylinder
import hep.dataforge.vis.spatial.detail
import info.laht.threekt.core.BufferGeometry
import info.laht.threekt.geometries.CylinderBufferGeometry
import kotlin.math.pow
object ThreeCylinderFactory : MeshThreeFactory<Cylinder>(Cylinder::class) {
override fun buildGeometry(obj: Cylinder): BufferGeometry {
return obj.detail?.let {
val segments = it.toDouble().pow(0.5).toInt()
CylinderBufferGeometry(
radiusTop = obj.upperRadius!!,
radiusBottom = obj.radius!!,
height = obj.height!!,
radialSegments = segments,
heightSegments = segments,
openEnded = false,
thetaStart = obj.startAngle,
thetaLength = obj.angle
)
} ?: CylinderBufferGeometry(
radiusTop = obj.upperRadius!!,
radiusBottom = obj.radius!!,
height = obj.height!!,
openEnded = false,
thetaStart = obj.startAngle,
thetaLength = obj.angle
)
}
}

View File

@ -5,7 +5,7 @@ import hep.dataforge.meta.*
import hep.dataforge.output.Output import hep.dataforge.output.Output
import hep.dataforge.vis.common.Colors import hep.dataforge.vis.common.Colors
import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.common.VisualObject
import hep.dataforge.vis.spatial.demo.require import hep.dataforge.vis.hmr.require
import info.laht.threekt.WebGLRenderer import info.laht.threekt.WebGLRenderer
import info.laht.threekt.helpers.AxesHelper import info.laht.threekt.helpers.AxesHelper
import info.laht.threekt.lights.AmbientLight import info.laht.threekt.lights.AmbientLight
@ -39,7 +39,7 @@ class ThreeOutput(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Output<V
setSize(width, height) setSize(width, height)
} }
three.addControls(camera,renderer.domElement, meta["controls"].node?:EmptyMeta) three.addControls(camera, renderer.domElement, meta["controls"].node ?: EmptyMeta)
fun animate() { fun animate() {
window.requestAnimationFrame { window.requestAnimationFrame {
@ -63,5 +63,9 @@ class ThreeOutput(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Output<V
} }
} }
fun ThreePlugin.output(meta: Meta = EmptyMeta, override: MetaBuilder.() -> Unit = {}) = fun ThreePlugin.output(element: Element? = null, meta: Meta = EmptyMeta, override: MetaBuilder.() -> Unit = {}) =
ThreeOutput(this, buildMeta(meta, override)) ThreeOutput(this, buildMeta(meta, override)).apply {
if(element!=null){
attach(element)
}
}

View File

@ -28,6 +28,7 @@ class ThreePlugin : AbstractPlugin() {
objectFactories[Box::class] = ThreeBoxFactory objectFactories[Box::class] = ThreeBoxFactory
objectFactories[Convex::class] = ThreeConvexFactory objectFactories[Convex::class] = ThreeConvexFactory
objectFactories[Sphere::class] = ThreeSphereFactory objectFactories[Sphere::class] = ThreeSphereFactory
objectFactories[Cylinder::class] = ThreeCylinderFactory
} }
private fun findObjectFactory(type: KClass<out VisualObject>): ThreeFactory<*>? { private fun findObjectFactory(type: KClass<out VisualObject>): ThreeFactory<*>? {

View File

@ -25,7 +25,9 @@ fun VisualGroup.composite(type: CompositeType, builder: VisualGroup.() -> Unit):
val group = VisualGroup().apply(builder) val group = VisualGroup().apply(builder)
val children = group.toList() val children = group.toList()
if (children.size != 2) error("Composite requires exactly two children") if (children.size != 2) error("Composite requires exactly two children")
return Composite(this, children[0], children[1], type, group.properties.seal()).also { add(it) } return Composite(this, children[0], children[1], type, group.properties.seal()).also {
this.add(it)
}
} }
fun VisualGroup.union(builder: VisualGroup.() -> Unit) = fun VisualGroup.union(builder: VisualGroup.() -> Unit) =

View File

@ -16,13 +16,13 @@ class Cylinder(parent: VisualObject?, meta: Meta) : DisplayLeaf(parent, meta) {
var upperRadius by number(default = radius) var upperRadius by number(default = radius)
var height by number() var height by number()
var startAngle by number(0.0) var startAngle by number(0.0)
var angle by number(2* PI) var angle by number(2 * PI)
} }
fun VisualGroup.cylinder(r: Number, height: Number, meta: Meta = EmptyMeta, block: Cylinder.()->Unit = {}):Cylinder{ fun VisualGroup.cylinder(r: Number, height: Number, meta: Meta = EmptyMeta, block: Cylinder.() -> Unit = {}): Cylinder {
val cylinder = Cylinder(this,meta) val cylinder = Cylinder(this, meta)
cylinder.radius = r cylinder.radius = r
cylinder.height = height cylinder.height = height
cylinder.apply(block) cylinder.apply(block)
return cylinder return cylinder.also { add(it) }
} }

View File

@ -1,6 +1,7 @@
package hep.dataforge.vis.spatial package hep.dataforge.vis.spatial
import hep.dataforge.meta.* import hep.dataforge.meta.*
import hep.dataforge.names.toName
import hep.dataforge.output.Output import hep.dataforge.output.Output
import hep.dataforge.vis.common.VisualGroup import hep.dataforge.vis.common.VisualGroup
import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.common.VisualObject
@ -28,60 +29,71 @@ var VisualObject.visible
// 3D Object position // 3D Object position
private val xPos = "pos.x".toName()
/** /**
* x position property relative to parent. Not inherited * x position property relative to parent. Not inherited
*/ */
var VisualObject.x var VisualObject.x
get() = properties["pos.x"].number ?: 0.0 get() = properties[xPos].number ?: 0.0
set(value) { set(value) {
properties["pos.x"] = value properties[xPos] = value
} }
private val yPos = "pos.y".toName()
/** /**
* y position property. Not inherited * y position property. Not inherited
*/ */
var VisualObject.y var VisualObject.y
get() = properties["pos.y"].number ?: 0.0 get() = properties[yPos].number ?: 0.0
set(value) { set(value) {
properties["pos.y"] = value properties[yPos] = value
} }
private val zPos = "pos.z".toName()
/** /**
* z position property. Not inherited * z position property. Not inherited
*/ */
var VisualObject.z var VisualObject.z
get() = properties["pos.z"].number ?: 0.0 get() = properties[zPos].number ?: 0.0
set(value) { set(value) {
properties["pos.z"] = value properties[zPos] = value
} }
// 3D Object rotation // 3D Object rotation
private val xRotation = "rotation.x".toName()
/** /**
* x rotation relative to parent. Not inherited * x rotation relative to parent. Not inherited
*/ */
var VisualObject.rotationX var VisualObject.rotationX
get() = properties["rotation.x"].number ?: 0.0 get() = properties[xRotation].number ?: 0.0
set(value) { set(value) {
properties["rotation.x"] = value properties[xRotation] = value
} }
private val yRotation = "rotation.y".toName()
/** /**
* y rotation relative to parent. Not inherited * y rotation relative to parent. Not inherited
*/ */
var VisualObject.rotationY var VisualObject.rotationY
get() = properties["rotation.y"].number ?: 0.0 get() = properties[yRotation].number ?: 0.0
set(value) { set(value) {
properties["rotation.y"] = value properties[yRotation] = value
} }
private val zRotation = "rotation.z".toName()
/** /**
* z rotation relative to parent. Not inherited * z rotation relative to parent. Not inherited
*/ */
var VisualObject.rotationZ var VisualObject.rotationZ
get() = properties["rotation.z"].number ?: 0.0 get() = properties[zRotation].number ?: 0.0
set(value) { set(value) {
properties["rotation.z"] = value properties[zRotation] = value
} }
enum class RotationOrder { enum class RotationOrder {