forked from kscience/visionforge
GDML optimization
This commit is contained in:
parent
a5eba1789b
commit
b362f86f9b
@ -20,7 +20,7 @@ fun cubes(): GDML = GDML {
|
|||||||
val circle = volume("composite", boxMaterial, smallBox.ref()) {
|
val circle = volume("composite", boxMaterial, smallBox.ref()) {
|
||||||
for (i in 0 until 6) {
|
for (i in 0 until 6) {
|
||||||
physVolume(segmentVolume) {
|
physVolume(segmentVolume) {
|
||||||
name = "segment$i"
|
name = "segment_$i"
|
||||||
positionref = center.ref()
|
positionref = center.ref()
|
||||||
rotation {
|
rotation {
|
||||||
z = 60 * i
|
z = 60 * i
|
||||||
|
@ -10,11 +10,21 @@ import kotlin.test.Test
|
|||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
class GDMLVisualTest {
|
class GDMLVisualTest {
|
||||||
|
val gdml = cubes()
|
||||||
|
|
||||||
|
// @Test
|
||||||
|
// fun testCubesStyles(){
|
||||||
|
// val cubes = gdml.toVision()
|
||||||
|
// val segment = cubes["composite000.segment_0".toName()] as Solid
|
||||||
|
// println(segment.styles)
|
||||||
|
// println(segment.material)
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testPrototypeProperty() {
|
fun testPrototypeProperty() {
|
||||||
val gdml = cubes()
|
|
||||||
val visual = gdml.toVision()
|
val visual = gdml.toVision()
|
||||||
visual["composite000.segment0".toName()]?.setItem(SolidMaterial.MATERIAL_COLOR_KEY, "red".asValue())
|
visual["composite000.segment_0".toName()]?.setItem(SolidMaterial.MATERIAL_COLOR_KEY, "red".asValue())
|
||||||
assertEquals("red", visual["composite000.segment0".toName()]?.getItem(SolidMaterial.MATERIAL_COLOR_KEY).string)
|
assertEquals("red", visual["composite000.segment_0".toName()]?.getItem(SolidMaterial.MATERIAL_COLOR_KEY).string)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -84,7 +84,6 @@ class StyleSheet private constructor(private val styleMap: MutableMap<String, Me
|
|||||||
override fun serialize(encoder: Encoder, value: StyleSheet) {
|
override fun serialize(encoder: Encoder, value: StyleSheet) {
|
||||||
mapSerializer.serialize(encoder, value.items)
|
mapSerializer.serialize(encoder, value.items)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +92,7 @@ class StyleSheet private constructor(private val styleMap: MutableMap<String, Me
|
|||||||
* Add style name to the list of styles to be resolved later. The style with given name does not necessary exist at the moment.
|
* Add style name to the list of styles to be resolved later. The style with given name does not necessary exist at the moment.
|
||||||
*/
|
*/
|
||||||
fun Vision.useStyle(name: String) {
|
fun Vision.useStyle(name: String) {
|
||||||
styles = styles + name
|
styles = properties[Vision.STYLE_KEY].stringList + name
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5,7 +5,6 @@ import hep.dataforge.names.Name
|
|||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
import hep.dataforge.names.toName
|
import hep.dataforge.names.toName
|
||||||
import hep.dataforge.provider.Type
|
import hep.dataforge.provider.Type
|
||||||
import hep.dataforge.values.asValue
|
|
||||||
import hep.dataforge.vision.Vision.Companion.TYPE
|
import hep.dataforge.vision.Vision.Companion.TYPE
|
||||||
import kotlinx.serialization.PolymorphicSerializer
|
import kotlinx.serialization.PolymorphicSerializer
|
||||||
import kotlinx.serialization.Transient
|
import kotlinx.serialization.Transient
|
||||||
@ -63,7 +62,7 @@ interface Vision : Configurable {
|
|||||||
var styles: List<String>
|
var styles: List<String>
|
||||||
get() = properties[STYLE_KEY].stringList
|
get() = properties[STYLE_KEY].stringList
|
||||||
set(value) {
|
set(value) {
|
||||||
setItem(STYLE_KEY,value.map { it.asValue() }.asValue())
|
config[STYLE_KEY] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -6,7 +6,6 @@ import hep.dataforge.names.Name
|
|||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
import hep.dataforge.names.plus
|
import hep.dataforge.names.plus
|
||||||
import hep.dataforge.names.toName
|
import hep.dataforge.names.toName
|
||||||
import hep.dataforge.vision.get
|
|
||||||
import hep.dataforge.vision.set
|
import hep.dataforge.vision.set
|
||||||
import hep.dataforge.vision.solid.*
|
import hep.dataforge.vision.solid.*
|
||||||
import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY
|
import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY
|
||||||
@ -27,6 +26,7 @@ class GDMLTransformer(val root: GDML) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var lUnit: LUnit = LUnit.MM
|
var lUnit: LUnit = LUnit.MM
|
||||||
|
var aUnit: AUnit = AUnit.RADIAN
|
||||||
|
|
||||||
var solidAction: (GDMLSolid) -> Action = { Action.CACHE }
|
var solidAction: (GDMLSolid) -> Action = { Action.CACHE }
|
||||||
var volumeAction: (GDMLGroup) -> Action = { Action.CACHE }
|
var volumeAction: (GDMLGroup) -> Action = { Action.CACHE }
|
||||||
@ -65,10 +65,6 @@ class GDMLTransformer(val root: GDML) {
|
|||||||
|
|
||||||
obj.solidConfiguration(parent, solid)
|
obj.solidConfiguration(parent, solid)
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// internal fun solidAdded(solid: GDMLSolid) {
|
|
||||||
// solidCounter[solid.name] = (solidCounter[solid.name] ?: 0) + 1
|
|
||||||
// }
|
|
||||||
|
|
||||||
var onFinish: GDMLTransformer.() -> Unit = {}
|
var onFinish: GDMLTransformer.() -> Unit = {}
|
||||||
|
|
||||||
@ -94,6 +90,7 @@ class GDMLTransformer(val root: GDML) {
|
|||||||
|
|
||||||
private fun Solid.withPosition(
|
private fun Solid.withPosition(
|
||||||
lUnit: LUnit,
|
lUnit: LUnit,
|
||||||
|
aUnit: AUnit = AUnit.RADIAN,
|
||||||
newPos: GDMLPosition? = null,
|
newPos: GDMLPosition? = null,
|
||||||
newRotation: GDMLRotation? = null,
|
newRotation: GDMLRotation? = null,
|
||||||
newScale: GDMLScale? = null
|
newScale: GDMLScale? = null
|
||||||
@ -105,7 +102,7 @@ private fun Solid.withPosition(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
newRotation?.let {
|
newRotation?.let {
|
||||||
val point = Point3D(it.x(), it.y(), it.z())
|
val point = Point3D(it.x(aUnit), it.y(aUnit), it.z(aUnit))
|
||||||
if (rotation != null || point != World.ZERO) {
|
if (rotation != null || point != World.ZERO) {
|
||||||
rotation = point
|
rotation = point
|
||||||
}
|
}
|
||||||
@ -120,6 +117,13 @@ private fun Solid.withPosition(
|
|||||||
//TODO convert units if needed
|
//TODO convert units if needed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun Solid.withPosition(context: GDMLTransformer, physVolume: GDMLPhysVolume) = withPosition(
|
||||||
|
context.lUnit, context.aUnit,
|
||||||
|
physVolume.resolvePosition(context.root),
|
||||||
|
physVolume.resolveRotation(context.root),
|
||||||
|
physVolume.resolveScale(context.root)
|
||||||
|
)
|
||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
private inline operator fun Number.times(d: Double) = toDouble() * d
|
private inline operator fun Number.times(d: Double) = toDouble() * d
|
||||||
|
|
||||||
@ -129,8 +133,7 @@ private inline operator fun Number.times(f: Float) = toFloat() * f
|
|||||||
private fun SolidGroup.addSolid(
|
private fun SolidGroup.addSolid(
|
||||||
context: GDMLTransformer,
|
context: GDMLTransformer,
|
||||||
solid: GDMLSolid,
|
solid: GDMLSolid,
|
||||||
name: String = "",
|
name: String = ""
|
||||||
block: Solid.() -> Unit = {}
|
|
||||||
): Solid {
|
): Solid {
|
||||||
//context.solidAdded(solid)
|
//context.solidAdded(solid)
|
||||||
val lScale = solid.lscale(context.lUnit)
|
val lScale = solid.lscale(context.lUnit)
|
||||||
@ -168,11 +171,10 @@ private fun SolidGroup.addSolid(
|
|||||||
}
|
}
|
||||||
is GDMLScaledSolid -> {
|
is GDMLScaledSolid -> {
|
||||||
//Add solid with modified scale
|
//Add solid with modified scale
|
||||||
val innerSolid = solid.solidref.resolve(context.root)
|
val innerSolid: GDMLSolid = solid.solidref.resolve(context.root)
|
||||||
?: error("Solid with tag ${solid.solidref.ref} for scaled solid ${solid.name} not defined")
|
?: error("Solid with tag ${solid.solidref.ref} for scaled solid ${solid.name} not defined")
|
||||||
|
|
||||||
addSolid(context, innerSolid, name) {
|
addSolid(context, innerSolid, name).apply {
|
||||||
block()
|
|
||||||
scaleX *= solid.scale.x.toFloat()
|
scaleX *= solid.scale.x.toFloat()
|
||||||
scaleY *= solid.scale.y.toFloat()
|
scaleY *= solid.scale.y.toFloat()
|
||||||
scaleZ = solid.scale.z.toFloat()
|
scaleZ = solid.scale.z.toFloat()
|
||||||
@ -199,8 +201,8 @@ private fun SolidGroup.addSolid(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is GDMLBoolSolid -> {
|
is GDMLBoolSolid -> {
|
||||||
val first = solid.first.resolve(context.root) ?: error("")
|
val first: GDMLSolid = solid.first.resolve(context.root) ?: error("")
|
||||||
val second = solid.second.resolve(context.root) ?: error("")
|
val second: GDMLSolid = solid.second.resolve(context.root) ?: error("")
|
||||||
val type: CompositeType = when (solid) {
|
val type: CompositeType = when (solid) {
|
||||||
is GDMLUnion -> CompositeType.UNION
|
is GDMLUnion -> CompositeType.UNION
|
||||||
is GDMLSubtraction -> CompositeType.SUBTRACT
|
is GDMLSubtraction -> CompositeType.SUBTRACT
|
||||||
@ -208,54 +210,51 @@ private fun SolidGroup.addSolid(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return composite(type, name) {
|
return composite(type, name) {
|
||||||
addSolid(context, first) {
|
addSolid(context, first).withPosition(
|
||||||
withPosition(
|
context.lUnit, context.aUnit,
|
||||||
context.lUnit,
|
solid.resolveFirstPosition(context.root),
|
||||||
solid.resolveFirstPosition(context.root),
|
solid.resolveFirstRotation(context.root),
|
||||||
solid.resolveFirstRotation(context.root),
|
null
|
||||||
null
|
)
|
||||||
)
|
|
||||||
}
|
addSolid(context, second).withPosition(
|
||||||
addSolid(context, second) {
|
context.lUnit, context.aUnit,
|
||||||
withPosition(
|
solid.resolvePosition(context.root),
|
||||||
context.lUnit,
|
solid.resolveRotation(context.root),
|
||||||
solid.resolvePosition(context.root),
|
null
|
||||||
solid.resolveRotation(context.root),
|
)
|
||||||
null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> error("Renderer for $solid not supported yet")
|
else -> error("Renderer for $solid not supported yet")
|
||||||
}.apply(block)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private val solidsName = "solids".asName()
|
||||||
|
|
||||||
private fun SolidGroup.addSolidWithCaching(
|
private fun SolidGroup.addSolidWithCaching(
|
||||||
context: GDMLTransformer,
|
context: GDMLTransformer,
|
||||||
solid: GDMLSolid,
|
solid: GDMLSolid,
|
||||||
volume: GDMLVolume,
|
|
||||||
name: String = solid.name
|
name: String = solid.name
|
||||||
) {
|
): Solid? {
|
||||||
when (context.solidAction(solid)) {
|
return when (context.solidAction(solid)) {
|
||||||
GDMLTransformer.Action.ACCEPT -> {
|
GDMLTransformer.Action.ACCEPT -> {
|
||||||
addSolid(context, solid, name) {
|
addSolid(context, solid, name)
|
||||||
context.configureSolid(this, volume, solid)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
GDMLTransformer.Action.CACHE -> {
|
GDMLTransformer.Action.CACHE -> {
|
||||||
if (context.proto[solid.name] == null) {
|
val fullName = solidsName + solid.name.asName()
|
||||||
context.proto.addSolid(context, solid, name) {
|
if (context.proto[fullName] == null) {
|
||||||
context.configureSolid(this, volume, solid)
|
val parent = (context.proto[solidsName] as? SolidGroup) ?: context.proto.group(solidsName)
|
||||||
}
|
parent.addSolid(context, solid, solid.name)
|
||||||
}
|
}
|
||||||
ref(solid.name.asName(), name)
|
ref(fullName, name)
|
||||||
}
|
}
|
||||||
GDMLTransformer.Action.REJECT -> {
|
GDMLTransformer.Action.REJECT -> {
|
||||||
//ignore
|
//ignore
|
||||||
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val volumesName = "volumes".asName()
|
private val volumesName = "volumes".asName()
|
||||||
@ -268,31 +267,20 @@ private fun SolidGroup.addPhysicalVolume(
|
|||||||
?: error("Volume with ref ${physVolume.volumeref.ref} could not be resolved")
|
?: error("Volume with ref ${physVolume.volumeref.ref} could not be resolved")
|
||||||
|
|
||||||
// a special case for single solid volume
|
// a special case for single solid volume
|
||||||
// if (volume is GDMLVolume && volume.physVolumes.isEmpty() && volume.placement == null) {
|
if (volume is GDMLVolume && volume.physVolumes.isEmpty() && volume.placement == null) {
|
||||||
// val solid = volume.solidref.resolve(context.root)
|
val solid = volume.solidref.resolve(context.root)
|
||||||
// ?: error("Solid with tag ${volume.solidref.ref} for volume ${volume.name} not defined")
|
?: error("Solid with tag ${volume.solidref.ref} for volume ${volume.name} not defined")
|
||||||
// addSolidWithCaching(context, solid, volume, physVolume.name ?: "").apply {
|
addSolidWithCaching(context, solid, physVolume.name ?: "")?.apply {
|
||||||
// withPosition(
|
context.configureSolid(this, volume, solid)
|
||||||
// context.lUnit,
|
withPosition(context, physVolume)
|
||||||
// physVolume.resolvePosition(context.root),
|
}
|
||||||
// physVolume.resolveRotation(context.root),
|
return
|
||||||
// physVolume.resolveScale(context.root)
|
}
|
||||||
// )
|
|
||||||
// }
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
when (context.volumeAction(volume)) {
|
when (context.volumeAction(volume)) {
|
||||||
GDMLTransformer.Action.ACCEPT -> {
|
GDMLTransformer.Action.ACCEPT -> {
|
||||||
val group: SolidGroup = volume(context, volume)
|
val group: SolidGroup = volume(context, volume)
|
||||||
this[physVolume.name ?: ""] = group.apply {
|
this[physVolume.name ?: ""] = group.withPosition(context, physVolume)
|
||||||
withPosition(
|
|
||||||
context.lUnit,
|
|
||||||
physVolume.resolvePosition(context.root),
|
|
||||||
physVolume.resolveRotation(context.root),
|
|
||||||
physVolume.resolveScale(context.root)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
GDMLTransformer.Action.CACHE -> {
|
GDMLTransformer.Action.CACHE -> {
|
||||||
val fullName = volumesName + volume.name.asName()
|
val fullName = volumesName + volume.name.asName()
|
||||||
@ -300,14 +288,7 @@ private fun SolidGroup.addPhysicalVolume(
|
|||||||
context.proto[fullName] = volume(context, volume)
|
context.proto[fullName] = volume(context, volume)
|
||||||
}
|
}
|
||||||
|
|
||||||
this[physVolume.name ?: ""] = Proxy(this, fullName).apply {
|
this[physVolume.name ?: ""] = Proxy(this, fullName).withPosition(context, physVolume)
|
||||||
withPosition(
|
|
||||||
context.lUnit,
|
|
||||||
physVolume.resolvePosition(context.root),
|
|
||||||
physVolume.resolveRotation(context.root),
|
|
||||||
physVolume.resolveScale(context.root)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
GDMLTransformer.Action.REJECT -> {
|
GDMLTransformer.Action.REJECT -> {
|
||||||
//ignore
|
//ignore
|
||||||
@ -326,8 +307,6 @@ private fun SolidGroup.addDivisionVolume(
|
|||||||
set(Name.EMPTY, volume(context, volume))
|
set(Name.EMPTY, volume(context, volume))
|
||||||
}
|
}
|
||||||
|
|
||||||
//private val solidsName = "solids".asName()
|
|
||||||
|
|
||||||
private fun volume(
|
private fun volume(
|
||||||
context: GDMLTransformer,
|
context: GDMLTransformer,
|
||||||
group: GDMLGroup
|
group: GDMLGroup
|
||||||
@ -336,7 +315,9 @@ private fun volume(
|
|||||||
val solid: GDMLSolid = group.solidref.resolve(context.root)
|
val solid: GDMLSolid = 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")
|
||||||
|
|
||||||
addSolidWithCaching(context, solid, group)
|
addSolidWithCaching(context, solid)?.apply {
|
||||||
|
context.configureSolid(this, group, solid)
|
||||||
|
}
|
||||||
|
|
||||||
when (val vol: GDMLPlacement? = group.placement) {
|
when (val vol: GDMLPlacement? = group.placement) {
|
||||||
is GDMLPhysVolume -> addPhysicalVolume(context, vol)
|
is GDMLPhysVolume -> addPhysicalVolume(context, vol)
|
||||||
|
@ -5,7 +5,6 @@ package hep.dataforge.vision.solid
|
|||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
import hep.dataforge.meta.descriptors.NodeDescriptor
|
import hep.dataforge.meta.descriptors.NodeDescriptor
|
||||||
import hep.dataforge.names.*
|
import hep.dataforge.names.*
|
||||||
import hep.dataforge.values.asValue
|
|
||||||
import hep.dataforge.vision.*
|
import hep.dataforge.vision.*
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@ -13,36 +12,8 @@ import kotlinx.serialization.Transient
|
|||||||
import kotlinx.serialization.UseSerializers
|
import kotlinx.serialization.UseSerializers
|
||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
|
|
||||||
|
abstract class AbstractProxy : AbstractVision(), VisionGroup {
|
||||||
class AbstractProxy
|
abstract val prototype: Vision
|
||||||
|
|
||||||
/**
|
|
||||||
* A proxy [Solid] to reuse a template object
|
|
||||||
*/
|
|
||||||
@Serializable
|
|
||||||
@SerialName("solid.proxy")
|
|
||||||
class Proxy private constructor(
|
|
||||||
val templateName: Name
|
|
||||||
) : AbstractVision(), VisionGroup, Solid {
|
|
||||||
|
|
||||||
constructor(parent: SolidGroup, templateName: Name) : this(templateName) {
|
|
||||||
this.parent = parent
|
|
||||||
}
|
|
||||||
|
|
||||||
override var position: Point3D? = null
|
|
||||||
override var rotation: Point3D? = null
|
|
||||||
override var scale: Point3D? = null
|
|
||||||
|
|
||||||
override var properties: Config? = null
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Recursively search for defined template in the parent
|
|
||||||
*/
|
|
||||||
val prototype: Solid
|
|
||||||
get() = (parent as? SolidGroup)?.getPrototype(templateName)
|
|
||||||
?: error("Prototype with name $templateName not found in $parent")
|
|
||||||
|
|
||||||
override val styleSheet: StyleSheet get() = parent?.styleSheet ?: StyleSheet(this)
|
|
||||||
|
|
||||||
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {
|
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {
|
||||||
return if (inherit) {
|
return if (inherit) {
|
||||||
@ -61,24 +32,11 @@ class Proxy private constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val children: Map<NameToken, ProxyChild>
|
override var styles: List<String>
|
||||||
get() = (prototype as? VisionGroup)?.children
|
get() = properties[Vision.STYLE_KEY].stringList + prototype.styles
|
||||||
?.filter { !it.key.toString().startsWith("@") }
|
set(value) {
|
||||||
?.mapValues {
|
config[Vision.STYLE_KEY] = value
|
||||||
ProxyChild(it.key.asName())
|
}
|
||||||
} ?: emptyMap()
|
|
||||||
|
|
||||||
@Transient
|
|
||||||
private val propertyCache: HashMap<Name, Config> = HashMap()
|
|
||||||
|
|
||||||
fun childPropertyName(childName: Name, propertyName: Name): Name {
|
|
||||||
return NameToken(PROXY_CHILD_PROPERTY_PREFIX, childName.toString()) + propertyName
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun prototypeFor(name: Name): Vision {
|
|
||||||
return (prototype as? VisionGroup)?.get(name)
|
|
||||||
?: error("Prototype with name $name not found in $this")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getAllProperties(): Laminate =
|
override fun getAllProperties(): Laminate =
|
||||||
Laminate(properties, allStyles, prototype.getAllProperties(), parent?.getAllProperties())
|
Laminate(properties, allStyles, prototype.getAllProperties(), parent?.getAllProperties())
|
||||||
@ -87,29 +45,77 @@ class Proxy private constructor(
|
|||||||
//do nothing
|
//do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val descriptor: NodeDescriptor? get() = prototype.descriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A proxy [Solid] to reuse a template object
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
@SerialName("solid.proxy")
|
||||||
|
class Proxy private constructor(
|
||||||
|
val templateName: Name
|
||||||
|
) : AbstractProxy(), Solid {
|
||||||
|
|
||||||
|
constructor(parent: SolidGroup, templateName: Name) : this(templateName) {
|
||||||
|
this.parent = parent
|
||||||
|
}
|
||||||
|
|
||||||
|
override var position: Point3D? = null
|
||||||
|
override var rotation: Point3D? = null
|
||||||
|
override var scale: Point3D? = null
|
||||||
|
|
||||||
|
override var properties: Config? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively search for defined template in the parent
|
||||||
|
*/
|
||||||
|
override val prototype: Solid
|
||||||
|
get() = (parent as? SolidGroup)?.getPrototype(templateName)
|
||||||
|
?: error("Prototype with name $templateName not found in $parent")
|
||||||
|
|
||||||
|
override val styleSheet: StyleSheet get() = parent?.styleSheet ?: StyleSheet(this)
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
private val propertyCache: HashMap<Name, Config> = HashMap()
|
||||||
|
|
||||||
|
|
||||||
|
override val children: Map<NameToken, Proxy.ProxyChild>
|
||||||
|
get() = (prototype as? VisionGroup)?.children
|
||||||
|
?.filter { !it.key.toString().startsWith("@") }
|
||||||
|
?.mapValues {
|
||||||
|
ProxyChild(it.key.asName())
|
||||||
|
} ?: emptyMap()
|
||||||
|
|
||||||
|
private fun childPropertyName(childName: Name, propertyName: Name): Name {
|
||||||
|
return NameToken(PROXY_CHILD_PROPERTY_PREFIX, childName.toString()) + propertyName
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun prototypeFor(name: Name): Vision {
|
||||||
|
return (prototype as? VisionGroup)?.get(name)
|
||||||
|
?: error("Prototype with name $name not found in $this")
|
||||||
|
}
|
||||||
|
|
||||||
|
override val descriptor: NodeDescriptor? get() = prototype.descriptor
|
||||||
|
|
||||||
//override fun findAllStyles(): Laminate = Laminate((styles + prototype.styles).mapNotNull { findStyle(it) })
|
//override fun findAllStyles(): Laminate = Laminate((styles + prototype.styles).mapNotNull { findStyle(it) })
|
||||||
|
|
||||||
override var styles: List<String>
|
/**
|
||||||
get() = properties[Vision.STYLE_KEY].stringList + prototype.styles
|
* A ProxyChild is created temporarily only to interact with properties, it does not store any values
|
||||||
set(value) {
|
* (properties are stored in external cache) and created and destroyed on-demand).
|
||||||
setItem(Vision.STYLE_KEY, value.map { it.asValue() }.asValue())
|
*/
|
||||||
}
|
inner class ProxyChild(val name: Name) : AbstractProxy() {
|
||||||
|
|
||||||
override val descriptor: NodeDescriptor?
|
override val prototype: Vision get() = prototypeFor(name)
|
||||||
get() = prototype.descriptor
|
|
||||||
|
|
||||||
inner class ProxyChild(val name: Name) : AbstractVision(), VisionGroup {
|
|
||||||
|
|
||||||
val prototype: Vision get() = prototypeFor(name)
|
|
||||||
|
|
||||||
override val styleSheet: StyleSheet get() = this@Proxy.styleSheet
|
override val styleSheet: StyleSheet get() = this@Proxy.styleSheet
|
||||||
|
|
||||||
override val children: Map<NameToken, Vision>
|
override val children: Map<NameToken, Vision>
|
||||||
get() = (prototype as? VisionGroup)?.children?.mapValues { (key, _) ->
|
get() = (prototype as? VisionGroup)?.children
|
||||||
ProxyChild(
|
?.filter { !it.key.toString().startsWith("@") }
|
||||||
name + key.asName()
|
?.mapValues { (key, _) ->
|
||||||
)
|
ProxyChild(name + key.asName())
|
||||||
} ?: emptyMap()
|
} ?: emptyMap()
|
||||||
|
|
||||||
override var properties: Config?
|
override var properties: Config?
|
||||||
get() = propertyCache[name]
|
get() = propertyCache[name]
|
||||||
@ -128,39 +134,6 @@ class Proxy private constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {
|
|
||||||
return if (inherit) {
|
|
||||||
sequence {
|
|
||||||
yield(properties?.get(name))
|
|
||||||
yieldAll(getStyleItems(name))
|
|
||||||
yield(prototype.getItem(name))
|
|
||||||
yield(parent?.getProperty(name, inherit))
|
|
||||||
}.merge()
|
|
||||||
} else {
|
|
||||||
sequence {
|
|
||||||
yield(properties?.get(name))
|
|
||||||
yieldAll(getStyleItems(name))
|
|
||||||
yield(prototype.getProperty(name, false))
|
|
||||||
}.merge()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun attachChildren() {
|
|
||||||
//do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getAllProperties(): Laminate =
|
|
||||||
Laminate(properties, allStyles, prototype.getAllProperties(), parent?.getAllProperties())
|
|
||||||
|
|
||||||
|
|
||||||
override var styles: List<String>
|
|
||||||
get() = properties[Vision.STYLE_KEY].stringList + prototype.styles
|
|
||||||
set(value) {
|
|
||||||
setItem(Vision.STYLE_KEY, value.map { it.asValue() }.asValue())
|
|
||||||
}
|
|
||||||
|
|
||||||
override val descriptor: NodeDescriptor?
|
|
||||||
get() = prototype.descriptor
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -170,8 +143,7 @@ class Proxy private constructor(
|
|||||||
|
|
||||||
val Vision.prototype: Vision
|
val Vision.prototype: Vision
|
||||||
get() = when (this) {
|
get() = when (this) {
|
||||||
is Proxy -> prototype
|
is AbstractProxy -> prototype
|
||||||
is Proxy.ProxyChild -> prototype
|
|
||||||
else -> this
|
else -> this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,13 +99,14 @@ fun SolidGroup(block: SolidGroup.() -> Unit): SolidGroup {
|
|||||||
tailrec fun PrototypeHolder.getPrototype(name: Name): Solid? =
|
tailrec fun PrototypeHolder.getPrototype(name: Name): Solid? =
|
||||||
prototypes?.get(name) as? Solid ?: (parent as? PrototypeHolder)?.getPrototype(name)
|
prototypes?.get(name) as? Solid ?: (parent as? PrototypeHolder)?.getPrototype(name)
|
||||||
|
|
||||||
|
fun MutableVisionGroup.group(name: Name = Name.EMPTY, action: SolidGroup.() -> Unit = {}): SolidGroup =
|
||||||
|
SolidGroup().apply(action).also { set(name, it) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define a group with given [name], attach it to this parent and return it.
|
* Define a group with given [name], attach it to this parent and return it.
|
||||||
*/
|
*/
|
||||||
fun MutableVisionGroup.group(name: String = "", action: SolidGroup.() -> Unit = {}): SolidGroup =
|
fun MutableVisionGroup.group(name: String, action: SolidGroup.() -> Unit = {}): SolidGroup =
|
||||||
SolidGroup().apply(action).also {
|
SolidGroup().apply(action).also { set(name, it) }
|
||||||
set(name, it)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A special class which works as a holder for prototypes
|
* A special class which works as a holder for prototypes
|
||||||
|
@ -35,19 +35,11 @@ abstract class MeshThreeFactory<in T : Solid>(
|
|||||||
|
|
||||||
//val meshMeta: Meta = obj.properties[Material3D.MATERIAL_KEY]?.node ?: Meta.empty
|
//val meshMeta: Meta = obj.properties[Material3D.MATERIAL_KEY]?.node ?: Meta.empty
|
||||||
|
|
||||||
val mesh = Mesh(geometry, getMaterial(obj, true)).apply {
|
val mesh = Mesh(geometry, null).apply{
|
||||||
matrixAutoUpdate = false
|
matrixAutoUpdate = false
|
||||||
applyEdges(obj)
|
|
||||||
applyWireFrame(obj)
|
|
||||||
|
|
||||||
//set position for mesh
|
//set position for mesh
|
||||||
updatePosition(obj)
|
updatePosition(obj)
|
||||||
|
}.applyProperties(obj)
|
||||||
layers.enable(obj.layer)
|
|
||||||
children.forEach {
|
|
||||||
it.layers.enable(obj.layer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//add listener to object properties
|
//add listener to object properties
|
||||||
obj.onPropertyChange(this) { name ->
|
obj.onPropertyChange(this) { name ->
|
||||||
@ -79,6 +71,16 @@ abstract class MeshThreeFactory<in T : Solid>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Mesh.applyProperties(obj: Solid): Mesh = apply{
|
||||||
|
material = getMaterial(obj, true)
|
||||||
|
applyEdges(obj)
|
||||||
|
applyWireFrame(obj)
|
||||||
|
layers.enable(obj.layer)
|
||||||
|
children.forEach {
|
||||||
|
it.layers.enable(obj.layer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun Mesh.applyEdges(obj: Solid) {
|
fun Mesh.applyEdges(obj: Solid) {
|
||||||
val edges = children.find { it.name == "@edges" } as? LineSegments
|
val edges = children.find { it.name == "@edges" } as? LineSegments
|
||||||
//inherited edges definition, enabled by default
|
//inherited edges definition, enabled by default
|
||||||
|
@ -41,18 +41,6 @@ fun Object3D.updatePosition(obj: Vision) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///**
|
|
||||||
// * Unsafe invocation of a factory
|
|
||||||
// */
|
|
||||||
//operator fun <T : VisualObject3D> ThreeFactory<T>.invoke(obj: Any): Object3D {
|
|
||||||
// if (type.isInstance(obj)) {
|
|
||||||
// @Suppress("UNCHECKED_CAST")
|
|
||||||
// return invoke(obj as T)
|
|
||||||
// } else {
|
|
||||||
// error("The object of type ${obj::class} could not be rendered by this factory")
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update non-position non-geometry property
|
* Update non-position non-geometry property
|
||||||
*/
|
*/
|
||||||
|
@ -4,7 +4,6 @@ import hep.dataforge.names.toName
|
|||||||
import hep.dataforge.vision.solid.Proxy
|
import hep.dataforge.vision.solid.Proxy
|
||||||
import hep.dataforge.vision.solid.Proxy.Companion.PROXY_CHILD_PROPERTY_PREFIX
|
import hep.dataforge.vision.solid.Proxy.Companion.PROXY_CHILD_PROPERTY_PREFIX
|
||||||
import hep.dataforge.vision.solid.Solid
|
import hep.dataforge.vision.solid.Solid
|
||||||
import info.laht.threekt.core.BufferGeometry
|
|
||||||
import info.laht.threekt.core.Object3D
|
import info.laht.threekt.core.Object3D
|
||||||
import info.laht.threekt.objects.Mesh
|
import info.laht.threekt.objects.Mesh
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
@ -14,16 +13,16 @@ class ThreeProxyFactory(val three: ThreePlugin) : ThreeFactory<Proxy> {
|
|||||||
|
|
||||||
override val type: KClass<Proxy> = Proxy::class
|
override val type: KClass<Proxy> = Proxy::class
|
||||||
|
|
||||||
private fun Object3D.replicate(): Object3D {
|
// private fun Object3D.replicate(): Object3D {
|
||||||
return when (this) {
|
// return when (this) {
|
||||||
is Mesh -> Mesh(geometry as BufferGeometry, material)
|
// is Mesh -> Mesh(geometry as BufferGeometry, material)
|
||||||
else -> clone(false)
|
// else -> clone(false)
|
||||||
}.also { obj: Object3D ->
|
// }.also { obj: Object3D ->
|
||||||
children.forEach { child: Object3D ->
|
// children.forEach { child: Object3D ->
|
||||||
obj.add(child.replicate())
|
// obj.add(child.replicate())
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
override fun invoke(obj: Proxy): Object3D {
|
override fun invoke(obj: Proxy): Object3D {
|
||||||
val template = obj.prototype
|
val template = obj.prototype
|
||||||
@ -31,10 +30,13 @@ class ThreeProxyFactory(val three: ThreePlugin) : ThreeFactory<Proxy> {
|
|||||||
three.buildObject3D(template)
|
three.buildObject3D(template)
|
||||||
}
|
}
|
||||||
|
|
||||||
val object3D: Object3D = cachedObject.replicate()
|
val object3D: Object3D = cachedObject.clone()//cachedObject.replicate()
|
||||||
|
|
||||||
object3D.updatePosition(obj)
|
object3D.updatePosition(obj)
|
||||||
|
|
||||||
|
if(object3D is Mesh){
|
||||||
|
object3D.applyProperties(obj)
|
||||||
|
}
|
||||||
|
|
||||||
obj.onPropertyChange(this) { name ->
|
obj.onPropertyChange(this) { name ->
|
||||||
if (name.first()?.body == PROXY_CHILD_PROPERTY_PREFIX) {
|
if (name.first()?.body == PROXY_CHILD_PROPERTY_PREFIX) {
|
||||||
val childName = name.first()?.index?.toName() ?: error("Wrong syntax for proxy child property: '$name'")
|
val childName = name.first()?.index?.toName() ?: error("Wrong syntax for proxy child property: '$name'")
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package hep.dataforge.vision.solid.three
|
package hep.dataforge.vision.solid.three
|
||||||
|
|
||||||
import hep.dataforge.js.requireJS
|
import hep.dataforge.js.requireJS
|
||||||
|
import hep.dataforge.meta.DFExperimental
|
||||||
import hep.dataforge.vision.bootstrap.accordion
|
import hep.dataforge.vision.bootstrap.accordion
|
||||||
import hep.dataforge.vision.bootstrap.entry
|
import hep.dataforge.vision.bootstrap.entry
|
||||||
import hep.dataforge.vision.solid.SolidGroup
|
import hep.dataforge.vision.solid.SolidGroup
|
||||||
@ -31,6 +32,7 @@ private fun saveData(event: Event, fileName: String, mimeType: String = "text/pl
|
|||||||
fileSaver.saveAs(blob, fileName)
|
fileSaver.saveAs(blob, fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(DFExperimental::class)
|
||||||
fun RBuilder.canvasControls(canvas: ThreeCanvas) = accordion("controls") {
|
fun RBuilder.canvasControls(canvas: ThreeCanvas) = accordion("controls") {
|
||||||
entry("Settings") {
|
entry("Settings") {
|
||||||
div("row") {
|
div("row") {
|
||||||
|
@ -33,8 +33,8 @@ import info.laht.threekt.materials.Material
|
|||||||
|
|
||||||
open external class Mesh : Object3D {
|
open external class Mesh : Object3D {
|
||||||
|
|
||||||
constructor(geometry: Geometry, material: Material)
|
constructor(geometry: Geometry?, material: Material?)
|
||||||
constructor(geometry: BufferGeometry, material: Material)
|
constructor(geometry: BufferGeometry?, material: Material?)
|
||||||
|
|
||||||
var geometry: dynamic
|
var geometry: dynamic
|
||||||
var material: Material
|
var material: Material
|
||||||
|
Loading…
Reference in New Issue
Block a user