GDML demo renders something
This commit is contained in:
parent
687393c243
commit
d3500c3a57
@ -4,6 +4,7 @@ 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
|
||||
@ -181,13 +182,14 @@ object Colors {
|
||||
const val yellowgreen = 0x9ACD32
|
||||
}
|
||||
|
||||
private val material = "material".toName()
|
||||
|
||||
fun VisualObject.color(rgb: Int) {
|
||||
this.properties["material"] = rgb
|
||||
this.config[material] = rgb
|
||||
}
|
||||
|
||||
fun VisualObject.color(meta: Meta) {
|
||||
this.properties["material"] = meta
|
||||
this.config[material] = meta
|
||||
}
|
||||
|
||||
fun VisualObject.color(builder: MetaBuilder.() -> Unit) {
|
||||
|
@ -1,29 +1,41 @@
|
||||
package hep.dataforge.vis.common
|
||||
|
||||
import hep.dataforge.meta.EmptyMeta
|
||||
import hep.dataforge.meta.Config
|
||||
import hep.dataforge.meta.Laminate
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.Styled
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.toName
|
||||
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
|
||||
|
||||
/**
|
||||
* A display group which allows both named and unnamed children
|
||||
*/
|
||||
class VisualGroup(
|
||||
override val parent: VisualObject? = null, meta: Meta = EmptyMeta
|
||||
override val parent: VisualObject? = null, tagRefs: Array<out Meta> = emptyArray()
|
||||
) : VisualObject, Iterable<VisualObject>, Provider {
|
||||
|
||||
private val namedChildren = HashMap<Name, VisualObject>()
|
||||
private val unnamedChildren = ArrayList<VisualObject>()
|
||||
|
||||
override val defaultTarget: String get() = VisualObject.TYPE
|
||||
override val properties: Styled = Styled(meta)
|
||||
override val config = Config()
|
||||
|
||||
override val properties: Laminate by lazy { combineProperties(parent, config, tagRefs) }
|
||||
|
||||
override fun iterator(): Iterator<VisualObject> = (namedChildren.values + unnamedChildren).iterator()
|
||||
|
||||
override fun provideTop(target: String): Map<Name, Any> {
|
||||
return when(target){
|
||||
return when (target) {
|
||||
VisualObject.TYPE -> namedChildren
|
||||
else -> emptyMap()
|
||||
}
|
||||
@ -49,13 +61,12 @@ class VisualGroup(
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Add named or unnamed child to the group. If key is [null] the child is considered unnamed. Both key and value are not
|
||||
* allowed to be null in the same time. If name is present and [child] is null, the appropriate element is removed.
|
||||
*/
|
||||
operator fun set(key: String?, child: VisualObject?) {
|
||||
if(key == null){
|
||||
|
||||
} else {
|
||||
val name = key.toName()
|
||||
operator fun set(name: Name?, child: VisualObject?) {
|
||||
when {
|
||||
name != null -> {
|
||||
if (child == null) {
|
||||
namedChildren.remove(name)
|
||||
} else {
|
||||
@ -63,7 +74,12 @@ class VisualGroup(
|
||||
}
|
||||
listeners.forEach { it.callback(name, child) }
|
||||
}
|
||||
child != null -> unnamedChildren.add(child)
|
||||
else -> error("Both key and child element are empty")
|
||||
}
|
||||
}
|
||||
|
||||
operator fun set(key: String?, child: VisualObject?) = set(key?.asName(), child)
|
||||
|
||||
/**
|
||||
* Append unnamed child
|
||||
|
@ -2,24 +2,34 @@ package hep.dataforge.vis.common
|
||||
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.provider.Type
|
||||
import hep.dataforge.vis.common.VisualObject.Companion.META_KEY
|
||||
import hep.dataforge.vis.common.VisualObject.Companion.TAGS_KEY
|
||||
import hep.dataforge.vis.common.VisualObject.Companion.TYPE
|
||||
|
||||
private fun Laminate.withTop(meta: Meta): Laminate = Laminate(listOf(meta) + layers)
|
||||
private fun Laminate.withBottom(meta: Meta): Laminate = Laminate(layers + meta)
|
||||
|
||||
/**
|
||||
* A root type for display hierarchy
|
||||
*/
|
||||
@Type(TYPE)
|
||||
interface VisualObject : MetaRepr {
|
||||
interface VisualObject : MetaRepr, Configurable {
|
||||
|
||||
/**
|
||||
* The parent object of this one. If null, this one is a root.
|
||||
*/
|
||||
val parent: VisualObject?
|
||||
|
||||
val properties: Styled
|
||||
/**
|
||||
* Individual properties configurator
|
||||
*/
|
||||
override val config: Config
|
||||
|
||||
/**
|
||||
* All properties including inherited ones
|
||||
*/
|
||||
val properties: Laminate
|
||||
|
||||
override fun toMeta(): Meta = buildMeta {
|
||||
"type" to this::class
|
||||
@ -37,18 +47,11 @@ interface VisualObject : MetaRepr {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the property of this display object of parent's if not found
|
||||
*/
|
||||
tailrec fun VisualObject.getProperty(name: Name): MetaItem<*>? = properties[name] ?: parent?.getProperty(name)
|
||||
|
||||
fun VisualObject.getProperty(name: String): MetaItem<*>? = getProperty(name.toName())
|
||||
|
||||
/**
|
||||
* A change listener for [VisualObject] configuration.
|
||||
*/
|
||||
fun VisualObject.onChange(owner: Any?, action: (Name, before: MetaItem<*>?, after: MetaItem<*>?) -> Unit) {
|
||||
properties.onChange(owner, action)
|
||||
config.onChange(owner, action)
|
||||
parent?.onChange(owner, action)
|
||||
}
|
||||
|
||||
@ -56,7 +59,7 @@ fun VisualObject.onChange(owner: Any?, action: (Name, before: MetaItem<*>?, afte
|
||||
* Remove all meta listeners with matching owners
|
||||
*/
|
||||
fun VisualObject.removeChangeListener(owner: Any?) {
|
||||
properties.removeListener(owner)
|
||||
config.removeListener(owner)
|
||||
parent?.removeChangeListener(owner)
|
||||
}
|
||||
|
||||
@ -64,18 +67,28 @@ fun VisualObject.removeChangeListener(owner: Any?) {
|
||||
/**
|
||||
* Additional meta not relevant to display
|
||||
*/
|
||||
val VisualObject.meta: Meta get() = properties[META_KEY]?.node ?: EmptyMeta
|
||||
val VisualObject.meta: Meta get() = config[META_KEY]?.node ?: EmptyMeta
|
||||
|
||||
val VisualObject.tags: List<String> get() = properties[TAGS_KEY].stringList
|
||||
val VisualObject.tags: List<String> get() = config[TAGS_KEY].stringList
|
||||
|
||||
/**
|
||||
* Basic [VisualObject] leaf element
|
||||
*/
|
||||
open class DisplayLeaf(
|
||||
override val parent: VisualObject?,
|
||||
meta: Meta = EmptyMeta
|
||||
open class VisualLeaf(
|
||||
final override val parent: VisualObject?,
|
||||
tagRefs: Array<out Meta>
|
||||
) : VisualObject {
|
||||
final override val properties = Styled(meta)
|
||||
final override val config = Config()
|
||||
|
||||
override val properties: Laminate by lazy { combineProperties(parent, config, tagRefs) }
|
||||
}
|
||||
|
||||
internal fun combineProperties(parent: VisualObject?, config: Config, tagRefs: Array<out Meta>): Laminate {
|
||||
val list = ArrayList<Meta>(tagRefs.size + 2)
|
||||
list += config
|
||||
list.addAll(tagRefs)
|
||||
parent?.properties?.let { list.add(it) }
|
||||
return Laminate(list)
|
||||
}
|
||||
|
||||
///**
|
||||
|
@ -2,13 +2,16 @@ package hep.dataforge.vis.common
|
||||
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.names.NameToken
|
||||
import hep.dataforge.names.asName
|
||||
import hep.dataforge.values.Value
|
||||
import kotlin.jvm.JvmName
|
||||
import kotlin.properties.ReadOnlyProperty
|
||||
import kotlin.properties.ReadWriteProperty
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
fun String.asName() = NameToken(this).asName()
|
||||
|
||||
/**
|
||||
* A delegate for display object properties
|
||||
*/
|
||||
@ -18,17 +21,17 @@ class DisplayObjectDelegate(
|
||||
val inherited: Boolean
|
||||
) : ReadWriteProperty<VisualObject, MetaItem<*>?> {
|
||||
override fun getValue(thisRef: VisualObject, property: KProperty<*>): MetaItem<*>? {
|
||||
val name = key ?: property.name.toName()
|
||||
val name = key ?: property.name.asName()
|
||||
return if (inherited) {
|
||||
thisRef.getProperty(name)
|
||||
} else {
|
||||
thisRef.properties[name]
|
||||
} else {
|
||||
thisRef.config[name]
|
||||
} ?: default
|
||||
}
|
||||
|
||||
override fun setValue(thisRef: VisualObject, property: KProperty<*>, value: MetaItem<*>?) {
|
||||
val name = key ?: property.name.toName()
|
||||
thisRef.properties[name] = value
|
||||
val name = key ?: property.name.asName()
|
||||
thisRef.config[name] = value
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,70 +46,71 @@ class DisplayObjectDelegateWrapper<T>(
|
||||
//private var cachedName: Name? = null
|
||||
|
||||
override fun getValue(thisRef: VisualObject, property: KProperty<*>): T {
|
||||
val name = key ?: property.name.toName()
|
||||
val name = key ?: property.name.asName()
|
||||
return if (inherited) {
|
||||
read(thisRef.getProperty(name))
|
||||
} else {
|
||||
read(thisRef.properties[name])
|
||||
} else {
|
||||
read(thisRef.config[name])
|
||||
} ?: default
|
||||
}
|
||||
|
||||
override fun setValue(thisRef: VisualObject, property: KProperty<*>, value: T) {
|
||||
val name = key ?: property.name.toName()
|
||||
thisRef.properties[name] = value
|
||||
val name = key ?: property.name.asName()
|
||||
thisRef.config[name] = value
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun VisualObject.value(default: Value? = null, key: String? = null, inherited: Boolean = false) =
|
||||
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.value }
|
||||
DisplayObjectDelegateWrapper(key?.asName(), default, inherited) { it.value }
|
||||
|
||||
fun VisualObject.string(default: String? = null, key: String? = null, inherited: Boolean = false) =
|
||||
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.string }
|
||||
DisplayObjectDelegateWrapper(key?.asName(), default, inherited) { it.string }
|
||||
|
||||
fun VisualObject.boolean(default: Boolean? = null, key: String? = null, inherited: Boolean = false) =
|
||||
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.boolean }
|
||||
DisplayObjectDelegateWrapper(key?.asName(), default, inherited) { it.boolean }
|
||||
|
||||
fun VisualObject.number(default: Number? = null, key: String? = null, inherited: Boolean = false) =
|
||||
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.number }
|
||||
DisplayObjectDelegateWrapper(key?.asName(), default, inherited) { it.number }
|
||||
|
||||
fun VisualObject.double(default: Double? = null, key: String? = null, inherited: Boolean = false) =
|
||||
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.double }
|
||||
DisplayObjectDelegateWrapper(key?.asName(), default, inherited) { it.double }
|
||||
|
||||
fun VisualObject.int(default: Int? = null, key: String? = null, inherited: Boolean = false) =
|
||||
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.int }
|
||||
DisplayObjectDelegateWrapper(key?.asName(), default, inherited) { it.int }
|
||||
|
||||
|
||||
fun VisualObject.node(key: String? = null, inherited: Boolean = true) =
|
||||
DisplayObjectDelegateWrapper(key?.toName(), null, inherited) { it.node }
|
||||
DisplayObjectDelegateWrapper(key?.asName(), null, inherited) { it.node }
|
||||
|
||||
fun VisualObject.item(key: String? = null, inherited: Boolean = true) =
|
||||
DisplayObjectDelegateWrapper(key?.toName(), null, inherited) { it }
|
||||
DisplayObjectDelegateWrapper(key?.asName(), null, inherited) { it }
|
||||
|
||||
//fun <T : Configurable> Configurable.spec(spec: Specification<T>, key: String? = null) = ChildConfigDelegate<T>(key) { spec.wrap(this) }
|
||||
|
||||
@JvmName("safeString")
|
||||
fun VisualObject.string(default: String, key: String? = null, inherited: Boolean = false) =
|
||||
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.string }
|
||||
DisplayObjectDelegateWrapper(key?.asName(), default, inherited) { it.string }
|
||||
|
||||
@JvmName("safeBoolean")
|
||||
fun VisualObject.boolean(default: Boolean, key: String? = null, inherited: Boolean = false) =
|
||||
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.boolean }
|
||||
DisplayObjectDelegateWrapper(key?.asName(), default, inherited) { it.boolean }
|
||||
|
||||
@JvmName("safeNumber")
|
||||
fun VisualObject.number(default: Number, key: String? = null, inherited: Boolean = false) =
|
||||
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.number }
|
||||
DisplayObjectDelegateWrapper(key?.asName(), default, inherited) { it.number }
|
||||
|
||||
@JvmName("safeDouble")
|
||||
fun VisualObject.double(default: Double, key: String? = null, inherited: Boolean = false) =
|
||||
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.double }
|
||||
DisplayObjectDelegateWrapper(key?.asName(), default, inherited) { it.double }
|
||||
|
||||
@JvmName("safeInt")
|
||||
fun VisualObject.int(default: Int, key: String? = null, inherited: Boolean = false) =
|
||||
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.int }
|
||||
DisplayObjectDelegateWrapper(key?.asName(), default, inherited) { it.int }
|
||||
|
||||
|
||||
inline fun <reified E : Enum<E>> VisualObject.enum(default: E, key: String? = null, inherited: Boolean = false) =
|
||||
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { item -> item.string?.let { enumValueOf<E>(it) } }
|
||||
DisplayObjectDelegateWrapper(key?.let{ NameToken(it).asName()}, default, inherited) { item -> item.string?.let { enumValueOf<E>(it) } }
|
||||
|
||||
//merge properties
|
||||
|
||||
@ -116,11 +120,11 @@ fun <T> VisualObject.merge(
|
||||
): ReadOnlyProperty<VisualObject, T> {
|
||||
return object : ReadOnlyProperty<VisualObject, T> {
|
||||
override fun getValue(thisRef: VisualObject, property: KProperty<*>): T {
|
||||
val name = key?.toName() ?: property.name.toName()
|
||||
val name = key?.asName() ?: property.name.asName()
|
||||
val sequence = sequence<MetaItem<*>> {
|
||||
var thisObj: VisualObject? = thisRef
|
||||
while (thisObj != null) {
|
||||
thisObj.properties[name]?.let { yield(it) }
|
||||
thisObj.config[name]?.let { yield(it) }
|
||||
thisObj = thisObj.parent
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ import hep.dataforge.meta.*
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
import hep.dataforge.vis.common.getProperty
|
||||
import hep.dataforge.vis.common.onChange
|
||||
import javafx.beans.binding.ObjectBinding
|
||||
import tornadofx.*
|
||||
@ -24,7 +23,7 @@ class DisplayObjectFXListener(val obj: VisualObject) {
|
||||
operator fun get(key: Name): ObjectBinding<MetaItem<*>?> {
|
||||
return binndings.getOrPut(key) {
|
||||
object : ObjectBinding<MetaItem<*>?>() {
|
||||
override fun computeValue(): MetaItem<*>? = obj.getProperty(key)
|
||||
override fun computeValue(): MetaItem<*>? = obj.properties[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,21 +27,14 @@ class RendererDemoView : View() {
|
||||
|
||||
renderer.render {
|
||||
group = group {
|
||||
box {
|
||||
xSize = 100.0
|
||||
ySize = 100.0
|
||||
zSize = 100.0
|
||||
}
|
||||
box {
|
||||
box(100,100,100)
|
||||
box(100,100,100) {
|
||||
x = 110.0
|
||||
xSize = 100.0
|
||||
ySize = 100.0
|
||||
zSize = 100.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var color by group.properties.number(1530).int
|
||||
var color by group.config.number(1530).int
|
||||
|
||||
GlobalScope.launch {
|
||||
val random = Random(111)
|
||||
|
@ -11,28 +11,57 @@ import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
||||
|
||||
private fun VisualObject.applyPosition(pos: GDMLPosition): VisualObject = apply {
|
||||
private fun VisualObject.withPosition(
|
||||
pos: GDMLPosition? = null,
|
||||
rotation: GDMLRotation? = null,
|
||||
scale: GDMLScale? = null
|
||||
): VisualObject =
|
||||
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 {
|
||||
x = pos.x
|
||||
y = pos.y
|
||||
z = pos.z
|
||||
//TODO convert units if needed
|
||||
}
|
||||
|
||||
private fun VisualObject.applyRotation(rotation: GDMLRotation): VisualObject = apply {
|
||||
}
|
||||
rotation?.let {
|
||||
rotationX = rotation.x
|
||||
rotationY = rotation.y
|
||||
rotationZ = rotation.z
|
||||
}
|
||||
//}
|
||||
scale?.let {
|
||||
scaleX = scale.x
|
||||
scaleY = scale.y
|
||||
scaleZ = scale.z
|
||||
}
|
||||
//TODO convert units if needed
|
||||
}
|
||||
}
|
||||
|
||||
private fun VisualGroup.addSolid(root: GDML, solid: GDMLSolid, block: VisualObject.() -> Unit = {}): VisualObject {
|
||||
|
||||
private fun VisualGroup.addSolid(
|
||||
root: GDML,
|
||||
solid: GDMLSolid,
|
||||
name: String? = null,
|
||||
block: VisualObject.() -> Unit = {}
|
||||
): VisualObject {
|
||||
return when (solid) {
|
||||
is GDMLBox -> box(solid.x, solid.y, solid.z)
|
||||
is GDMLTube -> cylinder(solid.rmax, solid.z) {
|
||||
is GDMLBox -> box(solid.x, solid.y, solid.z, name)
|
||||
is GDMLTube -> cylinder(solid.rmax, solid.z, name) {
|
||||
startAngle = solid.startphi
|
||||
angle = solid.deltaphi
|
||||
}
|
||||
is GDMLXtru -> extrude {
|
||||
is GDMLXtru -> extrude(name) {
|
||||
shape {
|
||||
solid.vertices.forEach {
|
||||
point(it.x, it.y)
|
||||
@ -46,6 +75,7 @@ private fun VisualGroup.addSolid(root: GDML, solid: GDMLSolid, block: VisualObje
|
||||
//Add solid with modified scale
|
||||
val innerSolid = solid.solidref.resolve(root)
|
||||
?: error("Solid with tag ${solid.solidref.ref} for scaled solid ${solid.name} not defined")
|
||||
|
||||
addSolid(root, innerSolid) {
|
||||
block()
|
||||
scaleX = scaleX.toDouble() * solid.scale.x.toDouble()
|
||||
@ -53,12 +83,12 @@ private fun VisualGroup.addSolid(root: GDML, solid: GDMLSolid, block: VisualObje
|
||||
scaleZ = scaleZ.toDouble() * solid.scale.z.toDouble()
|
||||
}
|
||||
}
|
||||
is GDMLSphere -> sphere(solid.rmax, solid.deltaphi, solid.deltatheta) {
|
||||
is GDMLSphere -> sphere(solid.rmax, solid.deltaphi, solid.deltatheta, name) {
|
||||
phiStart = solid.startphi.toDouble()
|
||||
thetaStart = solid.starttheta.toDouble()
|
||||
}
|
||||
is GDMLOrb -> sphere(solid.r)
|
||||
is GDMLPolyhedra -> extrude {
|
||||
is GDMLOrb -> sphere(solid.r, name = name)
|
||||
is GDMLPolyhedra -> extrude(name) {
|
||||
//getting the radius of first
|
||||
require(solid.planes.size > 1) { "The polyhedron geometry requires at least two planes" }
|
||||
val baseRadius = solid.planes.first().rmax.toDouble()
|
||||
@ -81,14 +111,13 @@ private fun VisualGroup.addSolid(root: GDML, solid: GDMLSolid, block: VisualObje
|
||||
is GDMLSubtraction -> CompositeType.SUBTRACT
|
||||
is GDMLIntersection -> CompositeType.INTERSECT
|
||||
}
|
||||
return composite(type) {
|
||||
|
||||
return composite(type, name) {
|
||||
addSolid(root, first) {
|
||||
solid.resolveFirstPosition(root)?.let { applyPosition(it) }
|
||||
solid.resolveFirstRotation(root)?.let { applyRotation(it) }
|
||||
withPosition(solid.resolveFirstPosition(root), solid.resolveFirstRotation(root), null)
|
||||
}
|
||||
addSolid(root, second)
|
||||
solid.resolvePosition(root)?.let { applyPosition(it) }
|
||||
solid.resolveRotation(root)?.let { applyRotation(it) }
|
||||
withPosition(solid.resolvePosition(root), solid.resolveRotation(root), null)
|
||||
}
|
||||
}
|
||||
}.apply(block)
|
||||
@ -97,30 +126,42 @@ private fun VisualGroup.addSolid(root: GDML, solid: GDMLSolid, block: VisualObje
|
||||
private fun VisualGroup.addVolume(
|
||||
root: GDML,
|
||||
group: GDMLGroup,
|
||||
position: GDMLPosition? = null,
|
||||
rotation: GDMLRotation? = null,
|
||||
scale: GDMLScale? = null,
|
||||
resolveColor: GDMLMaterial.() -> Meta
|
||||
): VisualGroup {
|
||||
) {
|
||||
|
||||
group(group.name) {
|
||||
withPosition(position, rotation, scale)
|
||||
|
||||
if (group is GDMLVolume) {
|
||||
val solid = group.solidref.resolve(root)
|
||||
?: error("Solid with tag ${group.solidref.ref} for volume ${group.name} not defined")
|
||||
val material = group.materialref.resolve(root)
|
||||
?: error("Material with tag ${group.materialref.ref} for volume ${group.name} not defined")
|
||||
|
||||
addSolid(root, solid) {
|
||||
addSolid(root, solid, solid.name) {
|
||||
color(material.resolveColor())
|
||||
}
|
||||
//TODO render placements
|
||||
}
|
||||
|
||||
group.physVolumes.forEach {
|
||||
val volume: GDMLGroup =
|
||||
it.volumeref.resolve(root) ?: error("Volume with ref ${it.volumeref.ref} could not be resolved")
|
||||
addVolume(root, volume, resolveColor).apply {
|
||||
it.resolvePosition(root)?.let { pos -> applyPosition(pos) }
|
||||
it.resolveRotation(root)?.let { rot -> applyRotation(rot) }
|
||||
group.physVolumes.forEach { physVolume ->
|
||||
val volume: GDMLGroup = physVolume.volumeref.resolve(root)
|
||||
?: error("Volume with ref ${physVolume.volumeref.ref} could not be resolved")
|
||||
|
||||
addVolume(
|
||||
root,
|
||||
volume,
|
||||
physVolume.resolvePosition(root),
|
||||
physVolume.resolveRotation(root),
|
||||
physVolume.resolveScale(root),
|
||||
resolveColor
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
|
||||
|
@ -17,7 +17,7 @@ import scientifik.gdml.GDML
|
||||
import kotlin.browser.document
|
||||
import kotlin.dom.clear
|
||||
|
||||
class GDMLDemoApp : ApplicationBase() {
|
||||
private class GDMLDemoApp : ApplicationBase() {
|
||||
|
||||
|
||||
/**
|
||||
@ -56,13 +56,13 @@ class GDMLDemoApp : ApplicationBase() {
|
||||
|
||||
val context = Global.context("demo") {}
|
||||
val three = context.plugins.load(ThreePlugin)
|
||||
val canvas = document.getElementById("canvas") ?: error("Element with id canvas not found on page")
|
||||
canvas.clear()
|
||||
val output = three.output(canvas)
|
||||
//val url = URL("https://drive.google.com/open?id=1w5e7fILMN83JGgB8WANJUYm8OW2s0WVO")
|
||||
|
||||
val canvas = document.getElementById("canvas") ?: error("Element with id canvas not found on page")
|
||||
|
||||
val action: suspend (String) -> Unit = {
|
||||
canvas.clear()
|
||||
val output = three.output(canvas)
|
||||
val gdml = GDML.format.parse(GDML.serializer(), it)
|
||||
val visual = gdml.toVisual()
|
||||
output.render(visual)
|
||||
|
@ -13,7 +13,7 @@ class BMNTest {
|
||||
|
||||
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()){
|
||||
val stream = if (file.exists()) {
|
||||
file.inputStream()
|
||||
} else {
|
||||
url.openStream()
|
||||
@ -21,7 +21,7 @@ class BMNTest {
|
||||
|
||||
val xmlReader = StAXReader(stream, "UTF-8")
|
||||
val xml = GDML.format.parse(GDML.serializer(), xmlReader)
|
||||
repeat(5) {
|
||||
repeat(20) {
|
||||
xml.toVisual()
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ import kotlin.math.sin
|
||||
import kotlin.random.Random
|
||||
|
||||
|
||||
class ThreeDemoApp : ApplicationBase() {
|
||||
private class ThreeDemoApp : ApplicationBase() {
|
||||
|
||||
override val stateKeys: List<String> = emptyList()
|
||||
|
||||
@ -39,18 +39,12 @@ class ThreeDemoApp : ApplicationBase() {
|
||||
|
||||
demo("dynamic", "Dynamic properties") {
|
||||
val group = group {
|
||||
box {
|
||||
box(100, 100, 100) {
|
||||
z = 110.0
|
||||
xSize = 100.0
|
||||
ySize = 100.0
|
||||
zSize = 100.0
|
||||
}
|
||||
box {
|
||||
box(100, 100, 100) {
|
||||
visible = false
|
||||
x = 110.0
|
||||
xSize = 100.0
|
||||
ySize = 100.0
|
||||
zSize = 100.0
|
||||
//override color for this cube
|
||||
color(1530)
|
||||
|
||||
@ -63,7 +57,7 @@ class ThreeDemoApp : ApplicationBase() {
|
||||
}
|
||||
}
|
||||
|
||||
var material by group.properties.number(1530).int
|
||||
var material by group.config.number(1530).int
|
||||
|
||||
GlobalScope.launch {
|
||||
val random = Random(111)
|
||||
@ -100,34 +94,28 @@ class ThreeDemoApp : ApplicationBase() {
|
||||
demo("CSG", "CSG operations") {
|
||||
composite(CompositeType.UNION) {
|
||||
box(100, 100, 100) {
|
||||
z = 100
|
||||
rotationX = PI / 4
|
||||
rotationY = PI / 4
|
||||
z = 50
|
||||
}
|
||||
box(100, 100, 100)
|
||||
sphere(50)
|
||||
color {
|
||||
"color" to Colors.lightgreen
|
||||
"opacity" to 0.3
|
||||
}
|
||||
}
|
||||
composite(CompositeType.INTERSECT) {
|
||||
box(100, 100, 100) {
|
||||
z = 100
|
||||
rotationX = PI / 4
|
||||
rotationY = PI / 4
|
||||
}
|
||||
box(100, 100, 100)
|
||||
y = 300
|
||||
box(100, 100, 100) {
|
||||
z = 50
|
||||
}
|
||||
sphere(50)
|
||||
color(Colors.red)
|
||||
}
|
||||
composite(CompositeType.SUBTRACT) {
|
||||
box(100, 100, 100) {
|
||||
z = 100
|
||||
rotationX = PI / 4
|
||||
rotationY = PI / 4
|
||||
}
|
||||
box(100, 100, 100)
|
||||
y = -300
|
||||
box(100, 100, 100) {
|
||||
z = 50
|
||||
}
|
||||
sphere(50)
|
||||
color(Colors.blue)
|
||||
}
|
||||
}
|
||||
|
@ -11,9 +11,9 @@ object ThreeCylinderFactory : MeshThreeFactory<Cylinder>(Cylinder::class) {
|
||||
return obj.detail?.let {
|
||||
val segments = it.toDouble().pow(0.5).toInt()
|
||||
CylinderBufferGeometry(
|
||||
radiusTop = obj.upperRadius!!,
|
||||
radiusBottom = obj.radius!!,
|
||||
height = obj.height!!,
|
||||
radiusTop = obj.upperRadius,
|
||||
radiusBottom = obj.radius,
|
||||
height = obj.height,
|
||||
radialSegments = segments,
|
||||
heightSegments = segments,
|
||||
openEnded = false,
|
||||
@ -21,9 +21,9 @@ object ThreeCylinderFactory : MeshThreeFactory<Cylinder>(Cylinder::class) {
|
||||
thetaLength = obj.angle
|
||||
)
|
||||
} ?: CylinderBufferGeometry(
|
||||
radiusTop = obj.upperRadius!!,
|
||||
radiusBottom = obj.radius!!,
|
||||
height = obj.height!!,
|
||||
radiusTop = obj.upperRadius,
|
||||
radiusBottom = obj.radius,
|
||||
height = obj.height,
|
||||
openEnded = false,
|
||||
thetaStart = obj.startAngle,
|
||||
thetaLength = obj.angle
|
||||
|
@ -1,11 +1,10 @@
|
||||
package hep.dataforge.vis.spatial.three
|
||||
|
||||
import hep.dataforge.meta.boolean
|
||||
import hep.dataforge.meta.get
|
||||
import hep.dataforge.names.startsWith
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.provider.Type
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
import hep.dataforge.vis.common.getProperty
|
||||
import hep.dataforge.vis.common.onChange
|
||||
import hep.dataforge.vis.spatial.*
|
||||
import hep.dataforge.vis.spatial.three.ThreeFactory.Companion.TYPE
|
||||
@ -19,7 +18,7 @@ import info.laht.threekt.objects.LineSegments
|
||||
import info.laht.threekt.objects.Mesh
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
internal val VisualObject.material get() = getProperty("material").material()
|
||||
internal val VisualObject.material get() = properties["material"].material()
|
||||
|
||||
/**
|
||||
* Builder and updater for three.js object
|
||||
@ -43,14 +42,14 @@ interface ThreeFactory<T : VisualObject> {
|
||||
val mesh = Mesh(geometry, obj.material)
|
||||
|
||||
//inherited edges definition, enabled by default
|
||||
if (obj.getProperty("edges.enabled").boolean != false) {
|
||||
val material = obj.getProperty("edges.material")?.material() ?: Materials.DEFAULT
|
||||
if (obj.properties["edges.enabled"].boolean != false) {
|
||||
val material = obj.properties["edges.material"]?.material() ?: Materials.DEFAULT
|
||||
mesh.add(LineSegments(EdgesGeometry(mesh.geometry as BufferGeometry), material))
|
||||
}
|
||||
|
||||
//inherited wireframe definition, disabled by default
|
||||
if (obj.getProperty("wireframe.enabled").boolean == true) {
|
||||
val material = obj.getProperty("edges.material")?.material() ?: Materials.DEFAULT
|
||||
if (obj.properties["wireframe.enabled"].boolean == true) {
|
||||
val material = obj.properties["edges.material"]?.material() ?: Materials.DEFAULT
|
||||
mesh.add(LineSegments(WireframeGeometry(mesh.geometry as BufferGeometry), material))
|
||||
}
|
||||
|
||||
@ -63,9 +62,9 @@ interface ThreeFactory<T : VisualObject> {
|
||||
//updated material
|
||||
mesh.material = obj.material
|
||||
} else if (
|
||||
name.startsWith("pos".toName()) ||
|
||||
name.startsWith("scale".toName()) ||
|
||||
name.startsWith("rotation".toName()) ||
|
||||
name.startsWith(PropertyNames3D.position) ||
|
||||
name.startsWith(PropertyNames3D.rotation) ||
|
||||
name.startsWith(PropertyNames3D.scale) ||
|
||||
name.toString() == "visible"
|
||||
) {
|
||||
//update position of mesh using this object
|
||||
|
@ -38,7 +38,14 @@ class ThreePlugin : AbstractPlugin() {
|
||||
|
||||
fun buildObject3D(obj: VisualObject): Object3D {
|
||||
return when (obj) {
|
||||
is VisualGroup -> Group(obj.map { buildObject3D(it) }).apply {
|
||||
is VisualGroup -> Group(obj.mapNotNull {
|
||||
try {
|
||||
buildObject3D(it)
|
||||
} catch (ex: Throwable){
|
||||
logger.error(ex){"Failed to render $it"}
|
||||
null
|
||||
}
|
||||
}).apply {
|
||||
updatePosition(obj)
|
||||
}
|
||||
is Composite -> compositeFactory(obj)
|
||||
|
@ -1,23 +1,18 @@
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.meta.EmptyMeta
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.vis.common.VisualGroup
|
||||
import hep.dataforge.vis.common.DisplayLeaf
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
import hep.dataforge.vis.common.double
|
||||
|
||||
class Box(parent: VisualObject?, meta: Meta) : DisplayLeaf(parent, meta), Shape {
|
||||
var xSize by double(100.0)
|
||||
var ySize by double(100.0)
|
||||
var zSize by double(100.0)
|
||||
class Box(parent: VisualObject?, val xSize: Number, val ySize: Number, val zSize: Number, meta: Array<out Meta>) :
|
||||
VisualObject3D(parent, meta), Shape {
|
||||
|
||||
//TODO add helper for color configuration
|
||||
|
||||
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {
|
||||
val dx = xSize / 2
|
||||
val dy = ySize / 2
|
||||
val dz = zSize / 2
|
||||
val dx = xSize.toDouble() / 2
|
||||
val dy = ySize.toDouble() / 2
|
||||
val dz = zSize.toDouble() / 2
|
||||
val node1 = Point3D(-dx, -dy, -dz)
|
||||
val node2 = Point3D(dx, -dy, -dz)
|
||||
val node3 = Point3D(dx, dy, -dz)
|
||||
@ -40,12 +35,15 @@ class Box(parent: VisualObject?, meta: Meta) : DisplayLeaf(parent, meta), Shape
|
||||
}
|
||||
}
|
||||
|
||||
fun VisualGroup.box(meta: Meta = EmptyMeta, action: Box.() -> Unit = {}) =
|
||||
Box(this, meta).apply(action).also { add(it) }
|
||||
//fun VisualGroup.box(meta: Meta = EmptyMeta, action: Box.() -> Unit = {}) =
|
||||
// Box(this, meta).apply(action).also { add(it) }
|
||||
|
||||
fun VisualGroup.box(xSize: Number, ySize: Number, zSize: Number, meta: Meta = EmptyMeta, action: Box.() -> Unit = {}) =
|
||||
Box(this, meta).apply(action).apply{
|
||||
this.xSize = xSize.toDouble()
|
||||
this.ySize = ySize.toDouble()
|
||||
this.zSize = zSize.toDouble()
|
||||
}.also { add(it) }
|
||||
fun VisualGroup.box(
|
||||
xSize: Number,
|
||||
ySize: Number,
|
||||
zSize: Number,
|
||||
name: String? = null,
|
||||
vararg meta: Meta,
|
||||
action: Box.() -> Unit = {}
|
||||
) =
|
||||
Box(this, xSize, ySize, zSize, meta).apply(action).also { set(name, it) }
|
@ -1,9 +1,8 @@
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.meta.EmptyMeta
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.seal
|
||||
import hep.dataforge.vis.common.DisplayLeaf
|
||||
import hep.dataforge.meta.update
|
||||
import hep.dataforge.vis.common.VisualGroup
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
|
||||
@ -13,28 +12,35 @@ enum class CompositeType {
|
||||
SUBTRACT
|
||||
}
|
||||
|
||||
class Composite(
|
||||
open class Composite(
|
||||
parent: VisualObject?,
|
||||
val first: VisualObject,
|
||||
val second: VisualObject,
|
||||
val type: CompositeType = CompositeType.UNION,
|
||||
meta: Meta = EmptyMeta
|
||||
) : DisplayLeaf(parent, meta)
|
||||
meta: Array<out Meta>
|
||||
) : VisualObject3D(parent, meta)
|
||||
|
||||
fun VisualGroup.composite(type: CompositeType, builder: VisualGroup.() -> Unit): Composite {
|
||||
fun VisualGroup.composite(
|
||||
type: CompositeType,
|
||||
name: String? = null,
|
||||
vararg meta: Meta,
|
||||
builder: VisualGroup.() -> Unit
|
||||
): Composite {
|
||||
val group = VisualGroup().apply(builder)
|
||||
val children = group.toList()
|
||||
if (children.size != 2) error("Composite requires exactly two children")
|
||||
return Composite(this, children[0], children[1], type, group.properties.seal()).also {
|
||||
this.add(it)
|
||||
val groupMeta = group.properties.seal()
|
||||
return Composite(this, children[0], children[1], type, meta).also {
|
||||
it.config.update(groupMeta)
|
||||
set(name, it)
|
||||
}
|
||||
}
|
||||
|
||||
fun VisualGroup.union(builder: VisualGroup.() -> Unit) =
|
||||
composite(CompositeType.UNION,builder)
|
||||
fun VisualGroup.union(name: String? = null, vararg meta: Meta, builder: VisualGroup.() -> Unit) =
|
||||
composite(CompositeType.UNION, name, *meta, builder = builder)
|
||||
|
||||
fun VisualGroup.subtract(builder: VisualGroup.() -> Unit) =
|
||||
composite(CompositeType.SUBTRACT,builder)
|
||||
fun VisualGroup.subtract(name: String? = null, vararg meta: Meta, builder: VisualGroup.() -> Unit) =
|
||||
composite(CompositeType.SUBTRACT, name, *meta, builder = builder)
|
||||
|
||||
fun VisualGroup.intersect(builder: VisualGroup.() -> Unit) =
|
||||
composite(CompositeType.INTERSECT,builder)
|
||||
fun VisualGroup.intersect(name: String? = null, vararg meta: Meta, builder: VisualGroup.() -> Unit) =
|
||||
composite(CompositeType.INTERSECT, name, *meta, builder = builder)
|
@ -1,26 +1,19 @@
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.vis.common.VisualGroup
|
||||
import hep.dataforge.vis.common.DisplayLeaf
|
||||
import hep.dataforge.vis.common.VisualLeaf
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
|
||||
class Convex(parent: VisualObject?, meta: Meta) : DisplayLeaf(parent, meta) {
|
||||
class Convex(parent: VisualObject?, val points: List<Point3D>, meta: Array<out Meta>) : VisualLeaf(parent, meta) {
|
||||
|
||||
val points = points(properties["points"] ?: error("Vertices not defined"))
|
||||
|
||||
companion object {
|
||||
const val TYPE = "geometry.3d.convex"
|
||||
|
||||
fun points(item: MetaItem<*>): List<Point3D> {
|
||||
return item.node?.getAll("point")?.map { (_, value) ->
|
||||
Point3D.from(value.node?: error("Point definition is not a node"))
|
||||
} ?: emptyList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun VisualGroup.convex(meta: Meta = EmptyMeta, action: ConvexBuilder.() -> Unit = {}) =
|
||||
fun VisualGroup.convex(vararg meta: Meta, action: ConvexBuilder.() -> Unit = {}) =
|
||||
ConvexBuilder().apply(action).build(this, meta).also { add(it) }
|
||||
|
||||
class ConvexBuilder {
|
||||
@ -30,13 +23,7 @@ class ConvexBuilder {
|
||||
points.add(Point3D(x, y, z))
|
||||
}
|
||||
|
||||
fun build(parent: VisualObject?, meta: Meta): Convex {
|
||||
val points = buildMeta {
|
||||
points.forEachIndexed { index, value ->
|
||||
"points.point[$index]" to value.toMeta()
|
||||
}
|
||||
}.seal()
|
||||
|
||||
return Convex(parent, points)
|
||||
fun build(parent: VisualObject?, meta: Array<out Meta>): Convex {
|
||||
return Convex(parent, points, meta)
|
||||
}
|
||||
}
|
@ -1,9 +1,8 @@
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.meta.EmptyMeta
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.vis.common.DisplayLeaf
|
||||
import hep.dataforge.vis.common.VisualGroup
|
||||
import hep.dataforge.vis.common.VisualLeaf
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
import hep.dataforge.vis.common.number
|
||||
import kotlin.math.PI
|
||||
@ -11,18 +10,23 @@ import kotlin.math.PI
|
||||
/**
|
||||
* A cylinder or cut cone segment
|
||||
*/
|
||||
class Cylinder(parent: VisualObject?, meta: Meta) : DisplayLeaf(parent, meta) {
|
||||
var radius by number()
|
||||
var upperRadius by number(default = radius)
|
||||
var height by number()
|
||||
class Cylinder(parent: VisualObject?, radius: Number, height: Number, meta: Array<out Meta>) :
|
||||
VisualLeaf(parent, meta) {
|
||||
var radius by number(radius)
|
||||
var upperRadius by number(radius)
|
||||
var height by number(height)
|
||||
var startAngle by number(0.0)
|
||||
var angle by number(2 * PI)
|
||||
}
|
||||
|
||||
fun VisualGroup.cylinder(r: Number, height: Number, meta: Meta = EmptyMeta, block: Cylinder.() -> Unit = {}): Cylinder {
|
||||
val cylinder = Cylinder(this, meta)
|
||||
cylinder.radius = r
|
||||
cylinder.height = height
|
||||
fun VisualGroup.cylinder(
|
||||
r: Number,
|
||||
height: Number,
|
||||
name: String? = null,
|
||||
vararg meta: Meta,
|
||||
block: Cylinder.() -> Unit = {}
|
||||
): Cylinder {
|
||||
val cylinder = Cylinder(this, r, height, meta)
|
||||
cylinder.apply(block)
|
||||
return cylinder.also { add(it) }
|
||||
return cylinder.also { set(name, it) }
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.vis.common.DisplayLeaf
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.vis.common.VisualGroup
|
||||
import hep.dataforge.vis.common.VisualLeaf
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.cos
|
||||
@ -18,7 +18,7 @@ class Shape2DBuilder {
|
||||
list.add(Point2D(x, y))
|
||||
}
|
||||
|
||||
infix fun Number.to(y:Number) = point(this, y)
|
||||
infix fun Number.to(y: Number) = point(this, y)
|
||||
|
||||
fun build(): Shape2D = list
|
||||
}
|
||||
@ -31,45 +31,22 @@ fun Shape2DBuilder.polygon(vertices: Int, radius: Number) {
|
||||
}
|
||||
}
|
||||
|
||||
class Layer(override val config: Config) : Specific {
|
||||
var z by number(0.0)
|
||||
var x by number(0.0)
|
||||
var y by number(0.0)
|
||||
var scale by number(1.0)
|
||||
data class Layer(var x: Number, var y: Number, var z: Number, var scale: Number)
|
||||
|
||||
companion object : Specification<Layer> {
|
||||
override fun wrap(config: Config): Layer = Layer(config)
|
||||
}
|
||||
}
|
||||
class Extruded(parent: VisualObject?, meta: Array<out Meta>) : VisualLeaf(parent, meta), Shape {
|
||||
|
||||
//class Layer(val z: Number, val x: Number = 0.0, val y: Number = 0.0, val scale: Number = 1.0)
|
||||
|
||||
class Extruded(parent: VisualObject?, meta: Meta) : DisplayLeaf(parent, meta), Shape {
|
||||
|
||||
val shape
|
||||
get() = properties.getAll("shape.point").map { (_, value) ->
|
||||
Point2D.from(value.node ?: error("Point definition is not a node"))
|
||||
}
|
||||
var shape: List<Point2D> = ArrayList()
|
||||
|
||||
fun shape(block: Shape2DBuilder.() -> Unit) {
|
||||
val points = Shape2DBuilder().apply(block).build().map { it.toMeta() }
|
||||
properties["shape.point"] = points
|
||||
this.shape = Shape2DBuilder().apply(block).build()
|
||||
//TODO send invalidation signal
|
||||
}
|
||||
|
||||
val layers
|
||||
get() = properties.getAll("layer").values.map {
|
||||
Layer.wrap(it.node ?: error("layer item is not a node"))
|
||||
}
|
||||
val layers: MutableList<Layer> = ArrayList()
|
||||
|
||||
fun layer(z: Number, x: Number = 0.0, y: Number = 0.0, scale: Number = 1.0): Layer {
|
||||
val layer = Layer.build {
|
||||
this.x = x
|
||||
this.y = y
|
||||
this.z = z
|
||||
this.scale = scale
|
||||
}
|
||||
properties.append("layer", layer)
|
||||
return layer
|
||||
fun layer(z: Number, x: Number = 0.0, y: Number = 0.0, scale: Number = 1.0) {
|
||||
layers.add(Layer(x,y,z,scale))
|
||||
//TODO send invalidation signal
|
||||
}
|
||||
|
||||
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {
|
||||
@ -121,5 +98,5 @@ class Extruded(parent: VisualObject?, meta: Meta) : DisplayLeaf(parent, meta), S
|
||||
}
|
||||
}
|
||||
|
||||
fun VisualGroup.extrude(meta: Meta = EmptyMeta, action: Extruded.() -> Unit = {}) =
|
||||
Extruded(this, meta).apply(action).also { add(it) }
|
||||
fun VisualGroup.extrude(name: String? = null, vararg meta: Meta, action: Extruded.() -> Unit = {}) =
|
||||
Extruded(this, meta).apply(action).also { set(name, it) }
|
@ -1,14 +1,13 @@
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.meta.EmptyMeta
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.vis.common.VisualGroup
|
||||
import hep.dataforge.vis.common.DisplayLeaf
|
||||
import hep.dataforge.vis.common.VisualLeaf
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
import hep.dataforge.vis.common.double
|
||||
import kotlin.math.PI
|
||||
|
||||
class Sphere(parent: VisualObject?, meta: Meta) : DisplayLeaf(parent, meta) {
|
||||
class Sphere(parent: VisualObject?, meta: Array<out Meta>) : VisualLeaf(parent, meta) {
|
||||
var radius by double(50.0)
|
||||
var phiStart by double(0.0)
|
||||
var phi by double(2 * PI)
|
||||
@ -16,17 +15,15 @@ class Sphere(parent: VisualObject?, meta: Meta) : DisplayLeaf(parent, meta) {
|
||||
var theta by double(PI)
|
||||
}
|
||||
|
||||
fun VisualGroup.sphere(meta: Meta = EmptyMeta, action: Sphere.() -> Unit = {}) =
|
||||
Sphere(this, meta).apply(action).also { add(it) }
|
||||
|
||||
fun VisualGroup.sphere(
|
||||
radius: Number,
|
||||
phi: Number = 2 * PI,
|
||||
theta: Number = PI,
|
||||
meta: Meta = EmptyMeta,
|
||||
name: String? = null,
|
||||
vararg meta: Meta,
|
||||
action: Sphere.() -> Unit = {}
|
||||
) = Sphere(this, meta).apply(action).apply {
|
||||
this.radius = radius.toDouble()
|
||||
this.phi = phi.toDouble()
|
||||
this.theta = theta.toDouble()
|
||||
}.also { add(it) }
|
||||
}.also { set(name, it) }
|
@ -0,0 +1,196 @@
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.names.plus
|
||||
import hep.dataforge.output.Output
|
||||
import hep.dataforge.vis.common.VisualGroup
|
||||
import hep.dataforge.vis.common.VisualLeaf
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
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 =
|
||||
VisualGroup(this, meta).apply(action).also { set(key, it) }
|
||||
|
||||
|
||||
fun Output<VisualObject>.render(meta: Meta = EmptyMeta, action: VisualGroup.() -> Unit) =
|
||||
render(VisualGroup().apply(action), meta)
|
||||
|
||||
//TODO replace properties by containers?
|
||||
|
||||
object PropertyNames3D {
|
||||
val x = "x".asName()
|
||||
val y = "y".asName()
|
||||
val z = "z".asName()
|
||||
|
||||
val position = "pos".asName()
|
||||
|
||||
val xPos = position + x
|
||||
val yPos = position + y
|
||||
val zPos = position + z
|
||||
|
||||
val rotation = "rotation".asName()
|
||||
|
||||
val xRotation = rotation + x
|
||||
val yRotation = rotation + y
|
||||
val zRotation = rotation + z
|
||||
|
||||
val rotationOrder = rotation + "order"
|
||||
|
||||
val scale = "scale".asName()
|
||||
|
||||
val xScale = scale + x
|
||||
val yScale = scale + y
|
||||
val zScale = scale + z
|
||||
}
|
||||
|
||||
// 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 {
|
||||
XYZ,
|
||||
YZX,
|
||||
ZXY,
|
||||
XZY,
|
||||
YXZ,
|
||||
ZYX
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotation order. Not inherited
|
||||
*/
|
||||
var VisualObject.rotationOrder: RotationOrder
|
||||
get() = config[PropertyNames3D.rotationOrder].enum<RotationOrder>() ?: RotationOrder.XYZ
|
||||
set(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
|
||||
*/
|
||||
var VisualObject.detail: Int?
|
||||
get() = properties["detail"]?.int
|
||||
set(value) {
|
||||
config["detail"] = value
|
||||
}
|
||||
|
||||
object World {
|
||||
const val CAMERA_INITIAL_DISTANCE = -500.0
|
||||
const val CAMERA_INITIAL_X_ANGLE = -50.0
|
||||
const val CAMERA_INITIAL_Y_ANGLE = 0.0
|
||||
const val CAMERA_INITIAL_Z_ANGLE = -210.0
|
||||
const val CAMERA_NEAR_CLIP = 0.1
|
||||
const val CAMERA_FAR_CLIP = 10000.0
|
||||
}
|
@ -1,164 +0,0 @@
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.output.Output
|
||||
import hep.dataforge.vis.common.VisualGroup
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
import hep.dataforge.vis.common.getProperty
|
||||
|
||||
fun VisualGroup.group(meta: Meta = EmptyMeta, action: VisualGroup.() -> Unit = {}): VisualGroup =
|
||||
VisualGroup(this, meta).apply(action).also { add(it) }
|
||||
|
||||
|
||||
fun Output<VisualObject>.render(meta: Meta = EmptyMeta, action: VisualGroup.() -> Unit) =
|
||||
render(VisualGroup(null, EmptyMeta).apply(action), meta)
|
||||
|
||||
//TODO replace properties by containers?
|
||||
|
||||
// Common properties
|
||||
|
||||
/**
|
||||
* Visibility property. Inherited from parent
|
||||
*/
|
||||
var VisualObject.visible
|
||||
get() = getProperty("visible").boolean ?: true
|
||||
set(value) {
|
||||
properties["visible"] = value
|
||||
}
|
||||
|
||||
// 3D Object position
|
||||
|
||||
private val xPos = "pos.x".toName()
|
||||
/**
|
||||
* x position property relative to parent. Not inherited
|
||||
*/
|
||||
var VisualObject.x
|
||||
get() = properties[xPos].number ?: 0.0
|
||||
set(value) {
|
||||
properties[xPos] = value
|
||||
}
|
||||
|
||||
private val yPos = "pos.y".toName()
|
||||
|
||||
/**
|
||||
* y position property. Not inherited
|
||||
*/
|
||||
var VisualObject.y
|
||||
get() = properties[yPos].number ?: 0.0
|
||||
set(value) {
|
||||
properties[yPos] = value
|
||||
}
|
||||
|
||||
private val zPos = "pos.z".toName()
|
||||
|
||||
/**
|
||||
* z position property. Not inherited
|
||||
*/
|
||||
var VisualObject.z
|
||||
get() = properties[zPos].number ?: 0.0
|
||||
set(value) {
|
||||
properties[zPos] = value
|
||||
}
|
||||
|
||||
// 3D Object rotation
|
||||
|
||||
private val xRotation = "rotation.x".toName()
|
||||
|
||||
/**
|
||||
* x rotation relative to parent. Not inherited
|
||||
*/
|
||||
var VisualObject.rotationX
|
||||
get() = properties[xRotation].number ?: 0.0
|
||||
set(value) {
|
||||
properties[xRotation] = value
|
||||
}
|
||||
|
||||
private val yRotation = "rotation.y".toName()
|
||||
|
||||
/**
|
||||
* y rotation relative to parent. Not inherited
|
||||
*/
|
||||
var VisualObject.rotationY
|
||||
get() = properties[yRotation].number ?: 0.0
|
||||
set(value) {
|
||||
properties[yRotation] = value
|
||||
}
|
||||
|
||||
private val zRotation = "rotation.z".toName()
|
||||
|
||||
/**
|
||||
* z rotation relative to parent. Not inherited
|
||||
*/
|
||||
var VisualObject.rotationZ
|
||||
get() = properties[zRotation].number ?: 0.0
|
||||
set(value) {
|
||||
properties[zRotation] = value
|
||||
}
|
||||
|
||||
enum class RotationOrder {
|
||||
XYZ,
|
||||
YZX,
|
||||
ZXY,
|
||||
XZY,
|
||||
YXZ,
|
||||
ZYX
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotation order. Not inherited
|
||||
*/
|
||||
var VisualObject.rotationOrder: RotationOrder
|
||||
get() = getProperty("rotation.order").enum<RotationOrder>() ?: RotationOrder.XYZ
|
||||
set(value) {
|
||||
properties["rotation.order"] = value
|
||||
}
|
||||
|
||||
// 3D object scale
|
||||
|
||||
/**
|
||||
* X scale. Not inherited
|
||||
*/
|
||||
var VisualObject.scaleX
|
||||
get() = properties["scale.x"].number ?: 1.0
|
||||
set(value) {
|
||||
properties["scale.x"] = value
|
||||
}
|
||||
|
||||
/**
|
||||
* Y scale. Not inherited
|
||||
*/
|
||||
var VisualObject.scaleY
|
||||
get() = properties["scale.y"].number ?: 1.0
|
||||
set(value) {
|
||||
properties["scale.y"] = value
|
||||
}
|
||||
|
||||
/**
|
||||
* Z scale. Not inherited
|
||||
*/
|
||||
var VisualObject.scaleZ
|
||||
get() = properties["scale.z"].number ?: 1.0
|
||||
set(value) {
|
||||
properties["scale.z"] = value
|
||||
}
|
||||
|
||||
//TODO add inherited scale
|
||||
|
||||
/**
|
||||
* Preferred number of polygons for displaying the object. If not defined, uses shape or renderer default
|
||||
*/
|
||||
var VisualObject.detail: Int?
|
||||
get() = properties["detail"]?.int
|
||||
set(value) {
|
||||
properties["detail"] = value
|
||||
}
|
||||
|
||||
object World {
|
||||
const val CAMERA_INITIAL_DISTANCE = -500.0
|
||||
const val CAMERA_INITIAL_X_ANGLE = -50.0
|
||||
const val CAMERA_INITIAL_Y_ANGLE = 0.0
|
||||
const val CAMERA_INITIAL_Z_ANGLE = -210.0
|
||||
const val CAMERA_NEAR_CLIP = 0.1
|
||||
const val CAMERA_FAR_CLIP = 10000.0
|
||||
}
|
@ -26,7 +26,7 @@ class ConvexTest {
|
||||
|
||||
val convex = group.first() as Convex
|
||||
|
||||
val pointsNode = convex.properties["points"].node
|
||||
val pointsNode = convex.config["points"].node
|
||||
|
||||
assertEquals(8, pointsNode?.items?.count())
|
||||
val points = pointsNode?.getAll("point".toName())
|
||||
|
@ -0,0 +1,52 @@
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.vis.common.Colors
|
||||
import hep.dataforge.vis.common.VisualGroup
|
||||
import hep.dataforge.vis.common.color
|
||||
import kotlin.math.PI
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class GroupTest {
|
||||
@Test
|
||||
fun testGroupWithComposite(){
|
||||
val group = VisualGroup().apply{
|
||||
union {
|
||||
box(100, 100, 100) {
|
||||
z = 100
|
||||
rotationX = PI / 4
|
||||
rotationY = PI / 4
|
||||
}
|
||||
box(100, 100, 100)
|
||||
color {
|
||||
"color" to Colors.lightgreen
|
||||
"opacity" to 0.3
|
||||
}
|
||||
}
|
||||
intersect{
|
||||
box(100, 100, 100) {
|
||||
z = 100
|
||||
rotationX = PI / 4
|
||||
rotationY = PI / 4
|
||||
}
|
||||
box(100, 100, 100)
|
||||
y = 300
|
||||
color(Colors.red)
|
||||
}
|
||||
subtract{
|
||||
box(100, 100, 100) {
|
||||
z = 100
|
||||
rotationX = PI / 4
|
||||
rotationY = PI / 4
|
||||
}
|
||||
box(100, 100, 100)
|
||||
y = -300
|
||||
color(Colors.blue)
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(3, group.count())
|
||||
assertEquals(300.0,group.toList()[1].y.toDouble())
|
||||
assertEquals(-300.0,group.toList()[2].y.toDouble())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user