Add polygon and polycone and add generics to TObjectArray

This commit is contained in:
Alexander Nozik 2021-08-25 18:04:15 +03:00
parent e39f79e4ab
commit df30f8ecc3
12 changed files with 297 additions and 97 deletions

View File

@ -1,7 +1,7 @@
plugins {
id("ru.mipt.npm.gradle.project")
// kotlin("multiplatform") version "1.5.30-RC" apply false
// kotlin("js") version "1.5.30-RC" apply false
kotlin("multiplatform") version "1.5.30" apply false
kotlin("js") version "1.5.30" apply false
}
val dataforgeVersion by extra("0.5.1")

View File

@ -1,26 +0,0 @@
package ru.mipt.npm.root
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.JsonElement
@Serializable(JsonRootSerializer::class)
public class JsonRootObject(public val element: JsonElement): TObject()
public object JsonRootSerializer: KSerializer<JsonRootObject>{
private val jsonElementSerializer = JsonElement.serializer()
override val descriptor: SerialDescriptor
get() = jsonElementSerializer.descriptor
override fun deserialize(decoder: Decoder): JsonRootObject {
return JsonRootObject(decoder.decodeSerializableValue(jsonElementSerializer))
}
override fun serialize(encoder: Encoder, value: JsonRootObject) {
encoder.encodeSerializableValue(jsonElementSerializer, value.element)
}
}

View File

@ -9,11 +9,14 @@ import kotlinx.serialization.Serializable
public class TGeoManager : TNamed() {
@Contextual
public val fMatrices: TObjArray = TObjArray.empty
public val fMatrices: TObjArray<TGeoMatrix> = TObjArray.getEmpty()
@Contextual
public val fShapes: TObjArray = TObjArray.empty
public val fShapes: TObjArray<TGeoShape> = TObjArray.getEmpty()
@Contextual
public val fVolumes: TObjArray = TObjArray.empty
public val fVolumes: TObjArray<TGeoVolume> = TObjArray.getEmpty()
@Contextual
public val fNodes: TObjArray<TGeoNode> = TObjArray.getEmpty()
}

View File

@ -6,7 +6,7 @@ import kotlinx.serialization.Serializable
@Serializable
@SerialName("TGeoNode")
public open class TGeoNode : TNamed() {
public sealed class TGeoNode : TNamed() {
public val fGeoAtt: UInt = 0u
@Contextual
@ -26,3 +26,9 @@ public class TGeoNodeMatrix : TGeoNode() {
@Contextual
public val fMatrix: TGeoMatrix? = null
}
@Serializable
@SerialName("TGeoNodeOffset")
public class TGeoNodeOffset : TGeoNode() {
public val fOffset: Double = 0.0
}

View File

@ -3,6 +3,7 @@ package ru.mipt.npm.root
import kotlinx.serialization.Contextual
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlin.math.PI
@Serializable
@SerialName("TGeoShape")
@ -27,13 +28,13 @@ public sealed class TGeoBoolNode : TObject() {
public abstract val fLeft: TGeoShape
@Contextual
public abstract val fLeftMat: TGeoMatrix
public val fLeftMat: TGeoMatrix? = null
@Contextual
public abstract val fRight: TGeoShape
@Contextual
public abstract val fRightMat: TGeoMatrix
public val fRightMat: TGeoMatrix? = null
}
@Serializable
@ -42,11 +43,7 @@ public class TGeoUnion(
@Contextual
override val fLeft: TGeoShape,
@Contextual
override val fLeftMat: TGeoMatrix,
@Contextual
override val fRight: TGeoShape,
@Contextual
override val fRightMat: TGeoMatrix
) : TGeoBoolNode()
@Serializable
@ -55,11 +52,7 @@ public class TGeoSubtraction(
@Contextual
override val fLeft: TGeoShape,
@Contextual
override val fLeftMat: TGeoMatrix,
@Contextual
override val fRight: TGeoShape,
@Contextual
override val fRightMat: TGeoMatrix
) : TGeoBoolNode()
@Serializable
@ -68,11 +61,7 @@ public class TGeoIntersection(
@Contextual
override val fLeft: TGeoShape,
@Contextual
override val fLeftMat: TGeoMatrix,
@Contextual
override val fRight: TGeoShape,
@Contextual
override val fRightMat: TGeoMatrix
) : TGeoBoolNode()
@ -97,18 +86,15 @@ public class TGeoXtru(
@Serializable
@SerialName("TGeoTube")
public open class TGeoTube(
public val fRmin: Double,
public val fRmax: Double,
public val fDz: Double,
) : TGeoBBox()
public open class TGeoTube : TGeoBBox() {
public val fRmin: Double = 0.0
public val fRmax: Double = 0.0
public val fDz: Double = 0.0
}
@Serializable
@SerialName("TGeoTubeSeg")
public class TGeoTubeSeg(
public val fRmin: Double,
public val fRmax: Double,
public val fDz: Double,
public val fPhi1: Double,
public val fPhi2: Double,
public val fS1: Double,
@ -118,7 +104,24 @@ public class TGeoTubeSeg(
public val fSm: Double,
public val fCm: Double,
public val fCdfi: Double,
) : TGeoBBox()
) : TGeoTube()
@Serializable
@SerialName("TGeoPcon")
public open class TGeoPcon : TGeoBBox() {
public val fNz: Int = 0 // number of z planes (at least two)
public val fPhi1: Double = 0.0 // lower phi limit (converted to [0,2*pi)
public val fDphi: Double = PI * 2 // phi range
public val fRmin: DoubleArray = doubleArrayOf() //[fNz] pointer to array of inner radii
public val fRmax: DoubleArray = doubleArrayOf() //[fNz] pointer to array of outer radii
public val fZ: DoubleArray = doubleArrayOf() //[fNz] pointer to array of Z planes positions
}
@Serializable
@SerialName("TGeoPgon")
public open class TGeoPgon : TGeoPcon() {
public val fNedges: Int = 0
}
@Serializable
@SerialName("TGeoShapeAssembly")

View File

@ -15,7 +15,7 @@ public open class TGeoVolume : TNamed() {
public val fFillStyle: Int? = null
@Contextual
public val fNodes: TObjArray? = null
public val fNodes: TObjArray<TGeoNode>? = null
@Contextual
public val fShape: TGeoShape? = null

View File

@ -19,9 +19,9 @@ public open class TNamed : TObject() {
@Serializable
@SerialName("TObjArray")
public class TObjArray(public val arr: List<@Contextual TObject>): TObject() {
public class TObjArray<T: TObject>(public val arr: List<@Contextual T>): TObject() {
public companion object{
public val empty: TObjArray = TObjArray(emptyList())
public fun <T: TObject> getEmpty(): TObjArray<T> = TObjArray(emptyList())
}
}

View File

@ -1,12 +1,27 @@
package ru.mipt.npm.root
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.json.*
import kotlinx.serialization.modules.*
private fun <T> jsonRootDeserializer(tSerializer: KSerializer<T>, builder: (JsonElement) -> T): DeserializationStrategy<T> = object :
DeserializationStrategy<T> {
private val jsonElementSerializer = JsonElement.serializer()
override val descriptor: SerialDescriptor
get() = jsonElementSerializer.descriptor
override fun deserialize(decoder: Decoder): T {
val json = decoder.decodeSerializableValue(jsonElementSerializer)
return builder(json)
}
}
/**
* Load Json encoded TObject
*/
@ -22,8 +37,7 @@ private object RootDecoder {
private class RootUnrefSerializer<T>(
private val tSerializer: KSerializer<T>,
private val refCache: List<RefEntry>,// = ArrayList<RefEntry>(4096)
//private val counter: ReferenceCounter
private val refCache: List<RefEntry>,
) : KSerializer<T> by tSerializer {
override fun deserialize(decoder: Decoder): T {
@ -31,7 +45,7 @@ private object RootDecoder {
val element = input.decodeJsonElement()
val refId = (element as? JsonObject)?.get("\$ref")?.jsonPrimitive?.int
val ref = if (refId != null) {
//println("Substituting ref $refId")
//println("Substituting ${tSerializer.descriptor.serialName} ref $refId")
//Forward ref for shapes
when (tSerializer.descriptor.serialName) {
"TGeoShape" -> return TGeoShapeRef {
@ -66,24 +80,50 @@ private object RootDecoder {
include(serializersModule)
contextual(TGeoManager.serializer().unref(refCache))
contextual(TObjArray.serializer().unref(refCache))
contextual(TObjArray::class) { TObjArray.serializer(it[0]).unref(refCache) }
contextual(TGeoVolumeAssembly.serializer().unref(refCache))
contextual(TGeoShapeAssembly.serializer().unref(refCache))
contextual(TGeoRotation.serializer().unref(refCache))
contextual(TGeoMedium.serializer().unref(refCache))
contextual(TGeoVolume.serializer().unref(refCache))
contextual(TGeoMatrix.serializer().unref(refCache))
contextual(TGeoNode.serializer().unref(refCache))
contextual(TGeoNodeOffset.serializer().unref(refCache))
contextual(TGeoNodeMatrix.serializer().unref(refCache))
contextual(TGeoShape.serializer().unref(refCache))
contextual(TObject.serializer().unref(refCache))
polymorphicDefault(TGeoShape::class) {
if (it == null) {
TGeoShape.serializer().unref(refCache)
} else {
error("Unrecognized shape $it")
}
}
polymorphicDefault(TGeoMatrix::class) {
if (it == null) {
TGeoMatrix.serializer().unref(refCache)
} else {
error("Unrecognized matrix $it")
}
}
polymorphicDefault(TGeoVolume::class) {
if (it == null) {
TGeoVolume.serializer().unref(refCache)
} else {
error("Unrecognized volume $it")
}
}
polymorphicDefault(TGeoNode::class) {
if (it == null) {
TGeoNode.serializer().unref(refCache)
} else {
error("Unrecognized node $it")
}
}
}
@ -126,14 +166,6 @@ private object RootDecoder {
return unrefJson(refCache).decodeFromJsonElement(sourceDeserializer.unref(refCache), source)
}
// class ReferenceCounter(var value: Int = 0) {
// fun increment() {
// value += 1
// }
//
// override fun toString(): String = value.toString()
// }
class RefEntry(val element: JsonElement) {
var value: Any? = null
@ -154,6 +186,8 @@ private object RootDecoder {
subclass(TGeoXtru.serializer())
subclass(TGeoTube.serializer())
subclass(TGeoTubeSeg.serializer())
subclass(TGeoPcon.serializer())
subclass(TGeoPgon.serializer())
subclass(TGeoShapeAssembly.serializer())
}
@ -173,25 +207,24 @@ private object RootDecoder {
private val serializersModule = SerializersModule {
polymorphic(TObject::class) {
default { JsonRootSerializer }
subclass(TObjArray.serializer())
shapes()
matrices()
boolNodes()
subclass(TGeoMaterial.serializer())
subclass(TGeoMixture.serializer())
subclass(TGeoMedium.serializer())
subclass(TGeoNode.serializer())
subclass(TGeoNodeMatrix.serializer())
subclass(TGeoVolume.serializer())
subclass(TGeoVolumeAssembly.serializer())
subclass(TGeoManager.serializer())
}
// polymorphic(TObject::class) {
// default { JsonRootSerializer }
//
// shapes()
// matrices()
// boolNodes()
//
// subclass(TGeoMaterial.serializer())
// subclass(TGeoMixture.serializer())
//
// subclass(TGeoMedium.serializer())
//
// //subclass(TGeoNode.serializer())
// subclass(TGeoNodeMatrix.serializer())
// subclass(TGeoVolume.serializer())
// subclass(TGeoVolumeAssembly.serializer())
// subclass(TGeoManager.serializer())
// }
polymorphic(TGeoShape::class) {
shapes()
@ -205,8 +238,9 @@ private object RootDecoder {
boolNodes()
}
polymorphic(TGeoNode::class, TGeoNode.serializer()) {
polymorphic(TGeoNode::class) {
subclass(TGeoNodeMatrix.serializer())
subclass(TGeoNodeOffset.serializer())
}
polymorphic(TGeoVolume::class, TGeoVolume.serializer()) {

View File

@ -0,0 +1,176 @@
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.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
private class GdmlLoader {
// 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: 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
}
composite(compositeType, name = shape.fName) {
addShape(bool.fLeft).apply {
useMatrix(bool.fLeftMat)
}
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)
}
}
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 val SolidGroup.rootPrototypes: SolidGroup get() = (parent as? SolidGroup)?.rootPrototypes ?: this
fun SolidGroup.volume(volume: TGeoVolume): SolidGroup {
val group = buildGroup(volume)
val ref = rootPrototypes.prototypes {
}
set(volume.fName.ifEmpty { null }?.asName(), group)
return group
}
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<Name, MutableList<SolidReferenceGroup>>()
TODO()
}
}

View File

@ -31,6 +31,7 @@ fun main() {
val time = measureTimeMillis {
val geo = TObject.decodeFromString(TGeoManager.serializer(), string)
println(geo)
}
println(Duration.ofMillis(time))

View File

@ -3,7 +3,7 @@ kotlin.mpp.enableGranularSourceSetsMetadata=true
kotlin.mpp.stability.nowarn=true
kotlin.native.enableDependencyPropagation=false
kotlin.jupyter.add.scanner=false
#kotlin.jupyter.add.scanner=false
org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G
org.gradle.parallel=true

View File

@ -5,7 +5,10 @@ import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import space.kscience.dataforge.meta.*
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MetaProvider
import space.kscience.dataforge.meta.float
import space.kscience.dataforge.meta.get
import space.kscience.visionforge.solid.Solid.Companion.X_KEY
import space.kscience.visionforge.solid.Solid.Companion.Y_KEY
import space.kscience.visionforge.solid.Solid.Companion.Z_KEY
@ -54,7 +57,7 @@ internal object Point3DSerializer : KSerializer<Point3D> {
override val descriptor: SerialDescriptor = Point3DImpl.serializer().descriptor
override fun deserialize(decoder: Decoder): Point3D = decoder.decodeSerializableValue(Point3DImpl.serializer())
override fun deserialize(decoder: Decoder): MutablePoint3D = decoder.decodeSerializableValue(Point3DImpl.serializer())
override fun serialize(encoder: Encoder, value: Point3D) {
val impl: Point3DImpl = (value as? Point3DImpl) ?: Point3DImpl(value.x, value.y, value.z)