v0.2.0-dev-22 #47

Merged
altavir merged 158 commits from dev into master 2021-07-17 11:04:22 +03:00
518 changed files with 14102 additions and 9447 deletions

2
.gitignore vendored
View File

@ -5,6 +5,4 @@ out/
.gradle
build/
!gradle-wrapper.jar
gradle.properties

View File

@ -0,0 +1,36 @@
# Changelog
## [Unreleased]
### Added
- Server module
- Change collector
- Customizable accessors for colors
- SphereLayer solid
- Hexagon interface and GenericHexagon implementation (Box inherits Hexagon)
- Increased the default detail level for spheres and cones to 32
- Simple clipping for Solids in ThreeJs
### Changed
- Vision does not implement ItemProvider anymore. Property changes are done via `getProperty`/`setProperty` and `property` delegate.
- Point3D and Point2D are made separate classes instead of expect/actual (to split up different engines.
- JavaFX support moved to a separate module
- Threejs support moved to a separate module
- \[Format breaking change!\] Stylesheets are moved into properties under `@stylesheet` key
- VisionGroup builder accepts `null` as name for statics instead of `""`
- gdml sphere is rendered as a SphereLayer instead of Sphere (#35)
- Tube is replaced by more general ConeSurface
- position, rotation and size moved to properties
- prototypes moved to children
- Immutable Solid instances
- Property listeners are not triggered if there are no changes.
- Feedback websocket connection in the client.
### Deprecated
### Removed
- Primary modules dependencies on UI
### Fixed
- Version conflicts
### Security

View File

@ -3,11 +3,14 @@
![Gradle build](https://github.com/mipt-npm/visionforge/workflows/Gradle%20build/badge.svg)
[![Slack](https://img.shields.io/badge/slack-channel-green?logo=slack)](https://kotlinlang.slack.com/archives/CEXV2QWNM)
# DataForge Visualization Platform
## Table of Contents
* [Introduction](#introduction)
* [Requirements](#requirements)
* [Features](#features)
* [About DataForge](#about-dataforge)
* [Modules contained in this repository](#modules-contained-in-this-repository)
@ -32,6 +35,9 @@ Other applications including 2D plots are planned for the future.
The project is developed as a [Kotlin multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html)
application, currently targeting browser JavaScript and JVM.
## Requirements
JVM backend requires JDK 11 or later
## Features
@ -67,7 +73,7 @@ The `visionforge-core` module also includes configuration editors for JS (in `js
**Class diagram:**
![](doc/resources/class-diag-core.png)
![](docs/images/class-diag-core.png)
### visionforge-solid
@ -76,7 +82,7 @@ Includes common classes and serializers for 3D visualization, as well as Three.j
**Class diagram:**
![](doc/resources/class-diag-solid.png)
![](docs/images/class-diag-solid.png)
##### Prototypes
@ -85,7 +91,7 @@ also referred to as templates). The idea is that prototype geometry can be rende
for multiple objects. This helps to significantly decrease memory usage.
The `prototypes` property tree is defined in `SolidGroup` class via `PrototypeHolder` interface, and
`Proxy` class helps to reuse a template object.
`SolidReference` class helps to reuse a template object.
##### Styles
@ -121,7 +127,7 @@ Some shapes will also periodically change their color and visibility.
**Example view:**
![](doc/resources/spatial-showcase.png)
![](docs/images/spatial-showcase.png)
### Full-Stack Application Example - Muon Monitor Visualization
@ -133,7 +139,7 @@ A full-stack application example, showing the
**Example view:**
![](doc/resources/muon-monitor.png)
![](docs/images/muon-monitor.png)
### GDML Example
@ -144,7 +150,7 @@ Visualization example for geometry defined as GDML file.
##### Example view:
![](doc/resources/gdml-demo.png)
![](docs/images/gdml-demo.png)
## Thanks and references

View File

@ -1,35 +1,41 @@
import scientifik.useFx
import scientifik.useSerialization
val dataforgeVersion by extra("0.1.8")
plugins {
id("scientifik.mpp") apply false
id("scientifik.jvm") apply false
id("scientifik.js") apply false
id("scientifik.publish") apply false
id("org.jetbrains.changelog") version "0.4.0"
id("ru.mipt.npm.gradle.project")
//Override kotlin version
// val kotlinVersion = "1.5.20-RC"
// kotlin("multiplatform") version(kotlinVersion) apply false
// kotlin("jvm") version(kotlinVersion) apply false
// kotlin("js") version(kotlinVersion) apply false
}
val dataforgeVersion by extra("0.4.3")
val fxVersion by extra("11")
allprojects {
repositories {
mavenLocal()
maven("https://dl.bintray.com/pdvrieze/maven")
maven("http://maven.jzy3d.org/releases")
mavenCentral()
jcenter()
maven("https://repo.kotlin.link")
maven("https://maven.jzy3d.org/releases")
}
group = "hep.dataforge"
version = "0.1.5-dev"
group = "space.kscience"
version = "0.2.0-dev-22"
}
val githubProject by extra("visionforge")
val bintrayRepo by extra("dataforge")
val fxVersion by extra("14")
subprojects {
if (name.startsWith("visionforge")) {
apply(plugin = "scientifik.publish")
plugins.apply("maven-publish")
}
useSerialization()
useFx(scientifik.FXModule.CONTROLS, version = fxVersion)
}
ksciencePublish{
github("visionforge")
space()
sonatype()
}
apiValidation {
validationDisabled = true
ignoredPackages.add("info.laht.threekt")
}

View File

View File

@ -12,4 +12,4 @@ drag-and-drop GDML file to the window to see visualization. For an example file,
##### Example view:
![](../../doc/resources/gdml-demo.png)
![](../../docs/images/gdml-demo.png)

View File

@ -1,25 +1,29 @@
import scientifik.DependencyConfiguration
import scientifik.FXModule
import scientifik.useFx
import ru.mipt.npm.gradle.DependencyConfiguration
import ru.mipt.npm.gradle.FXModule
plugins {
id("scientifik.mpp")
id("application")
id("ru.mipt.npm.gradle.mpp")
application
}
kscience {
val fxVersion: String by rootProject.extra
useFx(FXModule.CONTROLS, version = fxVersion, configuration = DependencyConfiguration.IMPLEMENTATION)
application()
}
kotlin {
jvm {
withJava()
}
js{
useCommonJs()
browser {
commonWebpackConfig {
cssSupport.enabled = false
}
}
}
sourceSets {
commonMain {
dependencies {
@ -27,9 +31,15 @@ kotlin {
implementation(project(":visionforge-gdml"))
}
}
jvmMain {
dependencies {
implementation(project(":visionforge-fx"))
}
}
jsMain {
dependencies {
implementation(project(":ui:bootstrap"))
implementation(project(":ui:ring"))
implementation(project(":visionforge-threejs"))
implementation(npm("react-file-drop", "3.0.6"))
}
}
@ -37,11 +47,11 @@ kotlin {
}
application {
mainClassName = "hep.dataforge.vision.gdml.demo.GDMLDemoAppKt"
mainClass.set("space.kscience.visionforge.gdml.demo.GdmlFxDemoAppKt")
}
val convertGdmlToJson by tasks.creating(JavaExec::class) {
group = "application"
classpath = sourceSets["main"].runtimeClasspath
main = "hep.dataforge.vis.spatial.gdml.demo.SaveToJsonKt"
main = "space.kscience.dataforge.vis.spatial.gdml.demo.SaveToJsonKt"
}

View File

@ -1,54 +0,0 @@
package hep.dataforge.vision.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 = AUnit.DEG.title
}
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 = AUnit.DEG.title
}
}
}
}
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
}
}
}
}
}
}
}
}

View File

@ -1,20 +0,0 @@
package hep.dataforge.vision.gdml
import hep.dataforge.meta.setItem
import hep.dataforge.meta.string
import hep.dataforge.names.toName
import hep.dataforge.values.asValue
import hep.dataforge.vision.gdml.demo.cubes
import hep.dataforge.vision.solid.SolidMaterial
import kotlin.test.Test
import kotlin.test.assertEquals
class GDMLVisualTest {
@Test
fun testPrototypeProperty() {
val gdml = cubes()
val visual = gdml.toVision()
visual["composite000.segment0".toName()]?.setItem(SolidMaterial.MATERIAL_COLOR_KEY, "red".asValue())
assertEquals("red", visual["composite000.segment0".toName()]?.getItem(SolidMaterial.MATERIAL_COLOR_KEY).string)
}
}

View File

@ -0,0 +1,32 @@
package space.kscience.visionforge.gdml
import space.kscience.dataforge.meta.string
import space.kscience.dataforge.names.toName
import space.kscience.dataforge.values.asValue
import space.kscience.gdml.GdmlShowCase
import space.kscience.visionforge.setProperty
import space.kscience.visionforge.solid.SolidMaterial
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
class GDMLVisionTest {
// @Test
// fun testCubesStyles(){
// val cubes = gdml.toVision()
// val segment = cubes["composite000.segment_0".toName()] as Solid
// println(segment.styles)
// println(segment.material)
// }
@Test
fun testPrototypeProperty() {
val vision = GdmlShowCase.cubes().toVision()
val child = vision["composite-000.segment-0".toName()]
assertNotNull(child)
child.setProperty(SolidMaterial.MATERIAL_COLOR_KEY, "red".asValue())
assertEquals("red", child.getProperty(SolidMaterial.MATERIAL_COLOR_KEY).string)
}
}

View File

@ -5,7 +5,9 @@ package drop
import org.w3c.dom.DragEvent
import org.w3c.files.FileList
import react.*
import react.Component
import react.RProps
import react.RState
external enum class DropEffects {
copy,

View File

@ -1,154 +0,0 @@
package hep.dataforge.vision.gdml.demo
import hep.dataforge.context.Context
import hep.dataforge.names.Name
import hep.dataforge.names.isEmpty
import hep.dataforge.vision.Vision
import hep.dataforge.vision.VisionGroup
import hep.dataforge.vision.bootstrap.*
import hep.dataforge.vision.gdml.toVision
import hep.dataforge.vision.react.component
import hep.dataforge.vision.react.configEditor
import hep.dataforge.vision.react.flexColumn
import hep.dataforge.vision.react.state
import hep.dataforge.vision.solid.Solid
import hep.dataforge.vision.solid.SolidGroup
import hep.dataforge.vision.solid.specifications.Camera
import hep.dataforge.vision.solid.specifications.Canvas3DOptions
import hep.dataforge.vision.solid.three.ThreeCanvas
import hep.dataforge.vision.solid.three.ThreeCanvasComponent
import hep.dataforge.vision.solid.three.canvasControls
import kotlinx.css.FlexBasis
import kotlinx.css.Overflow
import kotlinx.css.flex
import kotlinx.css.overflow
import org.w3c.files.FileReader
import org.w3c.files.get
import react.RProps
import react.dom.h1
import scientifik.gdml.GDML
import scientifik.gdml.parse
import styled.css
import styled.styledDiv
import kotlin.browser.window
import kotlin.math.PI
interface GDMLAppProps : RProps {
var context: Context
var rootObject: Vision?
var selected: Name?
}
private val canvasConfig = Canvas3DOptions {
camera = Camera {
distance = 2100.0
latitude = PI / 6
azimuth = PI + PI / 6
}
}
val GDMLApp = component<GDMLAppProps> { props ->
var selected by state { props.selected }
var canvas: ThreeCanvas? by state { null }
var visual: Vision? by state { props.rootObject }
val select: (Name?) -> Unit = {
selected = it
}
fun loadData(name: String, data: String) {
visual = when {
name.endsWith(".gdml") || name.endsWith(".xml") -> {
val gdml = GDML.parse(data)
gdml.toVision(gdmlConfiguration)
}
name.endsWith(".json") -> SolidGroup.parseJson(data)
else -> {
window.alert("File extension is not recognized: $name")
error("File extension is not recognized: $name")
}
}
}
flexColumn {
css {
flex(1.0, 1.0, FlexBasis.auto)
}
h1 { +"GDML/JSON loader demo" }
styledDiv {
css {
classes.add("row")
classes.add("p-1")
overflow = Overflow.auto
}
gridColumn(3, maxSize= GridMaxSize.XL, classes = "order-2 order-xl-1") {
card("Load data") {
fileDrop("(drag file here)") { files ->
val file = files?.get(0)
if (file != null) {
FileReader().apply {
onload = {
val string = result as String
loadData(file.name, string)
}
readAsText(file)
}
}
}
}
//tree
card("Object tree", "overflow-auto") {
visual?.let {
objectTree(it, selected, select)
}
}
}
gridColumn(6, maxSize= GridMaxSize.XL, classes = "order-1 order-xl-2") {
//canvas
(visual as? Solid)?.let { visual3D ->
child(ThreeCanvasComponent::class) {
attrs {
this.context = props.context
this.obj = visual3D
this.selected = selected
this.clickCallback = select
this.canvasCallback = {
canvas = it
}
}
}
}
}
gridColumn(3, maxSize= GridMaxSize.XL, classes = "order-3") {
container {
//settings
canvas?.let {
card("Canvas configuration") {
canvasControls(it)
}
}
}
container {
namecrumbs(selected, "World") { selected = it }
}
container {
//properties
card("Properties") {
selected.let { selected ->
val selectedObject: Vision? = when {
selected == null -> null
selected.isEmpty() -> visual
else -> (visual as? VisionGroup)?.get(selected)
}
if (selectedObject != null) {
configEditor(selectedObject, default = selectedObject.getAllProperties(), key = selected)
}
}
}
}
}
}
}
}

View File

@ -1,86 +0,0 @@
package hep.dataforge.vision.gdml.demo
import hep.dataforge.context.Global
import hep.dataforge.js.Application
import hep.dataforge.js.startApplication
import hep.dataforge.vision.gdml.GDMLTransformer
import hep.dataforge.vision.gdml.LUnit
import hep.dataforge.vision.gdml.toVision
import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_OPACITY_KEY
import kotlinx.css.*
import react.child
import react.dom.render
import styled.injectGlobal
import kotlin.browser.document
val gdmlConfiguration: GDMLTransformer.() -> Unit = {
lUnit = LUnit.CM
volumeAction = { volume ->
when {
volume.name.startsWith("ecal01lay") -> GDMLTransformer.Action.REJECT
volume.name.startsWith("UPBL") -> GDMLTransformer.Action.REJECT
volume.name.startsWith("USCL") -> GDMLTransformer.Action.REJECT
volume.name.startsWith("VPBL") -> GDMLTransformer.Action.REJECT
volume.name.startsWith("VSCL") -> GDMLTransformer.Action.REJECT
else -> GDMLTransformer.Action.CACHE
}
}
solidConfiguration = { parent, solid ->
if (
solid.name.startsWith("Yoke")
|| solid.name.startsWith("Pole")
|| parent.physVolumes.isNotEmpty()
) {
useStyle("opaque") {
MATERIAL_OPACITY_KEY put 0.3
}
}
}
}
private class GDMLDemoApp : Application {
override fun start(state: Map<String, Any>) {
injectGlobal {
body {
height = 100.pct
width = 100.pct
margin(0.px)
padding(0.px)
}
}
val context = Global.context("demo") {}
val element = document.getElementById("app") ?: error("Element with id 'app' not found on page")
render(element) {
child(GDMLApp) {
attrs {
this.context = context
this.rootObject = cubes().toVision(gdmlConfiguration)
}
}
}
// (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)
// }
}
}
fun main() {
startApplication(::GDMLDemoApp)
}

View File

@ -0,0 +1,78 @@
package space.kscience.visionforge.gdml.demo
import kotlinx.browser.window
import org.w3c.files.FileReader
import org.w3c.files.get
import react.*
import react.dom.h2
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.fetch
import space.kscience.dataforge.names.Name
import space.kscience.gdml.Gdml
import space.kscience.gdml.decodeFromString
import space.kscience.visionforge.gdml.markLayers
import space.kscience.visionforge.gdml.toVision
import space.kscience.visionforge.ring.ThreeCanvasWithControls
import space.kscience.visionforge.ring.tab
import space.kscience.visionforge.root
import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.Solids
external interface GDMLAppProps : RProps {
var context: Context
var vision: Solid?
var selected: Name?
}
@JsExport
val GDMLApp = functionalComponent<GDMLAppProps>("GDMLApp") { props ->
val visionManager = useMemo(props.context) { props.context.fetch(Solids).visionManager }
var vision: Solid? by useState { props.vision?.apply { root(visionManager) } }
fun loadData(name: String, data: String) {
val parsedVision = when {
name.endsWith(".gdml") || name.endsWith(".xml") -> {
val gdml = Gdml.decodeFromString(data)
gdml.toVision().apply {
root(visionManager)
console.info("Marking layers for file $name")
markLayers()
}
}
name.endsWith(".json") -> visionManager.decodeFromString(data)
else -> {
window.alert("File extension is not recognized: $name")
error("File extension is not recognized: $name")
}
}
vision = parsedVision as? Solid ?: error("Parsed vision is not a solid")
}
child(ThreeCanvasWithControls) {
attrs {
this.context = props.context
this.solid = vision
this.selected = props.selected
tab("Load") {
h2 {
+"Drag and drop .gdml or .json VisionForge files here"
}
fileDrop("(drag file here)") { files ->
val file = files?.get(0)
if (file != null) {
FileReader().apply {
onload = {
val string = result as String
loadData(file.name, string)
}
readAsText(file)
}
}
}
}
}
}
}

View File

@ -0,0 +1,58 @@
package space.kscience.visionforge.gdml.demo
import kotlinx.browser.document
import kotlinx.css.*
import react.child
import react.dom.render
import space.kscience.dataforge.context.Global
import space.kscience.gdml.GdmlShowCase
import space.kscience.visionforge.Application
import space.kscience.visionforge.gdml.toVision
import space.kscience.visionforge.solid.three.ThreePlugin
import space.kscience.visionforge.startApplication
import styled.injectGlobal
private class GDMLDemoApp : Application {
override fun start(state: Map<String, Any>) {
val context = Global.buildContext("gdml-demo"){
plugin(ThreePlugin)
}
injectGlobal {
html{
height = 100.pct
}
body{
height = 100.pct
display = Display.flex
alignItems = Align.stretch
}
"#application"{
width = 100.pct
display = Display.flex
alignItems = Align.stretch
}
}
val element = document.getElementById("application") ?: error("Element with id 'application' not found on page")
render(element) {
child(GDMLApp) {
val vision = GdmlShowCase.cubes().toVision()
//println(context.plugins.fetch(VisionManager).encodeToString(vision))
attrs {
this.context = context
this.vision = vision
}
}
}
}
}
fun main() {
startApplication(::GDMLDemoApp)
}

View File

@ -1,4 +1,4 @@
package hep.dataforge.vision.gdml.demo
package space.kscience.visionforge.gdml.demo
import drop.FileDrop
import kotlinx.css.*
@ -14,6 +14,7 @@ fun RBuilder.fileDrop(title: String, action: (files: FileList?) -> Unit) {
styledDiv {
css {
border(style = BorderStyle.dashed, width = 1.px, color = Color.orange)
flexGrow = 0.0
alignContent = Align.center
}

View File

@ -2,16 +2,12 @@
<html>
<head>
<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">
<title>Three js demo for particle physics</title>
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/main.css">
<script type="text/javascript" src="gdml.js"></script>
<link rel="stylesheet" href="css/fileDrop.css">
<script type="text/javascript" src="main.bundle.js"></script>
<script type="text/javascript" src ="js/jquery-3.4.1.min.js"></script>
<script type="text/javascript" src ="js/bootstrap.bundle.min.js"></script>
</head>
<body class="application">
<div class="container-fluid" id = "app"> </div>
<div id = "application"></div>
</body>
</html>

View File

@ -1,54 +0,0 @@
package hep.dataforge.vision.gdml.demo
import hep.dataforge.meta.DFExperimental
import hep.dataforge.meta.setItem
import hep.dataforge.values.asValue
import hep.dataforge.vision.gdml.LUnit
import hep.dataforge.vision.gdml.readFile
import hep.dataforge.vision.gdml.toVision
import hep.dataforge.vision.solid.SolidGroup
import hep.dataforge.vision.solid.SolidManager
import hep.dataforge.vision.solid.SolidMaterial
import scientifik.gdml.GDML
import java.io.File
import java.util.zip.GZIPInputStream
import java.util.zip.ZipInputStream
@OptIn(DFExperimental::class)
fun SolidManager.Companion.readFile(file: File): SolidGroup = when {
file.extension == "gdml" || file.extension == "xml" -> {
GDML.readFile(file.toPath()).toVision {
lUnit = LUnit.CM
solidConfiguration = { parent, solid ->
if (solid.name == "cave") {
setItem(SolidMaterial.MATERIAL_WIREFRAME_KEY, true.asValue())
}
if (parent.physVolumes.isNotEmpty()) {
useStyle("opaque") {
SolidMaterial.MATERIAL_OPACITY_KEY put 0.3
}
}
}
}
}
file.extension == "json" -> SolidGroup.parseJson(file.readText())
file.name.endsWith("json.zip") -> {
file.inputStream().use {
val unzip = ZipInputStream(it, Charsets.UTF_8)
val text = unzip.readBytes().decodeToString()
SolidGroup.parseJson(text)
}
}
file.name.endsWith("json.gz") -> {
file.inputStream().use {
val unzip = GZIPInputStream(it)
val text = unzip.readBytes().decodeToString()
SolidGroup.parseJson(text)
}
}
else -> error("Unknown extension ${file.extension}")
}
@OptIn(DFExperimental::class)
fun SolidManager.Companion.readFile(fileName: String): SolidGroup = readFile(File(fileName))

View File

@ -1,28 +0,0 @@
package hep.dataforge.vision.gdml.demo
import hep.dataforge.vision.gdml.LUnit
import hep.dataforge.vision.gdml.readFile
import hep.dataforge.vision.gdml.toVision
import hep.dataforge.vision.solid.stringify
import scientifik.gdml.GDML
import java.io.File
import java.nio.file.Paths
fun main(args: Array<String>) {
require(args.isNotEmpty()){"At least one argument is required"}
val inputFileName = args[0]
require(inputFileName.endsWith(".gdml")){"GDML required"}
val outputFileName = args.getOrNull(1)?:inputFileName.replace(".gdml",".json")
val gdml = GDML.readFile(Paths.get(inputFileName))
//GDML.readFile(Paths.get("D:\\Work\\Projects\\visionforge\\visionforge-spatial-gdml\\src\\jvmTest\\resources\\gdml\\simple1.gdml"))
val visual = gdml.toVision {
lUnit = LUnit.CM
}
val json = visual.stringify()
println(json)
File(outputFileName).writeText(json)
//File("D:\\Work\\Projects\\gdml.kt\\gdml-source\\cubes.json").writeText(json)
}

View File

@ -1,22 +1,32 @@
package hep.dataforge.vision.gdml.demo
package space.kscience.visionforge.gdml.demo
import hep.dataforge.context.Global
import hep.dataforge.vision.editor.VisualObjectEditorFragment
import hep.dataforge.vision.editor.VisualObjectTreeFragment
import hep.dataforge.vision.gdml.toVision
import hep.dataforge.vision.solid.SolidManager
import hep.dataforge.vision.solid.SolidMaterial
import hep.dataforge.vision.solid.fx.FX3DPlugin
import hep.dataforge.vision.solid.fx.FXCanvas3D
import javafx.geometry.Orientation
import javafx.scene.Parent
import javafx.stage.FileChooser
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.fetch
import space.kscience.gdml.GdmlShowCase
import space.kscience.visionforge.VisionManager
import space.kscience.visionforge.describedProperties
import space.kscience.visionforge.editor.VisualObjectEditorFragment
import space.kscience.visionforge.editor.VisualObjectTreeFragment
import space.kscience.visionforge.gdml.toVision
import space.kscience.visionforge.solid.FX3DPlugin
import space.kscience.visionforge.solid.FXCanvas3D
import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.SolidMaterial
import tornadofx.*
class GDMLDemoApp : App(GDMLView::class)
class GDMLView : View() {
private val fx3d = Global.plugins.fetch(FX3DPlugin)
private val context = Context {
plugin(FX3DPlugin)
plugin(VisionManager)
}
private val fx3d = context.fetch(FX3DPlugin)
private val visionManager = context.fetch(VisionManager)
private val canvas = FXCanvas3D(fx3d)
private val treeFragment = VisualObjectTreeFragment().apply {
@ -24,7 +34,7 @@ class GDMLView : View() {
}
private val propertyEditor = VisualObjectEditorFragment {
it.getAllProperties()
it.describedProperties
}.apply {
descriptorProperty.set(SolidMaterial.descriptor)
itemProperty.bind(treeFragment.selectedProperty)
@ -36,12 +46,11 @@ class GDMLView : View() {
buttonbar {
button("Load GDML/json") {
action {
runAsync {
val file = chooseFile("Select a GDML/json file", filters = fileNameFilter).firstOrNull()
?: return@runAsync null
SolidManager.readFile(file)
if(file!= null) {
runAsync {
visionManager.readFile(file) as Solid
} ui {
if (it != null) {
canvas.render(it)
}
}
@ -58,7 +67,7 @@ class GDMLView : View() {
init {
runAsync {
cubes().toVision()
GdmlShowCase.cubes().toVision()
} ui {
canvas.render(it)
}

View File

@ -0,0 +1,37 @@
package space.kscience.visionforge.gdml.demo
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.gdml.Gdml
import space.kscience.gdml.decodeFromFile
import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionManager
import space.kscience.visionforge.gdml.toVision
import java.io.File
import java.util.zip.GZIPInputStream
import java.util.zip.ZipInputStream
@OptIn(DFExperimental::class)
fun VisionManager.readFile(file: File): Vision = when {
file.extension == "gdml" || file.extension == "xml" -> {
Gdml.decodeFromFile(file.toPath(),true).toVision()
}
file.extension == "json" -> decodeFromString(file.readText())
file.name.endsWith("json.zip") -> {
file.inputStream().use {
val unzip = ZipInputStream(it, Charsets.UTF_8)
val text = unzip.readBytes().decodeToString()
decodeFromString(text)
}
}
file.name.endsWith("json.gz") -> {
file.inputStream().use {
val unzip = GZIPInputStream(it)
val text = unzip.readBytes().decodeToString()
decodeFromString(text)
}
}
else -> error("Unknown extension ${file.extension}")
}
@OptIn(DFExperimental::class)
fun VisionManager.readFile(fileName: String): Vision = readFile(File(fileName))

View File

@ -0,0 +1,28 @@
package space.kscience.visionforge.gdml.demo
import space.kscience.gdml.Gdml
import space.kscience.gdml.LUnit
import space.kscience.gdml.decodeFromFile
import space.kscience.visionforge.gdml.toVision
import space.kscience.visionforge.solid.Solids
import java.io.File
import java.nio.file.Paths
fun main(args: Array<String>) {
require(args.isNotEmpty()) { "At least one argument is required" }
val inputFileName = args[0]
require(inputFileName.endsWith(".gdml")) { "GDML required" }
val outputFileName = args.getOrNull(1) ?: inputFileName.replace(".gdml", ".json")
val gdml = Gdml.decodeFromFile(Paths.get(inputFileName), true)
//GDML.readFile(Paths.get("D:\\Work\\Projects\\visionforge\\visionforge-spatial-gdml\\src\\jvmTest\\resources\\gdml\\simple1.gdml"))
val vision = gdml.toVision {
lUnit = LUnit.CM
}
val json = Solids.encodeToString(vision)
println(json)
File(outputFileName).writeText(json)
//File("D:\\Work\\Projects\\gdml.kt\\gdml-source\\cubes.json").writeText(json)
}

View File

@ -1,7 +1,7 @@
package hep.dataforge.vision.solid
package space.kscience.visionforge.solid
import hep.dataforge.names.asName
import org.junit.jupiter.api.Test
import space.kscience.dataforge.names.asName
import kotlin.test.Ignore
class FileSerializationTest {
@ -9,7 +9,7 @@ class FileSerializationTest {
@Ignore
fun testFileRead(){
val text = this::class.java.getResourceAsStream("/cubes.json").readBytes().decodeToString()
val visual = SolidGroup.parseJson(text)
val visual = Solids.decodeFromString(text) as SolidGroup
visual["composite_001".asName()]
}
}

3
demo/gdml/webpack.config.d/01.ring.js vendored Normal file
View File

@ -0,0 +1,3 @@
const ringConfig = require('@jetbrains/ring-ui/webpack.config').config;
config.module.rules.push(...ringConfig.module.rules)

View File

@ -0,0 +1,27 @@
plugins {
id("ru.mipt.npm.gradle.js")
}
kscience{
useCoroutines()
application()
}
kotlin{
js(IR){
useCommonJs()
browser {
commonWebpackConfig {
cssSupport.enabled = false
}
}
}
}
dependencies{
implementation(project(":visionforge-gdml"))
implementation(project(":visionforge-plotly"))
implementation(project(":visionforge-threejs"))
implementation(project(":ui:ring"))
}

View File

@ -0,0 +1,50 @@
import kotlinx.browser.document
import kotlinx.css.*
import react.child
import react.dom.render
import space.kscience.dataforge.context.Context
import space.kscience.gdml.GdmlShowCase
import space.kscience.visionforge.Application
import space.kscience.visionforge.VisionClient
import space.kscience.visionforge.gdml.toVision
import space.kscience.visionforge.ring.ThreeCanvasWithControls
import space.kscience.visionforge.ring.ThreeWithControlsPlugin
import space.kscience.visionforge.startApplication
import styled.css
import styled.styledDiv
private class JsPlaygroundApp : Application {
override fun start(state: Map<String, Any>) {
val playgroundContext = Context {
plugin(ThreeWithControlsPlugin)
plugin(VisionClient)
}
val element = document.getElementById("playground") ?: error("Element with id 'playground' not found on page")
val visionOfD0 = GdmlShowCase.babyIaxo().toVision()
render(element) {
styledDiv {
css{
padding(0.pt)
margin(0.pt)
height = 100.vh
width = 100.vw
}
child(ThreeCanvasWithControls) {
attrs {
context = playgroundContext
solid = visionOfD0
}
}
}
}
}
}
public fun main() {
startApplication(::JsPlaygroundApp)
}

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>js-playground</title>
<script src="js-playground.js"></script>
</head>
<body class="application">
<div id="playground"></div>
</body>
</html>

View File

@ -0,0 +1,3 @@
const ringConfig = require('@jetbrains/ring-ui/webpack.config').config;
config.module.rules.push(...ringConfig.module.rules)

View File

@ -0,0 +1,35 @@
plugins {
kotlin("jvm")
kotlin("jupyter.api")
id("com.github.johnrengelman.shadow") version "6.1.0"
}
repositories {
mavenCentral()
maven("https://repo.kotlin.link")
}
dependencies {
implementation(project(":demo:playground"))
}
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile> {
kotlinOptions {
useIR = true
jvmTarget = ru.mipt.npm.gradle.KScienceVersions.JVM_TARGET.toString()
}
}
extensions.findByType<JavaPluginExtension>()?.apply {
targetCompatibility = ru.mipt.npm.gradle.KScienceVersions.JVM_TARGET
}
tasks.withType<Test> {
useJUnitPlatform()
}
tasks.processJupyterApiResources {
libraryProducers = listOf("space.kscience.dataforge.playground.VisionForgePlayGroundForJupyter")
}
tasks.findByName("shadowJar")?.dependsOn("processJupyterApiResources")

View File

@ -0,0 +1,98 @@
package space.kscience.dataforge.playground
import kotlinx.html.div
import kotlinx.html.id
import kotlinx.html.script
import kotlinx.html.stream.createHTML
import kotlinx.html.unsafe
import org.jetbrains.kotlinx.jupyter.api.HTML
import org.jetbrains.kotlinx.jupyter.api.annotations.JupyterLibrary
import org.jetbrains.kotlinx.jupyter.api.libraries.*
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.gdml.Gdml
import space.kscience.plotly.Plot
import space.kscience.visionforge.Vision
import space.kscience.visionforge.gdml.toVision
import space.kscience.visionforge.html.HtmlVisionFragment
import space.kscience.visionforge.html.Page
import space.kscience.visionforge.html.embedVisionFragment
import space.kscience.visionforge.plotly.PlotlyPlugin
import space.kscience.visionforge.plotly.asVision
import space.kscience.visionforge.solid.Solids
import space.kscience.visionforge.visionManager
@JupyterLibrary
@DFExperimental
internal class VisionForgePlayGroundForJupyter : JupyterIntegration() {
private val context = Context("VisionForge") {
plugin(Solids)
plugin(PlotlyPlugin)
}
private val jsBundle = ResourceFallbacksBundle(listOf(
ResourceLocation("js/visionforge-playground.js", ResourcePathType.CLASSPATH_PATH))
)
private val jsResource = LibraryResource(name = "VisionForge", type = ResourceType.JS, bundles = listOf(jsBundle))
private var counter = 0
private fun produceHtmlVisionString(fragment: HtmlVisionFragment) = createHTML().div {
val id = "visionforge.vision[${counter++}]"
div {
this.id = id
embedVisionFragment(context.visionManager, fragment = fragment)
}
script {
type = "text/javascript"
unsafe { +"window.renderAllVisionsById(\"$id\");" }
}
}
override fun Builder.onLoaded() {
resource(jsResource)
import(
"space.kscience.gdml.*",
"space.kscience.plotly.*",
"space.kscience.plotly.models.*",
"kotlinx.html.*",
"space.kscience.visionforge.solid.*",
"space.kscience.visionforge.html.Page",
"space.kscience.visionforge.html.page"
)
render<Gdml> { gdmlModel ->
val fragment = HtmlVisionFragment {
vision(gdmlModel.toVision())
}
HTML(produceHtmlVisionString(fragment))
}
render<Vision> { vision ->
val fragment = HtmlVisionFragment {
vision(vision)
}
HTML(produceHtmlVisionString(fragment))
}
render<Plot> { plot ->
val fragment = HtmlVisionFragment {
vision(plot.asVision())
}
HTML(produceHtmlVisionString(fragment))
}
render<space.kscience.plotly.PlotlyHtmlFragment> { fragment ->
HTML(createHTML().apply(fragment.visit).finalize())
}
render<Page> { page ->
HTML(page.render(createHTML()), true)
}
}
}

View File

@ -30,5 +30,5 @@ run `demo/muon-monitor/application/run` task.
##### Example view:
![](../../doc/resources/muon-monitor.png)
![](../../docs/images/muon-monitor.png)

View File

@ -1,43 +1,31 @@
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPILATION_NAME
import scientifik.jsDistDirectory
plugins {
id("scientifik.mpp")
id("application")
id("ru.mipt.npm.gradle.mpp")
application
}
group = "ru.mipt.npm"
val ktorVersion = "1.3.2"
val ktorVersion: String = ru.mipt.npm.gradle.KScienceVersions.ktorVersion
kscience {
useCoroutines()
useSerialization()
application()
}
kotlin {
val installJS = tasks.getByName("jsBrowserDistribution")
js {
browser {
dceTask {
dceOptions {
keep("ktor-ktor-io.\$\$importsForInline\$\$.ktor-ktor-io.io.ktor.utils.io")
}
}
webpackTask {
mode = org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig.Mode.PRODUCTION
}
}
}
jvm {
withJava()
compilations[MAIN_COMPILATION_NAME]?.apply {
tasks.getByName<ProcessResources>(processResourcesTaskName) {
dependsOn(installJS)
afterEvaluate {
from(project.jsDistDirectory)
}
}
}
afterEvaluate {
val jsBrowserDistribution by tasks.getting
tasks.getByName<ProcessResources>("jvmProcessResources") {
dependsOn(jsBrowserDistribution)
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
from(jsBrowserDistribution)
}
}
sourceSets {
@ -57,31 +45,31 @@ kotlin {
dependencies {
implementation(project(":ui:bootstrap"))
implementation("io.ktor:ktor-client-js:$ktorVersion")
implementation("io.ktor:ktor-client-serialization-js:$ktorVersion")
implementation(npm("text-encoding"))
implementation(npm("abort-controller"))
implementation(npm("bufferutil"))
implementation(npm("utf-8-validate"))
implementation(npm("fs"))
// implementation(npm("jquery"))
// implementation(npm("popper.js"))
// implementation(npm("react-is"))
implementation("io.ktor:ktor-client-serialization:$ktorVersion")
implementation(project(":visionforge-threejs"))
implementation(devNpm("webpack-bundle-analyzer", "4.4.0"))
}
}
}
}
application {
mainClassName = "ru.mipt.npm.muon.monitor.server.MMServerKt"
mainClass.set("ru.mipt.npm.muon.monitor.server.MMServerKt")
}
distributions {
main {
contents {
from("$buildDir/libs") {
rename("${rootProject.name}-jvm", rootProject.name)
into("lib")
}
}
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinJsCompile>() {
kotlinOptions {
freeCompilerArgs = freeCompilerArgs + "-Xir-property-lazy-initialization"
}
}
//distributions {
// main {
// contents {
// from("$buildDir/libs") {
// rename("${rootProject.name}-jvm", rootProject.name)
// into("lib")
// }
// }
// }
//}

View File

@ -1,10 +1,7 @@
@file:UseSerializers(Point3DSerializer::class)
package ru.mipt.npm.muon.monitor
import hep.dataforge.vision.solid.Point3D
import hep.dataforge.vision.solid.Point3DSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
import space.kscience.visionforge.solid.Point3D
typealias Track = List<Point3D>

View File

@ -1,13 +1,15 @@
package ru.mipt.npm.muon.monitor
import hep.dataforge.vision.removeAll
import hep.dataforge.vision.solid.*
import ru.mipt.npm.muon.monitor.Monitor.CENTRAL_LAYER_Z
import ru.mipt.npm.muon.monitor.Monitor.LOWER_LAYER_Z
import ru.mipt.npm.muon.monitor.Monitor.UPPER_LAYER_Z
import space.kscience.visionforge.VisionManager
import space.kscience.visionforge.removeAll
import space.kscience.visionforge.root
import space.kscience.visionforge.solid.*
import kotlin.math.PI
class Model {
class Model(val manager: VisionManager) {
private val map = HashMap<String, SolidGroup>()
private val events = HashSet<Event>()
@ -34,6 +36,7 @@ class Model {
var tracks: SolidGroup
val root: SolidGroup = SolidGroup().apply {
root(this@Model.manager)
rotationX = PI / 2
group("bottom") {
Monitor.detectors.filter { it.center.z == LOWER_LAYER_Z }.forEach {
@ -52,18 +55,16 @@ class Model {
detector(it)
}
}
tracks = group("tracks")
}
private fun highlight(pixel: String) {
map[pixel]?.color("blue")
map[pixel]?.color?.invoke("blue")
}
fun reset() {
map.values.forEach {
it.config
it.setItem(SolidMaterial.MATERIAL_COLOR_KEY, null)
it.setProperty(SolidMaterial.MATERIAL_COLOR_KEY, null)
}
tracks.removeAll()
}
@ -80,7 +81,5 @@ class Model {
}
}
companion object {
fun buildGeometry() = Model().root
}
fun encodeToString(): String = manager.encodeToString(this.root)
}

View File

@ -1,9 +1,9 @@
package ru.mipt.npm.muon.monitor
import hep.dataforge.vision.solid.Point3D
import hep.dataforge.vision.solid.plus
import ru.mipt.npm.muon.monitor.Monitor.PIXEL_XY_SIZE
import ru.mipt.npm.muon.monitor.Monitor.PIXEL_Z_SIZE
import space.kscience.visionforge.solid.Point3D
import space.kscience.visionforge.solid.plus
/**
* A single pixel
@ -11,7 +11,7 @@ import ru.mipt.npm.muon.monitor.Monitor.PIXEL_Z_SIZE
class SC1(
val name: String,
val center: Point3D,
val xSize: Double = PIXEL_XY_SIZE, val ySize: Double = PIXEL_XY_SIZE, val zSize: Double = PIXEL_Z_SIZE
val xSize: Float = PIXEL_XY_SIZE, val ySize: Float = PIXEL_XY_SIZE, val zSize: Float = PIXEL_Z_SIZE
)
class SC16(
@ -121,12 +121,12 @@ internal expect fun readMonitorConfig(): String
object Monitor {
const val GEOMETRY_TOLERANCE = 0.01
const val PIXEL_XY_SIZE = 122.0
const val PIXEL_XY_SPACING = 123.2
const val PIXEL_Z_SIZE = 30.0
const val CENTRAL_LAYER_Z = 0.0
const val UPPER_LAYER_Z = -166.0
const val LOWER_LAYER_Z = 180.0
const val PIXEL_XY_SIZE = 122.0f
const val PIXEL_XY_SPACING = 123.2f
const val PIXEL_Z_SIZE = 30.0f
const val CENTRAL_LAYER_Z = 0.0f
const val UPPER_LAYER_Z = -166.0f
const val LOWER_LAYER_Z = 180.0f
/**
* Build map for the whole monitor

View File

@ -1,89 +1,115 @@
package ru.mipt.npm.muon.monitor
import hep.dataforge.context.Context
import hep.dataforge.names.Name
import hep.dataforge.names.NameToken
import hep.dataforge.names.isEmpty
import hep.dataforge.vision.Vision
import hep.dataforge.vision.bootstrap.card
import hep.dataforge.vision.bootstrap.objectTree
import hep.dataforge.vision.react.component
import hep.dataforge.vision.react.configEditor
import hep.dataforge.vision.react.state
import hep.dataforge.vision.solid.specifications.Camera
import hep.dataforge.vision.solid.specifications.Canvas3DOptions
import hep.dataforge.vision.solid.three.ThreeCanvas
import hep.dataforge.vision.solid.three.ThreeCanvasComponent
import hep.dataforge.vision.solid.three.canvasControls
import io.ktor.client.HttpClient
import io.ktor.client.request.get
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.css.*
import kotlinx.html.js.onClickFunction
import react.RProps
import react.*
import react.dom.*
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.NameToken
import space.kscience.dataforge.names.isEmpty
import space.kscience.dataforge.names.length
import space.kscience.visionforge.Vision
import space.kscience.visionforge.bootstrap.canvasControls
import space.kscience.visionforge.bootstrap.card
import space.kscience.visionforge.bootstrap.gridRow
import space.kscience.visionforge.bootstrap.visionPropertyEditor
import space.kscience.visionforge.react.ThreeCanvasComponent
import space.kscience.visionforge.react.flexColumn
import space.kscience.visionforge.react.visionTree
import space.kscience.visionforge.solid.specifications.Camera
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
import styled.css
import styled.styledDiv
import kotlin.math.PI
interface MMAppProps : RProps {
external interface MMAppProps : RProps {
var model: Model
var context: Context
var connection: HttpClient
var selected: Name?
}
private val canvasConfig = Canvas3DOptions {
@JsExport
val MMApp = functionalComponent<MMAppProps>("Muon monitor") { props ->
var selected by useState { props.selected }
val onSelect: (Name?) -> Unit = {
selected = it
}
val mmOptions = useMemo {
Canvas3DOptions {
camera = Camera {
distance = 2100.0
latitude = PI / 6
azimuth = PI + PI / 6
}
}
val MMApp = component<MMAppProps> { props ->
var selected by state { props.selected }
var canvas: ThreeCanvas? by state { null }
val select: (Name?) -> Unit = {
selected = it
}
val visual = props.model.root
div("row") {
h1("mx-auto") {
+"Muon monitor demo"
this.onSelect = onSelect
}
}
div("row") {
div("col-lg-3 px-0 overflow-auto") {
val root = props.model.root
gridRow {
flexColumn {
css {
+"col-lg-3"
+"order-lg-1"
+"order-2"
padding(0.px)
overflowY = Overflow.auto
height = 100.vh
}
//tree
card("Object tree") {
objectTree(visual, selected, select)
css {
flex(1.0, 1.0, FlexBasis.auto)
}
visionTree(root, selected, onSelect)
}
}
div("col-lg-6") {
flexColumn {
css {
+"col-lg-6"
+"order-lg-2"
+"order-1"
height = 100.vh
}
h1("mx-auto page-header") {
+"Muon monitor demo"
}
//canvas
child(ThreeCanvasComponent::class) {
child(ThreeCanvasComponent) {
attrs {
this.context = props.context
this.obj = visual
this.options = canvasConfig
this.solid = root
this.selected = selected
this.clickCallback = select
this.canvasCallback = {
canvas = it
this.options = mmOptions
}
}
}
flexColumn {
css {
+"col-lg-3"
+"order-3"
padding(0.px)
height = 100.vh
}
styledDiv {
css {
flex(0.0, 1.0, FlexBasis.zero)
}
div("col-lg-3") {
div("row") {
//settings
canvas?.let {
card("Canvas configuration") {
canvasControls(it)
}
canvasControls(mmOptions, root)
}
card("Events") {
button {
+"Next"
@ -106,8 +132,10 @@ val MMApp = component<MMAppProps> { props ->
}
}
}
div("row") {
div("container-fluid p-0") {
styledDiv {
css {
padding(0.px)
}
nav {
attrs {
attributes["aria-label"] = "breadcrumb"
@ -118,7 +146,7 @@ val MMApp = component<MMAppProps> { props ->
+"World"
attrs {
onClickFunction = {
selected = hep.dataforge.names.Name.EMPTY
selected = Name.EMPTY
}
}
}
@ -144,18 +172,20 @@ val MMApp = component<MMAppProps> { props ->
}
}
}
styledDiv {
css {
overflowY = Overflow.auto
}
div("row") {
//properties
card("Properties") {
selected.let { selected ->
val selectedObject: Vision? = when {
selected == null -> null
selected.isEmpty() -> visual
else -> visual[selected]
selected.isEmpty() -> root
else -> root[selected]
}
if (selectedObject != null) {
configEditor(selectedObject, default = selectedObject.getAllProperties(), key = selected)
visionPropertyEditor(selectedObject, key = selected)
}
}
}

View File

@ -1,48 +1,47 @@
package ru.mipt.npm.muon.monitor
import hep.dataforge.context.Global
import hep.dataforge.js.Application
import hep.dataforge.js.startApplication
import hep.dataforge.vision.solid.SolidManager
import io.ktor.client.HttpClient
import io.ktor.client.features.json.JsonFeature
import io.ktor.client.features.json.serializer.KotlinxSerializer
import kotlinx.serialization.json.Json
import kotlinx.browser.document
import react.child
import react.dom.div
import react.dom.render
import kotlin.browser.document
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.Global
import space.kscience.dataforge.context.fetch
import space.kscience.visionforge.Application
import space.kscience.visionforge.VisionManager
import space.kscience.visionforge.bootstrap.useBootstrap
import space.kscience.visionforge.startApplication
private class MMDemoApp : Application {
private val model = Model()
private val visionManager = Global.fetch(VisionManager)
private val model = Model(visionManager)
private val connection = HttpClient {
install(JsonFeature) {
serializer = KotlinxSerializer(Json(context = SolidManager.serialModule))
serializer = KotlinxSerializer()
}
}
//TODO introduce react application
override fun start(state: Map<String, Any>) {
useBootstrap()
val context = Global.context("demo") {}
val element = document.getElementById("app") ?: error("Element with id 'app' not found on page")
val context = Context("demo")
render(element) {
div("container-fluid h-100") {
child(MMApp) {
attrs {
model = this@MMDemoApp.model
connection = this@MMDemoApp.connection
this.model = this@MMDemoApp.model
this.connection = this@MMDemoApp.connection
this.context = context
}
}
}
}
}
}
fun main() {
startApplication(::MMDemoApp)

View File

@ -1,9 +1,7 @@
package ru.mipt.npm.muon.monitor
import hep.dataforge.js.requireJS
actual fun readResource(path: String): String {
return requireJS(path) as String
return kotlinext.js.require(path) as String
}
// TODO replace by resource

View File

@ -4,13 +4,10 @@
<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="css/bootstrap.min.css">
<link rel="stylesheet" href="css/main.css">
<script type="text/javascript" src="main.bundle.js"></script>
<script type="text/javascript" src ="js/jquery-3.4.1.min.js"></script>
<script type="text/javascript" src ="js/bootstrap.bundle.min.js"></script>
<script type="text/javascript" src="muon-monitor.js"></script>
<link rel="stylesheet" href="css/custom-bootstrap.css">
</head>
<body class="application">
<div class="container-fluid" id = "app"> </div>
<div class="container-fluid max-vh-100" id = "app"> </div>
</body>
</html>

View File

@ -1,7 +1,6 @@
package ru.mipt.npm.muon.monitor.server
import hep.dataforge.vision.solid.SolidManager
import io.ktor.application.Application
import io.ktor.application.call
import io.ktor.application.install
@ -9,34 +8,42 @@ import io.ktor.application.log
import io.ktor.features.CallLogging
import io.ktor.features.ContentNegotiation
import io.ktor.features.DefaultHeaders
import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode
import io.ktor.http.content.resources
import io.ktor.http.content.static
import io.ktor.response.respond
import io.ktor.response.respondText
import io.ktor.routing.Routing
import io.ktor.routing.get
import io.ktor.serialization.json
import io.ktor.server.cio.CIO
import io.ktor.server.engine.embeddedServer
import io.ktor.util.KtorExperimentalAPI
import org.apache.commons.math3.random.JDKRandomGenerator
import ru.mipt.npm.muon.monitor.Model
import ru.mipt.npm.muon.monitor.sim.Cos2TrackGenerator
import ru.mipt.npm.muon.monitor.sim.simulateOne
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.Global
import space.kscience.dataforge.context.fetch
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.visionforge.solid.Solids
import java.awt.Desktop
import java.io.File
import java.net.URI
private val generator = Cos2TrackGenerator(JDKRandomGenerator(223))
fun Application.module() {
@OptIn(DFExperimental::class)
fun Application.module(context: Context = Global) {
val currentDir = File(".").absoluteFile
environment.log.info("Current directory: $currentDir")
val solidManager = context.fetch(Solids)
install(DefaultHeaders)
install(CallLogging)
install(ContentNegotiation) {
json(module = SolidManager.serialModule)
json()
}
install(Routing) {
get("/event") {
@ -44,7 +51,11 @@ fun Application.module() {
call.respond(event)
}
get("/geometry") {
call.respond(Model.buildGeometry())
call.respondText(
Model(solidManager.visionManager).encodeToString(),
contentType = ContentType.Application.Json,
status = HttpStatusCode.OK
)
}
static("/") {
resources()
@ -57,7 +68,6 @@ fun Application.module() {
}
}
@OptIn(KtorExperimentalAPI::class)
fun main() {
embeddedServer(CIO, 8080, host = "localhost", module = Application::module).start(wait = true)
}

View File

@ -17,19 +17,19 @@ import kotlin.random.Random
internal class SC1Aux(val sc: SC1, var efficiency: Double = 1.0) {
// val layer: Layer = findLayer(center.z);
private val upLayer =
findLayer(sc.center.z + sc.zSize / 2.0)//Layer("${name}_up", center.z + zSize / 2.0);
findLayer(sc.center.z + sc.zSize / 2f)//Layer("${name}_up", center.z + zSize / 2.0);
private val bottomLayer =
findLayer(sc.center.z - sc.zSize / 2.0)//Layer("${name}_bottom", center.z - zSize / 2.0);
findLayer(sc.center.z - sc.zSize / 2f)//Layer("${name}_bottom", center.z - zSize / 2.0);
private val centralLayer = findLayer(sc.center.z)
private val center = Vector3D(sc.center.x, sc.center.y, sc.center.z)
private val center = Vector3D(sc.center.x.toDouble(), sc.center.y.toDouble(), sc.center.z.toDouble())
private val sideLayers: Array<Plane> = arrayOf(
Plane(center.add(Vector3D(PIXEL_XY_SIZE / 2, 0.0, 0.0)), Vector3D(1.0, 0.0, 0.0), GEOMETRY_TOLERANCE),
Plane(center.add(Vector3D(-PIXEL_XY_SIZE / 2, 0.0, 0.0)), Vector3D(-1.0, 0.0, 0.0), GEOMETRY_TOLERANCE),
Plane(center.add(Vector3D(0.0, PIXEL_XY_SIZE / 2, 0.0)), Vector3D(0.0, 1.0, 0.0), GEOMETRY_TOLERANCE),
Plane(center.add(Vector3D(0.0, -PIXEL_XY_SIZE / 2, 0.0)), Vector3D(0.0, -1.0, 0.0), GEOMETRY_TOLERANCE)
);
Plane(center.add(Vector3D(PIXEL_XY_SIZE / 2.0, 0.0, 0.0)), Vector3D(1.0, 0.0, 0.0), GEOMETRY_TOLERANCE),
Plane(center.add(Vector3D(-PIXEL_XY_SIZE / 2.0, 0.0, 0.0)), Vector3D(-1.0, 0.0, 0.0), GEOMETRY_TOLERANCE),
Plane(center.add(Vector3D(0.0, PIXEL_XY_SIZE / 2.0, 0.0)), Vector3D(0.0, 1.0, 0.0), GEOMETRY_TOLERANCE),
Plane(center.add(Vector3D(0.0, -PIXEL_XY_SIZE / 2.0, 0.0)), Vector3D(0.0, -1.0, 0.0), GEOMETRY_TOLERANCE)
)
//TODO add efficiency
private fun containsPoint(x: Double, y: Double, z: Double, tolerance: Double = GEOMETRY_TOLERANCE): Boolean {
@ -63,8 +63,8 @@ internal class SC1Aux(val sc: SC1, var efficiency: Double = 1.0) {
* The layer number from up to bottom
*/
fun getLayerNumber(): Int {
return when (this.center.z) {
UPPER_LAYER_Z -> 1;
return when (this.center.z.toFloat()) {
UPPER_LAYER_Z -> 1
CENTRAL_LAYER_Z -> 2;
LOWER_LAYER_Z -> 3;
else -> throw RuntimeException("Unknown layer");

View File

@ -1,11 +1,11 @@
package ru.mipt.npm.muon.monitor.sim
import hep.dataforge.vision.solid.Point3D
import org.apache.commons.math3.geometry.euclidean.threed.Line
import org.apache.commons.math3.geometry.euclidean.threed.Plane
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D
import ru.mipt.npm.muon.monitor.Monitor.CENTRAL_LAYER_Z
import ru.mipt.npm.muon.monitor.Monitor.GEOMETRY_TOLERANCE
import space.kscience.visionforge.solid.Point3D
/**
* Created by darksnake on 11-May-16.
@ -45,7 +45,7 @@ fun makeTrack(start: Vector3D, direction: Vector3D): Line {
fun makeTrack(x: Double, y: Double, theta: Double, phi: Double): Line {
//TODO check angle definitions
return makeTrack(
Vector3D(x, y, CENTRAL_LAYER_Z),
Vector3D(x, y, CENTRAL_LAYER_Z.toDouble()),
Vector3D(phi, theta)
)
}

View File

@ -7,19 +7,18 @@ import ru.mipt.npm.muon.monitor.Event
import ru.mipt.npm.muon.monitor.Monitor
import ru.mipt.npm.muon.monitor.SC1
import ru.mipt.npm.muon.monitor.readResource
import java.util.*
// minimal track length in detector
internal const val MINIMAL_TRACK_LENGTH = 10.0
private val layerCache = HashMap<Double, Plane>()
private val layerCache = HashMap<Float, Plane>()
fun findLayer(z: Double): Plane = layerCache.getOrPut(z) {
fun findLayer(z: Float): Plane = layerCache.getOrPut(z) {
Plane(
Vector3D(0.0, 0.0, z), Vector3D(0.0, 0.0, 1.0),
Monitor.GEOMETRY_TOLERANCE
Vector3D(0.0, 0.0, z.toDouble()), Vector3D(0.0, 0.0, 1.0),
Monitor.GEOMETRY_TOLERANCE.toDouble()
)
}

View File

@ -28,8 +28,8 @@ interface TrackGenerator {
*/
class UniformTrackGenerator(
override val rnd: RandomGenerator,
val maxX: Double = 4 * PIXEL_XY_SIZE,
val maxY: Double = 4 * PIXEL_XY_SIZE
val maxX: Float = 4 * PIXEL_XY_SIZE,
val maxY: Float = 4 * PIXEL_XY_SIZE
) :
TrackGenerator {
override fun generate(): Line {
@ -44,8 +44,8 @@ class UniformTrackGenerator(
class FixedAngleGenerator(
override val rnd: RandomGenerator,
val phi: Double, val theta: Double,
val maxX: Double = 4 * PIXEL_XY_SIZE,
val maxY: Double = 4 * PIXEL_XY_SIZE
val maxX: Float = 4 * PIXEL_XY_SIZE,
val maxY: Float = 4 * PIXEL_XY_SIZE
) : TrackGenerator {
override fun generate(): Line {
val x = (1 - rnd.nextDouble() * 2.0) * maxX
@ -60,8 +60,8 @@ class FixedAngleGenerator(
class Cos2TrackGenerator(
override val rnd: RandomGenerator,
val power: Double = 2.0,
val maxX: Double = 4 * PIXEL_XY_SIZE,
val maxY: Double = 4 * PIXEL_XY_SIZE
val maxX: Float = 4 * PIXEL_XY_SIZE,
val maxY: Float = 4 * PIXEL_XY_SIZE
) :
TrackGenerator {
override fun generate(): Line {

View File

@ -1,6 +1,7 @@
package ru.mipt.npm.muon.monitor
import kotlin.test.*
import kotlin.test.Test
import kotlin.test.assertTrue
class GeometryTest {

View File

@ -0,0 +1,75 @@
plugins {
kotlin("multiplatform")
}
repositories{
jcenter()
maven("https://kotlin.bintray.com/kotlinx")
maven("https://dl.bintray.com/kotlin/kotlin-eap")
maven("https://dl.bintray.com/mipt-npm/dataforge")
maven("https://dl.bintray.com/mipt-npm/kscience")
maven("https://dl.bintray.com/mipt-npm/dev")
}
kotlin {
js(IR) {
useCommonJs()
browser {
webpackTask {
this.outputFileName = "js/visionforge-playground.js"
}
commonWebpackConfig {
sourceMaps = false
cssSupport.enabled = false
}
}
binaries.executable()
}
jvm{
compilations.all {
kotlinOptions.jvmTarget = "11"
}
testRuns["test"].executionTask.configure {
useJUnitPlatform()
}
}
afterEvaluate {
val jsBrowserDistribution by tasks.getting
tasks.getByName<ProcessResources>("jvmProcessResources") {
dependsOn(jsBrowserDistribution)
afterEvaluate {
from(jsBrowserDistribution)
}
}
}
sourceSets {
val commonMain by getting {
dependencies {
api(project(":visionforge-solid"))
api(project(":visionforge-gdml"))
api(project(":visionforge-plotly"))
}
}
val jsMain by getting{
dependencies {
implementation(project(":ui:ring"))
api(project(":visionforge-threejs"))
}
}
val jvmMain by getting{
dependencies {
api(project(":visionforge-server"))
api("ch.qos.logback:logback-classic:1.2.3")
implementation("com.github.Ricky12Awesome:json-schema-serialization:0.6.6")
}
}
}
}

View File

@ -0,0 +1,10 @@
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.visionforge.plotly.PlotlyPlugin
import space.kscience.visionforge.ring.ThreeWithControlsPlugin
import space.kscience.visionforge.runVisionClient
@DFExperimental
fun main() = runVisionClient {
plugin(PlotlyPlugin)
plugin(ThreeWithControlsPlugin)
}

View File

@ -0,0 +1,244 @@
package space.kscience.visionforge.examples
import space.kscience.dataforge.context.Context
import space.kscience.gdml.*
import space.kscience.visionforge.gdml.toVision
import space.kscience.visionforge.html.ResourceLocation
import space.kscience.visionforge.solid.Solids
import space.kscience.visionforge.solid.color
import space.kscience.visionforge.solid.invoke
import space.kscience.visionforge.visible
import java.nio.file.Path
fun main() {
val context = Context {
plugin(Solids)
}
context.makeVisionFile(Path.of("curves.html"), resourceLocation = ResourceLocation.EMBED) {
vision("canvas") {
Gdml {
// geometry variables
val worldSize = 500
// chamber
val chamberHeight = 30 // length of the chamber
val chamberDiameter = 102 // inner diameter of the copper chamber
val chamberOuterSquareSide = 134 // chamber has a square footprint
val chamberBackplateThickness = 15 // thickness of the backplate of the chamber
// teflon disk
val cathodeTeflonDiskHoleRadius = 15
val cathodeTeflonDiskThickness = 5
val cathodeCopperSupportOuterRadius = 45
val cathodeCopperSupportInnerRadius = 8.5
val cathodeCopperSupportThickness = 1
// mylar cathode
val mylarCathodeThickness = 0.004
// patern
val cathodePatternLineWidth = 0.3
val cathodePatternDiskRadius = 4.25
// readout
val chamberTeflonWallThickness = 1
val readoutKaptonThickness = 0.5
val readoutCopperThickness = 0.2
val readoutPlaneSide = 60
structure {
val worldMaterial = materials.composite("G4_AIR")
val worldBox = solids.box(worldSize, worldSize, worldSize, name = "world")
val shieldingMaterial = materials.composite("G4_Pb")
val scintillatorMaterial = materials.composite("BC408")
val captureMaterial = materials.composite("G4_Cd")
// chamber
val copperMaterial = materials.composite("G4_Cu")
val chamberSolidBase = solids.box(chamberOuterSquareSide, chamberOuterSquareSide, chamberHeight)
val chamberSolidHole = solids.tube(chamberDiameter / 2, chamberHeight)
val chamberSolid = solids.subtraction(chamberSolidBase, chamberSolidHole)
val chamberBodyVolume = volume(copperMaterial, chamberSolid)
val chamberBackplateSolid =
solids.box(chamberOuterSquareSide, chamberOuterSquareSide, chamberBackplateThickness)
val chamberBackplateVolume = volume(copperMaterial, chamberBackplateSolid)
// chamber teflon walls
val teflonMaterial = materials.composite("G4_TEFLON")
val chamberTeflonWallSolid = solids.tube(chamberDiameter / 2, chamberHeight) {
rmin = chamberDiameter / 2.0 - chamberTeflonWallThickness
}
val chamberTeflonWallVolume = volume(teflonMaterial, chamberTeflonWallSolid)
// cathode
val cathodeCopperDiskMaterial = materials.composite("G4_Cu")
val cathodeWindowMaterial = materials.composite("G4_MYLAR")
val cathodeTeflonDiskSolidBase =
solids.tube(chamberOuterSquareSide / 2, cathodeTeflonDiskThickness) {
rmin = cathodeTeflonDiskHoleRadius
}
val cathodeCopperDiskSolid =
solids.tube(cathodeCopperSupportOuterRadius, cathodeCopperSupportThickness) {
rmin = cathodeCopperSupportInnerRadius
}
val cathodeTeflonDiskSolid = solids.subtraction(cathodeTeflonDiskSolidBase, cathodeCopperDiskSolid)
val cathodeTeflonDiskVolume = volume(teflonMaterial, cathodeTeflonDiskSolid)
val cathodeWindowSolid = solids.tube(cathodeTeflonDiskHoleRadius, mylarCathodeThickness)
val cathodeWindowVolume = volume(cathodeWindowMaterial, cathodeWindowSolid)
val cathodeFillingMaterial = materials.composite("G4_Galactic")
val cathodeFillingSolidBase = solids.tube(cathodeTeflonDiskHoleRadius, cathodeTeflonDiskThickness)
val cathodeFillingSolid = solids.subtraction(cathodeFillingSolidBase, cathodeCopperDiskSolid) {
position(z = chamberHeight / 2 - mylarCathodeThickness / 2)
}
val cathodeFillingVolume = volume(cathodeFillingMaterial, cathodeFillingSolid)
// pattern
val cathodePatternLineAux = solids.box(
cathodePatternLineWidth,
cathodeCopperSupportInnerRadius * 2,
cathodeCopperSupportThickness
)
val cathodePatternCentralHole = solids.tube(
cathodePatternDiskRadius - 0 * cathodePatternLineWidth,
cathodeCopperSupportThickness * 1.1
)
val cathodePatternLine = solids.subtraction(cathodePatternLineAux, cathodePatternCentralHole)
val cathodePatternDisk = solids.tube(
cathodePatternDiskRadius,
cathodeCopperSupportThickness
) { rmin = cathodePatternDiskRadius - cathodePatternLineWidth }
val cathodeCopperDiskSolidAux0 =
solids.union(cathodeCopperDiskSolid, cathodePatternLine) {
rotation(x = 0, y = 0, z = 0)
}
val cathodeCopperDiskSolidAux1 =
solids.union(cathodeCopperDiskSolidAux0, cathodePatternLine) {
rotation = GdmlRotation(
"cathodePatternRotation1", x = 0, y = 0, z = 45
)
}
val cathodeCopperDiskSolidAux2 =
solids.union(cathodeCopperDiskSolidAux1, cathodePatternLine) {
rotation = GdmlRotation(
"cathodePatternRotation2", x = 0, y = 0, z = 90
)
}
val cathodeCopperDiskSolidAux3 =
solids.union(cathodeCopperDiskSolidAux2, cathodePatternLine) {
rotation = GdmlRotation(
"cathodePatternRotation3", x = 0, y = 0, z = 135
)
}
val cathodeCopperDiskFinal =
solids.union(cathodeCopperDiskSolidAux3, cathodePatternDisk)
val cathodeCopperDiskVolume =
volume(cathodeCopperDiskMaterial, cathodeCopperDiskFinal)
val gasSolidOriginal = solids.tube(
chamberDiameter / 2 - chamberTeflonWallThickness,
chamberHeight
)
val kaptonReadoutMaterial = materials.composite("G4_KAPTON")
val kaptonReadoutSolid = solids.box(
chamberOuterSquareSide,
chamberOuterSquareSide,
readoutKaptonThickness)
val kaptonReadoutVolume = volume( kaptonReadoutMaterial, kaptonReadoutSolid)
val copperReadoutSolid =
solids.box(readoutPlaneSide, readoutPlaneSide, readoutCopperThickness)
val copperReadoutVolume = volume(copperMaterial, copperReadoutSolid)
val gasSolidAux =
solids.subtraction(gasSolidOriginal, copperReadoutSolid) {
position(z = -chamberHeight / 2 + readoutCopperThickness / 2)
}
val gasMaterial = materials.composite("G4_Ar")
val gasSolid =
solids.subtraction( gasSolidAux, cathodeWindowSolid) {
position(z = chamberHeight / 2 - mylarCathodeThickness / 2)
rotation(z = 45)
}
val gasVolume = volume(gasMaterial, gasSolid)
// world setup
world = volume(worldMaterial, worldBox) {
physVolume(gasVolume) {
name = "gas"
}
physVolume(kaptonReadoutVolume) {
name = "kaptonReadout"
position {
z = -chamberHeight / 2 - readoutKaptonThickness / 2
}
}
physVolume(copperReadoutVolume) {
name = "copperReadout"
position {
z = -chamberHeight / 2 + readoutCopperThickness / 2
}
rotation { z = 45 }
}
physVolume(chamberBodyVolume) {
name = "chamberBody"
}
physVolume(chamberBackplateVolume) {
name = "chamberBackplate"
position {
z = -chamberHeight / 2 - readoutKaptonThickness - chamberBackplateThickness / 2
}
}
physVolume(chamberTeflonWallVolume) {
name = "chamberTeflonWall"
}
physVolume(cathodeTeflonDiskVolume) {
name = "cathodeTeflonDisk"
position {
z = chamberHeight / 2 + cathodeTeflonDiskThickness / 2
}
}
physVolume(cathodeCopperDiskVolume) {
name = "cathodeCopperDisk"
position {
z = chamberHeight / 2 + cathodeCopperSupportThickness / 2
}
}
physVolume(cathodeWindowVolume) {
name = "cathodeWindow"
position {
z = chamberHeight / 2 - mylarCathodeThickness / 2
}
}
physVolume(cathodeFillingVolume) {
name = "cathodeFilling"
position {
z = chamberHeight / 2 + cathodeTeflonDiskThickness / 2
}
}
}
}
}.toVision {
configure { parent, solid, material ->
//disable visibility for the world box
if(solid.name == "world"){
visible = false
}
if(solid.name.startsWith("gas")){
color("green")
} else {
//make all solids semi-transparent
transparent()
}
}
}
}
}
}

View File

@ -0,0 +1,19 @@
package space.kscience.visionforge.examples
import space.kscience.dataforge.context.Context
import space.kscience.gdml.GdmlShowCase
import space.kscience.visionforge.gdml.toVision
import space.kscience.visionforge.html.ResourceLocation
import space.kscience.visionforge.solid.Solids
fun main() {
val context = Context {
plugin(Solids)
}
context.makeVisionFile(resourceLocation = ResourceLocation.SYSTEM){
vision("canvas") {
GdmlShowCase.cubes().toVision()
}
}
}

View File

@ -0,0 +1,16 @@
package space.kscience.visionforge.examples
import space.kscience.dataforge.context.Context
import space.kscience.gdml.GdmlShowCase
import space.kscience.visionforge.gdml.toVision
import space.kscience.visionforge.solid.Solids
fun main() {
val context = Context {
plugin(Solids)
}
context.makeVisionFile {
vision("canvas") { GdmlShowCase.babyIaxo().toVision() }
}
}

View File

@ -0,0 +1,21 @@
package space.kscience.visionforge.examples
import com.github.ricky12awesome.jss.encodeToSchema
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import space.kscience.visionforge.solid.SolidGroup
import space.kscience.visionforge.solid.Solids
@ExperimentalSerializationApi
fun main() {
val schema = Json {
serializersModule = Solids.serializersModuleForSolids
prettyPrintIndent = " "
prettyPrint = true
ignoreUnknownKeys = true
isLenient = true
coerceInputValues = true
encodeDefaults = true
}.encodeToSchema(SolidGroup.serializer(), generateDefinitions = false)
println(schema)
}

View File

@ -0,0 +1,23 @@
package space.kscience.visionforge.examples
import space.kscience.dataforge.context.Context
import space.kscience.plotly.scatter
import space.kscience.visionforge.html.ResourceLocation
import space.kscience.visionforge.plotly.PlotlyPlugin
import space.kscience.visionforge.plotly.plotly
fun main() {
val context = Context {
plugin(PlotlyPlugin)
}
context.makeVisionFile(resourceLocation = ResourceLocation.SYSTEM){
vision {
plotly {
scatter {
x(1, 2, 3)
y(5, 8, 7)
}
}
}
}
}

View File

@ -0,0 +1,41 @@
package space.kscience.visionforge.examples
import kotlinx.html.div
import kotlinx.html.h1
import space.kscience.dataforge.context.Context
import space.kscience.visionforge.html.ResourceLocation
import space.kscience.visionforge.solid.*
import java.nio.file.Paths
import kotlin.random.Random
fun main() {
val context = Context {
plugin(Solids)
}
val random = Random(112233)
context.makeVisionFile(
Paths.get("randomSpheres.html"),
resourceLocation = ResourceLocation.EMBED
) {
h1 { +"Happy new year!" }
div {
vision {
solid {
repeat(100) {
sphere(5, name = "sphere[$it]") {
x = random.nextDouble(-300.0, 300.0)
y = random.nextDouble(-300.0, 300.0)
z = random.nextDouble(-300.0, 300.0)
material {
color(random.nextInt())
}
detail = 16
}
}
}
}
}
}
}

View File

@ -0,0 +1,41 @@
package space.kscience.visionforge.examples
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.visionforge.html.ResourceLocation
import space.kscience.visionforge.html.VisionTagConsumer
import space.kscience.visionforge.html.page
import space.kscience.visionforge.html.scriptHeader
import space.kscience.visionforge.makeFile
import space.kscience.visionforge.three.server.VisionServer
import space.kscience.visionforge.three.server.useScript
import java.awt.Desktop
import java.nio.file.Path
public fun VisionServer.usePlayground(): Unit {
useScript("js/visionforge-playground.js")
}
@OptIn(DFExperimental::class)
public fun Context.makeVisionFile(
path: Path? = null,
title: String = "VisionForge page",
resourceLocation: ResourceLocation = ResourceLocation.SYSTEM,
show: Boolean = true,
content: VisionTagConsumer<*>.() -> Unit
): Unit {
val actualPath = page(title, content = content).makeFile(path) { actualPath ->
mapOf("threeJs" to scriptHeader("js/visionforge-playground.js", resourceLocation, actualPath))
}
if (show) Desktop.getDesktop().browse(actualPath.toFile().toURI())
}
//@DFExperimental
//public fun Context.makeVisionFile(
// vision: Vision,
// path: Path? = null,
// title: String = "VisionForge page",
// resourceLocation: ResourceLocation = ResourceLocation.SYSTEM,
// show: Boolean = true,
//): Unit = makeVisionFile({ vision(vision) }, path, title, resourceLocation, show)

View File

@ -0,0 +1,21 @@
package space.kscience.visionforge.examples
import space.kscience.dataforge.context.Context
import space.kscience.visionforge.html.ResourceLocation
import space.kscience.visionforge.solid.Solids
import space.kscience.visionforge.solid.box
import space.kscience.visionforge.solid.solid
fun main() {
val context = Context {
plugin(Solids)
}
context.makeVisionFile(resourceLocation = ResourceLocation.SYSTEM){
vision("canvas") {
solid {
box(100, 100, 100)
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,3 @@
const ringConfig = require('@jetbrains/ring-ui/webpack.config').config;
config.module.rules.push(...ringConfig.module.rules)

View File

@ -0,0 +1,57 @@
plugins {
kotlin("multiplatform")
application
id("org.openjfx.javafxplugin") version "0.0.9"
}
repositories {
maven("https://repo.kotlin.link")
mavenLocal()
jcenter()
}
kotlin {
jvm {
withJava()
}
js(IR) {
browser()
}
sourceSets{
commonMain{
dependencies {
}
}
val jvmMain by getting {
dependencies {
implementation("no.tornado:tornadofx:1.7.19")
implementation(project(":visionforge-server"))
implementation("ch.qos.logback:logback-classic:1.2.3")
}
}
}
}
javafx {
modules("javafx.web")
version = "16"
}
application {
mainClassName = "space.kscience.plotly.fx.PlotlyFXAppKt"
}
//
//val compileKotlin: KotlinCompile by tasks
//compileKotlin.kotlinOptions {
// jvmTarget = "11"
//}
//val compileTestKotlin: KotlinCompile by tasks
//compileTestKotlin.kotlinOptions {
// jvmTarget = "11"
//}

View File

@ -0,0 +1,23 @@
plugins {
id("ru.mipt.npm.gradle.jvm")
application
}
kscience {
// useSerialization {
// json()
// }
application()
}
group = "ru.mipt.npm"
dependencies{
implementation(project(":visionforge-threejs:visionforge-threejs-server"))
implementation("ch.qos.logback:logback-classic:1.2.3")
}
application {
mainClass.set("ru.mipt.npm.sat.SatServerKt")
}

View File

@ -0,0 +1,70 @@
package ru.mipt.npm.sat
import space.kscience.dataforge.meta.set
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.visionforge.solid.*
import space.kscience.visionforge.style
import space.kscience.visionforge.useStyle
import kotlin.math.PI
@DFExperimental
internal fun visionOfSatellite(
layers: Int = 10,
layerHeight: Number = 10,
xSegments: Int = 3,
ySegments: Int = xSegments,
xSegmentSize: Number = 30,
ySegmentSize: Number = xSegmentSize,
fiberDiameter: Number = 1.0,
): SolidGroup = SolidGroup {
val transparent by style {
this[SolidMaterial.MATERIAL_OPACITY_KEY] = 0.3
}
val red by style {
this[SolidMaterial.MATERIAL_COLOR_KEY] = "red"
}
val blue by style {
this[SolidMaterial.MATERIAL_COLOR_KEY] = "blue"
}
val totalXSize = xSegments * xSegmentSize.toDouble()
val totalYSize = ySegments * ySegmentSize.toDouble()
for (layer in 1..layers) {
group("layer[$layer]") {
for (i in 1..xSegments) {
for (j in 1..ySegments) {
box(xSegmentSize, ySegmentSize, layerHeight, name = "segment[$i,$j]") {
useStyle(transparent)
z = (layer - 0.5) * layerHeight.toDouble()
x = (i - 0.5) * xSegmentSize.toDouble()
y = (j - 0.5) * ySegmentSize.toDouble()
}
}
}
group("fibers") {
for (i in 1..xSegments) {
cylinder(fiberDiameter, totalYSize) {
useStyle(red)
rotationX = PI / 2
z = (layer - 1.0) * layerHeight.toDouble() + fiberDiameter.toDouble()
x = (i - 0.5) * xSegmentSize.toDouble()
y = totalYSize / 2
}
}
for (j in 1..ySegments) {
cylinder(fiberDiameter, totalXSize) {
useStyle(blue)
rotationY = PI / 2
z = (layer) * layerHeight.toDouble() - fiberDiameter.toDouble()
y = (j - 0.5) * xSegmentSize.toDouble()
x = totalXSize / 2
}
}
}
}
}
}

View File

@ -0,0 +1,61 @@
package ru.mipt.npm.sat
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.html.div
import kotlinx.html.h1
import space.kscience.dataforge.context.Global
import space.kscience.dataforge.names.toName
import space.kscience.visionforge.solid.*
import space.kscience.visionforge.three.server.*
import space.kscience.visionforge.visionManager
import kotlin.random.Random
fun main() {
val satContext = Global.buildContext ("sat") {
plugin(Solids)
}
//Create a geometry
val sat = visionOfSatellite(ySegments = 3)
val server = satContext.visionManager.serve {
//use client library
useThreeJs()
//use css
useCss("css/styles.css")
page {
div("flex-column") {
h1 { +"Satellite detector demo" }
vision(sat)
}
}
}
server.show()
GlobalScope.launch {
while (isActive) {
val randomLayer = Random.nextInt(1, 11)
val randomI = Random.nextInt(1, 4)
val randomJ = Random.nextInt(1, 4)
val target = "layer[$randomLayer].segment[$randomI,$randomJ]".toName()
val targetVision = sat[target] as Solid
targetVision.color("red")
delay(1000)
targetVision.color.clear()
delay(500)
}
}
println("Enter 'exit' to close server")
while (readLine() != "exit") {
//
}
server.close()
}

View File

@ -0,0 +1,16 @@
body{
width: 100%;
height: 100%;
overflow: hidden;
}
.flex-column{
width: calc(100% - 15px);
height: calc(100% - 15px);
display: flex;
flex-direction: column;
}
.visionforge-output{
flex-grow: 1;
}

View File

@ -12,8 +12,8 @@ To see Java FX demo, run `demo/spatial-showcase/Tasks/application/run` Gradle ta
##### Example view for JS:
![](../../doc/resources/spatial-showcase.png)
![](../../docs/images/spatial-showcase.png)
##### Example view for Java FX:
![](../../doc/resources/spatial-showcase-FX.png)
![](../../docs/images/spatial-showcase-FX.png)

View File

@ -0,0 +1,44 @@
import ru.mipt.npm.gradle.DependencyConfiguration
import ru.mipt.npm.gradle.FXModule
plugins {
id("ru.mipt.npm.gradle.mpp")
application
}
kscience {
useCoroutines()
val fxVersion: String by rootProject.extra
useFx(FXModule.CONTROLS, version = fxVersion, configuration = DependencyConfiguration.IMPLEMENTATION)
application()
}
kotlin {
jvm {
withJava()
}
sourceSets {
commonMain {
dependencies {
implementation(project(":visionforge-solid"))
// implementation(project(":visionforge-gdml"))
}
}
jvmMain {
dependencies {
implementation(project(":visionforge-fx"))
}
}
jsMain {
dependencies {
implementation(project(":visionforge-threejs"))
}
}
}
}
application {
mainClassName = "space.kscience.visionforge.solid.demo.FXDemoAppKt"
}

View File

@ -1,30 +1,35 @@
package hep.dataforge.vision.solid.demo
package space.kscience.visionforge.solid.demo
import hep.dataforge.meta.Meta
import hep.dataforge.meta.invoke
import hep.dataforge.names.toName
import hep.dataforge.output.OutputManager
import hep.dataforge.vision.Colors
import hep.dataforge.vision.Vision
import hep.dataforge.vision.solid.*
import hep.dataforge.vision.solid.specifications.Canvas3DOptions
import kotlinx.coroutines.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.invoke
import space.kscience.dataforge.names.toName
import space.kscience.visionforge.Colors
import space.kscience.visionforge.VisionLayout
import space.kscience.visionforge.solid.*
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
import space.kscience.visionforge.visible
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin
import kotlin.random.Random
fun OutputManager.demo(name: String, title: String = name, block: SolidGroup.() -> Unit) {
fun VisionLayout<Solid>.demo(name: String, title: String = name, block: SolidGroup.() -> Unit) {
val meta = Meta {
"title" put title
}
val output = get(Vision::class, name.toName(), meta = meta)
output.render (action = block)
val vision = SolidGroup(block)
render(name.toName(), vision)
}
val canvasOptions = Canvas3DOptions {
minSize = 500
size {
minSize = 400
}
axes {
size = 500.0
visible = true
@ -35,19 +40,27 @@ val canvasOptions = Canvas3DOptions {
}
}
fun OutputManager.showcase() {
fun VisionLayout<Solid>.showcase() {
demo("shapes", "Basic shapes") {
box(100.0, 100.0, 100.0) {
z = -110.0
color("teal")
}
sphere(50.0) {
x = 110
detail = 16
color("red")
}
tube(50, height = 10, innerRadius = 25, angle = PI) {
y = 110
detail = 16
rotationX = PI / 4
color("blue")
}
sphereLayer(50, 40, theta = PI / 2) {
rotationX = -PI * 3 / 4
z = 110
color(Colors.pink)
}
}
@ -55,6 +68,7 @@ fun OutputManager.showcase() {
val group = group {
box(100, 100, 100) {
z = 110.0
opacity = 0.5
}
box(100, 100, 100) {
@ -63,7 +77,7 @@ fun OutputManager.showcase() {
//override color for this cube
color(1530)
GlobalScope.launch(Dispatchers.Main) {
launch(Dispatchers.Main) {
while (isActive) {
delay(500)
visible = !(visible ?: false)
@ -72,7 +86,7 @@ fun OutputManager.showcase() {
}
}
GlobalScope.launch(Dispatchers.Main) {
launch(Dispatchers.Main) {
val random = Random(111)
while (isActive) {
delay(1000)
@ -132,42 +146,51 @@ fun OutputManager.showcase() {
}
}
fun OutputManager.showcaseCSG() {
fun VisionLayout<Solid>.showcaseCSG() {
demo("CSG.simple", "CSG operations") {
composite(CompositeType.UNION) {
box(100, 100, 100) {
z = 50
}
sphere(50)
material {
color(Colors.lightgreen)
opacity = 0.3f
}
}
composite(CompositeType.INTERSECT) {
y = 300
box(100, 100, 100) {
z = 50
}
sphere(50)
color(Colors.red)
sphere(50) {
detail = 32
}
material {
color(Colors.pink)
}
}
composite(CompositeType.UNION) {
box(100, 100, 100) {
z = 50
}
sphere(50) {
detail = 32
}
color("lightgreen")
opacity = 0.7
}
composite(CompositeType.SUBTRACT) {
y = -300
box(100, 100, 100) {
z = 50
}
sphere(50)
color(Colors.blue)
sphere(50) {
detail = 32
}
color("teal")
opacity = 0.7
}
}
demo("CSG.custom", "CSG with manually created object") {
intersect {
tube(60, 10) {
detail = 64
cylinder(60, 10) {
detail = 32
}
box(100, 100, 100)
color("red")
opacity = 0.5
}
}
}

View File

@ -0,0 +1,48 @@
package space.kscience.visionforge.solid.demo
import kotlinx.browser.document
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import space.kscience.visionforge.Application
import space.kscience.visionforge.solid.x
import space.kscience.visionforge.solid.y
import space.kscience.visionforge.startApplication
import kotlin.random.Random
private class ThreeDemoApp : Application {
override fun start(state: Map<String, Any>) {
val element = document.getElementById("demo") ?: error("Element with id 'demo' not found on page")
ThreeDemoGrid(element).run {
showcase()
showcaseCSG()
demo("dynamicBox", "Dancing boxes") {
val boxes = (-10..10).flatMap { i ->
(-10..10).map { j ->
varBox(10, 10, name = "cell_${i}_${j}") {
x = i * 10
y = j * 10
value = 128
}
}
}
GlobalScope.launch {
while (isActive) {
delay(500)
boxes.forEach { box ->
box.value = (box.value + Random.nextInt(-15, 15)).coerceIn(1..255)
}
}
}
}
}
}
}
fun main() {
startApplication(::ThreeDemoApp)
}

View File

@ -0,0 +1,77 @@
package space.kscience.visionforge.solid.demo
import kotlinx.browser.document
import kotlinx.dom.clear
import kotlinx.html.dom.append
import kotlinx.html.id
import kotlinx.html.js.*
import kotlinx.html.style
import org.w3c.dom.Element
import org.w3c.dom.HTMLDivElement
import org.w3c.dom.HTMLElement
import space.kscience.dataforge.context.Global
import space.kscience.dataforge.context.fetch
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.string
import space.kscience.dataforge.names.Name
import space.kscience.visionforge.VisionLayout
import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.three.ThreeCanvas
import space.kscience.visionforge.solid.three.ThreePlugin
class ThreeDemoGrid(element: Element) : VisionLayout<Solid> {
private lateinit var navigationElement: HTMLElement
private lateinit var contentElement: HTMLDivElement
private val outputs: MutableMap<Name, ThreeCanvas> = HashMap()
private val three = Global.fetch(ThreePlugin)
init {
element.clear()
element.append {
nav("navbar navbar-expand-md navbar-dark fixed-top bg-dark") {
a(classes = "navbar-brand") {
href = "#"
+"Demo grid"
}
div("navbar-collapse collapse") {
id = "navbar"
navigationElement = ul("nav navbar-nav")
}
}
contentElement = div {
id = "content"
}
}
}
override fun render(name: Name, vision: Solid, meta: Meta) {
outputs.getOrPut(name) {
navigationElement.append {
li("nav-item") {
a(classes = "nav-link") {
href = "#$name"
+name.toString()
}
}
}
contentElement.append {
div("container") {
id = name.toString()
hr()
h2 { +(meta["title"].string ?: name.toString()) }
hr()
div {
style = "height: 600px;"
id = "output-$name"
}
}
}
val element = document.getElementById("output-$name") ?: error("Element not found")
three.getOrCreateCanvas(element, canvasOptions)
}.render(vision)
}
}

View File

@ -0,0 +1,84 @@
package space.kscience.visionforge.solid.demo
import info.laht.threekt.core.Object3D
import info.laht.threekt.geometries.BoxGeometry
import info.laht.threekt.objects.Mesh
import space.kscience.dataforge.meta.int
import space.kscience.dataforge.meta.number
import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.startsWith
import space.kscience.dataforge.values.asValue
import space.kscience.visionforge.onPropertyChange
import space.kscience.visionforge.set
import space.kscience.visionforge.setProperty
import space.kscience.visionforge.solid.SolidGroup
import space.kscience.visionforge.solid.layer
import space.kscience.visionforge.solid.three.*
import kotlin.math.max
internal fun SolidGroup.varBox(
xSize: Number,
ySize: Number,
name: String = "",
action: VariableBox.() -> Unit = {},
): VariableBox = VariableBox(xSize, ySize).apply(action).also { set(name, it) }
internal class VariableBox(val xSize: Number, val ySize: Number) : ThreeJsVision() {
override fun render(three: ThreePlugin): Object3D {
val geometry = BoxGeometry(xSize, ySize, 1)
val material = ThreeMaterials.DEFAULT.clone()
val mesh = Mesh(geometry, material).apply {
//updateMaterial(this@VariableBox)
applyEdges(this@VariableBox)
//applyWireFrame(this@VariableBox)
//set position for mesh
updatePosition(this@VariableBox)
layers.enable(this@VariableBox.layer)
children.forEach {
it.layers.enable(this@VariableBox.layer)
}
}
mesh.scale.z = getOwnProperty(VALUE).number?.toDouble() ?: 1.0
//add listener to object properties
onPropertyChange(three.context) { name ->
when {
name == VALUE -> {
val value = getOwnProperty(VALUE).int ?: 0
val size = value.toFloat() / 255f * 20f
mesh.scale.z = size.toDouble()
mesh.position.z = size.toDouble() / 2
val b = max(0, 128 - value)
val r = max(0, value - 128)
val g = 255 - b - r
material.color.setRGB(r.toFloat() / 256, g.toFloat() / 256, b.toFloat() / 256)
mesh.updateMatrix()
}
name.startsWith(MeshThreeFactory.EDGES_KEY) -> mesh.applyEdges(this@VariableBox)
else -> mesh.updateProperty(this@VariableBox, name)
}
}
return mesh
}
var value: Int
get() = getOwnProperty(VALUE).int ?: 0
set(value) {
setProperty(VALUE, value.asValue())
}
companion object {
private val VALUE = "value".asName()
//
// private val X_SIZE_KEY = GEOMETRY_KEY + "xSize"
// private val Y_SIZE_KEY = GEOMETRY_KEY + "ySize"
// private val Z_SIZE_KEY = GEOMETRY_KEY + "zSize"
}
}

View File

@ -0,0 +1,27 @@
<!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>
<!-- CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css"
integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<link rel="stylesheet" href="styles.css">
<script type="text/javascript" src="solid-showcase.js"></script>
</head>
<body class="application">
<div class="container" id="demo"></div>
<!-- jQuery and JS bundle w/ Popper.js -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"
integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-ho+j7jyWK8fNQe+A12Hb8AhRq26LrZ/JpcUGGOn+Y7RsweNrtN/tE3MoK7ZeZDyx"
crossorigin="anonymous"></script>
</body>
</html>

View File

@ -0,0 +1,4 @@
body{
min-height: 75rem;
padding-top: 4.5rem;
}

View File

@ -0,0 +1,23 @@
package space.kscience.visionforge.solid.demo
import javafx.stage.Stage
import tornadofx.*
class FXDemoApp : App(FXDemoGrid::class) {
val view: FXDemoGrid by inject()
override fun start(stage: Stage) {
super.start(stage)
stage.width = 600.0
stage.height = 600.0
view.showcase()
view.showcaseCSG()
}
}
fun main() {
launch<FXDemoApp>()
}

View File

@ -0,0 +1,33 @@
package space.kscience.visionforge.solid.demo
import javafx.collections.FXCollections
import javafx.scene.Parent
import javafx.scene.control.Tab
import space.kscience.dataforge.context.Global
import space.kscience.dataforge.context.fetch
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.names.Name
import space.kscience.visionforge.VisionLayout
import space.kscience.visionforge.solid.FX3DPlugin
import space.kscience.visionforge.solid.FXCanvas3D
import space.kscience.visionforge.solid.Solid
import tornadofx.*
class FXDemoGrid : View(title = "DataForge-vis FX demo"), VisionLayout<Solid> {
private val outputs = FXCollections.observableHashMap<Name, FXCanvas3D>()
override val root: Parent = borderpane {
center = tabpane {
tabs.bind(outputs) { key: Name, value: FXCanvas3D ->
Tab(key.toString(), value.root)
}
}
}
private val fx3d = Global.fetch(FX3DPlugin)
override fun render(name: Name, vision: Solid, meta: Meta) {
outputs.getOrPut(name) { FXCanvas3D(fx3d, canvasOptions) }.render(vision)
}
}

View File

@ -1,13 +1,13 @@
package hep.dataforge.vision.demo
package space.kscience.visionforge.demo
import hep.dataforge.meta.Meta
import hep.dataforge.meta.asConfig
import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.values.ValueType
import hep.dataforge.vision.editor.ConfigEditor
import hep.dataforge.vision.editor.FXMeta
import hep.dataforge.vision.editor.MetaViewer
import javafx.geometry.Orientation
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.asConfig
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
import space.kscience.dataforge.values.ValueType
import space.kscience.visionforge.editor.ConfigEditor
import space.kscience.visionforge.editor.FXMeta
import space.kscience.visionforge.editor.MetaViewer
import tornadofx.*

View File

@ -1,31 +0,0 @@
import scientifik.DependencyConfiguration
import scientifik.FXModule
import scientifik.useFx
plugins {
id("scientifik.mpp")
id("application")
}
val fxVersion: String by rootProject.extra
useFx(FXModule.CONTROLS, version = fxVersion, configuration = DependencyConfiguration.IMPLEMENTATION)
kotlin {
jvm {
withJava()
}
sourceSets {
commonMain {
dependencies {
api(project(":visionforge-solid"))
api(project(":visionforge-gdml"))
}
}
}
}
application {
mainClassName = "hep.dataforge.vision.solid.demo.FXDemoAppKt"
}

View File

@ -1,46 +0,0 @@
package hep.dataforge.vision.solid.demo
import hep.dataforge.js.Application
import hep.dataforge.js.startApplication
import kotlin.browser.document
private class ThreeDemoApp : Application {
override fun start(state: Map<String, Any>) {
val element = document.getElementById("canvas") ?: error("Element with id 'canvas' not found on page")
ThreeDemoGrid(element).run {
showcase()
showcaseCSG()
// demo("dynamicBox", "Dancing boxes") {
// val boxes = (-10..10).flatMap { i ->
// (-10..10).map { j ->
// varBox(10, 10, 0, name = "cell_${i}_${j}") {
// x = i * 10
// y = j * 10
// value = 128
// setProperty(EDGES_ENABLED_KEY, false)
// setProperty(WIREFRAME_ENABLED_KEY, false)
// }
// }
// }
// GlobalScope.launch {
// while (isActive) {
// delay(500)
// boxes.forEach { box ->
// box.value = (box.value + Random.nextInt(-15, 15)).coerceIn(0..255)
// }
// }
// }
// }
}
}
}
fun main() {
startApplication(::ThreeDemoApp)
}

View File

@ -1,62 +0,0 @@
package hep.dataforge.vision.solid.demo
import hep.dataforge.context.Global
import hep.dataforge.meta.Meta
import hep.dataforge.meta.get
import hep.dataforge.meta.string
import hep.dataforge.names.Name
import hep.dataforge.output.OutputManager
import hep.dataforge.output.Renderer
import hep.dataforge.vision.Vision
import hep.dataforge.vision.solid.three.ThreeCanvas
import hep.dataforge.vision.solid.three.ThreePlugin
import hep.dataforge.vision.solid.three.output
import kotlinx.html.dom.append
import kotlinx.html.dom.create
import kotlinx.html.h2
import kotlinx.html.hr
import kotlinx.html.id
import kotlinx.html.js.div
import kotlinx.html.span
import org.w3c.dom.Element
import kotlin.browser.document
import kotlin.dom.clear
import kotlin.reflect.KClass
class ThreeDemoGrid(element: Element, meta: Meta = Meta.EMPTY) : OutputManager {
private val gridRoot = document.create.div("row")
private val outputs: MutableMap<Name, ThreeCanvas> = HashMap()
private val three = Global.plugins.fetch(ThreePlugin)
init {
element.clear()
element.append(gridRoot)
}
@Suppress("UNCHECKED_CAST")
override fun <T : Any> get(type: KClass<out T>, name: Name, stage: Name, meta: Meta): Renderer<T> {
return outputs.getOrPut(name) {
if (type != Vision::class) error("Supports only DisplayObject")
lateinit var output: ThreeCanvas
//TODO calculate cell width here using jquery
gridRoot.append {
span("border") {
div("col-6") {
div { id = "output-$name" }.also {
output = three.output(it, canvasOptions)
//output.attach(it)
}
hr()
h2 { +(meta["title"].string ?: name.toString()) }
}
}
}
output
} as Renderer<T>
}
}

View File

@ -1,106 +0,0 @@
@file:UseSerializers(Point3DSerializer::class)
package hep.dataforge.vision.solid.demo
import hep.dataforge.meta.int
import hep.dataforge.meta.number
import hep.dataforge.meta.setItem
import hep.dataforge.names.plus
import hep.dataforge.names.startsWith
import hep.dataforge.values.asValue
import hep.dataforge.vision.getProperty
import hep.dataforge.vision.set
import hep.dataforge.vision.solid.*
import hep.dataforge.vision.solid.Solid.Companion.GEOMETRY_KEY
import hep.dataforge.vision.solid.demo.VariableBoxThreeFactory.Z_SIZE_KEY
import hep.dataforge.vision.solid.three.*
import hep.dataforge.vision.solid.three.ThreeMaterials.getMaterial
import info.laht.threekt.core.BufferGeometry
import info.laht.threekt.core.Object3D
import info.laht.threekt.geometries.BoxBufferGeometry
import info.laht.threekt.objects.Mesh
import kotlinx.serialization.UseSerializers
import kotlin.math.max
import kotlin.reflect.KClass
internal var Solid.variableZSize: Number
get() = getProperty(Z_SIZE_KEY, false).number ?: 0f
set(value) {
setItem(Z_SIZE_KEY, value.asValue())
}
internal var Solid.value: Int
get() = getProperty("value", false).int ?: 0
set(value) {
setItem("value", value.asValue())
val size = value.toFloat() / 255f * 20f
scaleZ = size
z = -size / 2
val b = max(0, 255 - value)
val r = max(0, value - 255)
val g = 255 - b - r
color(r.toUByte(), g.toUByte(), b.toUByte())
}
fun SolidGroup.varBox(
xSize: Number,
ySize: Number,
zSize: Number,
name: String = "",
action: Solid.() -> Unit = {}
) = CustomThreeVision(VariableBoxThreeFactory).apply {
scaleX = xSize
scaleY = ySize
scaleZ = zSize
}.apply(action).also { set(name, it) }
private object VariableBoxThreeFactory : ThreeFactory<Solid> {
val X_SIZE_KEY = GEOMETRY_KEY + "xSize"
val Y_SIZE_KEY = GEOMETRY_KEY + "ySize"
val Z_SIZE_KEY = GEOMETRY_KEY + "zSize"
override val type: KClass<in Solid> get() = Solid::class
override fun invoke(obj: Solid): Object3D {
val xSize = obj.getProperty(X_SIZE_KEY, false).number?.toDouble() ?: 1.0
val ySize = obj.getProperty(Y_SIZE_KEY, false).number?.toDouble() ?: 1.0
val zSize = obj.getProperty(Z_SIZE_KEY, false).number?.toDouble() ?: 1.0
val geometry = BoxBufferGeometry(1, 1, 1)
//JS sometimes tries to pass Geometry as BufferGeometry
@Suppress("USELESS_IS_CHECK") if (geometry !is BufferGeometry) error("BufferGeometry expected")
val mesh = Mesh(geometry, getMaterial(obj)).apply {
applyEdges(obj)
applyWireFrame(obj)
//set position for mesh
updatePosition(obj)
layers.enable(obj.layer)
children.forEach {
it.layers.enable(obj.layer)
}
}
mesh.scale.set(xSize, ySize, zSize)
//add listener to object properties
obj.onPropertyChange(this) { name ->
when {
// name.startsWith(GEOMETRY_KEY) -> {
// val newXSize = obj.getProperty(X_SIZE_KEY, false).number?.toDouble() ?: 1.0
// val newYSize = obj.getProperty(Y_SIZE_KEY, false).number?.toDouble() ?: 1.0
// val newZSize = obj.getProperty(Z_SIZE_KEY, false).number?.toDouble() ?: 1.0
// mesh.scale.set(newXSize, newYSize, newZSize)
// mesh.updateMatrix()
// }
name.startsWith(MeshThreeFactory.WIREFRAME_KEY) -> mesh.applyWireFrame(obj)
name.startsWith(MeshThreeFactory.EDGES_KEY) -> mesh.applyEdges(obj)
else -> mesh.updateProperty(obj, name)
}
}
return mesh
}
}

View File

@ -1,17 +0,0 @@
<!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.4.1/css/bootstrap.min.css"
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<script type="text/javascript" src="main.bundle.js"></script>
</head>
<body class="application">
<div class="container">
<h1>Demo grid</h1>
</div>
<div class="container" id="canvas"></div>
</body>
</html>

View File

@ -1,35 +0,0 @@
package hep.dataforge.vision.solid.demo
import hep.dataforge.vision.gdml.gdml
import javafx.stage.Stage
import tornadofx.*
import java.nio.file.NoSuchFileException
import java.nio.file.Paths
class FXDemoApp : App(FXDemoGrid::class) {
val view: FXDemoGrid by inject()
override fun start(stage: Stage) {
super.start(stage)
stage.width = 600.0
stage.height = 600.0
view.showcase()
try {
view.demo("gdml", "gdml-cubes") {
gdml(Paths.get("D:\\Work\\Projects\\gdml.kt\\gdml-source\\cubes.gdml"))
//setProperty(Material3D.MATERIAL_WIREFRAME_KEY, true)
}
}
catch (e: NoSuchFileException) {
println("GDML demo: Please specify the correct file path e.g. " +
"visionforge\\demo\\gdml\\src\\commonMain\\resources\\cubes.gdml")
}
}
}
fun main() {
launch<FXDemoApp>()
}

View File

@ -1,40 +0,0 @@
package hep.dataforge.vision.solid.demo
import hep.dataforge.context.Global
import hep.dataforge.meta.Meta
import hep.dataforge.names.Name
import hep.dataforge.output.OutputManager
import hep.dataforge.output.Renderer
import hep.dataforge.vision.Vision
import hep.dataforge.vision.solid.fx.FX3DPlugin
import hep.dataforge.vision.solid.fx.FXCanvas3D
import javafx.collections.FXCollections
import javafx.scene.Parent
import javafx.scene.control.Tab
import tornadofx.*
import kotlin.reflect.KClass
class FXDemoGrid : View(title = "DataForge-vis FX demo"), OutputManager {
private val outputs = FXCollections.observableHashMap<Name, FXCanvas3D>()
override val root: Parent = borderpane {
center = tabpane {
tabs.bind(outputs) { key: Name, value: FXCanvas3D ->
Tab(key.toString(), value.root)
}
}
}
private val fx3d = Global.plugins.fetch(FX3DPlugin)
@Suppress("UNCHECKED_CAST")
override fun <T : Any> get(type: KClass<out T>, name: Name, stage: Name, meta: Meta): Renderer<T> {
return outputs.getOrPut(name) {
if (type != Vision::class) kotlin.error("Supports only DisplayObject")
val output = FXCanvas3D(fx3d, canvasOptions)
output
} as Renderer<T>
}
}

7
docs/appendix.md Normal file
View File

@ -0,0 +1,7 @@
## Appendix
### DataForge Name
### DataForge Meta
### DataForge Context

19
docs/design.md Normal file
View File

@ -0,0 +1,19 @@
## Library design
The central point of the library design is the `Vision` interface. The `Vision` stores an optional reference to its parent and is able to store a number of mutable or read-only properties. Each property is represented by its `Name`, and a `MetaItem` value-tree, both following DataForge library specification (discussed in the [Appendix](appendix.md)). The `Vision` objects are organized in a tree using `VisionGroup` as nodes. `VisionGroup` additionally to all `Vision` properties holds a `children` container that holds named references to its direct children `Vision`s. Thus, `Vision`s form a doubly linked tree (a parent stores references to all its children and children store a reference to the parent).
An important concept using in the VisionForge is the property layering mechanism. It means that if the property with a given name is not found in the `Vision` it is requested from, it could be requested from the parent `Vision`, form the style declaration, the prototype for the vision or any other place defined by the component author. For example, let's take a `color` attribute used in 3D visualization. When one draws a group of objects, he usually wants to make the color of all objects in the group to be defined by a single handle in the group common ancestor. So when the parent color changes, all children color must follow suite, but we also want to change children color individually without changing the parent. In this case two property layers are defined:
* own properties layer
* parent properties layer
When the user or a part of inner program mechanics requests a property, it searched in `Vision` own properties. If it is defined there, it is returned, if not, the search continues to the parent properties and up the parentage chain. So if the parent color is defined and children colors are blank, then the parent color will be used. If one of children redefines its own color, then this color is used for this specific color, and the parent color used for all other children. The change of parent property automatically propagated to all children.
### Styling
The actual layering scheme is more complicated. All objects support styling. The styles are named `Meta` nodes that could be used to define groups of properties together and use in different `Vision`s. The styles are defined as named `Meta` nodes in a `VisionGroup` `@stylesheet` property (DataForge states that names starting with `@` are reserved for system properties, not visible by default to the user). The style or a list of styles could be applied to a `Vision` by setting the reserved `@style` property to the name of the style being used or by using `Vision::style` extension property. The style name is then resolved to the nearest ancestor that defines it. The key difference from the CSS styling in HTML is that the stylesheets could be added to any node, not only to the hierarchy root. It allows to decouple the whole subtrees together with styles from the main `Vision` graph, or create stand-alone branches. One must note, that the same style could be defined on different levels of the tree, only the nearest ancestor is resolved, meaning that one can override styles for a sub-tree.
### Intermediate representation
An important thing about VisionForge is that it does not strictly bound to a single format representation.
### Kotlin DSL for creating vision-graphs

Binary file not shown.

5
docs/features.md Normal file
View File

@ -0,0 +1,5 @@
## Features
### Customization and plugins
### Full-stack development

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 97 KiB

View File

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 87 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

77
docs/solids.md Normal file
View File

@ -0,0 +1,77 @@
## Solids
The primary initial goal of creating the library was to provide a flexible API and rendering engine to draw solid geometric forms for so-called event display task in particle physics. Event display is used to provide visualization for particle hit events in both accelerator and non-accelerator experiments (see [add links here] for examples). The event display system must have a way to render basic 3D shapes like boxes, tubes and spheres and particle tracks. An additional requirement is to be able to change coloring and transparency of different elements as well as custom attributes specific to the problem.
The `Solid` class inherits the `Vision` and has three additional nullable real vector properties: `position`, `rotation` and `scale`. Those properties are placed on the top level of the class instead of `properties` tree for performance optimization purposes. The `position` and `rotation` properties reflect the position offset in absolute units and rotation in radians relative to the parent and have defaults of `0.0`. Relativity means that if the parent `Vision` (`SolidGroup`) has `position = (1.0, 0.0, 1.0)` and a child has `position = (0.0, 2.0, 0.0)`, then the real offset of rendered object will be `(1.0, 2.0, 1.0)`. The same goes for the rotation. By default, the rotation uses intrinsic Cordan (TaitBryan) angles with `XYZ` order, but order could be changed with an inherited property `rotation.order`. The `scale` property is not inherited and represents local `Solid` scaling factor with default value of `1.0`.
The `SolidGroup` represents the specific kind of `VisionGroup` that has properties of a `Solid` and has one additional special property: the prototype container.
### Solid prototypes
One of the important requirements for event display system is the ability to render a huge number of primitives (tens and hundreds of thousands). This is especially important for accelerator experiments with fine-grained calorimeter detectors ([ref here]). The most memory and CPU-consuming task to render such structures is computing the geometry o equal elements (like calorimeter cells). In order to optimize rendering and model representation for such cases, we introduced so-called prototypes. The idea is that multiple visions could have the same prototype and share the definition and actual rendered geometry. The prototypes are stored in a special container property called `prototypes` in a `SolidGroup` object. In order to access those prototypes there is a special `Solid` object called `SolidReference`. It inherits `Solid` (has properties container, position, rotation and scale), but does not define any geometry. Instead, it has a single `refName` property which stores a fully qualified DataForge `Name` (see [Appendix](appendix.md)) that designates the name of the prototype to be used. During rendering phase, the system searches for appropriate prototype in the nearest parent. If the prototype is not found, the search continues in the next parent in the chain. Like property resolution, the prototype resolution is fine-grained and local, meaning that a part of `Vision` graph could be self-contained together with prototypes.
An important point is that prototypes are resolved in a parent vision container, and the parent vision container for prototypes is the vision group. It means that prototype itself could reference a prototype, or even in corner cases reference itself (such cases should be checked for infinite loops). The prototype relation example is shown in [prototypes.uml](uml/prototypes.puml). Here `Prototype Ref` vision references the `Prototype` vision by first seeking up to `VirionGroup`, the resolving the prototype with appropriate name. In theory, vision groups inside prototypes groups could contain the prototypes of their own, but such constructs should be used with care.
### Solid definitions
Solid models are defined as kotlin classes that also serve as builders for DSL and serialization models. For example, here is the definition for a `Box` class:
```kotlin
@Serializable
@SerialName("solid.box")
class Box(
val xSize: Float,
val ySize: Float,
val zSize: Float
) : SolidBase(), GeometrySolid
```
In general, one does not define how specific solid is rendered, it is done in the rendering back-end. It means that in general, there should be a specific renderer defined for each type of solids defined in the model. Some solids have additional mechanism to avoid providing renderers for each primitive. Classes that inherit `GeometrySolid` interface provide a way to define geometry via polygons like this:
```kotlin
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {
val dx = xSize / 2
val dy = ySize / 2
val dz = zSize / 2
val node1 = Point3D(-dx, -dy, -dz)
val node2 = Point3D(dx, -dy, -dz)
val node3 = Point3D(dx, dy, -dz)
val node4 = Point3D(-dx, dy, -dz)
val node5 = Point3D(-dx, -dy, dz)
val node6 = Point3D(dx, -dy, dz)
val node7 = Point3D(dx, dy, dz)
val node8 = Point3D(-dx, dy, dz)
geometryBuilder.face4(node1, node4, node3, node2)
geometryBuilder.face4(node1, node2, node6, node5)
geometryBuilder.face4(node2, node3, node7, node6)
geometryBuilder.face4(node4, node8, node7, node3)
geometryBuilder.face4(node1, node5, node8, node4)
geometryBuilder.face4(node8, node5, node6, node7)
}
```
The `GeometryBuilder` instance is provided by the specific rendering engine, so the polygons are generated for target engine without intermediate steps. If the renderer provides its own implementation for a solid renderer, it takes precedence over generic `GeometrySolid` definition.
An important basic solid is the `Composite`. It is a primitive, that allows combine two (maybe more in future) primitives via [composite solid geometry or CSG](https://en.wikipedia.org/wiki/Constructive_solid_geometry) transformations (union, difference and subtraction). At this moment, the actual transformation is done on the renderer side.
### GDML bindings
VisionForge supports extensible geometry primitive list, but we've started with primitives needed to render BM@N ([ref]) GDML ([ref]) geometry. GDML files are read with [gdml.kt](https://github.com/mipt-npm/gdml.kt) package designed specifically for this purpose. The package uses [https://github.com/pdvrieze/xmlutil](https://github.com/pdvrieze/xmlutil) serialization plugin to parse GDML structure into the convenient object structure and has language definitions for all GDML primitives. The `visionforge-gdml` module contains a converter that transforms Gdml.kt structures into `Solid`.
The GDML file definition contains several sections:
* **defines** - Dimensions and numbers for geometries.
* **materials** - Material definitions.
* **solids** - Primitive definitions and their composition.
* **structure** - Combinations of solids and groups used in geometry.
* **setup** - Metadata and geometry entry point.
GDML materials are currently used only for Solid coloring. The data from material is stored in the `Vision` properties. Solids section and structures are transformed into top level group prototypes, which allows not only to create a compact representation, but also optimize rendering. The gdml structure is not always flexible. For example, it is not possible to add a solid directly into a group, but instead one needs to add a group with a single element. Problems like this could be automatically optimized by the convertor.
Not all GDML solids are currently supported by the converter, they could be added later on-demand. Current support covers all solids used in BM@N geometry.
### ThreeJs renderer
VisionForge is not tied to any single renderer. Right now the primary target is the Browser rendering with [Three.js library](https://threejs.org/). The Three.js supports different renderers including WebGL with hardware support and virtual reality.
The bindings for three-js was implemented in kotlin-js based on a [work by Lars Ivar Hatledal](https://github.com/markaren/three-kt-wrapper). The wrapper allows seamless integration with a lot of different library APIs including custom cameras and CSG.

45
docs/uml/Vision.puml Normal file
View File

@ -0,0 +1,45 @@
@startuml
'https://plantuml.com/class-diagram
interface Vision{
val parent: Vision?
fun getProperty(name): MetaItem?
fun setProperty(name, value)
}
class VisionBase{
basic vision
implementation
}
Vision <|-- VisionBase
interface VisionGroup{
A group of Visions
}
Vision <|-- VisionGroup
interface Solid{
The base for 3D geometry
}
Vision <|-- Solid
class SolidGroup
Solid <|-- SolidGroup
VisionGroup <|-- SolidGroup
class Composite
Solid <|-- Composite
VisionGroup <|-- Composite
class Box
Solid <|-- Box
class Tube
Solid <|-- Tube
class Sphere
Solid <|-- Sphere
@enduml

14
docs/uml/prototypes.puml Normal file
View File

@ -0,0 +1,14 @@
@startuml
package "VisionGroup" {
package "Prototypes"{
[Prototype]
package "Prototype group"{
[Prototype Ref] --> [Prototype]
}
}
package "Child group"{
[Ref] --> [Prototype Ref]
}
}
@enduml

7
gradle.properties Normal file
View File

@ -0,0 +1,7 @@
kotlin.code.style=official
kotlin.mpp.enableGranularSourceSetsMetadata=true
kotlin.mpp.stability.nowarn=true
kotlin.native.enableDependencyPropagation=false
org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G
org.gradle.parallel=true

Binary file not shown.

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

2
gradlew vendored
View File

@ -82,6 +82,7 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@ -129,6 +130,7 @@ fi
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath

22
gradlew.bat vendored
View File

@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@ -54,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@ -64,28 +64,14 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell

Some files were not shown because too many files have changed in this diff Show More