WIP Root object model

This commit is contained in:
Alexander Nozik 2021-08-18 23:02:17 +03:00
parent a15afb3d52
commit b79265e8c2
19 changed files with 390 additions and 110 deletions

View File

@ -36,7 +36,9 @@ apiValidation {
ignoredPackages.add("info.laht.threekt") ignoredPackages.add("info.laht.threekt")
} }
//workaround for https://youtrack.jetbrains.com/issue/KT-48273
rootProject.plugins.withType(org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin::class.java) { afterEvaluate {
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension>().versions.webpackDevServer.version = "4.0.0-rc.0" extensions.configure<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension> {
versions.webpackDevServer.version = "4.0.0"
}
} }

View File

@ -0,0 +1,19 @@
plugins {
id("ru.mipt.npm.gradle.mpp")
}
kscience{
useSerialization {
json()
}
}
kotlin {
sourceSets {
val commonMain by getting {
dependencies {
api(project(":visionforge-solid"))
}
}
}
}

View File

@ -0,0 +1,25 @@
package ru.mipt.npm.root
import kotlin.properties.PropertyDelegateProvider
import kotlin.reflect.KType
import kotlin.reflect.typeOf
public interface RootValueProvider {
/**
* Provide a member cast or reinterpreted to given type.
* Returns null if member with given name/type could not be resolved.
*/
public fun <T : Any> provideOrNull(name: String, type: KType): T?
}
public interface RootModel {
public val provider: RootValueProvider
}
public inline fun <reified T : Any> RootValueProvider.provide(name: String): T =
provideOrNull(name, typeOf<T>()) ?: error("A member with type ${T::class} and name $name could not be resolved")
public inline fun <reified T : Any> RootModel.member(name: String? = null): PropertyDelegateProvider<Any?, Lazy<T>> =
PropertyDelegateProvider { _, property ->
lazy { provider.provide(name ?: property.name) }
}

View File

@ -0,0 +1,33 @@
package ru.mipt.npm.root
import kotlinx.serialization.Serializable
@Serializable
public sealed class TGeoMatrix : TNamed()
@Serializable
public class TGeoIdentity : TGeoMatrix()
@Serializable
public class TGeoHMatrix(
public val fTranslation: DoubleArray,
public val fRotationMatrix: DoubleArray,
public val fScale: DoubleArray
) : TGeoMatrix()
@Serializable
public class TGeoTranslation(
public val fTranslation: DoubleArray
) : TGeoMatrix()
@Serializable
public class TGeoRotation(
public val fRotationMatrix: DoubleArray
): TGeoMatrix()
@Serializable
public class TGeoCombiTrans(
public val fTranslation: DoubleArray,
public val fRotation: TGeoRotation? = null,
): TGeoMatrix()

View File

@ -0,0 +1,30 @@
package ru.mipt.npm.root
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
@Serializable
public class TGeoManager : TNamed() {
public val fMatrices: TObjArray = TObjArray.empty
public val fShapes: TObjArray = TObjArray.empty
public val fVolumes: TObjArray = TObjArray.empty
companion object {
public val rootJson: Json = Json {
encodeDefaults = true
ignoreUnknownKeys = true
classDiscriminator = "_typename"
}
/**
* Load Json encoded TGeoManager
*/
public fun decodeFromJson(jsonObject: JsonObject): TGeoManager = TODO()
}
}

View File

@ -0,0 +1,9 @@
package ru.mipt.npm.root
import kotlinx.serialization.Serializable
@Serializable
public open class TGeoMaterial: TNamed()
@Serializable
public class TGeoMixture: TGeoMaterial()

View File

@ -0,0 +1,10 @@
package ru.mipt.npm.root
import kotlinx.serialization.Serializable
@Serializable
public class TGeoMedium(
public val fId : Int,
public val fMaterial: TGeoMaterial,
public val fParams: DoubleArray
): TNamed()

View File

@ -0,0 +1,17 @@
package ru.mipt.npm.root
import kotlinx.serialization.Serializable
@Serializable
public class TGeoNode : TNamed() {
//val fGeoAtt: UInt
public val fVolume: TGeoVolume? = null
public val fMother: TGeoVolume? = null
public val fNumber: Int = 0
public val fNovlp: Int = 0
public val fOverlaps: IntArray = intArrayOf()
}
public class TGeoNodeMatrix : TGeoMatrix() {
public val fMatrix: TGeoMatrix? = null
}

View File

@ -0,0 +1,80 @@
package ru.mipt.npm.root
import kotlinx.serialization.Serializable
@Serializable
public abstract class TGeoShape : TNamed() {
public val fShapeBits: UInt = 0u
public val fShapeId: Int = 0
}
@Serializable
public open class TGeoBBox : TGeoShape() {
public val fDX: Double = 0.0
public val fDY: Double = 0.0
public val fDZ: Double = 0.0
public val fOrigin: DoubleArray = doubleArrayOf(0.0, 0.0, 0.0)
}
@Serializable
public sealed class TGeoBoolNode : TObject() {
public abstract val fLeft: TGeoShape
public abstract val fLeftMat: TGeoMatrix
public abstract val fRight: TGeoShape
public abstract val fRightMat: TGeoMatrix
}
@Serializable
public class TGeoUnion(
override val fLeft: TGeoShape,
override val fLeftMat: TGeoMatrix,
override val fRight: TGeoShape,
override val fRightMat: TGeoMatrix
) : TGeoBoolNode()
@Serializable
public class TGeoSubtraction(
override val fLeft: TGeoShape,
override val fLeftMat: TGeoMatrix,
override val fRight: TGeoShape,
override val fRightMat: TGeoMatrix
) : TGeoBoolNode()
@Serializable
public class TGeoIntersection(
override val fLeft: TGeoShape,
override val fLeftMat: TGeoMatrix,
override val fRight: TGeoShape,
override val fRightMat: TGeoMatrix
) : TGeoBoolNode()
@Serializable
public class TGeoCompositeShape(public val fNode: TGeoBoolNode) : TGeoBBox()
@Serializable
public class TGeoXtru(
public val fNvert: Int,
public val fNz: Int,
public val fZcurrent: Double,
public val fX: DoubleArray,
public val fY: DoubleArray,
public val fZ: DoubleArray,
public val fScale: DoubleArray,
public val fX0: DoubleArray,
public val fY0: DoubleArray
) : TGeoBBox()
@Serializable
public class TGeoTube(
public val fRmin: Double,
public val fRmax: Double,
public val fDz: Double,
) : TGeoBBox()
@Serializable
public class TGeoShapeAssembly(
public val fVolume: TGeoVolumeAssembly,
public val fBBoxOK: Boolean = true
): TGeoBBox()

View File

@ -0,0 +1,22 @@
package ru.mipt.npm.root
import kotlinx.serialization.Serializable
@Serializable
public open class TGeoVolume : TNamed(){
// "fGeoAtt" : 3084,
// "fLineColor" : 3,
// "fLineStyle" : 1,
// "fLineWidth" : 1,
// "fFillColor" : 19,
// "fFillStyle" : 1001,
public lateinit var fNodes: TObjArray
public lateinit var fShape: TGeoShape
public lateinit var fMedium: TGeoMedium
public val fNumber: Int = 1
public val fNtotal: Int = 1
public val fRefCount: Int = 1
}
@Serializable
public class TGeoVolumeAssembly : TGeoVolume()

View File

@ -0,0 +1,22 @@
package ru.mipt.npm.root
import kotlinx.serialization.Serializable
@Serializable
public abstract class TObject {
public val fUniqueID: UInt = 0u
public val fBits: UInt = 0u
}
@Serializable
public abstract class TNamed : TObject() {
public val fName: String = ""
public val fTitle: String = ""
}
@Serializable
public class TObjArray(public val arr: List<TObject>){
public companion object{
public val empty = TObjArray(emptyList())
}
}

View File

@ -6,6 +6,7 @@ import react.RProps
import react.child import react.child
import react.functionalComponent import react.functionalComponent
import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.Context
import space.kscience.plotly.layout
import space.kscience.plotly.models.Trace import space.kscience.plotly.models.Trace
import space.kscience.visionforge.markup.VisionOfMarkup import space.kscience.visionforge.markup.VisionOfMarkup
import space.kscience.visionforge.react.flexRow import space.kscience.visionforge.react.flexRow
@ -91,7 +92,10 @@ val GravityDemo = functionalComponent<DemoProps> { props ->
height = 50.vh - 50.pt height = 50.vh - 50.pt
} }
plotly { plotly {
traces(velocityTrace) traces(velocityTrace,energyTrace)
layout {
xaxis.title = "time"
}
} }
Markup { Markup {
attrs { attrs {

View File

@ -32,7 +32,7 @@ val Markup = functionalComponent<MarkupProps>("Markup") { props ->
//TODO add new formats via plugins //TODO add new formats via plugins
else -> error("Format ${vision.format} not recognized") else -> error("Format ${vision.format} not recognized")
} }
vision.useProperty(VisionOfMarkup::content) { content -> vision.useProperty(VisionOfMarkup::content) { content: String? ->
element.clear() element.clear()
element.append { element.append {
markdown(flavour) { content ?: "" } markdown(flavour) { content ?: "" }

View File

@ -32,6 +32,7 @@ include(
":visionforge-threejs", ":visionforge-threejs",
":visionforge-threejs:visionforge-threejs-server", ":visionforge-threejs:visionforge-threejs-server",
":visionforge-gdml", ":visionforge-gdml",
":cern-root-loader",
":visionforge-server", ":visionforge-server",
":visionforge-plotly", ":visionforge-plotly",
":visionforge-markdown", ":visionforge-markdown",

View File

@ -13,9 +13,7 @@ import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.NameToken import space.kscience.dataforge.names.NameToken
import space.kscience.dataforge.names.isEmpty import space.kscience.dataforge.names.isEmpty
import space.kscience.dataforge.names.length import space.kscience.dataforge.names.length
import space.kscience.visionforge.Vision import space.kscience.visionforge.*
import space.kscience.visionforge.VisionGroup
import space.kscience.visionforge.computeProperties
import space.kscience.visionforge.react.ThreeCanvasComponent import space.kscience.visionforge.react.ThreeCanvasComponent
import space.kscience.visionforge.react.flexColumn import space.kscience.visionforge.react.flexColumn
import space.kscience.visionforge.react.flexRow import space.kscience.visionforge.react.flexRow
@ -85,7 +83,9 @@ public val ThreeCanvasWithControls: FunctionComponent<ThreeCanvasWithControlsPro
useEffect { useEffect {
props.context.launch { props.context.launch {
solid = props.builderOfSolid.await() solid = props.builderOfSolid.await().also {
it?.root(props.context.visionManager)
}
} }
} }

View File

@ -1,5 +1,4 @@
plugins { plugins {
kotlin("multiplatform")
id("ru.mipt.npm.gradle.mpp") id("ru.mipt.npm.gradle.mpp")
} }

View File

@ -0,0 +1,95 @@
package space.kscience.visionforge.gdml
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.names.Name
import space.kscience.gdml.*
import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.SolidMaterial
import space.kscience.visionforge.solid.invoke
import space.kscience.visionforge.useStyle
import kotlin.random.Random
public class GdmlLoaderOptions {
public enum class Action {
ADD,
REJECT,
PROTOTYPE
}
public var lUnit: LUnit = LUnit.MM
public var aUnit: AUnit = AUnit.RADIAN
public var solidAction: (GdmlSolid) -> Action = { Action.PROTOTYPE }
public var volumeAction: (GdmlGroup) -> Action = { Action.PROTOTYPE }
internal val styleCache = HashMap<Name, Meta>()
public fun Solid.registerAndUseStyle(name: String, builder: MutableMeta.() -> Unit) {
styleCache.getOrPut(Name.parse(name)) {
Meta(builder)
}
useStyle(name)
}
public fun Solid.transparent() {
registerAndUseStyle("transparent") {
SolidMaterial.MATERIAL_OPACITY_KEY put 0.3
"edges.enabled" put true
}
}
/**
* Configure paint for given solid with given [GdmlMaterial]
*/
public var configurePaint: SolidMaterial.(material: GdmlMaterial, solid: GdmlSolid) -> Unit =
{ material, _ -> color(randomColor(material)) }
private set
public fun paint(block: SolidMaterial.(material: GdmlMaterial, solid: GdmlSolid) -> Unit) {
configurePaint = block
}
/**
* Configure given solid
*/
public var configureSolid: Solid.(parent: GdmlVolume, solid: GdmlSolid, material: GdmlMaterial) -> Unit =
{ parent, solid, material ->
val styleName = "materials.${material.name}"
if (parent.physVolumes.isNotEmpty()) transparent()
registerAndUseStyle(styleName) {
val vfMaterial = SolidMaterial().apply {
configurePaint(material, solid)
}
SolidMaterial.MATERIAL_KEY put vfMaterial.toMeta()
"Gdml.material" put material.name
}
}
private set
public fun configure(block: Solid.(parent: GdmlVolume, solid: GdmlSolid, material: GdmlMaterial) -> Unit) {
val oldConfigure = configureSolid
configureSolid = { parent: GdmlVolume, solid: GdmlSolid, material: GdmlMaterial ->
oldConfigure(parent, solid, material)
block(parent, solid, material)
}
}
public companion object {
private val random: Random = Random(222)
private val colorCache = HashMap<GdmlMaterial, Int>()
/**
* Use random color and cache it based on the material. Meaning that colors are random, but always the same for the
* same material.
*/
public fun randomColor(material: GdmlMaterial): Int {
return colorCache.getOrPut(material) { random.nextInt(16777216) }
}
}
}

View File

@ -1,7 +1,5 @@
package space.kscience.visionforge.gdml package space.kscience.visionforge.gdml
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.asName
@ -11,10 +9,8 @@ import space.kscience.gdml.*
import space.kscience.visionforge.* import space.kscience.visionforge.*
import space.kscience.visionforge.html.VisionOutput import space.kscience.visionforge.html.VisionOutput
import space.kscience.visionforge.solid.* import space.kscience.visionforge.solid.*
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_KEY
import kotlin.math.cos import kotlin.math.cos
import kotlin.math.sin import kotlin.math.sin
import kotlin.random.Random
private val solidsName = "solids".asName() private val solidsName = "solids".asName()
private val volumesName = "volumes".asName() private val volumesName = "volumes".asName()
@ -25,91 +21,7 @@ private inline operator fun Number.times(d: Double) = toDouble() * d
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
private inline operator fun Number.times(f: Float) = toFloat() * f private inline operator fun Number.times(f: Float) = toFloat() * f
public class GdmlTransformer { private class GdmlLoader(val settings: GdmlLoaderOptions) {
public enum class Action {
ADD,
REJECT,
PROTOTYPE
}
public var lUnit: LUnit = LUnit.MM
public var aUnit: AUnit = AUnit.RADIAN
public var solidAction: (GdmlSolid) -> Action = { Action.PROTOTYPE }
public var volumeAction: (GdmlGroup) -> Action = { Action.PROTOTYPE }
internal val styleCache = HashMap<Name, Meta>()
public fun Solid.registerAndUseStyle(name: String, builder: MutableMeta.() -> Unit) {
styleCache.getOrPut(Name.parse(name)) {
Meta(builder)
}
useStyle(name)
}
public fun Solid.transparent() {
registerAndUseStyle("transparent") {
SolidMaterial.MATERIAL_OPACITY_KEY put 0.3
"edges.enabled" put true
}
}
/**
* Configure paint for given solid with given [GdmlMaterial]
*/
public var configurePaint: SolidMaterial.(material: GdmlMaterial, solid: GdmlSolid) -> Unit =
{ material, _ -> color(randomColor(material)) }
private set
public fun paint(block: SolidMaterial.(material: GdmlMaterial, solid: GdmlSolid) -> Unit) {
configurePaint = block
}
/**
* Configure given solid
*/
public var configureSolid: Solid.(parent: GdmlVolume, solid: GdmlSolid, material: GdmlMaterial) -> Unit =
{ parent, solid, material ->
val styleName = "materials.${material.name}"
if (parent.physVolumes.isNotEmpty()) transparent()
registerAndUseStyle(styleName) {
val vfMaterial = SolidMaterial().apply {
configurePaint(material, solid)
}
MATERIAL_KEY put vfMaterial.toMeta()
"Gdml.material" put material.name
}
}
private set
public fun configure(block: Solid.(parent: GdmlVolume, solid: GdmlSolid, material: GdmlMaterial) -> Unit) {
val oldConfigure = configureSolid
configureSolid = { parent: GdmlVolume, solid: GdmlSolid, material: GdmlMaterial ->
oldConfigure(parent, solid, material)
block(parent, solid, material)
}
}
public companion object {
private val random: Random = Random(222)
private val colorCache = HashMap<GdmlMaterial, Int>()
/**
* Use random color and cache it based on the material. Meaning that colors are random, but always the same for the
* same material.
*/
public fun randomColor(material: GdmlMaterial): Int {
return colorCache.getOrPut(material) { random.nextInt(16777216) }
}
}
}
private class GdmlTransformerEnv(val settings: GdmlTransformer) {
//private val materialCache = HashMap<GdmlMaterial, Meta>() //private val materialCache = HashMap<GdmlMaterial, Meta>()
/** /**
@ -356,13 +268,13 @@ private class GdmlTransformerEnv(val settings: GdmlTransformer) {
): Solid? { ): Solid? {
require(name != "") { "Can't use empty solid name. Use null instead." } require(name != "") { "Can't use empty solid name. Use null instead." }
return when (settings.solidAction(solid)) { return when (settings.solidAction(solid)) {
GdmlTransformer.Action.ADD -> { GdmlLoaderOptions.Action.ADD -> {
addSolid(root, solid, name) addSolid(root, solid, name)
} }
GdmlTransformer.Action.PROTOTYPE -> { GdmlLoaderOptions.Action.PROTOTYPE -> {
proxySolid(root, this, solid, name ?: solid.name) proxySolid(root, this, solid, name ?: solid.name)
} }
GdmlTransformer.Action.REJECT -> { GdmlLoaderOptions.Action.REJECT -> {
//ignore //ignore
null null
} }
@ -388,14 +300,14 @@ private class GdmlTransformerEnv(val settings: GdmlTransformer) {
} }
when (settings.volumeAction(volume)) { when (settings.volumeAction(volume)) {
GdmlTransformer.Action.ADD -> { GdmlLoaderOptions.Action.ADD -> {
val group: SolidGroup = volume(root, volume) val group: SolidGroup = volume(root, volume)
this[physVolume.name] = group.withPosition(root, physVolume) this[physVolume.name] = group.withPosition(root, physVolume)
} }
GdmlTransformer.Action.PROTOTYPE -> { GdmlLoaderOptions.Action.PROTOTYPE -> {
proxyVolume(root, this, physVolume, volume) proxyVolume(root, this, physVolume, volume)
} }
GdmlTransformer.Action.REJECT -> { GdmlLoaderOptions.Action.REJECT -> {
//ignore //ignore
} }
} }
@ -460,16 +372,16 @@ private class GdmlTransformerEnv(val settings: GdmlTransformer) {
} }
public fun Gdml.toVision(block: GdmlTransformer.() -> Unit = {}): SolidGroup { public fun Gdml.toVision(block: GdmlLoaderOptions.() -> Unit = {}): SolidGroup {
val settings = GdmlTransformer().apply(block) val settings = GdmlLoaderOptions().apply(block)
val context = GdmlTransformerEnv(settings) val context = GdmlLoader(settings)
return context.transform(this) return context.transform(this)
} }
/** /**
* Append Gdml node to the group * Append Gdml node to the group
*/ */
public fun SolidGroup.gdml(gdml: Gdml, key: String? = null, transformer: GdmlTransformer.() -> Unit = {}) { public fun SolidGroup.gdml(gdml: Gdml, key: String? = null, transformer: GdmlLoaderOptions.() -> Unit = {}) {
val visual = gdml.toVision(transformer) val visual = gdml.toVision(transformer)
//println(Visual3DPlugin.json.stringify(VisualGroup3D.serializer(), visual)) //println(Visual3DPlugin.json.stringify(VisualGroup3D.serializer(), visual))
set(key, visual) set(key, visual)

View File

@ -9,7 +9,7 @@ public fun SolidGroup.gdml(
file: Path, file: Path,
key: String = "", key: String = "",
usePreprocessor: Boolean = false, usePreprocessor: Boolean = false,
transformer: GdmlTransformer.() -> Unit = {}, transformer: GdmlLoaderOptions.() -> Unit = {},
) { ) {
val gdml = Gdml.decodeFromFile(file, usePreprocessor) val gdml = Gdml.decodeFromFile(file, usePreprocessor)
gdml(gdml, key, transformer) gdml(gdml, key, transformer)