diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/jsonToRoot.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/jsonToRoot.kt index d0c3afb9..585accf0 100644 --- a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/jsonToRoot.kt +++ b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/jsonToRoot.kt @@ -25,10 +25,10 @@ private fun jsonRootDeserializer(tSerializer: KSerializer, builder: (Json /** * Load Json encoded TObject */ -public fun TObject.Companion.decodeFromJson(serializer: KSerializer, jsonElement: JsonElement): TObject = +public fun TObject.Companion.decodeFromJson(serializer: KSerializer, jsonElement: JsonElement): T = RootDecoder.decode(serializer, jsonElement) -public fun TObject.Companion.decodeFromString(serializer: KSerializer, string: String): TObject { +public fun TObject.Companion.decodeFromString(serializer: KSerializer, string: String): T { val json = RootDecoder.json.parseToJsonElement(string) return RootDecoder.decode(serializer, json) } @@ -49,12 +49,14 @@ private object RootDecoder { //Forward ref for shapes when (tSerializer.descriptor.serialName) { "TGeoShape" -> return TGeoShapeRef { - //Should be not null at the moment of actualization - refCache[refId].value as TGeoShape + refCache[refId].getOrPutValue { + input.json.decodeFromJsonElement(tSerializer, it) as TGeoShape + } } as T "TGeoVolumeAssembly" -> return TGeoVolumeAssemblyRef { - //Should be not null at the moment of actualization - refCache[refId].value as TGeoVolumeAssembly + refCache[refId].getOrPutValue { + input.json.decodeFromJsonElement(tSerializer, it) as TGeoVolumeAssembly + } } as T //Do unref else -> refCache[refId] @@ -138,7 +140,7 @@ private object RootDecoder { } - fun decode(sourceDeserializer: KSerializer, source: JsonElement): TObject { + fun decode(sourceDeserializer: KSerializer, source: JsonElement): T { val refCache = ArrayList() fun fillCache(element: JsonElement) { diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/rootToSolid.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/rootToSolid.kt index ebfb7b06..9cbbb64b 100644 --- a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/rootToSolid.kt +++ b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/rootToSolid.kt @@ -2,7 +2,7 @@ package ru.mipt.npm.root import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.asName -import space.kscience.visionforge.setPropertyNode +import space.kscience.dataforge.names.plus import space.kscience.visionforge.solid.* import kotlin.math.PI import kotlin.math.atan2 @@ -19,158 +19,162 @@ private operator fun Number.times(f: Float) = toFloat() * f private fun degToRad(d: Double) = d * PI / 180.0 -private class GdmlLoader { +// converting to XYZ to Tait–Bryan angles according to https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix +private fun Solid.rotate(rot: DoubleArray) { + val xAngle = atan2(-rot[5], rot[8]) + val yAngle = atan2(rot[2], sqrt(1.0 - rot[2].pow(2))) + val zAngle = atan2(-rot[1], rot[0]) + rotation = Point3D(xAngle, yAngle, zAngle) +} - // converting to XYZ to Tait–Bryan angles according to https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix - private fun Solid.rotate(rot: DoubleArray) { - val xAngle = atan2(-rot[5], rot[8]) - val yAngle = atan2(rot[2], sqrt(1.0 - rot[2].pow(2))) - val zAngle = atan2(-rot[1], rot[0]) - rotation = Point3D(xAngle, yAngle, zAngle) - } +private fun Solid.translate(trans: DoubleArray) { + val (x, y, z) = trans + position = Point3D(x, y, z) +} - private fun Solid.translate(trans: DoubleArray) { - val (x, y, z) = trans - position = Point3D(x, y, z) - } - - private fun Solid.useMatrix(matrix: TGeoMatrix?) { - when (matrix) { - null, is TGeoIdentity -> { - //do nothing - } - is TGeoTranslation -> { - translate(matrix.fTranslation) - } - is TGeoRotation -> { - rotate(matrix.fRotationMatrix) - } - is TGeoCombiTrans -> { - translate(matrix.fTranslation) - matrix.fRotation?.let { rotate(it.fRotationMatrix) } - } - is TGeoHMatrix -> { - translate(matrix.fTranslation) - rotate(matrix.fRotationMatrix) - val (xScale, yScale, zScale) = matrix.fScale - scale = Point3D(xScale, yScale, zScale) - } +private fun Solid.useMatrix(matrix: TGeoMatrix?) { + when (matrix) { + null, is TGeoIdentity -> { + //do nothing + } + is TGeoTranslation -> { + translate(matrix.fTranslation) + } + is TGeoRotation -> { + rotate(matrix.fRotationMatrix) + } + is TGeoCombiTrans -> { + translate(matrix.fTranslation) + matrix.fRotation?.let { rotate(it.fRotationMatrix) } + } + is TGeoHMatrix -> { + translate(matrix.fTranslation) + rotate(matrix.fRotationMatrix) + val (xScale, yScale, zScale) = matrix.fScale + scale = Point3D(xScale, yScale, zScale) } } +} - fun SolidGroup.addShape(shape: TGeoShape) { - when (shape) { - is TGeoShapeRef -> addShape(shape.value) - is TGeoCompositeShape -> { - val bool: TGeoBoolNode = shape.fNode - val compositeType = when (bool) { - is TGeoIntersection -> CompositeType.INTERSECT - is TGeoSubtraction -> CompositeType.SUBTRACT - is TGeoUnion -> CompositeType.UNION +private fun SolidGroup.addShape(shape: TGeoShape) { + when (shape) { + is TGeoShapeRef -> addShape(shape.value) + is TGeoCompositeShape -> { + val bool: TGeoBoolNode = shape.fNode + val compositeType = when (bool) { + is TGeoIntersection -> CompositeType.INTERSECT + is TGeoSubtraction -> CompositeType.SUBTRACT + is TGeoUnion -> CompositeType.UNION + } + composite(compositeType, name = shape.fName) { + addShape(bool.fLeft).apply { + useMatrix(bool.fLeftMat) } - composite(compositeType, name = shape.fName) { - addShape(bool.fLeft).apply { - useMatrix(bool.fLeftMat) - } - addShape(bool.fRight).apply { - useMatrix(bool.fRightMat) - } + addShape(bool.fRight).apply { + useMatrix(bool.fRightMat) } } - is TGeoXtru -> extruded(name = shape.fName) { - - (0 until shape.fNvert).forEach { index -> - shape { - point(shape.fX[index], shape.fY[index]) - } - } - - (0 until shape.fNz).forEach { index -> - layer( - shape.fZ[index], - shape.fX0[index], - shape.fY0[index], - shape.fScale[index] - ) - } - } - is TGeoTube -> tube( - radius = shape.fRmax, - height = shape.fDz * 2, - innerRadius = shape.fRmin, - name = shape.fName - ) - is TGeoTubeSeg -> tube( - radius = shape.fRmax, - height = shape.fDz * 2, - innerRadius = shape.fRmin, - startAngle = degToRad(shape.fPhi1), - angle = degToRad(shape.fPhi2 - shape.fPhi1), - name = shape.fName - ) - is TGeoPcon -> TODO() - is TGeoPgon -> TODO() - is TGeoShapeAssembly -> volume(shape.fVolume) - is TGeoBBox -> box(shape.fDX * 2, shape.fDY * 2, shape.fDZ * 2, name = shape.fName) } - } + is TGeoXtru -> extruded(name = shape.fName) { - fun SolidGroup.node(obj: TGeoNode) { - if (obj.fVolume != null) { - volume(obj.fVolume).apply { - when (obj) { - is TGeoNodeMatrix -> { - useMatrix(obj.fMatrix) - } - is TGeoNodeOffset -> { - x = obj.fOffset - } + (0 until shape.fNvert).forEach { index -> + shape { + point(shape.fX[index], shape.fY[index]) + } + } + + (0 until shape.fNz).forEach { index -> + layer( + shape.fZ[index], + shape.fX0[index], + shape.fY0[index], + shape.fScale[index] + ) + } + } + is TGeoTube -> tube( + radius = shape.fRmax, + height = shape.fDz * 2, + innerRadius = shape.fRmin, + name = shape.fName + ) + is TGeoTubeSeg -> tube( + radius = shape.fRmax, + height = shape.fDz * 2, + innerRadius = shape.fRmin, + startAngle = degToRad(shape.fPhi1), + angle = degToRad(shape.fPhi2 - shape.fPhi1), + name = shape.fName + ) + is TGeoPcon -> TODO() + is TGeoPgon -> TODO() + is TGeoShapeAssembly -> volume(shape.fVolume) + is TGeoBBox -> box(shape.fDX * 2, shape.fDY * 2, shape.fDZ * 2, name = shape.fName) + } +} + +private fun SolidGroup.node(obj: TGeoNode) { + if (obj.fVolume != null) { + volume(obj.fVolume).apply { + when (obj) { + is TGeoNodeMatrix -> { + useMatrix(obj.fMatrix) + } + is TGeoNodeOffset -> { + x = obj.fOffset } } } } +} - fun buildGroup(volume: TGeoVolume): SolidGroup { - return if (volume is TGeoVolumeAssemblyRef) { - buildGroup(volume.value) - } else { - SolidGroup { - volume.fShape?.let { addShape(it) } - volume.fNodes?.let { - it.arr.forEach { obj -> - node(obj) - } +private fun buildGroup(volume: TGeoVolume): SolidGroup { + return if (volume is TGeoVolumeAssemblyRef) { + buildGroup(volume.value) + } else { + SolidGroup { + volume.fShape?.let { addShape(it) } + volume.fNodes?.let { + it.arr.forEach { obj -> + node(obj) } } } } +} - private val SolidGroup.rootPrototypes: SolidGroup get() = (parent as? SolidGroup)?.rootPrototypes ?: this +private val SolidGroup.rootPrototypes: SolidGroup get() = (parent as? SolidGroup)?.rootPrototypes ?: this - fun SolidGroup.volume(volume: TGeoVolume): SolidGroup { - val group = buildGroup(volume) - val ref = rootPrototypes.prototypes { +private fun SolidGroup.volume(volume: TGeoVolume, cache: Boolean = true): Solid { + val group = buildGroup(volume) + return if (!cache) { + group + } else newRef( + name = volume.fName.ifEmpty { null }, + obj = group, + prototypeHolder = rootPrototypes, + templateName = volumesName + Name.parse(volume.fName.ifEmpty { group.toString() }) + ) +} - } - set(volume.fName.ifEmpty { null }?.asName(), group) - return group +// private fun load(geo: TGeoManager): SolidGroup { +//// /** +//// * A special group for local templates +//// */ +//// val proto = SolidGroup() +//// +//// val solids = proto.group(solidsName) { +//// setPropertyNode("edges.enabled", false) +//// } +//// +//// val volumes = proto.group(volumesName) +//// +//// val referenceStore = HashMap>() +// } + + +public fun TGeoManager.toSolid(): SolidGroup = SolidGroup { + fNodes.arr.forEach { + node(it) } - - fun load(geo: TGeoManager): SolidGroup { - /** - * A special group for local templates - */ - val proto = SolidGroup() - - val solids = proto.group(solidsName) { - setPropertyNode("edges.enabled", false) - } - - val volumes = proto.group(volumesName) - - val referenceStore = HashMap>() - - TODO() - } - } \ No newline at end of file diff --git a/cern-root-loader/src/jvmTest/kotlin/ru/mipt/npm/root/loadBMN.kt b/cern-root-loader/src/jvmTest/kotlin/ru/mipt/npm/root/loadBMN.kt index c6cec829..7d5f4b24 100644 --- a/cern-root-loader/src/jvmTest/kotlin/ru/mipt/npm/root/loadBMN.kt +++ b/cern-root-loader/src/jvmTest/kotlin/ru/mipt/npm/root/loadBMN.kt @@ -31,7 +31,9 @@ fun main() { val time = measureTimeMillis { val geo = TObject.decodeFromString(TGeoManager.serializer(), string) - println(geo) + val solid = geo.toSolid() + + println(solid) } println(Duration.ofMillis(time)) diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt index d2080924..f58bcf8b 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt @@ -158,21 +158,28 @@ public fun SolidGroup.ref( name: String? = null, ): SolidReferenceGroup = SolidReferenceGroup(templateName).also { set(name, it) } -/** - * Add new [SolidReferenceGroup] wrapping given object and automatically adding it to the prototypes - */ public fun SolidGroup.ref( - name: String, + templateName: String, + name: String? = null, +): SolidReferenceGroup = ref(Name.parse(templateName), name) + +/** + * Add new [SolidReferenceGroup] wrapping given object and automatically adding it to the prototypes. + * One must ensure that [prototypeHolder] is the owner of this group. + */ +public fun SolidGroup.newRef( + name: String?, obj: Solid, - templateName: Name = Name.parse(name), + prototypeHolder: PrototypeHolder = this, + templateName: Name = Name.parse(name ?: obj.toString()), ): SolidReferenceGroup { val existing = getPrototype(templateName) if (existing == null) { - prototypes { - this[templateName] = obj + prototypeHolder.prototypes { + set(templateName, obj) } } else if (existing != obj) { error("Can't add different prototype on top of existing one") } - return this@ref.ref(templateName, name) + return ref(templateName, name) } diff --git a/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/SerializationTest.kt b/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/SerializationTest.kt index 8f5c3f57..f8af54a0 100644 --- a/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/SerializationTest.kt +++ b/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/SerializationTest.kt @@ -16,7 +16,7 @@ fun SolidGroup.refGroup( block: MutableVisionGroup.() -> Unit ): SolidReferenceGroup { val group = SolidGroup().apply(block) - return ref(name, group, templateName) + return newRef(name, group, templateName = templateName) } @@ -42,7 +42,7 @@ class SerializationTest { z = -100 } val group = SolidGroup { - ref("cube", cube) + newRef("cube", cube) refGroup("pg", Name.parse("pg.content")) { sphere(50) { x = -100 diff --git a/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/SolidReferenceTest.kt b/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/SolidReferenceTest.kt index 2f8b7781..cfdd73f0 100644 --- a/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/SolidReferenceTest.kt +++ b/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/SolidReferenceTest.kt @@ -14,7 +14,7 @@ class SolidReferenceTest { val theStyle by style { SolidMaterial.MATERIAL_COLOR_KEY put "red" } - ref("test", Box(100f,100f,100f).apply { + newRef("test", Box(100f,100f,100f).apply { color("blue") useStyle(theStyle) })