Finished Root converter

This commit is contained in:
Alexander Nozik 2021-09-05 18:37:16 +03:00
parent 7b5faaa61e
commit e25c1bd49b
7 changed files with 466 additions and 362 deletions

View File

@ -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<Any?, DoubleArray> = value(key) {
it?.doubleArray ?: doubleArrayOf(*default)
}
public class DObjectCache(private val cache: List<Meta>, public val refStack: List<Int> = 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<T : DObject> {
// public fun resolve(): T?
//}
//public class ChildObjectRef<T : DObject>(
// public val builder: (Meta, DObjectCache) -> T,
// public val refCache: DObjectCache,
// public val metaProvider: () -> Meta?
//) : ObjectRef<T> {
// 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 <T : DObject> 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 <T : DObject> tObjectArray(
builder: (Meta, DObjectCache) -> T
): ReadOnlyProperty<Any?, List<T>> = ReadOnlyProperty { _, property ->
meta.getIndexed(Name.of(property.name, "arr")).values.mapNotNull {
resolve(builder, it)
}
}
internal fun <T : DObject> dObject(
builder: (Meta, DObjectCache) -> T,
key: Name? = null
): ReadOnlyProperty<Any?, T?> = 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<DGeoNode> 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<DGeoMatrix> by tObjectArray(::DGeoMatrix)
public val fShapes: List<DGeoShape> by tObjectArray(::DGeoShape)
public val fVolumes: List<DGeoVolume> by tObjectArray(::DGeoVolume)
public val fNodes: List<DGeoNode> by tObjectArray(::DGeoNode)
public companion object {
public fun parse(string: String): DGeoManager {
val meta = Json.decodeFromString(MetaSerializer, string)
val res = ArrayList<Meta>(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)
}
}
}

View File

@ -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<Meta>
public interface ObjectRef<T : TObjectScheme> {
public fun resolve(refCache: RefCache): T?
}
private class ChildObjectRef<T : TObjectScheme>(
val spec: Specification<T>,
val metaProvider: () -> Meta?
) : ObjectRef<T> {
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 <T: TObjectScheme> List<ObjectRef<T>>.resolve(refCache: RefCache): List<T> = 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 <T : TObjectScheme> tObjectArray(
spec: Specification<T>
): ReadOnlyProperty<Any?, List<ObjectRef<T>>> = ReadOnlyProperty { _, property ->
meta.getIndexed(Name.of(property.name, "arr")).values.map { ChildObjectRef(spec){it} }
}
internal fun <T : TObjectScheme> refSpec(
spec: Specification<T>,
key: Name? = null
): ReadOnlyProperty<Any?, ObjectRef<T>> = ReadOnlyProperty { _, property ->
ChildObjectRef(spec) { meta[key ?: property.name.asName()] }
}
public companion object : SchemeSpec<TObjectScheme>(::TObjectScheme)
}
public open class TNamedScheme : TObjectScheme() {
public val fName: String by string("")
public val fTitle: String by string("")
public companion object : SchemeSpec<TNamedScheme>(::TNamedScheme)
}
public class TGeoMaterialScheme : TNamedScheme() {
public companion object : SchemeSpec<TGeoMaterialScheme>(::TGeoMaterialScheme)
}
public class TGeoMediumScheme : TNamedScheme() {
public val fMaterial: ObjectRef<TGeoMaterialScheme> by refSpec(TGeoMaterialScheme)
public val fParams: DoubleArray by doubleArray()
public companion object : SchemeSpec<TGeoMediumScheme>(::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>(::TGeoShapeScheme)
}
public class TGeoVolumeScheme : TNamedScheme() {
public val fNodes: List<ObjectRef<TGeoNodeScheme>> by tObjectArray(TGeoNodeScheme)
public val fShape: ObjectRef<TGeoShapeScheme> by refSpec(TGeoShapeScheme)
public val fMedium: ObjectRef<TGeoMediumScheme> by refSpec(TGeoMediumScheme)
public companion object : SchemeSpec<TGeoVolumeScheme>(::TGeoVolumeScheme)
}
public class TGeoNodeScheme : TNamedScheme() {
public val fVolume: ObjectRef<TGeoVolumeScheme> by refSpec(TGeoVolumeScheme)
public companion object : SchemeSpec<TGeoNodeScheme>(::TGeoNodeScheme)
}
public class TGeoMatrixScheme : TNamedScheme() {
public companion object : SchemeSpec<TGeoMatrixScheme>(::TGeoMatrixScheme)
}
public class TGeoBoolNodeScheme : TObjectScheme() {
public val fLeft: ObjectRef<TGeoShapeScheme> by refSpec(TGeoShapeScheme)
public val fLeftMat: ObjectRef<TGeoMatrixScheme> by refSpec(TGeoMatrixScheme)
public val fRight: ObjectRef<TGeoShapeScheme> by refSpec(TGeoShapeScheme)
public val fRightMat: ObjectRef<TGeoMatrixScheme> by refSpec(TGeoMatrixScheme)
public companion object : SchemeSpec<TGeoBoolNodeScheme>(::TGeoBoolNodeScheme)
}
public class TGeoManagerScheme : TNamedScheme() {
public val fMatrices: List<ObjectRef<TGeoMatrixScheme>> by tObjectArray(TGeoMatrixScheme)
public val fShapes: List<ObjectRef<TGeoShapeScheme>> by tObjectArray(TGeoShapeScheme)
public val fVolumes: List<ObjectRef<TGeoVolumeScheme>> by tObjectArray(TGeoVolumeScheme)
public val fNodes: List<ObjectRef<TGeoNodeScheme>> by tObjectArray(TGeoNodeScheme)
public val refCache: List<Meta> by lazy {
val res = ArrayList<Meta>(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>(::TGeoManagerScheme) {
public fun parse(string: String): TGeoManagerScheme {
val meta = Json.decodeFromString(MetaSerializer, string)
return read(meta)
}
}
}

View File

@ -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 TaitBryan 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)
}
}

View File

@ -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 TaitBryan 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)
}
}

View File

@ -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<String> = sequence {
@ -25,14 +31,28 @@ private fun JsonElement.countTypes(): Sequence<String> = sequence {
}
}
private fun Meta.countTypes() :Sequence<String> = 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)

View File

@ -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<Composite>
@VisionBuilder
public inline fun VisionContainerBuilder<Solid>.composite(
@ -30,7 +31,7 @@ public inline fun VisionContainerBuilder<Solid>.composite(
): Composite {
val group = SolidGroup().apply(builder)
val children = group.children.values.filterIsInstance<Solid>()
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)

View File

@ -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?,