Compare commits

..

2 Commits

Author SHA1 Message Date
ae12084dee Fix angle problems in Root importer 2023-09-30 12:51:11 +03:00
92bfb173d8 minor fix to Root rotations 2023-09-16 12:27:09 +03:00
8 changed files with 99 additions and 60 deletions

View File

@ -42,7 +42,7 @@ public open class DObject(public val meta: Meta, public val refCache: DObjectCac
} }
internal fun <T : DObject> tObjectArray( internal fun <T : DObject> tObjectArray(
builder: (Meta, DObjectCache) -> T builder: (Meta, DObjectCache) -> T,
): ReadOnlyProperty<Any?, List<T>> = ReadOnlyProperty { _, property -> ): ReadOnlyProperty<Any?, List<T>> = ReadOnlyProperty { _, property ->
meta.getIndexed(Name.of(property.name, "arr")).values.mapNotNull { meta.getIndexed(Name.of(property.name, "arr")).values.mapNotNull {
resolve(builder, it) resolve(builder, it)
@ -51,9 +51,9 @@ public open class DObject(public val meta: Meta, public val refCache: DObjectCac
internal fun <T : DObject> dObject( internal fun <T : DObject> dObject(
builder: (Meta, DObjectCache) -> T, builder: (Meta, DObjectCache) -> T,
key: Name? = null key: Name? = null,
): ReadOnlyProperty<Any?, T?> = ReadOnlyProperty { _, property -> ): ReadOnlyProperty<Any?, T?> = ReadOnlyProperty { _, property ->
meta[key ?: property.name.asName()]?.let { resolve(builder, it) } meta[key ?: property.name.asName()]?.takeIf { it.value != Null }?.let { resolve(builder, it) }
} }
} }
@ -62,8 +62,7 @@ public open class DNamed(meta: Meta, refCache: DObjectCache) : DObject(meta, ref
public val fTitle: String by meta.string("") public val fTitle: String by meta.string("")
} }
public class DGeoMaterial(meta: Meta, refCache: DObjectCache) : DNamed(meta, refCache) { public class DGeoMaterial(meta: Meta, refCache: DObjectCache) : DNamed(meta, refCache)
}
public class DGeoMedium(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 fMaterial: DGeoMaterial? by dObject(::DGeoMaterial)
@ -90,27 +89,69 @@ public class DGeoNode(meta: Meta, refCache: DObjectCache) : DNamed(meta, refCach
public val fVolume: DGeoVolume? by dObject(::DGeoVolume) public val fVolume: DGeoVolume? by dObject(::DGeoVolume)
} }
public open class DGeoMatrix(meta: Meta, refCache: DObjectCache) : DNamed(meta, refCache) public sealed class DGeoMatrix(meta: Meta, refCache: DObjectCache) : DNamed(meta, refCache)
public open class DGeoScale(meta: Meta, refCache: DObjectCache) : DGeoMatrix(meta, refCache) { public class DGeoIdentity(meta: Meta, refCache: DObjectCache) : DGeoMatrix(meta, refCache)
public class DGeoScale(meta: Meta, refCache: DObjectCache) : DGeoMatrix(meta, refCache) {
public val fScale: DoubleArray by meta.doubleArray(1.0, 1.0, 1.0) public val fScale: DoubleArray by meta.doubleArray(1.0, 1.0, 1.0)
public val x: Double get() = fScale[0] public val x: Double get() = fScale[0]
public val y: Double get() = fScale[1] public val y: Double get() = fScale[1]
public val z: Double get() = fScale[2] public val z: Double get() = fScale[2]
} }
public class DGeoRotation(meta: Meta, refCache: DObjectCache) : DGeoMatrix(meta, refCache) {
public val fRotationMatrix: DoubleArray by meta.doubleArray()
}
public class DGeoTranslation(meta: Meta, refCache: DObjectCache) : DGeoMatrix(meta, refCache) {
public val fTranslation: DoubleArray by meta.doubleArray()
}
public open class DGeoCombiTrans(meta: Meta, refCache: DObjectCache) : DGeoMatrix(meta, refCache) {
public val fRotation: DGeoRotation? by dObject(::DGeoRotation)
public val fTranslation: DoubleArray by meta.doubleArray()
}
public class DGeoGenTrans(meta: Meta, refCache: DObjectCache) : DGeoCombiTrans(meta, refCache) {
public val fScale: DoubleArray by meta.doubleArray()
}
public class DGeoHMatrix(meta: Meta, refCache: DObjectCache) : DGeoMatrix(meta, refCache) {
public val fRotation: DGeoRotation? by dObject(::DGeoRotation)
public val fTranslation: DoubleArray by meta.doubleArray()
public val fScale: DoubleArray by meta.doubleArray()
}
/**
* Create a specialized version of [DGeoMatrix]
*/
internal fun dGeoMatrix(
meta: Meta,
refCache: DObjectCache,
): DGeoMatrix = when (val typename = meta["_typename"].string) {
null -> error("Type name is undefined")
"TGeoIdentity" -> DGeoIdentity(meta, refCache)
"TGeoScale" -> DGeoScale(meta, refCache)
"TGeoRotation" -> DGeoRotation(meta, refCache)
"TGeoTranslation" -> DGeoTranslation(meta, refCache)
"TGeoCombiTrans" -> DGeoCombiTrans(meta, refCache)
"TGeoGenTrans" -> DGeoGenTrans(meta, refCache)
"TGeoHMatrix" -> DGeoHMatrix(meta, refCache)
else -> error("$typename is not a member of TGeoMatrix")
}
public class DGeoBoolNode(meta: Meta, refCache: DObjectCache) : DObject(meta, refCache) { public class DGeoBoolNode(meta: Meta, refCache: DObjectCache) : DObject(meta, refCache) {
public val fLeft: DGeoShape? by dObject(::DGeoShape) public val fLeft: DGeoShape? by dObject(::DGeoShape)
public val fLeftMat: DGeoMatrix? by dObject(::DGeoMatrix) public val fLeftMat: DGeoMatrix? by dObject(::dGeoMatrix)
public val fRight: DGeoShape? by dObject(::DGeoShape) public val fRight: DGeoShape? by dObject(::DGeoShape)
public val fRightMat: DGeoMatrix? by dObject(::DGeoMatrix) public val fRightMat: DGeoMatrix? by dObject(::dGeoMatrix)
} }
public class DGeoManager(meta: Meta, refCache: DObjectCache) : DNamed(meta, refCache) { public class DGeoManager(meta: Meta, refCache: DObjectCache) : DNamed(meta, refCache) {
public val fMatrices: List<DGeoMatrix> by tObjectArray(::DGeoMatrix) public val fMatrices: List<DGeoMatrix> by tObjectArray(::dGeoMatrix)
public val fShapes: List<DGeoShape> by tObjectArray(::DGeoShape) public val fShapes: List<DGeoShape> by tObjectArray(::DGeoShape)

View File

@ -1,16 +1,23 @@
package ru.mipt.npm.root package ru.mipt.npm.root
import space.kscience.dataforge.meta.* import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.double
import space.kscience.dataforge.meta.int
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.parseAsName import space.kscience.dataforge.names.parseAsName
import space.kscience.dataforge.names.plus import space.kscience.dataforge.names.plus
import space.kscience.dataforge.names.withIndex import space.kscience.dataforge.names.withIndex
import space.kscience.kmath.complex.Quaternion
import space.kscience.kmath.geometry.fromRotationMatrix
import space.kscience.kmath.linear.VirtualMatrix
import space.kscience.visionforge.MutableVisionContainer import space.kscience.visionforge.MutableVisionContainer
import space.kscience.visionforge.isEmpty import space.kscience.visionforge.isEmpty
import space.kscience.visionforge.set import space.kscience.visionforge.set
import space.kscience.visionforge.solid.* import space.kscience.visionforge.solid.*
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY
import kotlin.math.* import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin
private val volumesName = Name.EMPTY //"volumes".asName() private val volumesName = Name.EMPTY //"volumes".asName()
@ -28,12 +35,10 @@ private data class RootToSolidContext(
val colorCache: MutableMap<Meta, String> = mutableMapOf(), val colorCache: MutableMap<Meta, String> = mutableMapOf(),
) )
// converting to XYZ to TaitBryan angles according to https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix // apply rotation from a matrix
private fun Solid.rotate(rot: DoubleArray) { private fun Solid.rotate(rot: DoubleArray) {
val xAngle = atan2(-rot[5], rot[8]) val matrix = VirtualMatrix(3, 3) { i, j -> rot[i * 3 + j] }
val yAngle = atan2(rot[2], sqrt(1.0 - rot[2].pow(2))) quaternion = Quaternion.fromRotationMatrix(matrix)
val zAngle = atan2(-rot[1], rot[0])
rotation = Float32Vector3D(xAngle, yAngle, zAngle)
} }
private fun Solid.translate(trans: DoubleArray) { private fun Solid.translate(trans: DoubleArray) {
@ -41,39 +46,32 @@ private fun Solid.translate(trans: DoubleArray) {
position = Float32Vector3D(x, y, z) position = Float32Vector3D(x, y, z)
} }
private fun Solid.useMatrix(matrix: DGeoMatrix?) { private fun Solid.scale(s: DoubleArray) {
if (matrix == null) return scale = Float32Vector3D(s[0], s[1], s[2])
when (matrix.typename) {
"TGeoIdentity" -> {
//do nothing
} }
"TGeoTranslation" -> { private fun Solid.useMatrix(matrix: DGeoMatrix?): Unit {
val fTranslation by matrix.meta.doubleArray() when (matrix) {
translate(fTranslation) null -> {}
is DGeoIdentity -> {}
is DGeoTranslation -> translate(matrix.fTranslation)
is DGeoRotation -> rotate(matrix.fRotationMatrix)
is DGeoScale -> scale(matrix.fScale)
is DGeoGenTrans -> {
translate(matrix.fTranslation)
matrix.fRotation?.fRotationMatrix?.let { rotate(it) }
scale(matrix.fScale)
} }
"TGeoRotation" -> { is DGeoCombiTrans -> {
val fRotationMatrix by matrix.meta.doubleArray() translate(matrix.fTranslation)
rotate(fRotationMatrix) matrix.fRotation?.fRotationMatrix?.let { rotate(it) }
} }
"TGeoCombiTrans" -> { is DGeoHMatrix -> {
val fTranslation by matrix.meta.doubleArray() translate(matrix.fTranslation)
matrix.fRotation?.fRotationMatrix?.let { rotate(it) }
translate(fTranslation) scale(matrix.fScale)
matrix.meta["fRotation.fRotationMatrix"]?.value?.let {
rotate(it.doubleArray)
}
}
"TGeoHMatrix" -> {
val fTranslation by matrix.meta.doubleArray()
val fRotationMatrix by matrix.meta.doubleArray()
val fScale by matrix.meta.doubleArray()
translate(fTranslation)
rotate(fRotationMatrix)
scale = Float32Vector3D(fScale[0], fScale[1], fScale[2])
} }
} }
} }
@ -96,10 +94,10 @@ private fun SolidGroup.addShape(
} }
smartComposite(compositeType, name = name) { smartComposite(compositeType, name = name) {
addShape(node.fLeft!!, context, null) { addShape(node.fLeft!!, context, null) {
this.useMatrix(node.fLeftMat) useMatrix(node.fLeftMat)
} }
addShape(node.fRight!!, context, null) { addShape(node.fRight!!, context, null) {
this.useMatrix(node.fRightMat) useMatrix(node.fRightMat)
} }
}.apply(block) }.apply(block)
} }
@ -283,7 +281,7 @@ private fun SolidGroup.addRootNode(obj: DGeoNode, context: RootToSolidContext) {
addRootVolume(volume, context, obj.fName) { addRootVolume(volume, context, obj.fName) {
when (obj.typename) { when (obj.typename) {
"TGeoNodeMatrix" -> { "TGeoNodeMatrix" -> {
val fMatrix by obj.dObject(::DGeoMatrix) val fMatrix by obj.dObject(::dGeoMatrix)
this.useMatrix(fMatrix) this.useMatrix(fMatrix)
} }

View File

@ -15,13 +15,13 @@ import kotlin.math.sin
fun main() = serve { fun main() = serve {
val azimuth = 60.degrees // val azimuth = 60.degrees
val inclination = 15.degrees // val inclination = 15.degrees
val direction = with(QuaternionField) { // val direction = with(QuaternionField) {
Quaternion.fromRotation(-azimuth, Euclidean3DSpace.zAxis) * // Quaternion.fromRotation(-azimuth, Euclidean3DSpace.zAxis) *
Quaternion.fromRotation(Angle.piDiv2 - inclination, Euclidean3DSpace.yAxis) // Quaternion.fromRotation(Angle.piDiv2 - inclination, Euclidean3DSpace.yAxis)
} // }
//val direction2 = Quaternion.fromEuler(Angle.zero, Angle.piDiv2 - inclination, -azimuth, RotationOrder.ZYX) //val direction2 = Quaternion.fromEuler(Angle.zero, Angle.piDiv2 - inclination, -azimuth, RotationOrder.ZYX)
@ -43,7 +43,7 @@ fun main() = serve {
solidGroup("frame") { solidGroup("frame") {
z = 60 z = 60
val antenna = solidGroup("antenna") { solidGroup("antenna") {
axes(200) axes(200)
tube(40, 10, 30) tube(40, 10, 30)
sphereLayer(100, 95, theta = PI / 6) { sphereLayer(100, 95, theta = PI / 6) {

View File

@ -206,7 +206,7 @@ public var Solid.rotationZ: Number by float(Z_ROTATION_KEY, 0f)
/** /**
* Raw quaternion value defined in properties * Raw quaternion value defined in properties
*/ */
public var Solid.quaternionValue: Quaternion? public var Solid.quaternionOrNull: Quaternion?
get() = properties.getValue(ROTATION_KEY)?.list?.let { get() = properties.getValue(ROTATION_KEY)?.list?.let {
require(it.size == 4) { "Quaternion must be a number array of 4 elements" } require(it.size == 4) { "Quaternion must be a number array of 4 elements" }
Quaternion(it[0].float, it[1].float, it[2].float, it[3].float) Quaternion(it[0].float, it[1].float, it[2].float, it[3].float)
@ -229,14 +229,14 @@ public var Solid.quaternionValue: Quaternion?
* Quaternion value including information from euler angles * Quaternion value including information from euler angles
*/ */
public var Solid.quaternion: Quaternion public var Solid.quaternion: Quaternion
get() = quaternionValue ?: Quaternion.fromEuler( get() = quaternionOrNull ?: Quaternion.fromEuler(
rotationX.radians, rotationX.radians,
rotationY.radians, rotationY.radians,
rotationZ.radians, rotationZ.radians,
rotationOrder rotationOrder
) )
set(value) { set(value) {
quaternionValue = value quaternionOrNull = value
} }
public var Solid.scaleX: Number by float(X_SCALE_KEY, 1f) public var Solid.scaleX: Number by float(X_SCALE_KEY, 1f)

View File

@ -41,7 +41,7 @@ public fun Object3D.updatePosition(vision: Vision) {
if (vision is Solid) { if (vision is Solid) {
position.set(vision.x, vision.y, vision.z) position.set(vision.x, vision.y, vision.z)
val quaternion = vision.quaternionValue val quaternion = vision.quaternionOrNull
if (quaternion != null) { if (quaternion != null) {
setRotationFromQuaternion( setRotationFromQuaternion(