Compare commits

...

60 Commits

Author SHA1 Message Date
25c3a19eed Fix demo package name to ensure proper package resolution 2023-06-27 20:30:29 +03:00
ea9d37b9a1 1.9.0-RC 2023-06-22 20:33:23 +03:00
a695e5e7c9 Use K2 2023-06-06 09:52:46 +03:00
140c59497e Change all Js modules to MPP 2023-06-02 20:58:32 +03:00
23cb8765b6 Minor fixes 2023-06-02 14:33:41 +03:00
a872f10523 Minor fixes 2023-05-30 20:04:23 +03:00
be52551564 Minor fixes 2023-05-30 19:37:03 +03:00
c4b866f5b5 Fix markup plugin. 2023-05-30 17:55:35 +03:00
d32dc3fa08 Fix markup plugin tag 2023-05-30 17:38:40 +03:00
18c39fc076 Add solids configuration to vision builder 2023-05-30 17:06:27 +03:00
f6f74b54f6 Fix cone segmenta and cone surface representation 2023-05-30 13:56:14 +03:00
33778801b6 Multiple fixes 2023-05-29 21:38:30 +03:00
c48e5aac25 build update and minor API changes 2023-05-29 09:53:56 +03:00
c921d5541b Cleanup and fix ROOT bug 2023-05-16 21:12:24 +03:00
4ec611eda3 Update versions 2023-05-14 18:33:30 +03:00
35fc7a7042 Update threejs server 2023-01-17 19:20:48 +03:00
2bdaea2e82 Update dependencies and compatibility 2023-01-17 18:50:19 +03:00
d28873e796
Refactor server API 2022-12-06 17:04:13 +03:00
fef1df3ab4
Refactor server API 2022-12-06 15:54:34 +03:00
fd8f693151
Refactor server API 2022-12-03 14:51:32 +03:00
c8141c6338
Refactor server API 2022-12-03 13:53:34 +03:00
20b20a621f
Refactor server API 2022-12-02 22:38:37 +03:00
d6c974fcbc
Fix loading duplicating plugins in visionServer 2022-11-23 13:41:36 +03:00
4ceffef67a
Update connection logic 2022-11-21 13:28:39 +03:00
279b848039
Add demo notebook 2022-11-20 20:35:36 +03:00
b2624cb10b
Fix API 2022-11-20 20:28:16 +03:00
eae1316de5
Update static/dynamic rendering logic 2022-11-20 19:42:05 +03:00
3c51060e2e
Refactor pages 2022-11-17 21:49:14 +03:00
960d17855b
Fix client updates 2022-08-25 22:48:00 +03:00
81aa5d2fcc
Replace plot properties by a wrapper 2022-08-24 22:46:27 +03:00
f0a6e12358
Fix light for GDML and ambient lighg updates 2022-08-24 09:59:10 +03:00
56d577453a
Fix edges for composite 2022-08-24 09:19:13 +03:00
25fc143363
Performance optimization 2022-08-23 12:06:27 +03:00
75540a078f
Add quaternion support 2022-08-21 17:21:36 +03:00
40b784f551
More universal treatment of highlighting in three 2022-08-19 11:22:10 +03:00
67afa4e45b
Fix light 2022-08-15 09:47:56 +03:00
cb25dca34c
Refactor three package. Add MeshLine 2022-08-14 22:03:46 +03:00
98bb935de5
Optimizations... optimizations 2022-08-14 20:28:47 +03:00
e2f281debe
Optimizations... optimizations 2022-08-14 17:22:10 +03:00
ac651c4d50
Fix reference property resolution 2022-08-14 14:41:22 +03:00
846e87a44b
Fix flaky properties test 2022-08-14 14:25:44 +03:00
34fbb23c60
Cleanup vision root rules 2022-08-14 12:52:18 +03:00
eeec89f0e6
Fix property editor 2022-08-14 10:47:36 +03:00
43362f51f5
Fix styling for Prototypes 2022-08-13 20:47:03 +03:00
c586a2ea14
Fix (almost) property resolution 2022-08-13 18:17:22 +03:00
ecf4a6a198
Add property flows 2022-08-13 12:45:10 +03:00
0ea1ee056a
All tests pass 2022-08-12 22:16:06 +03:00
9221df785d
[WIP] Completed solid refactoring 2022-08-09 14:53:46 +03:00
47bde02488
[WIP] Completed solid refactoring 2022-08-09 12:49:01 +03:00
c71042ae06
[WIP] great refactoring in progress 2022-08-08 22:17:06 +03:00
9b1ca8332b
[WIP] great refactoring in progress 2022-08-07 20:33:05 +03:00
791d6d7a81
[WIP] great refactoring in progress 2022-08-04 21:36:00 +03:00
4b1149b99b
Migrate to new build tools and DF 0.6 2022-07-06 11:11:48 +03:00
86935ce52a
Fix light in GDML demo 2022-05-24 23:09:40 +03:00
ce02a18c09
Fix mesh conversion and lightning for examples 2022-05-24 23:00:10 +03:00
212d729afb
A prototype for context receivers 2022-04-15 12:46:05 +03:00
3198bad094
Update build. 2022-04-13 17:08:25 +03:00
9648533ac8
Update build tools 2022-04-13 15:02:35 +03:00
7ee40679b9
Update light descriptor 2022-01-28 14:17:37 +03:00
f828f86e29
Replace light model for 3ds 2022-01-27 12:10:00 +03:00
417 changed files with 6079 additions and 13489 deletions

2
.gitignore vendored
View File

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

View File

@ -2,8 +2,18 @@
## [Unreleased]
### Added
- Context receivers flag
- MeshLine for thick lines
### Changed
- 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

View File

@ -1,29 +1,58 @@
import org.jetbrains.kotlin.gradle.dsl.KotlinJsCompile
import space.kscience.gradle.isInDevelopment
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.6.1")
val fxVersion by extra("11")
allprojects{
allprojects {
group = "space.kscience"
version = "0.2.0"
version = "0.3.0-dev-9"
}
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()
}
github(githubProject = "visionforge", githubOrg = "SciProgCentre")
space(
if (isInDevelopment) {
"https://maven.pkg.jetbrains.space/spc/p/sci/dev"
} else {
"https://maven.pkg.jetbrains.space/spc/p/sci/maven"
}
)
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

@ -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(

View File

@ -2,9 +2,11 @@ package ru.mipt.npm.root
import space.kscience.dataforge.meta.*
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.visionforge.MutableVisionContainer
import space.kscience.visionforge.isEmpty
import space.kscience.visionforge.set
import space.kscience.visionforge.solid.*
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY
import kotlin.math.*
@ -20,7 +22,9 @@ 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
@ -42,14 +46,17 @@ private fun Solid.useMatrix(matrix: DGeoMatrix?) {
"TGeoIdentity" -> {
//do nothing
}
"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()
@ -58,6 +65,7 @@ private fun Solid.useMatrix(matrix: DGeoMatrix?) {
rotate(it.doubleArray)
}
}
"TGeoHMatrix" -> {
val fTranslation by matrix.meta.doubleArray()
val fRotationMatrix by matrix.meta.doubleArray()
@ -73,7 +81,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" -> {
@ -94,6 +102,7 @@ private fun SolidGroup.addShape(
}
}.apply(block)
}
"TGeoXtru" -> {
val fNvert by shape.meta.int(0)
val fX by shape.meta.doubleArray()
@ -121,6 +130,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 +144,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 +162,7 @@ private fun SolidGroup.addShape(
block = block
)
}
"TGeoPcon" -> {
val fDphi by shape.meta.double(0.0)
val fNz by shape.meta.int(2)
@ -176,6 +188,7 @@ private fun SolidGroup.addShape(
TODO()
}
}
"TGeoPgon" -> {
//TODO add a inner polygone layer
val fDphi by shape.meta.double(0.0)
@ -206,15 +219,18 @@ private fun SolidGroup.addShape(
}
}.apply(block)
}
"TGeoShapeAssembly" -> {
val fVolume by shape.dObject(::DGeoVolume)
fVolume?.let { volume ->
addRootVolume(volume, context, 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)
@ -242,17 +258,19 @@ private fun SolidGroup.addShape(
val node8 = Point3D(-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) }) {
solidGroup(name?.let { Name.parse(it) }) {
scale = Point3D(fScale?.x ?: 1.0, fScale?.y ?: 1.0, fScale?.z ?: 1.0)
addShape(scaledShape, context)
apply(block)
}
}
}
else -> {
TODO("A shape with type ${shape.typename} not implemented")
}
@ -267,6 +285,7 @@ private fun SolidGroup.addRootNode(obj: DGeoNode, context: RootToSolidContext) {
val fMatrix by obj.dObject(::DGeoMatrix)
this.useMatrix(fMatrix)
}
"TGeoNodeOffset" -> {
val fOffset by obj.meta.double(0.0)
x = fOffset
@ -276,12 +295,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 +320,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.set(context.colorCache.getOrPut(medium.meta) { RootColors[11 + context.colorCache.size] })
}
if (!context.ignoreRootColors) {
volume.fFillColor?.let {
properties[MATERIAL_COLOR_KEY] = RootColors[it]
}
}
}
}
@ -317,8 +346,9 @@ 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) {
@ -328,35 +358,30 @@ private fun SolidGroup.addRootVolume(
}
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)
setChild(combinedName?.let { Name.parse(it) }, group)
} else {
val templateName = volumesName + volume.name
val existing = getPrototype(templateName)
if (existing == null) {
context.prototypeHolder.prototypes {
val group = buildVolume(volume, context)
set(templateName, group)
setChild(templateName, group)
}
}
ref(templateName, name).apply {
volume.fFillColor?.let {
meta[MATERIAL_COLOR_KEY] = RootColors[it]
}
block()
}
ref(templateName, name).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

@ -14,7 +14,7 @@ import kotlinx.serialization.modules.subclass
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 +46,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
@ -90,9 +91,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 +118,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 +136,7 @@ private object RootDecoder {
val unrefed = TGeoMatrix.serializer().unref(refCache)
default {
defaultDeserializer {
if (it == null) {
unrefed
} else {
@ -149,7 +149,7 @@ private object RootDecoder {
subclass(TGeoVolumeAssembly.serializer().unref(refCache))
val unrefed = TGeoVolume.serializer().unref(refCache)
default {
defaultDeserializer {
if (it == null) {
unrefed
} else {
@ -163,7 +163,7 @@ private object RootDecoder {
subclass(TGeoNodeOffset.serializer().unref(refCache))
val unrefed = TGeoNode.serializer().unref(refCache)
default {
defaultDeserializer {
if (it == null) {
unrefed
} else {
@ -197,11 +197,13 @@ private object RootDecoder {
fillCache(it)
}
}
is JsonArray -> {
element.forEach {
fillCache(it)
}
}
else -> {
//ignore primitives
}
@ -216,6 +218,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
@ -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"))
}
}
jvmMain {
dependencies {
implementation(project(":visionforge-fx"))
implementation("ch.qos.logback:logback-classic:1.2.5")
}
}
jsMain {
dependencies {
implementation(project(":ui:ring"))
implementation(project(":visionforge-threejs"))
implementation(npm("react-file-drop", "3.0.6"))
}
}
dependencies {
implementation(projects.visionforgeSolid)
implementation(projects.visionforgeGdml)
}
jvmMain {
// implementation(project(":visionforge-fx"))
implementation(spclibs.logback.classic)
}
jsMain {
implementation(projects.ui.ring)
implementation(projects.visionforgeThreejs)
implementation(npm("react-file-drop", "3.0.6"))
}
}
application {
mainClass.set("space.kscience.visionforge.gdml.demo.GdmlFxDemoAppKt")
kotlin {
explicitApi = null
}
val convertGdmlToJson by tasks.creating(JavaExec::class) {
group = "application"
classpath = sourceSets["main"].runtimeClasspath
mainClass.set("space.kscience.dataforge.vis.spatial.gdml.demo.SaveToJsonKt")
}
//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")
//}

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.getProperty(SolidMaterial.MATERIAL_COLOR_KEY).string)
}
}

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.set
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.set(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.set
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.set(Colors.white)
}
}
//println(context.plugins.fetch(VisionManager).encodeToString(vision))
attrs {
this.context = context
this.solids = context.request(Solids)
this.vision = vision
}
}

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,18 +1,20 @@
plugins {
id("ru.mipt.npm.gradle.js")
id("space.kscience.gradle.js")
}
kscience{
useCoroutines()
application()
}
kotlin{
js(IR){
useCommonJs()
browser {
binaries.executable()
commonWebpackConfig {
cssSupport.enabled = false
cssSupport{
enabled.set(false)
}
}
}
}

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.Colors
import space.kscience.visionforge.VisionClient
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,7 +30,7 @@ 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)
@ -38,7 +40,7 @@ private class JsPlaygroundApp : Application {
val element = document.getElementById("playground") ?: error("Element with id 'playground' not found on page")
render(element) {
createRoot(element).render {
styledDiv {
css {
padding(0.pt)
@ -48,9 +50,9 @@ private class JsPlaygroundApp : Application {
}
SmartTabs("gravity") {
Tab("gravity") {
GravityDemo{
GravityDemo {
attrs {
this.context = playgroundContext
this.solids = playgroundContext.request(Solids)
}
}
}
@ -71,15 +73,18 @@ private class JsPlaygroundApp : Application {
child(ThreeCanvasWithControls) {
val random = Random(112233)
attrs {
context = playgroundContext
solids = playgroundContext.request(Solids)
solid {
ambientLight {
color.set(Colors.white)
}
repeat(100) {
sphere(5, name = "sphere[$it]") {
x = random.nextDouble(-300.0, 300.0)
y = random.nextDouble(-300.0, 300.0)
z = random.nextDouble(-300.0, 300.0)
material {
color(random.nextInt())
color.set(random.nextInt())
}
detail = 16
}

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,14 +17,14 @@ import styled.styledDiv
import kotlin.math.sqrt
external interface DemoProps : Props {
var context: Context
var solids: Solids
}
val GravityDemo = fc<DemoProps> { props ->
val velocityTrace = Trace{
val velocityTrace = Trace {
name = "velocity"
}
val energyTrace = Trace{
val energyTrace = Trace {
name = "energy"
}
val markup = VisionOfMarkup()
@ -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.set(Colors.white)
}
ambientLight()
sphere(5.0, "ball") {
detail = 16
color("red")
color.set("red")
val h = 100.0
y = h
context.launch {
solids.context.launch {
val g = 10.0
val dt = 0.1
var time = 0.0
@ -91,7 +96,7 @@ val GravityDemo = fc<DemoProps> { props ->
height = 50.vh - 50.pt
}
plotly {
traces(velocityTrace,energyTrace)
traces(velocityTrace, energyTrace)
layout {
xaxis.title = "time"
}

View File

@ -20,9 +20,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)
}
}

View File

@ -1,61 +1,42 @@
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 {
commonWebpackConfig {
cssSupport.enabled = false
useKtor()
fullStack(
"muon-monitor.js",
jvmConfig = { withJava() },
jsConfig = { useCommonJs() }
) {
commonWebpackConfig {
cssSupport {
enabled.set(false)
}
}
}
afterEvaluate {
val jsBrowserDistribution by tasks.getting
tasks.getByName<ProcessResources>("jvmProcessResources") {
dependsOn(jsBrowserDistribution)
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
from(jsBrowserDistribution)
}
commonMain {
implementation(projects.visionforgeSolid)
}
sourceSets {
commonMain {
dependencies {
implementation(project(":visionforge-solid"))
}
}
jvmMain {
dependencies {
implementation("org.apache.commons:commons-math3:3.6.1")
implementation(npmlibs.ktor.server.cio)
implementation(npmlibs.ktor.serialization)
}
}
jsMain {
dependencies {
implementation(project(":ui:ring"))
implementation(project(":visionforge-threejs"))
//implementation(devNpm("webpack-bundle-analyzer", "4.4.0"))
}
}
jvmMain {
implementation("org.apache.commons:commons-math3:3.6.1")
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 {
implementation(projects.ui.ring)
implementation(projects.visionforgeThreejs)
//implementation(devNpm("webpack-bundle-analyzer", "4.4.0"))
}
}
@ -63,6 +44,7 @@ application {
mainClass.set("ru.mipt.npm.muon.monitor.server.MMServerKt")
}
//distributions {
// main {
// contents {

View File

@ -3,19 +3,19 @@ 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.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) {
private fun MutableVisionContainer<Solid>.pixel(pixel: SC1) {
val group = solidGroup(pixel.name) {
position = Point3D(pixel.center.x, pixel.center.y, pixel.center.z)
box(pixel.xSize, pixel.ySize, pixel.zSize)
label(pixel.name) {
@ -27,7 +27,7 @@ class Model(val manager: VisionManager) {
}
private fun SolidGroup.detector(detector: SC16) {
group(detector.name) {
solidGroup(detector.name) {
detector.pixels.forEach {
pixel(it)
}
@ -39,40 +39,39 @@ class Model(val manager: VisionManager) {
val root: SolidGroup = SolidGroup().apply {
setAsRoot(this@Model.manager)
material {
wireframe
color("darkgreen")
color.set("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")
tracks = solidGroup("tracks")
}
private fun highlight(pixel: String) {
println("highlight $pixel")
map[pixel]?.color?.invoke("blue")
map[pixel]?.color.set("blue")
}
fun reset() {
map.values.forEach {
it.setProperty(SolidMaterial.MATERIAL_COLOR_KEY, null)
it.properties.setProperty(SolidMaterial.MATERIAL_COLOR_KEY, null)
}
tracks.removeAll()
tracks.children.clear()
}
fun displayEvent(event: Event) {
@ -83,8 +82,7 @@ class Model(val manager: VisionManager) {
}
event.track?.let {
tracks.polyline(*it.toTypedArray(), name = "track[${event.id}]") {
thickness = 4
color("red")
color.set("red")
}
}
}

View File

@ -11,12 +11,12 @@ import space.kscience.visionforge.solid.plus
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 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: Point3D,
) {
/**
@ -28,73 +28,86 @@ 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 pixelName = "${name}_${index}"
@ -137,7 +150,7 @@ 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()

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.set
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.set(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,29 @@
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.resources
import io.ktor.server.http.content.static
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 +36,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()
}

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"
outputFileName = "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 {
@ -64,7 +67,7 @@ kotlin {
val jvmMain by getting {
dependencies {
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")
}
}
@ -87,4 +90,8 @@ val processJupyterApiResources by tasks.getting(org.jetbrains.kotlinx.jupyter.ap
libraryProducers = listOf("space.kscience.visionforge.examples.VisionForgePlayGroundForJupyter")
}
tasks.findByName("shadowJar")?.dependsOn(processJupyterApiResources)
tasks.findByName("shadowJar")?.dependsOn(processJupyterApiResources)
//application{
// mainClass.set("space.kscience.visionforge.examples.ShapesKt")
//}

View File

@ -0,0 +1,130 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"tags": [],
"pycharm": {
"is_executing": true
},
"ExecuteTime": {
"end_time": "2023-05-29T15:22:37.933397300Z",
"start_time": "2023-05-29T15:22:37.913872100Z"
}
},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"ExecuteTime": {
"end_time": "2023-05-29T15:22:50.486483300Z",
"start_time": "2023-05-29T15:22:50.457485500Z"
}
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Line_2.jupyter.kts (1:1 - 3) Unresolved reference: vf"
]
}
],
"source": [
"vf.startServer()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
},
"ExecuteTime": {
"end_time": "2023-05-29T15:22:51.410680600Z",
"start_time": "2023-05-29T15:22:51.250779400Z"
}
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Line_3.jupyter.kts (1:16 - 26) Unresolved reference: coroutines\n",
"Line_3.jupyter.kts (4:1 - 7) Unresolved reference: Plotly\n",
"Line_3.jupyter.kts (5:5 - 12) Unresolved reference: scatter\n",
"Line_3.jupyter.kts (6:9 - 10) Unresolved reference: x\n",
"Line_3.jupyter.kts (7:9 - 10) Unresolved reference: y\n",
"Line_3.jupyter.kts (8:12 - 14) Unresolved reference: vf\n",
"Line_3.jupyter.kts (9:13 - 15) Unresolved reference: vf\n",
"Line_3.jupyter.kts (10:23 - 31) Unresolved reference: isActive\n",
"Line_3.jupyter.kts (11:21 - 26) Unresolved reference: delay\n",
"Line_3.jupyter.kts (12:21 - 22) Unresolved reference: y"
]
}
],
"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": {
"isAddProjectLibrariesToClasspath": false
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -1,4 +1,5 @@
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.visionforge.jupyter.VFNotebookPlugin
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(VFNotebookPlugin)
}

View File

@ -6,17 +6,18 @@ 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.jupyter.VFIntegrationBase
import space.kscience.visionforge.plotly.PlotlyPlugin
import space.kscience.visionforge.plotly.asVision
import space.kscience.visionforge.solid.Solids
import space.kscience.visionforge.visionManager
@DFExperimental
internal class VisionForgePlayGroundForJupyter : JupyterPluginBase(
internal class VisionForgePlayGroundForJupyter : VFIntegrationBase(
Context("VisionForge") {
plugin(Solids)
plugin(PlotlyPlugin)
}
}.visionManager
) {
override fun Builder.afterLoaded() {

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,8 +34,15 @@ fun main() = makeVisionFile(
h2 { +"3D visualization with Three-js" }
vision("3D") {
solid {
box(100, 100, 100, name = "aBox"){
solid(
Canvas3DOptions {
axes {
size = 200.0
visible = true
}
}
) {
box(100, 100, 100, name = "aBox") {
z = 50.0
}
}

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,13 +67,11 @@ fun main() {
value = "Submit"
}
}
vision("form") { form }
form.onPropertyChange {
println(this)
}
println(form.values)
vision(form)
}
}
}.start(false)
server.openInBrowser()

View File

@ -5,7 +5,7 @@ import space.kscience.visionforge.gdml.toVision
import space.kscience.visionforge.html.ResourceLocation
import space.kscience.visionforge.solid.Solids
fun main() = makeVisionFile(resourceLocation = ResourceLocation.SYSTEM){
fun main() = makeVisionFile(resourceLocation = ResourceLocation.SYSTEM) {
vision("canvas") {
requirePlugin(Solids)
GdmlShowCase.cubes().toVision()

View File

@ -7,7 +7,7 @@ import space.kscience.visionforge.gdml.toVision
import space.kscience.visionforge.html.ResourceLocation
import space.kscience.visionforge.solid.Solids
import space.kscience.visionforge.solid.color
import space.kscience.visionforge.solid.invoke
import space.kscience.visionforge.solid.set
import space.kscience.visionforge.visible
import java.nio.file.Path
@ -223,13 +223,13 @@ 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
}
if(solid.name.startsWith("gas")){
color("green")
color.set("green")
} else {
//make all solids semi-transparent
transparent()

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,13 +18,16 @@ fun main() = makeVisionFile(
div {
vision {
solid {
ambientLight {
color.set(Colors.white)
}
repeat(100) {
sphere(5, name = "sphere[$it]") {
x = random.nextDouble(-300.0, 300.0)
y = random.nextDouble(-300.0, 300.0)
z = random.nextDouble(-300.0, 300.0)
material {
color(random.nextInt())
color.set(random.nextInt())
}
detail = 16
}

View File

@ -1,15 +1,20 @@
package space.kscience.visionforge.examples
import ru.mipt.npm.root.DGeoManager
import ru.mipt.npm.root.rootGeo
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.dataforge.meta.string
import space.kscience.visionforge.Colors
import space.kscience.visionforge.html.ResourceLocation
import space.kscience.visionforge.solid.Solids
import java.nio.file.Paths
import space.kscience.visionforge.solid.ambientLight
import space.kscience.visionforge.solid.set
import space.kscience.visionforge.solid.solid
import java.util.zip.ZipInputStream
import kotlin.io.path.Path
import kotlin.io.path.writeText
@ -34,73 +39,17 @@ fun main() {
println(it)
}
val solid = geo.toSolid()
Paths.get("BM@N.vf.json").writeText(Solids.encodeToString(solid))
//println(Solids.encodeToString(solid))
makeVisionFile {
makeVisionFile(path = Path("data/output.html"), resourceLocation = ResourceLocation.EMBED) {
vision("canvas") {
requirePlugin(Solids)
solid
solid {
ambientLight {
color.set(Colors.white)
}
rootGeo(geo,"BM@N", maxLayer = 3, ignoreRootColors = true).also {
Path("data/BM@N.vf.json").writeText(Solids.encodeToString(it))
}
}
}
}
}
/* 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,11 +1,8 @@
package space.kscience.visionforge.examples
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.visionManager
import java.awt.Desktop
import java.nio.file.Path
@ -16,10 +13,14 @@ 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())

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.set("teal")
}
sphere(50.0) {
x = 110
detail = 16
color.set("red")
}
tube(50, height = 10, innerRadius = 25, angle = PI) {
y = 110
detail = 16
rotationX = PI / 4
color.set("blue")
}
sphereLayer(50, 40, theta = PI / 2) {
rotationX = -PI * 3 / 4
z = 110
color.set(Colors.pink)
}
cylinder(30,20, name = "cylinder"){
detail = 31
y = -220
z = 15
}
}
}
}

View File

@ -2,8 +2,8 @@ package space.kscience.visionforge.examples
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.set
import space.kscience.visionforge.solid.solid
fun main() = makeVisionFile(resourceLocation = ResourceLocation.SYSTEM) {
@ -11,7 +11,7 @@ fun main() = makeVisionFile(resourceLocation = ResourceLocation.SYSTEM) {
solid {
box(100, 100, 100)
material {
emissiveColor("red")
emissiveColor.set("red")
}
}
}

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

View File

@ -1,5 +1,5 @@
plugins {
id("ru.mipt.npm.gradle.jvm")
id("space.kscience.gradle.jvm")
application
}
@ -8,16 +8,14 @@ kscience {
// useSerialization {
// json()
// }
application()
dependencies{
implementation(projects.visionforgeThreejs.visionforgeThreejsServer)
implementation("ch.qos.logback:logback-classic:1.4.5")
}
}
group = "ru.mipt.npm"
dependencies{
implementation(project(":visionforge-threejs:visionforge-threejs-server"))
implementation("ch.qos.logback:logback-classic:1.2.3")
}
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,8 +14,8 @@ internal fun visionOfSatellite(
xSegmentSize: Number = 30,
ySegmentSize: Number = xSegmentSize,
fiberDiameter: Number = 1.0,
): SolidGroup = SolidGroup {
color("darkgreen")
): SolidGroup = solidGroup {
color.set("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.set(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()
@ -44,9 +63,10 @@ fun main() {
val randomJ = Random.nextInt(1, 4)
val target = Name.parse("layer[$randomLayer].segment[$randomI,$randomJ]")
val targetVision = sat[target] as Solid
targetVision.color("red")
targetVision.color.set("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.material
import space.kscience.visionforge.solid.set
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.set("red")
}
}
}
}

View File

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

@ -18,7 +18,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.set(Colors.white)
}
}
render(Name.parse(name), vision, meta)
}
@ -39,30 +44,31 @@ 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")
color.set("teal")
}
sphere(50.0) {
x = 110
detail = 16
color("red")
color.set("red")
}
tube(50, height = 10, innerRadius = 25, angle = PI) {
y = 110
detail = 16
rotationX = PI / 4
color("blue")
color.set("blue")
}
sphereLayer(50, 40, theta = PI / 2) {
rotationX = -PI * 3 / 4
z = 110
color(Colors.pink)
color.set(Colors.pink)
}
}
demo("dynamic", "Dynamic properties") {
val group = group {
val group = solidGroup {
box(100, 100, 100) {
z = 110.0
opacity = 0.5
@ -72,7 +78,7 @@ fun VisionLayout<Solid>.showcase() {
visible = false
x = 110.0
//override color for this cube
color(1530)
color.set(1530)
GlobalScope.launch(Dispatchers.Main) {
while (isActive) {
@ -87,19 +93,19 @@ fun VisionLayout<Solid>.showcase() {
val random = Random(111)
while (isActive) {
delay(1000)
group.color(random.nextInt(0, Int.MAX_VALUE))
group.color.set(random.nextInt(0, Int.MAX_VALUE))
}
}
}
demo("rotation", "Rotations") {
box(100, 100, 100)
group {
solidGroup {
x = 200
rotationY = PI / 4
box(100, 100, 100) {
rotationZ = PI / 4
color(Colors.red)
color.set(Colors.red)
}
}
}
@ -112,7 +118,7 @@ fun VisionLayout<Solid>.showcase() {
for (i in 0..100) {
layer(i * 5, 20 * sin(2 * PI / 100 * i), 20 * cos(2 * PI / 100 * i))
}
color(Colors.teal)
color.set(Colors.teal)
rotationX = -PI / 2
}
}
@ -121,13 +127,13 @@ fun VisionLayout<Solid>.showcase() {
sphere(100) {
detail = 32
opacity = 0.4
color(Colors.blue)
color.set(Colors.blue)
}
repeat(20) {
polyline(Point3D(100, 100, 100), Point3D(-100, -100, -100)) {
thickness = 3.0
rotationX = it * PI2 / 20
color(Colors.green)
color.set(Colors.green)
//rotationY = it * PI2 / 20
}
}
@ -154,7 +160,7 @@ fun VisionLayout<Solid>.showcaseCSG() {
detail = 32
}
material {
color(Colors.pink)
color.set(Colors.pink)
}
}
composite(CompositeType.UNION) {
@ -164,7 +170,7 @@ fun VisionLayout<Solid>.showcaseCSG() {
sphere(50) {
detail = 32
}
color("lightgreen")
color.set("lightgreen")
opacity = 0.7
}
composite(CompositeType.SUBTRACT) {
@ -175,7 +181,7 @@ fun VisionLayout<Solid>.showcaseCSG() {
sphere(50) {
detail = 32
}
color("teal")
color.set("teal")
opacity = 0.7
}
}
@ -186,7 +192,7 @@ fun VisionLayout<Solid>.showcaseCSG() {
detail = 32
}
box(100, 100, 100)
color("red")
color.set("red")
opacity = 0.5
}
}

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,7 +21,7 @@ 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() {
@ -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.14.9-kotlin-1.9.0-RC-dev-1
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.1.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

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

View File

@ -0,0 +1,48 @@
package space.kscience.visionforge.jupyter
import kotlinx.browser.window
import org.w3c.dom.Element
import space.kscience.dataforge.context.AbstractPlugin
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.PluginFactory
import space.kscience.dataforge.context.PluginTag
import space.kscience.dataforge.meta.Meta
import space.kscience.visionforge.VisionClient
import space.kscience.visionforge.renderAllVisions
import space.kscience.visionforge.renderAllVisionsById
import space.kscience.visionforge.renderAllVisionsIn
@JsExport
public class VFNotebookPlugin : AbstractPlugin() {
private val client by require(VisionClient)
public fun renderAllVisionsIn(element: Element) {
client.renderAllVisionsIn(element)
}
public fun renderAllVisionsById(id: String) {
client.renderAllVisionsById(id)
}
public fun renderAllVisions() {
client.renderAllVisions()
}
init {
//register VisionForge in the browser window
window.asDynamic().vf = this
window.asDynamic().VisionForge = this
}
@Suppress("NON_EXPORTABLE_TYPE")
override val tag: PluginTag get() = Companion.tag
@Suppress("NON_EXPORTABLE_TYPE")
public companion object : PluginFactory<VFNotebookPlugin> {
override fun build(context: Context, meta: Meta): VFNotebookPlugin = VFNotebookPlugin()
override val tag: PluginTag = PluginTag(name = "vision.notebook", group = PluginTag.DATAFORGE_GROUP)
}
}

View File

@ -0,0 +1,144 @@
package space.kscience.visionforge.jupyter
import io.ktor.http.URLProtocol
import io.ktor.server.application.install
import io.ktor.server.cio.CIO
import io.ktor.server.engine.ApplicationEngine
import io.ktor.server.engine.embeddedServer
import io.ktor.server.util.url
import io.ktor.server.websocket.WebSockets
import kotlinx.coroutines.CoroutineScope
import kotlinx.html.*
import kotlinx.html.stream.createHTML
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.dataforge.names.Name
import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionManager
import space.kscience.visionforge.html.HtmlVisionFragment
import space.kscience.visionforge.html.visionFragment
import space.kscience.visionforge.server.VisionRoute
import space.kscience.visionforge.server.serveVisionData
import space.kscience.visionforge.visionManager
import kotlin.coroutines.CoroutineContext
import kotlin.random.Random
import kotlin.random.nextUInt
internal fun TagConsumer<*>.renderScriptForId(id: String) {
script {
type = "text/javascript"
unsafe { +"VisionForge.renderAllVisionsById(\"$id\");" }
}
}
/**
* A handler class that includes a server and common utilities
*/
public class VFForNotebook(override val context: Context) : ContextAware, CoroutineScope {
public val visionManager: VisionManager = context.visionManager
private var counter = 0
private var engine: ApplicationEngine? = null
public var isolateFragments: Boolean = false
override val coroutineContext: CoroutineContext get() = context.coroutineContext
public fun legacyMode() {
isolateFragments = true
}
public fun isServerRunning(): Boolean = engine != 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 ?: VisionRoute.DEFAULT_PORT,
): MimeTypedResult = html {
if (engine != null) {
p {
style = "color: red;"
+"Stopping current VisionForge server"
}
}
//val connector: EngineConnectorConfig = EngineConnectorConfig(host, port)
engine?.stop(1000, 2000)
engine = context.embeddedServer(CIO, port, host) {
install(WebSockets)
}.start(false)
p {
style = "color: blue;"
+"Starting VisionForge server on http://$host:$port"
}
}
public fun stopServer() {
engine?.apply {
logger.info { "Stopping VisionForge server" }
stop(1000, 2000)
engine = null
}
}
private fun produceHtmlString(
fragment: HtmlVisionFragment,
): String = createHTML().apply {
val id = "fragment[${fragment.hashCode()}/${Random.nextUInt()}]"
div {
this.id = id
val engine = engine
if (engine != null) {
//if server exist, serve dynamically
//server.serveVisionsFromFragment(consumer, "content-${counter++}", fragment)
val cellRoute = "content-${counter++}"
val collector: MutableMap<Name, Vision> = mutableMapOf()
val url = engine.environment.connectors.first().let {
url {
protocol = URLProtocol.WS
host = it.host
port = it.port
pathSegments = listOf(cellRoute, "ws")
}
}
engine.application.serveVisionData(VisionRoute(cellRoute, visionManager), collector)
visionFragment(
visionManager,
embedData = true,
updatesUrl = url,
onVisionRendered = { name, vision -> collector[name] = vision },
fragment = fragment
)
} else {
//if not, use static rendering
visionFragment(visionManager, fragment = fragment)
}
}
renderScriptForId(id)
}.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,8 +1,7 @@
package space.kscience.visionforge.jupyter
import kotlinx.html.p
import kotlinx.html.*
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
@ -10,12 +9,21 @@ 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.VisionManager
import space.kscience.visionforge.html.*
import kotlin.random.Random
import kotlin.random.nextUInt
/**
* A base class for different Jupyter VF integrations
*/
@DFExperimental
public abstract class JupyterPluginBase(final override val context: Context) : JupyterIntegration(), ContextAware {
public abstract class VFIntegrationBase(
public val visionManager: VisionManager,
) : JupyterIntegration(), ContextAware {
protected val handler: VisionForgeForNotebook = VisionForgeForNotebook(context)
override val context: Context get() = visionManager.context
protected val handler: VFForNotebook = VFForNotebook(visionManager.context)
protected abstract fun Builder.afterLoaded()
@ -44,13 +52,30 @@ public abstract class JupyterPluginBase(final override val context: Context) : J
render<Vision> { vision ->
handler.produceHtml {
vision { vision }
vision(vision)
}
}
render<Page> { page ->
HTML(page.render(createHTML()), true)
render<VisionPage> { page ->
HTML(createHTML().apply {
head {
meta {
charset = "utf-8"
}
page.pageHeaders.values.forEach {
fragment(it)
}
}
body {
val id = "fragment[${page.hashCode()}/${Random.nextUInt()}]"
div {
this.id = id
visionFragment(visionManager, fragment = page.content)
}
renderScriptForId(id)
}
}.finalize(), true)
}
render<HtmlFormFragment> { fragment ->
@ -62,7 +87,7 @@ public abstract class JupyterPluginBase(final override val context: Context) : J
}
}
fragment(fragment.formBody)
vision { fragment.vision }
vision(fragment.vision)
}
}

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

@ -0,0 +1,27 @@
package space.kscience.visionforge.jupyter
import kotlinx.html.FORM
import kotlinx.html.form
import kotlinx.html.id
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.get
import space.kscience.visionforge.html.HtmlFragment
import space.kscience.visionforge.html.VisionOfHtmlForm
public class HtmlFormFragment internal constructor(
public val vision: VisionOfHtmlForm,
public val formBody: HtmlFragment,
){
public val values: Meta? get() = vision.values
public operator fun get(valueName: String): Meta? = values?.get(valueName)
}
public fun HtmlFormFragment(id: String? = null, builder: FORM.() -> Unit): HtmlFormFragment {
val realId = id ?: "form[${builder.hashCode().toUInt()}]"
return HtmlFormFragment(VisionOfHtmlForm(realId)) {
form {
this.id = realId
builder()
}
}
}

View File

@ -1,60 +1,38 @@
plugins {
id("ru.mipt.npm.gradle.mpp")
id("space.kscience.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 {
fullStack("js/gdml-jupyter.js",
jsConfig = { useCommonJs() }
) {
commonWebpackConfig {
sourceMaps = false
cssSupport {
enabled.set(false)
}
}
}
dependencies{
implementation(projects.visionforgeSolid)
implementation(projects.jupyter)
}
dependencies(jvmMain){
implementation(projects.visionforgeGdml)
}
dependencies(jsMain){
implementation(projects.visionforgeThreejs)
implementation(projects.ui.ring)
}
jupyterLibrary("space.kscience.visionforge.gdml.jupyter.GdmlForJupyter")
}
readme {
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
maturity = space.kscience.gradle.Maturity.EXPERIMENTAL
}

View File

@ -6,7 +6,7 @@ import space.kscience.visionforge.runVisionClient
@DFExperimental
@JsExport
fun main(): Unit = runVisionClient {
public fun main(): Unit = runVisionClient {
plugin(ThreeWithControlsPlugin)
}

View File

@ -5,14 +5,15 @@ 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.jupyter.VFIntegrationBase
import space.kscience.visionforge.solid.Solids
import space.kscience.visionforge.visionManager
@DFExperimental
internal class GdmlForJupyter : JupyterPluginBase(
internal class GdmlForJupyter : VFIntegrationBase(
Context("GDML") {
plugin(Solids)
}
}.visionManager
) {
override fun Builder.afterLoaded() {

File diff suppressed because it is too large Load Diff

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,7 +62,7 @@ include(
":demo:muon-monitor",
":demo:sat-demo",
":demo:playground",
":demo:plotly-fx",
// ":demo:plotly-fx",
":demo:js-playground",
":jupyter",
":jupyter:visionforge-jupyter-gdml"

View File

@ -1,15 +1,19 @@
plugins {
kotlin("js")
id("ru.mipt.npm.gradle.js")
id("space.kscience.gradle.mpp")
}
val dataforgeVersion: String by rootProject.extra
dependencies {
api(project(":visionforge-solid"))
api(project(":ui:react"))
implementation(npm("file-saver", "2.0.2"))
implementation(npm("bootstrap","4.6.0"))
implementation(npm("jquery","3.5.1"))
implementation(npm("popper.js","1.16.1"))
kscience{
js()
jsMain{
dependencies {
api(project(":visionforge-solid"))
api(project(":ui:react"))
implementation(npm("file-saver", "2.0.2"))
implementation(npm("bootstrap","4.6.0"))
implementation(npm("jquery","3.5.1"))
implementation(npm("popper.js","1.16.1"))
}
}
}

View File

@ -1,12 +1,14 @@
package space.kscience.visionforge.bootstrap
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.css.BorderStyle
import kotlinx.css.Color
import kotlinx.css.padding
import kotlinx.css.properties.border
import kotlinx.css.px
import kotlinx.html.js.onClickFunction
import org.w3c.dom.events.Event
import kotlinx.html.org.w3c.dom.events.Event
import org.w3c.files.Blob
import org.w3c.files.BlobPropertyBag
import react.FC
@ -15,7 +17,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
@ -47,6 +48,7 @@ public external interface CanvasControlsProps : Props {
public var vision: Vision?
}
public val CanvasControls: FC<CanvasControlsProps> = fc("CanvasControls") { props ->
flexColumn {
flexRow {
@ -68,9 +70,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

@ -10,8 +10,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
@ -51,7 +51,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?.getMeta(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)
}

View File

@ -0,0 +1,11 @@
package space.kscience.visionforge.compose
import androidx.compose.material.Surface
import androidx.compose.runtime.Composable
@Composable
public fun ThreeJs(){
Surface {
}
}

View File

@ -1,11 +1,16 @@
plugins {
id("ru.mipt.npm.gradle.js")
id("space.kscience.gradle.mpp")
}
dependencies{
api(project(":visionforge-solid"))
api("org.jetbrains.kotlin-wrappers:kotlin-styled")
api("org.jetbrains.kotlin-wrappers:kotlin-react-dom")
kscience {
js()
jsMain {
dependencies {
api(projects.visionforgeSolid)
api("org.jetbrains.kotlin-wrappers:kotlin-styled")
api("org.jetbrains.kotlin-wrappers:kotlin-react-dom")
// implementation(npm("react-select","4.3.0"))
implementation(project(":visionforge-threejs"))
api(projects.visionforgeThreejs)
}
}
}

View File

@ -3,7 +3,7 @@ package space.kscience.visionforge.react
import kotlinx.css.Align
import kotlinx.css.alignItems
import kotlinx.html.js.onClickFunction
import org.w3c.dom.events.Event
import kotlinx.html.org.w3c.dom.events.Event
import react.*
import react.dom.a
import react.dom.attrs

View File

@ -1,31 +1,31 @@
package space.kscience.visionforge.react
import kotlinx.html.js.onChangeFunction
import kotlinx.html.org.w3c.dom.events.Event
import org.w3c.dom.HTMLOptionElement
import org.w3c.dom.HTMLSelectElement
import org.w3c.dom.asList
import org.w3c.dom.events.Event
import react.FC
import react.dom.attrs
import react.dom.option
import react.dom.select
import react.fc
import space.kscience.dataforge.meta.asValue
import space.kscience.dataforge.meta.descriptors.allowedValues
import space.kscience.dataforge.values.asValue
import space.kscience.dataforge.values.string
import space.kscience.dataforge.meta.string
@JsExport
public val MultiSelectChooser: FC<ValueChooserProps> = fc("MultiSelectChooser") { props ->
val onChange: (Event) -> Unit = { event: Event ->
val newSelected = (event.target as HTMLSelectElement).selectedOptions.asList()
.map { (it as HTMLOptionElement).value.asValue() }
props.meta.value = newSelected.asValue()
props.onValueChange(newSelected.asValue())
}
select {
attrs {
multiple = true
values = (props.actual.value?.list ?: emptyList()).mapTo(HashSet()) { it.string }
values = (props.value?.list ?: emptyList()).mapTo(HashSet()) { it.string }
onChangeFunction = onChange
}
props.descriptor?.allowedValues?.forEach { optionValue ->

View File

@ -1,17 +1,25 @@
package space.kscience.visionforge.react
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.css.*
import kotlinx.css.properties.TextDecoration
import kotlinx.html.js.onClickFunction
import org.w3c.dom.Element
import org.w3c.dom.events.Event
import kotlinx.html.org.w3c.dom.events.Event
import react.*
import react.dom.attrs
import react.dom.render
import space.kscience.dataforge.meta.*
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.ObservableMutableMeta
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.descriptors.ValueRequirement
import space.kscience.dataforge.meta.descriptors.get
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.remove
import space.kscience.dataforge.names.*
import space.kscience.visionforge.hidden
import styled.css
@ -19,17 +27,30 @@ import styled.styledButton
import styled.styledDiv
import styled.styledSpan
/**
* The display state of a property
*/
public sealed class EditorPropertyState {
public object Defined : EditorPropertyState()
public class Default(public val source: String = "unknown") : EditorPropertyState()
public object Undefined : EditorPropertyState()
}
public external interface PropertyEditorProps : Props {
/**
* Root config object - always non-null
*/
public var meta: ObservableMutableMeta
public var meta: MutableMeta
/**
* Provide default item (greyed out if used)
*/
public var withDefault: MetaProvider
public var getPropertyState: (Name) -> EditorPropertyState
public var scope: CoroutineScope
public var updates: Flow<Name>
/**
* Full path to the displayed node in [meta]. Could be empty
@ -54,7 +75,9 @@ private val PropertyEditorItem: FC<PropertyEditorProps> = fc("PropertyEditorItem
private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
var expanded: Boolean by useState { props.expanded ?: true }
val descriptor: MetaDescriptor? = useMemo(props.descriptor, props.name) { props.descriptor?.get(props.name) }
var ownProperty: ObservableMutableMeta by useState { props.meta.getOrCreate(props.name) }
var property: MutableMeta by useState { props.meta.getOrCreate(props.name) }
var editorPropertyState: EditorPropertyState by useState { props.getPropertyState(props.name) }
val keys = useMemo(descriptor) {
buildSet {
@ -70,17 +93,19 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
val token = props.name.lastOrNull()?.toString() ?: "Properties"
fun update() {
ownProperty = props.meta.getOrCreate(props.name)
property = props.meta.getOrCreate(props.name)
editorPropertyState = props.getPropertyState(props.name)
}
useEffect(props.meta) {
props.meta.onChange(props) { updatedName ->
val job = props.updates.onEach { updatedName ->
if (updatedName == props.name) {
update()
}
}
}.launchIn(props.scope)
cleanup {
props.meta.removeListener(props)
job.cancel()
}
}
@ -115,7 +140,7 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
styledSpan {
css {
+TreeStyles.treeLabel
if (ownProperty.isEmpty()) {
if (editorPropertyState != EditorPropertyState.Defined) {
+TreeStyles.treeLabelInactive
}
}
@ -131,8 +156,12 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
ValueChooser {
attrs {
this.descriptor = descriptor
this.meta = ownProperty
this.actual = props.withDefault.getMeta(props.name) ?: ownProperty
this.state = editorPropertyState
this.value = property.value
this.onValueChange = {
property.value = it
editorPropertyState = props.getPropertyState(props.name)
}
}
}
}
@ -156,7 +185,7 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
}
+"\u00D7"
attrs {
if (ownProperty.isEmpty()) {
if (editorPropertyState!= EditorPropertyState.Defined) {
disabled = true
} else {
onClickFunction = removeClick
@ -179,9 +208,11 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
attrs {
this.key = props.name.toString()
this.meta = props.meta
this.withDefault = props.withDefault
this.name = props.name + token
this.descriptor = props.descriptor
this.scope = props.scope
this.getPropertyState = { props.getPropertyState(props.name + token) }
this.updates = props.updates
}
}
//configEditor(props.root, props.name + token, props.descriptor, props.default)
@ -197,44 +228,51 @@ public val PropertyEditor: FC<PropertyEditorProps> = fc("PropertyEditor") { prop
attrs {
this.key = ""
this.meta = props.meta
this.withDefault = props.withDefault
this.name = Name.EMPTY
this.descriptor = props.descriptor
this.expanded = props.expanded
this.scope = props.scope
this.getPropertyState = props.getPropertyState
this.updates = props.updates
}
}
}
@OptIn(ExperimentalCoroutinesApi::class)
public fun RBuilder.propertyEditor(
ownProperties: ObservableMutableMeta,
allProperties: MetaProvider = ownProperties,
scope: CoroutineScope,
properties: ObservableMutableMeta,
descriptor: MetaDescriptor? = null,
key: Any? = null,
expanded: Boolean? = null,
) {
child(PropertyEditor) {
attrs {
this.meta = ownProperties
this.withDefault = allProperties
this.meta = properties
this.descriptor = descriptor
this.key = key?.toString() ?: ""
this.expanded = expanded
this.scope = scope
this.getPropertyState = { name ->
if (properties[name] != null) {
EditorPropertyState.Defined
} else if (descriptor?.get(name)?.defaultValue != null) {
EditorPropertyState.Default("descriptor")
} else {
EditorPropertyState.Undefined
}
}
this.updates = callbackFlow {
properties.onChange(scope) { name ->
scope.launch {
send(name)
}
}
invokeOnClose {
properties.removeListener(scope)
}
}
}
}
}
public fun RBuilder.configEditor(
config: ObservableMutableMeta,
default: MetaProvider = config,
descriptor: MetaDescriptor? = null,
key: Any? = null,
): Unit = propertyEditor(config, default, descriptor, key = key)
public fun Element.configEditor(
config: ObservableMutableMeta,
default: Meta = config,
descriptor: MetaDescriptor? = null,
key: Any? = null,
): Unit = render(this) {
configEditor(config, default, descriptor, key = key)
}

View File

@ -4,38 +4,40 @@ import kotlinx.css.pct
import kotlinx.css.width
import kotlinx.html.InputType
import kotlinx.html.js.onChangeFunction
import kotlinx.html.org.w3c.dom.events.Event
import org.w3c.dom.HTMLInputElement
import org.w3c.dom.events.Event
import react.FC
import react.dom.attrs
import react.fc
import react.useState
import space.kscience.dataforge.meta.asValue
import space.kscience.dataforge.meta.descriptors.ValueRequirement
import space.kscience.dataforge.meta.double
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.string
import space.kscience.dataforge.values.asValue
import styled.css
import styled.styledInput
@JsExport
public val RangeValueChooser: FC<ValueChooserProps> = fc("RangeValueChooser") { props ->
var innerValue by useState(props.actual.double)
var rangeDisabled: Boolean by useState(props.meta.value == null)
var innerValue by useState(props.value?.double)
var rangeDisabled: Boolean by useState(props.state != EditorPropertyState.Defined)
val handleDisable: (Event) -> Unit = {
val checkBoxValue = (it.target as HTMLInputElement).checked
rangeDisabled = !checkBoxValue
props.meta.value = if (!checkBoxValue) {
null
} else {
innerValue?.asValue()
}
props.onValueChange(
if (!checkBoxValue) {
null
} else {
innerValue?.asValue()
}
)
}
val handleChange: (Event) -> Unit = {
val newValue = (it.target as HTMLInputElement).value
props.meta.value = newValue.toDoubleOrNull()?.asValue()
props.onValueChange(newValue.toDoubleOrNull()?.asValue())
innerValue = newValue.toDoubleOrNull()
}

View File

@ -5,7 +5,7 @@ import org.w3c.dom.Element
import org.w3c.dom.HTMLElement
import react.*
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.fetch
import space.kscience.dataforge.context.request
import space.kscience.dataforge.names.Name
import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
@ -25,7 +25,7 @@ public val ThreeCanvasComponent: FC<ThreeCanvasProps> = fc("ThreeCanvasComponent
val elementRef = useRef<Element>(null)
var canvas by useState<ThreeCanvas?>(null)
val three: ThreePlugin = useMemo(props.context) { props.context.fetch(ThreePlugin) }
val three: ThreePlugin = useMemo(props.context) { props.context.request(ThreePlugin) }
useEffect(props.solid, props.options, elementRef) {
if (canvas == null) {

View File

@ -7,7 +7,7 @@ import kotlinx.css.cursor
import kotlinx.css.properties.TextDecorationLine
import kotlinx.css.properties.textDecoration
import kotlinx.html.js.onClickFunction
import org.w3c.dom.events.Event
import kotlinx.html.org.w3c.dom.events.Event
import react.*
import react.dom.attrs
import space.kscience.dataforge.names.Name
@ -16,6 +16,7 @@ import space.kscience.dataforge.names.plus
import space.kscience.dataforge.names.startsWith
import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionGroup
import space.kscience.visionforge.asSequence
import space.kscience.visionforge.isEmpty
import styled.css
import styled.styledDiv
@ -61,7 +62,7 @@ private fun RBuilder.visionTree(props: ObjectTreeProps): Unit {
//display as node if any child is visible
if (obj is VisionGroup) {
flexRow {
if (obj.children.any { !it.key.body.startsWith("@") }) {
if (obj.children.keys.any { !it.body.startsWith("@") }) {
styledSpan {
css {
+TreeStyles.treeCaret
@ -81,9 +82,9 @@ private fun RBuilder.visionTree(props: ObjectTreeProps): Unit {
css {
+TreeStyles.tree
}
obj.children.entries
.filter { !it.key.toString().startsWith("@") } // ignore statics and other hidden children
.sortedBy { (it.value as? VisionGroup)?.isEmpty() ?: true } // ignore empty groups
obj.children.asSequence()
.filter { !it.first.toString().startsWith("@") } // ignore statics and other hidden children
.sortedBy { (it.second as? VisionGroup)?.children?.isEmpty() ?: true } // ignore empty groups
.forEach { (childToken, child) ->
styledDiv {
css {

View File

@ -0,0 +1,17 @@
@file:JsModule("react-dom/client")
@file:JsNonModule
package space.kscience.visionforge.react
import org.w3c.dom.Element
import react.dom.client.Root
import react.dom.client.RootOptions
/**
* Compatibility method to work with old browser API
*/
public external fun createRoot(
container: Element,
options: RootOptions = definedExternally,
): Root

View File

@ -0,0 +1,10 @@
package space.kscience.visionforge.react
import react.Props
import react.RBuilder
import react.createElement
import react.dom.client.Root
public fun Root.render(block: RBuilder.() -> Unit) {
render(createElement<Props>(block))
}

View File

@ -7,9 +7,9 @@ import kotlinx.css.width
import kotlinx.html.InputType
import kotlinx.html.js.onChangeFunction
import kotlinx.html.js.onKeyDownFunction
import kotlinx.html.org.w3c.dom.events.Event
import org.w3c.dom.HTMLInputElement
import org.w3c.dom.HTMLSelectElement
import org.w3c.dom.events.Event
import react.FC
import react.Props
import react.dom.attrs
@ -19,29 +19,27 @@ import react.useState
import space.kscience.dataforge.meta.*
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.descriptors.allowedValues
import space.kscience.dataforge.values.ValueType
import space.kscience.dataforge.values.asValue
import space.kscience.dataforge.values.int
import space.kscience.dataforge.values.string
import space.kscience.visionforge.Colors
import space.kscience.visionforge.widgetType
import styled.css
import styled.styledInput
import styled.styledSelect
import three.math.Color
public external interface ValueChooserProps : Props {
public var descriptor: MetaDescriptor?
public var meta: ObservableMutableMeta
public var actual: Meta
public var state: EditorPropertyState
public var value: Value?
public var onValueChange: (Value?) -> Unit
}
@JsExport
public val StringValueChooser: FC<ValueChooserProps> = fc("StringValueChooser") { props ->
var value by useState(props.actual.string ?: "")
var value by useState(props.value?.string ?: "")
val keyDown: (Event) -> Unit = { event ->
if (event.type == "keydown" && event.asDynamic().key == "Enter") {
value = (event.target as HTMLInputElement).value
props.meta.value = value.asValue()
props.onValueChange(value.asValue())
}
}
val handleChange: (Event) -> Unit = {
@ -63,7 +61,7 @@ public val StringValueChooser: FC<ValueChooserProps> = fc("StringValueChooser")
public val BooleanValueChooser: FC<ValueChooserProps> = fc("BooleanValueChooser") { props ->
val handleChange: (Event) -> Unit = {
val newValue = (it.target as HTMLInputElement).checked
props.meta.value = newValue.asValue()
props.onValueChange(newValue.asValue())
}
styledInput(type = InputType.checkBox) {
css {
@ -71,7 +69,7 @@ public val BooleanValueChooser: FC<ValueChooserProps> = fc("BooleanValueChooser"
}
attrs {
//this.attributes["indeterminate"] = (props.item == null).toString()
checked = props.actual.boolean ?: false
checked = props.value?.boolean ?: false
onChangeFunction = handleChange
}
}
@ -79,7 +77,7 @@ public val BooleanValueChooser: FC<ValueChooserProps> = fc("BooleanValueChooser"
@JsExport
public val NumberValueChooser: FC<ValueChooserProps> = fc("NumberValueChooser") { props ->
var innerValue by useState(props.actual.string ?: "")
var innerValue by useState(props.value?.string ?: "")
val keyDown: (Event) -> Unit = { event ->
if (event.type == "keydown" && event.asDynamic().key == "Enter") {
innerValue = (event.target as HTMLInputElement).value
@ -87,7 +85,7 @@ public val NumberValueChooser: FC<ValueChooserProps> = fc("NumberValueChooser")
if (number == null) {
console.error("The input value $innerValue is not a number")
} else {
props.meta.value = number.asValue()
props.onValueChange(number.asValue())
}
}
}
@ -117,10 +115,10 @@ public val NumberValueChooser: FC<ValueChooserProps> = fc("NumberValueChooser")
@JsExport
public val ComboValueChooser: FC<ValueChooserProps> = fc("ComboValueChooser") { props ->
var selected by useState(props.actual.string ?: "")
var selected by useState(props.value?.string ?: "")
val handleChange: (Event) -> Unit = {
selected = (it.target as HTMLSelectElement).value
props.meta.value = selected.asValue()
props.onValueChange(selected.asValue())
}
styledSelect {
css {
@ -132,7 +130,7 @@ public val ComboValueChooser: FC<ValueChooserProps> = fc("ComboValueChooser") {
}
}
attrs {
this.value = props.actual.string ?: ""
this.value = props.value?.string ?: ""
multiple = false
onChangeFunction = handleChange
}
@ -142,7 +140,7 @@ public val ComboValueChooser: FC<ValueChooserProps> = fc("ComboValueChooser") {
@JsExport
public val ColorValueChooser: FC<ValueChooserProps> = fc("ColorValueChooser") { props ->
val handleChange: (Event) -> Unit = {
props.meta.value = (it.target as HTMLInputElement).value.asValue()
props.onValueChange((it.target as HTMLInputElement).value.asValue())
}
styledInput(type = InputType.color) {
css {
@ -150,9 +148,9 @@ public val ColorValueChooser: FC<ValueChooserProps> = fc("ColorValueChooser") {
margin(0.px)
}
attrs {
this.value = props.actual.value?.let { value ->
this.value = props.value?.let { value ->
if (value.type == ValueType.NUMBER) Colors.rgbToString(value.int)
else value.string
else "#" + Color(value.string).getHexString()
} ?: "#000000"
onChangeFunction = handleChange
}

View File

@ -1,24 +1,25 @@
plugins {
id("ru.mipt.npm.gradle.js")
id("space.kscience.gradle.mpp")
}
val dataforgeVersion: String by rootProject.extra
kotlin{
kscience{
js{
useCommonJs()
browser {
commonWebpackConfig {
cssSupport.enabled = false
cssSupport{
enabled.set(false)
}
}
}
}
}
jsMain{
api(projects.ui.react)
api("org.jetbrains.kotlin-wrappers:kotlin-ring-ui")
dependencies{
api(project(":ui:react"))
api("org.jetbrains.kotlin-wrappers:kotlin-ring-ui")
implementation(npm("core-js","3.12.1"))
implementation(npm("file-saver", "2.0.2"))
implementation(npm("core-js","3.12.1"))
implementation(npm("file-saver", "2.0.2"))
}
}

View File

@ -5,39 +5,46 @@ import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.css.*
import react.*
import react.dom.b
import react.dom.div
import react.dom.p
import react.dom.span
import ringui.*
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.NameToken
import space.kscience.dataforge.names.isEmpty
import space.kscience.dataforge.names.length
import space.kscience.visionforge.*
import space.kscience.visionforge.react.ThreeCanvasComponent
import space.kscience.visionforge.react.flexColumn
import space.kscience.visionforge.react.flexRow
import space.kscience.visionforge.react.propertyEditor
import space.kscience.visionforge.react.*
import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.SolidGroup
import space.kscience.visionforge.solid.Solids
import space.kscience.visionforge.solid.solidGroup
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
import styled.css
import styled.styledDiv
public external interface ThreeCanvasWithControlsProps : Props {
public var context: Context
public var solids: Solids
public var builderOfSolid: Deferred<Solid?>
public var selected: Name?
public var options: Canvas3DOptions?
public var additionalTabs: Map<String, RBuilder.() -> Unit>?
}
private val ThreeCanvasWithControlsProps.context get() = solids.context
public fun ThreeCanvasWithControlsProps.solid(block: SolidGroup.() -> Unit) {
builderOfSolid = context.async {
SolidGroup(block)
solids.solidGroup(null, block)
}
}
public fun ThreeCanvasWithControlsProps.options(block: Canvas3DOptions.() -> Unit) {
options = Canvas3DOptions(block)
}
public fun ThreeCanvasWithControlsProps.tab(title: String, block: RBuilder.() -> Unit) {
additionalTabs = (additionalTabs ?: emptyMap()) + (title to block)
}
@ -77,14 +84,14 @@ public fun RBuilder.nameCrumbs(name: Name?, link: (Name) -> Unit): Unit = styled
@JsExport
public val ThreeCanvasWithControls: FC<ThreeCanvasWithControlsProps> = fc("ThreeViewWithControls") { props ->
var selected by useState { props.selected }
var selected: Name? by useState { props.selected }
var solid: Solid? by useState(null)
useEffect {
props.context.launch {
solid = props.builderOfSolid.await()
//ensure that the solid is properly rooted
if(solid?.parent == null){
if (solid?.parent == null) {
solid?.setAsRoot(props.context.visionManager)
}
}
@ -104,7 +111,7 @@ public val ThreeCanvasWithControls: FC<ThreeCanvasWithControlsProps> = fc("Three
selected?.let {
when {
it.isEmpty() -> solid
else -> (solid as? VisionGroup)?.get(it)
else -> (solid as? SolidGroup)?.get(it)
}
}
}
@ -160,12 +167,31 @@ public val ThreeCanvasWithControls: FC<ThreeCanvasWithControlsProps> = fc("Three
nameCrumbs(selected) { selected = it }
}
IslandContent {
propertyEditor(
ownProperties = vision.meta,
allProperties = vision.computeProperties(),
descriptor = vision.descriptor,
key = selected
)
child(PropertyEditor) {
attrs {
this.key = selected.toString()
this.meta = vision.properties.root()
this.updates = vision.properties.changes
this.descriptor = vision.descriptor
this.scope = props.context
this.getPropertyState = { name ->
if (vision.properties.own?.get(name) != null) {
EditorPropertyState.Defined
} else if (vision.properties.root()[name] != null) {
// TODO differentiate
EditorPropertyState.Default()
} else {
EditorPropertyState.Undefined
}
}
}
}
vision.styles.takeIf { it.isNotEmpty() }?.let { styles ->
p {
b { +"Styles: " }
+styles.joinToString(separator = ", ")
}
}
}
}
}

View File

@ -2,7 +2,6 @@ package space.kscience.visionforge.ring
import kotlinx.coroutines.async
import org.w3c.dom.Element
import react.child
import space.kscience.dataforge.context.AbstractPlugin
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.PluginFactory
@ -12,9 +11,9 @@ import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName
import space.kscience.visionforge.ElementVisionRenderer
import space.kscience.visionforge.Vision
import space.kscience.visionforge.react.render
import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.three.ThreePlugin
import kotlin.reflect.KClass
public class ThreeWithControlsPlugin : AbstractPlugin(), ElementVisionRenderer {
public val three: ThreePlugin by require(ThreePlugin)
@ -24,11 +23,11 @@ public class ThreeWithControlsPlugin : AbstractPlugin(), ElementVisionRenderer {
override fun rateVision(vision: Vision): Int =
if (vision is Solid) ElementVisionRenderer.DEFAULT_RATING * 2 else ElementVisionRenderer.ZERO_RATING
override fun render(element: Element, vision: Vision, meta: Meta) {
react.dom.render(element) {
override fun render(element: Element, name: Name, vision: Vision, meta: Meta) {
space.kscience.visionforge.react.createRoot(element).render {
child(ThreeCanvasWithControls) {
attrs {
this.context = this@ThreeWithControlsPlugin.context
this.solids = three.solids
this.builderOfSolid = context.async { vision as Solid}
}
}
@ -44,7 +43,7 @@ public class ThreeWithControlsPlugin : AbstractPlugin(), ElementVisionRenderer {
public companion object : PluginFactory<ThreeWithControlsPlugin> {
override val tag: PluginTag = PluginTag("vision.threejs.withControls", PluginTag.DATAFORGE_GROUP)
override val type: KClass<ThreeWithControlsPlugin> = ThreeWithControlsPlugin::class
override fun invoke(meta: Meta, context: Context): ThreeWithControlsPlugin = ThreeWithControlsPlugin()
override fun build(context: Context, meta: Meta): ThreeWithControlsPlugin = ThreeWithControlsPlugin()
}
}

View File

@ -3,17 +3,15 @@ package space.kscience.visionforge.ring
import org.w3c.dom.Element
import react.RBuilder
import react.dom.p
import react.dom.render
import ringui.Island
import ringui.SmartTabs
import ringui.Tab
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.get
import space.kscience.visionforge.Vision
import space.kscience.visionforge.computeProperties
import space.kscience.visionforge.getStyle
import space.kscience.visionforge.react.flexColumn
import space.kscience.visionforge.react.metaViewer
import space.kscience.visionforge.react.propertyEditor
import space.kscience.visionforge.react.*
import space.kscience.visionforge.root
import space.kscience.visionforge.solid.SolidReference
import space.kscience.visionforge.styles
@ -30,12 +28,25 @@ public fun RBuilder.ringPropertyEditor(
flexColumn {
Island("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->
if(vision.properties.own?.get(name)!= null){
EditorPropertyState.Defined
} else if(vision.properties.root()[name] != null){
// TODO differentiate
EditorPropertyState.Default()
} else {
EditorPropertyState.Undefined
}
}
}
}
}
if (styles.isNotEmpty()) {
@ -72,6 +83,6 @@ public fun RBuilder.ringPropertyEditor(
public fun Element.ringPropertyEditor(
item: Vision,
descriptor: MetaDescriptor? = item.descriptor,
): Unit = render(this) {
): Unit = createRoot(this).render {
ringPropertyEditor(item, descriptor = descriptor)
}

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