SphereLayer

This commit is contained in:
Alexander Nozik 2021-03-04 09:47:41 +03:00
parent 545753b14b
commit 3f6e39b18d
21 changed files with 1207 additions and 41 deletions

View File

@ -5,6 +5,7 @@
- Server module - Server module
- Change collector - Change collector
- Customizable accessors for colors - Customizable accessors for colors
- SphereLayer solid
### Changed ### Changed
- Vision does not implement ItemProvider anymore. Property changes are done via `getProperty`/`setProperty` and `property` delegate. - Vision does not implement ItemProvider anymore. Property changes are done via `getProperty`/`setProperty` and `property` delegate.
@ -13,6 +14,7 @@
- Threejs support moved to a separate module - Threejs support moved to a separate module
- \[Format breaking change!\] Stylesheets are moved into properties under `@stylesheet` key - \[Format breaking change!\] Stylesheets are moved into properties under `@stylesheet` key
- VisionGroup builder accepts `null` as name for statics instead of `""` - VisionGroup builder accepts `null` as name for statics instead of `""`
- gdml sphere is rendered as a SphereLayer instead of Sphere (#35)
### Deprecated ### Deprecated

View File

@ -2,6 +2,7 @@ package hep.dataforge.vision.gdml.demo
import hep.dataforge.context.Global import hep.dataforge.context.Global
import hep.dataforge.vision.Application import hep.dataforge.vision.Application
import hep.dataforge.vision.bootstrap.useBootstrap
import hep.dataforge.vision.gdml.GdmlShowcase import hep.dataforge.vision.gdml.GdmlShowcase
import hep.dataforge.vision.gdml.toVision import hep.dataforge.vision.gdml.toVision
import hep.dataforge.vision.solid.three.ThreePlugin import hep.dataforge.vision.solid.three.ThreePlugin
@ -14,6 +15,8 @@ import react.dom.render
private class GDMLDemoApp : Application { private class GDMLDemoApp : Application {
override fun start(state: Map<String, Any>) { override fun start(state: Map<String, Any>) {
useBootstrap()
val element = document.getElementById("app") ?: error("Element with id 'app' not found on page") val element = document.getElementById("app") ?: error("Element with id 'app' not found on page")
val context = Global.context("demo") .apply{ val context = Global.context("demo") .apply{

View File

@ -4,15 +4,11 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>Three js demo for particle physics</title> <title>Three js demo for particle physics</title>
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/main.css">
<link rel="stylesheet" href="css/fileDrop.css">
<script type="text/javascript" src="gdml.js"></script> <script type="text/javascript" src="gdml.js"></script>
<link rel="stylesheet" href="css/custom-bootstrap.css">
<link rel="stylesheet" href="css/fileDrop.css">
</head> </head>
<body class="application"> <body class="application">
<div class="container-fluid max-vh-100" id = "app"> </div> <div class="container-fluid max-vh-100" id = "app"> </div>
<script type="text/javascript" src ="js/jquery-3.4.1.min.js"></script>
<script type="text/javascript" src ="js/bootstrap.bundle.min.js"></script>
</body> </body>
</html> </html>

View File

@ -2,6 +2,7 @@ package ru.mipt.npm.muon.monitor
import hep.dataforge.context.Global import hep.dataforge.context.Global
import hep.dataforge.vision.Application import hep.dataforge.vision.Application
import hep.dataforge.vision.bootstrap.useBootstrap
import hep.dataforge.vision.startApplication import hep.dataforge.vision.startApplication
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.features.json.JsonFeature import io.ktor.client.features.json.JsonFeature
@ -21,6 +22,8 @@ private class MMDemoApp : Application {
} }
override fun start(state: Map<String, Any>) { override fun start(state: Map<String, Any>) {
useBootstrap()
val element = document.getElementById("app") ?: error("Element with id 'app' not found on page") val element = document.getElementById("app") ?: error("Element with id 'app' not found on page")
val context = Global.context("demo") {} val context = Global.context("demo") {}

View File

@ -4,14 +4,10 @@
<meta charset="utf-8"> <meta charset="utf-8">
<!-- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">--> <!-- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">-->
<title>Three js demo for particle physics</title> <title>Three js demo for particle physics</title>
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/main.css">
<script type="text/javascript" src="muon-monitor.js"></script> <script type="text/javascript" src="muon-monitor.js"></script>
<link rel="stylesheet" href="css/custom-bootstrap.css">
</head> </head>
<body class="application"> <body class="application">
<div class="container-fluid max-vh-100" id = "app"> </div> <div class="container-fluid max-vh-100" id = "app"> </div>
<script type="text/javascript" src ="js/jquery-3.4.1.min.js"></script>
<script type="text/javascript" src ="js/bootstrap.bundle.min.js"></script>
</body> </body>
</html> </html>

View File

@ -0,0 +1,24 @@
package hep.dataforge.vision.examples
import hep.dataforge.misc.DFExperimental
import hep.dataforge.vision.VisionForge
import hep.dataforge.vision.gdml.toVision
import hep.dataforge.vision.html.ResourceLocation
import hep.dataforge.vision.html.fragment
import hep.dataforge.vision.invoke
import hep.dataforge.vision.solid.Solids
import space.kscience.gdml.Gdml
import space.kscience.gdml.LUnit
import space.kscience.gdml.decodeFromStream
@DFExperimental
fun main() = VisionForge(Solids) {
val content = VisionForge.fragment {
vision("canvas") {
Gdml.decodeFromStream(Gdml.javaClass.getResourceAsStream("/gdml/babyIAXO.gdml")!!, true).toVision {
lUnit = LUnit.MM
}
}
}
makeVisionFile(content, resourceLocation = ResourceLocation.EMBED)
}

File diff suppressed because it is too large Load Diff

View File

@ -52,6 +52,12 @@ fun VisionLayout<Solid>.showcase() {
rotationX = PI / 4 rotationX = PI / 4
color("blue") color("blue")
} }
sphereLayer(50,40){
theta = (PI/2).toFloat()
rotationX = - PI * 3 / 4
z = 110
color(Colors.pink)
}
} }
demo("dynamic", "Dynamic properties") { demo("dynamic", "Dynamic properties") {

View File

@ -10,7 +10,7 @@
<link rel="stylesheet" href="styles.css"> <link rel="stylesheet" href="styles.css">
<script type="text/javascript" src="spatial-showcase.js"></script> <script type="text/javascript" src="solid-showcase.js"></script>
</head> </head>
<body class="application"> <body class="application">
<div class="container" id="demo"></div> <div class="container" id="demo"></div>

View File

@ -8,4 +8,7 @@ dependencies {
api(project(":visionforge-solid")) api(project(":visionforge-solid"))
api(project(":ui:react")) api(project(":ui:react"))
implementation(npm("file-saver", "2.0.2")) implementation(npm("file-saver", "2.0.2"))
implementation(npm("bootstrap","4.6.0"))
implementation(npm("jquery","3.5.1"))
implementation(npm("popper.js","1.16.1"))
} }

View File

@ -1,5 +1,10 @@
package hep.dataforge.vision.bootstrap package hep.dataforge.vision.bootstrap
public fun useBootstrap(){
kotlinext.js.require("bootstrap/dist/css/bootstrap.min.css")
kotlinext.js.require("bootstrap")
}
//public inline fun TagConsumer<HTMLElement>.card(title: String, crossinline block: TagConsumer<HTMLElement>.() -> Unit) { //public inline fun TagConsumer<HTMLElement>.card(title: String, crossinline block: TagConsumer<HTMLElement>.() -> Unit) {
// div("card w-100") { // div("card w-100") {
// div("card-body") { // div("card-body") {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -9,7 +9,7 @@ import hep.dataforge.names.toName
import hep.dataforge.vision.set import hep.dataforge.vision.set
import hep.dataforge.vision.setProperty import hep.dataforge.vision.setProperty
import hep.dataforge.vision.solid.* import hep.dataforge.vision.solid.*
import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_KEY
import hep.dataforge.vision.styleSheet import hep.dataforge.vision.styleSheet
import hep.dataforge.vision.useStyle import hep.dataforge.vision.useStyle
import space.kscience.gdml.* import space.kscience.gdml.*
@ -27,6 +27,8 @@ private inline operator fun Number.times(d: Double) = toDouble() * d
private inline operator fun Number.times(f: Float) = toFloat() * f private inline operator fun Number.times(f: Float) = toFloat() * f
public class GdmlTransformerSettings { public class GdmlTransformerSettings {
public val random: Random = Random(222)
public enum class Action { public enum class Action {
ADD, ADD,
REJECT, REJECT,
@ -38,11 +40,14 @@ public class GdmlTransformerSettings {
public var solidAction: (GdmlSolid) -> Action = { Action.PROTOTYPE } public var solidAction: (GdmlSolid) -> Action = { Action.PROTOTYPE }
public var volumeAction: (GdmlGroup) -> Action = { Action.PROTOTYPE } public var volumeAction: (GdmlGroup) -> Action = { Action.PROTOTYPE }
public var paint: SolidMaterial.(material: GdmlMaterial) -> Unit = { _->
color(random.nextInt(16777216))
}
} }
private class GdmlTransformer(val settings: GdmlTransformerSettings) { private class GdmlTransformer(val settings: GdmlTransformerSettings) {
//private val materialCache = HashMap<GdmlMaterial, Meta>() //private val materialCache = HashMap<GdmlMaterial, Meta>()
private val random = Random(222)
/** /**
* A special group for local templates * A special group for local templates
@ -105,7 +110,8 @@ private class GdmlTransformer(val settings: GdmlTransformerSettings) {
val styleName = "materials.${material.name}" val styleName = "materials.${material.name}"
obj.useStyle(styleName) { obj.useStyle(styleName) {
MATERIAL_COLOR_KEY put random.nextInt(16777216) val vfMaterial = settings.run { SolidMaterial().apply { paint(material)}}
MATERIAL_KEY put vfMaterial.toMeta()
"Gdml.material" put material.name "Gdml.material" put material.name
} }
@ -195,7 +201,9 @@ private class GdmlTransformer(val settings: GdmlTransformerSettings) {
scaleZ = solid.scale.z.toFloat() scaleZ = solid.scale.z.toFloat()
} }
} }
is GdmlSphere -> sphere(solid.rmax * lScale, solid.deltaphi * aScale, solid.deltatheta * aScale, name) { is GdmlSphere -> sphereLayer(solid.rmax * lScale, solid.rmin * lScale, name) {
phi = solid.deltaphi * aScale
theta = solid.deltatheta * aScale
phiStart = solid.startphi * aScale phiStart = solid.startphi * aScale
thetaStart = solid.starttheta * aScale thetaStart = solid.starttheta * aScale
} }
@ -255,7 +263,7 @@ private class GdmlTransformer(val settings: GdmlTransformerSettings) {
solid: GdmlSolid, solid: GdmlSolid,
name: String?, name: String?,
): Solid? { ): Solid? {
require(name != ""){"Can't use empty solid name. Use null instead."} require(name != "") { "Can't use empty solid name. Use null instead." }
return when (settings.solidAction(solid)) { return when (settings.solidAction(solid)) {
GdmlTransformerSettings.Action.ADD -> { GdmlTransformerSettings.Action.ADD -> {
addSolid(root, solid, name) addSolid(root, solid, name)

View File

@ -5,8 +5,8 @@ import hep.dataforge.vision.visitor.countDistinct
import hep.dataforge.vision.visitor.flowStatistics import hep.dataforge.vision.visitor.flowStatistics
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import space.kscience.gdml.Gdml
import nl.adaptivity.xmlutil.StAXReader import nl.adaptivity.xmlutil.StAXReader
import space.kscience.gdml.Gdml
import java.io.File import java.io.File
import kotlin.reflect.KClass import kotlin.reflect.KClass
@ -17,7 +17,7 @@ suspend fun main() {
File("D:\\Work\\Projects\\dataforge-vis\\visionforge-gdml\\src\\jvmTest\\resources\\gdml\\BM@N.gdml").inputStream() File("D:\\Work\\Projects\\dataforge-vis\\visionforge-gdml\\src\\jvmTest\\resources\\gdml\\BM@N.gdml").inputStream()
val xmlReader = StAXReader(stream, "UTF-8") val xmlReader = StAXReader(stream, "UTF-8")
val xml = Gdml.format.parse(Gdml.serializer(), xmlReader) val xml = Gdml.format.decodeFromReader(Gdml.serializer(), xmlReader)
val vision = xml.toVision() val vision = xml.toVision()

View File

@ -54,12 +54,8 @@ public class Sphere(
@VisionBuilder @VisionBuilder
public inline fun VisionContainerBuilder<Solid>.sphere( public inline fun VisionContainerBuilder<Solid>.sphere(
radius: Number, radius: Number,
phi: Number = 2 * PI,
theta: Number = PI,
name: String? = null, name: String? = null,
action: Sphere.() -> Unit = {}, action: Sphere.() -> Unit = {},
): Sphere = Sphere( ): Sphere = Sphere(
radius.toFloat(), radius.toFloat(),
phi = phi.toFloat(),
theta = theta.toFloat()
).apply(action).also { set(name, it) } ).apply(action).also { set(name, it) }

View File

@ -0,0 +1,77 @@
package hep.dataforge.vision.solid
import hep.dataforge.vision.VisionBuilder
import hep.dataforge.vision.VisionContainerBuilder
import hep.dataforge.vision.set
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin
@Serializable
@SerialName("solid.sphereLayer")
public class SphereLayer(
public var outerRadius: Float,
public var innerRadius: Float,
public var phiStart: Float = 0f,
public var phi: Float = PI2,
public var thetaStart: Float = 0f,
public var theta: Float = PI.toFloat(),
) : SolidBase(), GeometrySolid {
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>): Unit = geometryBuilder.run {
require(outerRadius > 0) { "Outer radius must be positive" }
require(innerRadius >= 0) { "inner radius must be non-negative" }
fun point3DfromSphCoord(r: Float, theta: Float, phi: Float): Point3D {
// This transformation matches three.js sphere implementation
val y = r * cos(theta)
val z = r * sin(theta) * sin(phi)
val x = -r * sin(theta) * cos(phi)
return Point3D(x, y, z)
}
val segments = detail ?: 8
require(segments >= 4) { "The detail for sphere must be >= 4" }
val phiStep = phi / segments
val thetaStep = theta / segments
for (i in 0 until segments) { // theta iteration
val theta1 = thetaStart + i * thetaStep
val theta2 = theta1 + thetaStep
for (j in 0 until segments) { // phi iteration
val phi1 = phiStart + j * phiStep
val phi2 = phi1 + phiStep
//outer points
val outerPoint1 = point3DfromSphCoord(outerRadius, theta1, phi1)
val outerPoint2 = point3DfromSphCoord(outerRadius, theta1, phi2)
val outerPoint3 = point3DfromSphCoord(outerRadius, theta2, phi2)
val outerPoint4 = point3DfromSphCoord(outerRadius, theta2, phi1)
// 1-2-3-4 gives the same face but with opposite orientation
face4(outerPoint1, outerPoint4, outerPoint3, outerPoint2)
if (innerRadius > 0) {
val innerPoint1 = point3DfromSphCoord(innerRadius, theta1, phi1)
val innerPoint2 = point3DfromSphCoord(innerRadius, theta1, phi2)
val innerPoint3 = point3DfromSphCoord(innerRadius, theta2, phi2)
val innerPoint4 = point3DfromSphCoord(innerRadius, theta2, phi1)
face4(innerPoint1, innerPoint2, innerPoint3, innerPoint4)
//the cup
if (i == segments - 1 && theta != PI.toFloat() && innerRadius != outerRadius) {
face4(outerPoint4, innerPoint4, innerPoint3, outerPoint3)
}
}
}
}
}
}
@VisionBuilder
public inline fun VisionContainerBuilder<Solid>.sphereLayer(
outerRadius: Number,
innerRadius: Number,
name: String? = null,
action: SphereLayer.() -> Unit = {},
): SphereLayer = SphereLayer(
outerRadius.toFloat(),
innerRadius.toFloat(),
).apply(action).also { set(name, it) }