feature/root #69

Merged
altavir merged 23 commits from feature/root into dev 2021-09-11 19:14:21 +03:00
10 changed files with 200 additions and 184 deletions
Showing only changes of commit bdbe940272 - Show all commits

View File

@ -16,7 +16,7 @@ allprojects {
} }
group = "space.kscience" group = "space.kscience"
version = "0.2.0-dev-23" version = "0.2.0-dev-24"
} }
subprojects { subprojects {

View File

@ -15,7 +15,6 @@ public fun MetaProvider.doubleArray(
it?.doubleArray ?: doubleArrayOf(*default) it?.doubleArray ?: doubleArrayOf(*default)
} }
public class DObjectCache(private val cache: List<Meta>, public val refStack: List<Int> = emptyList()) { public class DObjectCache(private val cache: List<Meta>, public val refStack: List<Int> = emptyList()) {
public operator fun get(index: Int): Meta = cache[index] public operator fun get(index: Int): Meta = cache[index]
@ -25,28 +24,6 @@ public class DObjectCache(private val cache: List<Meta>, public val refStack: Li
public val empty: DObjectCache = DObjectCache(emptyList(), emptyList()) public val empty: DObjectCache = DObjectCache(emptyList(), emptyList())
} }
} }
//
//public interface ObjectRef<T : DObject> {
// public fun resolve(): T?
//}
//public class ChildObjectRef<T : DObject>(
// public val builder: (Meta, DObjectCache) -> T,
// public val refCache: DObjectCache,
// public val metaProvider: () -> Meta?
//) : ObjectRef<T> {
// override fun resolve(): T? {
// val meta = metaProvider() ?: return null
// meta["\$ref"]?.int?.let { refId ->
// if (refCache.refStack.contains(refId)) {
// println("Circular reference $refId in stack ${refCache.refStack}")
// return null
// }
// return builder(refCache[refId], refCache.stack(refId))
// }
// return builder(meta, refCache)
// }
//}
public open class DObject(public val meta: Meta, private val refCache: DObjectCache) { public open class DObject(public val meta: Meta, private val refCache: DObjectCache) {

View File

@ -4,6 +4,7 @@ import space.kscience.dataforge.meta.*
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.plus import space.kscience.dataforge.names.plus
import space.kscience.dataforge.values.doubleArray import space.kscience.dataforge.values.doubleArray
import space.kscience.visionforge.isEmpty
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.*
@ -16,7 +17,16 @@ 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 RootToSolidContext(val prototypeHolder: PrototypeHolder) private class RootToSolidContext(val prototypeHolder: PrototypeHolder, val maxLayer: Int = 3) {
val layers: MutableList<Int> = mutableListOf(0)
val layerLimits = listOf(10_000, 25_000, 50_000, 100_000, 200_000, 400_000, 600_000)
val bottomLayer: Int get() = layers.size - 1
fun addLayer() {
layers.add(0)
}
}
// converting to XYZ to TaitBryan angles according to https://en.wikipedia.org/wiki/Euler_angles#Rotation_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) {
@ -67,157 +77,164 @@ private fun Solid.useMatrix(matrix: DGeoMatrix?) {
private fun SolidGroup.addShape( private fun SolidGroup.addShape(
shape: DGeoShape, shape: DGeoShape,
context: RootToSolidContext, context: RootToSolidContext,
name: String? = shape.fName.ifEmpty { null } name: String? = shape.fName.ifEmpty { null },
): Solid? = when (shape.typename) { block: Solid.() -> Unit = {}
"TGeoCompositeShape" -> { ) {
val fNode: DGeoBoolNode? by shape.dObject(::DGeoBoolNode) when (shape.typename) {
val node = fNode ?: error("Composite shape node not resolved") "TGeoCompositeShape" -> {
val compositeType = when (node.typename) { val fNode: DGeoBoolNode? by shape.dObject(::DGeoBoolNode)
"TGeoIntersection" -> CompositeType.INTERSECT val node = fNode ?: error("Composite shape node not resolved")
"TGeoSubtraction" -> CompositeType.SUBTRACT val compositeType = when (node.typename) {
"TGeoUnion" -> CompositeType.GROUP "TGeoIntersection" -> CompositeType.INTERSECT
else -> error("Unknown bool node type ${node.typename}") "TGeoSubtraction" -> CompositeType.SUBTRACT
} "TGeoUnion" -> CompositeType.GROUP
smartComposite(compositeType, name = name) { else -> error("Unknown bool node type ${node.typename}")
addShape(node.fLeft!!, context, null).also {
if (it == null) TODO()
it.useMatrix(node.fLeftMat)
} }
addShape(node.fRight!!, context, null).also { smartComposite(compositeType, name = name) {
if (it == null) TODO() addShape(node.fLeft!!, context, null) {
it.useMatrix(node.fRightMat) this.useMatrix(node.fLeftMat)
}
}
}
"TGeoXtru" -> {
val fNvert by shape.meta.int(0)
val fX by shape.meta.doubleArray()
val fY by shape.meta.doubleArray()
val fNz by shape.meta.int(0)
val fZ by shape.meta.doubleArray()
val fX0 by shape.meta.doubleArray()
val fY0 by shape.meta.doubleArray()
val fScale by shape.meta.doubleArray()
extruded(name = name) {
(0 until fNvert).forEach { index ->
shape {
point(fX[index], fY[index])
} }
} addShape(node.fRight!!, context, null) {
this.useMatrix(node.fRightMat)
(0 until fNz).forEach { index -> }
layer( }.apply(block)
fZ[index],
fX0[index],
fY0[index],
fScale[index]
)
}
} }
} "TGeoXtru" -> {
"TGeoTube" -> { val fNvert by shape.meta.int(0)
val fRmax by shape.meta.double(0.0) val fX by shape.meta.doubleArray()
val fDz by shape.meta.double(0.0) val fY by shape.meta.doubleArray()
val fRmin by shape.meta.double(0.0) val fNz by shape.meta.int(0)
val fZ by shape.meta.doubleArray()
val fX0 by shape.meta.doubleArray()
val fY0 by shape.meta.doubleArray()
val fScale by shape.meta.doubleArray()
tube( extruded(name = name) {
radius = fRmax, (0 until fNvert).forEach { index ->
height = fDz * 2, shape {
innerRadius = fRmin, point(fX[index], fY[index])
name = name }
) }
}
"TGeoTubeSeg" -> {
val fRmax by shape.meta.double(0.0)
val fDz by shape.meta.double(0.0)
val fRmin by shape.meta.double(0.0)
val fPhi1 by shape.meta.double(0.0)
val fPhi2 by shape.meta.double(0.0)
tube( (0 until fNz).forEach { index ->
radius = fRmax, layer(
height = fDz * 2, fZ[index],
innerRadius = fRmin, fX0[index],
startAngle = degToRad(fPhi1), fY0[index],
angle = degToRad(fPhi2 - fPhi1), fScale[index]
name = name )
) }
} }.apply(block)
"TGeoPcon" -> { }
val fDphi by shape.meta.double(0.0) "TGeoTube" -> {
val fNz by shape.meta.int(2) val fRmax by shape.meta.double(0.0)
val fPhi1 by shape.meta.double(360.0) val fDz by shape.meta.double(0.0)
val fRmax by shape.meta.doubleArray() val fRmin by shape.meta.double(0.0)
val fRmin by shape.meta.doubleArray()
val fZ by shape.meta.doubleArray() tube(
if (fNz == 2) { radius = fRmax,
coneSurface( height = fDz * 2,
bottomOuterRadius = fRmax[0], innerRadius = fRmin,
bottomInnerRadius = fRmin[0], name = name,
height = fZ[1] - fZ[0], block = block
topOuterRadius = fRmax[1], )
topInnerRadius = fRmin[1], }
"TGeoTubeSeg" -> {
val fRmax by shape.meta.double(0.0)
val fDz by shape.meta.double(0.0)
val fRmin by shape.meta.double(0.0)
val fPhi1 by shape.meta.double(0.0)
val fPhi2 by shape.meta.double(0.0)
tube(
radius = fRmax,
height = fDz * 2,
innerRadius = fRmin,
startAngle = degToRad(fPhi1), startAngle = degToRad(fPhi1),
angle = degToRad(fDphi), angle = degToRad(fPhi2 - fPhi1),
name = name name = name,
) { block = block
z = (fZ[1] + fZ[0]) / 2 )
}
} else {
TODO()
} }
} "TGeoPcon" -> {
"TGeoPgon" -> { val fDphi by shape.meta.double(0.0)
val fDphi by shape.meta.double(0.0) val fNz by shape.meta.int(2)
val fNz by shape.meta.int(2) val fPhi1 by shape.meta.double(360.0)
val fPhi1 by shape.meta.double(360.0) val fRmax by shape.meta.doubleArray()
val fRmax by shape.meta.doubleArray() val fRmin by shape.meta.doubleArray()
val fRmin by shape.meta.doubleArray() val fZ by shape.meta.doubleArray()
val fZ by shape.meta.doubleArray() if (fNz == 2) {
coneSurface(
bottomOuterRadius = fRmax[0],
bottomInnerRadius = fRmin[0],
height = fZ[1] - fZ[0],
topOuterRadius = fRmax[1],
topInnerRadius = fRmin[1],
startAngle = degToRad(fPhi1),
angle = degToRad(fDphi),
name = name,
) {
z = (fZ[1] + fZ[0]) / 2
val fNedges by shape.meta.int(1) }.apply(block)
} else {
TODO()
}
}
"TGeoPgon" -> {
val fDphi by shape.meta.double(0.0)
val fNz by shape.meta.int(2)
val fPhi1 by shape.meta.double(360.0)
val fRmax by shape.meta.doubleArray()
val fRmin by shape.meta.doubleArray()
val fZ by shape.meta.doubleArray()
val startphi = degToRad(fPhi1) val fNedges by shape.meta.int(1)
val deltaphi = degToRad(fDphi)
extruded(name) { val startphi = degToRad(fPhi1)
//getting the radius of first val deltaphi = degToRad(fDphi)
require(fNz > 1) { "The polyhedron geometry requires at least two planes" }
val baseRadius = fRmax[0] extruded(name) {
shape { //getting the radius of first
(0..fNedges).forEach { require(fNz > 1) { "The polyhedron geometry requires at least two planes" }
val phi = deltaphi * fNedges * it + startphi val baseRadius = fRmax[0]
(baseRadius * cos(phi) to baseRadius * sin(phi)) shape {
(0..fNedges).forEach {
val phi = deltaphi * fNedges * it + startphi
(baseRadius * cos(phi) to baseRadius * sin(phi))
}
} }
} (0 until fNz).forEach { index ->
(0 until fNz).forEach { index -> //scaling all radii relative to first layer radius
//scaling all radii relative to first layer radius layer(fZ[index], scale = fRmax[index] / baseRadius)
layer(fZ[index], scale = fRmax[index] / baseRadius) }
}.apply(block)
}
"TGeoShapeAssembly" -> {
val fVolume by shape.dObject(::DGeoVolume)
fVolume?.let { volume ->
addRootVolume(volume, context, block = block)
} }
} }
} "TGeoBBox" -> {
"TGeoShapeAssembly" -> { box(shape.fDX * 2, shape.fDY * 2, shape.fDZ * 2, name = name, block = block)
val fVolume by shape.dObject(::DGeoVolume) }
fVolume?.let { volume -> else -> {
addRootVolume(volume, context) TODO("A shape with type ${shape.typename} not implemented")
} }
}
"TGeoBBox" -> {
box(shape.fDX * 2, shape.fDY * 2, shape.fDZ * 2, name = name)
}
else -> {
TODO("A shape with type ${shape.typename} not implemented")
} }
} }
private fun SolidGroup.addRootNode(obj: DGeoNode, context: RootToSolidContext) { private fun SolidGroup.addRootNode(obj: DGeoNode, context: RootToSolidContext) {
val volume = obj.fVolume ?: return val volume = obj.fVolume ?: return
addRootVolume(volume, context, obj.fName).apply { addRootVolume(volume, context, obj.fName) {
if (context.bottomLayer > 0) {
this.layer = context.bottomLayer
}
when (obj.typename) { when (obj.typename) {
"TGeoNodeMatrix" -> { "TGeoNodeMatrix" -> {
val fMatrix by obj.dObject(::DGeoMatrix) val fMatrix by obj.dObject(::DGeoMatrix)
useMatrix(fMatrix) this.useMatrix(fMatrix)
} }
"TGeoNodeOffset" -> { "TGeoNodeOffset" -> {
val fOffset by obj.meta.double(0.0) val fOffset by obj.meta.double(0.0)
@ -227,19 +244,29 @@ private fun SolidGroup.addRootNode(obj: DGeoNode, context: RootToSolidContext) {
} }
} }
private fun buildVolume(volume: DGeoVolume, context: RootToSolidContext): Solid { private fun buildVolume(volume: DGeoVolume, context: RootToSolidContext): Solid? {
val group = SolidGroup { val group = SolidGroup {
if(volume.fNodes.isEmpty()) { val nodesNum = volume.fNodes.size
if (nodesNum == 0) {
//TODO add smart filter //TODO add smart filter
volume.fShape?.let { shape -> volume.fShape?.let { shape ->
addShape(shape, context) addShape(shape, context)
} }
} }
val expectedLayerSize = context.layers.last() + nodesNum
//If expected number exceeds layer limit, move everything else to the bottom layer.
if (expectedLayerSize >= context.layerLimits[context.bottomLayer]) {
context.addLayer()
println("Adding new layer. Sizes after add: ${context.layers}")
}
context.layers[context.bottomLayer] += nodesNum
volume.fNodes.forEach { node -> volume.fNodes.forEach { node ->
addRootNode(node, context) addRootNode(node, context)
} }
} }
return if (group.children.size == 1 && group.meta.isEmpty()) { return if (group.isEmpty()) {
null
} else if (group.children.size == 1 && group.meta.isEmpty()) {
(group.children.values.first() as Solid).apply { parent = null } (group.children.values.first() as Solid).apply { parent = null }
} else { } else {
group group
@ -252,8 +279,15 @@ private fun SolidGroup.addRootVolume(
volume: DGeoVolume, volume: DGeoVolume,
context: RootToSolidContext, context: RootToSolidContext,
name: String? = null, name: String? = null,
cache: Boolean = true cache: Boolean = true,
): Solid { block: Solid.() -> Unit = {}
) {
//skip if maximum layer number is reached
if (context.bottomLayer > context.maxLayer){
println("Maximum layer depth reached. Skipping ${volume.fName}")
return
}
val combinedName = if (volume.fName.isEmpty()) { val combinedName = if (volume.fName.isEmpty()) {
name name
} else if (name == null) { } else if (name == null) {
@ -262,23 +296,29 @@ private fun SolidGroup.addRootVolume(
"${name}_${volume.fName}" "${name}_${volume.fName}"
} }
return if (!cache) { if (!cache) {
val group = buildVolume(volume, context) val group = buildVolume(volume, context)?.apply {
volume.fFillColor?.let {
meta[MATERIAL_COLOR_KEY] = RootColors[it]
}
block()
}
set(combinedName?.let { Name.parse(it) }, group) set(combinedName?.let { Name.parse(it) }, group)
group
} else { } else {
val templateName = volumesName + volume.name val templateName = volumesName + volume.name
val existing = getPrototype(templateName) val existing = getPrototype(templateName)
if (existing == null) { if (existing == null) {
context.prototypeHolder.prototypes { context.prototypeHolder.prototypes {
set(templateName, buildVolume(volume, context)) val group = buildVolume(volume, context)
set(templateName, group)
} }
} }
ref(templateName, name) ref(templateName, name).apply {
}.apply { volume.fFillColor?.let {
volume.fFillColor?.let { meta[MATERIAL_COLOR_KEY] = RootColors[it]
meta[MATERIAL_COLOR_KEY] = RootColors[it] }
block()
} }
} }
} }

View File

@ -65,12 +65,6 @@ application {
mainClass.set("ru.mipt.npm.muon.monitor.server.MMServerKt") mainClass.set("ru.mipt.npm.muon.monitor.server.MMServerKt")
} }
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinJsCompile>() {
kotlinOptions {
freeCompilerArgs = freeCompilerArgs + "-Xir-property-lazy-initialization"
}
}
//distributions { //distributions {
// main { // main {
// contents { // contents {

View File

@ -9,6 +9,8 @@ import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.isLeaf import space.kscience.dataforge.meta.isLeaf
import space.kscience.dataforge.values.string import space.kscience.dataforge.values.string
import space.kscience.visionforge.solid.Solids import space.kscience.visionforge.solid.Solids
import java.nio.file.Paths
import kotlin.io.path.writeText
private fun Meta.countTypes(): Sequence<String> = sequence { private fun Meta.countTypes(): Sequence<String> = sequence {
@ -37,12 +39,18 @@ fun main() {
val solid = geo.toSolid() val solid = geo.toSolid()
//Paths.get("BM@N.vf.json").writeText(Solids.encodeToString(solid)) Paths.get("BM@N.vf.json").writeText(Solids.encodeToString(solid))
//println(Solids.encodeToString(solid)) //println(Solids.encodeToString(solid))
context.makeVisionFile { context.makeVisionFile {
vision("canvas") { vision("canvas") {
solid solid
}
}
}
/* SolidGroup { /* SolidGroup {
set( set(
"Coil", "Coil",
@ -99,6 +107,3 @@ fun main() {
} }
}*//* }*//*
}*/ }*/
}
}
}

View File

@ -2,7 +2,7 @@ kotlin.code.style=official
kotlin.mpp.stability.nowarn=true kotlin.mpp.stability.nowarn=true
#kotlin.jupyter.add.scanner=false #kotlin.jupyter.add.scanner=false
kotlin.incremental.js.klib=false #kotlin.incremental.js.klib=false
org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G
org.gradle.parallel=true org.gradle.parallel=true

View File

@ -83,7 +83,7 @@ private fun RBuilder.visionTree(props: ObjectTreeProps): Unit {
} }
obj.children.entries obj.children.entries
.filter { !it.key.toString().startsWith("@") } // ignore statics and other hidden children .filter { !it.key.toString().startsWith("@") } // ignore statics and other hidden children
.sortedBy { (it.value as? VisionGroup)?.isEmpty ?: true } // ignore empty groups .sortedBy { (it.value as? VisionGroup)?.isEmpty() ?: true } // ignore empty groups
.forEach { (childToken, child) -> .forEach { (childToken, child) ->
styledDiv { styledDiv {
css { css {

View File

@ -63,7 +63,7 @@ public interface VisionGroup : Provider, Vision, VisionContainer<Vision> {
*/ */
public operator fun VisionGroup.iterator(): Iterator<Vision> = children.values.iterator() public operator fun VisionGroup.iterator(): Iterator<Vision> = children.values.iterator()
public val VisionGroup.isEmpty: Boolean get() = this.children.isEmpty() public fun VisionGroup.isEmpty(): Boolean = this.children.isEmpty()
public interface VisionContainerBuilder<in V : Vision> { public interface VisionContainerBuilder<in V : Vision> {
//TODO add documentation //TODO add documentation

View File

@ -67,8 +67,8 @@ internal fun checkOrStoreFile(htmlPath: Path, filePath: Path, resource: String):
if (!skip) { if (!skip) {
logger.debug("File $fullPath does not exist or wrong checksum. Writing file") logger.debug("File $fullPath does not exist or wrong checksum. Writing file")
Files.createDirectories(fullPath.parent) Files.createDirectories(fullPath.parent)
Files.write(fullPath, bytes, StandardOpenOption.CREATE, StandardOpenOption.WRITE) Files.write(fullPath, bytes, StandardOpenOption.CREATE,StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE)
Files.write(md5File, checksum.encodeToByteArray(), StandardOpenOption.CREATE, StandardOpenOption.WRITE) Files.write(md5File, checksum.encodeToByteArray(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE)
} }
return if (htmlPath.isAbsolute && fullPath.startsWith(htmlPath.parent)) { return if (htmlPath.isAbsolute && fullPath.startsWith(htmlPath.parent)) {

View File

@ -57,8 +57,8 @@ public inline fun VisionContainerBuilder<Solid>.box(
ySize: Number, ySize: Number,
zSize: Number, zSize: Number,
name: String? = null, name: String? = null,
action: Box.() -> Unit = {}, block: Box.() -> Unit = {},
): Box = Box(xSize.toFloat(), ySize.toFloat(), zSize.toFloat()).apply(action).also { set(name, it) } ): Box = Box(xSize.toFloat(), ySize.toFloat(), zSize.toFloat()).apply(block).also { set(name, it) }
@Serializable @Serializable
@SerialName("solid.hexagon") @SerialName("solid.hexagon")