Reimplemented coordinates as properties

This commit is contained in:
Alexander Nozik 2021-07-11 13:43:56 +03:00
parent 2b6942b827
commit 7b30b62849
11 changed files with 107 additions and 150 deletions

View File

@ -48,7 +48,7 @@ class FXCompositeFactory(val plugin: FX3DPlugin) : FX3DFactory<Composite> {
val firstCSG = first.toCSG() val firstCSG = first.toCSG()
val secondCSG = second.toCSG() val secondCSG = second.toCSG()
val resultCSG = when (obj.compositeType) { val resultCSG = when (obj.compositeType) {
CompositeType.UNION -> firstCSG.union(secondCSG) CompositeType.SUM, CompositeType.UNION -> firstCSG.union(secondCSG)
CompositeType.INTERSECT -> firstCSG.intersect(secondCSG) CompositeType.INTERSECT -> firstCSG.intersect(secondCSG)
CompositeType.SUBTRACT -> firstCSG.difference(secondCSG) CompositeType.SUBTRACT -> firstCSG.difference(secondCSG)
} }

View File

@ -1,75 +0,0 @@
package space.kscience.visionforge.gdml
import space.kscience.dataforge.meta.itemSequence
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.visionforge.Vision
import space.kscience.visionforge.meta
import space.kscience.visionforge.solid.*
public expect class Counter() {
public fun get(): Int
public fun incrementAndGet(): Int
}
@DFExperimental
internal fun Vision.updateFrom(other: Vision): Vision {
if (this is Solid && other is Solid) {
position += other.position
rotation += other.rotation
scaleX = scaleX.toDouble() * other.scaleX.toDouble()
scaleY = scaleY.toDouble() * other.scaleY.toDouble()
scaleZ = scaleZ.toDouble() * other.scaleZ.toDouble()
other.meta.itemSequence().forEach { (name, item) ->
if (getProperty(name) == null) {
setProperty(name, item)
}
}
}
return this
}
//
//@DFExperimental
//private class GdmlOptimizer() : VisionVisitor {
// val logger = KotlinLogging.logger("SingleChildReducer")
//
// private val depthCount = HashMap<Int, Counter>()
//
// override suspend fun visit(name: Name, vision: Vision) {
// val depth = name.length
// depthCount.getOrPut(depth) { Counter() }.incrementAndGet()
// }
//
// override fun skip(name: Name, vision: Vision): Boolean = vision is Proxy.ProxyChild
//
// override suspend fun visitChildren(name: Name, group: VisionGroup) {
// if (name == "volumes".toName()) return
// if (group !is MutableVisionGroup) return
//
// val newChildren = group.children.entries.associate { (visionToken, vision) ->
// //Reduce single child groups
// if (vision is VisionGroup && vision !is Proxy && vision.children.size == 1) {
// val (token, child) = vision.children.entries.first()
// child.parent = null
// if (token != visionToken) {
// child.config["solidName"] = token.toString()
// }
// visionToken to child.updateFrom(vision)
// } else {
// visionToken to vision
// }
// }
// if (newChildren != group.children) {
// group.removeAll()
// newChildren.forEach { (token, child) ->
// group[token] = child
// }
// }
// }
//}
//
//@DFExperimental
//suspend fun SolidGroup.optimizeGdml(): Job = coroutineScope {
// prototypes?.let {
// VisionVisitor.visitTree(GdmlOptimizer(), this, it)
// } ?: CompletableDeferred(Unit)
//}

View File

@ -163,26 +163,27 @@ private class GdmlTransformerEnv(val settings: GdmlTransformer) {
newScale: GdmlScale? = null, newScale: GdmlScale? = null,
): T = apply { ): T = apply {
newPos?.let { newPos?.let {
val point = Point3D(it.x(settings.lUnit), it.y(settings.lUnit), it.z(settings.lUnit)) val gdmlX = it.x(settings.lUnit)
if (point != Point3D.ZERO) { if (gdmlX != 0f) x = gdmlX
position = point val gdmlY = it.y(settings.lUnit)
} if (gdmlY != 0f) y = gdmlY
val gdmlZ = it.z(settings.lUnit)
if (gdmlZ != 0f) z = gdmlZ
} }
newRotation?.let { newRotation?.let {
val point = Point3D(it.x(settings.aUnit), it.y(settings.aUnit), it.z(settings.aUnit)) val gdmlX = it.x(settings.aUnit)
if (point != Point3D.ZERO) { if (gdmlX != 0f) rotationX = gdmlX
rotation = point val gdmlY = it.y(settings.aUnit)
} if (gdmlY != 0f) rotationY = gdmlY
//this@withPosition.rotationOrder = RotationOrder.ZXY val gdmlZ = it.z(settings.aUnit)
if (gdmlZ != 0f) rotationZ = gdmlZ
} }
newScale?.let { newScale?.let {
val point = Point3D(it.x, it.y, it.z) if (it.x != 1f) scaleX = it.x
if (point != Point3D.ONE) { if (it.y != 1f) scaleY = it.y
scale = point if (it.z != 1f) scaleZ = it.z
} }
} }
//TODO convert units if needed
}
fun <T : Solid> T.withPosition(root: Gdml, physVolume: GdmlPhysVolume): T = withPosition( fun <T : Solid> T.withPosition(root: Gdml, physVolume: GdmlPhysVolume): T = withPosition(
physVolume.resolvePosition(root), physVolume.resolvePosition(root),
@ -301,7 +302,7 @@ private class GdmlTransformerEnv(val settings: GdmlTransformer) {
val first: GdmlSolid = solid.first.resolve(root) ?: error("") val first: GdmlSolid = solid.first.resolve(root) ?: error("")
val second: GdmlSolid = solid.second.resolve(root) ?: error("") val second: GdmlSolid = solid.second.resolve(root) ?: error("")
val type: CompositeType = when (solid) { val type: CompositeType = when (solid) {
is GdmlUnion -> CompositeType.UNION is GdmlUnion -> CompositeType.SUM // dumb sum for better performance
is GdmlSubtraction -> CompositeType.SUBTRACT is GdmlSubtraction -> CompositeType.SUBTRACT
is GdmlIntersection -> CompositeType.INTERSECT is GdmlIntersection -> CompositeType.INTERSECT
} }

View File

@ -1,8 +0,0 @@
package space.kscience.visionforge.gdml
public actual class Counter {
private var count: Int = 0
public actual fun get(): Int = count
public actual fun incrementAndGet(): Int = count++
}

View File

@ -4,9 +4,6 @@ import space.kscience.gdml.Gdml
import space.kscience.gdml.decodeFromFile import space.kscience.gdml.decodeFromFile
import space.kscience.visionforge.solid.SolidGroup import space.kscience.visionforge.solid.SolidGroup
import java.nio.file.Path import java.nio.file.Path
import java.util.concurrent.atomic.AtomicInteger
public actual typealias Counter = AtomicInteger
public fun SolidGroup.gdml( public fun SolidGroup.gdml(
file: Path, file: Path,

View File

@ -6,7 +6,8 @@ import space.kscience.dataforge.meta.update
import space.kscience.visionforge.* import space.kscience.visionforge.*
public enum class CompositeType { public enum class CompositeType {
UNION, SUM, // Dumb sum of meshes
UNION, //CSG union
INTERSECT, INTERSECT,
SUBTRACT SUBTRACT
} }

View File

@ -48,7 +48,7 @@ public interface Solid : Vision {
public val Y_KEY: Name = "y".asName() public val Y_KEY: Name = "y".asName()
public val Z_KEY: Name = "z".asName() public val Z_KEY: Name = "z".asName()
public val POSITION_KEY: Name = "pos".asName() public val POSITION_KEY: Name = "position".asName()
public val X_POSITION_KEY: Name = POSITION_KEY + X_KEY public val X_POSITION_KEY: Name = POSITION_KEY + X_KEY
public val Y_POSITION_KEY: Name = POSITION_KEY + Y_KEY public val Y_POSITION_KEY: Name = POSITION_KEY + Y_KEY
@ -83,6 +83,18 @@ public interface Solid : Vision {
hide() hide()
} }
node(POSITION_KEY){
hide()
}
node(ROTATION_KEY){
hide()
}
node(SCALE_KEY){
hide()
}
value(DETAIL_KEY) { value(DETAIL_KEY) {
type(ValueType.NUMBER) type(ValueType.NUMBER)
hide() hide()
@ -145,7 +157,7 @@ public var Vision.ignore: Boolean?
// get() = getProperty(SELECTED_KEY).boolean // get() = getProperty(SELECTED_KEY).boolean
// set(value) = setProperty(SELECTED_KEY, value) // set(value) = setProperty(SELECTED_KEY, value)
internal fun number(name: Name, default: Number): ReadWriteProperty<Solid, Number> = internal fun float(name: Name, default: Number): ReadWriteProperty<Solid, Number> =
object : ReadWriteProperty<Solid, Number> { object : ReadWriteProperty<Solid, Number> {
override fun getValue(thisRef: Solid, property: KProperty<*>): Number { override fun getValue(thisRef: Solid, property: KProperty<*>): Number {
return thisRef.getOwnProperty(name)?.number ?: default return thisRef.getOwnProperty(name)?.number ?: default
@ -156,33 +168,40 @@ internal fun number(name: Name, default: Number): ReadWriteProperty<Solid, Numbe
} }
} }
internal fun point(name: Name, default: Float): ReadWriteProperty<Solid, Point3D> = internal fun point(name: Name, default: Float): ReadWriteProperty<Solid, Point3D?> =
object : ReadWriteProperty<Solid, Point3D> { object : ReadWriteProperty<Solid, Point3D?> {
override fun getValue(thisRef: Solid, property: KProperty<*>): Point3D = object : Point3D { override fun getValue(thisRef: Solid, property: KProperty<*>): Point3D? {
override val x: Float get() = thisRef.getOwnProperty(name + X_KEY)?.float ?: default val item = thisRef.getOwnProperty(name) ?: return null
override val y: Float get() = thisRef.getOwnProperty(name + Y_KEY)?.float ?: default return object : Point3D {
override val z: Float get() = thisRef.getOwnProperty(name + Z_KEY)?.float ?: default override val x: Float get() = item[X_KEY]?.float ?: default
override val y: Float get() = item[Y_KEY]?.float ?: default
override val z: Float get() = item[Z_KEY]?.float ?: default
}
} }
override fun setValue(thisRef: Solid, property: KProperty<*>, value: Point3D) { override fun setValue(thisRef: Solid, property: KProperty<*>, value: Point3D?) {
if (value == null) {
thisRef.setProperty(name, null)
} else {
thisRef.setProperty(name + X_KEY, value.x) thisRef.setProperty(name + X_KEY, value.x)
thisRef.setProperty(name + Y_KEY, value.y) thisRef.setProperty(name + Y_KEY, value.y)
thisRef.setProperty(name + Z_KEY, value.z) thisRef.setProperty(name + Z_KEY, value.z)
} }
} }
}
public var Solid.position: Point3D by point(POSITION_KEY, 0f) public var Solid.position: Point3D? by point(POSITION_KEY, 0f)
public var Solid.rotation: Point3D by point(ROTATION_KEY, 0f) public var Solid.rotation: Point3D? by point(ROTATION_KEY, 0f)
public var Solid.scale: Point3D by point(SCALE_KEY, 1f) public var Solid.scale: Point3D? by point(SCALE_KEY, 1f)
public var Solid.x: Number by number(X_POSITION_KEY, 0f) public var Solid.x: Number by float(X_POSITION_KEY, 0f)
public var Solid.y: Number by number(Y_POSITION_KEY, 0f) public var Solid.y: Number by float(Y_POSITION_KEY, 0f)
public var Solid.z: Number by number(Z_POSITION_KEY, 0f) public var Solid.z: Number by float(Z_POSITION_KEY, 0f)
public var Solid.rotationX: Number by number(X_ROTATION_KEY, 0f) public var Solid.rotationX: Number by float(X_ROTATION_KEY, 0f)
public var Solid.rotationY: Number by number(Y_ROTATION_KEY, 0f) public var Solid.rotationY: Number by float(Y_ROTATION_KEY, 0f)
public var Solid.rotationZ: Number by number(Z_ROTATION_KEY, 0f) public var Solid.rotationZ: Number by float(Z_ROTATION_KEY, 0f)
public var Solid.scaleX: Number by number(X_SCALE_KEY, 1f) public var Solid.scaleX: Number by float(X_SCALE_KEY, 1f)
public var Solid.scaleY: Number by number(Y_SCALE_KEY, 1f) public var Solid.scaleY: Number by float(Y_SCALE_KEY, 1f)
public var Solid.scaleZ: Number by number(Z_SCALE_KEY, 1f) public var Solid.scaleZ: Number by float(Z_SCALE_KEY, 1f)

View File

@ -1,32 +1,39 @@
package space.kscience.visionforge.solid.transform package space.kscience.visionforge.solid.transform
import space.kscience.dataforge.meta.itemSequence
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.asName
import space.kscience.visionforge.* import space.kscience.visionforge.MutableVisionGroup
import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionGroup
import space.kscience.visionforge.meta
import space.kscience.visionforge.solid.* import space.kscience.visionforge.solid.*
private operator fun Number.plus(other: Number) = toFloat() + other.toFloat()
private operator fun Number.times(other: Number) = toFloat() * other.toFloat()
@DFExperimental @DFExperimental
internal fun mergeChild(parent: VisionGroup, child: Vision): Vision { internal fun Vision.updateFrom(other: Vision): Vision {
return child.apply { if (this is Solid && other is Solid) {
x += other.x
configure(parent.meta) y += other.y
z += other.y
//parent.properties?.let { config.update(it) } rotationX += other.rotationX
rotationY += other.rotationY
if (this is Solid && parent is Solid) { rotationZ += other.rotationZ
position += parent.position scaleX *= other.scaleX
rotation += parent.rotation scaleY *= other.scaleY
scale = Point3D( scaleZ *= other.scaleZ
scale.x * parent.scale.x, other.meta.itemSequence().forEach { (name, item) ->
scale.y * parent.scale.y, if (getProperty(name) == null) {
scale.z * parent.scale.z setProperty(name, item)
)
} }
} }
}
return this
} }
@DFExperimental @DFExperimental
internal object RemoveSingleChild : VisualTreeTransform<SolidGroup>() { internal object RemoveSingleChild : VisualTreeTransform<SolidGroup>() {
@ -39,7 +46,7 @@ internal object RemoveSingleChild : VisualTreeTransform<SolidGroup>() {
} }
if (parent is VisionGroup && parent.children.size == 1) { if (parent is VisionGroup && parent.children.size == 1) {
val child = parent.children.values.first() val child = parent.children.values.first()
val newParent = mergeChild(parent, child) val newParent = child.updateFrom(parent)
newParent.parent = null newParent.parent = null
set(childName.asName(), newParent) set(childName.asName(), newParent)
} }

View File

@ -31,7 +31,7 @@ internal object UnRef : VisualTreeTransform<SolidGroup>() {
} }
children.filter { (it.value as? SolidReferenceGroup)?.refName == name }.forEach { (key, value) -> children.filter { (it.value as? SolidReferenceGroup)?.refName == name }.forEach { (key, value) ->
val reference = value as SolidReferenceGroup val reference = value as SolidReferenceGroup
val newChild = mergeChild(reference, reference.prototype) val newChild = reference.prototype.updateFrom(reference)
newChild.parent = null newChild.parent = null
set(key.asName(), newChild) // replace proxy with merged object set(key.asName(), newChild) // replace proxy with merged object
} }

View File

@ -0,0 +1,15 @@
@file:JsModule("three/examples/jsm/utils/BufferGeometryUtils")
@file:JsNonModule
package info.laht.threekt.utils
import info.laht.threekt.core.BufferGeometry
public external object BufferGeometryUtils {
/**
* Merges a set of geometries into a single instance. All geometries must have compatible attributes. If merge does not succeed, the method returns null.
* @param geometries -- Array of BufferGeometry instances.
* @param useGroups -- Whether groups should be generated for the merged geometry or not.
*/
public fun mergeBufferGeometries(geometries: Array<BufferGeometry>, useGroups: Boolean): BufferGeometry
}

View File

@ -42,9 +42,9 @@ public class ThreeCompositeFactory(public val three: ThreePlugin) : ThreeFactory
val first = three.buildObject3D(obj.first) as? Mesh ?: error("First part of composite is not a mesh") val first = three.buildObject3D(obj.first) as? Mesh ?: error("First part of composite is not a mesh")
val second = three.buildObject3D(obj.second) as? Mesh ?: error("Second part of composite is not a mesh") val second = three.buildObject3D(obj.second) as? Mesh ?: error("Second part of composite is not a mesh")
return when (obj.compositeType) { return when (obj.compositeType) {
CompositeType.UNION -> CSG.union(first,second) CompositeType.SUM, CompositeType.UNION -> CSG.union(first, second)
CompositeType.INTERSECT -> CSG.intersect(first,second) CompositeType.INTERSECT -> CSG.intersect(first, second)
CompositeType.SUBTRACT -> CSG.subtract(first,second) CompositeType.SUBTRACT -> CSG.subtract(first, second)
}.apply { }.apply {
updatePosition(obj) updatePosition(obj)
applyProperties(obj) applyProperties(obj)