forked from kscience/visionforge
Performance optimization
This commit is contained in:
parent
e31ad5ece1
commit
997a5a8e60
@ -1,11 +1,5 @@
|
|||||||
package hep.dataforge.vis.common
|
package hep.dataforge.vis.common
|
||||||
|
|
||||||
import hep.dataforge.meta.Meta
|
|
||||||
import hep.dataforge.meta.MetaBuilder
|
|
||||||
import hep.dataforge.meta.buildMeta
|
|
||||||
import hep.dataforge.meta.set
|
|
||||||
import hep.dataforge.names.toName
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Taken from https://github.com/markaren/three.kt/blob/master/threejs-wrapper/src/main/kotlin/info/laht/threekt/math/ColorConstants.kt
|
* Taken from https://github.com/markaren/three.kt/blob/master/threejs-wrapper/src/main/kotlin/info/laht/threekt/math/ColorConstants.kt
|
||||||
*/
|
*/
|
||||||
@ -181,23 +175,3 @@ object Colors {
|
|||||||
const val yellow = 0xFFFF00
|
const val yellow = 0xFFFF00
|
||||||
const val yellowgreen = 0x9ACD32
|
const val yellowgreen = 0x9ACD32
|
||||||
}
|
}
|
||||||
|
|
||||||
private val material = "material".toName()
|
|
||||||
|
|
||||||
fun VisualObject.color(rgb: Int) {
|
|
||||||
this.config[material] = rgb
|
|
||||||
}
|
|
||||||
|
|
||||||
fun VisualObject.color(meta: Meta) {
|
|
||||||
this.config[material] = meta
|
|
||||||
}
|
|
||||||
|
|
||||||
fun VisualObject.color(builder: MetaBuilder.() -> Unit) {
|
|
||||||
color(buildMeta(builder))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun VisualObject.color(r: Int, g: Int, b: Int) = color {
|
|
||||||
"red" to r
|
|
||||||
"green" to g
|
|
||||||
"blue" to b
|
|
||||||
}
|
|
@ -5,22 +5,12 @@ import hep.dataforge.meta.Laminate
|
|||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.provider.Provider
|
import hep.dataforge.provider.Provider
|
||||||
import kotlin.collections.ArrayList
|
|
||||||
import kotlin.collections.HashMap
|
|
||||||
import kotlin.collections.HashSet
|
|
||||||
import kotlin.collections.Iterable
|
|
||||||
import kotlin.collections.Iterator
|
|
||||||
import kotlin.collections.Map
|
|
||||||
import kotlin.collections.emptyMap
|
|
||||||
import kotlin.collections.forEach
|
|
||||||
import kotlin.collections.plus
|
|
||||||
import kotlin.collections.removeAll
|
|
||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A display group which allows both named and unnamed children
|
* A display group which allows both named and unnamed children
|
||||||
*/
|
*/
|
||||||
class VisualGroup(
|
open class VisualGroup(
|
||||||
override val parent: VisualObject? = null, tagRefs: Array<out Meta> = emptyArray()
|
override val parent: VisualObject? = null, tagRefs: Array<out Meta> = emptyArray()
|
||||||
) : VisualObject, Iterable<VisualObject>, Provider {
|
) : VisualObject, Iterable<VisualObject>, Provider {
|
||||||
|
|
||||||
@ -30,7 +20,9 @@ class VisualGroup(
|
|||||||
override val defaultTarget: String get() = VisualObject.TYPE
|
override val defaultTarget: String get() = VisualObject.TYPE
|
||||||
override val config = Config()
|
override val config = Config()
|
||||||
|
|
||||||
override val properties: Laminate by lazy { combineProperties(parent, config, tagRefs) }
|
override val properties: Laminate by lazy {
|
||||||
|
combineProperties(parent, config, tagRefs)
|
||||||
|
}
|
||||||
|
|
||||||
override fun iterator(): Iterator<VisualObject> = (namedChildren.values + unnamedChildren).iterator()
|
override fun iterator(): Iterator<VisualObject> = (namedChildren.values + unnamedChildren).iterator()
|
||||||
|
|
||||||
|
@ -78,9 +78,11 @@ open class VisualLeaf(
|
|||||||
final override val parent: VisualObject?,
|
final override val parent: VisualObject?,
|
||||||
tagRefs: Array<out Meta>
|
tagRefs: Array<out Meta>
|
||||||
) : VisualObject {
|
) : VisualObject {
|
||||||
final override val config = Config()
|
override val config = Config()
|
||||||
|
|
||||||
override val properties: Laminate by lazy { combineProperties(parent, config, tagRefs) }
|
override val properties: Laminate by lazy {
|
||||||
|
combineProperties(parent, config, tagRefs)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun combineProperties(parent: VisualObject?, config: Config, tagRefs: Array<out Meta>): Laminate {
|
internal fun combineProperties(parent: VisualObject?, config: Config, tagRefs: Array<out Meta>): Laminate {
|
||||||
|
@ -5,71 +5,72 @@ import scientifik.gdml.GDMLRotation
|
|||||||
import scientifik.gdml.GDMLSolid
|
import scientifik.gdml.GDMLSolid
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
|
|
||||||
enum class LUnit(val value: Double) {
|
enum class LUnit(val value: Float) {
|
||||||
MM(1.0),
|
MM(1f),
|
||||||
CM(10.0),
|
CM(10f),
|
||||||
M(1000.0)
|
M(1000f)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class AUnit(val value: Double) {
|
enum class AUnit(val value: Float) {
|
||||||
DEG(PI / 180),
|
DEG(PI.toFloat() / 180),
|
||||||
RAD(1.0),
|
DEGREE(PI.toFloat() / 180),
|
||||||
RADIAN(1.0)
|
RAD(1f),
|
||||||
|
RADIAN(1f)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun GDMLPosition.unit(): LUnit = LUnit.valueOf(unit.toUpperCase())
|
fun GDMLPosition.unit(): LUnit = LUnit.valueOf(unit.toUpperCase())
|
||||||
|
|
||||||
fun GDMLPosition.x(unit: LUnit): Double = if (unit.name == this.unit) {
|
fun GDMLPosition.x(unit: LUnit): Float = if (unit.name == this.unit) {
|
||||||
x.toDouble()
|
x.toFloat()
|
||||||
} else {
|
} else {
|
||||||
x.toDouble() / unit.value * unit().value
|
x.toFloat() / unit.value * unit().value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun GDMLPosition.y(unit: LUnit): Double = if (unit.name == this.unit) {
|
fun GDMLPosition.y(unit: LUnit): Float = if (unit.name == this.unit) {
|
||||||
y.toDouble()
|
y.toFloat()
|
||||||
} else {
|
} else {
|
||||||
y.toDouble() / unit.value * unit().value
|
y.toFloat() / unit.value * unit().value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun GDMLPosition.z(unit: LUnit): Double = if (unit.name == this.unit) {
|
fun GDMLPosition.z(unit: LUnit): Float = if (unit.name == this.unit) {
|
||||||
z.toDouble()
|
z.toFloat()
|
||||||
} else {
|
} else {
|
||||||
z.toDouble() / unit.value * unit().value
|
z.toFloat() / unit.value * unit().value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun GDMLRotation.unit(): AUnit = AUnit.valueOf(unit.toUpperCase())
|
fun GDMLRotation.unit(): AUnit = AUnit.valueOf(unit.toUpperCase())
|
||||||
|
|
||||||
fun GDMLRotation.x(unit: AUnit = AUnit.RAD): Double = if (unit.name == this.unit) {
|
fun GDMLRotation.x(unit: AUnit = AUnit.RAD): Float = if (unit.name == this.unit) {
|
||||||
x.toDouble()
|
x.toFloat()
|
||||||
} else {
|
} else {
|
||||||
x.toDouble() / unit.value * unit().value
|
x.toFloat() / unit.value * unit().value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun GDMLRotation.y(unit: AUnit = AUnit.RAD): Double = if (unit.name == this.unit) {
|
fun GDMLRotation.y(unit: AUnit = AUnit.RAD): Float = if (unit.name == this.unit) {
|
||||||
y.toDouble()
|
y.toFloat()
|
||||||
} else {
|
} else {
|
||||||
y.toDouble() / unit.value * unit().value
|
y.toFloat() / unit.value * unit().value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun GDMLRotation.z(unit: AUnit = AUnit.RAD): Double = if (unit.name == this.unit) {
|
fun GDMLRotation.z(unit: AUnit = AUnit.RAD): Float = if (unit.name == this.unit) {
|
||||||
z.toDouble()
|
z.toFloat()
|
||||||
} else {
|
} else {
|
||||||
z.toDouble() / unit.value * unit().value
|
z.toFloat() / unit.value * unit().value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun GDMLSolid.lscale(unit: LUnit): Double {
|
fun GDMLSolid.lscale(unit: LUnit): Float {
|
||||||
val solidUnit = lunit?.let { LUnit.valueOf(it.toUpperCase()) } ?: return 1.0
|
val solidUnit = lunit?.let { LUnit.valueOf(it.toUpperCase()) } ?: return 1f
|
||||||
return if (solidUnit == unit) {
|
return if (solidUnit == unit) {
|
||||||
1.0
|
1f
|
||||||
} else {
|
} else {
|
||||||
solidUnit.value / unit.value
|
solidUnit.value / unit.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun GDMLSolid.ascale(unit: AUnit = AUnit.RAD): Double {
|
fun GDMLSolid.ascale(unit: AUnit = AUnit.RAD): Float {
|
||||||
val solidUnit = aunit?.let { AUnit.valueOf(it.toUpperCase()) } ?: return 1.0
|
val solidUnit = aunit?.let { AUnit.valueOf(it.toUpperCase()) } ?: return 1f
|
||||||
return if (solidUnit == unit) {
|
return if (solidUnit == unit) {
|
||||||
1.0
|
1f
|
||||||
} else {
|
} else {
|
||||||
solidUnit.value / unit.value
|
solidUnit.value / unit.value
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,7 @@ package hep.dataforge.vis.spatial.gdml
|
|||||||
|
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.meta.buildMeta
|
import hep.dataforge.meta.buildMeta
|
||||||
import hep.dataforge.vis.common.VisualGroup
|
import hep.dataforge.meta.builder
|
||||||
import hep.dataforge.vis.common.VisualObject
|
|
||||||
import hep.dataforge.vis.common.color
|
|
||||||
import hep.dataforge.vis.spatial.*
|
import hep.dataforge.vis.spatial.*
|
||||||
import scientifik.gdml.*
|
import scientifik.gdml.*
|
||||||
import kotlin.math.cos
|
import kotlin.math.cos
|
||||||
@ -12,41 +10,87 @@ import kotlin.math.sin
|
|||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
|
||||||
private fun VisualObject.withPosition(
|
class GDMLTransformer(val root: GDML) {
|
||||||
|
private val cache = HashMap<GDMLMaterial, Meta>()
|
||||||
|
private val random = Random(111)
|
||||||
|
|
||||||
|
var lUnit: LUnit = LUnit.MM
|
||||||
|
var resolveColor: ColorResolver = { material, _ ->
|
||||||
|
val materialColor = cache.getOrPut(material) {
|
||||||
|
buildMeta {
|
||||||
|
"color" to random.nextInt(0, Int.MAX_VALUE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this?.physVolumes?.isEmpty() != false) {
|
||||||
|
materialColor
|
||||||
|
} else {
|
||||||
|
materialColor.builder().apply { "opacity" to 0.5 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var acceptSolid: (GDMLSolid) -> Boolean = { true }
|
||||||
|
var acceptGroup: (GDMLGroup) -> Boolean = { true }
|
||||||
|
|
||||||
|
fun printStatistics() {
|
||||||
|
println("Solids:")
|
||||||
|
solidCounter.entries.sortedByDescending { it.value }.forEach {
|
||||||
|
println("\t$it")
|
||||||
|
}
|
||||||
|
println(println("Solids total: ${solidCounter.values.sum()}"))
|
||||||
|
}
|
||||||
|
|
||||||
|
private val solidCounter = HashMap<String, Int>()
|
||||||
|
|
||||||
|
internal fun solidAdded(solid: GDMLSolid) {
|
||||||
|
solidCounter[solid.name] = (solidCounter[solid.name] ?: 0) + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
var onFinish: GDMLTransformer.() -> Unit = {}
|
||||||
|
|
||||||
|
internal fun finished(){
|
||||||
|
onFinish(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun VisualObject3D.withPosition(
|
||||||
lUnit: LUnit,
|
lUnit: LUnit,
|
||||||
pos: GDMLPosition? = null,
|
pos: GDMLPosition? = null,
|
||||||
rotation: GDMLRotation? = null,
|
rotation: GDMLRotation? = null,
|
||||||
scale: GDMLScale? = null
|
scale: GDMLScale? = null
|
||||||
): VisualObject = apply {
|
): VisualObject3D = apply {
|
||||||
pos?.let {
|
pos?.let {
|
||||||
x = pos.x(lUnit)
|
this@withPosition.position.x = pos.x(lUnit)
|
||||||
y = pos.y(lUnit)
|
this@withPosition.position.y = pos.y(lUnit)
|
||||||
z = pos.z(lUnit)
|
this@withPosition.position.z = pos.z(lUnit)
|
||||||
}
|
}
|
||||||
rotation?.let {
|
rotation?.let {
|
||||||
rotationX = rotation.x()
|
this@withPosition.rotation.x = rotation.x()
|
||||||
rotationY = rotation.y()
|
this@withPosition.rotation.y = rotation.y()
|
||||||
rotationZ = rotation.z()
|
this@withPosition.rotation.z = rotation.z()
|
||||||
}
|
}
|
||||||
scale?.let {
|
scale?.let {
|
||||||
scaleX = scale.x
|
this@withPosition.scale.x = scale.x.toFloat()
|
||||||
scaleY = scale.y
|
this@withPosition.scale.y = scale.y.toFloat()
|
||||||
scaleZ = scale.z
|
this@withPosition.scale.z = scale.z.toFloat()
|
||||||
}
|
}
|
||||||
//TODO convert units if needed
|
//TODO convert units if needed
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline operator fun Number.times(d: Double) = toDouble() * d
|
private inline operator fun Number.times(d: Double) = toDouble() * d
|
||||||
|
private inline operator fun Number.times(f: Float) = toFloat() * f
|
||||||
|
|
||||||
|
|
||||||
private fun VisualGroup.addSolid(
|
private fun VisualGroup3D.addSolid(
|
||||||
root: GDML,
|
context: GDMLTransformer,
|
||||||
solid: GDMLSolid,
|
solid: GDMLSolid,
|
||||||
lUnit: LUnit,
|
|
||||||
name: String? = null,
|
name: String? = null,
|
||||||
block: VisualObject.() -> Unit = {}
|
block: VisualObject3D.() -> Unit = {}
|
||||||
): VisualObject {
|
): VisualObject3D {
|
||||||
val lScale = solid.lscale(lUnit)
|
context.solidAdded(solid)
|
||||||
|
val lScale = solid.lscale(context.lUnit)
|
||||||
val aScale = solid.ascale()
|
val aScale = solid.ascale()
|
||||||
return when (solid) {
|
return when (solid) {
|
||||||
is GDMLBox -> box(solid.x * lScale, solid.y * lScale, solid.z * lScale, name)
|
is GDMLBox -> box(solid.x * lScale, solid.y * lScale, solid.z * lScale, name)
|
||||||
@ -71,14 +115,14 @@ private fun VisualGroup.addSolid(
|
|||||||
}
|
}
|
||||||
is GDMLScaledSolid -> {
|
is GDMLScaledSolid -> {
|
||||||
//Add solid with modified scale
|
//Add solid with modified scale
|
||||||
val innerSolid = solid.solidref.resolve(root)
|
val innerSolid = solid.solidref.resolve(context.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, lUnit) {
|
addSolid(context, innerSolid) {
|
||||||
block()
|
block()
|
||||||
scaleX = scaleX.toDouble() * solid.scale.x.toDouble()
|
scale.x *= solid.scale.x.toFloat()
|
||||||
scaleY = scaleY.toDouble() * solid.scale.y.toDouble()
|
scale.y *= solid.scale.y.toFloat()
|
||||||
scaleZ = scaleZ.toDouble() * solid.scale.z.toDouble()
|
scale.z = solid.scale.z.toFloat()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is GDMLSphere -> sphere(solid.rmax * lScale, solid.deltaphi * aScale, solid.deltatheta * aScale, name) {
|
is GDMLSphere -> sphere(solid.rmax * lScale, solid.deltaphi * aScale, solid.deltatheta * aScale, name) {
|
||||||
@ -102,8 +146,8 @@ private fun VisualGroup.addSolid(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is GDMLBoolSolid -> {
|
is GDMLBoolSolid -> {
|
||||||
val first = solid.first.resolve(root) ?: error("")
|
val first = solid.first.resolve(context.root) ?: error("")
|
||||||
val second = solid.second.resolve(root) ?: error("")
|
val second = solid.second.resolve(context.root) ?: error("")
|
||||||
val type: CompositeType = when (solid) {
|
val type: CompositeType = when (solid) {
|
||||||
is GDMLUnion -> CompositeType.UNION
|
is GDMLUnion -> CompositeType.UNION
|
||||||
is GDMLSubtraction -> CompositeType.SUBTRACT
|
is GDMLSubtraction -> CompositeType.SUBTRACT
|
||||||
@ -111,97 +155,114 @@ private fun VisualGroup.addSolid(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return composite(type, name) {
|
return composite(type, name) {
|
||||||
addSolid(root, first, lUnit) {
|
addSolid(context, first) {
|
||||||
withPosition(lUnit, solid.resolveFirstPosition(root), solid.resolveFirstRotation(root), null)
|
withPosition(
|
||||||
|
context.lUnit,
|
||||||
|
solid.resolveFirstPosition(context.root),
|
||||||
|
solid.resolveFirstRotation(context.root),
|
||||||
|
null
|
||||||
|
)
|
||||||
}
|
}
|
||||||
addSolid(root, second, lUnit) {
|
addSolid(context, second) {
|
||||||
withPosition(lUnit, solid.resolvePosition(root), solid.resolveRotation(root), null)
|
withPosition(
|
||||||
|
context.lUnit,
|
||||||
|
solid.resolvePosition(context.root),
|
||||||
|
solid.resolveRotation(context.root),
|
||||||
|
null
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.apply(block)
|
}.apply(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun VisualGroup.addPhysicalVolume(
|
private fun VisualGroup3D.addPhysicalVolume(
|
||||||
root: GDML,
|
context: GDMLTransformer,
|
||||||
physVolume: GDMLPhysVolume,
|
physVolume: GDMLPhysVolume
|
||||||
lUnit: LUnit,
|
|
||||||
resolveColor: GDMLMaterial.() -> Meta
|
|
||||||
) {
|
) {
|
||||||
val volume: GDMLGroup = physVolume.volumeref.resolve(root)
|
val volume: GDMLGroup = physVolume.volumeref.resolve(context.root)
|
||||||
?: error("Volume with ref ${physVolume.volumeref.ref} could not be resolved")
|
?: error("Volume with ref ${physVolume.volumeref.ref} could not be resolved")
|
||||||
|
|
||||||
addVolume(
|
if (context.acceptGroup(volume)) {
|
||||||
root,
|
|
||||||
|
this[physVolume.name] = volume(
|
||||||
|
context,
|
||||||
volume,
|
volume,
|
||||||
lUnit,
|
physVolume.resolvePosition(context.root),
|
||||||
physVolume.resolvePosition(root),
|
physVolume.resolveRotation(context.root),
|
||||||
physVolume.resolveRotation(root),
|
physVolume.resolveScale(context.root)
|
||||||
physVolume.resolveScale(root),
|
|
||||||
resolveColor
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun VisualGroup.addDivisionVolume(
|
private fun VisualGroup3D.addDivisionVolume(
|
||||||
root: GDML,
|
context: GDMLTransformer,
|
||||||
divisionVolume: GDMLDivisionVolume,
|
divisionVolume: GDMLDivisionVolume
|
||||||
lUnit: LUnit,
|
|
||||||
resolveColor: GDMLMaterial.() -> Meta
|
|
||||||
) {
|
) {
|
||||||
val volume: GDMLGroup = divisionVolume.volumeref.resolve(root)
|
val volume: GDMLGroup = divisionVolume.volumeref.resolve(context.root)
|
||||||
?: error("Volume with ref ${divisionVolume.volumeref.ref} could not be resolved")
|
?: error("Volume with ref ${divisionVolume.volumeref.ref} could not be resolved")
|
||||||
|
|
||||||
//TODO add divisions
|
//TODO add divisions
|
||||||
addVolume(
|
add(
|
||||||
root,
|
volume(
|
||||||
volume,
|
context,
|
||||||
lUnit,
|
volume
|
||||||
resolveColor = resolveColor
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun VisualGroup.addVolume(
|
private fun VisualGroup3D.addVolume(
|
||||||
root: GDML,
|
context: GDMLTransformer,
|
||||||
group: GDMLGroup,
|
group: GDMLGroup,
|
||||||
lUnit: LUnit,
|
|
||||||
position: GDMLPosition? = null,
|
position: GDMLPosition? = null,
|
||||||
rotation: GDMLRotation? = null,
|
rotation: GDMLRotation? = null,
|
||||||
scale: GDMLScale? = null,
|
scale: GDMLScale? = null
|
||||||
resolveColor: GDMLMaterial.() -> Meta
|
|
||||||
) {
|
) {
|
||||||
|
this[group.name] = volume(context, group, position, rotation, scale)
|
||||||
|
}
|
||||||
|
|
||||||
group(group.name) {
|
private fun volume(
|
||||||
withPosition(lUnit, position, rotation, scale)
|
context: GDMLTransformer,
|
||||||
|
group: GDMLGroup,
|
||||||
|
position: GDMLPosition? = null,
|
||||||
|
rotation: GDMLRotation? = null,
|
||||||
|
scale: GDMLScale? = null
|
||||||
|
): VisualGroup3D {
|
||||||
|
|
||||||
|
return VisualGroup3D().apply {
|
||||||
|
withPosition(context.lUnit, position, rotation, scale)
|
||||||
|
|
||||||
if (group is GDMLVolume) {
|
if (group is GDMLVolume) {
|
||||||
val solid = group.solidref.resolve(root)
|
val solid = group.solidref.resolve(context.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) ?: GDMLElement(group.materialref.ref)
|
val material = group.materialref.resolve(context.root) ?: GDMLElement(group.materialref.ref)
|
||||||
//?: error("Material with tag ${group.materialref.ref} for volume ${group.name} not defined")
|
|
||||||
|
|
||||||
addSolid(root, solid, lUnit, solid.name) {
|
if (context.acceptSolid(solid)) {
|
||||||
color(material.resolveColor())
|
addSolid(context, solid, solid.name) {
|
||||||
|
this.material = context.resolveColor(group, material, solid)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
when (val vol = group.placement) {
|
when (val vol = group.placement) {
|
||||||
is GDMLPhysVolume -> addPhysicalVolume(root, vol, lUnit, resolveColor)
|
is GDMLPhysVolume -> addPhysicalVolume(context, vol)
|
||||||
is GDMLDivisionVolume -> addDivisionVolume(root, vol, lUnit, resolveColor)
|
is GDMLDivisionVolume -> addDivisionVolume(context, vol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
group.physVolumes.forEach { physVolume ->
|
group.physVolumes.forEach { physVolume ->
|
||||||
addPhysicalVolume(root, physVolume, lUnit, resolveColor)
|
addPhysicalVolume(context, physVolume)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun GDML.toVisual(lUnit: LUnit = LUnit.MM): VisualGroup {
|
typealias ColorResolver = GDMLGroup?.(GDMLMaterial, GDMLSolid?) -> Meta
|
||||||
val cache = HashMap<GDMLMaterial, Meta>()
|
|
||||||
val random = Random(111)
|
|
||||||
|
|
||||||
fun GDMLMaterial.color(): Meta = cache.getOrPut(this) {
|
|
||||||
buildMeta { "color" to random.nextInt(0, Int.MAX_VALUE) }
|
|
||||||
}
|
|
||||||
|
|
||||||
return VisualGroup().also { it.addVolume(this, world, lUnit) { color() } }
|
fun GDML.toVisual(block: GDMLTransformer.() -> Unit = {}): VisualGroup3D {
|
||||||
|
|
||||||
|
val context = GDMLTransformer(this).apply(block)
|
||||||
|
|
||||||
|
return volume(context, world).also{
|
||||||
|
context.finished()
|
||||||
|
}
|
||||||
}
|
}
|
@ -88,7 +88,14 @@ private class GDMLDemoApp : ApplicationBase() {
|
|||||||
launch { message("Loading GDML") }
|
launch { message("Loading GDML") }
|
||||||
val gdml = GDML.format.parse(GDML.serializer(), it)
|
val gdml = GDML.format.parse(GDML.serializer(), it)
|
||||||
launch { message("Converting GDML into DF-VIS format") }
|
launch { message("Converting GDML into DF-VIS format") }
|
||||||
val visual = gdml.toVisual(LUnit.CM)
|
val visual = gdml.toVisual {
|
||||||
|
lUnit = LUnit.CM
|
||||||
|
acceptSolid = { solid ->
|
||||||
|
!solid.name.startsWith("ecal")
|
||||||
|
&& !solid.name.startsWith("V")
|
||||||
|
&& !solid.name.startsWith("U")
|
||||||
|
}
|
||||||
|
}
|
||||||
launch { message("Rendering") }
|
launch { message("Rendering") }
|
||||||
val output = three.output(canvas)
|
val output = three.output(canvas)
|
||||||
output.render(visual)
|
output.render(visual)
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
package hep.dataforge.vis.spatial.gdml
|
||||||
|
|
||||||
|
import nl.adaptivity.xmlutil.StAXReader
|
||||||
|
import scientifik.gdml.GDML
|
||||||
|
import java.io.File
|
||||||
|
import java.net.URL
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val url = URL("https://drive.google.com/open?id=1w5e7fILMN83JGgB8WANJUYm8OW2s0WVO")
|
||||||
|
val file = File("D:\\Work\\Projects\\gdml.kt\\gdml-source\\BM@N.gdml")
|
||||||
|
val stream = if (file.exists()) {
|
||||||
|
file.inputStream()
|
||||||
|
} else {
|
||||||
|
url.openStream()
|
||||||
|
}
|
||||||
|
|
||||||
|
val xmlReader = StAXReader(stream, "UTF-8")
|
||||||
|
val xml = GDML.format.parse(GDML.serializer(), xmlReader)
|
||||||
|
xml.toVisual {
|
||||||
|
lUnit = LUnit.CM
|
||||||
|
acceptSolid = { solid -> !solid.name.startsWith("ecal") && !solid.name.startsWith("V") }
|
||||||
|
onFinish = { printStatistics() }
|
||||||
|
}
|
||||||
|
readLine()
|
||||||
|
}
|
@ -1,28 +0,0 @@
|
|||||||
package hep.dataforge.vis.spatial.gdml
|
|
||||||
|
|
||||||
import nl.adaptivity.xmlutil.StAXReader
|
|
||||||
import org.junit.Test
|
|
||||||
import scientifik.gdml.GDML
|
|
||||||
import java.io.File
|
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
class BMNTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testRead() {
|
|
||||||
|
|
||||||
val url = URL("https://drive.google.com/open?id=1w5e7fILMN83JGgB8WANJUYm8OW2s0WVO")
|
|
||||||
val file = File("D:\\Work\\Projects\\gdml.kt\\src\\commonTest\\resources\\gdml\\geofile_full.xml")
|
|
||||||
val stream = if (file.exists()) {
|
|
||||||
file.inputStream()
|
|
||||||
} else {
|
|
||||||
url.openStream()
|
|
||||||
}
|
|
||||||
|
|
||||||
val xmlReader = StAXReader(stream, "UTF-8")
|
|
||||||
val xml = GDML.format.parse(GDML.serializer(), xmlReader)
|
|
||||||
repeat(20) {
|
|
||||||
xml.toVisual()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,40 @@
|
|||||||
|
package hep.dataforge.vis.spatial.gdml
|
||||||
|
|
||||||
|
import nl.adaptivity.xmlutil.StAXReader
|
||||||
|
import org.junit.Test
|
||||||
|
import scientifik.gdml.GDML
|
||||||
|
import java.io.File
|
||||||
|
import java.net.URL
|
||||||
|
|
||||||
|
class TestConvertor {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testBMNGeometry() {
|
||||||
|
val url = URL("https://drive.google.com/open?id=1w5e7fILMN83JGgB8WANJUYm8OW2s0WVO")
|
||||||
|
val file = File("D:\\Work\\Projects\\gdml.kt\\gdml-source\\BM@N.gdml")
|
||||||
|
val stream = if (file.exists()) {
|
||||||
|
file.inputStream()
|
||||||
|
} else {
|
||||||
|
url.openStream()
|
||||||
|
}
|
||||||
|
|
||||||
|
val xmlReader = StAXReader(stream, "UTF-8")
|
||||||
|
val xml = GDML.format.parse(GDML.serializer(), xmlReader)
|
||||||
|
xml.toVisual()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testCubes() {
|
||||||
|
val file = File("D:\\Work\\Projects\\gdml.kt\\gdml-source\\cubes.gdml ")
|
||||||
|
val stream = if (file.exists()) {
|
||||||
|
file.inputStream()
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val xmlReader = StAXReader(stream, "UTF-8")
|
||||||
|
val xml = GDML.format.parse(GDML.serializer(), xmlReader)
|
||||||
|
val visual = xml.toVisual()
|
||||||
|
println(visual)
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,7 @@
|
|||||||
package hep.dataforge.vis.spatial.demo
|
package hep.dataforge.vis.spatial.demo
|
||||||
|
|
||||||
import hep.dataforge.context.ContextBuilder
|
import hep.dataforge.context.ContextBuilder
|
||||||
import hep.dataforge.meta.number
|
|
||||||
import hep.dataforge.vis.common.Colors
|
import hep.dataforge.vis.common.Colors
|
||||||
import hep.dataforge.vis.common.color
|
|
||||||
import hep.dataforge.vis.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.*
|
import hep.dataforge.vis.spatial.*
|
||||||
@ -42,6 +40,7 @@ private class ThreeDemoApp : ApplicationBase() {
|
|||||||
box(100, 100, 100) {
|
box(100, 100, 100) {
|
||||||
z = 110.0
|
z = 110.0
|
||||||
}
|
}
|
||||||
|
|
||||||
box(100, 100, 100) {
|
box(100, 100, 100) {
|
||||||
visible = false
|
visible = false
|
||||||
x = 110.0
|
x = 110.0
|
||||||
@ -51,32 +50,32 @@ private class ThreeDemoApp : ApplicationBase() {
|
|||||||
GlobalScope.launch {
|
GlobalScope.launch {
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
delay(500)
|
delay(500)
|
||||||
visible = !visible
|
visible = !(visible ?: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var material by group.config.number(1530).int
|
|
||||||
|
|
||||||
GlobalScope.launch {
|
GlobalScope.launch {
|
||||||
val random = Random(111)
|
val random = Random(111)
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
delay(1000)
|
delay(1000)
|
||||||
material = random.nextInt(0, Int.MAX_VALUE)
|
group.color(random.nextInt(0, Int.MAX_VALUE))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// demo("jsroot", "JSROOT cube") {
|
demo("rotation", "Rotations") {
|
||||||
// jsRootGeometry {
|
box(100, 100, 100)
|
||||||
// y = 110.0
|
group {
|
||||||
// shape = box(50, 50, 50)
|
x = 200
|
||||||
// color(Colors.lightcoral)
|
rotationY = PI / 4
|
||||||
// rotationX = PI / 4
|
box(100, 100, 100) {
|
||||||
// rotationY = PI / 4
|
rotationZ = PI / 4
|
||||||
// }
|
color(Colors.red)
|
||||||
// }
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
demo("extrude", "extruded shape") {
|
demo("extrude", "extruded shape") {
|
||||||
extrude {
|
extrude {
|
||||||
@ -86,10 +85,9 @@ private class ThreeDemoApp : ApplicationBase() {
|
|||||||
for (i in 0..100) {
|
for (i in 0..100) {
|
||||||
layer(i * 5, 20 * sin(2 * PI / 100 * i), 20 * cos(2 * PI / 100 * i))
|
layer(i * 5, 20 * sin(2 * PI / 100 * i), 20 * cos(2 * PI / 100 * i))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
color(Colors.teal)
|
color(Colors.teal)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
demo("CSG", "CSG operations") {
|
demo("CSG", "CSG operations") {
|
||||||
composite(CompositeType.UNION) {
|
composite(CompositeType.UNION) {
|
||||||
@ -97,7 +95,7 @@ private class ThreeDemoApp : ApplicationBase() {
|
|||||||
z = 50
|
z = 50
|
||||||
}
|
}
|
||||||
sphere(50)
|
sphere(50)
|
||||||
color {
|
material {
|
||||||
"color" to Colors.lightgreen
|
"color" to Colors.lightgreen
|
||||||
"opacity" to 0.3
|
"opacity" to 0.3
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,8 @@ import hep.dataforge.names.Name
|
|||||||
import hep.dataforge.names.toName
|
import hep.dataforge.names.toName
|
||||||
import hep.dataforge.output.Output
|
import hep.dataforge.output.Output
|
||||||
import hep.dataforge.output.OutputManager
|
import hep.dataforge.output.OutputManager
|
||||||
import hep.dataforge.vis.common.VisualGroup
|
|
||||||
import hep.dataforge.vis.common.VisualObject
|
import hep.dataforge.vis.common.VisualObject
|
||||||
|
import hep.dataforge.vis.spatial.VisualGroup3D
|
||||||
import hep.dataforge.vis.spatial.render
|
import hep.dataforge.vis.spatial.render
|
||||||
import hep.dataforge.vis.spatial.three.ThreeOutput
|
import hep.dataforge.vis.spatial.three.ThreeOutput
|
||||||
import hep.dataforge.vis.spatial.three.ThreePlugin
|
import hep.dataforge.vis.spatial.three.ThreePlugin
|
||||||
@ -79,7 +79,7 @@ class ThreeDemoGrid(meta: Meta) : AbstractPlugin(meta), OutputManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ThreeDemoGrid.demo(name: String, title: String = name, block: VisualGroup.() -> Unit) {
|
fun ThreeDemoGrid.demo(name: String, title: String = name, block: VisualGroup3D.() -> Unit) {
|
||||||
val meta = buildMeta {
|
val meta = buildMeta {
|
||||||
"title" to title
|
"title" to title
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,9 @@ import info.laht.threekt.math.Color
|
|||||||
|
|
||||||
|
|
||||||
object Materials {
|
object Materials {
|
||||||
|
val DEFAULT_COLOR = Color(Colors.darkgreen)
|
||||||
val DEFAULT = MeshPhongMaterial().apply {
|
val DEFAULT = MeshPhongMaterial().apply {
|
||||||
this.color.set(Colors.darkgreen)
|
this.color.set(DEFAULT_COLOR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,19 +43,18 @@ fun MetaItem<*>.color(): Color {
|
|||||||
/**
|
/**
|
||||||
* Infer Three material based on meta item
|
* Infer Three material based on meta item
|
||||||
*/
|
*/
|
||||||
fun MetaItem<*>?.material(): Material {
|
fun Meta?.jsMaterial(): Material {
|
||||||
return when (this) {
|
return if(this == null){
|
||||||
null -> Materials.DEFAULT
|
Materials.DEFAULT
|
||||||
is MetaItem.ValueItem -> MeshBasicMaterial().apply {
|
} else
|
||||||
color = this@material.color()
|
//TODO add more oprions for material
|
||||||
}
|
MeshBasicMaterial().apply {
|
||||||
is MetaItem.NodeItem -> MeshBasicMaterial().apply {
|
color = get("color")?.color()?: Materials.DEFAULT_COLOR
|
||||||
(node["color"] ?: this@material).let { color = it.color() }
|
opacity = get("opacity")?.double ?: 1.0
|
||||||
opacity = node["opacity"]?.double ?: 1.0
|
transparent = get("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
|
side = 2
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,11 +4,12 @@ import hep.dataforge.vis.spatial.Cylinder
|
|||||||
import hep.dataforge.vis.spatial.detail
|
import hep.dataforge.vis.spatial.detail
|
||||||
import info.laht.threekt.core.BufferGeometry
|
import info.laht.threekt.core.BufferGeometry
|
||||||
import info.laht.threekt.geometries.CylinderBufferGeometry
|
import info.laht.threekt.geometries.CylinderBufferGeometry
|
||||||
|
import kotlin.math.PI
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
|
|
||||||
object ThreeCylinderFactory : MeshThreeFactory<Cylinder>(Cylinder::class) {
|
object ThreeCylinderFactory : MeshThreeFactory<Cylinder>(Cylinder::class) {
|
||||||
override fun buildGeometry(obj: Cylinder): BufferGeometry {
|
override fun buildGeometry(obj: Cylinder): BufferGeometry {
|
||||||
return obj.detail?.let {
|
val cylinder = obj.detail?.let {
|
||||||
val segments = it.toDouble().pow(0.5).toInt()
|
val segments = it.toDouble().pow(0.5).toInt()
|
||||||
CylinderBufferGeometry(
|
CylinderBufferGeometry(
|
||||||
radiusTop = obj.upperRadius,
|
radiusTop = obj.upperRadius,
|
||||||
@ -28,5 +29,6 @@ object ThreeCylinderFactory : MeshThreeFactory<Cylinder>(Cylinder::class) {
|
|||||||
thetaStart = obj.startAngle,
|
thetaStart = obj.startAngle,
|
||||||
thetaLength = obj.angle
|
thetaLength = obj.angle
|
||||||
)
|
)
|
||||||
|
return cylinder.rotateX(PI/2)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,9 +2,10 @@ package hep.dataforge.vis.spatial.three
|
|||||||
|
|
||||||
import hep.dataforge.meta.boolean
|
import hep.dataforge.meta.boolean
|
||||||
import hep.dataforge.meta.get
|
import hep.dataforge.meta.get
|
||||||
|
import hep.dataforge.meta.int
|
||||||
|
import hep.dataforge.meta.node
|
||||||
import hep.dataforge.names.startsWith
|
import hep.dataforge.names.startsWith
|
||||||
import hep.dataforge.provider.Type
|
import hep.dataforge.provider.Type
|
||||||
import hep.dataforge.vis.common.VisualObject
|
|
||||||
import hep.dataforge.vis.common.onChange
|
import hep.dataforge.vis.common.onChange
|
||||||
import hep.dataforge.vis.spatial.*
|
import hep.dataforge.vis.spatial.*
|
||||||
import hep.dataforge.vis.spatial.three.ThreeFactory.Companion.TYPE
|
import hep.dataforge.vis.spatial.three.ThreeFactory.Companion.TYPE
|
||||||
@ -18,13 +19,11 @@ import info.laht.threekt.objects.LineSegments
|
|||||||
import info.laht.threekt.objects.Mesh
|
import info.laht.threekt.objects.Mesh
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
internal val VisualObject.material get() = properties["material"].material()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder and updater for three.js object
|
* Builder and updater for three.js object
|
||||||
*/
|
*/
|
||||||
@Type(TYPE)
|
@Type(TYPE)
|
||||||
interface ThreeFactory<T : VisualObject> {
|
interface ThreeFactory<T : VisualObject3D> {
|
||||||
|
|
||||||
val type: KClass<out T>
|
val type: KClass<out T>
|
||||||
|
|
||||||
@ -33,46 +32,50 @@ interface ThreeFactory<T : VisualObject> {
|
|||||||
companion object {
|
companion object {
|
||||||
const val TYPE = "threeFactory"
|
const val TYPE = "threeFactory"
|
||||||
|
|
||||||
fun <T : VisualObject> buildMesh(obj: T, geometryBuilder: (T) -> BufferGeometry): Mesh {
|
fun <T : VisualObject3D> buildMesh(obj: T, geometryBuilder: (T) -> BufferGeometry): Mesh {
|
||||||
val geometry = geometryBuilder(obj)
|
val geometry = geometryBuilder(obj)
|
||||||
|
|
||||||
//JS sometimes tries to pass Geometry as BufferGeometry
|
//JS sometimes tries to pass Geometry as BufferGeometry
|
||||||
@Suppress("USELESS_IS_CHECK") if (geometry !is BufferGeometry) error("BufferGeometry expected")
|
@Suppress("USELESS_IS_CHECK") if (geometry !is BufferGeometry) error("BufferGeometry expected")
|
||||||
|
|
||||||
val mesh = Mesh(geometry, obj.material)
|
val mesh = Mesh(geometry, obj.material.jsMaterial())
|
||||||
|
|
||||||
//inherited edges definition, enabled by default
|
//inherited edges definition, enabled by default
|
||||||
if (obj.properties["edges.enabled"].boolean != false) {
|
if (obj.properties["edges.enabled"].boolean != false) {
|
||||||
val material = obj.properties["edges.material"]?.material() ?: Materials.DEFAULT
|
val material = obj.properties["edges.material"].node?.jsMaterial() ?: Materials.DEFAULT
|
||||||
mesh.add(LineSegments(EdgesGeometry(mesh.geometry as BufferGeometry), material))
|
mesh.add(LineSegments(EdgesGeometry(mesh.geometry as BufferGeometry), material))
|
||||||
}
|
}
|
||||||
|
|
||||||
//inherited wireframe definition, disabled by default
|
//inherited wireframe definition, disabled by default
|
||||||
if (obj.properties["wireframe.enabled"].boolean == true) {
|
if (obj.properties["wireframe.enabled"].boolean == true) {
|
||||||
val material = obj.properties["edges.material"]?.material() ?: Materials.DEFAULT
|
val material = obj.properties["wireframe.material"].node?.jsMaterial() ?: Materials.DEFAULT
|
||||||
mesh.add(LineSegments(WireframeGeometry(mesh.geometry as BufferGeometry), material))
|
mesh.add(LineSegments(WireframeGeometry(mesh.geometry as BufferGeometry), material))
|
||||||
}
|
}
|
||||||
|
|
||||||
//set position for meseh
|
//set position for mesh
|
||||||
mesh.updatePosition(obj)
|
mesh.updatePosition(obj)
|
||||||
|
|
||||||
|
obj.config["layer"].int?.let {
|
||||||
|
mesh.layers.set(it)
|
||||||
|
}
|
||||||
|
|
||||||
//add listener to object properties
|
//add listener to object properties
|
||||||
obj.onChange(this) { name, _, _ ->
|
obj.onChange(this) { name, _, _ ->
|
||||||
if (name.toString() == "material") {
|
if (name.startsWith(VisualObject3D.materialKey)) {
|
||||||
//updated material
|
//updated material
|
||||||
mesh.material = obj.material
|
mesh.material = obj.material.jsMaterial()
|
||||||
} else if (
|
} else if (
|
||||||
name.startsWith(PropertyNames3D.position) ||
|
name.startsWith(VisualObject3D.position) ||
|
||||||
name.startsWith(PropertyNames3D.rotation) ||
|
name.startsWith(VisualObject3D.rotation) ||
|
||||||
name.startsWith(PropertyNames3D.scale) ||
|
name.startsWith(VisualObject3D.scale) ||
|
||||||
name.toString() == "visible"
|
name == VisualObject3D.visibleKey
|
||||||
) {
|
) {
|
||||||
//update position of mesh using this object
|
//update position of mesh using this object
|
||||||
mesh.updatePosition(obj)
|
mesh.updatePosition(obj)
|
||||||
} else {
|
} else {
|
||||||
//full update
|
//full update
|
||||||
mesh.geometry = geometryBuilder(obj)
|
mesh.geometry = geometryBuilder(obj)
|
||||||
mesh.material = obj.material
|
mesh.material = obj.material.jsMaterial()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return mesh
|
return mesh
|
||||||
@ -83,17 +86,17 @@ interface ThreeFactory<T : VisualObject> {
|
|||||||
/**
|
/**
|
||||||
* Update position, rotation and visibility
|
* Update position, rotation and visibility
|
||||||
*/
|
*/
|
||||||
internal fun Object3D.updatePosition(obj: VisualObject) {
|
internal fun Object3D.updatePosition(obj: VisualObject3D) {
|
||||||
position.set(obj.x, obj.y, obj.z)
|
position.set(obj.x, obj.y, obj.z)
|
||||||
setRotationFromEuler(obj.euler)
|
setRotationFromEuler(obj.euler)
|
||||||
scale.set(obj.scaleX, obj.scaleY, obj.scaleZ)
|
scale.set(obj.scaleX, obj.scaleY, obj.scaleZ)
|
||||||
visible = obj.visible
|
visible = obj.visible ?: true
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unsafe invocation of a factory
|
* Unsafe invocation of a factory
|
||||||
*/
|
*/
|
||||||
operator fun <T : VisualObject> ThreeFactory<T>.invoke(obj: Any): Object3D {
|
operator fun <T : VisualObject3D> ThreeFactory<T>.invoke(obj: Any): Object3D {
|
||||||
if (type.isInstance(obj)) {
|
if (type.isInstance(obj)) {
|
||||||
return invoke(obj as T)
|
return invoke(obj as T)
|
||||||
} else {
|
} else {
|
||||||
@ -104,8 +107,7 @@ operator fun <T : VisualObject> ThreeFactory<T>.invoke(obj: Any): Object3D {
|
|||||||
/**
|
/**
|
||||||
* Basic geometry-based factory
|
* Basic geometry-based factory
|
||||||
*/
|
*/
|
||||||
abstract class MeshThreeFactory<T : VisualObject>(override val type: KClass<out T>) :
|
abstract class MeshThreeFactory<T : VisualObject3D>(override val type: KClass<out T>) : ThreeFactory<T> {
|
||||||
ThreeFactory<T> {
|
|
||||||
/**
|
/**
|
||||||
* Build a geometry for an object
|
* Build a geometry for an object
|
||||||
*/
|
*/
|
||||||
@ -114,8 +116,7 @@ abstract class MeshThreeFactory<T : VisualObject>(override val type: KClass<out
|
|||||||
|
|
||||||
override fun invoke(obj: T): Mesh {
|
override fun invoke(obj: T): Mesh {
|
||||||
//create mesh from geometry
|
//create mesh from geometry
|
||||||
val mesh = buildMesh(obj, ::buildGeometry)
|
return buildMesh<T>(obj) { buildGeometry(it) }
|
||||||
return mesh
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,8 +4,8 @@ import hep.dataforge.context.Context
|
|||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
import hep.dataforge.output.Output
|
import hep.dataforge.output.Output
|
||||||
import hep.dataforge.vis.common.Colors
|
import hep.dataforge.vis.common.Colors
|
||||||
import hep.dataforge.vis.common.VisualObject
|
|
||||||
import hep.dataforge.vis.hmr.require
|
import hep.dataforge.vis.hmr.require
|
||||||
|
import hep.dataforge.vis.spatial.VisualObject3D
|
||||||
import info.laht.threekt.WebGLRenderer
|
import info.laht.threekt.WebGLRenderer
|
||||||
import info.laht.threekt.helpers.AxesHelper
|
import info.laht.threekt.helpers.AxesHelper
|
||||||
import info.laht.threekt.lights.AmbientLight
|
import info.laht.threekt.lights.AmbientLight
|
||||||
@ -15,7 +15,7 @@ import kotlin.browser.window
|
|||||||
|
|
||||||
private val elementResizeEvent = require("element-resize-event")
|
private val elementResizeEvent = require("element-resize-event")
|
||||||
|
|
||||||
class ThreeOutput(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Output<VisualObject> {
|
class ThreeOutput(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Output<VisualObject3D> {
|
||||||
|
|
||||||
override val context: Context get() = three.context
|
override val context: Context get() = three.context
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ class ThreeOutput(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Output<V
|
|||||||
animate()
|
animate()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun render(obj: VisualObject, meta: Meta) {
|
override fun render(obj: VisualObject3D, meta: Meta) {
|
||||||
scene.add(three.buildObject3D(obj))
|
scene.add(three.buildObject3D(obj))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,6 @@ import hep.dataforge.context.PluginFactory
|
|||||||
import hep.dataforge.context.PluginTag
|
import hep.dataforge.context.PluginTag
|
||||||
import hep.dataforge.context.content
|
import hep.dataforge.context.content
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
import hep.dataforge.vis.common.VisualGroup
|
|
||||||
import hep.dataforge.vis.common.VisualObject
|
|
||||||
import hep.dataforge.vis.spatial.*
|
import hep.dataforge.vis.spatial.*
|
||||||
import info.laht.threekt.cameras.Camera
|
import info.laht.threekt.cameras.Camera
|
||||||
import info.laht.threekt.cameras.PerspectiveCamera
|
import info.laht.threekt.cameras.PerspectiveCamera
|
||||||
@ -20,7 +18,7 @@ import kotlin.reflect.KClass
|
|||||||
class ThreePlugin : AbstractPlugin() {
|
class ThreePlugin : AbstractPlugin() {
|
||||||
override val tag: PluginTag get() = Companion.tag
|
override val tag: PluginTag get() = Companion.tag
|
||||||
|
|
||||||
private val objectFactories = HashMap<KClass<out VisualObject>, ThreeFactory<*>>()
|
private val objectFactories = HashMap<KClass<out VisualObject3D>, ThreeFactory<*>>()
|
||||||
private val compositeFactory = ThreeCompositeFactory(this)
|
private val compositeFactory = ThreeCompositeFactory(this)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -31,15 +29,16 @@ class ThreePlugin : AbstractPlugin() {
|
|||||||
objectFactories[Cylinder::class] = ThreeCylinderFactory
|
objectFactories[Cylinder::class] = ThreeCylinderFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findObjectFactory(type: KClass<out VisualObject>): ThreeFactory<*>? {
|
private fun findObjectFactory(type: KClass<out VisualObject3D>): ThreeFactory<*>? {
|
||||||
return objectFactories[type]
|
return objectFactories[type]
|
||||||
?: context.content<ThreeFactory<*>>(ThreeFactory.TYPE).values.find { it.type == type }
|
?: context.content<ThreeFactory<*>>(ThreeFactory.TYPE).values.find { it.type == type }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun buildObject3D(obj: VisualObject): Object3D {
|
fun buildObject3D(obj: VisualObject3D): Object3D {
|
||||||
return when (obj) {
|
return when (obj) {
|
||||||
is VisualGroup -> Group(obj.mapNotNull {
|
is VisualGroup3D -> Group(obj.mapNotNull {
|
||||||
try {
|
try {
|
||||||
|
it as VisualObject3D
|
||||||
buildObject3D(it)
|
buildObject3D(it)
|
||||||
} catch (ex: Throwable) {
|
} catch (ex: Throwable) {
|
||||||
console.error(ex)
|
console.error(ex)
|
||||||
|
@ -4,11 +4,7 @@ import hep.dataforge.meta.MetaItem
|
|||||||
import hep.dataforge.meta.float
|
import hep.dataforge.meta.float
|
||||||
import hep.dataforge.meta.get
|
import hep.dataforge.meta.get
|
||||||
import hep.dataforge.meta.node
|
import hep.dataforge.meta.node
|
||||||
import hep.dataforge.vis.common.VisualObject
|
import hep.dataforge.vis.spatial.*
|
||||||
import hep.dataforge.vis.spatial.rotationOrder
|
|
||||||
import hep.dataforge.vis.spatial.rotationX
|
|
||||||
import hep.dataforge.vis.spatial.rotationY
|
|
||||||
import hep.dataforge.vis.spatial.rotationZ
|
|
||||||
import info.laht.threekt.core.BufferGeometry
|
import info.laht.threekt.core.BufferGeometry
|
||||||
import info.laht.threekt.core.Geometry
|
import info.laht.threekt.core.Geometry
|
||||||
import info.laht.threekt.core.Object3D
|
import info.laht.threekt.core.Object3D
|
||||||
@ -25,7 +21,7 @@ fun Group(children: Collection<Object3D>) = info.laht.threekt.objects.Group().ap
|
|||||||
children.forEach { this.add(it) }
|
children.forEach { this.add(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
val VisualObject.euler get() = Euler(rotationX, rotationY, rotationZ, rotationOrder.name)
|
val VisualObject3D.euler get() = Euler(rotationX, rotationY, rotationZ, rotationOrder.name)
|
||||||
|
|
||||||
val MetaItem<*>.vector get() = Vector3(node["x"].float ?: 0f, node["y"].float ?: 0f, node["z"].float ?: 0f)
|
val MetaItem<*>.vector get() = Vector3(node["x"].float ?: 0f, node["y"].float ?: 0f, node["z"].float ?: 0f)
|
||||||
|
|
||||||
|
@ -2,14 +2,12 @@ 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>) :
|
||||||
VisualLeaf(parent, meta), Shape {
|
VisualLeaf3D(parent, meta), Shape {
|
||||||
|
|
||||||
//TODO add helper for color configuration
|
//TODO add helper for color configuration
|
||||||
|
|
||||||
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {
|
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {
|
||||||
val dx = xSize.toDouble() / 2
|
val dx = xSize.toDouble() / 2
|
||||||
val dy = ySize.toDouble() / 2
|
val dy = ySize.toDouble() / 2
|
||||||
@ -39,12 +37,11 @@ class Box(parent: VisualObject?, val xSize: Number, val ySize: Number, val zSize
|
|||||||
//fun VisualGroup.box(meta: Meta = EmptyMeta, action: Box.() -> Unit = {}) =
|
//fun VisualGroup.box(meta: Meta = EmptyMeta, action: Box.() -> Unit = {}) =
|
||||||
// Box(this, meta).apply(action).also { add(it) }
|
// Box(this, meta).apply(action).also { add(it) }
|
||||||
|
|
||||||
fun VisualGroup.box(
|
inline fun VisualGroup.box(
|
||||||
xSize: Number,
|
xSize: Number,
|
||||||
ySize: Number,
|
ySize: Number,
|
||||||
zSize: Number,
|
zSize: Number,
|
||||||
name: String? = null,
|
name: String? = null,
|
||||||
vararg meta: Meta,
|
vararg meta: Meta,
|
||||||
action: Box.() -> Unit = {}
|
action: Box.() -> Unit = {}
|
||||||
) =
|
) = Box(this, xSize, ySize, zSize, meta).apply(action).also { set(name, it) }
|
||||||
Box(this, xSize, ySize, zSize, meta).apply(action).also { set(name, it) }
|
|
@ -1,10 +1,9 @@
|
|||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.meta.seal
|
import hep.dataforge.meta.isEmpty
|
||||||
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 {
|
||||||
@ -15,33 +14,38 @@ enum class CompositeType {
|
|||||||
|
|
||||||
open class Composite(
|
open class Composite(
|
||||||
parent: VisualObject?,
|
parent: VisualObject?,
|
||||||
val first: VisualObject,
|
val first: VisualObject3D,
|
||||||
val second: VisualObject,
|
val second: VisualObject3D,
|
||||||
val type: CompositeType = CompositeType.UNION,
|
val type: CompositeType = CompositeType.UNION,
|
||||||
meta: Array<out Meta>
|
meta: Array<out Meta>
|
||||||
) : VisualLeaf(parent, meta)
|
) : VisualLeaf3D(parent, meta)
|
||||||
|
|
||||||
fun VisualGroup.composite(
|
fun VisualGroup.composite(
|
||||||
type: CompositeType,
|
type: CompositeType,
|
||||||
name: String? = null,
|
name: String? = null,
|
||||||
vararg meta: Meta,
|
vararg meta: Meta,
|
||||||
builder: VisualGroup.() -> Unit
|
builder: VisualGroup3D.() -> Unit
|
||||||
): Composite {
|
): Composite {
|
||||||
val group = VisualGroup().apply(builder)
|
val group = VisualGroup3D().apply(builder)
|
||||||
val children = group.toList()
|
val children = group.filterIsInstance<VisualObject3D>()
|
||||||
if (children.size != 2) error("Composite requires exactly two children")
|
if (children.size != 2) error("Composite requires exactly two children")
|
||||||
val groupMeta = group.properties.seal()
|
|
||||||
return Composite(this, children[0], children[1], type, meta).also {
|
return Composite(this, children[0], children[1], type, meta).also {
|
||||||
it.config.update(groupMeta)
|
if( !group.config.isEmpty()) {
|
||||||
|
it.config.update(group.config)
|
||||||
|
}
|
||||||
|
it.position = group.position
|
||||||
|
it.rotation = group.rotation
|
||||||
|
it.scale = group.scale
|
||||||
|
it.material = group.material
|
||||||
set(name, it)
|
set(name, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun VisualGroup.union(name: String? = null, vararg meta: Meta, builder: VisualGroup.() -> Unit) =
|
fun VisualGroup3D.union(name: String? = null, vararg meta: Meta, builder: VisualGroup3D.() -> Unit) =
|
||||||
composite(CompositeType.UNION, name, *meta, builder = builder)
|
composite(CompositeType.UNION, name, *meta, builder = builder)
|
||||||
|
|
||||||
fun VisualGroup.subtract(name: String? = null, vararg meta: Meta, builder: VisualGroup.() -> Unit) =
|
fun VisualGroup3D.subtract(name: String? = null, vararg meta: Meta, builder: VisualGroup3D.() -> Unit) =
|
||||||
composite(CompositeType.SUBTRACT, name, *meta, builder = builder)
|
composite(CompositeType.SUBTRACT, name, *meta, builder = builder)
|
||||||
|
|
||||||
fun VisualGroup.intersect(name: String? = null, vararg meta: Meta, builder: VisualGroup.() -> Unit) =
|
fun VisualGroup3D.intersect(name: String? = null, vararg meta: Meta, builder: VisualGroup3D.() -> Unit) =
|
||||||
composite(CompositeType.INTERSECT, name, *meta, builder = builder)
|
composite(CompositeType.INTERSECT, name, *meta, builder = builder)
|
@ -2,10 +2,9 @@ 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 Convex(parent: VisualObject?, val points: List<Point3D>, meta: Array<out Meta>) : VisualLeaf(parent, meta) {
|
class Convex(parent: VisualObject?, val points: List<Point3D>, meta: Array<out Meta>) : VisualLeaf3D(parent, meta) {
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -2,7 +2,6 @@ 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
|
||||||
import hep.dataforge.vis.common.number
|
import hep.dataforge.vis.common.number
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
@ -10,11 +9,9 @@ import kotlin.math.PI
|
|||||||
/**
|
/**
|
||||||
* A cylinder or cut cone segment
|
* A cylinder or cut cone segment
|
||||||
*/
|
*/
|
||||||
class Cylinder(parent: VisualObject?, radius: Number, height: Number, meta: Array<out Meta>) :
|
class Cylinder(parent: VisualObject?, var radius: Number, var height: Number, meta: Array<out Meta>) :
|
||||||
VisualLeaf(parent, meta) {
|
VisualLeaf3D(parent, meta) {
|
||||||
var radius by number(radius)
|
|
||||||
var upperRadius by number(radius)
|
var upperRadius by number(radius)
|
||||||
var height by number(height)
|
|
||||||
var startAngle by number(0.0)
|
var startAngle by number(0.0)
|
||||||
var angle by number(2 * PI)
|
var angle by number(2 * PI)
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ 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
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
import kotlin.math.cos
|
import kotlin.math.cos
|
||||||
@ -33,7 +32,7 @@ fun Shape2DBuilder.polygon(vertices: Int, radius: Number) {
|
|||||||
|
|
||||||
data class Layer(var x: Number, var y: Number, var z: Number, var scale: Number)
|
data class Layer(var x: Number, var y: Number, var z: Number, var scale: Number)
|
||||||
|
|
||||||
class Extruded(parent: VisualObject?, meta: Array<out Meta>) : VisualLeaf(parent, meta), Shape {
|
class Extruded(parent: VisualObject?, meta: Array<out Meta>) : VisualLeaf3D(parent, meta), Shape {
|
||||||
|
|
||||||
var shape: List<Point2D> = ArrayList()
|
var shape: List<Point2D> = ArrayList()
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
import hep.dataforge.vis.common.VisualObject
|
|
||||||
|
|
||||||
data class Point2D(val x: Number, val y: Number) : MetaRepr {
|
data class Point2D(val x: Number, val y: Number) : MetaRepr {
|
||||||
override fun toMeta(): Meta = buildMeta {
|
override fun toMeta(): Meta = buildMeta {
|
||||||
@ -60,6 +59,6 @@ fun GeometryBuilder<*>.face4(
|
|||||||
face(vertex1, vertex3, vertex4, normal, meta)
|
face(vertex1, vertex3, vertex4, normal, meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Shape : VisualObject {
|
interface Shape : VisualObject3D {
|
||||||
fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>)
|
fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>)
|
||||||
}
|
}
|
@ -2,17 +2,15 @@ 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
|
||||||
import hep.dataforge.vis.common.double
|
import hep.dataforge.vis.common.number
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
|
|
||||||
class Sphere(parent: VisualObject?, meta: Array<out Meta>) : VisualLeaf(parent, meta) {
|
class Sphere(parent: VisualObject?, var radius: Number, meta: Array<out Meta>) : VisualLeaf3D(parent, meta) {
|
||||||
var radius by double(50.0)
|
var phiStart by number(0.0)
|
||||||
var phiStart by double(0.0)
|
var phi by number(2 * PI)
|
||||||
var phi by double(2 * PI)
|
var thetaStart by number(0.0)
|
||||||
var thetaStart by double(0.0)
|
var theta by number(PI)
|
||||||
var theta by double(PI)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun VisualGroup.sphere(
|
fun VisualGroup.sphere(
|
||||||
@ -22,8 +20,7 @@ fun VisualGroup.sphere(
|
|||||||
name: String? = null,
|
name: String? = null,
|
||||||
vararg meta: Meta,
|
vararg meta: Meta,
|
||||||
action: Sphere.() -> Unit = {}
|
action: Sphere.() -> Unit = {}
|
||||||
) = Sphere(this, meta).apply(action).apply {
|
) = Sphere(this, radius, meta).apply(action).apply {
|
||||||
this.radius = radius.toDouble()
|
|
||||||
this.phi = phi.toDouble()
|
this.phi = phi.toDouble()
|
||||||
this.theta = theta.toDouble()
|
this.theta = theta.toDouble()
|
||||||
}.also { set(name, it) }
|
}.also { set(name, it) }
|
@ -1,22 +1,32 @@
|
|||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
|
import hep.dataforge.names.Name
|
||||||
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
|
||||||
|
import hep.dataforge.vis.spatial.VisualObject3D.Companion.detailKey
|
||||||
|
import hep.dataforge.vis.spatial.VisualObject3D.Companion.materialKey
|
||||||
|
import hep.dataforge.vis.spatial.VisualObject3D.Companion.visibleKey
|
||||||
|
|
||||||
fun VisualGroup.group(key: String? = null, vararg meta: Meta, action: VisualGroup.() -> Unit = {}): VisualGroup =
|
data class Value3(var x: Float = 0f, var y: Float = 0f, var z: Float = 0f)
|
||||||
VisualGroup(this, meta).apply(action).also { set(key, it) }
|
|
||||||
|
|
||||||
|
interface VisualObject3D : VisualObject {
|
||||||
|
var position: Value3
|
||||||
|
var rotation: Value3
|
||||||
|
var scale: Value3
|
||||||
|
|
||||||
fun Output<VisualObject>.render(meta: Meta = EmptyMeta, action: VisualGroup.() -> Unit) =
|
fun setProperty(name: Name, value: Any?)
|
||||||
render(VisualGroup().apply(action), meta)
|
fun getProperty(name: Name, inherit: Boolean = true): MetaItem<*>?
|
||||||
|
|
||||||
//TODO replace properties by containers?
|
companion object {
|
||||||
|
val materialKey = "material".asName()
|
||||||
|
val visibleKey = "visible".asName()
|
||||||
|
val detailKey = "detail".asName()
|
||||||
|
|
||||||
object PropertyNames3D {
|
|
||||||
val x = "x".asName()
|
val x = "x".asName()
|
||||||
val y = "y".asName()
|
val y = "y".asName()
|
||||||
val z = "z".asName()
|
val z = "z".asName()
|
||||||
@ -41,78 +51,65 @@ object PropertyNames3D {
|
|||||||
val yScale = scale + y
|
val yScale = scale + y
|
||||||
val zScale = scale + z
|
val zScale = scale + z
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open class VisualLeaf3D(parent: VisualObject?, tagRefs: Array<out Meta>) : VisualLeaf(parent, tagRefs), VisualObject3D {
|
||||||
|
override var position: Value3 = Value3()
|
||||||
|
override var rotation: Value3 = Value3()
|
||||||
|
override var scale: Value3 = Value3(1f, 1f, 1f)
|
||||||
|
|
||||||
|
private var _config: Config? = null
|
||||||
|
override val config: Config get() = _config ?: Config().also { _config = it }
|
||||||
|
|
||||||
|
override fun setProperty(name: Name, value: Any?) {
|
||||||
|
config[name] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {
|
||||||
|
return if (inherit) {
|
||||||
|
config[name] ?: (parent as? VisualObject3D)?.getProperty(name, inherit) ?: parent?.properties[name]
|
||||||
|
} else {
|
||||||
|
_config?.get(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class VisualGroup3D(
|
||||||
|
parent: VisualObject? = null,
|
||||||
|
tagRefs: Array<out Meta> = emptyArray()
|
||||||
|
) : VisualGroup(parent, tagRefs), VisualObject3D {
|
||||||
|
|
||||||
|
override var position: Value3 = Value3()
|
||||||
|
override var rotation: Value3 = Value3()
|
||||||
|
override var scale: Value3 = Value3(1f, 1f, 1f)
|
||||||
|
|
||||||
|
private var _config: Config? = null
|
||||||
|
override val config: Config get() = _config ?: Config().also { _config = it }
|
||||||
|
|
||||||
|
override fun setProperty(name: Name, value: Any?) {
|
||||||
|
config[name] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {
|
||||||
|
return if (inherit) {
|
||||||
|
config[name] ?: (parent as? VisualObject3D)?.getProperty(name, inherit) ?: parent?.properties[name]
|
||||||
|
} else {
|
||||||
|
_config?.get(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun VisualGroup.group(key: String? = null, vararg meta: Meta, action: VisualGroup3D.() -> Unit = {}): VisualGroup3D =
|
||||||
|
VisualGroup3D(this, meta).apply(action).also { set(key, it) }
|
||||||
|
|
||||||
|
|
||||||
|
fun Output<VisualObject>.render(meta: Meta = EmptyMeta, action: VisualGroup3D.() -> Unit) =
|
||||||
|
render(VisualGroup3D().apply(action), meta)
|
||||||
|
|
||||||
|
|
||||||
// Common properties
|
// Common properties
|
||||||
|
|
||||||
/**
|
|
||||||
* Visibility property. Inherited from parent
|
|
||||||
*/
|
|
||||||
var VisualObject.visible
|
|
||||||
get() = properties["visible"].boolean ?: true
|
|
||||||
set(value) {
|
|
||||||
config["visible"] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3D Object position
|
|
||||||
|
|
||||||
/**
|
|
||||||
* x position property relative to parent. Not inherited
|
|
||||||
*/
|
|
||||||
var VisualObject.x
|
|
||||||
get() = config[PropertyNames3D.xPos].number ?: 0.0
|
|
||||||
set(value) {
|
|
||||||
config[PropertyNames3D.xPos] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* y position property. Not inherited
|
|
||||||
*/
|
|
||||||
var VisualObject.y
|
|
||||||
get() = config[PropertyNames3D.yPos].number ?: 0.0
|
|
||||||
set(value) {
|
|
||||||
config[PropertyNames3D.yPos] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* z position property. Not inherited
|
|
||||||
*/
|
|
||||||
var VisualObject.z
|
|
||||||
get() = config[PropertyNames3D.zPos].number ?: 0.0
|
|
||||||
set(value) {
|
|
||||||
config[PropertyNames3D.zPos] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3D Object rotation
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* x rotation relative to parent. Not inherited
|
|
||||||
*/
|
|
||||||
var VisualObject.rotationX
|
|
||||||
get() = config[PropertyNames3D.xRotation].number ?: 0.0
|
|
||||||
set(value) {
|
|
||||||
config[PropertyNames3D.xRotation] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* y rotation relative to parent. Not inherited
|
|
||||||
*/
|
|
||||||
var VisualObject.rotationY
|
|
||||||
get() = config[PropertyNames3D.yRotation].number ?: 0.0
|
|
||||||
set(value) {
|
|
||||||
config[PropertyNames3D.yRotation] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* z rotation relative to parent. Not inherited
|
|
||||||
*/
|
|
||||||
var VisualObject.rotationZ
|
|
||||||
get() = config[PropertyNames3D.zRotation].number ?: 0.0
|
|
||||||
set(value) {
|
|
||||||
config[PropertyNames3D.zRotation] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class RotationOrder {
|
enum class RotationOrder {
|
||||||
XYZ,
|
XYZ,
|
||||||
@ -124,52 +121,40 @@ enum class RotationOrder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rotation order. Not inherited
|
* Rotation order
|
||||||
*/
|
*/
|
||||||
var VisualObject.rotationOrder: RotationOrder
|
var VisualObject3D.rotationOrder: RotationOrder
|
||||||
get() = config[PropertyNames3D.rotationOrder].enum<RotationOrder>() ?: RotationOrder.XYZ
|
get() = getProperty(VisualObject3D.rotationOrder).enum<RotationOrder>() ?: RotationOrder.XYZ
|
||||||
set(value) {
|
set(value) = setProperty(VisualObject3D.rotationOrder, value)
|
||||||
config[PropertyNames3D.rotationOrder] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3D object scale
|
|
||||||
|
|
||||||
/**
|
|
||||||
* X scale. Not inherited
|
|
||||||
*/
|
|
||||||
var VisualObject.scaleX
|
|
||||||
get() = config[PropertyNames3D.xScale].number ?: 1.0
|
|
||||||
set(value) {
|
|
||||||
config[PropertyNames3D.xScale] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Y scale. Not inherited
|
|
||||||
*/
|
|
||||||
var VisualObject.scaleY
|
|
||||||
get() = config[PropertyNames3D.yScale].number ?: 1.0
|
|
||||||
set(value) {
|
|
||||||
config[PropertyNames3D.yScale] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Z scale. Not inherited
|
|
||||||
*/
|
|
||||||
var VisualObject.scaleZ
|
|
||||||
get() = config[PropertyNames3D.zScale].number ?: 1.0
|
|
||||||
set(value) {
|
|
||||||
config[PropertyNames3D.zScale] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO add inherited scale
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Preferred number of polygons for displaying the object. If not defined, uses shape or renderer default
|
* Preferred number of polygons for displaying the object. If not defined, uses shape or renderer default
|
||||||
*/
|
*/
|
||||||
var VisualObject.detail: Int?
|
var VisualObject3D.detail: Int?
|
||||||
get() = properties["detail"]?.int
|
get() = getProperty(detailKey).int
|
||||||
set(value) {
|
set(value) = setProperty(detailKey, value)
|
||||||
config["detail"] = value
|
|
||||||
|
var VisualObject3D.material: Meta?
|
||||||
|
get() = getProperty(materialKey).node
|
||||||
|
set(value) = setProperty(materialKey, value)
|
||||||
|
|
||||||
|
var VisualObject3D.visible: Boolean?
|
||||||
|
get() = getProperty(visibleKey).boolean
|
||||||
|
set(value) = setProperty(visibleKey, value)
|
||||||
|
|
||||||
|
fun VisualObject3D.color(rgb: Int) {
|
||||||
|
material = buildMeta { "color" to rgb }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun VisualObject3D.material(builder: MetaBuilder.() -> Unit) {
|
||||||
|
material = buildMeta(builder)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun VisualObject3D.color(r: Int, g: Int, b: Int) = material {
|
||||||
|
"red" to r
|
||||||
|
"green" to g
|
||||||
|
"blue" to b
|
||||||
}
|
}
|
||||||
|
|
||||||
object World {
|
object World {
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
|
var VisualObject3D.x: Number
|
||||||
|
get() = position.x
|
||||||
|
set(value) {position.x = value.toFloat()}
|
||||||
|
|
||||||
|
var VisualObject3D.y: Number
|
||||||
|
get() = position.y
|
||||||
|
set(value) {position.y = value.toFloat()}
|
||||||
|
|
||||||
|
var VisualObject3D.z: Number
|
||||||
|
get() = position.z
|
||||||
|
set(value) {position.z = value.toFloat()}
|
||||||
|
|
||||||
|
var VisualObject3D.rotationX: Number
|
||||||
|
get() = rotation.x
|
||||||
|
set(value) {rotation.x = value.toFloat()}
|
||||||
|
|
||||||
|
var VisualObject3D.rotationY: Number
|
||||||
|
get() = rotation.y
|
||||||
|
set(value) {rotation.y = value.toFloat()}
|
||||||
|
|
||||||
|
var VisualObject3D.rotationZ: Number
|
||||||
|
get() = rotation.z
|
||||||
|
set(value) {rotation.z = value.toFloat()}
|
||||||
|
|
||||||
|
var VisualObject3D.scaleX: Number
|
||||||
|
get() = scale.x
|
||||||
|
set(value) {scale.x = value.toFloat()}
|
||||||
|
|
||||||
|
var VisualObject3D.scaleY: Number
|
||||||
|
get() = scale.y
|
||||||
|
set(value) {scale.y = value.toFloat()}
|
||||||
|
|
||||||
|
var VisualObject3D.scaleZ: Number
|
||||||
|
get() = scale.z
|
||||||
|
set(value) {scale.z = value.toFloat()}
|
@ -18,7 +18,7 @@ class GroupTest {
|
|||||||
rotationY = PI / 4
|
rotationY = PI / 4
|
||||||
}
|
}
|
||||||
box(100, 100, 100)
|
box(100, 100, 100)
|
||||||
color {
|
material {
|
||||||
"color" to Colors.lightgreen
|
"color" to Colors.lightgreen
|
||||||
"opacity" to 0.3
|
"opacity" to 0.3
|
||||||
}
|
}
|
||||||
@ -31,7 +31,7 @@ class GroupTest {
|
|||||||
}
|
}
|
||||||
box(100, 100, 100)
|
box(100, 100, 100)
|
||||||
y = 300
|
y = 300
|
||||||
color(Colors.red)
|
material(Colors.red)
|
||||||
}
|
}
|
||||||
subtract{
|
subtract{
|
||||||
box(100, 100, 100) {
|
box(100, 100, 100) {
|
||||||
@ -41,7 +41,7 @@ class GroupTest {
|
|||||||
}
|
}
|
||||||
box(100, 100, 100)
|
box(100, 100, 100)
|
||||||
y = -300
|
y = -300
|
||||||
color(Colors.blue)
|
material(Colors.blue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user