diff --git a/build.gradle.kts b/build.gradle.kts index 5b093e09..505c349c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -36,7 +36,9 @@ apiValidation { 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) { - rootProject.the().versions.webpackDevServer.version = "4.0.0-rc.0" + +afterEvaluate { + extensions.configure { + versions.webpackDevServer.version = "4.0.0" + } } \ No newline at end of file diff --git a/cern-root-loader/build.gradle.kts b/cern-root-loader/build.gradle.kts new file mode 100644 index 00000000..fa26fab5 --- /dev/null +++ b/cern-root-loader/build.gradle.kts @@ -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")) + } + } + } +} \ No newline at end of file diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/RootModel.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/RootModel.kt new file mode 100644 index 00000000..8f53d71f --- /dev/null +++ b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/RootModel.kt @@ -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 provideOrNull(name: String, type: KType): T? +} + +public interface RootModel { + public val provider: RootValueProvider +} + +public inline fun RootValueProvider.provide(name: String): T = + provideOrNull(name, typeOf()) ?: error("A member with type ${T::class} and name $name could not be resolved") + +public inline fun RootModel.member(name: String? = null): PropertyDelegateProvider> = + PropertyDelegateProvider { _, property -> + lazy { provider.provide(name ?: property.name) } + } diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoHMatrix.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoHMatrix.kt new file mode 100644 index 00000000..f70e9a24 --- /dev/null +++ b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoHMatrix.kt @@ -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() \ No newline at end of file diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoManager.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoManager.kt new file mode 100644 index 00000000..2dcf5598 --- /dev/null +++ b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoManager.kt @@ -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() + } +} + + diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoMaterial.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoMaterial.kt new file mode 100644 index 00000000..9094d721 --- /dev/null +++ b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoMaterial.kt @@ -0,0 +1,9 @@ +package ru.mipt.npm.root + +import kotlinx.serialization.Serializable + +@Serializable +public open class TGeoMaterial: TNamed() + +@Serializable +public class TGeoMixture: TGeoMaterial() \ No newline at end of file diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoMedium.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoMedium.kt new file mode 100644 index 00000000..196c209c --- /dev/null +++ b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoMedium.kt @@ -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() \ No newline at end of file diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoNode.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoNode.kt new file mode 100644 index 00000000..2793773f --- /dev/null +++ b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoNode.kt @@ -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 +} \ No newline at end of file diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoShape.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoShape.kt new file mode 100644 index 00000000..344f5e6f --- /dev/null +++ b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoShape.kt @@ -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() \ No newline at end of file diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoVolume.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoVolume.kt new file mode 100644 index 00000000..1bd12cbf --- /dev/null +++ b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoVolume.kt @@ -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() \ No newline at end of file diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TObject.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TObject.kt new file mode 100644 index 00000000..fb17d8ac --- /dev/null +++ b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TObject.kt @@ -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){ + public companion object{ + public val empty = TObjArray(emptyList()) + } +} \ No newline at end of file diff --git a/demo/js-playground/src/main/kotlin/gravityDemo.kt b/demo/js-playground/src/main/kotlin/gravityDemo.kt index e8ea5856..eec16afe 100644 --- a/demo/js-playground/src/main/kotlin/gravityDemo.kt +++ b/demo/js-playground/src/main/kotlin/gravityDemo.kt @@ -6,6 +6,7 @@ import react.RProps import react.child import react.functionalComponent import space.kscience.dataforge.context.Context +import space.kscience.plotly.layout import space.kscience.plotly.models.Trace import space.kscience.visionforge.markup.VisionOfMarkup import space.kscience.visionforge.react.flexRow @@ -91,7 +92,10 @@ val GravityDemo = functionalComponent { props -> height = 50.vh - 50.pt } plotly { - traces(velocityTrace) + traces(velocityTrace,energyTrace) + layout { + xaxis.title = "time" + } } Markup { attrs { diff --git a/demo/js-playground/src/main/kotlin/markupComponent.kt b/demo/js-playground/src/main/kotlin/markupComponent.kt index 5a5f6df2..879ab3df 100644 --- a/demo/js-playground/src/main/kotlin/markupComponent.kt +++ b/demo/js-playground/src/main/kotlin/markupComponent.kt @@ -32,7 +32,7 @@ val Markup = functionalComponent("Markup") { props -> //TODO add new formats via plugins else -> error("Format ${vision.format} not recognized") } - vision.useProperty(VisionOfMarkup::content) { content -> + vision.useProperty(VisionOfMarkup::content) { content: String? -> element.clear() element.append { markdown(flavour) { content ?: "" } diff --git a/settings.gradle.kts b/settings.gradle.kts index d4616ea7..7303d884 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -32,6 +32,7 @@ include( ":visionforge-threejs", ":visionforge-threejs:visionforge-threejs-server", ":visionforge-gdml", + ":cern-root-loader", ":visionforge-server", ":visionforge-plotly", ":visionforge-markdown", diff --git a/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ThreeViewWithControls.kt b/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ThreeViewWithControls.kt index e69b04c9..94f02fdd 100644 --- a/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ThreeViewWithControls.kt +++ b/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ThreeViewWithControls.kt @@ -13,9 +13,7 @@ import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.NameToken import space.kscience.dataforge.names.isEmpty import space.kscience.dataforge.names.length -import space.kscience.visionforge.Vision -import space.kscience.visionforge.VisionGroup -import space.kscience.visionforge.computeProperties +import space.kscience.visionforge.* import space.kscience.visionforge.react.ThreeCanvasComponent import space.kscience.visionforge.react.flexColumn import space.kscience.visionforge.react.flexRow @@ -85,7 +83,9 @@ public val ThreeCanvasWithControls: FunctionComponent Action = { Action.PROTOTYPE } + public var volumeAction: (GdmlGroup) -> Action = { Action.PROTOTYPE } + + internal val styleCache = HashMap() + + 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() + + /** + * 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) } + } + } +} \ No newline at end of file diff --git a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlTransformer.kt b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/gdmlLoader.kt similarity index 80% rename from visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlTransformer.kt rename to visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/gdmlLoader.kt index 284d80cf..8eca342c 100644 --- a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlTransformer.kt +++ b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/gdmlLoader.kt @@ -1,7 +1,5 @@ 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.names.Name import space.kscience.dataforge.names.asName @@ -11,10 +9,8 @@ import space.kscience.gdml.* import space.kscience.visionforge.* import space.kscience.visionforge.html.VisionOutput import space.kscience.visionforge.solid.* -import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_KEY import kotlin.math.cos import kotlin.math.sin -import kotlin.random.Random private val solidsName = "solids".asName() private val volumesName = "volumes".asName() @@ -25,91 +21,7 @@ private inline operator fun Number.times(d: Double) = toDouble() * d @Suppress("NOTHING_TO_INLINE") private inline operator fun Number.times(f: Float) = toFloat() * f -public class GdmlTransformer { - - 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() - - 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() - - /** - * 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 class GdmlLoader(val settings: GdmlLoaderOptions) { //private val materialCache = HashMap() /** @@ -356,13 +268,13 @@ private class GdmlTransformerEnv(val settings: GdmlTransformer) { ): Solid? { require(name != "") { "Can't use empty solid name. Use null instead." } return when (settings.solidAction(solid)) { - GdmlTransformer.Action.ADD -> { + GdmlLoaderOptions.Action.ADD -> { addSolid(root, solid, name) } - GdmlTransformer.Action.PROTOTYPE -> { + GdmlLoaderOptions.Action.PROTOTYPE -> { proxySolid(root, this, solid, name ?: solid.name) } - GdmlTransformer.Action.REJECT -> { + GdmlLoaderOptions.Action.REJECT -> { //ignore null } @@ -388,14 +300,14 @@ private class GdmlTransformerEnv(val settings: GdmlTransformer) { } when (settings.volumeAction(volume)) { - GdmlTransformer.Action.ADD -> { + GdmlLoaderOptions.Action.ADD -> { val group: SolidGroup = volume(root, volume) this[physVolume.name] = group.withPosition(root, physVolume) } - GdmlTransformer.Action.PROTOTYPE -> { + GdmlLoaderOptions.Action.PROTOTYPE -> { proxyVolume(root, this, physVolume, volume) } - GdmlTransformer.Action.REJECT -> { + GdmlLoaderOptions.Action.REJECT -> { //ignore } } @@ -460,16 +372,16 @@ private class GdmlTransformerEnv(val settings: GdmlTransformer) { } -public fun Gdml.toVision(block: GdmlTransformer.() -> Unit = {}): SolidGroup { - val settings = GdmlTransformer().apply(block) - val context = GdmlTransformerEnv(settings) +public fun Gdml.toVision(block: GdmlLoaderOptions.() -> Unit = {}): SolidGroup { + val settings = GdmlLoaderOptions().apply(block) + val context = GdmlLoader(settings) return context.transform(this) } /** * 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) //println(Visual3DPlugin.json.stringify(VisualGroup3D.serializer(), visual)) set(key, visual) diff --git a/visionforge-gdml/src/jvmMain/kotlin/space/kscience/visionforge/gdml/gdmlJVM.kt b/visionforge-gdml/src/jvmMain/kotlin/space/kscience/visionforge/gdml/gdmlJVM.kt index b67e231e..ed854100 100644 --- a/visionforge-gdml/src/jvmMain/kotlin/space/kscience/visionforge/gdml/gdmlJVM.kt +++ b/visionforge-gdml/src/jvmMain/kotlin/space/kscience/visionforge/gdml/gdmlJVM.kt @@ -9,7 +9,7 @@ public fun SolidGroup.gdml( file: Path, key: String = "", usePreprocessor: Boolean = false, - transformer: GdmlTransformer.() -> Unit = {}, + transformer: GdmlLoaderOptions.() -> Unit = {}, ) { val gdml = Gdml.decodeFromFile(file, usePreprocessor) gdml(gdml, key, transformer)