Major caching update for objects
This commit is contained in:
parent
073ae8a353
commit
c3a7afc6d0
@ -0,0 +1,130 @@
|
|||||||
|
package hep.dataforge.vis.common
|
||||||
|
|
||||||
|
import hep.dataforge.meta.MetaBuilder
|
||||||
|
import hep.dataforge.meta.MetaItem
|
||||||
|
import hep.dataforge.names.Name
|
||||||
|
import hep.dataforge.names.get
|
||||||
|
import hep.dataforge.provider.Provider
|
||||||
|
import kotlinx.serialization.Transient
|
||||||
|
import kotlin.collections.set
|
||||||
|
|
||||||
|
open class VisualGroup<T : VisualObject> : AbstractVisualObject(), Iterable<T>, Provider {
|
||||||
|
|
||||||
|
protected val namedChildren = HashMap<Name, T>()
|
||||||
|
protected val unnamedChildren = ArrayList<T>()
|
||||||
|
|
||||||
|
override val defaultTarget: String get() = VisualObject.TYPE
|
||||||
|
|
||||||
|
override fun iterator(): Iterator<T> = (namedChildren.values + unnamedChildren).iterator()
|
||||||
|
|
||||||
|
override fun provideTop(target: String): Map<Name, Any> {
|
||||||
|
return when (target) {
|
||||||
|
VisualObject.TYPE -> namedChildren
|
||||||
|
else -> emptyMap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun propertyChanged(name: Name, before: MetaItem<*>?, after: MetaItem<*>?) {
|
||||||
|
super.propertyChanged(name, before, after)
|
||||||
|
forEach {
|
||||||
|
it.propertyChanged(name, before, after)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class Listener<T : VisualObject>(val owner: Any?, val callback: (Name?, T?) -> Unit)
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
private val listeners = HashSet<Listener<T>>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add listener for children change
|
||||||
|
*/
|
||||||
|
fun onChildrenChange(owner: Any?, action: (Name?, T?) -> Unit) {
|
||||||
|
listeners.add(Listener(owner, action))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove children change listener
|
||||||
|
*/
|
||||||
|
fun removeChildrenChangeListener(owner: Any?) {
|
||||||
|
listeners.removeAll { it.owner === owner }
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun set(name: Name, child: T?) {
|
||||||
|
if (child == null) {
|
||||||
|
namedChildren.remove(name)
|
||||||
|
} else {
|
||||||
|
if (child.parent == null) {
|
||||||
|
child.parent = this
|
||||||
|
} else {
|
||||||
|
error("Can't reassign existing parent for $child")
|
||||||
|
}
|
||||||
|
namedChildren[name] = child
|
||||||
|
}
|
||||||
|
listeners.forEach { it.callback(name, child) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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(name: Name?, child: T?) {
|
||||||
|
when {
|
||||||
|
name != null -> set(name, child)
|
||||||
|
child != null -> add(child)
|
||||||
|
else -> error("Both key and child element are empty")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun set(key: String?, child: T?) = set(key?.asName(), child)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get named child by name
|
||||||
|
*/
|
||||||
|
operator fun get(name: Name): T? = namedChildren[name]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get named child by string
|
||||||
|
*/
|
||||||
|
operator fun get(key: String): T? = namedChildren.get(key)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an unnamed child
|
||||||
|
*/
|
||||||
|
operator fun get(index: Int): T? = unnamedChildren[index]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append unnamed child
|
||||||
|
*/
|
||||||
|
fun add(child: T) {
|
||||||
|
if (child.parent == null) {
|
||||||
|
child.parent = this
|
||||||
|
} else {
|
||||||
|
error("Can't reassign existing parent for $child")
|
||||||
|
}
|
||||||
|
unnamedChildren.add(child)
|
||||||
|
listeners.forEach { it.callback(null, child) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* remove unnamed child
|
||||||
|
*/
|
||||||
|
fun remove(child: VisualObject) {
|
||||||
|
unnamedChildren.remove(child)
|
||||||
|
listeners.forEach { it.callback(null, null) }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun MetaBuilder.updateChildren() {
|
||||||
|
//adding unnamed children
|
||||||
|
"unnamedChildren" to unnamedChildren.map { it.toMeta() }
|
||||||
|
//adding named children
|
||||||
|
namedChildren.forEach {
|
||||||
|
"children[${it.key}]" to it.value.toMeta()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun MetaBuilder.updateMeta() {
|
||||||
|
updateChildren()
|
||||||
|
}
|
||||||
|
}
|
@ -6,10 +6,7 @@ import hep.dataforge.names.Name
|
|||||||
/**
|
/**
|
||||||
* Basic [VisualObject] leaf element
|
* Basic [VisualObject] leaf element
|
||||||
*/
|
*/
|
||||||
open class VisualLeaf(
|
open class VisualLeaf(meta: Meta = EmptyMeta) : AbstractVisualObject(), Configurable {
|
||||||
parent: VisualObject? = null,
|
|
||||||
meta: Meta = EmptyMeta
|
|
||||||
) : AbstractVisualObject(parent), Configurable {
|
|
||||||
|
|
||||||
val properties = Styled(meta)
|
val properties = Styled(meta)
|
||||||
|
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
package hep.dataforge.vis.common
|
package hep.dataforge.vis.common
|
||||||
|
|
||||||
|
import hep.dataforge.io.ConfigSerializer
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.get
|
|
||||||
import hep.dataforge.provider.Provider
|
|
||||||
import hep.dataforge.provider.Type
|
import hep.dataforge.provider.Type
|
||||||
import hep.dataforge.vis.common.VisualObject.Companion.TYPE
|
import hep.dataforge.vis.common.VisualObject.Companion.TYPE
|
||||||
import kotlin.collections.set
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.Transient
|
||||||
|
|
||||||
private fun Laminate.withTop(meta: Meta): Laminate = Laminate(listOf(meta) + layers)
|
private fun Laminate.withTop(meta: Meta): Laminate = Laminate(listOf(meta) + layers)
|
||||||
private fun Laminate.withBottom(meta: Meta): Laminate = Laminate(layers + meta)
|
private fun Laminate.withBottom(meta: Meta): Laminate = Laminate(layers + meta)
|
||||||
@ -22,7 +23,8 @@ interface VisualObject : MetaRepr, Configurable {
|
|||||||
/**
|
/**
|
||||||
* The parent object of this one. If null, this one is a root.
|
* The parent object of this one. If null, this one is a root.
|
||||||
*/
|
*/
|
||||||
val parent: VisualObject?
|
@Transient
|
||||||
|
var parent: VisualObject?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set property for this object
|
* Set property for this object
|
||||||
@ -62,8 +64,10 @@ internal data class MetaListener(
|
|||||||
val action: (name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) -> Unit
|
val action: (name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) -> Unit
|
||||||
)
|
)
|
||||||
|
|
||||||
|
abstract class AbstractVisualObject : VisualObject {
|
||||||
|
override var parent: VisualObject? = null
|
||||||
|
|
||||||
abstract class AbstractVisualObject(override val parent: VisualObject?) : VisualObject {
|
@Transient
|
||||||
private val listeners = HashSet<MetaListener>()
|
private val listeners = HashSet<MetaListener>()
|
||||||
|
|
||||||
override fun propertyChanged(name: Name, before: MetaItem<*>?, after: MetaItem<*>?) {
|
override fun propertyChanged(name: Name, before: MetaItem<*>?, after: MetaItem<*>?) {
|
||||||
@ -80,6 +84,8 @@ abstract class AbstractVisualObject(override val parent: VisualObject?) : Visual
|
|||||||
listeners.removeAll { it.owner == owner }
|
listeners.removeAll { it.owner == owner }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serializable(ConfigSerializer::class)
|
||||||
|
@SerialName("properties")
|
||||||
private var _config: Config? = null
|
private var _config: Config? = null
|
||||||
override val config: Config
|
override val config: Config
|
||||||
get() = _config ?: Config().also { config ->
|
get() = _config ?: Config().also { config ->
|
||||||
@ -103,117 +109,9 @@ abstract class AbstractVisualObject(override val parent: VisualObject?) : Visual
|
|||||||
|
|
||||||
override fun toMeta(): Meta = buildMeta {
|
override fun toMeta(): Meta = buildMeta {
|
||||||
"type" to type
|
"type" to type
|
||||||
"properties" to _config
|
"properties" to config
|
||||||
updateMeta()
|
updateMeta()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open class VisualGroup<T : VisualObject>(parent: VisualObject?) : AbstractVisualObject(parent), Iterable<T>, Provider {
|
|
||||||
|
|
||||||
protected val namedChildren = HashMap<Name, T>()
|
|
||||||
protected val unnamedChildren = ArrayList<T>()
|
|
||||||
|
|
||||||
override val defaultTarget: String get() = VisualObject.TYPE
|
|
||||||
|
|
||||||
override fun iterator(): Iterator<T> = (namedChildren.values + unnamedChildren).iterator()
|
|
||||||
|
|
||||||
override fun provideTop(target: String): Map<Name, Any> {
|
|
||||||
return when (target) {
|
|
||||||
TYPE -> namedChildren
|
|
||||||
else -> emptyMap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun propertyChanged(name: Name, before: MetaItem<*>?, after: MetaItem<*>?) {
|
|
||||||
super.propertyChanged(name, before, after)
|
|
||||||
forEach {
|
|
||||||
it.propertyChanged(name, before, after)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private data class Listener<T : VisualObject>(val owner: Any?, val callback: (Name?, T?) -> Unit)
|
|
||||||
|
|
||||||
private val listeners = HashSet<Listener<T>>()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add listener for children change
|
|
||||||
*/
|
|
||||||
fun onChildrenChange(owner: Any?, action: (Name?, T?) -> Unit) {
|
|
||||||
listeners.add(Listener(owner, action))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove children change listener
|
|
||||||
*/
|
|
||||||
fun removeChildrenChangeListener(owner: Any?) {
|
|
||||||
listeners.removeAll { it.owner === owner }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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(name: Name?, child: T?) {
|
|
||||||
when {
|
|
||||||
name != null -> {
|
|
||||||
if (child == null) {
|
|
||||||
namedChildren.remove(name)
|
|
||||||
} else {
|
|
||||||
namedChildren[name] = child
|
|
||||||
}
|
|
||||||
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: T?) = set(key?.asName(), child)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get named child by name
|
|
||||||
*/
|
|
||||||
operator fun get(name: Name): T? = namedChildren[name]
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get named child by string
|
|
||||||
*/
|
|
||||||
operator fun get(key: String): T? = namedChildren[key]
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get an unnamed child
|
|
||||||
*/
|
|
||||||
operator fun get(index: Int): T? = unnamedChildren[index]
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Append unnamed child
|
|
||||||
*/
|
|
||||||
fun add(child: T) {
|
|
||||||
unnamedChildren.add(child)
|
|
||||||
listeners.forEach { it.callback(null, child) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* remove unnamed child
|
|
||||||
*/
|
|
||||||
fun remove(child: VisualObject) {
|
|
||||||
unnamedChildren.remove(child)
|
|
||||||
listeners.forEach { it.callback(null, null) }
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun MetaBuilder.updateChildren() {
|
|
||||||
//adding unnamed children
|
|
||||||
"children" to unnamedChildren.map { it.toMeta() }
|
|
||||||
//adding named children
|
|
||||||
namedChildren.forEach {
|
|
||||||
"children[${it.key}" to it.value.toMeta()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun MetaBuilder.updateMeta() {
|
|
||||||
updateChildren()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
package hep.dataforge.vis.common
|
||||||
|
|
||||||
|
import hep.dataforge.context.*
|
||||||
|
import hep.dataforge.meta.Meta
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
interface VisualFactory<T : VisualObject> {
|
||||||
|
val type: KClass<T>
|
||||||
|
operator fun invoke(
|
||||||
|
context: Context,
|
||||||
|
parent: VisualObject?,
|
||||||
|
meta: Meta
|
||||||
|
): T
|
||||||
|
}
|
||||||
|
|
||||||
|
class VisualPlugin(meta: Meta) : AbstractPlugin(meta) {
|
||||||
|
override val tag: PluginTag get() = Companion.tag
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a list of factories on first call and cache it
|
||||||
|
*/
|
||||||
|
val visualFactories by lazy {
|
||||||
|
context.content<VisualFactory<*>>(VISUAL_FACTORY_TYPE).mapKeys { it.value.type }
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : VisualObject> buildVisual(parent: VisualObject?, meta: Meta): T? {
|
||||||
|
return visualFactories[T::class]?.invoke(context, parent, meta) as T?
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object : PluginFactory<VisualPlugin> {
|
||||||
|
override val tag: PluginTag = PluginTag(name = "visual", group = PluginTag.DATAFORGE_GROUP)
|
||||||
|
override val type: KClass<out VisualPlugin> = VisualPlugin::class
|
||||||
|
override fun invoke(meta: Meta): VisualPlugin = VisualPlugin(meta)
|
||||||
|
|
||||||
|
const val VISUAL_FACTORY_TYPE = "visual.factory"
|
||||||
|
}
|
||||||
|
}
|
@ -96,14 +96,14 @@ class FXMetaNode<M : MetaNode<M>>(
|
|||||||
if (name.length == 1) invalidate()
|
if (name.length == 1) invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
(node as? MutableMeta<*>)?.onChange(this, listener)
|
(node as? Config)?.onChange(this, listener)
|
||||||
|
|
||||||
nodeProperty.addListener { _, oldValue, newValue ->
|
nodeProperty.addListener { _, oldValue, newValue ->
|
||||||
if (newValue == null) {
|
if (newValue == null) {
|
||||||
(oldValue as? MutableMeta<*>)?.removeListener(this)
|
(oldValue as? Config)?.removeListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newValue is MutableMeta<*>) {
|
if (newValue is Config) {
|
||||||
newValue.onChange(this, listener)
|
newValue.onChange(this, listener)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ kotlin {
|
|||||||
val commonMain by getting {
|
val commonMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
api(project(":dataforge-vis-spatial"))
|
api(project(":dataforge-vis-spatial"))
|
||||||
api("scientifik:gdml:0.1.3")
|
api("scientifik:gdml:0.1.4-dev-1")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val jsMain by getting {
|
val jsMain by getting {
|
||||||
|
@ -14,6 +14,12 @@ class GDMLTransformer(val root: GDML) {
|
|||||||
private val materialCache = HashMap<GDMLMaterial, Meta>()
|
private val materialCache = HashMap<GDMLMaterial, Meta>()
|
||||||
private val random = Random(111)
|
private val random = Random(111)
|
||||||
|
|
||||||
|
enum class Action{
|
||||||
|
ACCEPT,
|
||||||
|
REJECT,
|
||||||
|
CACHE
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A special group for local templates
|
* A special group for local templates
|
||||||
*/
|
*/
|
||||||
@ -34,15 +40,15 @@ class GDMLTransformer(val root: GDML) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var acceptSolid: (GDMLSolid) -> Boolean = { true }
|
var solidAction: (GDMLSolid) -> Action = { Action.CACHE }
|
||||||
var acceptGroup: (GDMLGroup) -> Boolean = { true }
|
var volumeAction: (GDMLGroup) -> Action = { Action.ACCEPT }
|
||||||
|
|
||||||
fun printStatistics() {
|
fun printStatistics() {
|
||||||
println("Solids:")
|
println("Solids:")
|
||||||
solidCounter.entries.sortedByDescending { it.value }.forEach {
|
solidCounter.entries.sortedByDescending { it.value }.forEach {
|
||||||
println("\t$it")
|
println("\t$it")
|
||||||
}
|
}
|
||||||
println(println("Solids total: ${solidCounter.values.sum()}"))
|
println("Solids total: ${solidCounter.values.sum()}")
|
||||||
}
|
}
|
||||||
|
|
||||||
private val solidCounter = HashMap<String, Int>()
|
private val solidCounter = HashMap<String, Int>()
|
||||||
@ -53,8 +59,9 @@ class GDMLTransformer(val root: GDML) {
|
|||||||
|
|
||||||
var onFinish: GDMLTransformer.() -> Unit = {}
|
var onFinish: GDMLTransformer.() -> Unit = {}
|
||||||
|
|
||||||
internal fun finished() {
|
internal fun finished(final: VisualGroup3D) {
|
||||||
onFinish(this)
|
final.templates = templates
|
||||||
|
onFinish(this@GDMLTransformer)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,6 +1,8 @@
|
|||||||
package hep.dataforge.vis.spatial.gdml
|
package hep.dataforge.vis.spatial.gdml
|
||||||
|
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.names.plus
|
||||||
|
import hep.dataforge.vis.common.asName
|
||||||
import hep.dataforge.vis.spatial.*
|
import hep.dataforge.vis.spatial.*
|
||||||
import scientifik.gdml.*
|
import scientifik.gdml.*
|
||||||
import kotlin.math.cos
|
import kotlin.math.cos
|
||||||
@ -131,6 +133,8 @@ private fun VisualGroup3D.addSolid(
|
|||||||
}.apply(block)
|
}.apply(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val volumesName = "volumes".asName()
|
||||||
|
|
||||||
private fun VisualGroup3D.addPhysicalVolume(
|
private fun VisualGroup3D.addPhysicalVolume(
|
||||||
context: GDMLTransformer,
|
context: GDMLTransformer,
|
||||||
physVolume: GDMLPhysVolume
|
physVolume: GDMLPhysVolume
|
||||||
@ -138,17 +142,37 @@ private fun VisualGroup3D.addPhysicalVolume(
|
|||||||
val volume: GDMLGroup = physVolume.volumeref.resolve(context.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")
|
||||||
|
|
||||||
if (context.acceptGroup(volume)) {
|
when (context.volumeAction(volume)) {
|
||||||
|
GDMLTransformer.Action.ACCEPT -> {
|
||||||
this[physVolume.name] = volume(
|
this[physVolume.name] = volume(context, volume).apply {
|
||||||
context,
|
withPosition(
|
||||||
volume,
|
context.lUnit,
|
||||||
physVolume.resolvePosition(context.root),
|
physVolume.resolvePosition(context.root),
|
||||||
physVolume.resolveRotation(context.root),
|
physVolume.resolveRotation(context.root),
|
||||||
physVolume.resolveScale(context.root)
|
physVolume.resolveScale(context.root)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
GDMLTransformer.Action.CACHE -> {
|
||||||
|
val name = volumesName + volume.name.asName()
|
||||||
|
if (context.templates[name] == null) {
|
||||||
|
context.templates[name] = volume(context, volume)
|
||||||
|
}
|
||||||
|
|
||||||
|
this[physVolume.name] = Proxy(name).apply {
|
||||||
|
withPosition(
|
||||||
|
context.lUnit,
|
||||||
|
physVolume.resolvePosition(context.root),
|
||||||
|
physVolume.resolveRotation(context.root),
|
||||||
|
physVolume.resolveScale(context.root)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GDMLTransformer.Action.REJECT -> {
|
||||||
|
//ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun VisualGroup3D.addDivisionVolume(
|
private fun VisualGroup3D.addDivisionVolume(
|
||||||
context: GDMLTransformer,
|
context: GDMLTransformer,
|
||||||
@ -168,36 +192,38 @@ private fun VisualGroup3D.addDivisionVolume(
|
|||||||
|
|
||||||
private fun VisualGroup3D.addVolume(
|
private fun VisualGroup3D.addVolume(
|
||||||
context: GDMLTransformer,
|
context: GDMLTransformer,
|
||||||
group: GDMLGroup,
|
group: GDMLGroup
|
||||||
position: GDMLPosition? = null,
|
|
||||||
rotation: GDMLRotation? = null,
|
|
||||||
scale: GDMLScale? = null
|
|
||||||
) {
|
) {
|
||||||
this[group.name] = volume(context, group, position, rotation, scale)
|
this[group.name] = volume(context, group)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun volume(
|
private fun volume(
|
||||||
context: GDMLTransformer,
|
context: GDMLTransformer,
|
||||||
group: GDMLGroup,
|
group: GDMLGroup
|
||||||
position: GDMLPosition? = null,
|
|
||||||
rotation: GDMLRotation? = null,
|
|
||||||
scale: GDMLScale? = null
|
|
||||||
): VisualGroup3D {
|
): VisualGroup3D {
|
||||||
|
|
||||||
return VisualGroup3D().apply {
|
return VisualGroup3D().apply {
|
||||||
withPosition(context.lUnit, position, rotation, scale)
|
|
||||||
|
|
||||||
if (group is GDMLVolume) {
|
if (group is GDMLVolume) {
|
||||||
val solid = group.solidref.resolve(context.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(context.root) ?: GDMLElement(group.materialref.ref)
|
val material = group.materialref.resolve(context.root) ?: GDMLElement(group.materialref.ref)
|
||||||
|
|
||||||
if (context.acceptSolid(solid)) {
|
when (context.solidAction(solid)) {
|
||||||
val cachedSolid = context.templates[solid.name]
|
GDMLTransformer.Action.ACCEPT -> {
|
||||||
?: context.templates.addSolid(context, solid, solid.name) {
|
addSolid(context, solid, solid.name) {
|
||||||
this.material = context.resolveColor(group, material, solid)
|
this.material = context.resolveColor(group, material, solid)
|
||||||
}
|
}
|
||||||
proxy(cachedSolid, solid.name)
|
}
|
||||||
|
GDMLTransformer.Action.CACHE -> {
|
||||||
|
if (context.templates[solid.name] == null) {
|
||||||
|
context.templates.addSolid(context, solid, solid.name) {
|
||||||
|
this.material = context.resolveColor(group, material, solid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ref(solid.name.asName(), solid.name)
|
||||||
|
}
|
||||||
|
GDMLTransformer.Action.REJECT -> {
|
||||||
|
//ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
when (val vol = group.placement) {
|
when (val vol = group.placement) {
|
||||||
@ -220,6 +246,6 @@ fun GDML.toVisual(block: GDMLTransformer.() -> Unit = {}): VisualGroup3D {
|
|||||||
val context = GDMLTransformer(this).apply(block)
|
val context = GDMLTransformer(this).apply(block)
|
||||||
|
|
||||||
return volume(context, world).also {
|
return volume(context, world).also {
|
||||||
context.finished()
|
context.finished(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,6 +3,7 @@ package hep.dataforge.vis.spatial.gdml.demo
|
|||||||
import hep.dataforge.context.Global
|
import hep.dataforge.context.Global
|
||||||
import hep.dataforge.vis.hmr.ApplicationBase
|
import hep.dataforge.vis.hmr.ApplicationBase
|
||||||
import hep.dataforge.vis.hmr.startApplication
|
import hep.dataforge.vis.hmr.startApplication
|
||||||
|
import hep.dataforge.vis.spatial.gdml.GDMLTransformer
|
||||||
import hep.dataforge.vis.spatial.gdml.LUnit
|
import hep.dataforge.vis.spatial.gdml.LUnit
|
||||||
import hep.dataforge.vis.spatial.gdml.toVisual
|
import hep.dataforge.vis.spatial.gdml.toVisual
|
||||||
import hep.dataforge.vis.spatial.three.ThreePlugin
|
import hep.dataforge.vis.spatial.three.ThreePlugin
|
||||||
@ -82,7 +83,7 @@ private class GDMLDemoApp : ApplicationBase() {
|
|||||||
val canvas = document.getElementById("canvas") ?: error("Element with id canvas not found on page")
|
val canvas = document.getElementById("canvas") ?: error("Element with id canvas not found on page")
|
||||||
canvas.clear()
|
canvas.clear()
|
||||||
|
|
||||||
val action: suspend CoroutineScope.(String) -> Unit = {
|
val action: suspend CoroutineScope.(String) -> Unit = { it ->
|
||||||
canvas.clear()
|
canvas.clear()
|
||||||
launch { spinner(true) }
|
launch { spinner(true) }
|
||||||
launch { message("Loading GDML") }
|
launch { message("Loading GDML") }
|
||||||
@ -90,12 +91,16 @@ private class GDMLDemoApp : ApplicationBase() {
|
|||||||
launch { message("Converting GDML into DF-VIS format") }
|
launch { message("Converting GDML into DF-VIS format") }
|
||||||
val visual = gdml.toVisual {
|
val visual = gdml.toVisual {
|
||||||
lUnit = LUnit.CM
|
lUnit = LUnit.CM
|
||||||
acceptSolid = { solid ->
|
volumeAction = { volume ->
|
||||||
!solid.name.startsWith("ecal")
|
when {
|
||||||
// && !solid.name.startsWith("V")
|
volume.name.startsWith("ecal") -> GDMLTransformer.Action.REJECT
|
||||||
// && !solid.name.startsWith("U")
|
volume.name.startsWith("U") -> GDMLTransformer.Action.CACHE
|
||||||
|
volume.name.startsWith("V") -> GDMLTransformer.Action.CACHE
|
||||||
|
else -> GDMLTransformer.Action.ACCEPT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
launch { message("Rendering") }
|
launch { message("Rendering") }
|
||||||
val output = three.output(canvas)
|
val output = three.output(canvas)
|
||||||
output.render(visual)
|
output.render(visual)
|
||||||
|
@ -1,25 +1,38 @@
|
|||||||
package hep.dataforge.vis.spatial.gdml
|
package hep.dataforge.vis.spatial.gdml
|
||||||
|
|
||||||
|
import hep.dataforge.names.toName
|
||||||
|
import hep.dataforge.vis.spatial.VisualGroup3D
|
||||||
import nl.adaptivity.xmlutil.StAXReader
|
import nl.adaptivity.xmlutil.StAXReader
|
||||||
import scientifik.gdml.GDML
|
import scientifik.gdml.GDML
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
fun main() {
|
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 file = File("D:\\Work\\Projects\\gdml.kt\\gdml-source\\BM@N.gdml")
|
||||||
val stream = if (file.exists()) {
|
//val file = File("D:\\Work\\Projects\\gdml.kt\\gdml-source\\cubes.gdml")
|
||||||
file.inputStream()
|
|
||||||
} else {
|
|
||||||
url.openStream()
|
|
||||||
}
|
|
||||||
|
|
||||||
val xmlReader = StAXReader(stream, "UTF-8")
|
val xmlReader = StAXReader(file.inputStream(), "UTF-8")
|
||||||
val xml = GDML.format.parse(GDML.serializer(), xmlReader)
|
val xml = GDML.format.parse(GDML.serializer(), xmlReader)
|
||||||
xml.toVisual {
|
val visual = xml.toVisual {
|
||||||
lUnit = LUnit.CM
|
lUnit = LUnit.CM
|
||||||
//acceptSolid = { solid -> !solid.name.startsWith("ecal") && !solid.name.startsWith("V") }
|
volumeAction = { volume ->
|
||||||
|
when {
|
||||||
|
volume.name.startsWith("ecal") -> GDMLTransformer.Action.CACHE
|
||||||
|
volume.name.startsWith("U") -> GDMLTransformer.Action.CACHE
|
||||||
|
volume.name.startsWith("V") -> GDMLTransformer.Action.CACHE
|
||||||
|
else -> GDMLTransformer.Action.ACCEPT
|
||||||
|
}
|
||||||
|
}
|
||||||
onFinish = { printStatistics() }
|
onFinish = { printStatistics() }
|
||||||
}
|
}
|
||||||
readLine()
|
|
||||||
|
val template = visual.getTemplate("volumes.ecal01mod".toName())
|
||||||
|
println(template)
|
||||||
|
visual.flatMap { (it as? VisualGroup3D) ?: listOf(it) }.forEach {
|
||||||
|
if(it.parent==null) error("")
|
||||||
|
}
|
||||||
|
//readLine()
|
||||||
|
//val meta = visual.toMeta()
|
||||||
|
// val tmpFile = File.createTempFile("dataforge-visual", "json")
|
||||||
|
//tmpFile.writeText(meta.toString())
|
||||||
|
//println(tmpFile.absoluteFile)
|
||||||
}
|
}
|
@ -49,7 +49,7 @@ class ThreePlugin : AbstractPlugin() {
|
|||||||
updatePosition(obj)
|
updatePosition(obj)
|
||||||
}
|
}
|
||||||
is Composite -> compositeFactory(obj)
|
is Composite -> compositeFactory(obj)
|
||||||
is Proxy3D -> proxyFactory(obj)
|
is Proxy -> proxyFactory(obj)
|
||||||
else -> {
|
else -> {
|
||||||
//find specialized factory for this type if it is present
|
//find specialized factory for this type if it is present
|
||||||
val factory = findObjectFactory(obj::class)
|
val factory = findObjectFactory(obj::class)
|
||||||
@ -84,7 +84,7 @@ class ThreePlugin : AbstractPlugin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object : PluginFactory<ThreePlugin> {
|
companion object : PluginFactory<ThreePlugin> {
|
||||||
override val tag = PluginTag("vis.three", "hep.dataforge")
|
override val tag = PluginTag("visual.three", PluginTag.DATAFORGE_GROUP)
|
||||||
override val type = ThreePlugin::class
|
override val type = ThreePlugin::class
|
||||||
override fun invoke(meta: Meta) = ThreePlugin()
|
override fun invoke(meta: Meta) = ThreePlugin()
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
package hep.dataforge.vis.spatial.three
|
package hep.dataforge.vis.spatial.three
|
||||||
|
|
||||||
import hep.dataforge.vis.spatial.Proxy3D
|
import hep.dataforge.vis.spatial.Proxy
|
||||||
import hep.dataforge.vis.spatial.VisualObject3D
|
import hep.dataforge.vis.spatial.VisualObject3D
|
||||||
import info.laht.threekt.core.Object3D
|
import info.laht.threekt.core.Object3D
|
||||||
import info.laht.threekt.objects.Mesh
|
|
||||||
|
|
||||||
class ThreeProxyFactory(val three: ThreePlugin) : ThreeFactory<Proxy3D> {
|
class ThreeProxyFactory(val three: ThreePlugin) : ThreeFactory<Proxy> {
|
||||||
private val cache = HashMap<VisualObject3D, Mesh>()
|
private val cache = HashMap<VisualObject3D, Object3D>()
|
||||||
|
|
||||||
override val type = Proxy3D::class
|
override val type = Proxy::class
|
||||||
|
|
||||||
override fun invoke(obj: Proxy3D): Object3D {
|
override fun invoke(obj: Proxy): Object3D {
|
||||||
val templateMesh = cache.getOrPut(obj.template) {
|
val template = obj.template
|
||||||
three.buildObject3D(obj.template) as Mesh
|
val cachedObject = cache.getOrPut(template) {
|
||||||
|
three.buildObject3D(template)
|
||||||
}
|
}
|
||||||
|
|
||||||
//val mesh = Mesh(templateMesh.geometry as BufferGeometry, templateMesh.material)
|
//val mesh = Mesh(templateMesh.geometry as BufferGeometry, templateMesh.material)
|
||||||
val mesh = templateMesh.clone()
|
val mesh = cachedObject.clone()
|
||||||
|
|
||||||
mesh.updatePosition(obj)
|
mesh.updatePosition(obj)
|
||||||
return mesh
|
return mesh
|
||||||
|
@ -2,13 +2,34 @@ plugins {
|
|||||||
id("scientifik.mpp")
|
id("scientifik.mpp")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scientifik{
|
||||||
|
serialization = true
|
||||||
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
|
jvm{
|
||||||
|
withJava()
|
||||||
|
}
|
||||||
sourceSets {
|
sourceSets {
|
||||||
val commonMain by getting {
|
commonMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
api(project(":dataforge-vis-common"))
|
api(project(":dataforge-vis-common"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
jvmMain{
|
||||||
|
dependencies {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jsMain{
|
||||||
|
dependencies {
|
||||||
|
api("info.laht.threekt:threejs-wrapper:0.106-npm-3")
|
||||||
|
implementation(npm("three", "0.106.2"))
|
||||||
|
implementation(npm("@hi-level/three-csg"))
|
||||||
|
implementation(npm("style-loader"))
|
||||||
|
implementation(npm("element-resize-event"))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,19 @@
|
|||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
|
import hep.dataforge.context.Context
|
||||||
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.meta.MetaBuilder
|
||||||
|
import hep.dataforge.meta.float
|
||||||
|
import hep.dataforge.meta.get
|
||||||
|
import hep.dataforge.vis.common.VisualFactory
|
||||||
import hep.dataforge.vis.common.VisualObject
|
import hep.dataforge.vis.common.VisualObject
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
class Box(parent: VisualObject?, val xSize: Number, val ySize: Number, val zSize: Number) :
|
data class Box(
|
||||||
VisualLeaf3D(parent), Shape {
|
val xSize: Float,
|
||||||
|
val ySize: Float,
|
||||||
|
val zSize: Float
|
||||||
|
) : VisualLeaf3D(), 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>) {
|
||||||
@ -26,9 +36,24 @@ class Box(parent: VisualObject?, val xSize: Number, val ySize: Number, val zSize
|
|||||||
geometryBuilder.face4(node8, node5, node6, node7)
|
geometryBuilder.face4(node8, node5, node6, node7)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
override fun MetaBuilder.updateMeta() {
|
||||||
|
"xSize" to xSize
|
||||||
|
"ySize" to ySize
|
||||||
|
"zSize" to ySize
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object : VisualFactory<Box> {
|
||||||
const val TYPE = "geometry.3d.box"
|
const val TYPE = "geometry.3d.box"
|
||||||
|
|
||||||
|
override val type: KClass<Box> get() = Box::class
|
||||||
|
|
||||||
|
override fun invoke(context: Context, parent: VisualObject?, meta: Meta): Box = Box(
|
||||||
|
meta["xSize"].float!!,
|
||||||
|
meta["ySize"].float!!,
|
||||||
|
meta["zSize"].float!!
|
||||||
|
).apply {
|
||||||
|
update(meta)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,4 +63,4 @@ inline fun VisualGroup3D.box(
|
|||||||
zSize: Number,
|
zSize: Number,
|
||||||
name: String? = null,
|
name: String? = null,
|
||||||
action: Box.() -> Unit = {}
|
action: Box.() -> Unit = {}
|
||||||
) = Box(this, xSize, ySize, zSize).apply(action).also { set(name, it) }
|
) = Box(xSize.toFloat(), ySize.toFloat(), zSize.toFloat()).apply(action).also { set(name, it) }
|
@ -2,7 +2,6 @@ package hep.dataforge.vis.spatial
|
|||||||
|
|
||||||
import hep.dataforge.meta.isEmpty
|
import hep.dataforge.meta.isEmpty
|
||||||
import hep.dataforge.meta.update
|
import hep.dataforge.meta.update
|
||||||
import hep.dataforge.vis.common.VisualObject
|
|
||||||
|
|
||||||
enum class CompositeType {
|
enum class CompositeType {
|
||||||
UNION,
|
UNION,
|
||||||
@ -11,13 +10,12 @@ enum class CompositeType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
open class Composite(
|
open class Composite(
|
||||||
parent: VisualObject?,
|
|
||||||
val first: VisualObject3D,
|
val first: VisualObject3D,
|
||||||
val second: VisualObject3D,
|
val second: VisualObject3D,
|
||||||
val compositeType: CompositeType = CompositeType.UNION
|
val compositeType: CompositeType = CompositeType.UNION
|
||||||
) : VisualLeaf3D(parent)
|
) : VisualLeaf3D()
|
||||||
|
|
||||||
fun VisualGroup3D.composite(
|
inline fun VisualGroup3D.composite(
|
||||||
type: CompositeType,
|
type: CompositeType,
|
||||||
name: String? = null,
|
name: String? = null,
|
||||||
builder: VisualGroup3D.() -> Unit
|
builder: VisualGroup3D.() -> Unit
|
||||||
@ -25,7 +23,7 @@ fun VisualGroup3D.composite(
|
|||||||
val group = VisualGroup3D().apply(builder)
|
val group = VisualGroup3D().apply(builder)
|
||||||
val children = group.filterIsInstance<VisualObject3D>()
|
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")
|
||||||
return Composite(this, children[0], children[1], type).also {
|
return Composite(children[0], children[1], type).also {
|
||||||
if (!group.config.isEmpty()) {
|
if (!group.config.isEmpty()) {
|
||||||
it.config.update(group.config)
|
it.config.update(group.config)
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,24 @@
|
|||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.vis.common.VisualObject
|
import hep.dataforge.meta.MetaBuilder
|
||||||
|
|
||||||
class Convex(parent: VisualObject?, val points: List<Point3D>) : VisualLeaf3D(parent) {
|
class Convex(
|
||||||
|
val points: List<Point3D>
|
||||||
|
) : VisualLeaf3D() {
|
||||||
|
|
||||||
|
override fun MetaBuilder.updateMeta() {
|
||||||
|
"points" to {
|
||||||
|
"point" to points.map{it.toMeta()}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val TYPE = "geometry.3d.convex"
|
const val TYPE = "geometry.3d.convex"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun VisualGroup3D.convex(action: ConvexBuilder.() -> Unit = {}) =
|
inline fun VisualGroup3D.convex(name: String? = null, action: ConvexBuilder.() -> Unit = {}) =
|
||||||
ConvexBuilder().apply(action).build(this).also { add(it) }
|
ConvexBuilder().apply(action).build().also { set(name, it) }
|
||||||
|
|
||||||
class ConvexBuilder {
|
class ConvexBuilder {
|
||||||
private val points = ArrayList<Point3D>()
|
private val points = ArrayList<Point3D>()
|
||||||
@ -20,7 +27,7 @@ class ConvexBuilder {
|
|||||||
points.add(Point3D(x, y, z))
|
points.add(Point3D(x, y, z))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun build(parent: VisualObject?): Convex {
|
fun build(): Convex {
|
||||||
return Convex(parent, points)
|
return Convex(points)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,27 +1,22 @@
|
|||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.vis.common.VisualObject
|
|
||||||
import kotlin.math.PI
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A cylinder or cut cone segment
|
* A cylinder or cut cone segment
|
||||||
*/
|
*/
|
||||||
class Cylinder(
|
class Cylinder(
|
||||||
parent: VisualObject?,
|
var radius: Float,
|
||||||
var radius: Number,
|
var height: Float,
|
||||||
var height: Number,
|
var upperRadius: Float = radius,
|
||||||
var upperRadius: Number = radius,
|
var startAngle: Float = 0f,
|
||||||
var startAngle: Number = 0f,
|
var angle: Float = PI2
|
||||||
var angle: Number = 2 * PI
|
) : VisualLeaf3D()
|
||||||
) : VisualLeaf3D(parent)
|
|
||||||
|
|
||||||
fun VisualGroup3D.cylinder(
|
inline fun VisualGroup3D.cylinder(
|
||||||
r: Number,
|
r: Number,
|
||||||
height: Number,
|
height: Number,
|
||||||
name: String? = null,
|
name: String? = null,
|
||||||
block: Cylinder.() -> Unit = {}
|
block: Cylinder.() -> Unit = {}
|
||||||
): Cylinder {
|
): Cylinder = Cylinder(
|
||||||
val cylinder = Cylinder(this, r, height)
|
r.toFloat(),
|
||||||
cylinder.apply(block)
|
height.toFloat()
|
||||||
return cylinder.also { set(name, it) }
|
).apply(block).also { set(name, it) }
|
||||||
}
|
|
@ -1,6 +1,5 @@
|
|||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.vis.common.VisualObject
|
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
import kotlin.math.cos
|
import kotlin.math.cos
|
||||||
import kotlin.math.sin
|
import kotlin.math.sin
|
||||||
@ -30,7 +29,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?) : VisualLeaf3D(parent), Shape {
|
class Extruded : VisualLeaf3D(), Shape {
|
||||||
|
|
||||||
var shape: List<Point2D> = ArrayList()
|
var shape: List<Point2D> = ArrayList()
|
||||||
|
|
||||||
@ -98,4 +97,4 @@ class Extruded(parent: VisualObject?) : VisualLeaf3D(parent), Shape {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun VisualGroup3D.extrude(name: String? = null, action: Extruded.() -> Unit = {}) =
|
fun VisualGroup3D.extrude(name: String? = null, action: Extruded.() -> Unit = {}) =
|
||||||
Extruded(this).apply(action).also { set(name, it) }
|
Extruded().apply(action).also { set(name, it) }
|
@ -0,0 +1,54 @@
|
|||||||
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
|
import hep.dataforge.meta.MetaBuilder
|
||||||
|
import hep.dataforge.meta.MetaItem
|
||||||
|
import hep.dataforge.names.Name
|
||||||
|
import hep.dataforge.vis.common.AbstractVisualObject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A proxy [VisualObject3D] to reuse a template object
|
||||||
|
*/
|
||||||
|
class Proxy(val templateName: Name) : AbstractVisualObject(), VisualObject3D {
|
||||||
|
override var position: Value3 = Value3()
|
||||||
|
override var rotation: Value3 = Value3()
|
||||||
|
override var scale: Value3 = Value3(1f, 1f, 1f)
|
||||||
|
|
||||||
|
val template by lazy { getTemplate() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively search for defined template in the parent
|
||||||
|
*/
|
||||||
|
private fun getTemplate(): VisualObject3D {
|
||||||
|
return (parent as? VisualGroup3D)?.getTemplate(templateName)
|
||||||
|
?: error("Template with name $templateName not found in $parent")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {
|
||||||
|
return if (inherit) {
|
||||||
|
super.getProperty(name, false) ?: template.getProperty(name, false) ?: parent?.getProperty(name, inherit)
|
||||||
|
} else {
|
||||||
|
super.getProperty(name, false) ?: template.getProperty(name, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun MetaBuilder.updateMeta() {
|
||||||
|
//TODO add reference to child
|
||||||
|
updatePosition()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//fun VisualGroup3D.proxy(
|
||||||
|
// templateName: Name,
|
||||||
|
// //name: String? = null,
|
||||||
|
// builder: VisualGroup3D.() -> Unit
|
||||||
|
//): Proxy {
|
||||||
|
// val template = getTemplate(templateName) ?: templates.builder()
|
||||||
|
// return Proxy(this, templateName).also { set(name, it) }
|
||||||
|
//}
|
||||||
|
|
||||||
|
inline fun VisualGroup3D.ref(
|
||||||
|
templateName: Name,
|
||||||
|
name: String? = null,
|
||||||
|
action: Proxy.() -> Unit = {}
|
||||||
|
) = Proxy(templateName).apply(action).also { set(name, it) }
|
@ -1,34 +0,0 @@
|
|||||||
package hep.dataforge.vis.spatial
|
|
||||||
|
|
||||||
import hep.dataforge.meta.MetaBuilder
|
|
||||||
import hep.dataforge.meta.MetaItem
|
|
||||||
import hep.dataforge.names.Name
|
|
||||||
import hep.dataforge.vis.common.AbstractVisualObject
|
|
||||||
import hep.dataforge.vis.common.VisualObject
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A proxy [VisualObject3D] to reuse a [template] object
|
|
||||||
*/
|
|
||||||
class Proxy3D(parent: VisualObject?, val template: VisualObject3D) : AbstractVisualObject(parent), VisualObject3D {
|
|
||||||
override var position: Value3 = Value3()
|
|
||||||
override var rotation: Value3 = Value3()
|
|
||||||
override var scale: Value3 = Value3(1f, 1f, 1f)
|
|
||||||
|
|
||||||
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {
|
|
||||||
return if (inherit) {
|
|
||||||
super.getProperty(name, false) ?: template.getProperty(name, false) ?: parent?.getProperty(name, inherit)
|
|
||||||
} else {
|
|
||||||
super.getProperty(name, false) ?: template.getProperty(name, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun MetaBuilder.updateMeta() {
|
|
||||||
updatePosition()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun VisualGroup3D.proxy(
|
|
||||||
template: VisualObject3D,
|
|
||||||
name: String? = null,
|
|
||||||
action: Proxy3D.() -> Unit = {}
|
|
||||||
) = Proxy3D(this, template).apply(action).also { set(name, it) }
|
|
@ -1,23 +1,23 @@
|
|||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.vis.common.VisualObject
|
|
||||||
import hep.dataforge.vis.common.number
|
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
|
|
||||||
class Sphere(parent: VisualObject?, var radius: Number) : VisualLeaf3D(parent) {
|
class Sphere(
|
||||||
var phiStart by number(0.0)
|
var radius: Float,
|
||||||
var phi by number(2 * PI)
|
var phiStart: Float = 0f,
|
||||||
var thetaStart by number(0.0)
|
var phi: Float = PI2,
|
||||||
var theta by number(PI)
|
var thetaStart: Float = 0f,
|
||||||
}
|
var theta: Float = PI.toFloat()
|
||||||
|
) : VisualLeaf3D()
|
||||||
|
|
||||||
fun VisualGroup3D.sphere(
|
inline fun VisualGroup3D.sphere(
|
||||||
radius: Number,
|
radius: Number,
|
||||||
phi: Number = 2 * PI,
|
phi: Number = 2 * PI,
|
||||||
theta: Number = PI,
|
theta: Number = PI,
|
||||||
name: String? = null,
|
name: String? = null,
|
||||||
action: Sphere.() -> Unit = {}
|
action: Sphere.() -> Unit = {}
|
||||||
) = Sphere(this, radius).apply(action).apply {
|
) = Sphere(
|
||||||
this.phi = phi.toDouble()
|
radius.toFloat(),
|
||||||
this.theta = theta.toDouble()
|
phi = phi.toFloat(),
|
||||||
}.also { set(name, it) }
|
theta = theta.toFloat()
|
||||||
|
).apply(action).also { set(name, it) }
|
@ -1,21 +1,19 @@
|
|||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.vis.common.VisualObject
|
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
import kotlin.math.cos
|
import kotlin.math.cos
|
||||||
import kotlin.math.sin
|
import kotlin.math.sin
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stright tube segment
|
* Straight tube segment
|
||||||
*/
|
*/
|
||||||
class Tube(
|
class Tube(
|
||||||
parent: VisualObject?,
|
|
||||||
var radius: Float,
|
var radius: Float,
|
||||||
var height: Float,
|
var height: Float,
|
||||||
var innerRadius: Float = 0f,
|
var innerRadius: Float = 0f,
|
||||||
var startAngle: Float = 0f,
|
var startAngle: Float = 0f,
|
||||||
var angle: Float = PI2
|
var angle: Float = PI2
|
||||||
) : VisualLeaf3D(parent), Shape {
|
) : VisualLeaf3D(), Shape {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
require(radius > 0)
|
require(radius > 0)
|
||||||
@ -108,7 +106,7 @@ class Tube(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun VisualGroup3D.tube(
|
inline fun VisualGroup3D.tube(
|
||||||
r: Number,
|
r: Number,
|
||||||
height: Number,
|
height: Number,
|
||||||
innerRadius: Number = 0f,
|
innerRadius: Number = 0f,
|
||||||
@ -116,9 +114,7 @@ fun VisualGroup3D.tube(
|
|||||||
angle: Number = 2 * PI,
|
angle: Number = 2 * PI,
|
||||||
name: String? = null,
|
name: String? = null,
|
||||||
block: Tube.() -> Unit = {}
|
block: Tube.() -> Unit = {}
|
||||||
): Tube {
|
): Tube = Tube(
|
||||||
val tube = Tube(
|
|
||||||
this,
|
|
||||||
r.toFloat(),
|
r.toFloat(),
|
||||||
height.toFloat(),
|
height.toFloat(),
|
||||||
innerRadius.toFloat(),
|
innerRadius.toFloat(),
|
||||||
@ -126,6 +122,4 @@ fun VisualGroup3D.tube(
|
|||||||
angle.toFloat()
|
angle.toFloat()
|
||||||
).apply(
|
).apply(
|
||||||
block
|
block
|
||||||
)
|
).also { set(name, it) }
|
||||||
return tube.also { set(name, it) }
|
|
||||||
}
|
|
@ -0,0 +1,40 @@
|
|||||||
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
|
import hep.dataforge.context.AbstractPlugin
|
||||||
|
import hep.dataforge.context.PluginFactory
|
||||||
|
import hep.dataforge.context.PluginTag
|
||||||
|
import hep.dataforge.meta.*
|
||||||
|
import hep.dataforge.names.Name
|
||||||
|
import hep.dataforge.vis.common.VisualPlugin
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
class Visual3DPlugin(meta: Meta) : AbstractPlugin(meta) {
|
||||||
|
override val tag: PluginTag get() = Companion.tag
|
||||||
|
|
||||||
|
override fun provideTop(target: String): Map<Name, Any> {
|
||||||
|
return if (target == VisualPlugin.VISUAL_FACTORY_TYPE) {
|
||||||
|
mapOf()
|
||||||
|
} else {
|
||||||
|
emptyMap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object : PluginFactory<Visual3DPlugin> {
|
||||||
|
override val tag: PluginTag = PluginTag(name = "visual.spatial", group = PluginTag.DATAFORGE_GROUP)
|
||||||
|
override val type: KClass<out Visual3DPlugin> = Visual3DPlugin::class
|
||||||
|
override fun invoke(meta: Meta): Visual3DPlugin = Visual3DPlugin(meta)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun VisualObject3D.update(meta: Meta) {
|
||||||
|
fun Meta.toVector(default: Float = 0f) = Value3(
|
||||||
|
this[VisualObject3D.x].float ?: default,
|
||||||
|
this[VisualObject3D.y].float ?: default,
|
||||||
|
this[VisualObject3D.z].float ?: default
|
||||||
|
)
|
||||||
|
|
||||||
|
meta[VisualObject3D.position].node?.toVector()?.let { position = it }
|
||||||
|
meta[VisualObject3D.rotation].node?.toVector()?.let { rotation = it }
|
||||||
|
meta[VisualObject3D.scale].node?.toVector(1f)?.let { scale = it }
|
||||||
|
meta["properties"].node?.let { configure(it) }
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
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.AbstractVisualObject
|
import hep.dataforge.vis.common.AbstractVisualObject
|
||||||
@ -61,18 +62,29 @@ interface VisualObject3D : VisualObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class VisualLeaf3D(parent: VisualObject?) : AbstractVisualObject(parent), VisualObject3D, Configurable {
|
abstract class VisualLeaf3D : AbstractVisualObject(), VisualObject3D, Configurable {
|
||||||
override var position: Value3 = Value3()
|
override var position: Value3 = Value3()
|
||||||
override var rotation: Value3 = Value3()
|
override var rotation: Value3 = Value3()
|
||||||
override var scale: Value3 = Value3(1f, 1f, 1f)
|
override var scale: Value3 = Value3(1f, 1f, 1f)
|
||||||
}
|
}
|
||||||
|
|
||||||
class VisualGroup3D(parent: VisualObject? = null) : VisualGroup<VisualObject3D>(parent), VisualObject3D, Configurable {
|
class VisualGroup3D : VisualGroup<VisualObject3D>(), VisualObject3D, Configurable {
|
||||||
|
|
||||||
override var position: Value3 = Value3()
|
override var position: Value3 = Value3()
|
||||||
override var rotation: Value3 = Value3()
|
override var rotation: Value3 = Value3()
|
||||||
override var scale: Value3 = Value3(1f, 1f, 1f)
|
override var scale: Value3 = Value3(1f, 1f, 1f)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A container for templates visible inside this group
|
||||||
|
*/
|
||||||
|
var templates: VisualGroup3D? = null
|
||||||
|
set(value) {
|
||||||
|
value?.parent = this
|
||||||
|
field = value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getTemplate(name: Name): VisualObject3D? = templates?.get(name) ?: (parent as? VisualGroup3D)?.getTemplate(name)
|
||||||
|
|
||||||
override fun MetaBuilder.updateMeta() {
|
override fun MetaBuilder.updateMeta() {
|
||||||
updatePosition()
|
updatePosition()
|
||||||
updateChildren()
|
updateChildren()
|
||||||
@ -80,7 +92,7 @@ class VisualGroup3D(parent: VisualObject? = null) : VisualGroup<VisualObject3D>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun VisualGroup3D.group(key: String? = null, action: VisualGroup3D.() -> Unit = {}): VisualGroup3D =
|
fun VisualGroup3D.group(key: String? = null, action: VisualGroup3D.() -> Unit = {}): VisualGroup3D =
|
||||||
VisualGroup3D(this).apply(action).also { set(key, it) }
|
VisualGroup3D().apply(action).also { set(key, it) }
|
||||||
|
|
||||||
fun Output<VisualObject3D>.render(meta: Meta = EmptyMeta, action: VisualGroup3D.() -> Unit) =
|
fun Output<VisualObject3D>.render(meta: Meta = EmptyMeta, action: VisualGroup3D.() -> Unit) =
|
||||||
render(VisualGroup3D().apply(action), meta)
|
render(VisualGroup3D().apply(action), meta)
|
||||||
|
@ -10,7 +10,7 @@ import kotlin.test.assertEquals
|
|||||||
class ConvexTest {
|
class ConvexTest {
|
||||||
@Test
|
@Test
|
||||||
fun testConvexBuilder() {
|
fun testConvexBuilder() {
|
||||||
val group = VisualNode().apply {
|
val group = VisualGroup3D().apply {
|
||||||
convex {
|
convex {
|
||||||
point(50, 50, -50)
|
point(50, 50, -50)
|
||||||
point(50, -50, -50)
|
point(50, -50, -50)
|
||||||
@ -25,7 +25,7 @@ class ConvexTest {
|
|||||||
|
|
||||||
val convex = group.first() as Convex
|
val convex = group.first() as Convex
|
||||||
|
|
||||||
val pointsNode = convex.config["points"].node
|
val pointsNode = convex.toMeta()["points"].node
|
||||||
|
|
||||||
assertEquals(8, pointsNode?.items?.count())
|
assertEquals(8, pointsNode?.items?.count())
|
||||||
val points = pointsNode?.getAll("point".toName())
|
val points = pointsNode?.getAll("point".toName())
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.vis.common.Colors
|
import hep.dataforge.vis.common.Colors
|
||||||
import hep.dataforge.vis.common.color
|
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -9,7 +8,7 @@ import kotlin.test.assertEquals
|
|||||||
class GroupTest {
|
class GroupTest {
|
||||||
@Test
|
@Test
|
||||||
fun testGroupWithComposite(){
|
fun testGroupWithComposite(){
|
||||||
val group = VisualNode().apply{
|
val group = VisualGroup3D().apply{
|
||||||
union {
|
union {
|
||||||
box(100, 100, 100) {
|
box(100, 100, 100) {
|
||||||
z = 100
|
z = 100
|
||||||
@ -30,7 +29,7 @@ class GroupTest {
|
|||||||
}
|
}
|
||||||
box(100, 100, 100)
|
box(100, 100, 100)
|
||||||
y = 300
|
y = 300
|
||||||
material(Colors.red)
|
color(Colors.red)
|
||||||
}
|
}
|
||||||
subtract{
|
subtract{
|
||||||
box(100, 100, 100) {
|
box(100, 100, 100) {
|
||||||
@ -40,7 +39,7 @@ class GroupTest {
|
|||||||
}
|
}
|
||||||
box(100, 100, 100)
|
box(100, 100, 100)
|
||||||
y = -300
|
y = -300
|
||||||
material(Colors.blue)
|
color(Colors.blue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
|
import hep.dataforge.context.Global
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class SerializationTest {
|
||||||
|
@Test
|
||||||
|
fun testCubeSerialization(){
|
||||||
|
val cube = Box(null,100f,100f,100f).apply{
|
||||||
|
color(222)
|
||||||
|
}
|
||||||
|
val meta = cube.toMeta()
|
||||||
|
println(meta)
|
||||||
|
val newCube = Box(Global,null, meta)
|
||||||
|
assertEquals(cube,newCube)
|
||||||
|
}
|
||||||
|
}
|
@ -37,7 +37,8 @@ include(
|
|||||||
":dataforge-vis-spatial-fx",
|
":dataforge-vis-spatial-fx",
|
||||||
":dataforge-vis-spatial-js",
|
":dataforge-vis-spatial-js",
|
||||||
// ":dataforge-vis-jsroot",
|
// ":dataforge-vis-jsroot",
|
||||||
":dataforge-vis-spatial-gdml"
|
":dataforge-vis-spatial-gdml",
|
||||||
|
":spatial-js-demo"
|
||||||
)
|
)
|
||||||
|
|
||||||
//if(file("../dataforge-core").exists()) {
|
//if(file("../dataforge-core").exists()) {
|
||||||
|
19
spatial-js-demo/build.gradle.kts
Normal file
19
spatial-js-demo/build.gradle.kts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
plugins {
|
||||||
|
id("scientifik.js")
|
||||||
|
//id("kotlin-dce-js")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api(project(":dataforge-vis-spatial-js"))
|
||||||
|
api("info.laht.threekt:threejs-wrapper:0.106-npm-3")
|
||||||
|
testCompile(kotlin("test-js"))
|
||||||
|
}
|
||||||
|
|
||||||
|
//kotlin{
|
||||||
|
// sourceSets["main"].dependencies{
|
||||||
|
// implementation(npm("three","0.106.2"))
|
||||||
|
// implementation(npm("@hi-level/three-csg"))
|
||||||
|
// implementation(npm("style-loader"))
|
||||||
|
// implementation(npm("element-resize-event"))
|
||||||
|
// }
|
||||||
|
//}
|
Loading…
Reference in New Issue
Block a user