Finalize serialization refactoring

This commit is contained in:
Alexander Nozik 2020-04-11 21:28:52 +03:00
parent 54c42a6a56
commit e19ec02ff3
26 changed files with 6086 additions and 137 deletions

View File

@ -74,12 +74,41 @@ abstract class AbstractVisualGroup : AbstractVisualObject(),
* Add a static child. Statics could not be found by name, removed or replaced
*/
protected open fun addStatic(child: VisualObject) =
setChild(NameToken("@static(${child.hashCode()})"), child)
set(NameToken("@static(${child.hashCode()})").asName(), child)
protected abstract fun createGroup(): AbstractVisualGroup
/**
* Set this node as parent for given node
*/
protected fun attach(child: VisualObject) {
if (child.parent == null) {
child.parent = this
} else if (child.parent !== this) {
error("Can't reassign existing parent for $child")
}
}
/**
* Recursively create a child group
*/
protected abstract fun createGroup(name: Name): MutableVisualGroup
private fun createGroups(name: Name): AbstractVisualGroup {
return when {
name.isEmpty() -> error("Should be unreachable")
name.length == 1 -> {
val token = name.first()!!
when (val current = children[token]) {
null -> createGroup().also { child ->
attach(child)
setChild(token, child)
}
is AbstractVisualGroup -> current
else -> error("Can't create group with name $name because it exists and not a group")
}
}
else -> createGroups(name.first()!!.asName()).createGroups(name.cutFirst())
}
}
/**
* Add named or unnamed child to the group. If key is null the child is considered unnamed. Both key and value are not
@ -97,16 +126,17 @@ abstract class AbstractVisualGroup : AbstractVisualObject(),
if (child == null) {
removeChild(token)
} else {
attach(child)
setChild(token, child)
}
}
else -> {
//TODO add safety check
val parent = (get(name.cutLast()) as? MutableVisualGroup) ?: createGroup(name.cutLast())
val parent = (get(name.cutLast()) as? MutableVisualGroup) ?: createGroups(name.cutLast())
parent[name.last()!!.asName()] = child
}
}
structureChangeListeners.forEach { it.callback(name, child) }
childrenChanged(name, child)
}
}

View File

@ -15,7 +15,7 @@ internal data class PropertyListener(
abstract class AbstractVisualObject : VisualObject {
@Transient
override var parent: VisualObject? = null
override var parent: VisualGroup? = null
protected abstract var properties: Config?

View File

@ -6,12 +6,14 @@ import hep.dataforge.meta.*
import hep.dataforge.names.Name
import hep.dataforge.names.asName
import kotlinx.serialization.*
import kotlinx.serialization.builtins.MapSerializer
import kotlinx.serialization.builtins.serializer
/**
* A container for styles
*/
@Serializable
class StyleSheet() {
class StyleSheet private constructor(private val styleMap: MutableMap<String, Meta> = LinkedHashMap()) {
@Transient
internal var owner: VisualObject? = null
@ -19,12 +21,10 @@ class StyleSheet() {
this.owner = owner
}
private val styleMap = HashMap<String, Meta>()
val items: Map<String, Meta> get() = styleMap
operator fun get(key: String): Meta? {
return styleMap[key] ?: (owner?.parent as? VisualGroup)?.styleSheet?.get(key)
return styleMap[key] ?: owner?.parent?.styleSheet?.get(key)
}
/**
@ -49,16 +49,19 @@ class StyleSheet() {
set(key, newStyle.seal())
}
companion object: KSerializer<StyleSheet>{
override val descriptor: SerialDescriptor
get() = TODO("Not yet implemented")
@Serializer(StyleSheet::class)
companion object : KSerializer<StyleSheet> {
private val mapSerializer = MapSerializer(String.serializer(), MetaSerializer)
override val descriptor: SerialDescriptor get() = mapSerializer.descriptor
override fun deserialize(decoder: Decoder): StyleSheet {
TODO("Not yet implemented")
val map = mapSerializer.deserialize(decoder)
return StyleSheet(map as? MutableMap<String, Meta> ?: LinkedHashMap(map))
}
override fun serialize(encoder: Encoder, value: StyleSheet) {
TODO("Not yet implemented")
mapSerializer.serialize(encoder, value.items)
}
}

View File

@ -24,7 +24,7 @@ interface VisualObject : Configurable {
* The parent object of this one. If null, this one is a root.
*/
@Transient
var parent: VisualObject?
var parent: VisualGroup?
/**
* All properties including styles and prototypes if present, but without inheritance

View File

@ -3,10 +3,11 @@ package hep.dataforge.vis.spatial.gdml
import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaBuilder
import hep.dataforge.names.Name
import hep.dataforge.names.asName
import hep.dataforge.names.toName
import hep.dataforge.vis.useStyle
import hep.dataforge.vis.spatial.*
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_COLOR_KEY
import hep.dataforge.vis.useStyle
import scientifik.gdml.*
import kotlin.random.Random
@ -68,7 +69,13 @@ class GDMLTransformer(val root: GDML) {
var onFinish: GDMLTransformer.() -> Unit = {}
internal fun finalize(final: VisualGroup3D): VisualGroup3D {
final.prototypes = proto
//final.prototypes = proto
final.prototypes {
proto.children.forEach { (token, item) ->
item.parent = null
set(token.asName(), item)
}
}
styleCache.forEach {
final.styleSheet {
define(it.key.toString(), it.value)

View File

@ -1,5 +1,6 @@
package hep.dataforge.vis.spatial.gdml
import hep.dataforge.meta.JSON_PRETTY
import hep.dataforge.meta.Meta
import hep.dataforge.vis.spatial.*
import kotlinx.serialization.*
@ -157,7 +158,7 @@ fun main() {
}
println(
Json.indented.stringify(
JSON_PRETTY.stringify(
JsonObjectSerializer,
json {
"definitions" to definitions

View File

@ -1,43 +1,29 @@
package hep.dataforge.vis.spatial.gdml
import hep.dataforge.vis.spatial.stringify
import nl.adaptivity.xmlutil.StAXReader
import org.junit.jupiter.api.Test
import scientifik.gdml.GDML
import java.io.File
import java.net.URL
import kotlin.test.Ignore
class TestConvertor {
@Test
@Ignore
fun testBMNGeometry() {
val url = URL("https://drive.google.com/open?id=1w5e7fILMN83JGgB8WANJUYm8OW2s0WVO")
val file = File("D:\\Work\\Projects\\gdml.kt\\gdml-source\\BM@N.gdml")
val stream = if (file.exists()) {
file.inputStream()
} else {
url.openStream()
}
val xmlReader = StAXReader(stream, "UTF-8")
val xml = GDML.format.parse(GDML.serializer(), xmlReader)
xml.toVisual()
}
@Test
@Ignore
fun testCubes() {
val file = File("D:\\Work\\Projects\\gdml.kt\\gdml-source\\cubes.gdml ")
val stream = if (file.exists()) {
file.inputStream()
} else {
return
}
val stream = javaClass.getResourceAsStream("/gdml/BM@N.gdml")
val xmlReader = StAXReader(stream, "UTF-8")
val xml = GDML.format.parse(GDML.serializer(), xmlReader)
val visual = xml.toVisual()
println(visual)
println(visual.stringify())
}
@Test
fun testCubes() {
val stream = javaClass.getResourceAsStream("/gdml/cubes.gdml")
val xmlReader = StAXReader(stream, "UTF-8")
val xml = GDML.format.parse(GDML.serializer(), xmlReader)
val visual = xml.toVisual()
// println(visual)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,254 @@
<gdml>
<define>
<position name="center" x="0.0" y="0.0" z="0.0" unit="cm"/>
<position name="box_position" x="25.0" y="50.0" z="75.0" unit="cm"/>
<rotation name="Rot0" x="0.0" y="0.0" z="0.0" unit="deg"/>
<rotation name="Rot1" x="0.0" y="0.0" z="60.0" unit="deg"/>
<rotation name="Rot2" x="0.0" y="0.0" z="120.0" unit="deg"/>
<rotation name="Rot3" x="0.0" y="0.0" z="180.0" unit="deg"/>
<rotation name="Rot4" x="0.0" y="0.0" z="240.0" unit="deg"/>
<rotation name="Rot5" x="0.0" y="0.0" z="300.0" unit="deg"/>
<rotation name="Rot000" x="0.0" y="0.0" z="0.0" unit="deg"/>
<position name="Pos000" x="-50.0" y="-50.0" z="-50.0" unit="cm"/>
<rotation name="Rot001" x="0.0" y="0.0" z="120.0" unit="deg"/>
<position name="Pos001" x="-50.0" y="-50.0" z="0.0" unit="cm"/>
<rotation name="Rot002" x="0.0" y="0.0" z="240.0" unit="deg"/>
<position name="Pos002" x="-50.0" y="-50.0" z="50.0" unit="cm"/>
<rotation name="Rot010" x="0.0" y="120.0" z="0.0" unit="deg"/>
<position name="Pos010" x="-50.0" y="0.0" z="-50.0" unit="cm"/>
<rotation name="Rot011" x="0.0" y="120.0" z="120.0" unit="deg"/>
<position name="Pos011" x="-50.0" y="0.0" z="0.0" unit="cm"/>
<rotation name="Rot012" x="0.0" y="120.0" z="240.0" unit="deg"/>
<position name="Pos012" x="-50.0" y="0.0" z="50.0" unit="cm"/>
<rotation name="Rot020" x="0.0" y="240.0" z="0.0" unit="deg"/>
<position name="Pos020" x="-50.0" y="50.0" z="-50.0" unit="cm"/>
<rotation name="Rot021" x="0.0" y="240.0" z="120.0" unit="deg"/>
<position name="Pos021" x="-50.0" y="50.0" z="0.0" unit="cm"/>
<rotation name="Rot022" x="0.0" y="240.0" z="240.0" unit="deg"/>
<position name="Pos022" x="-50.0" y="50.0" z="50.0" unit="cm"/>
<rotation name="Rot100" x="120.0" y="0.0" z="0.0" unit="deg"/>
<position name="Pos100" x="0.0" y="-50.0" z="-50.0" unit="cm"/>
<rotation name="Rot101" x="120.0" y="0.0" z="120.0" unit="deg"/>
<position name="Pos101" x="0.0" y="-50.0" z="0.0" unit="cm"/>
<rotation name="Rot102" x="120.0" y="0.0" z="240.0" unit="deg"/>
<position name="Pos102" x="0.0" y="-50.0" z="50.0" unit="cm"/>
<rotation name="Rot110" x="120.0" y="120.0" z="0.0" unit="deg"/>
<position name="Pos110" x="0.0" y="0.0" z="-50.0" unit="cm"/>
<rotation name="Rot111" x="120.0" y="120.0" z="120.0" unit="deg"/>
<position name="Pos111" x="0.0" y="0.0" z="0.0" unit="cm"/>
<rotation name="Rot112" x="120.0" y="120.0" z="240.0" unit="deg"/>
<position name="Pos112" x="0.0" y="0.0" z="50.0" unit="cm"/>
<rotation name="Rot120" x="120.0" y="240.0" z="0.0" unit="deg"/>
<position name="Pos120" x="0.0" y="50.0" z="-50.0" unit="cm"/>
<rotation name="Rot121" x="120.0" y="240.0" z="120.0" unit="deg"/>
<position name="Pos121" x="0.0" y="50.0" z="0.0" unit="cm"/>
<rotation name="Rot122" x="120.0" y="240.0" z="240.0" unit="deg"/>
<position name="Pos122" x="0.0" y="50.0" z="50.0" unit="cm"/>
<rotation name="Rot200" x="240.0" y="0.0" z="0.0" unit="deg"/>
<position name="Pos200" x="50.0" y="-50.0" z="-50.0" unit="cm"/>
<rotation name="Rot201" x="240.0" y="0.0" z="120.0" unit="deg"/>
<position name="Pos201" x="50.0" y="-50.0" z="0.0" unit="cm"/>
<rotation name="Rot202" x="240.0" y="0.0" z="240.0" unit="deg"/>
<position name="Pos202" x="50.0" y="-50.0" z="50.0" unit="cm"/>
<rotation name="Rot210" x="240.0" y="120.0" z="0.0" unit="deg"/>
<position name="Pos210" x="50.0" y="0.0" z="-50.0" unit="cm"/>
<rotation name="Rot211" x="240.0" y="120.0" z="120.0" unit="deg"/>
<position name="Pos211" x="50.0" y="0.0" z="0.0" unit="cm"/>
<rotation name="Rot212" x="240.0" y="120.0" z="240.0" unit="deg"/>
<position name="Pos212" x="50.0" y="0.0" z="50.0" unit="cm"/>
<rotation name="Rot220" x="240.0" y="240.0" z="0.0" unit="deg"/>
<position name="Pos220" x="50.0" y="50.0" z="-50.0" unit="cm"/>
<rotation name="Rot221" x="240.0" y="240.0" z="120.0" unit="deg"/>
<position name="Pos221" x="50.0" y="50.0" z="0.0" unit="cm"/>
<rotation name="Rot222" x="240.0" y="240.0" z="240.0" unit="deg"/>
<position name="Pos222" x="50.0" y="50.0" z="50.0" unit="cm"/>
</define>
<materials/>
<solids>
<tube aunit="degree" name="segment" rmax="20.0" z="5.0" rmin="17.0" startphi="0.0" deltaphi="60.0"/>
<box name="cave" x="200.0" y="200.0" z="200.0"/>
<box name="box" x="30.0" y="30.0" z="30.0"/>
</solids>
<structure>
<volume name="segment_vol">
<materialref ref="G4_WATER"/>
<solidref ref="segment"/>
</volume>
<volume name="composite">
<physvol name="segment_0">
<volumeref ref="segment_vol"/>
<positionref ref="center"/>
<rotationref ref="Rot0"/>
</physvol>
<physvol name="segment_1">
<volumeref ref="segment_vol"/>
<positionref ref="center"/>
<rotationref ref="Rot1"/>
</physvol>
<physvol name="segment_2">
<volumeref ref="segment_vol"/>
<positionref ref="center"/>
<rotationref ref="Rot2"/>
</physvol>
<physvol name="segment_3">
<volumeref ref="segment_vol"/>
<positionref ref="center"/>
<rotationref ref="Rot3"/>
</physvol>
<physvol name="segment_4">
<volumeref ref="segment_vol"/>
<positionref ref="center"/>
<rotationref ref="Rot4"/>
</physvol>
<physvol name="segment_5">
<volumeref ref="segment_vol"/>
<positionref ref="center"/>
<rotationref ref="Rot5"/>
</physvol>
<materialref ref="G4_AIR"/>
<solidref ref="box"/>
</volume>
<volume name="world">
<physvol name="composite_000">
<volumeref ref="composite"/>
<positionref ref="Pos000"/>
<rotationref ref="Rot000"/>
</physvol>
<physvol name="composite_001">
<volumeref ref="composite"/>
<positionref ref="Pos001"/>
<rotationref ref="Rot001"/>
</physvol>
<physvol name="composite_002">
<volumeref ref="composite"/>
<positionref ref="Pos002"/>
<rotationref ref="Rot002"/>
</physvol>
<physvol name="composite_003">
<volumeref ref="composite"/>
<positionref ref="Pos010"/>
<rotationref ref="Rot010"/>
</physvol>
<physvol name="composite_004">
<volumeref ref="composite"/>
<positionref ref="Pos011"/>
<rotationref ref="Rot011"/>
</physvol>
<physvol name="composite_005">
<volumeref ref="composite"/>
<positionref ref="Pos012"/>
<rotationref ref="Rot012"/>
</physvol>
<physvol name="composite_006">
<volumeref ref="composite"/>
<positionref ref="Pos020"/>
<rotationref ref="Rot020"/>
</physvol>
<physvol>
<volumeref ref="composite"/>
<positionref ref="Pos021"/>
<rotationref ref="Rot021"/>
</physvol>
<physvol>
<volumeref ref="composite"/>
<positionref ref="Pos022"/>
<rotationref ref="Rot022"/>
</physvol>
<physvol>
<volumeref ref="composite"/>
<positionref ref="Pos100"/>
<rotationref ref="Rot100"/>
</physvol>
<physvol>
<volumeref ref="composite"/>
<positionref ref="Pos101"/>
<rotationref ref="Rot101"/>
</physvol>
<physvol>
<volumeref ref="composite"/>
<positionref ref="Pos102"/>
<rotationref ref="Rot102"/>
</physvol>
<physvol>
<volumeref ref="composite"/>
<positionref ref="Pos110"/>
<rotationref ref="Rot110"/>
</physvol>
<physvol>
<volumeref ref="composite"/>
<positionref ref="Pos111"/>
<rotationref ref="Rot111"/>
</physvol>
<physvol>
<volumeref ref="composite"/>
<positionref ref="Pos112"/>
<rotationref ref="Rot112"/>
</physvol>
<physvol>
<volumeref ref="composite"/>
<positionref ref="Pos120"/>
<rotationref ref="Rot120"/>
</physvol>
<physvol>
<volumeref ref="composite"/>
<positionref ref="Pos121"/>
<rotationref ref="Rot121"/>
</physvol>
<physvol>
<volumeref ref="composite"/>
<positionref ref="Pos122"/>
<rotationref ref="Rot122"/>
</physvol>
<physvol>
<volumeref ref="composite"/>
<positionref ref="Pos200"/>
<rotationref ref="Rot200"/>
</physvol>
<physvol>
<volumeref ref="composite"/>
<positionref ref="Pos201"/>
<rotationref ref="Rot201"/>
</physvol>
<physvol>
<volumeref ref="composite"/>
<positionref ref="Pos202"/>
<rotationref ref="Rot202"/>
</physvol>
<physvol>
<volumeref ref="composite"/>
<positionref ref="Pos210"/>
<rotationref ref="Rot210"/>
</physvol>
<physvol>
<volumeref ref="composite"/>
<positionref ref="Pos211"/>
<rotationref ref="Rot211"/>
</physvol>
<physvol>
<volumeref ref="composite"/>
<positionref ref="Pos212"/>
<rotationref ref="Rot212"/>
</physvol>
<physvol>
<volumeref ref="composite"/>
<positionref ref="Pos220"/>
<rotationref ref="Rot220"/>
</physvol>
<physvol>
<volumeref ref="composite"/>
<positionref ref="Pos221"/>
<rotationref ref="Rot221"/>
</physvol>
<physvol>
<volumeref ref="composite"/>
<positionref ref="Pos222"/>
<rotationref ref="Rot222"/>
</physvol>
<materialref ref="G4_AIR"/>
<solidref ref="cave"/>
</volume>
</structure>
<setup name="Default" version="1.0">
<world ref="world"/>
</setup>
</gdml>

View File

@ -6,10 +6,7 @@ import hep.dataforge.meta.Config
import hep.dataforge.meta.Meta
import hep.dataforge.meta.float
import hep.dataforge.meta.get
import hep.dataforge.vis.AbstractVisualObject
import hep.dataforge.vis.VisualFactory
import hep.dataforge.vis.VisualObject
import hep.dataforge.vis.set
import hep.dataforge.vis.*
import hep.dataforge.vis.spatial.Box.Companion.TYPE_NAME
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@ -67,7 +64,7 @@ class Box(
}
}
inline fun VisualGroup3D.box(
inline fun MutableVisualGroup.box(
xSize: Number,
ySize: Number,
zSize: Number,

View File

@ -4,8 +4,8 @@ package hep.dataforge.vis.spatial
import hep.dataforge.meta.Config
import hep.dataforge.meta.update
import hep.dataforge.vis.AbstractVisualObject
import hep.dataforge.vis.set
import hep.dataforge.names.NameToken
import hep.dataforge.vis.*
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
@ -22,7 +22,7 @@ class Composite(
val compositeType: CompositeType,
val first: VisualObject3D,
val second: VisualObject3D
) : AbstractVisualObject(), VisualObject3D {
) : AbstractVisualObject(), VisualObject3D, VisualGroup {
init {
first.parent = this
@ -34,9 +34,15 @@ class Composite(
override var scale: Point3D? = null
override var properties: Config? = null
override val children: Map<NameToken, VisualObject>
get() = mapOf(NameToken("first") to first, NameToken("second") to second)
override val styleSheet: StyleSheet?
get() = null
}
inline fun VisualGroup3D.composite(
inline fun MutableVisualGroup.composite(
type: CompositeType,
name: String = "",
builder: VisualGroup3D.() -> Unit
@ -48,24 +54,24 @@ inline fun VisualGroup3D.composite(
it.config.update(group.config)
//it.material = group.material
if(group.position!=null) {
if (group.position != null) {
it.position = group.position
}
if(group.rotation!=null) {
if (group.rotation != null) {
it.rotation = group.rotation
}
if(group.scale!=null) {
if (group.scale != null) {
it.scale = group.scale
}
set(name, it)
}
}
fun VisualGroup3D.union(name: String = "", builder: VisualGroup3D.() -> Unit) =
inline fun MutableVisualGroup.union(name: String = "", builder: VisualGroup3D.() -> Unit) =
composite(CompositeType.UNION, name, builder = builder)
fun VisualGroup3D.subtract(name: String = "", builder: VisualGroup3D.() -> Unit) =
inline fun MutableVisualGroup.subtract(name: String = "", builder: VisualGroup3D.() -> Unit) =
composite(CompositeType.SUBTRACT, name, builder = builder)
fun VisualGroup3D.intersect(name: String = "", builder: VisualGroup3D.() -> Unit) =
inline fun MutableVisualGroup.intersect(name: String = "", builder: VisualGroup3D.() -> Unit) =
composite(CompositeType.INTERSECT, name, builder = builder)

View File

@ -4,6 +4,7 @@ package hep.dataforge.vis.spatial
import hep.dataforge.meta.Config
import hep.dataforge.vis.AbstractVisualObject
import hep.dataforge.vis.MutableVisualGroup
import hep.dataforge.vis.set
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@ -74,7 +75,7 @@ class ConeSegment(
}
inline fun VisualGroup3D.cylinder(
inline fun MutableVisualGroup.cylinder(
r: Number,
height: Number,
name: String = "",
@ -86,7 +87,7 @@ inline fun VisualGroup3D.cylinder(
).apply(block).also { set(name, it) }
inline fun VisualGroup3D.cone(
inline fun MutableVisualGroup.cone(
bottomRadius: Number,
height: Number,
upperRadius: Number = 0.0,

View File

@ -4,6 +4,7 @@ package hep.dataforge.vis.spatial
import hep.dataforge.meta.Config
import hep.dataforge.vis.AbstractVisualObject
import hep.dataforge.vis.MutableVisualGroup
import hep.dataforge.vis.set
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@ -24,7 +25,7 @@ class Convex(val points: List<Point3D>) : AbstractVisualObject(), VisualObject3D
}
}
inline fun VisualGroup3D.convex(name: String = "", action: ConvexBuilder.() -> Unit = {}) =
inline fun MutableVisualGroup.convex(name: String = "", action: ConvexBuilder.() -> Unit = {}) =
ConvexBuilder().apply(action).build().also { set(name, it) }
class ConvexBuilder {

View File

@ -3,6 +3,7 @@ package hep.dataforge.vis.spatial
import hep.dataforge.meta.Config
import hep.dataforge.vis.AbstractVisualObject
import hep.dataforge.vis.MutableVisualGroup
import hep.dataforge.vis.set
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@ -111,5 +112,5 @@ class Extruded(
}
}
fun VisualGroup3D.extrude(name: String = "", action: Extruded.() -> Unit = {}) =
fun MutableVisualGroup.extrude(name: String = "", action: Extruded.() -> Unit = {}) =
Extruded().apply(action).also { set(name, it) }

View File

@ -4,6 +4,7 @@ package hep.dataforge.vis.spatial
import hep.dataforge.meta.Config
import hep.dataforge.vis.AbstractVisualObject
import hep.dataforge.vis.MutableVisualGroup
import hep.dataforge.vis.set
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@ -20,7 +21,7 @@ class Label3D(var text: String, var fontSize: Double, var fontFamily: String) :
}
fun VisualGroup3D.label(
fun MutableVisualGroup.label(
text: String,
fontSize: Number = 20,
fontFamily: String = "Arial",

View File

@ -7,6 +7,7 @@ import hep.dataforge.meta.number
import hep.dataforge.names.asName
import hep.dataforge.names.plus
import hep.dataforge.vis.AbstractVisualObject
import hep.dataforge.vis.MutableVisualGroup
import hep.dataforge.vis.set
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@ -30,5 +31,5 @@ class PolyLine(var points: List<Point3D>) : AbstractVisualObject(), VisualObject
}
fun VisualGroup3D.polyline(vararg points: Point3D, name: String = "", action: PolyLine.() -> Unit = {}) =
fun MutableVisualGroup.polyline(vararg points: Point3D, name: String = "", action: PolyLine.() -> Unit = {}) =
PolyLine(points.toList()).apply(action).also { set(name, it) }

View File

@ -6,10 +6,7 @@ import hep.dataforge.meta.Config
import hep.dataforge.meta.Laminate
import hep.dataforge.meta.MetaItem
import hep.dataforge.meta.get
import hep.dataforge.names.Name
import hep.dataforge.names.NameToken
import hep.dataforge.names.asName
import hep.dataforge.names.plus
import hep.dataforge.names.*
import hep.dataforge.vis.*
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@ -24,8 +21,9 @@ import kotlin.collections.set
*/
@Serializable
@SerialName("3d.proxy")
class Proxy private constructor(val templateName: Name) : AbstractVisualObject(),
VisualGroup, VisualObject3D {
class Proxy private constructor(
val templateName: Name
) : AbstractVisualObject(), VisualGroup, VisualObject3D {
constructor(parent: VisualGroup3D, templateName: Name) : this(templateName) {
this.parent = parent
@ -42,10 +40,10 @@ class Proxy private constructor(val templateName: Name) : AbstractVisualObject()
*/
val prototype: VisualObject3D
get() = (parent as? VisualGroup3D)?.getPrototype(templateName)
?: error("Template with name $templateName not found in $parent")
?: error("Prototype with name $templateName not found in $parent")
override val styleSheet: StyleSheet
get() = (parent as? VisualGroup)?.styleSheet ?: StyleSheet(
get() = parent?.styleSheet ?: StyleSheet(
this
)
@ -166,9 +164,9 @@ inline fun VisualGroup3D.ref(
* Add new proxy wrapping given object and automatically adding it to the prototypes
*/
fun VisualGroup3D.proxy(
templateName: Name,
name: String,
obj: VisualObject3D,
name: String = "",
templateName: Name = name.toName(),
block: Proxy.() -> Unit = {}
): Proxy {
val existing = getPrototype(templateName)

View File

@ -4,6 +4,7 @@ package hep.dataforge.vis.spatial
import hep.dataforge.meta.Config
import hep.dataforge.vis.AbstractVisualObject
import hep.dataforge.vis.MutableVisualGroup
import hep.dataforge.vis.set
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@ -59,7 +60,7 @@ class Sphere(
}
}
inline fun VisualGroup3D.sphere(
inline fun MutableVisualGroup.sphere(
radius: Number,
phi: Number = 2 * PI,
theta: Number = PI,

View File

@ -3,6 +3,7 @@ package hep.dataforge.vis.spatial
import hep.dataforge.meta.Config
import hep.dataforge.vis.AbstractVisualObject
import hep.dataforge.vis.MutableVisualGroup
import hep.dataforge.vis.set
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@ -127,7 +128,7 @@ class Tube(
}
inline fun VisualGroup3D.tube(
inline fun MutableVisualGroup.tube(
r: Number,
height: Number,
innerRadius: Number = 0f,

View File

@ -8,22 +8,23 @@ import hep.dataforge.meta.Config
import hep.dataforge.names.Name
import hep.dataforge.names.NameToken
import hep.dataforge.names.asName
import hep.dataforge.names.isEmpty
import hep.dataforge.vis.AbstractVisualGroup
import hep.dataforge.vis.StyleSheet
import hep.dataforge.vis.VisualObject
import hep.dataforge.vis.set
import hep.dataforge.vis.*
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
import kotlin.collections.set
interface PrototypeHolder {
val parent: VisualGroup?
val prototypes: MutableVisualGroup?
}
/**
* Represents 3-dimensional Visual Group
*/
@Serializable
@SerialName("group.3d")
class VisualGroup3D : AbstractVisualGroup(), VisualObject3D {
class VisualGroup3D : AbstractVisualGroup(), VisualObject3D, PrototypeHolder {
override var styleSheet: StyleSheet? = null
private set
@ -31,11 +32,19 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D {
/**
* A container for templates visible inside this group
*/
var prototypes: VisualGroup3D? = null
set(value) {
value?.parent = this
field = value
}
@Serializable(PrototypesSerializer::class)
override var prototypes: MutableVisualGroup? = null
private set
/**
* Create or edit prototype node as a group
*/
fun prototypes(builder: MutableVisualGroup.() -> Unit): Unit {
(prototypes ?: Prototypes().also {
attach(it)
prototypes = it
}).run(builder)
}
//FIXME to be lifted to AbstractVisualGroup after https://github.com/Kotlin/kotlinx.serialization/issues/378 is fixed
override var properties: Config? = null
@ -48,11 +57,6 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D {
private val _children = HashMap<NameToken, VisualObject>()
override val children: Map<NameToken, VisualObject> get() = _children
// init {
// //Do after deserialization
// attachChildren()
// }
override fun attachChildren() {
prototypes?.parent = this
prototypes?.attachChildren()
@ -68,18 +72,11 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D {
}
override fun removeChild(token: NameToken) {
_children.remove(token)?.run { parent = null }
childrenChanged(token.asName(), null)
_children.remove(token)?.apply { parent = null }
}
override fun setChild(token: NameToken, child: VisualObject) {
if (child.parent == null) {
child.parent = this
} else if (child.parent !== this) {
error("Can't reassign existing parent for $child")
}
_children[token] = child
childrenChanged(token.asName(), child)
}
// /**
@ -87,47 +84,72 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D {
// */
// override fun addStatic(child: VisualObject) = setChild(NameToken("@static(${child.hashCode()})"), child)
override fun createGroup(name: Name): VisualGroup3D {
return when {
name.isEmpty() -> error("Should be unreachable")
name.length == 1 -> {
val token = name.first()!!
when (val current = children[token]) {
null -> VisualGroup3D().also { setChild(token, it) }
is VisualGroup3D -> current
else -> error("Can't create group with name $name because it exists and not a group")
}
}
else -> createGroup(name.first()!!.asName()).createGroup(name.cutFirst())
}
}
override fun createGroup(): VisualGroup3D = VisualGroup3D()
// return when {
// name.isEmpty() -> error("Should be unreachable")
// name.length == 1 -> {
// val token = name.first()!!
// when (val current = children[token]) {
// null -> VisualGroup3D().also { setChild(token, it) }
// is VisualGroup3D -> current
// else -> error("Can't create group with name $name because it exists and not a group")
// }
// }
// else -> createGroup(name.first()!!.asName()).createGroup(name.cutFirst())
// }
// }
companion object {
// val PROTOTYPES_KEY = NameToken("@prototypes")
fun fromJson(json: String): VisualGroup3D =
fun parseJson(json: String): VisualGroup3D =
Visual3D.json.parse(serializer(), json).also { it.attachChildren() }
}
}
fun VisualGroup3D.stringify(): String = Visual3D.json.stringify(VisualGroup3D.serializer(),this)
/**
* Ger a prototype redirecting the request to the parent if prototype is not found
*/
tailrec fun VisualGroup3D.getPrototype(name: Name): VisualObject3D? =
tailrec fun PrototypeHolder.getPrototype(name: Name): VisualObject3D? =
prototypes?.get(name) as? VisualObject3D ?: (parent as? VisualGroup3D)?.getPrototype(name)
/**
* Create or edit prototype node as a group
*/
inline fun VisualGroup3D.prototypes(builder: VisualGroup3D.() -> Unit): Unit {
(prototypes ?: VisualGroup3D().also { prototypes = it }).run(builder)
}
/**
* Define a group with given [name], attach it to this parent and return it.
*/
fun VisualGroup3D.group(name: String = "", action: VisualGroup3D.() -> Unit = {}): VisualGroup3D =
fun MutableVisualGroup.group(name: String = "", action: VisualGroup3D.() -> Unit = {}): VisualGroup3D =
VisualGroup3D().apply(action).also {
set(name, it)
}
internal class Prototypes(
override var children: MutableMap<NameToken, VisualObject> = LinkedHashMap()
) : AbstractVisualGroup(), MutableVisualGroup, PrototypeHolder {
override val styleSheet: StyleSheet? get() = null
override fun removeChild(token: NameToken) {
children.remove(token)
childrenChanged(token.asName(), null)
}
override fun setChild(token: NameToken, child: VisualObject) {
children[token] = child
}
override fun createGroup(): Prototypes = Prototypes()
override var properties: Config? = null
override val prototypes: MutableVisualGroup get() = this
override fun attachChildren() {
children.values.forEach {
it.parent = parent
(it as? VisualGroup)?.attachChildren()
}
}
}

View File

@ -1,7 +1,11 @@
package hep.dataforge.vis.spatial
import hep.dataforge.meta.double
import hep.dataforge.names.NameToken
import hep.dataforge.vis.MutableVisualGroup
import hep.dataforge.vis.VisualObject
import kotlinx.serialization.*
import kotlinx.serialization.builtins.MapSerializer
import kotlinx.serialization.builtins.nullable
import kotlinx.serialization.builtins.serializer
@ -91,3 +95,24 @@ object Point2DSerializer : KSerializer<Point2D> {
}
}
}
@Serializer(MutableVisualGroup::class)
internal object PrototypesSerializer : KSerializer<MutableVisualGroup> {
private val mapSerializer: KSerializer<Map<NameToken, VisualObject>> =
MapSerializer(
NameToken.serializer(),
PolymorphicSerializer(VisualObject::class)
)
override val descriptor: SerialDescriptor get() = mapSerializer.descriptor
override fun deserialize(decoder: Decoder): MutableVisualGroup {
val map = mapSerializer.deserialize(decoder)
return Prototypes(map as? MutableMap<NameToken, VisualObject> ?: LinkedHashMap(map))
}
override fun serialize(encoder: Encoder, value: MutableVisualGroup) {
mapSerializer.serialize(encoder, value.children)
}
}

View File

@ -6,7 +6,6 @@ import hep.dataforge.vis.MutableVisualGroup
import hep.dataforge.vis.VisualGroup
import hep.dataforge.vis.spatial.Proxy
import hep.dataforge.vis.spatial.VisualGroup3D
import hep.dataforge.vis.spatial.prototypes
object UnRef : VisualTreeTransform<VisualGroup3D>() {
private fun VisualGroup.countRefs(): Map<Name, Int> {

View File

@ -1,12 +1,11 @@
package hep.dataforge.vis.spatial
import hep.dataforge.vis.get
import hep.dataforge.vis.spatial.Visual3D.Companion.json
import kotlinx.serialization.ImplicitReflectionSerializer
import kotlin.test.Test
import kotlin.test.assertEquals
class SerializationTest {
@ImplicitReflectionSerializer
@Test
fun testCubeSerialization() {
val cube = Box(100f, 100f, 100f).apply {
@ -19,4 +18,21 @@ class SerializationTest {
val newCube = json.parse(Box.serializer(), string)
assertEquals(cube.config, newCube.config)
}
@Test
fun testProxySerialization() {
val cube = Box(100f, 100f, 100f).apply {
color(222)
x = 100
z = -100
}
val group = VisualGroup3D().apply {
proxy("cube", cube)
}
val string = group.stringify()
println(string)
val reconstructed = VisualGroup3D.parseJson(string)
assertEquals(group["cube"]?.config, reconstructed["cube"]?.config)
}
}

View File

@ -3,8 +3,6 @@ package hep.dataforge.vis.spatial.gdml.demo
import hep.dataforge.context.Global
import hep.dataforge.js.Application
import hep.dataforge.js.startApplication
import hep.dataforge.meta.Meta
import hep.dataforge.meta.withBottom
import hep.dataforge.names.Name
import hep.dataforge.names.isEmpty
import hep.dataforge.vis.VisualGroup
@ -23,7 +21,6 @@ import hep.dataforge.vis.spatial.gdml.toVisual
import hep.dataforge.vis.spatial.three.ThreePlugin
import hep.dataforge.vis.spatial.three.displayCanvasControls
import hep.dataforge.vis.spatial.three.output
import hep.dataforge.vis.spatial.visible
import org.w3c.dom.*
import org.w3c.files.FileList
import org.w3c.files.FileReader
@ -139,7 +136,7 @@ private class GDMLDemoApp : Application {
message("Converting GDML into DF-VIS format")
gdml.toVisual(gdmlConfiguration)
}
name.endsWith(".json") -> VisualGroup3D.fromJson(data)
name.endsWith(".json") -> VisualGroup3D.parseJson(data)
else -> {
window.alert("File extension is not recognized: $name")
error("File extension is not recognized: $name")

View File

@ -30,19 +30,19 @@ fun Visual3D.Companion.readFile(file: File): VisualGroup3D = when {
}
}
}
file.extension == "json" -> VisualGroup3D.fromJson(file.readText())
file.extension == "json" -> VisualGroup3D.parseJson(file.readText())
file.name.endsWith("json.zip") -> {
file.inputStream().use {
val unzip = ZipInputStream(it, Charsets.UTF_8)
val text = unzip.readAllBytes().decodeToString()
VisualGroup3D.fromJson(text)
VisualGroup3D.parseJson(text)
}
}
file.name.endsWith("json.gz") -> {
file.inputStream().use {
val unzip = GZIPInputStream(it)
val text = unzip.readAllBytes().decodeToString()
VisualGroup3D.fromJson(text)
VisualGroup3D.parseJson(text)
}
}
else -> error("Unknown extension ${file.extension}")

View File

@ -9,7 +9,7 @@ class FileSerializationTest {
@Ignore
fun testFileRead(){
val text = this::class.java.getResourceAsStream("/cubes.json").readAllBytes().decodeToString()
val visual = VisualGroup3D.fromJson(text)
val visual = VisualGroup3D.parseJson(text)
visual["composite_001".asName()]
}
}