diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/DObject.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/DObject.kt new file mode 100644 index 00000000..361e0ae2 --- /dev/null +++ b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/DObject.kt @@ -0,0 +1,160 @@ +package ru.mipt.npm.root + +import kotlinx.serialization.json.Json +import space.kscience.dataforge.meta.* +import space.kscience.dataforge.misc.Named +import space.kscience.dataforge.names.Name +import space.kscience.dataforge.names.asName +import space.kscience.dataforge.values.doubleArray +import kotlin.properties.ReadOnlyProperty + +public fun MetaProvider.doubleArray( + vararg default: Double, + key: Name? = null, +): ReadOnlyProperty = value(key) { + it?.doubleArray ?: doubleArrayOf(*default) +} + + +public class DObjectCache(private val cache: List, public val refStack: List = emptyList()) { + public operator fun get(index: Int): Meta = cache[index] + + public fun stack(ref: Int): DObjectCache = DObjectCache(cache, refStack + ref) + + public companion object { + public val empty: DObjectCache = DObjectCache(emptyList(), emptyList()) + } +} +// +//public interface ObjectRef { +// public fun resolve(): T? +//} + +//public class ChildObjectRef( +// public val builder: (Meta, DObjectCache) -> T, +// public val refCache: DObjectCache, +// public val metaProvider: () -> Meta? +//) : ObjectRef { +// override fun resolve(): T? { +// val meta = metaProvider() ?: return null +// meta["\$ref"]?.int?.let { refId -> +// if (refCache.refStack.contains(refId)) { +// println("Circular reference $refId in stack ${refCache.refStack}") +// return null +// } +// return builder(refCache[refId], refCache.stack(refId)) +// } +// return builder(meta, refCache) +// } +//} + +public open class DObject(public val meta: Meta, private val refCache: DObjectCache) { + + public val typename: String by meta.string(key = "_typename".asName()) { + error("Type is not defined") + } + + private fun resolve(builder: (Meta, DObjectCache) -> T, meta: Meta): T? { + meta["\$ref"]?.int?.let { refId -> + if (refCache.refStack.contains(refId)) { + println("Circular reference $refId in stack ${refCache.refStack}") + return null + } + return builder(refCache[refId], refCache.stack(refId)) + } + return builder(meta, refCache) + } + + internal fun tObjectArray( + builder: (Meta, DObjectCache) -> T + ): ReadOnlyProperty> = ReadOnlyProperty { _, property -> + meta.getIndexed(Name.of(property.name, "arr")).values.mapNotNull { + resolve(builder, it) + } + } + + internal fun dObject( + builder: (Meta, DObjectCache) -> T, + key: Name? = null + ): ReadOnlyProperty = ReadOnlyProperty { _, property -> + meta[key ?: property.name.asName()]?.let { resolve(builder, it) } + } +} + +public open class DNamed(meta: Meta, refCache: DObjectCache) : DObject(meta, refCache) { + public val fName: String by meta.string("") + public val fTitle: String by meta.string("") +} + +public class DGeoMaterial(meta: Meta, refCache: DObjectCache) : DNamed(meta, refCache) { +} + +public class DGeoMedium(meta: Meta, refCache: DObjectCache) : DNamed(meta, refCache) { + public val fMaterial: DGeoMaterial? by dObject(::DGeoMaterial) + public val fParams: DoubleArray by meta.doubleArray() +} + +public class DGeoShape(meta: Meta, refCache: DObjectCache) : DNamed(meta, refCache) { + public val fDX: Double by meta.double(0.0) + public val fDY: Double by meta.double(0.0) + public val fDZ: Double by meta.double(0.0) +} + +public class DGeoVolume(meta: Meta, refCache: DObjectCache) : DNamed(meta, refCache), Named { + public val fNodes: List by tObjectArray(::DGeoNode) + public val fShape: DGeoShape? by dObject(::DGeoShape) + public val fMedium: DGeoMedium? by dObject(::DGeoMedium) + + override val name: Name by lazy { Name.parse(fName.ifEmpty { "volume[${meta.hashCode().toUInt()}]" }) } +} + +public class DGeoNode(meta: Meta, refCache: DObjectCache) : DNamed(meta, refCache) { + public val fVolume: DGeoVolume? by dObject(::DGeoVolume) +} + +public class DGeoMatrix(meta: Meta, refCache: DObjectCache) : DNamed(meta, refCache) { +} + + +public class DGeoBoolNode(meta: Meta, refCache: DObjectCache) : DObject(meta, refCache) { + public val fLeft: DGeoShape? by dObject(::DGeoShape) + public val fLeftMat: DGeoMatrix? by dObject(::DGeoMatrix) + + public val fRight: DGeoShape? by dObject(::DGeoShape) + public val fRightMat: DGeoMatrix? by dObject(::DGeoMatrix) +} + + +public class DGeoManager(meta: Meta, refCache: DObjectCache) : DNamed(meta, refCache) { + public val fMatrices: List by tObjectArray(::DGeoMatrix) + + public val fShapes: List by tObjectArray(::DGeoShape) + + public val fVolumes: List by tObjectArray(::DGeoVolume) + + public val fNodes: List by tObjectArray(::DGeoNode) + + public companion object { + + public fun parse(string: String): DGeoManager { + val meta = Json.decodeFromString(MetaSerializer, string) + val res = ArrayList(4096) + + fun fillCache(element: Meta) { + if (element["\$ref"] == null) { + res.add(element) + element.items.values.forEach { + if (!it.isLeaf) { + fillCache(it) + } + } + } + } + + fillCache(meta) + + val refCache = DObjectCache(res) + return DGeoManager(meta, refCache) + } + } +} diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TObjectScheme.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TObjectScheme.kt deleted file mode 100644 index 0ec699bd..00000000 --- a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TObjectScheme.kt +++ /dev/null @@ -1,140 +0,0 @@ -package ru.mipt.npm.root - -import kotlinx.serialization.json.Json -import space.kscience.dataforge.meta.* -import space.kscience.dataforge.names.Name -import space.kscience.dataforge.names.asName -import kotlin.properties.ReadOnlyProperty - -public typealias RefCache = List - -public interface ObjectRef { - public fun resolve(refCache: RefCache): T? -} - -private class ChildObjectRef( - val spec: Specification, - val metaProvider: () -> Meta? -) : ObjectRef { - override fun resolve(refCache: RefCache): T? { - val meta = metaProvider() ?: return null - meta["\$ref"]?.int?.let { refId -> - return spec.read(refCache[refId]) - } - return spec.read(meta) - } -} - -public fun List>.resolve(refCache: RefCache): List = map { it.resolve(refCache)!! } - - -public open class TObjectScheme : Scheme() { - - public val typename: String by string(key = "_typename".asName()) { error("Type is not defined") } - - internal fun tObjectArray( - spec: Specification - ): ReadOnlyProperty>> = ReadOnlyProperty { _, property -> - meta.getIndexed(Name.of(property.name, "arr")).values.map { ChildObjectRef(spec){it} } - } - - internal fun refSpec( - spec: Specification, - key: Name? = null - ): ReadOnlyProperty> = ReadOnlyProperty { _, property -> - ChildObjectRef(spec) { meta[key ?: property.name.asName()] } - } - - public companion object : SchemeSpec(::TObjectScheme) -} - -public open class TNamedScheme : TObjectScheme() { - public val fName: String by string("") - public val fTitle: String by string("") - - public companion object : SchemeSpec(::TNamedScheme) -} - -public class TGeoMaterialScheme : TNamedScheme() { - - public companion object : SchemeSpec(::TGeoMaterialScheme) -} - -public class TGeoMediumScheme : TNamedScheme() { - public val fMaterial: ObjectRef by refSpec(TGeoMaterialScheme) - public val fParams: DoubleArray by doubleArray() - - public companion object : SchemeSpec(::TGeoMediumScheme) -} - -public class TGeoShapeScheme : TNamedScheme() { - public val fDX: Double by double(0.0) - public val fDY: Double by double(0.0) - public val fDZ: Double by double(0.0) - - public companion object : SchemeSpec(::TGeoShapeScheme) -} - -public class TGeoVolumeScheme : TNamedScheme() { - public val fNodes: List> by tObjectArray(TGeoNodeScheme) - public val fShape: ObjectRef by refSpec(TGeoShapeScheme) - public val fMedium: ObjectRef by refSpec(TGeoMediumScheme) - - public companion object : SchemeSpec(::TGeoVolumeScheme) -} - -public class TGeoNodeScheme : TNamedScheme() { - public val fVolume: ObjectRef by refSpec(TGeoVolumeScheme) - - public companion object : SchemeSpec(::TGeoNodeScheme) -} - -public class TGeoMatrixScheme : TNamedScheme() { - public companion object : SchemeSpec(::TGeoMatrixScheme) -} - - -public class TGeoBoolNodeScheme : TObjectScheme() { - public val fLeft: ObjectRef by refSpec(TGeoShapeScheme) - public val fLeftMat: ObjectRef by refSpec(TGeoMatrixScheme) - - public val fRight: ObjectRef by refSpec(TGeoShapeScheme) - public val fRightMat: ObjectRef by refSpec(TGeoMatrixScheme) - - public companion object : SchemeSpec(::TGeoBoolNodeScheme) -} - - -public class TGeoManagerScheme : TNamedScheme() { - public val fMatrices: List> by tObjectArray(TGeoMatrixScheme) - - public val fShapes: List> by tObjectArray(TGeoShapeScheme) - - public val fVolumes: List> by tObjectArray(TGeoVolumeScheme) - - public val fNodes: List> by tObjectArray(TGeoNodeScheme) - - public val refCache: List by lazy { - val res = ArrayList(4096) - fun fillCache(element: Meta) { - if(element["\$ref"] == null) { - res.add(element) - element.items.values.forEach { - if (!it.isLeaf) { - fillCache(it) - } - } - } - } - fillCache(meta) - res - } - - public companion object : SchemeSpec(::TGeoManagerScheme) { - - public fun parse(string: String): TGeoManagerScheme { - val meta = Json.decodeFromString(MetaSerializer, string) - return read(meta) - } - } -} diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/dRootToSolid.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/dRootToSolid.kt new file mode 100644 index 00000000..87422b97 --- /dev/null +++ b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/dRootToSolid.kt @@ -0,0 +1,280 @@ +package ru.mipt.npm.root + +import space.kscience.dataforge.meta.double +import space.kscience.dataforge.meta.get +import space.kscience.dataforge.meta.int +import space.kscience.dataforge.names.Name +import space.kscience.dataforge.names.plus +import space.kscience.visionforge.solid.* +import kotlin.math.* + +private val volumesName = Name.EMPTY //"volumes".asName() + +private operator fun Number.times(d: Double) = toDouble() * d + +private operator fun Number.times(f: Float) = toFloat() * f + +private fun degToRad(d: Double) = d * PI / 180.0 + +private class RootToSolidContext(val prototypeHolder: PrototypeHolder) + +// 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.useMatrix(matrix: DGeoMatrix?) { + if (matrix == null) return + when (matrix.typename) { + "TGeoIdentity" -> { + //do nothing + } + "TGeoTranslation" -> { + val fTranslation by matrix.meta.doubleArray() + translate(fTranslation) + } + "TGeoRotation" -> { + val fRotationMatrix by matrix.meta.doubleArray() + rotate(fRotationMatrix) + } + "TGeoCombiTrans" -> { + val fTranslation by matrix.meta.doubleArray() + + translate(fTranslation) + if (matrix.meta["fRotationMatrix"] != null) { + val fRotationMatrix by matrix.meta.doubleArray() + rotate(fRotationMatrix) + } + } + "TGeoHMatrix" -> { + val fTranslation by matrix.meta.doubleArray() + val fRotationMatrix by matrix.meta.doubleArray() + val fScale by matrix.meta.doubleArray() + translate(fTranslation) + rotate(fRotationMatrix) + scale = Point3D(fScale[0], fScale[1], fScale[2]) + } + } +} + +private fun SolidGroup.addShape( + shape: DGeoShape, + context: RootToSolidContext, + name: String? = shape.fName.ifEmpty { null } +): Solid? = when (shape.typename) { + "TGeoCompositeShape" -> { + val fNode: DGeoBoolNode? by shape.dObject(::DGeoBoolNode) + val node = fNode ?: error("Composite shape node not resolved") + val compositeType = when (node.typename) { + "TGeoIntersection" -> CompositeType.INTERSECT + "TGeoSubtraction" -> CompositeType.SUBTRACT + "TGeoUnion" -> CompositeType.UNION + else -> error("Unknown bool node type ${node.typename}") + } + composite(compositeType, name = name) { + addShape(node.fLeft!!, context, "left").also { + if (it == null) TODO() + it.useMatrix(node.fLeftMat) + } + addShape(node.fRight!!, context, "right").also { + if (it == null) TODO() + it.useMatrix(node.fRightMat) + } + } + } + "TGeoXtru" -> { + val fNvert by shape.meta.int(0) + val fX by shape.meta.doubleArray() + val fY by shape.meta.doubleArray() + val fNz by shape.meta.int(0) + val fZ by shape.meta.doubleArray() + val fX0 by shape.meta.doubleArray() + val fY0 by shape.meta.doubleArray() + val fScale by shape.meta.doubleArray() + + extruded(name = name) { + (0 until fNvert).forEach { index -> + shape { + point(fX[index], fY[index]) + } + } + + (0 until fNz).forEach { index -> + layer( + fZ[index], + fX0[index], + fY0[index], + fScale[index] + ) + } + } + } + "TGeoTube" -> { + val fRmax by shape.meta.double(0.0) + val fDz by shape.meta.double(0.0) + val fRmin by shape.meta.double(0.0) + + tube( + radius = fRmax, + height = fDz * 2, + innerRadius = fRmin, + name = name + ) + } + "TGeoTubeSeg" -> { + val fRmax by shape.meta.double(0.0) + val fDz by shape.meta.double(0.0) + val fRmin by shape.meta.double(0.0) + val fPhi1 by shape.meta.double(0.0) + val fPhi2 by shape.meta.double(0.0) + + tube( + radius = fRmax, + height = fDz * 2, + innerRadius = fRmin, + startAngle = degToRad(fPhi1), + angle = degToRad(fPhi2 - fPhi1), + name = name + ) + } + "TGeoPcon" -> { + val fDphi by shape.meta.double(0.0) + val fNz by shape.meta.int(2) + val fPhi1 by shape.meta.double(360.0) + val fRmax by shape.meta.doubleArray() + val fRmin by shape.meta.doubleArray() + val fZ by shape.meta.doubleArray() + if (fNz == 2) { + coneSurface( + bottomOuterRadius = fRmax[0], + bottomInnerRadius = fRmin[0], + height = fZ[1] - fZ[0], + topOuterRadius = fRmax[1], + topInnerRadius = fRmin[1], + startAngle = degToRad(fPhi1), + angle = degToRad(fDphi), + name = name + ) { + z = (fZ[1] + fZ[0]) / 2 + } + } else { + TODO() + } + } + "TGeoPgon" -> { + val fDphi by shape.meta.double(0.0) + val fNz by shape.meta.int(2) + val fPhi1 by shape.meta.double(360.0) + val fRmax by shape.meta.doubleArray() + val fRmin by shape.meta.doubleArray() + val fZ by shape.meta.doubleArray() + + val fNedges by shape.meta.int(1) + + val startphi = degToRad(fPhi1) + val deltaphi = degToRad(fDphi) + + extruded(name) { + //getting the radius of first + require(fNz > 1) { "The polyhedron geometry requires at least two planes" } + val baseRadius = fRmax[0] + shape { + (0..fNedges).forEach { + val phi = deltaphi * fNedges * it + startphi + (baseRadius * cos(phi) to baseRadius * sin(phi)) + } + } + (0 until fNz).forEach { index -> + //scaling all radii relative to first layer radius + layer(fZ[index], scale = fRmax[index] / baseRadius) + } + } + } + "TGeoShapeAssembly" -> { + val fVolume by shape.dObject(::DGeoVolume) + fVolume?.let { volume -> + addRootVolume(volume, context) + } + } + "TGeoBBox" -> { + box(shape.fDX * 2, shape.fDY * 2, shape.fDZ * 2, name = name) + } + else -> { + TODO("A shape with type ${shape.typename} not implemented") + } +} + +private fun SolidGroup.addRootNode(obj: DGeoNode, context: RootToSolidContext) { + val volume = obj.fVolume ?: return + addRootVolume(volume, context, obj.fName).apply { + when (obj.typename) { + "TGeoNodeMatrix" -> { + val fMatrix by obj.dObject(::DGeoMatrix) + useMatrix(fMatrix) + } + "TGeoNodeOffset" -> { + val fOffset by obj.meta.double(0.0) + x = fOffset + } + } + } +} + +private fun buildGroup(volume: DGeoVolume, context: RootToSolidContext): SolidGroup = SolidGroup { + volume.fShape?.let { + addShape(it, context) + } + volume.fNodes.let { + it.forEach { node -> + addRootNode(node, context) + } + } +} + +//private val SolidGroup.rootPrototypes: SolidGroup get() = (parent as? SolidGroup)?.rootPrototypes ?: this + +private fun SolidGroup.addRootVolume( + volume: DGeoVolume, + context: RootToSolidContext, + name: String? = null, + cache: Boolean = true +): Solid { + val combinedName = if (volume.fName.isEmpty()) { + name + } else if (name == null) { + volume.fName + } else { + "${name}_${volume.fName}" + } + + return if (!cache) { + val group = buildGroup(volume, context) + set(combinedName?.let { Name.parse(it) }, group) + group + } else { + val templateName = volumesName + volume.name + val existing = getPrototype(templateName) + if (existing == null) { + context.prototypeHolder.prototypes { + set(templateName, buildGroup(volume, context)) + } + } + + return ref(templateName, name) + } +} + +public fun DGeoManager.toSolid(): SolidGroup = SolidGroup { + val context = RootToSolidContext(this) + fNodes.forEach { node -> + addRootNode(node, context) + } +} \ No newline at end of file diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/rootSchemeToSolid.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/rootSchemeToSolid.kt deleted file mode 100644 index 89849613..00000000 --- a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/rootSchemeToSolid.kt +++ /dev/null @@ -1,217 +0,0 @@ -package ru.mipt.npm.root - -import space.kscience.dataforge.meta.* -import space.kscience.dataforge.names.Name -import space.kscience.dataforge.names.asName -import space.kscience.dataforge.names.plus -import space.kscience.visionforge.solid.* -import kotlin.math.PI -import kotlin.math.atan2 -import kotlin.math.pow -import kotlin.math.sqrt - -private val solidsName = "solids".asName() -private val volumesName = "volumes".asName() - -private operator fun Number.times(d: Double) = toDouble() * d - -private operator fun Number.times(f: Float) = toFloat() * f - -private fun degToRad(d: Double) = d * PI / 180.0 - -// 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.useMatrix(matrix: TGeoMatrixScheme?) { - if (matrix == null) return - when (matrix.typename) { - "TGeoIdentity" -> { - //do nothing - } - "TGeoTranslation" -> { - val fTranslation by matrix.doubleArray() - translate(fTranslation) - } - "TGeoRotation" -> { - val fRotationMatrix by matrix.doubleArray() - rotate(fRotationMatrix) - } - "TGeoCombiTrans" -> { - val fTranslation by matrix.doubleArray() - - translate(fTranslation) - if (matrix.meta["fRotationMatrix"] != null) { - val fRotationMatrix by matrix.doubleArray() - rotate(fRotationMatrix) - } - } - "TGeoHMatrix" -> { - val fTranslation by matrix.doubleArray() - val fRotationMatrix by matrix.doubleArray() - val fScale by matrix.doubleArray() - translate(fTranslation) - rotate(fRotationMatrix) - scale = Point3D(fScale[0], fScale[1], fScale[2]) - } - } -} - -private fun SolidGroup.addShape(shape: TGeoShapeScheme, refCache: RefCache) { - when (shape.typename) { - "TGeoCompositeShape" -> { - val bool by shape.spec(TGeoBoolNodeScheme) - val compositeType = when (bool.typename) { - "TGeoIntersection" -> CompositeType.INTERSECT - "TGeoSubtraction" -> CompositeType.SUBTRACT - "TGeoUnion" -> CompositeType.UNION - else -> error("Unknown bool node type ${bool.typename}") - } - composite(compositeType, name = shape.fName) { - addShape(bool.fLeft.resolve(refCache)!!, refCache).apply { - useMatrix(bool.fLeftMat.resolve(refCache)) - } - addShape(bool.fRight.resolve(refCache)!!, refCache).apply { - useMatrix(bool.fRightMat.resolve(refCache)) - } - } - } - "TGeoXtru" -> { - val fNvert by shape.meta.int(0) - val fX by shape.meta.doubleArray() - val fY by shape.meta.doubleArray() - val fNz by shape.meta.int(0) - val fZ by shape.meta.doubleArray() - val fX0 by shape.meta.doubleArray() - val fY0 by shape.meta.doubleArray() - val fScale by shape.meta.doubleArray() - - extruded(name = shape.fName) { - (0 until fNvert).forEach { index -> - shape { - point(fX[index], fY[index]) - } - } - - (0 until fNz).forEach { index -> - layer( - fZ[index], - fX0[index], - fY0[index], - fScale[index] - ) - } - } - } - "TGeoTube" -> { - val fRmax by shape.meta.double(0.0) - val fDz by shape.meta.double(0.0) - val fRmin by shape.meta.double(0.0) - - tube( - radius = fRmax, - height = fDz * 2, - innerRadius = fRmin, - name = shape.fName - ) - } - "TGeoTubeSeg" -> { - val fRmax by shape.meta.double(0.0) - val fDz by shape.meta.double(0.0) - val fRmin by shape.meta.double(0.0) - val fPhi1 by shape.meta.double(0.0) - val fPhi2 by shape.meta.double(0.0) - - tube( - radius = fRmax, - height = fDz * 2, - innerRadius = fRmin, - startAngle = degToRad(fPhi1), - angle = degToRad(fPhi2 - fPhi1), - name = shape.fName - ) - } - "TGeoPcon" -> { - TODO() - } - "TGeoPgon" -> { - TODO() - } - "TGeoShapeAssembly" -> { - val fVolume by shape.refSpec(TGeoVolumeScheme) - volume(fVolume.resolve(refCache)!!, refCache) - } - "TGeoBBox" -> { - box(shape.fDX * 2, shape.fDY * 2, shape.fDZ * 2, name = shape.fName) - } - } -} - -private fun SolidGroup.node(obj: TGeoNodeScheme, refCache: RefCache) { - val volume = obj.fVolume.resolve(refCache) - if (volume != null) { - volume(volume, refCache, obj.fName).apply { - when (obj.typename) { - "TGeoNodeMatrix" -> { - val fMatrix by obj.refSpec(TGeoMatrixScheme) - useMatrix(fMatrix.resolve(refCache)) - } - "TGeoNodeOffset" -> { - val fOffset by obj.meta.double(0.0) - x = fOffset - } - } - } - } -} - -private fun buildGroup(volume: TGeoVolumeScheme, refCache: RefCache): SolidGroup = SolidGroup { - volume.fShape.resolve(refCache)?.let { addShape(it, refCache) } - volume.fNodes.let { - it.forEach { obj -> - node(obj.resolve(refCache)!!, refCache) - } - } -} - -private val SolidGroup.rootPrototypes: SolidGroup get() = (parent as? SolidGroup)?.rootPrototypes ?: this - -private fun SolidGroup.volume( - volume: TGeoVolumeScheme, - refCache: RefCache, - name: String? = null, - cache: Boolean = true -): Solid { - val group = buildGroup(volume, refCache) - val combinedName = if (volume.fName.isEmpty()) { - name - } else if (name == null) { - volume.fName - } else { - "${name}_${volume.fName}" - } - return if (!cache) { - set(combinedName?.let { Name.parse(it)},group) - group - } else newRef( - name = combinedName, - obj = group, - prototypeHolder = rootPrototypes, - templateName = volumesName + Name.parse(combinedName ?: "volume[${group.hashCode()}]") - ) -} - -public fun TGeoManagerScheme.toSolid(): SolidGroup = SolidGroup { - fNodes.forEach { - node(it.resolve(refCache)!!, refCache) - } -} \ 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 fbd7482e..fdbcea6d 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 @@ -5,8 +5,14 @@ import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.jsonPrimitive import ru.mipt.npm.root.serialization.TGeoManager +import space.kscience.dataforge.meta.Meta +import space.kscience.dataforge.meta.get +import space.kscience.dataforge.meta.isLeaf +import space.kscience.dataforge.values.string import space.kscience.visionforge.solid.Solids +import java.nio.file.Paths import java.time.Duration +import kotlin.io.path.writeText import kotlin.system.measureTimeMillis private fun JsonElement.countTypes(): Sequence = sequence { @@ -25,14 +31,28 @@ private fun JsonElement.countTypes(): Sequence = sequence { } } +private fun Meta.countTypes() :Sequence = sequence { + if(!isLeaf){ + get("_typename")?.value?.let { yield(it.string) } + items.forEach { yieldAll(it.value.countTypes()) } + } +} + fun main() { val string = TGeoManager::class.java.getResourceAsStream("/BM@N.root.json")!! .readAllBytes().decodeToString() val time = measureTimeMillis { - val geo = TGeoManagerScheme.parse(string) + val geo = DGeoManager.parse(string) + + val sizes = geo.meta.countTypes().groupBy { it }.mapValues { it.value.size } + sizes.forEach { + println(it) + } + val solid = geo.toSolid() - println(Solids.encodeToString(solid)) + Paths.get("BM@N.vf.json").writeText(Solids.encodeToString(solid)) + //println(Solids.encodeToString(solid)) } // val json = Json.parseToJsonElement(string) diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Composite.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Composite.kt index 9debf612..00db285c 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Composite.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Composite.kt @@ -5,6 +5,7 @@ import kotlinx.serialization.Serializable import space.kscience.dataforge.meta.update import space.kscience.visionforge.VisionBuilder import space.kscience.visionforge.VisionContainerBuilder +import space.kscience.visionforge.VisionPropertyContainer import space.kscience.visionforge.set public enum class CompositeType { @@ -20,7 +21,7 @@ public class Composite( public val compositeType: CompositeType, public val first: Solid, public val second: Solid, -) : SolidBase(), Solid +) : SolidBase(), VisionPropertyContainer @VisionBuilder public inline fun VisionContainerBuilder.composite( @@ -30,7 +31,7 @@ public inline fun VisionContainerBuilder.composite( ): Composite { val group = SolidGroup().apply(builder) val children = group.children.values.filterIsInstance() - if (children.size != 2) error("Composite requires exactly two children") + if (children.size != 2) error("Composite requires exactly two children, but found ${children.size}") val res = Composite(type, children[0], children[1]) res.meta.update(group.meta) 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 f58bcf8b..eeab05ff 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 @@ -165,7 +165,7 @@ public fun SolidGroup.ref( /** * Add new [SolidReferenceGroup] wrapping given object and automatically adding it to the prototypes. - * One must ensure that [prototypeHolder] is the owner of this group. + * One must ensure that [prototypeHolder] is a parent of this group. */ public fun SolidGroup.newRef( name: String?,