0.2.0 #71
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,8 +5,14 @@ import kotlinx.serialization.json.JsonElement
|
|||||||
import kotlinx.serialization.json.JsonObject
|
import kotlinx.serialization.json.JsonObject
|
||||||
import kotlinx.serialization.json.jsonPrimitive
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
import ru.mipt.npm.root.serialization.TGeoManager
|
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 space.kscience.visionforge.solid.Solids
|
||||||
|
import java.nio.file.Paths
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
|
import kotlin.io.path.writeText
|
||||||
import kotlin.system.measureTimeMillis
|
import kotlin.system.measureTimeMillis
|
||||||
|
|
||||||
private fun JsonElement.countTypes(): Sequence<String> = sequence {
|
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() {
|
fun main() {
|
||||||
val string = TGeoManager::class.java.getResourceAsStream("/BM@N.root.json")!!
|
val string = TGeoManager::class.java.getResourceAsStream("/BM@N.root.json")!!
|
||||||
.readAllBytes().decodeToString()
|
.readAllBytes().decodeToString()
|
||||||
val time = measureTimeMillis {
|
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()
|
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)
|
// val json = Json.parseToJsonElement(string)
|
||||||
|
@ -5,6 +5,7 @@ import kotlinx.serialization.Serializable
|
|||||||
import space.kscience.dataforge.meta.update
|
import space.kscience.dataforge.meta.update
|
||||||
import space.kscience.visionforge.VisionBuilder
|
import space.kscience.visionforge.VisionBuilder
|
||||||
import space.kscience.visionforge.VisionContainerBuilder
|
import space.kscience.visionforge.VisionContainerBuilder
|
||||||
|
import space.kscience.visionforge.VisionPropertyContainer
|
||||||
import space.kscience.visionforge.set
|
import space.kscience.visionforge.set
|
||||||
|
|
||||||
public enum class CompositeType {
|
public enum class CompositeType {
|
||||||
@ -20,7 +21,7 @@ public class Composite(
|
|||||||
public val compositeType: CompositeType,
|
public val compositeType: CompositeType,
|
||||||
public val first: Solid,
|
public val first: Solid,
|
||||||
public val second: Solid,
|
public val second: Solid,
|
||||||
) : SolidBase(), Solid
|
) : SolidBase(), VisionPropertyContainer<Composite>
|
||||||
|
|
||||||
@VisionBuilder
|
@VisionBuilder
|
||||||
public inline fun VisionContainerBuilder<Solid>.composite(
|
public inline fun VisionContainerBuilder<Solid>.composite(
|
||||||
@ -30,7 +31,7 @@ public inline fun VisionContainerBuilder<Solid>.composite(
|
|||||||
): Composite {
|
): Composite {
|
||||||
val group = SolidGroup().apply(builder)
|
val group = SolidGroup().apply(builder)
|
||||||
val children = group.children.values.filterIsInstance<Solid>()
|
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])
|
val res = Composite(type, children[0], children[1])
|
||||||
|
|
||||||
res.meta.update(group.meta)
|
res.meta.update(group.meta)
|
||||||
|
@ -165,7 +165,7 @@ public fun SolidGroup.ref(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Add new [SolidReferenceGroup] wrapping given object and automatically adding it to the prototypes.
|
* 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(
|
public fun SolidGroup.newRef(
|
||||||
name: String?,
|
name: String?,
|
||||||
|
Loading…
Reference in New Issue
Block a user