forked from kscience/visionforge
GDML demo renders something
This commit is contained in:
parent
d3500c3a57
commit
e31ad5ece1
@ -0,0 +1,76 @@
|
|||||||
|
package hep.dataforge.vis.spatial.gdml
|
||||||
|
|
||||||
|
import scientifik.gdml.GDMLPosition
|
||||||
|
import scientifik.gdml.GDMLRotation
|
||||||
|
import scientifik.gdml.GDMLSolid
|
||||||
|
import kotlin.math.PI
|
||||||
|
|
||||||
|
enum class LUnit(val value: Double) {
|
||||||
|
MM(1.0),
|
||||||
|
CM(10.0),
|
||||||
|
M(1000.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class AUnit(val value: Double) {
|
||||||
|
DEG(PI / 180),
|
||||||
|
RAD(1.0),
|
||||||
|
RADIAN(1.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun GDMLPosition.unit(): LUnit = LUnit.valueOf(unit.toUpperCase())
|
||||||
|
|
||||||
|
fun GDMLPosition.x(unit: LUnit): Double = if (unit.name == this.unit) {
|
||||||
|
x.toDouble()
|
||||||
|
} else {
|
||||||
|
x.toDouble() / unit.value * unit().value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun GDMLPosition.y(unit: LUnit): Double = if (unit.name == this.unit) {
|
||||||
|
y.toDouble()
|
||||||
|
} else {
|
||||||
|
y.toDouble() / unit.value * unit().value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun GDMLPosition.z(unit: LUnit): Double = if (unit.name == this.unit) {
|
||||||
|
z.toDouble()
|
||||||
|
} else {
|
||||||
|
z.toDouble() / unit.value * unit().value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun GDMLRotation.unit(): AUnit = AUnit.valueOf(unit.toUpperCase())
|
||||||
|
|
||||||
|
fun GDMLRotation.x(unit: AUnit = AUnit.RAD): Double = if (unit.name == this.unit) {
|
||||||
|
x.toDouble()
|
||||||
|
} else {
|
||||||
|
x.toDouble() / unit.value * unit().value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun GDMLRotation.y(unit: AUnit = AUnit.RAD): Double = if (unit.name == this.unit) {
|
||||||
|
y.toDouble()
|
||||||
|
} else {
|
||||||
|
y.toDouble() / unit.value * unit().value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun GDMLRotation.z(unit: AUnit = AUnit.RAD): Double = if (unit.name == this.unit) {
|
||||||
|
z.toDouble()
|
||||||
|
} else {
|
||||||
|
z.toDouble() / unit.value * unit().value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun GDMLSolid.lscale(unit: LUnit): Double {
|
||||||
|
val solidUnit = lunit?.let { LUnit.valueOf(it.toUpperCase()) } ?: return 1.0
|
||||||
|
return if (solidUnit == unit) {
|
||||||
|
1.0
|
||||||
|
} else {
|
||||||
|
solidUnit.value / unit.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun GDMLSolid.ascale(unit: AUnit = AUnit.RAD): Double {
|
||||||
|
val solidUnit = aunit?.let { AUnit.valueOf(it.toUpperCase()) } ?: return 1.0
|
||||||
|
return if (solidUnit == unit) {
|
||||||
|
1.0
|
||||||
|
} else {
|
||||||
|
solidUnit.value / unit.value
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package hep.dataforge.vis.spatial.gdml
|
package hep.dataforge.vis.spatial.gdml
|
||||||
|
|
||||||
import hep.dataforge.meta.EmptyMeta
|
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.meta.buildMeta
|
||||||
import hep.dataforge.vis.common.VisualGroup
|
import hep.dataforge.vis.common.VisualGroup
|
||||||
import hep.dataforge.vis.common.VisualObject
|
import hep.dataforge.vis.common.VisualObject
|
||||||
import hep.dataforge.vis.common.color
|
import hep.dataforge.vis.common.color
|
||||||
@ -9,66 +9,64 @@ import hep.dataforge.vis.spatial.*
|
|||||||
import scientifik.gdml.*
|
import scientifik.gdml.*
|
||||||
import kotlin.math.cos
|
import kotlin.math.cos
|
||||||
import kotlin.math.sin
|
import kotlin.math.sin
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
|
||||||
private fun VisualObject.withPosition(
|
private fun VisualObject.withPosition(
|
||||||
|
lUnit: LUnit,
|
||||||
pos: GDMLPosition? = null,
|
pos: GDMLPosition? = null,
|
||||||
rotation: GDMLRotation? = null,
|
rotation: GDMLRotation? = null,
|
||||||
scale: GDMLScale? = null
|
scale: GDMLScale? = null
|
||||||
): VisualObject =
|
): VisualObject = apply {
|
||||||
apply {
|
|
||||||
// if( this is VisualObject3D){
|
|
||||||
// pos?.let {
|
|
||||||
// x = pos.x
|
|
||||||
// y = pos.y
|
|
||||||
// z = pos.z
|
|
||||||
// }
|
|
||||||
// rotation?.let {
|
|
||||||
// rotationX = rotation.x
|
|
||||||
// rotationY = rotation.y
|
|
||||||
// rotationZ = rotation.z
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
pos?.let {
|
pos?.let {
|
||||||
x = pos.x
|
x = pos.x(lUnit)
|
||||||
y = pos.y
|
y = pos.y(lUnit)
|
||||||
z = pos.z
|
z = pos.z(lUnit)
|
||||||
}
|
}
|
||||||
rotation?.let {
|
rotation?.let {
|
||||||
rotationX = rotation.x
|
rotationX = rotation.x()
|
||||||
rotationY = rotation.y
|
rotationY = rotation.y()
|
||||||
rotationZ = rotation.z
|
rotationZ = rotation.z()
|
||||||
}
|
}
|
||||||
//}
|
|
||||||
scale?.let {
|
scale?.let {
|
||||||
scaleX = scale.x
|
scaleX = scale.x
|
||||||
scaleY = scale.y
|
scaleY = scale.y
|
||||||
scaleZ = scale.z
|
scaleZ = scale.z
|
||||||
}
|
}
|
||||||
//TODO convert units if needed
|
//TODO convert units if needed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private inline operator fun Number.times(d: Double) = toDouble() * d
|
||||||
|
|
||||||
|
|
||||||
private fun VisualGroup.addSolid(
|
private fun VisualGroup.addSolid(
|
||||||
root: GDML,
|
root: GDML,
|
||||||
solid: GDMLSolid,
|
solid: GDMLSolid,
|
||||||
|
lUnit: LUnit,
|
||||||
name: String? = null,
|
name: String? = null,
|
||||||
block: VisualObject.() -> Unit = {}
|
block: VisualObject.() -> Unit = {}
|
||||||
): VisualObject {
|
): VisualObject {
|
||||||
|
val lScale = solid.lscale(lUnit)
|
||||||
|
val aScale = solid.ascale()
|
||||||
return when (solid) {
|
return when (solid) {
|
||||||
is GDMLBox -> box(solid.x, solid.y, solid.z, name)
|
is GDMLBox -> box(solid.x * lScale, solid.y * lScale, solid.z * lScale, name)
|
||||||
is GDMLTube -> cylinder(solid.rmax, solid.z, name) {
|
is GDMLTube -> cylinder(solid.rmax * lScale, solid.z * lScale, name) {
|
||||||
startAngle = solid.startphi
|
startAngle = solid.startphi * aScale
|
||||||
angle = solid.deltaphi
|
angle = solid.deltaphi * aScale
|
||||||
}
|
}
|
||||||
is GDMLXtru -> extrude(name) {
|
is GDMLXtru -> extrude(name) {
|
||||||
shape {
|
shape {
|
||||||
solid.vertices.forEach {
|
solid.vertices.forEach {
|
||||||
point(it.x, it.y)
|
point(it.x * lScale, it.y * lScale)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
solid.sections.sortedBy { it.zOrder }.forEach { section ->
|
solid.sections.sortedBy { it.zOrder }.forEach { section ->
|
||||||
layer(section.zPosition, section.xOffset, section.yOffset, section.scalingFactor)
|
layer(
|
||||||
|
section.zPosition * lScale,
|
||||||
|
section.xOffset * lScale,
|
||||||
|
section.yOffset * lScale,
|
||||||
|
section.scalingFactor
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is GDMLScaledSolid -> {
|
is GDMLScaledSolid -> {
|
||||||
@ -76,31 +74,31 @@ private fun VisualGroup.addSolid(
|
|||||||
val innerSolid = solid.solidref.resolve(root)
|
val innerSolid = solid.solidref.resolve(root)
|
||||||
?: error("Solid with tag ${solid.solidref.ref} for scaled solid ${solid.name} not defined")
|
?: error("Solid with tag ${solid.solidref.ref} for scaled solid ${solid.name} not defined")
|
||||||
|
|
||||||
addSolid(root, innerSolid) {
|
addSolid(root, innerSolid, lUnit) {
|
||||||
block()
|
block()
|
||||||
scaleX = scaleX.toDouble() * solid.scale.x.toDouble()
|
scaleX = scaleX.toDouble() * solid.scale.x.toDouble()
|
||||||
scaleY = scaleY.toDouble() * solid.scale.y.toDouble()
|
scaleY = scaleY.toDouble() * solid.scale.y.toDouble()
|
||||||
scaleZ = scaleZ.toDouble() * solid.scale.z.toDouble()
|
scaleZ = scaleZ.toDouble() * solid.scale.z.toDouble()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is GDMLSphere -> sphere(solid.rmax, solid.deltaphi, solid.deltatheta, name) {
|
is GDMLSphere -> sphere(solid.rmax * lScale, solid.deltaphi * aScale, solid.deltatheta * aScale, name) {
|
||||||
phiStart = solid.startphi.toDouble()
|
phiStart = solid.startphi * aScale
|
||||||
thetaStart = solid.starttheta.toDouble()
|
thetaStart = solid.starttheta * aScale
|
||||||
}
|
}
|
||||||
is GDMLOrb -> sphere(solid.r, name = name)
|
is GDMLOrb -> sphere(solid.r * lScale, name = name)
|
||||||
is GDMLPolyhedra -> extrude(name) {
|
is GDMLPolyhedra -> extrude(name) {
|
||||||
//getting the radius of first
|
//getting the radius of first
|
||||||
require(solid.planes.size > 1) { "The polyhedron geometry requires at least two planes" }
|
require(solid.planes.size > 1) { "The polyhedron geometry requires at least two planes" }
|
||||||
val baseRadius = solid.planes.first().rmax.toDouble()
|
val baseRadius = solid.planes.first().rmax * lScale
|
||||||
shape {
|
shape {
|
||||||
(0..solid.numsides).forEach {
|
(0..solid.numsides).forEach {
|
||||||
val phi = solid.deltaphi.toDouble() / solid.numsides * it + solid.startphi.toDouble()
|
val phi = solid.deltaphi * aScale / solid.numsides * it + solid.startphi * aScale
|
||||||
baseRadius * cos(phi) to baseRadius * sin(phi)
|
(baseRadius * cos(phi) to baseRadius * sin(phi))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
solid.planes.forEach { plane ->
|
solid.planes.forEach { plane ->
|
||||||
//scaling all radii relative to first layer radius
|
//scaling all radii relative to first layer radius
|
||||||
layer(plane.z, scale = plane.rmax.toDouble() / baseRadius)
|
layer(plane.z * lScale, scale = plane.rmax * lScale / baseRadius)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is GDMLBoolSolid -> {
|
is GDMLBoolSolid -> {
|
||||||
@ -113,19 +111,59 @@ private fun VisualGroup.addSolid(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return composite(type, name) {
|
return composite(type, name) {
|
||||||
addSolid(root, first) {
|
addSolid(root, first, lUnit) {
|
||||||
withPosition(solid.resolveFirstPosition(root), solid.resolveFirstRotation(root), null)
|
withPosition(lUnit, solid.resolveFirstPosition(root), solid.resolveFirstRotation(root), null)
|
||||||
|
}
|
||||||
|
addSolid(root, second, lUnit) {
|
||||||
|
withPosition(lUnit, solid.resolvePosition(root), solid.resolveRotation(root), null)
|
||||||
}
|
}
|
||||||
addSolid(root, second)
|
|
||||||
withPosition(solid.resolvePosition(root), solid.resolveRotation(root), null)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.apply(block)
|
}.apply(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun VisualGroup.addPhysicalVolume(
|
||||||
|
root: GDML,
|
||||||
|
physVolume: GDMLPhysVolume,
|
||||||
|
lUnit: LUnit,
|
||||||
|
resolveColor: GDMLMaterial.() -> Meta
|
||||||
|
) {
|
||||||
|
val volume: GDMLGroup = physVolume.volumeref.resolve(root)
|
||||||
|
?: error("Volume with ref ${physVolume.volumeref.ref} could not be resolved")
|
||||||
|
|
||||||
|
addVolume(
|
||||||
|
root,
|
||||||
|
volume,
|
||||||
|
lUnit,
|
||||||
|
physVolume.resolvePosition(root),
|
||||||
|
physVolume.resolveRotation(root),
|
||||||
|
physVolume.resolveScale(root),
|
||||||
|
resolveColor
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun VisualGroup.addDivisionVolume(
|
||||||
|
root: GDML,
|
||||||
|
divisionVolume: GDMLDivisionVolume,
|
||||||
|
lUnit: LUnit,
|
||||||
|
resolveColor: GDMLMaterial.() -> Meta
|
||||||
|
) {
|
||||||
|
val volume: GDMLGroup = divisionVolume.volumeref.resolve(root)
|
||||||
|
?: error("Volume with ref ${divisionVolume.volumeref.ref} could not be resolved")
|
||||||
|
|
||||||
|
//TODO add divisions
|
||||||
|
addVolume(
|
||||||
|
root,
|
||||||
|
volume,
|
||||||
|
lUnit,
|
||||||
|
resolveColor = resolveColor
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun VisualGroup.addVolume(
|
private fun VisualGroup.addVolume(
|
||||||
root: GDML,
|
root: GDML,
|
||||||
group: GDMLGroup,
|
group: GDMLGroup,
|
||||||
|
lUnit: LUnit,
|
||||||
position: GDMLPosition? = null,
|
position: GDMLPosition? = null,
|
||||||
rotation: GDMLRotation? = null,
|
rotation: GDMLRotation? = null,
|
||||||
scale: GDMLScale? = null,
|
scale: GDMLScale? = null,
|
||||||
@ -133,40 +171,37 @@ private fun VisualGroup.addVolume(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
group(group.name) {
|
group(group.name) {
|
||||||
withPosition(position, rotation, scale)
|
withPosition(lUnit, position, rotation, scale)
|
||||||
|
|
||||||
if (group is GDMLVolume) {
|
if (group is GDMLVolume) {
|
||||||
val solid = group.solidref.resolve(root)
|
val solid = group.solidref.resolve(root)
|
||||||
?: error("Solid with tag ${group.solidref.ref} for volume ${group.name} not defined")
|
?: error("Solid with tag ${group.solidref.ref} for volume ${group.name} not defined")
|
||||||
val material = group.materialref.resolve(root)
|
val material = group.materialref.resolve(root) ?: GDMLElement(group.materialref.ref)
|
||||||
?: error("Material with tag ${group.materialref.ref} for volume ${group.name} not defined")
|
//?: error("Material with tag ${group.materialref.ref} for volume ${group.name} not defined")
|
||||||
|
|
||||||
addSolid(root, solid, solid.name) {
|
addSolid(root, solid, lUnit, solid.name) {
|
||||||
color(material.resolveColor())
|
color(material.resolveColor())
|
||||||
}
|
}
|
||||||
//TODO render placements
|
|
||||||
|
when (val vol = group.placement) {
|
||||||
|
is GDMLPhysVolume -> addPhysicalVolume(root, vol, lUnit, resolveColor)
|
||||||
|
is GDMLDivisionVolume -> addDivisionVolume(root, vol, lUnit, resolveColor)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
group.physVolumes.forEach { physVolume ->
|
group.physVolumes.forEach { physVolume ->
|
||||||
val volume: GDMLGroup = physVolume.volumeref.resolve(root)
|
addPhysicalVolume(root, physVolume, lUnit, resolveColor)
|
||||||
?: error("Volume with ref ${physVolume.volumeref.ref} could not be resolved")
|
|
||||||
|
|
||||||
addVolume(
|
|
||||||
root,
|
|
||||||
volume,
|
|
||||||
physVolume.resolvePosition(root),
|
|
||||||
physVolume.resolveRotation(root),
|
|
||||||
physVolume.resolveScale(root),
|
|
||||||
resolveColor
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun GDML.toVisual(lUnit: LUnit = LUnit.MM): VisualGroup {
|
||||||
|
val cache = HashMap<GDMLMaterial, Meta>()
|
||||||
|
val random = Random(111)
|
||||||
|
|
||||||
fun GDML.toVisual(): VisualGroup {
|
fun GDMLMaterial.color(): Meta = cache.getOrPut(this) {
|
||||||
//TODO add materials cache
|
buildMeta { "color" to random.nextInt(0, Int.MAX_VALUE) }
|
||||||
fun GDMLMaterial.color(): Meta = EmptyMeta
|
}
|
||||||
return VisualGroup().also { it.addVolume(this, world) { color() } }
|
|
||||||
|
return VisualGroup().also { it.addVolume(this, world, lUnit) { color() } }
|
||||||
}
|
}
|
@ -3,9 +3,11 @@ package hep.dataforge.vis.spatial.gdml.demo
|
|||||||
import hep.dataforge.context.Global
|
import hep.dataforge.context.Global
|
||||||
import hep.dataforge.vis.hmr.ApplicationBase
|
import hep.dataforge.vis.hmr.ApplicationBase
|
||||||
import hep.dataforge.vis.hmr.startApplication
|
import hep.dataforge.vis.hmr.startApplication
|
||||||
|
import hep.dataforge.vis.spatial.gdml.LUnit
|
||||||
import hep.dataforge.vis.spatial.gdml.toVisual
|
import hep.dataforge.vis.spatial.gdml.toVisual
|
||||||
import hep.dataforge.vis.spatial.three.ThreePlugin
|
import hep.dataforge.vis.spatial.three.ThreePlugin
|
||||||
import hep.dataforge.vis.spatial.three.output
|
import hep.dataforge.vis.spatial.three.output
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.w3c.dom.HTMLDivElement
|
import org.w3c.dom.HTMLDivElement
|
||||||
@ -32,7 +34,7 @@ private class GDMLDemoApp : ApplicationBase() {
|
|||||||
/**
|
/**
|
||||||
* Load data from text file
|
* Load data from text file
|
||||||
*/
|
*/
|
||||||
private fun loadData(event: Event, block: suspend (String) -> Unit) {
|
private fun loadData(event: Event, block: suspend CoroutineScope.(String) -> Unit) {
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
@ -51,6 +53,25 @@ private class GDMLDemoApp : ApplicationBase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun spinner(show: Boolean) {
|
||||||
|
val style = if (show) {
|
||||||
|
"display:block;"
|
||||||
|
} else {
|
||||||
|
"display:none;"
|
||||||
|
}
|
||||||
|
document.getElementById("loader")?.setAttribute("style", style)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun message(message: String?) {
|
||||||
|
val element = document.getElementById("message")
|
||||||
|
if (message == null) {
|
||||||
|
element?.setAttribute("style", "display:none;")
|
||||||
|
} else {
|
||||||
|
element?.textContent = message
|
||||||
|
element?.setAttribute("style", "display:block;")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun start(state: Map<String, Any>) {
|
override fun start(state: Map<String, Any>) {
|
||||||
|
|
||||||
@ -59,13 +80,22 @@ private class GDMLDemoApp : ApplicationBase() {
|
|||||||
//val url = URL("https://drive.google.com/open?id=1w5e7fILMN83JGgB8WANJUYm8OW2s0WVO")
|
//val url = URL("https://drive.google.com/open?id=1w5e7fILMN83JGgB8WANJUYm8OW2s0WVO")
|
||||||
|
|
||||||
val canvas = document.getElementById("canvas") ?: error("Element with id canvas not found on page")
|
val canvas = document.getElementById("canvas") ?: error("Element with id canvas not found on page")
|
||||||
|
|
||||||
val action: suspend (String) -> Unit = {
|
|
||||||
canvas.clear()
|
canvas.clear()
|
||||||
val output = three.output(canvas)
|
|
||||||
|
val action: suspend CoroutineScope.(String) -> Unit = {
|
||||||
|
canvas.clear()
|
||||||
|
launch { spinner(true) }
|
||||||
|
launch { message("Loading GDML") }
|
||||||
val gdml = GDML.format.parse(GDML.serializer(), it)
|
val gdml = GDML.format.parse(GDML.serializer(), it)
|
||||||
val visual = gdml.toVisual()
|
launch { message("Converting GDML into DF-VIS format") }
|
||||||
|
val visual = gdml.toVisual(LUnit.CM)
|
||||||
|
launch { message("Rendering") }
|
||||||
|
val output = three.output(canvas)
|
||||||
output.render(visual)
|
output.render(visual)
|
||||||
|
launch {
|
||||||
|
message(null)
|
||||||
|
spinner(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(document.getElementById("drop_zone") as? HTMLDivElement)?.apply {
|
(document.getElementById("drop_zone") as? HTMLDivElement)?.apply {
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
<title>Three js demo for particle physics</title>
|
<title>Three js demo for particle physics</title>
|
||||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
|
||||||
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
|
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
|
||||||
|
<link rel="stylesheet" href="main.css">
|
||||||
<script type="text/javascript" src="main.bundle.js"></script>
|
<script type="text/javascript" src="main.bundle.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body class="testApp">
|
<body class="testApp">
|
||||||
@ -18,6 +19,8 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>GDML demo</h1>
|
<h1>GDML demo</h1>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="container loader" id="loader" style="display:none;"></div>
|
||||||
|
<div class="container animate-bottom" id="message" style="display:none;"></div>
|
||||||
<div class="container" id="canvas"></div>
|
<div class="container" id="canvas"></div>
|
||||||
|
|
||||||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
|
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
|
||||||
|
13
dataforge-vis-spatial-gdml/src/jsMain/web/main.css
Normal file
13
dataforge-vis-spatial-gdml/src/jsMain/web/main.css
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
.loader {
|
||||||
|
border: 16px solid #f3f3f3; /* Light grey */
|
||||||
|
border-top: 16px solid #3498db; /* Blue */
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
animation: spin 2s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% { transform: rotate(0deg); }
|
||||||
|
100% { transform: rotate(360deg); }
|
||||||
|
}
|
@ -4,6 +4,7 @@ import hep.dataforge.meta.*
|
|||||||
import hep.dataforge.values.ValueType
|
import hep.dataforge.values.ValueType
|
||||||
import hep.dataforge.vis.common.Colors
|
import hep.dataforge.vis.common.Colors
|
||||||
import info.laht.threekt.materials.Material
|
import info.laht.threekt.materials.Material
|
||||||
|
import info.laht.threekt.materials.MeshBasicMaterial
|
||||||
import info.laht.threekt.materials.MeshPhongMaterial
|
import info.laht.threekt.materials.MeshPhongMaterial
|
||||||
import info.laht.threekt.math.Color
|
import info.laht.threekt.math.Color
|
||||||
|
|
||||||
@ -39,19 +40,20 @@ fun MetaItem<*>.color(): Color {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Infer FX material based on meta item
|
* Infer Three material based on meta item
|
||||||
*/
|
*/
|
||||||
fun MetaItem<*>?.material(): Material {
|
fun MetaItem<*>?.material(): Material {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
null -> Materials.DEFAULT
|
null -> Materials.DEFAULT
|
||||||
is MetaItem.ValueItem -> MeshPhongMaterial().apply {
|
is MetaItem.ValueItem -> MeshBasicMaterial().apply {
|
||||||
color = this@material.color()
|
color = this@material.color()
|
||||||
}
|
}
|
||||||
is MetaItem.NodeItem -> MeshPhongMaterial().apply {
|
is MetaItem.NodeItem -> MeshBasicMaterial().apply {
|
||||||
(node["color"] ?: this@material).let { color = it.color() }
|
(node["color"] ?: this@material).let { color = it.color() }
|
||||||
opacity = node["opacity"]?.double ?: 1.0
|
opacity = node["opacity"]?.double ?: 1.0
|
||||||
transparent = node["transparent"].boolean ?: (opacity < 1.0)
|
transparent = node["transparent"].boolean ?: (opacity < 1.0)
|
||||||
node["specularColor"]?.let { specular = it.color() }
|
//node["specularColor"]?.let { specular = it.color() }
|
||||||
|
side = 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,15 +4,19 @@ import hep.dataforge.meta.Meta
|
|||||||
import hep.dataforge.meta.get
|
import hep.dataforge.meta.get
|
||||||
import hep.dataforge.meta.int
|
import hep.dataforge.meta.int
|
||||||
import hep.dataforge.vis.spatial.GeometryBuilder
|
import hep.dataforge.vis.spatial.GeometryBuilder
|
||||||
|
import hep.dataforge.vis.spatial.Point2D
|
||||||
import hep.dataforge.vis.spatial.Point3D
|
import hep.dataforge.vis.spatial.Point3D
|
||||||
import info.laht.threekt.core.BufferGeometry
|
import info.laht.threekt.core.BufferGeometry
|
||||||
import info.laht.threekt.core.Face3
|
import info.laht.threekt.core.Face3
|
||||||
import info.laht.threekt.core.Geometry
|
import info.laht.threekt.core.Geometry
|
||||||
|
import info.laht.threekt.math.Vector2
|
||||||
import info.laht.threekt.math.Vector3
|
import info.laht.threekt.math.Vector3
|
||||||
|
|
||||||
// TODO use unsafe cast instead
|
// TODO use unsafe cast instead
|
||||||
fun Point3D.asVector(): Vector3 = Vector3(this.x, this.y, this.z)
|
fun Point3D.asVector(): Vector3 = Vector3(this.x, this.y, this.z)
|
||||||
|
|
||||||
|
fun Point2D.asVector(): Vector2 = Vector2(this.x, this.y)
|
||||||
|
|
||||||
class ThreeGeometryBuilder : GeometryBuilder<BufferGeometry> {
|
class ThreeGeometryBuilder : GeometryBuilder<BufferGeometry> {
|
||||||
|
|
||||||
private val vertices = ArrayList<Point3D>()
|
private val vertices = ArrayList<Point3D>()
|
||||||
@ -38,6 +42,7 @@ class ThreeGeometryBuilder : GeometryBuilder<BufferGeometry> {
|
|||||||
faces.add(face)
|
faces.add(face)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun build(): BufferGeometry {
|
override fun build(): BufferGeometry {
|
||||||
return Geometry().apply {
|
return Geometry().apply {
|
||||||
vertices = this@ThreeGeometryBuilder.vertices.map { it.asVector() }.toTypedArray()
|
vertices = this@ThreeGeometryBuilder.vertices.map { it.asVector() }.toTypedArray()
|
||||||
|
@ -41,8 +41,9 @@ class ThreePlugin : AbstractPlugin() {
|
|||||||
is VisualGroup -> Group(obj.mapNotNull {
|
is VisualGroup -> Group(obj.mapNotNull {
|
||||||
try {
|
try {
|
||||||
buildObject3D(it)
|
buildObject3D(it)
|
||||||
} catch (ex: Throwable){
|
} catch (ex: Throwable) {
|
||||||
logger.error(ex){"Failed to render $it"}
|
console.error(ex)
|
||||||
|
logger.error(ex) { "Failed to render $it" }
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}).apply {
|
}).apply {
|
||||||
|
@ -2,10 +2,11 @@ package hep.dataforge.vis.spatial
|
|||||||
|
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.vis.common.VisualGroup
|
import hep.dataforge.vis.common.VisualGroup
|
||||||
|
import hep.dataforge.vis.common.VisualLeaf
|
||||||
import hep.dataforge.vis.common.VisualObject
|
import hep.dataforge.vis.common.VisualObject
|
||||||
|
|
||||||
class Box(parent: VisualObject?, val xSize: Number, val ySize: Number, val zSize: Number, meta: Array<out Meta>) :
|
class Box(parent: VisualObject?, val xSize: Number, val ySize: Number, val zSize: Number, meta: Array<out Meta>) :
|
||||||
VisualObject3D(parent, meta), Shape {
|
VisualLeaf(parent, meta), Shape {
|
||||||
|
|
||||||
//TODO add helper for color configuration
|
//TODO add helper for color configuration
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import hep.dataforge.meta.Meta
|
|||||||
import hep.dataforge.meta.seal
|
import hep.dataforge.meta.seal
|
||||||
import hep.dataforge.meta.update
|
import hep.dataforge.meta.update
|
||||||
import hep.dataforge.vis.common.VisualGroup
|
import hep.dataforge.vis.common.VisualGroup
|
||||||
|
import hep.dataforge.vis.common.VisualLeaf
|
||||||
import hep.dataforge.vis.common.VisualObject
|
import hep.dataforge.vis.common.VisualObject
|
||||||
|
|
||||||
enum class CompositeType {
|
enum class CompositeType {
|
||||||
@ -18,7 +19,7 @@ open class Composite(
|
|||||||
val second: VisualObject,
|
val second: VisualObject,
|
||||||
val type: CompositeType = CompositeType.UNION,
|
val type: CompositeType = CompositeType.UNION,
|
||||||
meta: Array<out Meta>
|
meta: Array<out Meta>
|
||||||
) : VisualObject3D(parent, meta)
|
) : VisualLeaf(parent, meta)
|
||||||
|
|
||||||
fun VisualGroup.composite(
|
fun VisualGroup.composite(
|
||||||
type: CompositeType,
|
type: CompositeType,
|
||||||
|
@ -45,10 +45,23 @@ class Extruded(parent: VisualObject?, meta: Array<out Meta>) : VisualLeaf(parent
|
|||||||
val layers: MutableList<Layer> = ArrayList()
|
val layers: MutableList<Layer> = ArrayList()
|
||||||
|
|
||||||
fun layer(z: Number, x: Number = 0.0, y: Number = 0.0, scale: Number = 1.0) {
|
fun layer(z: Number, x: Number = 0.0, y: Number = 0.0, scale: Number = 1.0) {
|
||||||
layers.add(Layer(x,y,z,scale))
|
layers.add(Layer(x, y, z, scale))
|
||||||
//TODO send invalidation signal
|
//TODO send invalidation signal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun <T : Any> GeometryBuilder<T>.cap(shape: List<Point3D>) {
|
||||||
|
//FIXME won't work for non-convex shapes
|
||||||
|
val center = Point3D(
|
||||||
|
shape.map { it.x.toDouble() }.average(),
|
||||||
|
shape.map { it.y.toDouble() }.average(),
|
||||||
|
shape.map { it.z.toDouble() }.average()
|
||||||
|
)
|
||||||
|
for(i in 0 until (shape.size - 1)){
|
||||||
|
face(shape[i], shape[i+1], center, null)
|
||||||
|
}
|
||||||
|
face(shape.last(), shape.first(),center,null)
|
||||||
|
}
|
||||||
|
|
||||||
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {
|
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {
|
||||||
val shape: Shape2D = shape
|
val shape: Shape2D = shape
|
||||||
|
|
||||||
@ -91,6 +104,8 @@ class Extruded(parent: VisualObject?, meta: Array<out Meta>) : VisualLeaf(parent
|
|||||||
)
|
)
|
||||||
lowerLayer = upperLayer
|
lowerLayer = upperLayer
|
||||||
}
|
}
|
||||||
|
geometryBuilder.cap(layers.first().reversed())
|
||||||
|
geometryBuilder.cap(layers.last())
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -4,23 +4,9 @@ import hep.dataforge.meta.*
|
|||||||
import hep.dataforge.names.plus
|
import hep.dataforge.names.plus
|
||||||
import hep.dataforge.output.Output
|
import hep.dataforge.output.Output
|
||||||
import hep.dataforge.vis.common.VisualGroup
|
import hep.dataforge.vis.common.VisualGroup
|
||||||
import hep.dataforge.vis.common.VisualLeaf
|
|
||||||
import hep.dataforge.vis.common.VisualObject
|
import hep.dataforge.vis.common.VisualObject
|
||||||
import hep.dataforge.vis.common.asName
|
import hep.dataforge.vis.common.asName
|
||||||
|
|
||||||
/**
|
|
||||||
* Performance optimized version of visual object
|
|
||||||
*/
|
|
||||||
open class VisualObject3D(parent: VisualObject?, tagRefs: Array<out Meta>) : VisualLeaf(parent, tagRefs) {
|
|
||||||
var x: Number? = null; get() = field ?: (this as VisualLeaf).x
|
|
||||||
var y: Number? = null; get() = field ?: (this as VisualLeaf).y
|
|
||||||
var z: Number? = null; get() = field ?: (this as VisualLeaf).z
|
|
||||||
|
|
||||||
var rotationX: Number? = null; get() = field ?: (this as VisualLeaf).rotationX
|
|
||||||
var rotationY: Number? = null; get() = field ?: (this as VisualLeaf).rotationY
|
|
||||||
var rotationZ: Number? = null; get() = field ?: (this as VisualLeaf).rotationZ
|
|
||||||
}
|
|
||||||
|
|
||||||
fun VisualGroup.group(key: String? = null, vararg meta: Meta, action: VisualGroup.() -> Unit = {}): VisualGroup =
|
fun VisualGroup.group(key: String? = null, vararg meta: Meta, action: VisualGroup.() -> Unit = {}): VisualGroup =
|
||||||
VisualGroup(this, meta).apply(action).also { set(key, it) }
|
VisualGroup(this, meta).apply(action).also { set(key, it) }
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user