feature/root #69
@ -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) {
|
||||||
|
@ -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 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)
|
||||||
|
}
|
||||||
|
|
||||||
// converting to XYZ to Tait–Bryan 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()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -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))
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user