Compare commits

..

No commits in common. "ae12084dee1cab085869cd219494b8ba263ab21a" and "6a801f9999df5d29640802f74f6bff5c93ceff51" have entirely different histories.

8 changed files with 60 additions and 99 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()]?.takeIf { it.value != Null }?.let { resolve(builder, it) } meta[key ?: property.name.asName()]?.let { resolve(builder, it) }
} }
} }
@ -62,7 +62,8 @@ 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)
@ -89,69 +90,27 @@ 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 sealed class DGeoMatrix(meta: Meta, refCache: DObjectCache) : DNamed(meta, refCache) public open class DGeoMatrix(meta: Meta, refCache: DObjectCache) : DNamed(meta, refCache)
public class DGeoIdentity(meta: Meta, refCache: DObjectCache) : DGeoMatrix(meta, refCache) public open class DGeoScale(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,23 +1,16 @@
package ru.mipt.npm.root package ru.mipt.npm.root
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.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.PI import kotlin.math.*
import kotlin.math.cos
import kotlin.math.sin
private val volumesName = Name.EMPTY //"volumes".asName() private val volumesName = Name.EMPTY //"volumes".asName()
@ -35,10 +28,12 @@ private data class RootToSolidContext(
val colorCache: MutableMap<Meta, String> = mutableMapOf(), val colorCache: MutableMap<Meta, String> = mutableMapOf(),
) )
// apply rotation from a matrix // converting to XYZ to TaitBryan angles according to https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
private fun Solid.rotate(rot: DoubleArray) { private fun Solid.rotate(rot: DoubleArray) {
val matrix = VirtualMatrix(3, 3) { i, j -> rot[i * 3 + j] } val xAngle = atan2(-rot[5], rot[8])
quaternion = Quaternion.fromRotationMatrix(matrix) val yAngle = atan2(rot[2], sqrt(1.0 - rot[2].pow(2)))
val zAngle = atan2(-rot[1], rot[0])
rotation = Float32Vector3D(xAngle, yAngle, zAngle)
} }
private fun Solid.translate(trans: DoubleArray) { private fun Solid.translate(trans: DoubleArray) {
@ -46,32 +41,39 @@ private fun Solid.translate(trans: DoubleArray) {
position = Float32Vector3D(x, y, z) position = Float32Vector3D(x, y, z)
} }
private fun Solid.scale(s: DoubleArray) { private fun Solid.useMatrix(matrix: DGeoMatrix?) {
scale = Float32Vector3D(s[0], s[1], s[2]) if (matrix == null) return
when (matrix.typename) {
"TGeoIdentity" -> {
//do nothing
} }
private fun Solid.useMatrix(matrix: DGeoMatrix?): Unit { "TGeoTranslation" -> {
when (matrix) { val fTranslation by matrix.meta.doubleArray()
null -> {} translate(fTranslation)
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)
} }
is DGeoCombiTrans -> { "TGeoRotation" -> {
translate(matrix.fTranslation) val fRotationMatrix by matrix.meta.doubleArray()
matrix.fRotation?.fRotationMatrix?.let { rotate(it) } rotate(fRotationMatrix)
} }
is DGeoHMatrix -> { "TGeoCombiTrans" -> {
translate(matrix.fTranslation) val fTranslation by matrix.meta.doubleArray()
matrix.fRotation?.fRotationMatrix?.let { rotate(it) }
scale(matrix.fScale) translate(fTranslation)
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])
} }
} }
} }
@ -94,10 +96,10 @@ private fun SolidGroup.addShape(
} }
smartComposite(compositeType, name = name) { smartComposite(compositeType, name = name) {
addShape(node.fLeft!!, context, null) { addShape(node.fLeft!!, context, null) {
useMatrix(node.fLeftMat) this.useMatrix(node.fLeftMat)
} }
addShape(node.fRight!!, context, null) { addShape(node.fRight!!, context, null) {
useMatrix(node.fRightMat) this.useMatrix(node.fRightMat)
} }
}.apply(block) }.apply(block)
} }
@ -281,7 +283,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
solidGroup("antenna") { val 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.quaternionOrNull: Quaternion? public var Solid.quaternionValue: 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.quaternionOrNull: 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() = quaternionOrNull ?: Quaternion.fromEuler( get() = quaternionValue ?: Quaternion.fromEuler(
rotationX.radians, rotationX.radians,
rotationY.radians, rotationY.radians,
rotationZ.radians, rotationZ.radians,
rotationOrder rotationOrder
) )
set(value) { set(value) {
quaternionOrNull = value quaternionValue = 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.quaternionOrNull val quaternion = vision.quaternionValue
if (quaternion != null) { if (quaternion != null) {
setRotationFromQuaternion( setRotationFromQuaternion(