Merge pull request #76 from SciProgCentre/dev

0.3.0-dev-17
This commit is contained in:
SPC-code 2023-12-05 16:47:35 +03:00 committed by GitHub
commit 8e5503f0d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
478 changed files with 24605 additions and 5357 deletions

View File

@ -8,15 +8,15 @@ on:
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 40
timeout-minutes: 30
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3.5.3
- name: Set up JDK 11
uses: actions/setup-java@v2.5.0
uses: actions/setup-java@v3.12.0
with:
java-version: 11
distribution: liberica
- name: execute build
uses: gradle/gradle-build-action@v2
uses: gradle/gradle-build-action@v2.7.1
with:
arguments: build

2
.gitignore vendored
View File

@ -7,3 +7,5 @@ build/
data/
!gradle-wrapper.jar
/kotlin-js-store/yarn.lock

View File

@ -2,14 +2,27 @@
## [Unreleased]
### Added
- Context receivers flag
- MeshLine for thick lines
- Custom client-side events and thier processing in VisionServer
### Changed
- Color accessor property is now `colorProperty`. Color uses non-nullable `invoke` instead of `set`.
- API update for server and pages
- Edges moved to solids module for easier construction
- Visions **must** be rooted in order to subscribe to updates.
- Visions use flows instead of direct subscriptions.
- Radical change of inner workings of vision children and properties.
- Three package changed to `three`.
- Naming of Canvas3D options.
- Lights are added to the scene instead of 3D options.
### Deprecated
### Removed
### Fixed
- Jupyter integration for IDEA and Jupyter lab.
### Security

View File

@ -1,29 +1,50 @@
import org.jetbrains.kotlin.gradle.dsl.KotlinJsCompile
import space.kscience.gradle.useApache2Licence
import space.kscience.gradle.useSPCTeam
plugins {
id("ru.mipt.npm.gradle.project")
id("org.jetbrains.kotlinx.kover") version "0.5.0-RC"
id("space.kscience.gradle.project")
// id("org.jetbrains.kotlinx.kover") version "0.5.0"
}
val dataforgeVersion by extra("0.5.2")
val dataforgeVersion by extra("0.7.1")
val fxVersion by extra("11")
allprojects {
group = "space.kscience"
version = "0.2.0"
version = "0.3.0-dev-17"
}
subprojects {
if (name.startsWith("visionforge")) apply<MavenPublishPlugin>()
repositories {
mavenLocal()
maven("https://repo.kotlin.link")
mavenCentral()
maven("https://maven.jzy3d.org/releases")
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
}
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions {
freeCompilerArgs = freeCompilerArgs + "-Xcontext-receivers"
}
}
tasks.withType<KotlinJsCompile>{
kotlinOptions{
useEsClasses = true
}
}
}
ksciencePublish {
github("visionforge")
space()
pom("https://github.com/SciProgCentre/visionforge") {
useApache2Licence()
useSPCTeam()
}
repository("spc","https://maven.sciprog.center/kscience")
sonatype()
}

View File

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

View File

@ -0,0 +1,53 @@
package ru.mipt.npm.root
import kotlinx.serialization.Serializable
import kotlinx.serialization.builtins.ListSerializer
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonArray
import space.kscience.visionforge.solid.Float32Vector3D
@Serializable
public data class FairTrackParam(
val fX: Double,
val fY: Double,
val fZ: Double,
val fTx: Double,
val fTy: Double,
val fQp: Double,
)
public fun FairTrackParam.toVector(): Float32Vector3D = Float32Vector3D(fX,fY,fZ)
@Serializable
public data class CbmStsTrack(
val fParamFirst: FairTrackParam,
val fParamLast: FairTrackParam,
)
@Serializable
public data class BmnGlobalTrack(
val fParamFirst: FairTrackParam,
val fParamLast: FairTrackParam,
)
public class BmnEventContainer(
public val cbmTracks: List<CbmStsTrack>,
public val bmnGlobalTracks: List<BmnGlobalTrack>,
)
public object BMN {
public val json: Json = Json {
ignoreUnknownKeys = true
classDiscriminator = "_typename"
}
public fun readEventJson(string: String): BmnEventContainer {
val jsonArray = json.parseToJsonElement(string) as JsonArray
val cbmTracks: List<CbmStsTrack> =
json.decodeFromJsonElement(ListSerializer(CbmStsTrack.serializer()), jsonArray[0])
val bmnGlobalTracks: List<BmnGlobalTrack> =
json.decodeFromJsonElement(ListSerializer(BmnGlobalTrack.serializer()), jsonArray[1])
return BmnEventContainer(cbmTracks, bmnGlobalTracks)
}
}

View File

@ -5,7 +5,6 @@ import space.kscience.dataforge.meta.*
import space.kscience.dataforge.misc.Named
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName
import space.kscience.dataforge.values.doubleArray
import kotlin.properties.ReadOnlyProperty
public fun MetaProvider.doubleArray(
@ -43,7 +42,7 @@ public open class DObject(public val meta: Meta, public val refCache: DObjectCac
}
internal fun <T : DObject> tObjectArray(
builder: (Meta, DObjectCache) -> T
builder: (Meta, DObjectCache) -> T,
): ReadOnlyProperty<Any?, List<T>> = ReadOnlyProperty { _, property ->
meta.getIndexed(Name.of(property.name, "arr")).values.mapNotNull {
resolve(builder, it)
@ -52,9 +51,9 @@ public open class DObject(public val meta: Meta, public val refCache: DObjectCac
internal fun <T : DObject> dObject(
builder: (Meta, DObjectCache) -> T,
key: Name? = null
key: Name? = null,
): ReadOnlyProperty<Any?, T?> = ReadOnlyProperty { _, property ->
meta[key ?: property.name.asName()]?.let { resolve(builder, it) }
meta[key ?: property.name.asName()]?.takeIf { it.value != Null }?.let { resolve(builder, it) }
}
}
@ -63,8 +62,7 @@ public open class DNamed(meta: Meta, refCache: DObjectCache) : DObject(meta, ref
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 val fMaterial: DGeoMaterial? by dObject(::DGeoMaterial)
@ -91,27 +89,69 @@ public class DGeoNode(meta: Meta, refCache: DObjectCache) : DNamed(meta, refCach
public val fVolume: DGeoVolume? by dObject(::DGeoVolume)
}
public open class DGeoMatrix(meta: Meta, refCache: DObjectCache) : DNamed(meta, refCache)
public sealed class DGeoMatrix(meta: Meta, refCache: DObjectCache) : DNamed(meta, refCache)
public open class DGeoScale(meta: Meta, refCache: DObjectCache) : DGeoMatrix(meta, refCache) {
public class DGeoIdentity(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 x: Double get() = fScale[0]
public val y: Double get() = fScale[1]
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 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 fRightMat: DGeoMatrix? by dObject(::DGeoMatrix)
public val fRightMat: DGeoMatrix? by dObject(::dGeoMatrix)
}
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)

View File

@ -1,13 +1,23 @@
package ru.mipt.npm.root
import space.kscience.dataforge.meta.*
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.double
import space.kscience.dataforge.meta.int
import space.kscience.dataforge.meta.set
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.parseAsName
import space.kscience.dataforge.names.plus
import space.kscience.dataforge.values.doubleArray
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.isEmpty
import space.kscience.visionforge.solid.*
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY
import kotlin.math.*
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin
private val volumesName = Name.EMPTY //"volumes".asName()
@ -20,51 +30,48 @@ private fun degToRad(d: Double) = d * PI / 180.0
private data class RootToSolidContext(
val prototypeHolder: PrototypeHolder,
val currentLayer: Int = 0,
val maxLayer: Int = 5
val maxLayer: Int = 5,
val ignoreRootColors: Boolean = false,
val colorCache: MutableMap<Meta, String> = mutableMapOf(),
)
// converting to XYZ to TaitBryan angles according to https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
// apply rotation from a matrix
private fun Solid.rotate(rot: DoubleArray) {
val xAngle = atan2(-rot[5], rot[8])
val yAngle = atan2(rot[2], sqrt(1.0 - rot[2].pow(2)))
val zAngle = atan2(-rot[1], rot[0])
rotation = Point3D(xAngle, yAngle, zAngle)
val matrix = VirtualMatrix(3, 3) { i, j -> rot[i * 3 + j] }
quaternion = Quaternion.fromRotationMatrix(matrix)
}
private fun Solid.translate(trans: DoubleArray) {
val (x, y, z) = trans
position = Point3D(x, y, z)
position = Float32Vector3D(x, y, z)
}
private fun Solid.useMatrix(matrix: DGeoMatrix?) {
if (matrix == null) return
when (matrix.typename) {
"TGeoIdentity" -> {
//do nothing
private fun Solid.scale(s: DoubleArray) {
scale = Float32Vector3D(s[0], s[1], s[2])
}
"TGeoTranslation" -> {
val fTranslation by matrix.meta.doubleArray()
translate(fTranslation)
}
"TGeoRotation" -> {
val fRotationMatrix by matrix.meta.doubleArray()
rotate(fRotationMatrix)
}
"TGeoCombiTrans" -> {
val fTranslation by matrix.meta.doubleArray()
translate(fTranslation)
matrix.meta["fRotation.fRotationMatrix"]?.value?.let {
rotate(it.doubleArray)
private fun Solid.useMatrix(matrix: DGeoMatrix?): Unit {
when (matrix) {
null -> {}
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 -> {
translate(matrix.fTranslation)
matrix.fRotation?.fRotationMatrix?.let { rotate(it) }
}
"TGeoHMatrix" -> {
val fTranslation by matrix.meta.doubleArray()
val fRotationMatrix by matrix.meta.doubleArray()
val fScale by matrix.meta.doubleArray()
translate(fTranslation)
rotate(fRotationMatrix)
scale = Point3D(fScale[0], fScale[1], fScale[2])
is DGeoHMatrix -> {
translate(matrix.fTranslation)
matrix.fRotation?.fRotationMatrix?.let { rotate(it) }
scale(matrix.fScale)
}
}
}
@ -73,7 +80,7 @@ private fun SolidGroup.addShape(
shape: DGeoShape,
context: RootToSolidContext,
name: String? = shape.fName.ifEmpty { null },
block: Solid.() -> Unit = {}
block: Solid.() -> Unit = {},
) {
when (shape.typename) {
"TGeoCompositeShape" -> {
@ -87,13 +94,14 @@ private fun SolidGroup.addShape(
}
smartComposite(compositeType, name = name) {
addShape(node.fLeft!!, context, null) {
this.useMatrix(node.fLeftMat)
useMatrix(node.fLeftMat)
}
addShape(node.fRight!!, context, null) {
this.useMatrix(node.fRightMat)
useMatrix(node.fRightMat)
}
}.apply(block)
}
"TGeoXtru" -> {
val fNvert by shape.meta.int(0)
val fX by shape.meta.doubleArray()
@ -105,8 +113,8 @@ private fun SolidGroup.addShape(
val fScale by shape.meta.doubleArray()
extruded(name = name) {
(0 until fNvert).forEach { index ->
shape {
(0 until fNvert).forEach { index ->
point(fX[index], fY[index])
}
}
@ -121,6 +129,7 @@ private fun SolidGroup.addShape(
}
}.apply(block)
}
"TGeoTube" -> {
val fRmax by shape.meta.double(0.0)
val fDz by shape.meta.double(0.0)
@ -134,6 +143,7 @@ private fun SolidGroup.addShape(
block = block
)
}
"TGeoTubeSeg" -> {
val fRmax by shape.meta.double(0.0)
val fDz by shape.meta.double(0.0)
@ -151,6 +161,7 @@ private fun SolidGroup.addShape(
block = block
)
}
"TGeoPcon" -> {
val fDphi by shape.meta.double(0.0)
val fNz by shape.meta.int(2)
@ -170,14 +181,14 @@ private fun SolidGroup.addShape(
name = name,
) {
z = (fZ[1] + fZ[0]) / 2
}.apply(block)
} else {
TODO()
TODO("Polycone is not implemented")
}
}
"TGeoPgon" -> {
//TODO add a inner polygone layer
val fDphi by shape.meta.double(0.0)
val fNz by shape.meta.int(2)
val fPhi1 by shape.meta.double(360.0)
@ -190,31 +201,41 @@ private fun SolidGroup.addShape(
val startphi = degToRad(fPhi1)
val deltaphi = degToRad(fDphi)
extruded(name) {
fun Shape2DBuilder.pGon(radius: Double){
(0..<fNedges).forEach {
val phi = deltaphi / fNedges * it + startphi
point(radius * cos(phi), radius * sin(phi))
}
}
surface(name) {
//getting the radius of first
require(fNz > 1) { "The polyhedron geometry requires at least two planes" }
val baseRadius = fRmax[0]
shape {
(0..fNedges).forEach {
val phi = deltaphi * fNedges * it + startphi
(baseRadius * cos(phi) to baseRadius * sin(phi))
for (index in 0 until fNz){
layer(
fZ[index],
innerBuilder = {
pGon(fRmin[index])
},
outerBuilder = {
pGon(fRmax[index])
}
}
(0 until fNz).forEach { index ->
//scaling all radii relative to first layer radius
layer(fZ[index], scale = fRmax[index] / baseRadius)
)
}
}.apply(block)
}
"TGeoShapeAssembly" -> {
val fVolume by shape.dObject(::DGeoVolume)
fVolume?.let { volume ->
addRootVolume(volume, context, block = block)
addRootVolume(volume, context, name = volume.fName.ifEmpty { null }, block = block)
}
}
"TGeoBBox" -> {
box(shape.fDX * 2, shape.fDY * 2, shape.fDZ * 2, name = name, block = block)
}
"TGeoTrap" -> {
val fTheta by shape.meta.double(0.0)
val fPhi by shape.meta.double(0.0)
@ -232,27 +253,67 @@ private fun SolidGroup.addShape(
val fDz by shape.meta.double(0.0)
//TODO check proper node order
val node1 = Point3D(-fBl1, -fH1, -fDz)
val node2 = Point3D(fBl1, -fH1, -fDz)
val node3 = Point3D(fTl1, fH1, -fDz)
val node4 = Point3D(-fTl1, fH1, -fDz)
val node5 = Point3D(-fBl2, -fH2, fDz)
val node6 = Point3D(fBl2, -fH2, fDz)
val node7 = Point3D(fTl2, fH2, fDz)
val node8 = Point3D(-fTl2, fH2, fDz)
val node1 = Float32Vector3D(-fBl1, -fH1, -fDz)
val node2 = Float32Vector3D(fBl1, -fH1, -fDz)
val node3 = Float32Vector3D(fTl1, fH1, -fDz)
val node4 = Float32Vector3D(-fTl1, fH1, -fDz)
val node5 = Float32Vector3D(-fBl2, -fH2, fDz)
val node6 = Float32Vector3D(fBl2, -fH2, fDz)
val node7 = Float32Vector3D(fTl2, fH2, fDz)
val node8 = Float32Vector3D(-fTl2, fH2, fDz)
hexagon(node1, node2, node3, node4, node5, node6, node7, node8, name)
}
"TGeoScaledShape" -> {
val fShape by shape.dObject(::DGeoShape)
val fScale by shape.dObject(::DGeoScale)
fShape?.let { scaledShape ->
group(name?.let { Name.parse(it) }) {
scale = Point3D(fScale?.x ?: 1.0, fScale?.y ?: 1.0, fScale?.z ?: 1.0)
solidGroup(name?.let { Name.parse(it) }) {
scale = Float32Vector3D(fScale?.x ?: 1.0, fScale?.y ?: 1.0, fScale?.z ?: 1.0)
addShape(scaledShape, context)
apply(block)
}
}
}
"TGeoCone" -> {
val fDz by shape.meta.double(0.0)
val fRmin1 by shape.meta.double(0.0)
val fRmax1 by shape.meta.double(0.0)
val fRmin2 by shape.meta.double(0.0)
val fRmax2 by shape.meta.double(0.0)
coneSurface(
bottomOuterRadius = fRmax1,
bottomInnerRadius = fRmin1,
height = fDz * 2.0,
topOuterRadius = fRmax2,
topInnerRadius = fRmin2,
name = name,
)
}
"TGeoCtub" -> {
val fRmin by shape.meta.double(0.0)
val fRmax by shape.meta.double(0.0)
val fDz by shape.meta.double(0.0)
val fPhi1 by shape.meta.double(0.0)
val fPhi2 by shape.meta.double(PI2.toDouble())
val fNlow by shape.meta.doubleArray()
val fNhigh by shape.meta.doubleArray()
cutTube(
outerRadius = fRmax,
innerRadius = fRmin,
height = fDz * 2.0,
startAngle = degToRad(fPhi1),
angle = degToRad(fPhi2 - fPhi1),
topNormal = Float32Vector3D(fNhigh[0], fNhigh[1], fNhigh[2]),
bottomNormal = Float32Vector3D(fNlow[0], fNlow[1], fNlow[2]),
name = name,
)
}
else -> {
TODO("A shape with type ${shape.typename} not implemented")
}
@ -264,9 +325,10 @@ private fun SolidGroup.addRootNode(obj: DGeoNode, context: RootToSolidContext) {
addRootVolume(volume, context, obj.fName) {
when (obj.typename) {
"TGeoNodeMatrix" -> {
val fMatrix by obj.dObject(::DGeoMatrix)
val fMatrix by obj.dObject(::dGeoMatrix)
this.useMatrix(fMatrix)
}
"TGeoNodeOffset" -> {
val fOffset by obj.meta.double(0.0)
x = fOffset
@ -276,12 +338,12 @@ private fun SolidGroup.addRootNode(obj: DGeoNode, context: RootToSolidContext) {
}
private fun buildVolume(volume: DGeoVolume, context: RootToSolidContext): Solid? {
val group = SolidGroup {
val group = SolidGroup().apply {
//set current layer
layer = context.currentLayer
val nodes = volume.fNodes
if (nodes.isEmpty() || context.currentLayer >= context.maxLayer) {
if (volume.typename != "TGeoVolumeAssembly" && (nodes.isEmpty() || context.currentLayer >= context.maxLayer)) {
//TODO add smart filter
volume.fShape?.let { shape ->
addShape(shape, context)
@ -301,12 +363,22 @@ private fun buildVolume(volume: DGeoVolume, context: RootToSolidContext): Solid?
}
}
}
return if (group.isEmpty()) {
return if (group.children.isEmpty()) {
null
} else if (group.children.size == 1 && group.meta.isEmpty()) {
(group.children.values.first() as Solid).apply { parent = null }
} else if (group.items.size == 1 && group.properties.own == null) {
group.items.values.first().apply { parent = null }
} else {
group
}.apply {
volume.fMedium?.let { medium ->
color(context.colorCache.getOrPut(medium.meta) { RootColors[11 + context.colorCache.size] })
}
if (!context.ignoreRootColors) {
volume.fFillColor?.let {
properties[MATERIAL_COLOR_KEY] = RootColors[it]
}
}
}
}
@ -317,46 +389,42 @@ private fun SolidGroup.addRootVolume(
context: RootToSolidContext,
name: String? = null,
cache: Boolean = true,
block: Solid.() -> Unit = {}
block: Solid.() -> Unit = {},
) {
val combinedName = if (volume.fName.isEmpty()) {
name
} else if (name == null) {
volume.fName
val combinedName = name?.parseAsName()?.let {
// this fix is required to work around malformed root files with duplicated node names
if (get(it) != null) {
it.withIndex(volume.hashCode().toString(16))
} else {
"${name}_${volume.fName}"
it
}
}
if (!cache) {
val group = buildVolume(volume, context)?.apply {
volume.fFillColor?.let {
meta[MATERIAL_COLOR_KEY] = RootColors[it]
}
block()
}
set(combinedName?.let { Name.parse(it) }, group)
val group = buildVolume(volume, context)?.apply(block) ?: return
setChild(combinedName, group)
} else {
val templateName = volumesName + volume.name
val existing = getPrototype(templateName)
val existing = context.prototypeHolder.getPrototype(templateName)
if (existing == null) {
context.prototypeHolder.prototypes {
val group = buildVolume(volume, context)
set(templateName, group)
val group = buildVolume(volume, context) ?: return@prototypes
setChild(templateName, group)
}
}
ref(templateName, name).apply {
volume.fFillColor?.let {
meta[MATERIAL_COLOR_KEY] = RootColors[it]
}
block()
}
ref(templateName, combinedName).apply(block)
}
}
public fun DGeoManager.toSolid(): SolidGroup = SolidGroup {
val context = RootToSolidContext(this)
fNodes.forEach { node ->
public fun MutableVisionContainer<Solid>.rootGeo(
dGeoManager: DGeoManager,
name: String? = null,
maxLayer: Int = 5,
ignoreRootColors: Boolean = false,
): SolidGroup = solidGroup(name = name?.parseAsName()) {
val context = RootToSolidContext(this, maxLayer = maxLayer, ignoreRootColors = ignoreRootColors)
dGeoManager.fNodes.forEach { node ->
addRootNode(node, context)
}
}

View File

@ -1,7 +1,7 @@
package ru.mipt.npm.root
public object RootColors {
private val colorMap = Array<String>(924) { "white" }
private val colorMap = MutableList(924) { "white" }
//colorMap[110] = "white"

View File

@ -12,9 +12,10 @@ import kotlinx.serialization.modules.polymorphic
import kotlinx.serialization.modules.subclass
@Suppress("UNUSED_PARAMETER")
private fun <T> jsonRootDeserializer(
tSerializer: KSerializer<T>,
builder: (JsonElement) -> T
builder: (JsonElement) -> T,
): DeserializationStrategy<T> = object :
DeserializationStrategy<T> {
private val jsonElementSerializer = JsonElement.serializer()
@ -46,6 +47,7 @@ private object RootDecoder {
private val refCache: List<RefEntry>,
) : KSerializer<T> by tSerializer {
@OptIn(ExperimentalSerializationApi::class)
@Suppress("UNCHECKED_CAST")
override fun deserialize(decoder: Decoder): T {
val input = decoder as JsonDecoder
@ -82,7 +84,7 @@ private object RootDecoder {
return ref.getOrPutValue {
// println("Decoding $it")
val actualTypeName = it.jsonObject["_typename"]?.jsonPrimitive?.content
// val actualTypeName = it.jsonObject["_typename"]?.jsonPrimitive?.content
input.json.decodeFromJsonElement(tSerializer, it)
}
}
@ -90,9 +92,8 @@ private object RootDecoder {
private fun <T> KSerializer<T>.unref(refCache: List<RefEntry>): KSerializer<T> = RootUnrefSerializer(this, refCache)
@OptIn(ExperimentalSerializationApi::class)
fun unrefSerializersModule(
refCache: List<RefEntry>
refCache: List<RefEntry>,
): SerializersModule = SerializersModule {
contextual(TObjArray::class) {
@ -118,7 +119,7 @@ private object RootDecoder {
subclass(TGeoCompositeShape.serializer().unref(refCache))
subclass(TGeoShapeAssembly.serializer().unref(refCache))
default {
defaultDeserializer {
if (it == null) {
TGeoShape.serializer().unref(refCache)
} else {
@ -136,7 +137,7 @@ private object RootDecoder {
val unrefed = TGeoMatrix.serializer().unref(refCache)
default {
defaultDeserializer {
if (it == null) {
unrefed
} else {
@ -149,7 +150,7 @@ private object RootDecoder {
subclass(TGeoVolumeAssembly.serializer().unref(refCache))
val unrefed = TGeoVolume.serializer().unref(refCache)
default {
defaultDeserializer {
if (it == null) {
unrefed
} else {
@ -163,7 +164,7 @@ private object RootDecoder {
subclass(TGeoNodeOffset.serializer().unref(refCache))
val unrefed = TGeoNode.serializer().unref(refCache)
default {
defaultDeserializer {
if (it == null) {
unrefed
} else {
@ -197,11 +198,13 @@ private object RootDecoder {
fillCache(it)
}
}
is JsonArray -> {
element.forEach {
fillCache(it)
}
}
else -> {
//ignore primitives
}
@ -216,6 +219,7 @@ private object RootDecoder {
var value: Any? = null
@Suppress("UNCHECKED_CAST")
fun <T> getOrPutValue(builder: (JsonElement) -> T): T {
if (value == null) {
value = builder(element)

View File

@ -3,6 +3,7 @@ package ru.mipt.npm.root.serialization
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.plus
import space.kscience.visionforge.MutableVisionContainer
import space.kscience.visionforge.solid.*
import kotlin.math.PI
import kotlin.math.atan2
@ -24,12 +25,12 @@ private fun Solid.rotate(rot: DoubleArray) {
val xAngle = atan2(-rot[5], rot[8])
val yAngle = atan2(rot[2], sqrt(1.0 - rot[2].pow(2)))
val zAngle = atan2(-rot[1], rot[0])
rotation = Point3D(xAngle, yAngle, zAngle)
rotation = Float32Vector3D(xAngle, yAngle, zAngle)
}
private fun Solid.translate(trans: DoubleArray) {
val (x, y, z) = trans
position = Point3D(x, y, z)
position = Float32Vector3D(x, y, z)
}
private fun Solid.useMatrix(matrix: TGeoMatrix?) {
@ -51,7 +52,7 @@ private fun Solid.useMatrix(matrix: TGeoMatrix?) {
translate(matrix.fTranslation)
rotate(matrix.fRotationMatrix)
val (xScale, yScale, zScale) = matrix.fScale
scale = Point3D(xScale, yScale, zScale)
scale = Float32Vector3D(xScale, yScale, zScale)
}
}
}
@ -132,7 +133,7 @@ private fun buildGroup(volume: TGeoVolume): SolidGroup {
return if (volume is TGeoVolumeAssemblyRef) {
buildGroup(volume.value)
} else {
SolidGroup {
SolidGroup().apply {
volume.fShape?.let { addShape(it) }
volume.fNodes?.let {
it.arr.forEach { obj ->
@ -160,7 +161,7 @@ private fun SolidGroup.volume(volume: TGeoVolume, name: String? = null, cache: B
name = combinedName,
obj = group,
prototypeHolder = rootPrototypes,
templateName = volumesName + Name.parse(combinedName ?: "volume[${group.hashCode()}]")
prototypeName = volumesName + Name.parse(combinedName ?: "volume[${group.hashCode()}]")
)
}
@ -180,8 +181,8 @@ private fun SolidGroup.volume(volume: TGeoVolume, name: String? = null, cache: B
// }
public fun TGeoManager.toSolid(): SolidGroup = SolidGroup {
fNodes.arr.forEach {
public fun MutableVisionContainer<Solid>.rootGeo(tGeoManager: TGeoManager): SolidGroup = solidGroup {
tGeoManager.fNodes.arr.forEach {
node(it)
}
}

11
demo/build.gradle.kts Normal file
View File

@ -0,0 +1,11 @@
import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode
import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper
subprojects {
plugins.withType<KotlinPluginWrapper> {
configure<KotlinProjectExtension> {
explicitApi = ExplicitApiMode.Disabled
}
}
}

View File

@ -1,60 +1,68 @@
import ru.mipt.npm.gradle.DependencyConfiguration
import ru.mipt.npm.gradle.FXModule
plugins {
id("ru.mipt.npm.gradle.mpp")
application
id("space.kscience.gradle.mpp")
}
group = "demo"
kscience {
val fxVersion: String by rootProject.extra
useFx(FXModule.CONTROLS, version = fxVersion, configuration = DependencyConfiguration.IMPLEMENTATION)
application()
}
kotlin {
jvm {
withJava()
}
jvm()
js {
useCommonJs()
browser {
binaries.executable()
commonWebpackConfig {
cssSupport.enabled = false
cssSupport {
enabled.set(false)
}
}
}
}
sourceSets {
commonMain {
dependencies {
implementation(project(":visionforge-solid"))
implementation(project(":visionforge-gdml"))
}
implementation(projects.visionforgeSolid)
implementation(projects.visionforgeGdml)
}
jvmMain {
dependencies {
implementation(project(":visionforge-fx"))
implementation("ch.qos.logback:logback-classic:1.2.5")
}
// implementation(project(":visionforge-fx"))
implementation(spclibs.logback.classic)
}
jsMain {
dependencies {
implementation(project(":ui:ring"))
implementation(project(":visionforge-threejs"))
implementation(projects.ui.ring)
implementation(projects.visionforgeThreejs)
implementation(npm("react-file-drop", "3.0.6"))
}
}
}
kotlin {
explicitApi = null
}
application {
mainClass.set("space.kscience.visionforge.gdml.demo.GdmlFxDemoAppKt")
}
//kotlin {
//
// sourceSets {
// commonMain {
// dependencies {
// implementation(project(":visionforge-solid"))
// implementation(project(":visionforge-gdml"))
// }
// }
// jvmMain {
// dependencies {
//// implementation(project(":visionforge-fx"))
// implementation("ch.qos.logback:logback-classic:1.2.11")
// }
// }
// jsMain {
// dependencies {
// implementation(project(":ui:ring"))
// implementation(project(":visionforge-threejs"))
// implementation(npm("react-file-drop", "3.0.6"))
// }
// }
// }
//}
val convertGdmlToJson by tasks.creating(JavaExec::class) {
group = "application"
classpath = sourceSets["main"].runtimeClasspath
mainClass.set("space.kscience.dataforge.vis.spatial.gdml.demo.SaveToJsonKt")
}
//val convertGdmlToJson by tasks.creating(JavaExec::class) {
// group = "application"
// classpath = sourceSets["main"].runtimeClasspath
// mainClass.set("space.kscience.dataforge.vis.spatial.gdml.demo.SaveToJsonKt")
//}

View File

@ -1,13 +1,11 @@
package space.kscience.visionforge.gdml
import space.kscience.dataforge.meta.asValue
import space.kscience.dataforge.meta.string
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.values.asValue
import space.kscience.dataforge.values.string
import space.kscience.gdml.GdmlShowCase
import space.kscience.visionforge.Vision
import space.kscience.visionforge.computeProperties
import space.kscience.visionforge.get
import space.kscience.visionforge.setProperty
import space.kscience.visionforge.getChild
import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.SolidMaterial
import space.kscience.visionforge.solid.material
@ -20,8 +18,8 @@ class GDMLVisionTest {
@Test
fun testCubesStyles(){
val segment = cubes["composite-000.segment-0"] as Solid
println(segment.computeProperties().getValue(Vision.STYLE_KEY))
val segment = cubes.children.getChild("composite-000.segment-0") as Solid
println(segment.properties.getValue(Vision.STYLE_KEY))
// println(segment.computePropertyNode(SolidMaterial.MATERIAL_KEY))
// println(segment.computeProperty(SolidMaterial.MATERIAL_COLOR_KEY))
@ -35,7 +33,7 @@ class GDMLVisionTest {
fun testPrototypeProperty() {
val child = cubes[Name.of("composite-000","segment-0")]
assertNotNull(child)
child.setProperty(SolidMaterial.MATERIAL_COLOR_KEY, "red".asValue())
assertEquals("red", child.getPropertyValue(SolidMaterial.MATERIAL_COLOR_KEY)?.string)
child.properties.setValue(SolidMaterial.MATERIAL_COLOR_KEY, "red".asValue())
assertEquals("red", child.properties[SolidMaterial.MATERIAL_COLOR_KEY].string)
}
}

View File

@ -9,11 +9,18 @@ import react.Component
import react.Props
import react.State
external enum class DropEffects {
copy,
move,
link,
none
sealed external class DropEffects {
@JsName("copy")
object Copy : DropEffects
@JsName("move")
object Move : DropEffects
@JsName("link")
object Link : DropEffects
@JsName("none")
object None : DropEffects
}
external interface FileDropProps : Props {
@ -26,6 +33,7 @@ external interface FileDropProps: Props {
var onFrameDragEnter: ((event: DragEvent) -> Unit)?
var onFrameDragLeave: ((event: DragEvent) -> Unit)?
var onFrameDrop: ((event: DragEvent) -> Unit)?
// var onDragOver: ReactDragEventHandler<HTMLDivElement>?
// var onDragLeave: ReactDragEventHandler<HTMLDivElement>?
var onDrop: ((files: FileList?, event: dynamic) -> Unit)?//event:DragEvent<HTMLDivElement>)

View File

@ -10,13 +10,11 @@ import org.w3c.files.get
import react.Props
import react.dom.h2
import react.fc
import react.useMemo
import react.useState
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.fetch
import space.kscience.dataforge.names.Name
import space.kscience.gdml.Gdml
import space.kscience.gdml.decodeFromString
import space.kscience.visionforge.Colors
import space.kscience.visionforge.gdml.markLayers
import space.kscience.visionforge.gdml.toVision
import space.kscience.visionforge.ring.ThreeCanvasWithControls
@ -24,18 +22,19 @@ import space.kscience.visionforge.ring.tab
import space.kscience.visionforge.setAsRoot
import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.Solids
import space.kscience.visionforge.solid.ambientLight
import space.kscience.visionforge.solid.invoke
import styled.css
import styled.styledDiv
external interface GDMLAppProps : Props {
var context: Context
var solids: Solids
var vision: Solid?
var selected: Name?
}
@JsExport
val GDMLApp = fc<GDMLAppProps>("GDMLApp") { props ->
val visionManager = useMemo(props.context) { props.context.fetch(Solids).visionManager }
var deferredVision: Deferred<Solid?> by useState {
CompletableDeferred(props.vision)
}
@ -50,12 +49,15 @@ val GDMLApp = fc<GDMLAppProps>("GDMLApp") { props ->
name.endsWith(".gdml") || name.endsWith(".xml") -> {
val gdml = Gdml.decodeFromString(data)
gdml.toVision().apply {
setAsRoot(visionManager)
setAsRoot(props.solids.visionManager)
console.info("Marking layers for file $name")
markLayers()
ambientLight {
color(Colors.white)
}
}
name.endsWith(".json") -> visionManager.decodeFromString(data)
}
name.endsWith(".json") -> props.solids.visionManager.decodeFromString(data)
else -> {
window.alert("File extension is not recognized: $name")
error("File extension is not recognized: $name")
@ -76,7 +78,7 @@ val GDMLApp = fc<GDMLAppProps>("GDMLApp") { props ->
}
child(ThreeCanvasWithControls) {
attrs {
this.context = props.context
this.solids = props.solids
this.builderOfSolid = deferredVision
this.selected = props.selected
tab("Load") {

View File

@ -1,12 +1,18 @@
package space.kscience.visionforge.gdml.demo
import kotlinx.browser.document
import kotlinx.css.*
import react.dom.render
import org.w3c.dom.Document
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.request
import space.kscience.gdml.GdmlShowCase
import space.kscience.visionforge.Application
import space.kscience.visionforge.Colors
import space.kscience.visionforge.gdml.toVision
import space.kscience.visionforge.react.createRoot
import space.kscience.visionforge.react.render
import space.kscience.visionforge.solid.Solids
import space.kscience.visionforge.solid.ambientLight
import space.kscience.visionforge.solid.invoke
import space.kscience.visionforge.solid.three.ThreePlugin
import space.kscience.visionforge.startApplication
import styled.injectGlobal
@ -14,7 +20,7 @@ import styled.injectGlobal
private class GDMLDemoApp : Application {
override fun start(state: Map<String, Any>) {
override fun start(document: Document, state: Map<String, Any>) {
val context = Context("gdml-demo"){
plugin(ThreePlugin)
}
@ -39,12 +45,16 @@ private class GDMLDemoApp : Application {
val element = document.getElementById("application") ?: error("Element with id 'application' not found on page")
render(element) {
createRoot(element).render {
child(GDMLApp) {
val vision = GdmlShowCase.cubes().toVision()
val vision = GdmlShowCase.cubes().toVision().apply {
ambientLight {
color(Colors.white)
}
}
//println(context.plugins.fetch(VisionManager).encodeToString(vision))
attrs {
this.context = context
this.solids = context.request(Solids)
this.vision = vision
}
}

View File

@ -2,7 +2,6 @@ package space.kscience.visionforge.gdml.demo
import drop.FileDrop
import kotlinx.css.*
import kotlinx.css.properties.border
import org.w3c.files.FileList
import react.RBuilder
import styled.css
@ -13,7 +12,7 @@ import styled.styledDiv
fun RBuilder.fileDrop(title: String, action: (files: FileList?) -> Unit) {
styledDiv {
css {
border(style = BorderStyle.dashed, width = 1.px, color = Color.orange)
border = Border(style = BorderStyle.dashed, width = 1.px, color = Color.orange)
flexGrow = 0.0
alignContent = Align.center
}

View File

@ -1,83 +1,83 @@
package space.kscience.visionforge.gdml.demo
import javafx.geometry.Orientation
import javafx.scene.Parent
import javafx.stage.FileChooser
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.fetch
import space.kscience.gdml.GdmlShowCase
import space.kscience.visionforge.VisionManager
import space.kscience.visionforge.editor.VisionEditorFragment
import space.kscience.visionforge.editor.VisionTreeFragment
import space.kscience.visionforge.gdml.toVision
import space.kscience.visionforge.solid.FX3DPlugin
import space.kscience.visionforge.solid.FXCanvas3D
import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.SolidMaterial
import tornadofx.*
class GDMLDemoApp : App(GDMLView::class)
class GDMLView : View() {
private val context = Context {
plugin(FX3DPlugin)
}
private val fx3d = context.fetch(FX3DPlugin)
private val visionManager = context.fetch(VisionManager)
private val canvas = FXCanvas3D(fx3d)
private val treeFragment = VisionTreeFragment().apply {
this.itemProperty.bind(canvas.rootObjectProperty)
}
private val propertyEditor = VisionEditorFragment().apply {
descriptorProperty.set(SolidMaterial.descriptor)
visionProperty.bind(treeFragment.selectedProperty)
}
override val root: Parent = borderpane {
top {
buttonbar {
button("Load GDML/json") {
action {
val file = chooseFile("Select a GDML/json file", filters = fileNameFilter).firstOrNull()
if (file != null) {
runAsync {
visionManager.readFile(file) as Solid
} ui {
canvas.render(it)
}
}
}
}
}
}
center {
splitpane(Orientation.HORIZONTAL, treeFragment.root, canvas.root, propertyEditor.root) {
setDividerPositions(0.2, 0.6, 0.2)
}
}
}
init {
runAsync {
GdmlShowCase.cubes().toVision()
} ui {
canvas.render(it)
}
}
companion object {
private val fileNameFilter = arrayOf(
FileChooser.ExtensionFilter("GDML", "*.gdml", "*.xml"),
FileChooser.ExtensionFilter("JSON", "*.json"),
FileChooser.ExtensionFilter("JSON.ZIP", "*.json.zip"),
FileChooser.ExtensionFilter("JSON.GZ", "*.json.gz")
)
}
}
fun main() {
launch<GDMLDemoApp>()
}
//package space.kscience.visionforge.gdml.demo
//
//import javafx.geometry.Orientation
//import javafx.scene.Parent
//import javafx.stage.FileChooser
//import space.kscience.dataforge.context.Context
//import space.kscience.dataforge.context.fetch
//import space.kscience.gdml.GdmlShowCase
//import space.kscience.visionforge.VisionManager
//import space.kscience.visionforge.editor.VisionEditorFragment
//import space.kscience.visionforge.editor.VisionTreeFragment
//import space.kscience.visionforge.gdml.toVision
//import space.kscience.visionforge.solid.FX3DPlugin
//import space.kscience.visionforge.solid.FXCanvas3D
//import space.kscience.visionforge.solid.Solid
//import space.kscience.visionforge.solid.SolidMaterial
//import tornadofx.*
//
//class GDMLDemoApp : App(GDMLView::class)
//
//class GDMLView : View() {
// private val context = Context {
// plugin(FX3DPlugin)
// }
//
// private val fx3d = context.fetch(FX3DPlugin)
// private val visionManager = context.fetch(VisionManager)
// private val canvas = FXCanvas3D(fx3d)
//
// private val treeFragment = VisionTreeFragment().apply {
// this.itemProperty.bind(canvas.rootObjectProperty)
// }
//
// private val propertyEditor = VisionEditorFragment().apply {
// descriptorProperty.set(SolidMaterial.descriptor)
// visionProperty.bind(treeFragment.selectedProperty)
// }
//
// override val root: Parent = borderpane {
// top {
// buttonbar {
// button("Load GDML/json") {
// action {
// val file = chooseFile("Select a GDML/json file", filters = fileNameFilter).firstOrNull()
// if (file != null) {
// runAsync {
// visionManager.readFile(file) as Solid
// } ui {
// canvas.render(it)
// }
// }
// }
// }
// }
// }
// center {
// splitpane(Orientation.HORIZONTAL, treeFragment.root, canvas.root, propertyEditor.root) {
// setDividerPositions(0.2, 0.6, 0.2)
// }
// }
// }
//
// init {
// runAsync {
// GdmlShowCase.cubes().toVision()
// } ui {
// canvas.render(it)
// }
// }
//
// companion object {
// private val fileNameFilter = arrayOf(
// FileChooser.ExtensionFilter("GDML", "*.gdml", "*.xml"),
// FileChooser.ExtensionFilter("JSON", "*.json"),
// FileChooser.ExtensionFilter("JSON.ZIP", "*.json.zip"),
// FileChooser.ExtensionFilter("JSON.GZ", "*.json.gz")
// )
// }
//}
//
//fun main() {
// launch<GDMLDemoApp>()
//}

View File

@ -1,28 +1,35 @@
plugins {
id("ru.mipt.npm.gradle.js")
id("space.kscience.gradle.mpp")
}
kscience {
useCoroutines()
application()
}
kotlin {
js(IR){
explicitApi = null
js {
useCommonJs()
browser {
binaries.executable()
commonWebpackConfig {
cssSupport.enabled = false
cssSupport {
enabled.set(false)
}
}
}
}
}
kscience {
dependencies {
implementation(projects.visionforge.visionforgeGdml)
implementation(projects.visionforge.visionforgePlotly)
implementation(projects.visionforge.visionforgeMarkdown)
implementation(projects.visionforge.visionforgeThreejs)
}
jsMain {
implementation(projects.ui.ring)
}
}

View File

@ -1,15 +1,17 @@
import kotlinx.browser.document
import kotlinx.css.*
import react.child
import react.dom.render
import org.w3c.dom.Document
import ringui.SmartTabs
import ringui.Tab
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.request
import space.kscience.plotly.models.Trace
import space.kscience.plotly.scatter
import space.kscience.visionforge.Application
import space.kscience.visionforge.VisionClient
import space.kscience.visionforge.Colors
import space.kscience.visionforge.JsVisionClient
import space.kscience.visionforge.plotly.PlotlyPlugin
import space.kscience.visionforge.react.createRoot
import space.kscience.visionforge.react.render
import space.kscience.visionforge.ring.ThreeCanvasWithControls
import space.kscience.visionforge.ring.ThreeWithControlsPlugin
import space.kscience.visionforge.ring.solid
@ -28,21 +30,21 @@ fun Trace.appendXYLatest(x: Number, y: Number, history: Int = 400, xErr: Number?
private class JsPlaygroundApp : Application {
override fun start(state: Map<String, Any>) {
override fun start(document: Document, state: Map<String, Any>) {
val playgroundContext = Context {
plugin(ThreeWithControlsPlugin)
plugin(VisionClient)
plugin(JsVisionClient)
plugin(PlotlyPlugin)
}
val element = document.getElementById("playground") ?: error("Element with id 'playground' not found on page")
render(element) {
createRoot(element).render {
styledDiv {
css {
padding(0.pt)
margin(0.pt)
padding = Padding(0.pt)
margin = Margin(0.pt)
height = 100.vh
width = 100.vw
}
@ -50,7 +52,7 @@ private class JsPlaygroundApp : Application {
Tab("gravity") {
GravityDemo {
attrs {
this.context = playgroundContext
this.solids = playgroundContext.request(Solids)
}
}
}
@ -71,8 +73,11 @@ private class JsPlaygroundApp : Application {
child(ThreeCanvasWithControls) {
val random = Random(112233)
attrs {
context = playgroundContext
solids = playgroundContext.request(Solids)
solid {
ambientLight {
color(Colors.white)
}
repeat(100) {
sphere(5, name = "sphere[$it]") {
x = random.nextDouble(-300.0, 300.0)

View File

@ -4,9 +4,9 @@ import kotlinx.coroutines.launch
import kotlinx.css.*
import react.Props
import react.fc
import space.kscience.dataforge.context.Context
import space.kscience.plotly.layout
import space.kscience.plotly.models.Trace
import space.kscience.visionforge.Colors
import space.kscience.visionforge.markup.VisionOfMarkup
import space.kscience.visionforge.react.flexRow
import space.kscience.visionforge.ring.ThreeCanvasWithControls
@ -17,7 +17,7 @@ import styled.styledDiv
import kotlin.math.sqrt
external interface DemoProps : Props {
var context: Context
var solids: Solids
}
val GravityDemo = fc<DemoProps> { props ->
@ -39,14 +39,19 @@ val GravityDemo = fc<DemoProps> { props ->
}
child(ThreeCanvasWithControls) {
attrs {
context = props.context
solids = props.solids
solid {
pointLight(200, 200, 200, name = "light"){
color(Colors.white)
}
ambientLight()
sphere(5.0, "ball") {
detail = 16
color("red")
val h = 100.0
y = h
context.launch {
solids.context.launch {
val g = 10.0
val dt = 0.1
var time = 0.0

View File

@ -1,5 +1,4 @@
import kotlinx.css.*
import kotlinx.css.properties.border
import kotlinx.dom.clear
import kotlinx.html.dom.append
import org.intellij.markdown.flavours.commonmark.CommonMarkFlavourDescriptor
@ -45,10 +44,10 @@ val Markup = fc<MarkupProps>("Markup") { props ->
css {
width = 100.pct
height = 100.pct
border(2.pt, BorderStyle.solid, Color.blue)
padding(left = 8.pt)
border= Border(2.pt, BorderStyle.solid, Color.blue)
padding = Padding(left = 8.pt)
backgroundColor = Color.white
flex(1.0)
flex = Flex(1.0)
zIndex = 10000
}
ref = elementRef

View File

@ -1,5 +1,4 @@
import kotlinx.css.*
import kotlinx.css.properties.border
import org.w3c.dom.Element
import org.w3c.dom.HTMLElement
import react.*
@ -20,9 +19,9 @@ val Plotly = fc<PlotlyProps>("Plotly") { props ->
useEffect(props.plot, elementRef) {
val element = elementRef.current as? HTMLElement ?: error("Plotly element not found")
props.plot?.let {
element.plot(it, PlotlyConfig {
element.plot(PlotlyConfig {
responsive = true
})
}, it)
}
}
@ -30,8 +29,8 @@ val Plotly = fc<PlotlyProps>("Plotly") { props ->
css {
width = 100.pct
height = 100.pct
border(2.pt, BorderStyle.solid, Color.blue)
flex(1.0)
border = Border(2.pt, BorderStyle.solid, Color.blue)
flex = Flex(1.0)
}
ref = elementRef
}

View File

@ -1,63 +1,46 @@
plugins {
id("ru.mipt.npm.gradle.mpp")
id("space.kscience.gradle.mpp")
application
}
group = "ru.mipt.npm"
val ktorVersion: String = npmlibs.versions.ktor.get()
val ktorVersion: String = spclibs.versions.ktor.get()
kscience {
useCoroutines()
useSerialization()
application()
}
kotlin {
jvm {
withJava()
}
js {
useCommonJs()
browser {
useKtor()
fullStack(
"muon-monitor.js",
jvmConfig = { withJava() },
jsConfig = { useCommonJs() }
) {
commonWebpackConfig {
cssSupport.enabled = false
cssSupport {
enabled.set(false)
}
}
}
afterEvaluate {
val jsBrowserDistribution by tasks.getting
tasks.getByName<ProcessResources>("jvmProcessResources") {
dependsOn(jsBrowserDistribution)
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
from(jsBrowserDistribution)
}
}
sourceSets {
commonMain {
dependencies {
implementation(project(":visionforge-solid"))
}
implementation(projects.visionforgeSolid)
}
jvmMain {
dependencies {
implementation("org.apache.commons:commons-math3:3.6.1")
implementation(npmlibs.ktor.server.cio)
implementation(npmlibs.ktor.serialization)
}
implementation("io.ktor:ktor-server-cio:${ktorVersion}")
implementation("io.ktor:ktor-server-content-negotiation:${ktorVersion}")
implementation("io.ktor:ktor-serialization-kotlinx-json:${ktorVersion}")
implementation("ch.qos.logback:logback-classic:1.2.11")
}
jsMain {
dependencies {
implementation(project(":ui:ring"))
implementation(project(":visionforge-threejs"))
implementation(projects.ui.ring)
implementation(projects.visionforgeThreejs)
//implementation(devNpm("webpack-bundle-analyzer", "4.4.0"))
}
}
}
}
kotlin.explicitApi = null
application {
mainClass.set("ru.mipt.npm.muon.monitor.server.MMServerKt")

View File

@ -1,9 +1,9 @@
package ru.mipt.npm.muon.monitor
import kotlinx.serialization.Serializable
import space.kscience.visionforge.solid.Point3D
import space.kscience.visionforge.solid.Float32Vector3D
typealias Track = List<Point3D>
typealias Track = List<Float32Vector3D>
/**
*

View File

@ -3,20 +3,21 @@ package ru.mipt.npm.muon.monitor
import ru.mipt.npm.muon.monitor.Monitor.CENTRAL_LAYER_Z
import ru.mipt.npm.muon.monitor.Monitor.LOWER_LAYER_Z
import ru.mipt.npm.muon.monitor.Monitor.UPPER_LAYER_Z
import space.kscience.dataforge.names.asName
import space.kscience.visionforge.MutableVisionContainer
import space.kscience.visionforge.VisionManager
import space.kscience.visionforge.removeAll
import space.kscience.visionforge.setAsRoot
import space.kscience.visionforge.setProperty
import space.kscience.visionforge.solid.*
import kotlin.collections.set
import kotlin.math.PI
class Model(val manager: VisionManager) {
private val map = HashMap<String, SolidGroup>()
private val events = HashSet<Event>()
private fun SolidGroup.pixel(pixel: SC1) {
val group = group(pixel.name) {
position = Point3D(pixel.center.x, pixel.center.y, pixel.center.z)
private fun MutableVisionContainer<Solid>.pixel(pixel: SC1) {
val group = solidGroup(pixel.name) {
position = Float32Vector3D(pixel.center.x, pixel.center.y, pixel.center.z)
box(pixel.xSize, pixel.ySize, pixel.zSize)
label(pixel.name) {
z = -Monitor.PIXEL_Z_SIZE / 2 - 5
@ -27,52 +28,52 @@ class Model(val manager: VisionManager) {
}
private fun SolidGroup.detector(detector: SC16) {
group(detector.name) {
solidGroup(detector.name) {
detector.pixels.forEach {
pixel(it)
}
}
}
var tracks: SolidGroup
val tracks: SolidGroup = SolidGroup()
val root: SolidGroup = SolidGroup().apply {
setAsRoot(this@Model.manager)
material {
wireframe
color("darkgreen")
}
rotationX = PI / 2
group("bottom") {
solidGroup("bottom") {
Monitor.detectors.filter { it.center.z == LOWER_LAYER_Z }.forEach {
detector(it)
}
}
group("middle") {
solidGroup("middle") {
Monitor.detectors.filter { it.center.z == CENTRAL_LAYER_Z }.forEach {
detector(it)
}
}
group("top") {
solidGroup("top") {
Monitor.detectors.filter { it.center.z == UPPER_LAYER_Z }.forEach {
detector(it)
}
}
tracks = group("tracks")
setChild("tracks".asName(), tracks)
}
private fun highlight(pixel: String) {
println("highlight $pixel")
map[pixel]?.color?.invoke("blue")
map[pixel]?.color("blue")
}
fun reset() {
map.values.forEach {
it.setProperty(SolidMaterial.MATERIAL_COLOR_KEY, null)
it.properties[SolidMaterial.MATERIAL_COLOR_KEY] = null
}
tracks.removeAll()
tracks.children.clear()
}
fun displayEvent(event: Event) {
@ -83,7 +84,6 @@ class Model(val manager: VisionManager) {
}
event.track?.let {
tracks.polyline(*it.toTypedArray(), name = "track[${event.id}]") {
thickness = 4
color("red")
}
}

View File

@ -2,21 +2,21 @@ package ru.mipt.npm.muon.monitor
import ru.mipt.npm.muon.monitor.Monitor.PIXEL_XY_SIZE
import ru.mipt.npm.muon.monitor.Monitor.PIXEL_Z_SIZE
import space.kscience.visionforge.solid.Point3D
import space.kscience.visionforge.solid.plus
import space.kscience.visionforge.solid.Float32Euclidean3DSpace
import space.kscience.visionforge.solid.Float32Vector3D
/**
* A single pixel
*/
class SC1(
val name: String,
val center: Point3D,
val xSize: Float = PIXEL_XY_SIZE, val ySize: Float = PIXEL_XY_SIZE, val zSize: Float = PIXEL_Z_SIZE
val center: Float32Vector3D,
val xSize: Float = PIXEL_XY_SIZE, val ySize: Float = PIXEL_XY_SIZE, val zSize: Float = PIXEL_Z_SIZE,
)
class SC16(
val name: String,
val center: Point3D
val center: Float32Vector3D,
) {
/**
@ -28,77 +28,90 @@ class SC16(
val y: Double
when (index) {
7 -> {
x = 1.5 * Monitor.PIXEL_XY_SPACING;
y = 1.5 * Monitor.PIXEL_XY_SPACING;
x = 1.5 * Monitor.PIXEL_XY_SPACING
y = 1.5 * Monitor.PIXEL_XY_SPACING
}
4 -> {
x = 0.5 * Monitor.PIXEL_XY_SPACING;
y = 1.5 * Monitor.PIXEL_XY_SPACING;
x = 0.5 * Monitor.PIXEL_XY_SPACING
y = 1.5 * Monitor.PIXEL_XY_SPACING
}
6 -> {
x = 1.5 * Monitor.PIXEL_XY_SPACING;
y = 0.5 * Monitor.PIXEL_XY_SPACING;
x = 1.5 * Monitor.PIXEL_XY_SPACING
y = 0.5 * Monitor.PIXEL_XY_SPACING
}
5 -> {
x = 0.5 * Monitor.PIXEL_XY_SPACING;
y = 0.5 * Monitor.PIXEL_XY_SPACING;
x = 0.5 * Monitor.PIXEL_XY_SPACING
y = 0.5 * Monitor.PIXEL_XY_SPACING
}
3 -> {
x = -1.5 * Monitor.PIXEL_XY_SPACING;
y = 1.5 * Monitor.PIXEL_XY_SPACING;
x = -1.5 * Monitor.PIXEL_XY_SPACING
y = 1.5 * Monitor.PIXEL_XY_SPACING
}
0 -> {
x = -0.5 * Monitor.PIXEL_XY_SPACING;
y = 1.5 * Monitor.PIXEL_XY_SPACING;
x = -0.5 * Monitor.PIXEL_XY_SPACING
y = 1.5 * Monitor.PIXEL_XY_SPACING
}
2 -> {
x = -1.5 * Monitor.PIXEL_XY_SPACING;
y = 0.5 * Monitor.PIXEL_XY_SPACING;
x = -1.5 * Monitor.PIXEL_XY_SPACING
y = 0.5 * Monitor.PIXEL_XY_SPACING
}
1 -> {
x = -0.5 * Monitor.PIXEL_XY_SPACING;
y = 0.5 * Monitor.PIXEL_XY_SPACING;
x = -0.5 * Monitor.PIXEL_XY_SPACING
y = 0.5 * Monitor.PIXEL_XY_SPACING
}
11 -> {
x = -1.5 * Monitor.PIXEL_XY_SPACING;
y = -1.5 * Monitor.PIXEL_XY_SPACING;
x = -1.5 * Monitor.PIXEL_XY_SPACING
y = -1.5 * Monitor.PIXEL_XY_SPACING
}
8 -> {
x = -0.5 * Monitor.PIXEL_XY_SPACING;
y = -1.5 * Monitor.PIXEL_XY_SPACING;
x = -0.5 * Monitor.PIXEL_XY_SPACING
y = -1.5 * Monitor.PIXEL_XY_SPACING
}
10 -> {
x = -1.5 * Monitor.PIXEL_XY_SPACING;
y = -0.5 * Monitor.PIXEL_XY_SPACING;
x = -1.5 * Monitor.PIXEL_XY_SPACING
y = -0.5 * Monitor.PIXEL_XY_SPACING
}
9 -> {
x = -0.5 * Monitor.PIXEL_XY_SPACING;
y = -0.5 * Monitor.PIXEL_XY_SPACING;
x = -0.5 * Monitor.PIXEL_XY_SPACING
y = -0.5 * Monitor.PIXEL_XY_SPACING
}
15 -> {
x = 1.5 * Monitor.PIXEL_XY_SPACING;
y = -1.5 * Monitor.PIXEL_XY_SPACING;
x = 1.5 * Monitor.PIXEL_XY_SPACING
y = -1.5 * Monitor.PIXEL_XY_SPACING
}
12 -> {
x = 0.5 * Monitor.PIXEL_XY_SPACING;
y = -1.5 * Monitor.PIXEL_XY_SPACING;
x = 0.5 * Monitor.PIXEL_XY_SPACING
y = -1.5 * Monitor.PIXEL_XY_SPACING
}
14 -> {
x = 1.5 * Monitor.PIXEL_XY_SPACING;
y = -0.5 * Monitor.PIXEL_XY_SPACING;
x = 1.5 * Monitor.PIXEL_XY_SPACING
y = -0.5 * Monitor.PIXEL_XY_SPACING
}
13 -> {
x = 0.5 * Monitor.PIXEL_XY_SPACING;
y = -0.5 * Monitor.PIXEL_XY_SPACING;
x = 0.5 * Monitor.PIXEL_XY_SPACING
y = -0.5 * Monitor.PIXEL_XY_SPACING
}
else -> throw Error();
else -> throw Error()
}
val offset = Point3D(-y, x, 0)//rotateDetector(Point3D(x, y, 0.0));
val offset = Float32Vector3D(-y, x, 0)//rotateDetector(Point3D(x, y, 0.0));
val pixelName = "${name}_${index}"
SC1(pixelName, offset + center)
SC1(pixelName, with(Float32Euclidean3DSpace) { offset + center })
}
}
}
@ -137,11 +150,11 @@ object Monitor {
.mapNotNull { line ->
if (line.startsWith(" ")) {
val split = line.trim().split("\\s+".toRegex())
val detectorName = split[1];
val detectorName = split[1]
val x = split[4].toDouble() - 500
val y = split[5].toDouble() - 500
val z = 180 - split[6].toDouble()
SC16(detectorName, Point3D(x, y, z))
SC16(detectorName, Float32Vector3D(x, y, z))
} else {
null
}

View File

@ -16,15 +16,18 @@ import react.dom.p
import react.fc
import react.useMemo
import react.useState
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.meta.invoke
import space.kscience.dataforge.names.Name
import space.kscience.visionforge.Colors
import space.kscience.visionforge.react.flexColumn
import space.kscience.visionforge.react.flexRow
import space.kscience.visionforge.ring.ThreeCanvasWithControls
import space.kscience.visionforge.ring.tab
import space.kscience.visionforge.solid.specifications.Camera
import space.kscience.visionforge.solid.Solids
import space.kscience.visionforge.solid.ambientLight
import space.kscience.visionforge.solid.edges
import space.kscience.visionforge.solid.invoke
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
import space.kscience.visionforge.solid.three.edges
import styled.css
import styled.styledDiv
import styled.styledSpan
@ -32,7 +35,7 @@ import kotlin.math.PI
external interface MMAppProps : Props {
var model: Model
var context: Context
var solids: Solids
var selected: Name?
}
@ -42,17 +45,21 @@ val MMApp = fc<MMAppProps>("Muon monitor") { props ->
val mmOptions = useMemo {
Canvas3DOptions {
camera = Camera {
camera {
distance = 2100.0
latitude = PI / 6
azimuth = PI + PI / 6
}
}
}
val root = useMemo(props.model) {
props.model.root.apply {
edges()
ambientLight{
color(Colors.white)
}
}
}
@ -64,7 +71,7 @@ val MMApp = fc<MMAppProps>("Muon monitor") { props ->
}
child(ThreeCanvasWithControls) {
attrs {
this.context = props.context
this.solids = props.solids
this.builderOfSolid = CompletableDeferred(root)
this.selected = props.selected
this.options = mmOptions
@ -75,7 +82,7 @@ val MMApp = fc<MMAppProps>("Muon monitor") { props ->
+"Next"
attrs {
onClickFunction = {
context.launch {
solids.context.launch {
val event = window.fetch(
"http://localhost:8080/event",
RequestInit("GET")

View File

@ -1,31 +1,34 @@
package ru.mipt.npm.muon.monitor
import kotlinx.browser.document
import react.dom.render
import org.w3c.dom.Document
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.fetch
import space.kscience.dataforge.context.request
import space.kscience.visionforge.Application
import space.kscience.visionforge.VisionManager
import space.kscience.visionforge.react.createRoot
import space.kscience.visionforge.react.render
import space.kscience.visionforge.solid.Solids
import space.kscience.visionforge.solid.three.ThreePlugin
import space.kscience.visionforge.startApplication
private class MMDemoApp : Application {
override fun start(state: Map<String, Any>) {
override fun start(document: Document, state: Map<String, Any>) {
val context = Context("MM-demo") {
plugin(ThreePlugin)
}
val visionManager = context.fetch(VisionManager)
val visionManager = context.request(VisionManager)
val model = Model(visionManager)
val element = document.getElementById("app") ?: error("Element with id 'app' not found on page")
render(element) {
createRoot(element).render {
child(MMApp) {
attrs {
this.model = model
this.context = context
this.solids = context.request(Solids)
}
}
}

View File

@ -5,7 +5,6 @@
<!-- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">-->
<title>Three js demo for particle physics</title>
<script type="text/javascript" src="muon-monitor.js"></script>
<link rel="stylesheet" href="css/custom-bootstrap.css">
</head>
<body class="application">
<div class="container-fluid max-vh-100" id = "app"> </div>

View File

@ -1,31 +1,28 @@
package ru.mipt.npm.muon.monitor.server
import io.ktor.application.Application
import io.ktor.application.call
import io.ktor.application.install
import io.ktor.application.log
import io.ktor.features.CallLogging
import io.ktor.features.ContentNegotiation
import io.ktor.features.DefaultHeaders
import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode
import io.ktor.http.content.resources
import io.ktor.http.content.static
import io.ktor.response.respond
import io.ktor.response.respondText
import io.ktor.routing.Routing
import io.ktor.routing.get
import io.ktor.serialization.json
import io.ktor.serialization.kotlinx.json.json
import io.ktor.server.application.Application
import io.ktor.server.application.call
import io.ktor.server.application.install
import io.ktor.server.application.log
import io.ktor.server.cio.CIO
import io.ktor.server.engine.embeddedServer
import io.ktor.server.http.content.staticResources
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
import io.ktor.server.response.respond
import io.ktor.server.response.respondText
import io.ktor.server.routing.Routing
import io.ktor.server.routing.get
import org.apache.commons.math3.random.JDKRandomGenerator
import ru.mipt.npm.muon.monitor.Model
import ru.mipt.npm.muon.monitor.sim.Cos2TrackGenerator
import ru.mipt.npm.muon.monitor.sim.simulateOne
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.Global
import space.kscience.dataforge.context.fetch
import space.kscience.dataforge.context.request
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.visionforge.solid.Solids
import java.awt.Desktop
@ -38,10 +35,8 @@ private val generator = Cos2TrackGenerator(JDKRandomGenerator(223))
fun Application.module(context: Context = Global) {
val currentDir = File(".").absoluteFile
environment.log.info("Current directory: $currentDir")
val solidManager = context.fetch(Solids)
val solidManager = context.request(Solids)
install(DefaultHeaders)
install(CallLogging)
install(ContentNegotiation) {
json()
}
@ -57,9 +52,7 @@ fun Application.module(context: Context = Global) {
status = HttpStatusCode.OK
)
}
static("/") {
resources()
}
staticResources("/", null)
}
try {
Desktop.getDesktop().browse(URI("http://localhost:8080/index.html"))

View File

@ -5,7 +5,7 @@ import org.apache.commons.math3.geometry.euclidean.threed.Plane
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D
import ru.mipt.npm.muon.monitor.Monitor.CENTRAL_LAYER_Z
import ru.mipt.npm.muon.monitor.Monitor.GEOMETRY_TOLERANCE
import space.kscience.visionforge.solid.Point3D
import space.kscience.visionforge.solid.Float32Vector3D
/**
* Created by darksnake on 11-May-16.
@ -50,12 +50,12 @@ fun makeTrack(x: Double, y: Double, theta: Double, phi: Double): Line {
)
}
fun Vector3D.toPoint() = Point3D(x, y, z)
fun Vector3D.toKMathVector() = Float32Vector3D(x, y, z)
fun Line.toPoints(): List<Point3D> {
fun Line.toKMathVectors(): List<Float32Vector3D> {
val basePoint = basePlane.intersection(this)
val bottom = basePoint.subtract(2000.0, direction)
val top = basePoint.add(2000.0, direction)
return listOf(bottom.toPoint(), top.toPoint())
return listOf(bottom.toKMathVector(), top.toKMathVector())
}

View File

@ -43,7 +43,7 @@ fun readEffs(): Map<String, Double> {
fun buildEventByTrack(index: Int, track: Line, hitResolver: (Line) -> Collection<SC1> = defaultHitResolver): Event {
return Event(index, track.toPoints(), hitResolver(track).map { it.name })
return Event(index, track.toKMathVectors(), hitResolver(track).map { it.name })
}
val defaultHitResolver: (Line) -> Collection<SC1> = { track: Line ->

View File

@ -2,6 +2,7 @@ plugins {
kotlin("multiplatform")
kotlin("jupyter.api")
id("com.github.johnrengelman.shadow") version "7.1.2"
// application
}
repositories {
@ -16,23 +17,25 @@ kotlin {
useCommonJs()
browser {
webpackTask {
this.outputFileName = "js/visionforge-playground.js"
mainOutputFileName.set("js/visionforge-playground.js")
}
commonWebpackConfig {
sourceMaps = true
cssSupport.enabled = false
cssSupport{
enabled.set(false)
}
}
}
binaries.executable()
}
jvm {
withJava()
// withJava()
compilations.all {
kotlinOptions {
jvmTarget = "11"
freeCompilerArgs =
freeCompilerArgs + "-Xjvm-default=all" + "-Xopt-in=kotlin.RequiresOptIn" + "-Xlambdas=indy"
freeCompilerArgs + "-Xjvm-default=all" + "-Xopt-in=kotlin.RequiresOptIn" + "-Xlambdas=indy" + "-Xcontext-receivers"
}
}
testRuns["test"].executionTask.configure {
@ -44,12 +47,11 @@ kotlin {
val commonMain by getting {
dependencies {
implementation(projects.visionforgeSolid)
implementation(projects.visionforgeGdml)
implementation(projects.visionforgePlotly)
implementation(projects.visionforgeMarkdown)
implementation(projects.visionforgeTables)
implementation(projects.cernRootLoader)
implementation(projects.jupyter)
api(projects.visionforgeJupyter.visionforgeJupyterCommon)
}
}
@ -63,8 +65,10 @@ kotlin {
val jvmMain by getting {
dependencies {
implementation("io.ktor:ktor-server-cio:${spclibs.versions.ktor.get()}")
implementation(projects.visionforgeGdml)
implementation(projects.visionforgeServer)
implementation("ch.qos.logback:logback-classic:1.2.3")
implementation(spclibs.logback.classic)
implementation("com.github.Ricky12Awesome:json-schema-serialization:0.6.6")
}
}
@ -88,3 +92,7 @@ val processJupyterApiResources by tasks.getting(org.jetbrains.kotlinx.jupyter.ap
}
tasks.findByName("shadowJar")?.dependsOn(processJupyterApiResources)
//application{
// mainClass.set("space.kscience.visionforge.examples.ShapesKt")
//}

View File

@ -0,0 +1,98 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"@file:Repository(\"*mavenLocal\")\n",
"@file:Repository(\"https://repo.kotlin.link\")\n",
"@file:Repository(\"https://maven.pkg.jetbrains.space/spc/p/sci/dev\")\n",
"@file:DependsOn(\"space.kscience:visionforge-jupyter-common-jvm:0.3.0-dev-12\")\n",
"//import space.kscience.visionforge.jupyter.JupyterCommonIntegration\n",
"//\n",
"//val integration = JupyterCommonIntegration()\n",
"//USE(integration.getDefinitions(notebook).first())"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"vf.fragment {\n",
" h1 { +\"AAA\" }\n",
" vision {\n",
" solid {\n",
" ambientLight()\n",
" box(100, 100, 200)\n",
"\n",
" sphere(100) {\n",
" x = 300\n",
" }\n",
" }\n",
" }\n",
"\n",
" vision {\n",
" plotly {\n",
" scatter {\n",
" x(1, 2, 3, 1)\n",
" y(1, 2, 3, 4)\n",
" }\n",
" }\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"Plotly.plot { \n",
" scatter{\n",
" x(1,2,3)\n",
" y(1,2,3)\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Kotlin",
"language": "kotlin",
"name": "kotlin"
},
"language_info": {
"codemirror_mode": "text/x-kotlin",
"file_extension": ".kt",
"mimetype": "text/x-kotlin",
"name": "kotlin",
"nbconvert_exporter": "",
"pygments_lexer": "kotlin",
"version": "1.8.20"
},
"ktnbPluginMetadata": {
"projectLibraries": []
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,45 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"USE(JupyterCommonIntegration())"
]
},
{
"cell_type": "code",
"execution_count": null,
"outputs": [],
"source": [],
"metadata": {
"collapsed": false
}
}
],
"metadata": {
"kernelspec": {
"display_name": "Kotlin",
"language": "kotlin",
"name": "kotlin"
},
"language_info": {
"name": "kotlin",
"version": "1.9.0",
"mimetype": "text/x-kotlin",
"file_extension": ".kt",
"pygments_lexer": "kotlin",
"codemirror_mode": "text/x-kotlin",
"nbconvert_exporter": ""
},
"ktnbPluginMetadata": {
"projectDependencies": true
}
},
"nbformat": 4,
"nbformat_minor": 0
}

View File

@ -0,0 +1,89 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": [],
"pycharm": {
"is_executing": true
}
},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"vf.startServer()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import kotlinx.coroutines.*\n",
"import kotlin.random.Random\n",
"\n",
"Plotly.plot{\n",
" scatter{\n",
" x(1,2,3)\n",
" y(1,2,3)\n",
" if(vf.isServerRunning()){\n",
" vf.launch{\n",
" while(isActive){\n",
" delay(500)\n",
" y(Random.nextDouble(), Random.nextDouble(), Random.nextDouble())\n",
" }\n",
" }\n",
" }\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"vf.stopServer()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Kotlin",
"language": "kotlin",
"name": "kotlin"
},
"language_info": {
"codemirror_mode": "text/x-kotlin",
"file_extension": ".kt",
"mimetype": "text/x-kotlin",
"name": "kotlin",
"nbconvert_exporter": "",
"pygments_lexer": "kotlin",
"version": "1.8.0-dev-3517"
},
"ktnbPluginMetadata": {
"projectLibraries": []
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -1,4 +1,5 @@
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.visionforge.jupyter.VFNotebookClient
import space.kscience.visionforge.markup.MarkupPlugin
import space.kscience.visionforge.plotly.PlotlyPlugin
import space.kscience.visionforge.ring.ThreeWithControlsPlugin
@ -11,4 +12,5 @@ fun main() = runVisionClient {
plugin(PlotlyPlugin)
plugin(MarkupPlugin)
plugin(TableVisionJsPlugin)
plugin(VFNotebookClient)
}

View File

@ -0,0 +1,83 @@
package space.kscience.visionforge.examples
import ru.mipt.npm.root.BMN
import ru.mipt.npm.root.DGeoManager
import ru.mipt.npm.root.rootGeo
import ru.mipt.npm.root.serialization.TGeoManager
import ru.mipt.npm.root.toVector
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.isLeaf
import space.kscience.dataforge.meta.string
import space.kscience.visionforge.Colors
import space.kscience.visionforge.html.ResourceLocation
import space.kscience.visionforge.solid.*
import java.util.zip.ZipInputStream
import kotlin.io.path.Path
import kotlin.io.path.createDirectories
import kotlin.io.path.writeText
private fun Meta.countTypes(): Sequence<String> = sequence {
if (!isLeaf) {
get("_typename")?.value?.let { yield(it.string) }
items.forEach { yieldAll(it.value.countTypes()) }
}
}
fun main() {
Path("data").createDirectories()
val string = ZipInputStream(TGeoManager::class.java.getResourceAsStream("/root/geometry_run_7-2076.zip")!!).use {
it.nextEntry
it.readAllBytes().decodeToString()
}
val geo = DGeoManager.parse(string)
val sizes = geo.meta.countTypes().groupBy { it }.mapValues { it.value.size }
sizes.forEach {
println(it)
}
val events = BMN.readEventJson(TGeoManager::class.java.getResourceAsStream("/root/event_0.json")!!.bufferedReader().readText())
makeVisionFile(path = Path("data/output.html"), resourceLocation = ResourceLocation.EMBED) {
vision("canvas") {
requirePlugin(Solids)
solid {
ambientLight {
color(Colors.white)
}
rootGeo(geo,"BM@N", ignoreRootColors = true).also {
Path("data/BM@N.vf.json").writeText(Solids.encodeToString(it))
}
solidGroup("cbmStsTracks") {
events.cbmTracks.forEach { track ->
polyline(
track.fParamFirst.toVector(),
track.fParamLast.toVector()
) {
thickness = 2.0
color(Colors.blue)
}
}
}
solidGroup("bmnGlobalTracks") {
events.bmnGlobalTracks.forEach { track ->
polyline(
track.fParamFirst.toVector(),
track.fParamLast.toVector()
) {
thickness = 2.0
color(Colors.red)
}
}
}
}
}
}
}

View File

@ -1,50 +0,0 @@
package space.kscience.visionforge.examples
import org.jetbrains.kotlinx.jupyter.api.libraries.resources
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.gdml.Gdml
import space.kscience.plotly.Plot
import space.kscience.visionforge.gdml.toVision
import space.kscience.visionforge.jupyter.JupyterPluginBase
import space.kscience.visionforge.plotly.PlotlyPlugin
import space.kscience.visionforge.plotly.asVision
import space.kscience.visionforge.solid.Solids
@DFExperimental
internal class VisionForgePlayGroundForJupyter : JupyterPluginBase(
Context("VisionForge") {
plugin(Solids)
plugin(PlotlyPlugin)
}
) {
override fun Builder.afterLoaded() {
resources {
js("VisionForge") {
classPath("js/visionforge-playground.js")
}
}
import(
"space.kscience.gdml.*",
"space.kscience.plotly.*",
"space.kscience.plotly.models.*",
"space.kscience.visionforge.solid.*",
)
render<Gdml> { gdmlModel ->
handler.produceHtml {
vision { gdmlModel.toVision() }
}
}
render<Plot> { plot ->
handler.produceHtml {
vision { plot.asVision() }
}
}
}
}

View File

@ -1,7 +1,8 @@
package space.kscience.visionforge.examples
import kotlinx.html.h2
import space.kscience.dataforge.values.ValueType
import space.kscience.dataforge.meta.ValueType
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.layout
import space.kscience.plotly.models.ScatterMode
import space.kscience.plotly.models.TextPosition
@ -12,13 +13,14 @@ import space.kscience.visionforge.markup.markdown
import space.kscience.visionforge.plotly.plotly
import space.kscience.visionforge.solid.box
import space.kscience.visionforge.solid.solid
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
import space.kscience.visionforge.solid.z
import space.kscience.visionforge.tables.columnTable
import java.nio.file.Paths
import kotlin.io.path.Path
fun main() = makeVisionFile(
Paths.get("VisionForgeDemo.html"),
Path("VisionForgeDemo.html"),
resourceLocation = ResourceLocation.EMBED
) {
markdown {
@ -32,7 +34,14 @@ fun main() = makeVisionFile(
h2 { +"3D visualization with Three-js" }
vision("3D") {
solid {
solid(
Canvas3DOptions {
axes {
size = 200.0
visible = true
}
}
) {
box(100, 100, 100, name = "aBox") {
z = 50.0
}

View File

@ -0,0 +1,102 @@
package space.kscience.visionforge.examples
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import space.kscience.dataforge.meta.configure
import space.kscience.kmath.complex.Quaternion
import space.kscience.kmath.complex.QuaternionField
import space.kscience.kmath.complex.conjugate
import space.kscience.kmath.geometry.*
import space.kscience.visionforge.solid.*
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin
fun main() = serve {
// val azimuth = 60.degrees
// val inclination = 15.degrees
// val direction = with(QuaternionField) {
// Quaternion.fromRotation(-azimuth, Euclidean3DSpace.zAxis) *
// Quaternion.fromRotation(Angle.piDiv2 - inclination, Euclidean3DSpace.yAxis)
// }
//val direction2 = Quaternion.fromEuler(Angle.zero, Angle.piDiv2 - inclination, -azimuth, RotationOrder.ZYX)
val target = Quaternion.fromEuler((-45).degrees, 45.degrees, Angle.zero, RotationOrder.XYZ)
vision("canvas") {
requirePlugin(Solids)
solid(options = {
configure { "controls.enabled" put false }
}) {
rotationX = -PI / 2
rotationZ = PI
//axes(200)
ambientLight()
val platform = solidGroup("platform") {
cylinder(50, 5, name = "base")
solidGroup("frame") {
z = 60
solidGroup("antenna") {
axes(200)
tube(40, 10, 30)
sphereLayer(100, 95, theta = PI / 6) {
z = 100
rotationX = -PI / 2
}
cylinder(5, 30) {
z = 15
}
sphereLayer(101, 94, phi = PI / 32, theta = PI / 6) {
z = 100
rotationX = -PI / 2
color("red")
}
quaternion = target
}
}
}
val frame = platform["frame"] as SolidGroup
val antenna = frame["antenna"] as SolidGroup
val xPeriod = 5000 //ms
val yPeriod = 7000 //ms
val incRot = Quaternion.fromRotation(30.degrees, Euclidean3DSpace.zAxis)
context.launch {
var time: Long = 0L
while (isActive) {
with(QuaternionField) {
delay(200)
platform.quaternion = Quaternion.fromRotation(
15.degrees * sin(time.toDouble() * 2 * PI / xPeriod),
Euclidean3DSpace.xAxis
) * Quaternion.fromRotation(
15.degrees * cos(time * 2 * PI / yPeriod),
Euclidean3DSpace.yAxis
)
val qi = platform.quaternion * incRot
antenna.quaternion = qi.conjugate * incRot.conjugate * target
time += 200
//antenna.quaternion = Quaternion.fromRotation(5.degrees, Euclidean3DSpace.zAxis) * antenna.quaternion
}
}
}
}
}
}

View File

@ -0,0 +1,22 @@
package space.kscience.visionforge.examples
import space.kscience.kmath.geometry.Euclidean3DSpace
import space.kscience.kmath.geometry.radians
import space.kscience.visionforge.html.ResourceLocation
import space.kscience.visionforge.solid.*
import kotlin.math.PI
fun main() = makeVisionFile(resourceLocation = ResourceLocation.SYSTEM) {
vision("canvas") {
requirePlugin(Solids)
solid {
axes(100, "root-axes")
solidGroup("group") {
z = 100
rotate((PI / 4).radians, Euclidean3DSpace.vector(1, 1, 1))
axes(100, "local-axes")
box(50, 50, 50, "box")
}
}
}
}

View File

@ -0,0 +1,22 @@
package space.kscience.visionforge.examples
import space.kscience.visionforge.solid.ambientLight
import space.kscience.visionforge.solid.extruded
import space.kscience.visionforge.solid.polygon
import space.kscience.visionforge.solid.solid
fun main() = makeVisionFile {
vision("canvas") {
solid {
ambientLight()
extruded("extruded") {
shape{
polygon(8, 100)
}
layer(-30)
layer(0, x = 10, y = 10)
layer(30)
}
}
}
}

View File

@ -1,22 +1,42 @@
package space.kscience.visionforge.examples
import io.ktor.server.cio.CIO
import io.ktor.server.engine.embeddedServer
import io.ktor.server.http.content.staticResources
import io.ktor.server.routing.routing
import kotlinx.html.*
import space.kscience.dataforge.context.Global
import space.kscience.dataforge.context.fetch
import space.kscience.dataforge.context.request
import space.kscience.visionforge.VisionManager
import space.kscience.visionforge.html.Page
import space.kscience.visionforge.html.formFragment
import space.kscience.visionforge.html.VisionOfHtmlForm
import space.kscience.visionforge.html.VisionPage
import space.kscience.visionforge.html.bindForm
import space.kscience.visionforge.onPropertyChange
import space.kscience.visionforge.server.close
import space.kscience.visionforge.server.openInBrowser
import space.kscience.visionforge.server.serve
import space.kscience.visionforge.server.visionPage
@Suppress("ExtractKtorModule")
fun main() {
val visionManager = Global.fetch(VisionManager)
val visionManager = Global.request(VisionManager)
val server = visionManager.serve {
page(header = Page.scriptHeader("js/visionforge-playground.js")) {
val form = formFragment("form") {
val server = embeddedServer(CIO) {
routing {
staticResources("/", null)
}
val form = VisionOfHtmlForm("form").apply {
onPropertyChange(visionManager.context) {
println(values)
}
}
visionPage(
visionManager,
VisionPage.scriptHeader("js/visionforge-playground.js"),
) {
bindForm(form) {
label {
htmlFor = "fname"
+"First name:"
@ -47,17 +67,15 @@ fun main() {
value = "Submit"
}
}
println(form.values)
vision(form)
}
vision("form") { form }
form.onPropertyChange {
println(this)
}
}
}
}.start(false)
server.openInBrowser()
while (readln() != "exit") {
while (readlnOrNull() != "exit") {
}

View File

@ -223,7 +223,7 @@ fun main() = makeVisionFile(Path.of("curves.html"), resourceLocation = ResourceL
}
}
}.toVision {
configure { _, solid, _ ->
solids { _, solid, _ ->
//disable visibility for the world box
if(solid.name == "world"){
visible = false

View File

@ -1,12 +1,15 @@
package space.kscience.visionforge.examples
import space.kscience.gdml.GdmlShowCase
import space.kscience.visionforge.gdml.toVision
import space.kscience.visionforge.gdml.gdml
import space.kscience.visionforge.solid.Solids
import space.kscience.visionforge.solid.solid
fun main() = makeVisionFile {
vision("canvas") {
requirePlugin(Solids)
GdmlShowCase.babyIaxo().toVision()
solid {
gdml(GdmlShowCase.babyIaxo(), "D0")
}
}
}

View File

@ -6,6 +6,7 @@ import kotlinx.serialization.json.Json
import space.kscience.visionforge.solid.SolidGroup
import space.kscience.visionforge.solid.Solids
@OptIn(ExperimentalSerializationApi::class)
private val json = Json {
serializersModule = Solids.serializersModuleForSolids
prettyPrintIndent = " "

View File

@ -1,15 +1,92 @@
package space.kscience.visionforge.examples
import space.kscience.plotly.scatter
import space.kscience.dataforge.meta.Value
import space.kscience.plotly.layout
import space.kscience.plotly.models.*
import space.kscience.visionforge.html.ResourceLocation
import space.kscience.visionforge.plotly.plotly
fun main() = makeVisionFile(resourceLocation = ResourceLocation.SYSTEM) {
vision {
val trace1 = Violin {
text("sample length: 32")
marker {
line {
width = 2
color("#bebada")
}
symbol = Symbol.valueOf("line-ns")
}
orientation = Orientation.h
hoveron = ViolinHoveron.`points+kde`
meanline {
visible = true
}
legendgroup = "F"
scalegroup = "F"
points = ViolinPoints.all
pointpos = 1.2
jitter = 0
box {
visible = true
}
scalemode = ViolinScaleMode.count
showlegend = false
side = ViolinSide.positive
y0 = Value.of(0)
line {
color("#bebada")
}
name = "F"
x(10.07, 34.83, 10.65, 12.43, 24.08, 13.42, 12.48, 29.8, 14.52, 11.38,
20.27, 11.17, 12.26, 18.26, 8.51, 10.33, 14.15, 13.16, 17.47, 27.05, 16.43,
8.35, 18.64, 11.87, 19.81, 43.11, 13.0, 12.74, 13.0, 16.4, 16.47, 18.78)
}
val trace2 = Violin {
text("sample length: 32")
marker {
line {
width = 2
color("#8dd3c7")
}
symbol = Symbol.valueOf("line-ns")
}
orientation = Orientation.h
hoveron = ViolinHoveron.`points+kde`
meanline {
visible = true
}
legendgroup = "M"
scalegroup = "M"
points = ViolinPoints.all
pointpos = -1.2
jitter = 0
box {
visible = true
}
scalemode = ViolinScaleMode.count
showlegend = false
side = ViolinSide.negative
y0 = Value.of(0)
line {
color("#8dd3c7")
}
name = "M"
x(27.2, 22.76, 17.29, 19.44, 16.66, 32.68, 15.98, 13.03, 18.28, 24.71,
21.16, 11.69, 14.26, 15.95, 8.52, 22.82, 19.08, 16.0, 34.3, 41.19, 9.78,
7.51, 28.44, 15.48, 16.58, 7.56, 10.34, 13.51, 18.71, 20.53)
}
plotly {
scatter {
x(1, 2, 3)
y(5, 8, 7)
traces(trace1, trace2)
layout {
width = 800
height = 800
title = "Advanced Violin Plot"
}
}
}

View File

@ -2,6 +2,7 @@ package space.kscience.visionforge.examples
import kotlinx.html.div
import kotlinx.html.h1
import space.kscience.visionforge.Colors
import space.kscience.visionforge.html.ResourceLocation
import space.kscience.visionforge.solid.*
import java.nio.file.Paths
@ -17,6 +18,9 @@ fun main() = makeVisionFile(
div {
vision {
solid {
ambientLight {
color(Colors.white)
}
repeat(100) {
sphere(5, name = "sphere[$it]") {
x = random.nextDouble(-300.0, 300.0)

View File

@ -1,106 +0,0 @@
package space.kscience.visionforge.examples
import ru.mipt.npm.root.DGeoManager
import ru.mipt.npm.root.serialization.TGeoManager
import ru.mipt.npm.root.toSolid
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.isLeaf
import space.kscience.dataforge.values.string
import space.kscience.visionforge.solid.Solids
import java.nio.file.Paths
import java.util.zip.ZipInputStream
import kotlin.io.path.writeText
private fun Meta.countTypes(): Sequence<String> = sequence {
if (!isLeaf) {
get("_typename")?.value?.let { yield(it.string) }
items.forEach { yieldAll(it.value.countTypes()) }
}
}
fun main() {
val string = ZipInputStream(TGeoManager::class.java.getResourceAsStream("/root/BM@N_geometry.zip")!!).use {
it.nextEntry
it.readAllBytes().decodeToString()
}
val geo = DGeoManager.parse(string)
val sizes = geo.meta.countTypes().groupBy { it }.mapValues { it.value.size }
sizes.forEach {
println(it)
}
val solid = geo.toSolid()
Paths.get("BM@N.vf.json").writeText(Solids.encodeToString(solid))
//println(Solids.encodeToString(solid))
makeVisionFile {
vision("canvas") {
requirePlugin(Solids)
solid
}
}
}
/* SolidGroup {
set(
"Coil",
solid.getPrototype("Coil".asName())!!.apply {
parent = null
}
)
*//* group("Shade") {
y = 200
color("red")
coneSurface(
bottomOuterRadius = 135,
bottomInnerRadius = 25,
height = 50,
topOuterRadius = 135,
topInnerRadius = 25,
angle = 1.5707964
) {
position = Point3D(79.6, 0, -122.1)
rotation = Point3D(-1.5707964, 0, 0)
}
coneSurface(
bottomOuterRadius = 135,
bottomInnerRadius = 25,
height = 50,
topOuterRadius = 135,
topInnerRadius = 25,
angle = 1.5707964
) {
position = Point3D(-79.6, 0, -122.1)
rotation = Point3D(1.5707964, 0, -3.1415927)
}
coneSurface(
bottomOuterRadius = 135,
bottomInnerRadius = 25,
height = 50,
topOuterRadius = 135,
topInnerRadius = 25,
angle = 1.5707964
) {
position = Point3D(79.6, 0, 122.1)
rotation = Point3D(1.5707964, 0, 0)
}
coneSurface(
bottomOuterRadius = 135,
bottomInnerRadius = 25,
height = 50,
topOuterRadius = 135,
topInnerRadius = 25,
angle = 1.5707964
) {
position = Point3D(-79.6, 0, 122.1)
rotation = Point3D(-1.5707964, 0, -3.1415927)
}
}*//*
}*/

View File

@ -1,14 +1,24 @@
package space.kscience.visionforge.examples
import io.ktor.server.cio.CIO
import io.ktor.server.engine.embeddedServer
import io.ktor.server.http.content.staticResources
import io.ktor.server.routing.routing
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.Global
import space.kscience.visionforge.html.HtmlVisionFragment
import space.kscience.visionforge.html.Page
import space.kscience.visionforge.html.ResourceLocation
import space.kscience.visionforge.html.importScriptHeader
import space.kscience.visionforge.makeFile
import space.kscience.visionforge.html.*
import space.kscience.visionforge.markup.MarkupPlugin
import space.kscience.visionforge.plotly.PlotlyPlugin
import space.kscience.visionforge.server.close
import space.kscience.visionforge.server.openInBrowser
import space.kscience.visionforge.server.visionPage
import space.kscience.visionforge.solid.Solids
import space.kscience.visionforge.tables.TableVisionPlugin
import space.kscience.visionforge.visionManager
import java.awt.Desktop
import java.nio.file.Path
public fun makeVisionFile(
path: Path? = null,
title: String = "VisionForge page",
@ -16,15 +26,58 @@ public fun makeVisionFile(
show: Boolean = true,
content: HtmlVisionFragment,
): Unit {
val actualPath = Page(Global, content = content).makeFile(path) { actualPath ->
val actualPath = VisionPage(Global.visionManager, content = content).makeFile(path) { actualPath ->
mapOf(
"title" to Page.title(title),
"playground" to Page.importScriptHeader("js/visionforge-playground.js", resourceLocation, actualPath),
"title" to VisionPage.title(title),
"playground" to VisionPage.importScriptHeader(
"js/visionforge-playground.js",
resourceLocation,
actualPath
),
)
}
if (show) Desktop.getDesktop().browse(actualPath.toFile().toURI())
}
public fun serve(
title: String = "VisionForge page",
show: Boolean = true,
content: HtmlVisionFragment,
) {
val context = Context("playground") {
plugin(Solids)
plugin(PlotlyPlugin)
plugin(MarkupPlugin)
plugin(TableVisionPlugin)
}
val server = embeddedServer(CIO, port = 7779) {
routing {
staticResources("", null, null)
}
visionPage(
context.visionManager,
VisionPage.scriptHeader("js/visionforge-playground.js") {
defer = true
},
VisionPage.title(title),
visionFragment = content
)
}.start(false)
if (show) {
server.openInBrowser()
}
println("Enter 'exit' to close server")
while (readlnOrNull() != "exit") {
//
}
server.close()
}
//@DFExperimental
//public fun Context.makeVisionFile(
// vision: Vision,

View File

@ -0,0 +1,40 @@
package space.kscience.visionforge.examples
import space.kscience.visionforge.Colors
import space.kscience.visionforge.solid.*
import kotlin.math.PI
fun main() = makeVisionFile {
vision("canvas") {
solid {
ambientLight()
box(100.0, 100.0, 100.0) {
z = -110.0
color("teal")
}
sphere(50.0) {
x = 110
detail = 16
color("red")
}
tube(50, height = 10, innerRadius = 25, angle = PI) {
y = 110
detail = 16
rotationX = PI / 4
color("blue")
}
sphereLayer(50, 40, theta = PI / 2) {
rotationX = -PI * 3 / 4
z = 110
color(Colors.pink)
}
cylinder(30,20, name = "cylinder"){
detail = 31
y = -220
z = 15
}
}
}
}

View File

@ -0,0 +1,19 @@
package space.kscience.visionforge.examples
import space.kscience.visionforge.solid.ambientLight
import space.kscience.visionforge.solid.polygon
import space.kscience.visionforge.solid.solid
import space.kscience.visionforge.solid.surface
fun main() = makeVisionFile {
vision("canvas") {
solid {
ambientLight()
surface("surface") {
layer(0, { polygon(8, 10) }, { polygon(8, 20) })
layer(10, { polygon(8, 20) }, { polygon(8, 30) })
layer(20, { polygon(8, 10) }, { polygon(8, 20) })
}
}
}
}

View File

@ -1,6 +1,6 @@
package space.kscience.visionforge.examples
import space.kscience.dataforge.values.ValueType
import space.kscience.dataforge.meta.ValueType
import space.kscience.tables.ColumnHeader
import space.kscience.tables.valueRow
import space.kscience.visionforge.html.ResourceLocation

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,215 @@
[
[{
"_typename" : "CbmStsTrack",
"fUniqueID" : 0,
"fBits" : 0,
"ststrk" : 2112745000,
"fStsHits" : [216, 221, 5, 50, 63, 82, 133],
"fMvdHits" : [],
"fPidHypo" : 211,
"fParamFirst" : {
"_typename" : "FairTrackParam",
"fUniqueID" : 0,
"fBits" : 0,
"fX" : -4.79052305221558,
"fY" : 8.83165168762207,
"fZ" : 36.5065002441406,
"fTx" : -0.11185921728611,
"fTy" : 0.228091076016426,
"fQp" : 0.893607378005981,
"fCovMatrix" : [1.68777798535302e-4, -9.69577522482723e-4, -1.07744517663377e-5, 1.2614247680176e-5, 2.87587154161884e-5, 0.0403835587203503, 5.90448107686825e-5, -5.16064348630607e-4, -2.05383723368868e-4, 2.20405854634009e-6, -8.30146461794357e-7, -5.49759215573431e-6, 1.16227884063846e-5, 3.6013934732182e-6, 1.46196922287345e-4]
},
"fParamLast" : {
"_typename" : "FairTrackParam",
"fUniqueID" : 0,
"fBits" : 0,
"fX" : 4.67626953125,
"fY" : 43.7959594726562,
"fZ" : 190.759826660156,
"fTx" : 0.240885242819786,
"fTy" : 0.230351597070694,
"fQp" : 0.896391570568085,
"fCovMatrix" : [0.00152156152762473, 0.00325645040720701, 4.73157851956785e-5, 4.51812447863631e-5, 1.32256536744535e-4, 0.0311740729957819, 1.29416745039634e-4, 3.94528120523319e-4, 3.28425812767819e-4, 3.75195077140233e-6, 1.75166894678114e-6, 9.62230569712119e-6, 9.89728778222343e-6, 4.38717188444571e-6, 1.46559861605056e-4]
},
"fFlag" : 0,
"fChi2" : 3.59655165672302,
"fNDF" : 9,
"fB" : 0,
"fnEv" : 0,
"fHitsArr" : {
"_typename" : "TClonesArray",
"name" : "CbmStsHits",
"arr" : []
}
}, {
"_typename" : "CbmStsTrack",
"fUniqueID" : 0,
"fBits" : 0,
"ststrk" : 0,
"fStsHits" : [79, 108, 136, 160],
"fMvdHits" : [],
"fPidHypo" : 211,
"fParamFirst" : {
"_typename" : "FairTrackParam",
"fUniqueID" : 0,
"fBits" : 0,
"fX" : 7.56474113464355,
"fY" : -6.31765508651733,
"fZ" : 123.474571228027,
"fTx" : 0.198165953159332,
"fTy" : -0.0599287338554859,
"fQp" : 0.826108694076538,
"fCovMatrix" : [0.00192060391418636, -0.00543995574116707, -7.47249359847046e-5, 9.40304598771036e-5, 4.32362634455785e-4, 0.0452092550694942, 2.69763870164752e-4, -7.19496863894165e-4, -0.00178805936593562, 5.47440777154407e-6, -4.97666542287334e-6, -3.32396593876183e-5, 1.67156704264926e-5, 3.69572808267549e-5, 3.62657097866759e-4]
},
"fParamLast" : {
"_typename" : "FairTrackParam",
"fUniqueID" : 0,
"fBits" : 0,
"fX" : 38.4175720214844,
"fY" : -12.5351896286011,
"fZ" : 222.266052246094,
"fTx" : 0.428264498710632,
"fTy" : -0.0652719661593437,
"fQp" : 0.827384233474731,
"fCovMatrix" : [0.00191446917597204, 0.00539331184700131, 7.50113686081022e-5, 9.10265880520456e-5, 4.29905543569475e-4, 0.0449054278433323, 2.68147414317355e-4, 7.0479983696714e-4, 0.00177141127642244, 5.60895068701939e-6, 4.76898094348144e-6, 3.39166836056393e-5, 1.61108710017288e-5, 3.51894050254487e-5, 3.57192009687424e-4]
},
"fFlag" : 0,
"fChi2" : 0.0889237225055695,
"fNDF" : 3,
"fB" : 0,
"fnEv" : 0,
"fHitsArr" : {
"_typename" : "TClonesArray",
"name" : "CbmStsHits",
"arr" : []
}
}]
,
[{
"_typename" : "BmnGlobalTrack",
"fUniqueID" : 0,
"fBits" : 0,
"fHits" : [],
"fParamFirst" : {
"_typename" : "FairTrackParam",
"fUniqueID" : 0,
"fBits" : 0,
"fX" : 0.514997541904449,
"fY" : 0.614071667194366,
"fZ" : 0.716018855571747,
"fTx" : -0.182437181472778,
"fTy" : 0.231170654296875,
"fQp" : 0.890645802021027,
"fCovMatrix" : [0.00640107085928321, -0.00549036636948586, -2.40077963098884e-4, 5.9050194977317e-5, 4.4034980237484e-4, 0.0939982086420059, 1.37060953420587e-4, -0.0010447750100866, -3.45796346664429e-4, 1.4494138667942e-5, -1.88720639471285e-6, -1.71545361808967e-5, 2.24065261136275e-5, 4.27886925535859e-6, 1.46344274980947e-4]
},
"fParamLast" : {
"_typename" : "FairTrackParam",
"fUniqueID" : 0,
"fBits" : 0,
"fX" : 4.67626953125,
"fY" : 43.7959594726562,
"fZ" : 190.759826660156,
"fTx" : 0.240885242819786,
"fTy" : 0.230351597070694,
"fQp" : 0.896391570568085,
"fCovMatrix" : [0.00152156152762473, 0.00325645040720701, 4.73157851956785e-5, 4.51812447863631e-5, 1.32256536744535e-4, 0.0311740729957819, 1.29416745039634e-4, 3.94528120523319e-4, 3.28425812767819e-4, 3.75195077140233e-6, 1.75166894678114e-6, 9.62230569712119e-6, 9.89728778222343e-6, 4.38717188444571e-6, 1.46559861605056e-4]
},
"fFlag" : -1,
"fChi2" : 3.596552,
"fNDF" : 9,
"fB" : 0,
"fLength" : 196.4224,
"fNhits" : 7,
"fUsing" : false,
"fGemTrack" : 0,
"fSsdTrack" : -1,
"fSilTrack" : -1,
"fTof1Hit" : -1,
"fTof2Hit" : -1,
"fDch1Track" : -1,
"fDch2Track" : -1,
"fDchTrack" : -1,
"fMwpc1Track" : -1,
"fMwpc2Track" : -1,
"fUpstreamTrack" : -1,
"fScWallCellId" : -1,
"fCscHit" : [-1, -1, -1, -1],
"fScWallSignal" : -1000,
"fBeta400" : -1000,
"fBeta700" : -1000,
"fdQdNUpper" : 0,
"fdQdNLower" : 0,
"fA" : -1,
"fZ" : 0,
"fPDG" : 0,
"fChi2InVertex" : 2.34478793822074e-310,
"fDCAInVertex" : 0.169359803199768,
"fPidTof400" : [],
"fPidTof700" : [],
"fIsPrimary" : true,
"fRefIndex" : 0
}, {
"_typename" : "BmnGlobalTrack",
"fUniqueID" : 0,
"fBits" : 0,
"fHits" : [],
"fParamFirst" : {
"_typename" : "FairTrackParam",
"fUniqueID" : 0,
"fBits" : 0,
"fX" : -1.30332088470459,
"fY" : 0.709633886814117,
"fZ" : 0.716018855571747,
"fTx" : -0.0394387505948544,
"fTy" : -0.0554707236588001,
"fQp" : 0.794627845287323,
"fCovMatrix" : [1.0362377166748, -0.242409482598305, -0.0120293609797955, 0.00132000644225627, 0.0113498065620661, 1.10034370422363, 0.0026963478885591, -0.0100266374647617, -0.00638964772224426, 1.71858730027452e-4, -1.46718830364989e-5, -1.39145020511933e-4, 1.31993641844019e-4, 3.72123940906022e-5, 3.64089268259704e-4]
},
"fParamLast" : {
"_typename" : "FairTrackParam",
"fUniqueID" : 0,
"fBits" : 0,
"fX" : 153.443832397461,
"fY" : -27.7408638000488,
"fZ" : 422.371002197266,
"fTx" : 0.623147189617157,
"fTy" : -0.0757252722978592,
"fQp" : 0.879441320896149,
"fCovMatrix" : [0.210621446371078, 0.00677151698619127, 0.00126052019186318, -1.89192069228739e-5, 0.00233594398014247, 0.117487587034702, 1.90632126759738e-5, 5.61361608561128e-4, 3.66047053830698e-4, 5.4321233619703e-5, -1.38209452416049e-6, 1.40239317261148e-5, 3.86252722819336e-5, -2.07852266953523e-7, 1.6525064711459e-4]
},
"fFlag" : -1,
"fChi2" : 28.54445,
"fNDF" : 3,
"fB" : 0,
"fLength" : 456.7299,
"fNhits" : 5,
"fUsing" : false,
"fGemTrack" : 1,
"fSsdTrack" : -1,
"fSilTrack" : -1,
"fTof1Hit" : 0,
"fTof2Hit" : -1,
"fDch1Track" : -1,
"fDch2Track" : -1,
"fDchTrack" : -1,
"fMwpc1Track" : -1,
"fMwpc2Track" : -1,
"fUpstreamTrack" : -1,
"fScWallCellId" : -1,
"fCscHit" : [-1, -1, -1, -1],
"fScWallSignal" : -1000,
"fBeta400" : 0.813491527513362,
"fBeta700" : -1000,
"fdQdNUpper" : 0,
"fdQdNLower" : 0,
"fA" : -1,
"fZ" : 0,
"fPDG" : 0,
"fChi2InVertex" : 2.34478793822074e-310,
"fDCAInVertex" : 1.82100653648376,
"fPidTof400" : [0.698706510566553, 0.0456706934329348, 0.070160747316434, 0.044178479600919, 0.0321317585690916, 0.0203602877603981, 0.0563498151154308, 0.0324417076382387],
"fPidTof700" : [],
"fIsPrimary" : true,
"fRefIndex" : 0
}]
]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
plugins {
id("ru.mipt.npm.gradle.jvm")
id("space.kscience.gradle.jvm")
application
}
@ -8,15 +8,15 @@ kscience {
// useSerialization {
// json()
// }
application()
}
group = "ru.mipt.npm"
useKtor()
dependencies{
implementation(project(":visionforge-threejs:visionforge-threejs-server"))
implementation("ch.qos.logback:logback-classic:1.2.3")
implementation("io.ktor:ktor-server-cio")
implementation(projects.visionforgeThreejs.visionforgeThreejsServer)
implementation(spclibs.logback.classic)
}
}
group = "center.sciprog"
application {
mainClass.set("ru.mipt.npm.sat.SatServerKt")

View File

@ -6,7 +6,7 @@ import space.kscience.visionforge.style
import space.kscience.visionforge.useStyle
import kotlin.math.PI
internal fun visionOfSatellite(
internal fun Solids.visionOfSatellite(
layers: Int = 10,
layerHeight: Number = 10,
xSegments: Int = 3,
@ -14,7 +14,7 @@ internal fun visionOfSatellite(
xSegmentSize: Number = 30,
ySegmentSize: Number = xSegmentSize,
fiberDiameter: Number = 1.0,
): SolidGroup = SolidGroup {
): SolidGroup = solidGroup {
color("darkgreen")
val transparent by style {
this[SolidMaterial.MATERIAL_OPACITY_KEY] = 0.3
@ -31,7 +31,7 @@ internal fun visionOfSatellite(
val totalXSize = xSegments * xSegmentSize.toDouble()
val totalYSize = ySegments * ySegmentSize.toDouble()
for (layer in 1..layers) {
group("layer[$layer]") {
solidGroup("layer[$layer]") {
for (i in 1..xSegments) {
for (j in 1..ySegments) {
box(xSegmentSize, ySegmentSize, layerHeight, name = "segment[$i,$j]") {
@ -42,7 +42,7 @@ internal fun visionOfSatellite(
}
}
}
group("fibers") {
solidGroup("fibers") {
for (i in 1..xSegments) {
cylinder(fiberDiameter, totalYSize) {
useStyle(red)

View File

@ -1,38 +1,57 @@
package ru.mipt.npm.sat
import io.ktor.server.cio.CIO
import io.ktor.server.engine.embeddedServer
import io.ktor.server.http.content.staticResources
import io.ktor.server.routing.routing
import kotlinx.coroutines.*
import kotlinx.html.div
import kotlinx.html.h1
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.request
import space.kscience.dataforge.meta.Null
import space.kscience.dataforge.names.Name
import space.kscience.visionforge.html.Page
import space.kscience.visionforge.html.plus
import space.kscience.visionforge.Colors
import space.kscience.visionforge.html.VisionPage
import space.kscience.visionforge.server.close
import space.kscience.visionforge.server.openInBrowser
import space.kscience.visionforge.server.serve
import space.kscience.visionforge.server.visionPage
import space.kscience.visionforge.solid.*
import space.kscience.visionforge.three.threeJsHeader
import space.kscience.visionforge.visionManager
import kotlin.random.Random
@Suppress("ExtractKtorModule")
fun main() {
val satContext = Context("sat") {
plugin(Solids)
}
//Create a geometry
val sat = visionOfSatellite(ySegments = 3)
val solids = satContext.request(Solids)
val server = satContext.visionManager.serve {
page(header = Page.threeJsHeader + Page.styleSheetHeader("css/styles.css")) {
//Create a geometry
val sat = solids.visionOfSatellite(ySegments = 3).apply {
ambientLight {
color(Colors.white)
}
}
val server = embeddedServer(CIO, port = 7777) {
routing {
staticResources("", null, null)
}
visionPage(
solids.visionManager, VisionPage.threeJsHeader,
VisionPage.styleSheetHeader("css/styles.css")
) {
div("flex-column") {
h1 { +"Satellite detector demo" }
vision { sat }
}
}
}
}.start(false)
server.openInBrowser()
@ -46,7 +65,8 @@ fun main() {
val targetVision = sat[target] as Solid
targetVision.color("red")
delay(1000)
targetVision.color.clear()
//use to ensure that color is cleared
targetVision.color.value = Null
delay(500)
}
}

View File

@ -0,0 +1,21 @@
package ru.mipt.npm.sat
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.visionforge.html.ResourceLocation
import space.kscience.visionforge.solid.box
import space.kscience.visionforge.solid.invoke
import space.kscience.visionforge.solid.material
import space.kscience.visionforge.solid.solid
import space.kscience.visionforge.three.makeThreeJsFile
@OptIn(DFExperimental::class)
fun main() = makeThreeJsFile(resourceLocation = ResourceLocation.SYSTEM) {
vision ("canvas") {
solid {
box(100, 100, 100)
material {
emissiveColor("red")
}
}
}
}

View File

@ -1,44 +1,26 @@
import ru.mipt.npm.gradle.DependencyConfiguration
import ru.mipt.npm.gradle.FXModule
plugins {
id("ru.mipt.npm.gradle.mpp")
application
id("space.kscience.gradle.mpp")
// application
}
kscience {
useCoroutines()
val fxVersion: String by rootProject.extra
useFx(FXModule.CONTROLS, version = fxVersion, configuration = DependencyConfiguration.IMPLEMENTATION)
application()
jvm()
js{
binaries.executable()
}
kotlin {
jvm {
withJava()
}
sourceSets {
commonMain {
dependencies {
implementation(project(":visionforge-solid"))
// implementation(project(":visionforge-gdml"))
}
}
jvmMain {
dependencies {
implementation(project(":visionforge-fx"))
}
implementation(projects.visionforgeSolid)
implementation(projects.visionforgeGdml)
}
jsMain {
dependencies {
implementation(project(":visionforge-threejs"))
}
}
implementation(projects.visionforgeThreejs)
}
}
application {
mainClassName = "space.kscience.visionforge.solid.demo.FXDemoAppKt"
}
kotlin.explicitApi = null
//application {
// mainClass.set("space.kscience.visionforge.solid.demo.FXDemoAppKt")
//}

View File

@ -3,7 +3,10 @@ package space.kscience.visionforge.solid.demo
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.names.Name
import space.kscience.visionforge.Vision
import space.kscience.visionforge.solid.Solids
public interface VisionLayout<in V: Vision> {
public fun render(name: Name, vision: V, meta: Meta = Meta.EMPTY)
interface VisionLayout<in V: Vision> {
val solids: Solids
fun render(name: Name, vision: V, meta: Meta = Meta.EMPTY)
}

View File

@ -4,6 +4,8 @@ import kotlinx.coroutines.*
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.invoke
import space.kscience.dataforge.names.Name
import space.kscience.kmath.geometry.Euclidean3DSpace
import space.kscience.kmath.geometry.radians
import space.kscience.visionforge.Colors
import space.kscience.visionforge.solid.*
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
@ -18,7 +20,12 @@ fun VisionLayout<Solid>.demo(name: String, title: String = name, block: SolidGro
val meta = Meta {
"title" put title
}
val vision = SolidGroup(block)
val vision = solids.solidGroup {
block()
ambientLight {
color(Colors.white)
}
}
render(Name.parse(name), vision, meta)
}
@ -39,6 +46,7 @@ val canvasOptions = Canvas3DOptions {
@OptIn(DelicateCoroutinesApi::class)
fun VisionLayout<Solid>.showcase() {
demo("shapes", "Basic shapes") {
ambientLight()
box(100.0, 100.0, 100.0) {
z = -110.0
color("teal")
@ -62,7 +70,7 @@ fun VisionLayout<Solid>.showcase() {
}
demo("dynamic", "Dynamic properties") {
val group = group {
val group = solidGroup {
box(100, 100, 100) {
z = 110.0
opacity = 0.5
@ -94,11 +102,18 @@ fun VisionLayout<Solid>.showcase() {
demo("rotation", "Rotations") {
box(100, 100, 100)
group {
solidGroup {
x = 200
rotationY = PI / 4
axes(200)
box(100, 100, 100) {
rotationZ = PI / 4
rotate((PI / 4).radians, Euclidean3DSpace.zAxis)
GlobalScope.launch(Dispatchers.Main) {
while (isActive) {
delay(100)
rotate((PI/20).radians,Euclidean3DSpace.yAxis)
}
}
color(Colors.red)
}
}
@ -124,7 +139,10 @@ fun VisionLayout<Solid>.showcase() {
color(Colors.blue)
}
repeat(20) {
polyline(Point3D(100, 100, 100), Point3D(-100, -100, -100)) {
polyline(
Float32Vector3D(100, 100, 100),
Float32Vector3D(-100, -100, -100)
) {
thickness = 3.0
rotationX = it * PI2 / 20
color(Colors.green)
@ -141,6 +159,10 @@ fun VisionLayout<Solid>.showcase() {
z = 26
}
}
demo("STL", "STL loaded from URL") {
stl("https://ozeki.hu/attachments/116/Menger_sponge_sample.stl")
}
}
fun VisionLayout<Solid>.showcaseCSG() {

View File

@ -1,9 +1,9 @@
package space.kscience.visionforge.solid.demo
import kotlinx.browser.document
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import org.w3c.dom.Document
import space.kscience.visionforge.Application
import space.kscience.visionforge.solid.x
import space.kscience.visionforge.solid.y
@ -12,7 +12,7 @@ import kotlin.random.Random
private class ThreeDemoApp : Application {
override fun start(state: Map<String, Any>) {
override fun start(document: Document, state: Map<String, Any>) {
val element = document.getElementById("demo") ?: error("Element with id 'demo' not found on page")

View File

@ -10,12 +10,13 @@ import org.w3c.dom.Element
import org.w3c.dom.HTMLDivElement
import org.w3c.dom.HTMLElement
import space.kscience.dataforge.context.Global
import space.kscience.dataforge.context.fetch
import space.kscience.dataforge.context.request
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.string
import space.kscience.dataforge.names.Name
import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.Solids
import space.kscience.visionforge.solid.three.ThreeCanvas
import space.kscience.visionforge.solid.three.ThreePlugin
@ -25,7 +26,9 @@ class ThreeDemoGrid(element: Element) : VisionLayout<Solid> {
private val outputs: MutableMap<Name, ThreeCanvas> = HashMap()
private val three = Global.fetch(ThreePlugin)
private val three = Global.request(ThreePlugin)
override val solids: Solids get() = three.solids
init {
element.clear()

View File

@ -1,20 +1,19 @@
package space.kscience.visionforge.solid.demo
import info.laht.threekt.core.Object3D
import info.laht.threekt.geometries.BoxGeometry
import info.laht.threekt.objects.Mesh
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.asValue
import space.kscience.dataforge.meta.int
import space.kscience.dataforge.meta.number
import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.startsWith
import space.kscience.dataforge.values.asValue
import space.kscience.visionforge.onPropertyChange
import space.kscience.visionforge.set
import space.kscience.visionforge.setProperty
import space.kscience.visionforge.setChild
import space.kscience.visionforge.solid.SolidGroup
import space.kscience.visionforge.solid.SolidMaterial.Companion.EDGES_KEY
import space.kscience.visionforge.solid.layer
import space.kscience.visionforge.solid.three.*
import three.core.Object3D
import three.geometries.BoxGeometry
import three.objects.Mesh
import kotlin.math.max
internal fun SolidGroup.varBox(
@ -22,11 +21,11 @@ internal fun SolidGroup.varBox(
ySize: Number,
name: String = "",
action: VariableBox.() -> Unit = {},
): VariableBox = VariableBox(xSize, ySize).apply(action).also { set(name, it) }
): VariableBox = VariableBox(xSize, ySize).apply(action).also { setChild(name, it) }
internal class VariableBox(val xSize: Number, val ySize: Number) : ThreeJsVision() {
override fun render(three: ThreePlugin): Object3D {
override suspend fun render(three: ThreePlugin): Object3D {
val geometry = BoxGeometry(xSize, ySize, 1)
val material = ThreeMaterials.DEFAULT.clone()
@ -44,13 +43,13 @@ internal class VariableBox(val xSize: Number, val ySize: Number) : ThreeJsVision
it.layers.enable(this@VariableBox.layer)
}
}
mesh.scale.z = meta[VALUE].number?.toDouble() ?: 1.0
mesh.scale.z = properties.getValue(VALUE)?.number?.toDouble() ?: 1.0
//add listener to object properties
onPropertyChange { name ->
when {
name == VALUE -> {
val value = meta.get(VALUE).int ?: 0
val value = properties.getValue(VALUE)?.int ?: 0
val size = value.toFloat() / 255f * 20f
mesh.scale.z = size.toDouble()
mesh.position.z = size.toDouble() / 2
@ -61,7 +60,8 @@ internal class VariableBox(val xSize: Number, val ySize: Number) : ThreeJsVision
material.color.setRGB(r.toFloat() / 256, g.toFloat() / 256, b.toFloat() / 256)
mesh.updateMatrix()
}
name.startsWith(MeshThreeFactory.EDGES_KEY) -> mesh.applyEdges(this@VariableBox)
name.startsWith(EDGES_KEY) -> mesh.applyEdges(this@VariableBox)
else -> mesh.updateProperty(this@VariableBox, name)
}
}
@ -70,9 +70,9 @@ internal class VariableBox(val xSize: Number, val ySize: Number) : ThreeJsVision
}
var value: Int
get() = meta[VALUE].int ?: 0
get() = properties.getValue(VALUE)?.int ?: 0
set(value) {
setProperty(VALUE, value.asValue())
properties.setValue(VALUE, value.asValue())
}
companion object {

View File

@ -10,9 +10,11 @@ import space.kscience.dataforge.names.Name
import space.kscience.visionforge.solid.FX3DPlugin
import space.kscience.visionforge.solid.FXCanvas3D
import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.Solids
import tornadofx.*
class FXDemoGrid : View(title = "DataForge-vis FX demo"), VisionLayout<Solid> {
private val outputs = FXCollections.observableHashMap<Name, FXCanvas3D>()
override val root: Parent = borderpane {
@ -24,6 +26,9 @@ class FXDemoGrid : View(title = "DataForge-vis FX demo"), VisionLayout<Solid> {
}
private val fx3d = Global.fetch(FX3DPlugin)
override val solids: Solids get() = fx3d.solids
override fun render(name: Name, vision: Solid, meta: Meta) {
outputs.getOrPut(name) { FXCanvas3D(fx3d, canvasOptions) }.render(vision)

View File

@ -2,10 +2,10 @@ package space.kscience.visionforge.demo
import javafx.geometry.Orientation
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.ValueType
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.descriptors.node
import space.kscience.dataforge.meta.descriptors.value
import space.kscience.dataforge.values.ValueType
import space.kscience.visionforge.editor.FXMetaModel
import space.kscience.visionforge.editor.MetaViewer
import space.kscience.visionforge.editor.MutableMetaEditor

View File

@ -3,7 +3,7 @@
![](../docs/images/hierarchy.png)
### Vision
* function `getPropertyValue(name: Name, inherit: Boolean = false, includeStyles: Boolean = true, includeDefaults: Boolean = true)` - get property value with given layer flags.
* function `getProperty(name: Name, inherit: Boolean = false, includeStyles: Boolean = true, includeDefaults: Boolean = true)` - get property value with given layer flags.
* function `setProperty(name: Name, item: Any?)` - a convenient method to set property node or value. If `item` is null, then node is removed, not a value
Sets the `item` property to the element with the `name` identification.

View File

@ -7,7 +7,7 @@ Properties, which can be inherited by objects, are `styles`, `prototypes` (if th
All values of `styles` property are contained in class `StyleSheet`, where they all are defined at `Group`s level. The `prototypes` property tree is defined in `SolidGroup` class via `PrototypeHolder` interface, and
`SolidReference` class helps to reuse a template object.
The order of inheritance of properties is set in function `getPropertyValue` in `VisionBase` class.
The order of inheritance of properties is set in function `getProperty` in `VisionBase` class.
The order is this:
* own styles
* prototypes

View File

@ -59,7 +59,7 @@ box(10, 10, 10, name = "small box"){
rotation = Point3D(0, 0, 0)
}
```
![](../docs/images/small-box.png)
![](../images/small-box.png)
The `big box` will have properties with custom values.
```kotlin
@ -72,7 +72,7 @@ box(40, 40, 40, name = "big box"){
rotation = Point3D(60, 80, 0)
}
```
![](../docs/images/big-rotated-box.png)
![](../images/big-rotated-box.png)
If we compare these boxes, we will see all differences.
Here is the function `main` with both boxes.
@ -111,8 +111,8 @@ fun main(){
}
}
```
![](../docs/images/two-boxes-1.png)
![](../docs/images/two-boxes-2.png)
![](../images/two-boxes-1.png)
![](../images/two-boxes-2.png)
***There is plenty of other properties, especially those, which you can create by yourself. Here we mention just a small part.***
@ -142,8 +142,8 @@ polyline(Point3D(30, 20, 10), Point3D(30, -100, 30), Point3D(30, -100, 30), Poin
}
```
![](../docs/images/polyline-points.png)
![](../docs/images/polyline-points-2.png)
![](../images/polyline-points.png)
![](../images/polyline-points-2.png)
### 2) Box
@ -165,7 +165,7 @@ Let's create just usual `box` with equal ribs.
color("pink")
}
```
![](../docs/images/box.png)
![](../images/box.png)
Now, let's make `box` with bigger `y` value.
```kotlin
@ -175,7 +175,7 @@ Now, let's make `box` with bigger `y` value.
```
As you can see, only the rib of `y-axis` differs from other ribs.
![](../docs/images/high-box.png)
![](../images/high-box.png)
For a final trial, let's create a `box` with a bigger `x` value.
@ -189,7 +189,7 @@ For a final trial, let's create a `box` with a bigger `x` value.
```
Predictably, only the `x-axis` rib is bigger than other ribs.
![](../docs/images/wide-box.png)
![](../images/wide-box.png)
### 3) Sphere
@ -206,7 +206,7 @@ As for `radius`, it has `Float` type, and, as you can guess, it sets the radius
color("blue")
}
```
![](../docs/images/sphere.png)
![](../images/sphere.png)
### 4) Hexagon
@ -220,7 +220,7 @@ It is solid which has six edges. It is set by eight values: `node1`,..., `node8`
5) Edge with vertices `node1`, `node5`, `node8`, `node4`
6) Edge with vertices `node8`, `node5`, `node6`, `node7`
![](../docs/images/scheme.png)
![](../images/scheme.png)
As the hexagon takes in specific points, we understand that this solid cannot be moved, it is fixed in space, and it can't make pivots.
@ -239,7 +239,7 @@ Let's make classic parallelepiped.
color("green")
}
```
![](../docs/images/classic-hexagon.png)
![](../images/classic-hexagon.png)
Now, let's make a custom hexagon.
@ -258,7 +258,7 @@ hexagon(
color("brown")
}
```
![](../docs/images/custom-hexagon.png)
![](../images/custom-hexagon.png)
### 3) Cone
It takes in six values: `bottomRadius`, `height`, `upperRadius`, `startAngle`, `angle`, and `name`.
@ -274,8 +274,8 @@ Let's build a classic cone:
color("beige")
}
```
![](../docs/images/cone-1.png)
![](../docs/images/cone-2.png)
![](../images/cone-1.png)
![](../images/cone-2.png)
First of all, we have to try to build a frustum cone:
```kotlin
@ -283,7 +283,7 @@ cone(60, 80, name = "cone") {
color(0u, 40u, 0u)
}
```
![](../docs/images/frustum-cone.png)
![](../images/frustum-cone.png)
Now, we need to make a try to build a cone segment:
@ -292,8 +292,8 @@ cone(60, 80, angle = PI, name = "cone") {
color(0u, 0u, 200u)
}
```
![](../docs/images/cone-segment-1.png)
![](../docs/images/cone-segment-2.png)
![](../images/cone-segment-1.png)
![](../images/cone-segment-2.png)
Finally, the segment of frustum cone is left for a try:
```kotlin
@ -301,7 +301,7 @@ cone(60, 100, 20, PI*3/4, angle = PI/3, name = "cone") {
color(190u, 0u, 0u)
}
```
![](../docs/images/frustum-cone-segment.png)
![](../images/frustum-cone-segment.png)
### 4) Cone Surface
This solid is set by seven values:`bottomOuterRadius`, `bottomInnerRadius`, `height`, `topOuterRadius`, `topInnerRadius`, `startAngle`, and `angle`.
@ -318,8 +318,8 @@ Let's build usual cone surface with almost all properties set:
rotation = Point3D(2, 50, -9)
}
```
![](../docs/images/cone-surface-1.png)
![](../docs/images/cone-surface-2.png)
![](../images/cone-surface-1.png)
![](../images/cone-surface-2.png)
Now, let's create a cone surface and set all it's properties:
@ -329,8 +329,8 @@ coneSurface(30, 25, 10, 10, 8,0f, pi*3/4, name = "cone surface") {
rotation = Point3D(2, 50, -9)
}
```
![](../docs/images/cone-surface-fragment.png)
![](../docs/images/cone-surface-fragment-2.png)
![](../images/cone-surface-fragment.png)
![](../images/cone-surface-fragment-2.png)
### 5) Cylinder
@ -344,8 +344,8 @@ cylinder(40, 100, "cylinder"){
color("indigo")
}
```
![](../docs/images/cylinder-1.png)
![](../docs/images/cylinder-2.png)
![](../images/cylinder-1.png)
![](../images/cylinder-2.png)
### 6) Tube
`tube` takes in `radius`, `height`, `innerRadius`, `startAngle`, `angle`, and `name`. *All values are familiar from `cone`, and `coneSurface` solids.*
@ -356,7 +356,7 @@ tube(50, 40, 20, name = "usual tube"){
opacity = 0.4
}
```
![](../docs/images/tube.png)
![](../images/tube.png)
This is an example of tube fragment:
@ -365,7 +365,7 @@ tube(50, 40, 20, 0f, PI, name = "fragmented tube"){
color("white")
}
```
![](../docs/images/tube-fragment.png)
![](../images/tube-fragment.png)
### 7) Extruded
`extruded` is set by two values: `shape`, and `layer`.

View File

@ -3,7 +3,7 @@
interface Vision{
val parent: VisionGroup?
fun getPropertyValue(name,inherit,includeStyles,includeDefaults): Value?
fun getProperty(name,inherit,includeStyles,includeDefaults): Value?
}
interface Solid{
@ -81,7 +81,7 @@ Solid <--- Composite
interface SolidReference{
val prototype: Solid
fun getPropertyValue(name,inherit,includeStyles,includeDefaults): Value?
fun getProperty(name,inherit,includeStyles,includeDefaults): Value?
}
VisionGroup <---- SolidReference
SolidReferenceGroup -- SolidReference
@ -91,7 +91,7 @@ class SolidReferenceGroup{
var properties: MutableMeta?
val prototype: Solid
val children: Map<NameToken, Vision>
fun getPropertyValue(name,inherit,includeStyles,includeDefaults): Value?
fun getProperty(name,inherit,includeStyles,includeDefaults): Value?
}
VisionBase <-- SolidReferenceGroup
VisionGroup <-- SolidReferenceGroup

View File

@ -1,12 +1,13 @@
kotlin.code.style=official
kotlin.mpp.stability.nowarn=true
kotlin.js.compiler=ir
#kotlin.incremental.js.ir=true
kotlin.jupyter.add.scanner=false
org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G
org.gradle.parallel=true
org.gradle.jvmargs=-Xmx4G
publishing.github=false
publishing.sonatype=false
org.jetbrains.compose.experimental.jscanvas.enabled=true
toolsVersion=0.11.1-kotlin-1.6.10
toolsVersion=0.15.2-kotlin-1.9.21
#kotlin.experimental.tryK2=true
#kscience.wasm.disabled=true

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@ -1,25 +0,0 @@
plugins {
id("ru.mipt.npm.gradle.mpp")
id("org.jetbrains.kotlin.jupyter.api")
}
description = "Common visionforge jupyter module"
kotlin {
sourceSets {
commonMain{
dependencies{
api(projects.visionforgeCore)
}
}
jvmMain {
dependencies {
api(projects.visionforgeServer)
}
}
}
}
readme {
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
}

View File

@ -1,71 +0,0 @@
package space.kscience.visionforge.jupyter
import kotlinx.html.p
import kotlinx.html.stream.createHTML
import kotlinx.html.style
import org.jetbrains.kotlinx.jupyter.api.HTML
import org.jetbrains.kotlinx.jupyter.api.declare
import org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.ContextAware
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.visionforge.Vision
import space.kscience.visionforge.html.*
@DFExperimental
public abstract class JupyterPluginBase(final override val context: Context) : JupyterIntegration(), ContextAware {
protected val handler: VisionForgeForNotebook = VisionForgeForNotebook(context)
protected abstract fun Builder.afterLoaded()
final override fun Builder.onLoaded() {
onLoaded {
declare("VisionForge" to handler, "vf" to handler)
}
onShutdown {
handler.stopServer()
}
import(
"kotlinx.html.*",
"space.kscience.visionforge.html.*"
)
render<HtmlFragment> { fragment ->
handler.produceHtml(fragment = fragment)
}
render<HtmlVisionFragment> { fragment ->
handler.produceHtml(fragment = fragment)
}
render<Vision> { vision ->
handler.produceHtml {
vision { vision }
}
}
render<Page> { page ->
HTML(page.render(createHTML()), true)
}
render<HtmlFormFragment> { fragment ->
handler.produceHtml {
if (!handler.isServerRunning()) {
p {
style = "color: red;"
+"The server is not running. Forms are not interactive. Start server with `VisionForge.startServer()."
}
}
fragment(fragment.formBody)
vision { fragment.vision }
}
}
afterLoaded()
}
}

View File

@ -1,89 +0,0 @@
package space.kscience.visionforge.jupyter
import io.ktor.server.engine.ApplicationEngine
import kotlinx.html.FORM
import kotlinx.html.TagConsumer
import kotlinx.html.p
import kotlinx.html.stream.createHTML
import kotlinx.html.style
import org.jetbrains.kotlinx.jupyter.api.HTML
import org.jetbrains.kotlinx.jupyter.api.MimeTypedResult
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.ContextAware
import space.kscience.dataforge.context.info
import space.kscience.dataforge.context.logger
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.int
import space.kscience.dataforge.meta.string
import space.kscience.visionforge.html.HtmlFormFragment
import space.kscience.visionforge.html.HtmlVisionFragment
import space.kscience.visionforge.html.visionFragment
import space.kscience.visionforge.server.VisionServer
import space.kscience.visionforge.server.serve
import space.kscience.visionforge.visionManager
/**
* A handler class that includes a server and common utilities
*/
public class VisionForgeForNotebook(override val context: Context) : ContextAware {
private var counter = 0
private var engine: ApplicationEngine? = null
private var server: VisionServer? = null
public var isolateFragments: Boolean = false
public fun legacyMode() {
isolateFragments = true
}
public fun isServerRunning(): Boolean = server != null
public fun html(block: TagConsumer<*>.() -> Unit): MimeTypedResult = HTML(createHTML().apply(block).finalize())
public fun startServer(
host: String = context.properties["visionforge.host"].string ?: "localhost",
port: Int = context.properties["visionforge.port"].int ?: VisionServer.DEFAULT_PORT,
configuration: VisionServer.() -> Unit = {},
): MimeTypedResult = html {
if (server != null) {
p {
style = "color: red;"
+"Stopping current VisionForge server"
}
}
engine?.stop(1000, 2000)
engine = context.visionManager.serve(host, port) {
configuration()
server = this
}.start()
p {
style = "color: blue;"
+"Starting VisionForge server on http://$host:$port"
}
}
public fun stopServer() {
engine?.apply {
logger.info { "Stopping VisionForge server" }
}?.stop(1000, 2000)
}
private fun produceHtmlString(
fragment: HtmlVisionFragment,
): String = server?.serveVisionsFromFragment("content[${counter++}]", fragment)
?: createHTML().apply {
visionFragment(context, fragment = fragment)
}.finalize()
public fun produceHtml(isolated: Boolean? = null, fragment: HtmlVisionFragment): MimeTypedResult =
HTML(produceHtmlString(fragment), isolated ?: isolateFragments)
public fun fragment(body: HtmlVisionFragment): MimeTypedResult = produceHtml(fragment = body)
public fun page(body: HtmlVisionFragment): MimeTypedResult = produceHtml(true, body)
public fun form(builder: FORM.() -> Unit): HtmlFormFragment =
HtmlFormFragment("form[${counter++}]", builder = builder)
}

View File

@ -1,32 +0,0 @@
# Module visionforge-jupyter-gdml
Jupyter api artifact for GDML rendering
## Usage
## Artifact:
The Maven coordinates of this project are `space.kscience:visionforge-jupyter-gdml:0.2.0`.
**Gradle Groovy:**
```groovy
repositories {
maven { url 'https://repo.kotlin.link' }
mavenCentral()
}
dependencies {
implementation 'space.kscience:visionforge-jupyter-gdml:0.2.0'
}
```
**Gradle Kotlin DSL:**
```kotlin
repositories {
maven("https://repo.kotlin.link")
mavenCentral()
}
dependencies {
implementation("space.kscience:visionforge-jupyter-gdml:0.2.0")
}
```

View File

@ -1,60 +0,0 @@
plugins {
id("ru.mipt.npm.gradle.mpp")
}
description = "Jupyter api artifact for GDML rendering"
kotlin {
explicitApi = null
js {
useCommonJs()
browser {
webpackTask {
this.outputFileName = "js/gdml-jupyter.js"
}
commonWebpackConfig {
sourceMaps = false
cssSupport.enabled = false
}
}
binaries.executable()
}
afterEvaluate {
val jsBrowserDistribution by tasks.getting
tasks.getByName<ProcessResources>("jvmProcessResources") {
dependsOn(jsBrowserDistribution)
from(jsBrowserDistribution)
}
}
sourceSets {
commonMain {
dependencies {
implementation(projects.visionforgeSolid)
implementation(projects.jupyter)
}
}
jvmMain {
dependencies {
implementation(projects.visionforgeGdml)
}
}
jsMain {
dependencies {
implementation(projects.visionforgeThreejs)
implementation(projects.ui.ring)
}
}
}
}
kscience {
jupyterLibrary("space.kscience.visionforge.gdml.jupyter.GdmlForJupyter")
}
readme {
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
}

View File

@ -1,12 +0,0 @@
package space.kscience.visionforge.gdml.jupyter
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.visionforge.ring.ThreeWithControlsPlugin
import space.kscience.visionforge.runVisionClient
@DFExperimental
@JsExport
fun main(): Unit = runVisionClient {
plugin(ThreeWithControlsPlugin)
}

View File

@ -1,37 +0,0 @@
package space.kscience.visionforge.gdml.jupyter
import org.jetbrains.kotlinx.jupyter.api.libraries.resources
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.gdml.Gdml
import space.kscience.visionforge.gdml.toVision
import space.kscience.visionforge.jupyter.JupyterPluginBase
import space.kscience.visionforge.solid.Solids
@DFExperimental
internal class GdmlForJupyter : JupyterPluginBase(
Context("GDML") {
plugin(Solids)
}
) {
override fun Builder.afterLoaded() {
resources {
js("three") {
classPath("js/gdml-jupyter.js")
}
}
import(
"space.kscience.gdml.*",
"space.kscience.visionforge.gdml.jupyter.*"
)
render<Gdml> { gdmlModel ->
handler.produceHtml {
vision { gdmlModel.toVision() }
}
}
}
}

View File

@ -1,3 +0,0 @@
const ringConfig = require('@jetbrains/ring-ui/webpack.config').config;
config.module.rules.push(...ringConfig.module.rules)

View File

@ -1,7 +1,6 @@
rootProject.name = "visionforge"
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
enableFeaturePreview("VERSION_CATALOGS")
pluginManagement {
@ -12,13 +11,14 @@ pluginManagement {
maven("https://repo.kotlin.link")
mavenCentral()
gradlePluginPortal()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
}
plugins {
id("ru.mipt.npm.gradle.project") version toolsVersion
id("ru.mipt.npm.gradle.mpp") version toolsVersion
id("ru.mipt.npm.gradle.jvm") version toolsVersion
id("ru.mipt.npm.gradle.js") version toolsVersion
id("space.kscience.gradle.project") version toolsVersion
id("space.kscience.gradle.mpp") version toolsVersion
id("space.kscience.gradle.jvm") version toolsVersion
id("space.kscience.gradle.js") version toolsVersion
}
}
@ -33,8 +33,8 @@ dependencyResolutionManagement {
}
versionCatalogs {
create("npmlibs") {
from("ru.mipt.npm:version-catalog:$toolsVersion")
create("spclibs") {
from("space.kscience:version-catalog:$toolsVersion")
}
}
}
@ -45,9 +45,10 @@ include(
":ui:ring",
// ":ui:material",
":ui:bootstrap",
":ui:compose",
":visionforge-core",
":visionforge-solid",
":visionforge-fx",
// ":visionforge-fx",
":visionforge-threejs",
":visionforge-threejs:visionforge-threejs-server",
":visionforge-gdml",
@ -61,8 +62,8 @@ include(
":demo:muon-monitor",
":demo:sat-demo",
":demo:playground",
":demo:plotly-fx",
// ":demo:plotly-fx",
":demo:js-playground",
":jupyter",
":jupyter:visionforge-jupyter-gdml"
":visionforge-jupyter",
":visionforge-jupyter:visionforge-jupyter-common"
)

View File

@ -1,10 +1,12 @@
plugins {
kotlin("js")
id("ru.mipt.npm.gradle.js")
id("space.kscience.gradle.mpp")
}
val dataforgeVersion: String by rootProject.extra
kscience{
js()
jsMain{
dependencies {
api(project(":visionforge-solid"))
api(project(":ui:react"))
@ -13,3 +15,5 @@ dependencies {
implementation(npm("jquery","3.5.1"))
implementation(npm("popper.js","1.16.1"))
}
}
}

View File

@ -1,8 +1,8 @@
package space.kscience.visionforge.bootstrap
public fun useBootstrap(){
kotlinext.js.require("bootstrap/dist/css/bootstrap.min.css")
kotlinext.js.require("bootstrap")
kotlinext.js.require<dynamic>("bootstrap/dist/css/bootstrap.min.css")
kotlinext.js.require<dynamic>("bootstrap")
}
//public inline fun TagConsumer<HTMLElement>.card(title: String, crossinline block: TagConsumer<HTMLElement>.() -> Unit) {

View File

@ -1,10 +1,8 @@
package space.kscience.visionforge.bootstrap
import kotlinx.css.BorderStyle
import kotlinx.css.Color
import kotlinx.css.padding
import kotlinx.css.properties.border
import kotlinx.css.px
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.css.*
import kotlinx.html.js.onClickFunction
import org.w3c.dom.events.Event
import org.w3c.files.Blob
@ -15,7 +13,6 @@ import react.RBuilder
import react.dom.attrs
import react.dom.button
import react.fc
import space.kscience.dataforge.meta.withDefault
import space.kscience.visionforge.Vision
import space.kscience.visionforge.encodeToString
import space.kscience.visionforge.react.flexColumn
@ -28,7 +25,7 @@ private fun saveData(event: Event, fileName: String, mimeType: String = "text/pl
event.stopPropagation();
event.preventDefault();
val fileSaver = kotlinext.js.require("file-saver")
val fileSaver = kotlinext.js.require<dynamic>("file-saver")
val blob = Blob(arrayOf(dataBuilder()), BlobPropertyBag("$mimeType;charset=utf-8"))
fileSaver.saveAs(blob, fileName)
}
@ -47,12 +44,13 @@ public external interface CanvasControlsProps : Props {
public var vision: Vision?
}
public val CanvasControls: FC<CanvasControlsProps> = fc("CanvasControls") { props ->
flexColumn {
flexRow {
css {
border(1.px, BorderStyle.solid, Color.blue)
padding(4.px)
border = Border(1.px, BorderStyle.solid, Color.blue)
padding = Padding(4.px)
}
props.vision?.let { vision ->
button {
@ -68,9 +66,10 @@ public val CanvasControls: FC<CanvasControlsProps> = fc("CanvasControls") { prop
}
}
}
@OptIn(DelicateCoroutinesApi::class)
propertyEditor(
ownProperties = props.canvasOptions.meta,
allProperties = props.canvasOptions.meta.withDefault(Canvas3DOptions.descriptor.defaultNode),
scope = props.vision?.manager?.context ?: GlobalScope,
properties = props.canvasOptions.meta,
descriptor = Canvas3DOptions.descriptor,
expanded = false
)

View File

@ -30,7 +30,7 @@ public external interface TabPaneProps : PropsWithChildren {
public val TabPane: FC<TabPaneProps> = fc("TabPane") { props ->
var activeTab: String? by useState(props.activeTab)
val children: Array<out ReactElement?> = Children.map(props.children) {
val children: Array<out ReactElement<*>?> = Children.map(props.children) {
it.asElementOrNull()
} ?: emptyArray()

View File

@ -1,7 +1,6 @@
package space.kscience.visionforge.bootstrap
import kotlinx.css.*
import kotlinx.css.properties.border
import react.FC
import react.PropsWithChildren
import react.RBuilder
@ -10,8 +9,8 @@ import react.fc
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.isEmpty
import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionGroup
import space.kscience.visionforge.react.visionTree
import space.kscience.visionforge.solid.SolidGroup
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
import styled.css
import styled.styledDiv
@ -33,13 +32,13 @@ public val ThreeControls: FC<ThreeControlsProps> = fc { props ->
}
tab("Tree") {
css {
border(1.px, BorderStyle.solid, Color.lightGray)
padding(10.px)
border = Border(1.px, BorderStyle.solid, Color.lightGray)
padding = Padding(10.px)
}
h2 { +"Object tree" }
styledDiv {
css {
flex(1.0, 1.0, FlexBasis.inherit)
flex = Flex(1.0, 1.0, FlexBasis.inherit)
}
props.vision?.let {
visionTree(it, props.selected, props.onSelect)
@ -51,7 +50,7 @@ public val ThreeControls: FC<ThreeControlsProps> = fc { props ->
val selectedObject: Vision? = when {
selected == null -> null
selected.isEmpty() -> props.vision
else -> (props.vision as? VisionGroup)?.get(selected)
else -> (props.vision as? SolidGroup)?.get(selected)
}
if (selectedObject != null) {
visionPropertyEditor(selectedObject, key = selected)

View File

@ -2,13 +2,15 @@ package space.kscience.visionforge.bootstrap
import org.w3c.dom.Element
import react.RBuilder
import react.dom.render
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.isEmpty
import space.kscience.visionforge.Vision
import space.kscience.visionforge.computeProperties
import space.kscience.visionforge.getStyle
import space.kscience.visionforge.react.EditorPropertyState
import space.kscience.visionforge.react.PropertyEditor
import space.kscience.visionforge.react.metaViewer
import space.kscience.visionforge.react.propertyEditor
import space.kscience.visionforge.react.render
import space.kscience.visionforge.root
import space.kscience.visionforge.solid.SolidReference
import space.kscience.visionforge.styles
@ -19,12 +21,26 @@ public fun RBuilder.visionPropertyEditor(
) {
card("Properties") {
propertyEditor(
ownProperties = vision.meta,
allProperties = vision.computeProperties(),
descriptor = descriptor,
key = key
)
child(PropertyEditor) {
attrs {
this.key = key?.toString()
this.meta = vision.properties.root()
this.updates = vision.properties.changes
this.descriptor = descriptor
this.scope = vision.manager?.context ?: error("Orphan vision could not be observed")
this.getPropertyState = { name ->
val ownMeta = vision.properties.own?.get(name)
if (ownMeta != null && !ownMeta.isEmpty()) {
EditorPropertyState.Defined
} else if (vision.properties.root().getValue(name) != null) {
// TODO differentiate
EditorPropertyState.Default()
} else {
EditorPropertyState.Undefined
}
}
}
}
}
val styles = if (vision is SolidReference) {
(vision.styles + vision.prototype.styles).distinct()
@ -50,6 +66,6 @@ public fun RBuilder.visionPropertyEditor(
public fun Element.visionPropertyEditor(
item: Vision,
descriptor: MetaDescriptor? = item.descriptor,
): Unit = render(this) {
): Unit = space.kscience.visionforge.react.createRoot(this).render {
visionPropertyEditor(item, descriptor = descriptor)
}

Some files were not shown because too many files have changed in this diff Show More