WIP Root to Solid conversion

This commit is contained in:
Alexander Nozik 2021-08-25 23:00:05 +03:00
parent df30f8ecc3
commit 193665b99a
6 changed files with 166 additions and 151 deletions

View File

@ -25,10 +25,10 @@ private fun <T> jsonRootDeserializer(tSerializer: KSerializer<T>, builder: (Json
/** /**
* Load Json encoded TObject * Load Json encoded TObject
*/ */
public fun TObject.Companion.decodeFromJson(serializer: KSerializer<out TObject>, jsonElement: JsonElement): TObject = public fun <T: TObject> TObject.Companion.decodeFromJson(serializer: KSerializer<T>, jsonElement: JsonElement): T =
RootDecoder.decode(serializer, jsonElement) RootDecoder.decode(serializer, jsonElement)
public fun TObject.Companion.decodeFromString(serializer: KSerializer<out TObject>, string: String): TObject { public fun <T: TObject> TObject.Companion.decodeFromString(serializer: KSerializer<T>, string: String): T {
val json = RootDecoder.json.parseToJsonElement(string) val json = RootDecoder.json.parseToJsonElement(string)
return RootDecoder.decode(serializer, json) return RootDecoder.decode(serializer, json)
} }
@ -49,12 +49,14 @@ private object RootDecoder {
//Forward ref for shapes //Forward ref for shapes
when (tSerializer.descriptor.serialName) { when (tSerializer.descriptor.serialName) {
"TGeoShape" -> return TGeoShapeRef { "TGeoShape" -> return TGeoShapeRef {
//Should be not null at the moment of actualization refCache[refId].getOrPutValue {
refCache[refId].value as TGeoShape input.json.decodeFromJsonElement(tSerializer, it) as TGeoShape
}
} as T } as T
"TGeoVolumeAssembly" -> return TGeoVolumeAssemblyRef { "TGeoVolumeAssembly" -> return TGeoVolumeAssemblyRef {
//Should be not null at the moment of actualization refCache[refId].getOrPutValue {
refCache[refId].value as TGeoVolumeAssembly input.json.decodeFromJsonElement(tSerializer, it) as TGeoVolumeAssembly
}
} as T } as T
//Do unref //Do unref
else -> refCache[refId] else -> refCache[refId]
@ -138,7 +140,7 @@ private object RootDecoder {
} }
fun decode(sourceDeserializer: KSerializer<out TObject>, source: JsonElement): TObject { fun <T: TObject> decode(sourceDeserializer: KSerializer<T>, source: JsonElement): T {
val refCache = ArrayList<RefEntry>() val refCache = ArrayList<RefEntry>()
fun fillCache(element: JsonElement) { fun fillCache(element: JsonElement) {

View File

@ -2,7 +2,7 @@ package ru.mipt.npm.root
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.asName
import space.kscience.visionforge.setPropertyNode import space.kscience.dataforge.names.plus
import space.kscience.visionforge.solid.* import space.kscience.visionforge.solid.*
import kotlin.math.PI import kotlin.math.PI
import kotlin.math.atan2 import kotlin.math.atan2
@ -19,158 +19,162 @@ private operator fun Number.times(f: Float) = toFloat() * f
private fun degToRad(d: Double) = d * PI / 180.0 private 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)
}
// converting to XYZ to TaitBryan angles according to https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix private fun Solid.translate(trans: DoubleArray) {
private fun Solid.rotate(rot: DoubleArray) { val (x, y, z) = trans
val xAngle = atan2(-rot[5], rot[8]) position = Point3D(x, y, z)
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) { private fun Solid.useMatrix(matrix: TGeoMatrix?) {
val (x, y, z) = trans when (matrix) {
position = Point3D(x, y, z) null, is TGeoIdentity -> {
} //do nothing
}
private fun Solid.useMatrix(matrix: TGeoMatrix?) { is TGeoTranslation -> {
when (matrix) { translate(matrix.fTranslation)
null, is TGeoIdentity -> { }
//do nothing is TGeoRotation -> {
} rotate(matrix.fRotationMatrix)
is TGeoTranslation -> { }
translate(matrix.fTranslation) is TGeoCombiTrans -> {
} translate(matrix.fTranslation)
is TGeoRotation -> { matrix.fRotation?.let { rotate(it.fRotationMatrix) }
rotate(matrix.fRotationMatrix) }
} is TGeoHMatrix -> {
is TGeoCombiTrans -> { translate(matrix.fTranslation)
translate(matrix.fTranslation) rotate(matrix.fRotationMatrix)
matrix.fRotation?.let { rotate(it.fRotationMatrix) } val (xScale, yScale, zScale) = matrix.fScale
} scale = Point3D(xScale, yScale, zScale)
is TGeoHMatrix -> {
translate(matrix.fTranslation)
rotate(matrix.fRotationMatrix)
val (xScale, yScale, zScale) = matrix.fScale
scale = Point3D(xScale, yScale, zScale)
}
} }
} }
}
fun SolidGroup.addShape(shape: TGeoShape) { private fun SolidGroup.addShape(shape: TGeoShape) {
when (shape) { when (shape) {
is TGeoShapeRef -> addShape(shape.value) is TGeoShapeRef -> addShape(shape.value)
is TGeoCompositeShape -> { is TGeoCompositeShape -> {
val bool: TGeoBoolNode = shape.fNode val bool: TGeoBoolNode = shape.fNode
val compositeType = when (bool) { val compositeType = when (bool) {
is TGeoIntersection -> CompositeType.INTERSECT is TGeoIntersection -> CompositeType.INTERSECT
is TGeoSubtraction -> CompositeType.SUBTRACT is TGeoSubtraction -> CompositeType.SUBTRACT
is TGeoUnion -> CompositeType.UNION is TGeoUnion -> CompositeType.UNION
}
composite(compositeType, name = shape.fName) {
addShape(bool.fLeft).apply {
useMatrix(bool.fLeftMat)
} }
composite(compositeType, name = shape.fName) { addShape(bool.fRight).apply {
addShape(bool.fLeft).apply { useMatrix(bool.fRightMat)
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)
} }
} is TGeoXtru -> extruded(name = shape.fName) {
fun SolidGroup.node(obj: TGeoNode) { (0 until shape.fNvert).forEach { index ->
if (obj.fVolume != null) { shape {
volume(obj.fVolume).apply { point(shape.fX[index], shape.fY[index])
when (obj) { }
is TGeoNodeMatrix -> { }
useMatrix(obj.fMatrix)
} (0 until shape.fNz).forEach { index ->
is TGeoNodeOffset -> { layer(
x = obj.fOffset shape.fZ[index],
} shape.fX0[index],
shape.fY0[index],
shape.fScale[index]
)
}
}
is TGeoTube -> tube(
radius = shape.fRmax,
height = shape.fDz * 2,
innerRadius = shape.fRmin,
name = shape.fName
)
is TGeoTubeSeg -> tube(
radius = shape.fRmax,
height = shape.fDz * 2,
innerRadius = shape.fRmin,
startAngle = degToRad(shape.fPhi1),
angle = degToRad(shape.fPhi2 - shape.fPhi1),
name = shape.fName
)
is TGeoPcon -> TODO()
is TGeoPgon -> TODO()
is TGeoShapeAssembly -> volume(shape.fVolume)
is TGeoBBox -> box(shape.fDX * 2, shape.fDY * 2, shape.fDZ * 2, name = shape.fName)
}
}
private fun SolidGroup.node(obj: TGeoNode) {
if (obj.fVolume != null) {
volume(obj.fVolume).apply {
when (obj) {
is TGeoNodeMatrix -> {
useMatrix(obj.fMatrix)
}
is TGeoNodeOffset -> {
x = obj.fOffset
} }
} }
} }
} }
}
fun buildGroup(volume: TGeoVolume): SolidGroup { private fun buildGroup(volume: TGeoVolume): SolidGroup {
return if (volume is TGeoVolumeAssemblyRef) { return if (volume is TGeoVolumeAssemblyRef) {
buildGroup(volume.value) buildGroup(volume.value)
} else { } else {
SolidGroup { SolidGroup {
volume.fShape?.let { addShape(it) } volume.fShape?.let { addShape(it) }
volume.fNodes?.let { volume.fNodes?.let {
it.arr.forEach { obj -> it.arr.forEach { obj ->
node(obj) node(obj)
}
} }
} }
} }
} }
}
private val SolidGroup.rootPrototypes: SolidGroup get() = (parent as? SolidGroup)?.rootPrototypes ?: this private val SolidGroup.rootPrototypes: SolidGroup get() = (parent as? SolidGroup)?.rootPrototypes ?: this
fun SolidGroup.volume(volume: TGeoVolume): SolidGroup { private fun SolidGroup.volume(volume: TGeoVolume, cache: Boolean = true): Solid {
val group = buildGroup(volume) val group = buildGroup(volume)
val ref = rootPrototypes.prototypes { return if (!cache) {
group
} else newRef(
name = volume.fName.ifEmpty { null },
obj = group,
prototypeHolder = rootPrototypes,
templateName = volumesName + Name.parse(volume.fName.ifEmpty { group.toString() })
)
}
} // private fun load(geo: TGeoManager): SolidGroup {
set(volume.fName.ifEmpty { null }?.asName(), group) //// /**
return group //// * 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>>()
// }
public fun TGeoManager.toSolid(): SolidGroup = SolidGroup {
fNodes.arr.forEach {
node(it)
} }
fun load(geo: TGeoManager): SolidGroup {
/**
* A special group for local templates
*/
val proto = SolidGroup()
val solids = proto.group(solidsName) {
setPropertyNode("edges.enabled", false)
}
val volumes = proto.group(volumesName)
val referenceStore = HashMap<Name, MutableList<SolidReferenceGroup>>()
TODO()
}
} }

View File

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

View File

@ -158,21 +158,28 @@ public fun SolidGroup.ref(
name: String? = null, name: String? = null,
): SolidReferenceGroup = SolidReferenceGroup(templateName).also { set(name, it) } ): SolidReferenceGroup = SolidReferenceGroup(templateName).also { set(name, it) }
/**
* Add new [SolidReferenceGroup] wrapping given object and automatically adding it to the prototypes
*/
public fun SolidGroup.ref( public fun SolidGroup.ref(
name: String, templateName: String,
name: String? = null,
): SolidReferenceGroup = ref(Name.parse(templateName), name)
/**
* Add new [SolidReferenceGroup] wrapping given object and automatically adding it to the prototypes.
* One must ensure that [prototypeHolder] is the owner of this group.
*/
public fun SolidGroup.newRef(
name: String?,
obj: Solid, obj: Solid,
templateName: Name = Name.parse(name), prototypeHolder: PrototypeHolder = this,
templateName: Name = Name.parse(name ?: obj.toString()),
): SolidReferenceGroup { ): SolidReferenceGroup {
val existing = getPrototype(templateName) val existing = getPrototype(templateName)
if (existing == null) { if (existing == null) {
prototypes { prototypeHolder.prototypes {
this[templateName] = obj set(templateName, obj)
} }
} else if (existing != obj) { } else if (existing != obj) {
error("Can't add different prototype on top of existing one") error("Can't add different prototype on top of existing one")
} }
return this@ref.ref(templateName, name) return ref(templateName, name)
} }

View File

@ -16,7 +16,7 @@ fun SolidGroup.refGroup(
block: MutableVisionGroup.() -> Unit block: MutableVisionGroup.() -> Unit
): SolidReferenceGroup { ): SolidReferenceGroup {
val group = SolidGroup().apply(block) val group = SolidGroup().apply(block)
return ref(name, group, templateName) return newRef(name, group, templateName = templateName)
} }
@ -42,7 +42,7 @@ class SerializationTest {
z = -100 z = -100
} }
val group = SolidGroup { val group = SolidGroup {
ref("cube", cube) newRef("cube", cube)
refGroup("pg", Name.parse("pg.content")) { refGroup("pg", Name.parse("pg.content")) {
sphere(50) { sphere(50) {
x = -100 x = -100

View File

@ -14,7 +14,7 @@ class SolidReferenceTest {
val theStyle by style { val theStyle by style {
SolidMaterial.MATERIAL_COLOR_KEY put "red" SolidMaterial.MATERIAL_COLOR_KEY put "red"
} }
ref("test", Box(100f,100f,100f).apply { newRef("test", Box(100f,100f,100f).apply {
color("blue") color("blue")
useStyle(theStyle) useStyle(theStyle)
}) })