Major build update and refactoring

This commit is contained in:
Alexander Nozik 2020-10-02 19:09:25 +03:00
parent 9361145197
commit 6116523091
83 changed files with 874 additions and 917 deletions

2
.gitignore vendored
View File

@ -5,6 +5,4 @@ out/
.gradle .gradle
build/ build/
!gradle-wrapper.jar !gradle-wrapper.jar
gradle.properties

View File

@ -0,0 +1,14 @@
# Changelog
## [Unreleased]
### Added
### Changed
### Deprecated
### Removed
### Fixed
### Security

View File

@ -1,16 +1,12 @@
import scientifik.useFx import ru.mipt.npm.gradle.useFx
import scientifik.useSerialization
val dataforgeVersion by extra("0.1.8")
plugins { plugins {
id("scientifik.mpp") apply false id("ru.mipt.npm.project")
id("scientifik.jvm") apply false
id("scientifik.js") apply false
id("scientifik.publish") apply false
id("org.jetbrains.changelog") version "0.4.0"
} }
val dataforgeVersion by extra("0.2.0-dev-3")
val ktorVersion by extra("1.4.1")
allprojects { allprojects {
repositories { repositories {
mavenLocal() mavenLocal()
@ -19,7 +15,7 @@ allprojects {
} }
group = "hep.dataforge" group = "hep.dataforge"
version = "0.1.5-dev-2" version = "0.2.0-dev-1"
} }
val githubProject by extra("visionforge") val githubProject by extra("visionforge")
@ -28,8 +24,17 @@ val fxVersion by extra("14")
subprojects { subprojects {
if(name.startsWith("visionforge")) { if(name.startsWith("visionforge")) {
apply(plugin = "scientifik.publish") apply<ru.mipt.npm.gradle.KSciencePublishPlugin>()
} }
afterEvaluate {
extensions.findByType<ru.mipt.npm.gradle.KScienceExtension>()?.run {
useSerialization() useSerialization()
useFx(scientifik.FXModule.CONTROLS, version = fxVersion) useFx(ru.mipt.npm.gradle.FXModule.CONTROLS, version = fxVersion)
}
}
}
apiValidation {
validationDisabled = true
ignoredPackages.add("info.laht.threekt")
} }

View File

View File

@ -1,20 +1,25 @@
import scientifik.DependencyConfiguration import ru.mipt.npm.gradle.DependencyConfiguration
import scientifik.FXModule import ru.mipt.npm.gradle.FXModule
import scientifik.useFx import ru.mipt.npm.gradle.useFx
plugins { plugins {
id("scientifik.mpp") id("ru.mipt.npm.mpp")
id("application") application
} }
kscience {
val fxVersion: String by rootProject.extra val fxVersion: String by rootProject.extra
useFx(FXModule.CONTROLS, version = fxVersion, configuration = DependencyConfiguration.IMPLEMENTATION) useFx(FXModule.CONTROLS, version = fxVersion, configuration = DependencyConfiguration.IMPLEMENTATION)
application()
}
kotlin { kotlin {
jvm { jvm {
afterEvaluate {
withJava() withJava()
} }
}
js { js {
useCommonJs() useCommonJs()

View File

@ -1,6 +1,6 @@
package hep.dataforge.vision.gdml.demo package hep.dataforge.vision.gdml.demo
import scientifik.gdml.* import kscience.gdml.*
fun cubes(): GDML = GDML { fun cubes(): GDML = GDML {

View File

@ -1,7 +1,6 @@
package hep.dataforge.vision.gdml.demo package hep.dataforge.vision.gdml.demo
import hep.dataforge.context.Context import hep.dataforge.context.Context
import hep.dataforge.meta.set
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.isEmpty import hep.dataforge.names.isEmpty
import hep.dataforge.vision.Vision import hep.dataforge.vision.Vision
@ -18,18 +17,18 @@ import hep.dataforge.vision.solid.specifications.Canvas3DOptions
import hep.dataforge.vision.solid.three.ThreeCanvas import hep.dataforge.vision.solid.three.ThreeCanvas
import hep.dataforge.vision.solid.three.ThreeCanvasComponent import hep.dataforge.vision.solid.three.ThreeCanvasComponent
import hep.dataforge.vision.solid.three.canvasControls import hep.dataforge.vision.solid.three.canvasControls
import kotlinx.browser.window
import kotlinx.css.FlexBasis import kotlinx.css.FlexBasis
import kotlinx.css.Overflow import kotlinx.css.Overflow
import kotlinx.css.flex import kotlinx.css.flex
import kotlinx.css.overflow import kotlinx.css.overflow
import kscience.gdml.GDML
import kscience.gdml.decodeFromString
import org.w3c.files.FileReader import org.w3c.files.FileReader
import org.w3c.files.get import org.w3c.files.get
import react.RProps import react.RProps
import react.dom.h1 import react.dom.h1
import scientifik.gdml.GDML
import scientifik.gdml.parse
import styled.css import styled.css
import kotlin.browser.window
import kotlin.math.PI import kotlin.math.PI
interface GDMLAppProps : RProps { interface GDMLAppProps : RProps {
@ -58,10 +57,10 @@ val GDMLApp = component<GDMLAppProps> { props ->
fun loadData(name: String, data: String) { fun loadData(name: String, data: String) {
val parsedVision = when { val parsedVision = when {
name.endsWith(".gdml") || name.endsWith(".xml") -> { name.endsWith(".gdml") || name.endsWith(".xml") -> {
val gdml = GDML.parse(data) val gdml = GDML.decodeFromString(data)
gdml.toVision() gdml.toVision()
} }
name.endsWith(".json") -> SolidGroup.parseJson(data) name.endsWith(".json") -> SolidGroup.decodeFromString(data)
else -> { else -> {
window.alert("File extension is not recognized: $name") window.alert("File extension is not recognized: $name")
error("File extension is not recognized: $name") error("File extension is not recognized: $name")

View File

@ -3,15 +3,12 @@ package hep.dataforge.vision.gdml.demo
import hep.dataforge.context.Global import hep.dataforge.context.Global
import hep.dataforge.js.Application import hep.dataforge.js.Application
import hep.dataforge.js.startApplication import hep.dataforge.js.startApplication
import hep.dataforge.vision.gdml.GDMLTransformer
import hep.dataforge.vision.gdml.LUnit
import hep.dataforge.vision.gdml.toVision import hep.dataforge.vision.gdml.toVision
import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_OPACITY_KEY import kotlinx.browser.document
import kotlinx.css.* import kotlinx.css.*
import react.child import react.child
import react.dom.render import react.dom.render
import styled.injectGlobal import styled.injectGlobal
import kotlin.browser.document
private class GDMLDemoApp : Application { private class GDMLDemoApp : Application {

View File

@ -7,7 +7,7 @@
<link rel="stylesheet" href="css/bootstrap.min.css"> <link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/main.css"> <link rel="stylesheet" href="css/main.css">
<link rel="stylesheet" href="css/fileDrop.css"> <link rel="stylesheet" href="css/fileDrop.css">
<script type="text/javascript" src="main.bundle.js"></script> <script type="text/javascript" src="gdml.js"></script>
<script type="text/javascript" src ="js/jquery-3.4.1.min.js"></script> <script type="text/javascript" src ="js/jquery-3.4.1.min.js"></script>
<script type="text/javascript" src ="js/bootstrap.bundle.min.js"></script> <script type="text/javascript" src ="js/bootstrap.bundle.min.js"></script>
</head> </head>

View File

@ -3,13 +3,12 @@ package hep.dataforge.vision.gdml.demo
import hep.dataforge.meta.DFExperimental import hep.dataforge.meta.DFExperimental
import hep.dataforge.meta.setItem import hep.dataforge.meta.setItem
import hep.dataforge.values.asValue import hep.dataforge.values.asValue
import hep.dataforge.vision.gdml.LUnit
import hep.dataforge.vision.gdml.readFile import hep.dataforge.vision.gdml.readFile
import hep.dataforge.vision.gdml.toVision import hep.dataforge.vision.gdml.toVision
import hep.dataforge.vision.solid.SolidGroup import hep.dataforge.vision.solid.SolidGroup
import hep.dataforge.vision.solid.SolidManager import hep.dataforge.vision.solid.SolidManager
import hep.dataforge.vision.solid.SolidMaterial import hep.dataforge.vision.solid.SolidMaterial
import scientifik.gdml.GDML import kscience.gdml.GDML
import java.io.File import java.io.File
import java.util.zip.GZIPInputStream import java.util.zip.GZIPInputStream
import java.util.zip.ZipInputStream import java.util.zip.ZipInputStream
@ -32,19 +31,19 @@ fun SolidManager.Companion.readFile(file: File): SolidGroup = when {
// } // }
} }
} }
file.extension == "json" -> SolidGroup.parseJson(file.readText()) file.extension == "json" -> SolidGroup.decodeFromString(file.readText())
file.name.endsWith("json.zip") -> { file.name.endsWith("json.zip") -> {
file.inputStream().use { file.inputStream().use {
val unzip = ZipInputStream(it, Charsets.UTF_8) val unzip = ZipInputStream(it, Charsets.UTF_8)
val text = unzip.readBytes().decodeToString() val text = unzip.readBytes().decodeToString()
SolidGroup.parseJson(text) SolidGroup.decodeFromString(text)
} }
} }
file.name.endsWith("json.gz") -> { file.name.endsWith("json.gz") -> {
file.inputStream().use { file.inputStream().use {
val unzip = GZIPInputStream(it) val unzip = GZIPInputStream(it)
val text = unzip.readBytes().decodeToString() val text = unzip.readBytes().decodeToString()
SolidGroup.parseJson(text) SolidGroup.decodeFromString(text)
} }
} }
else -> error("Unknown extension ${file.extension}") else -> error("Unknown extension ${file.extension}")

View File

@ -1,10 +1,10 @@
package hep.dataforge.vision.gdml.demo package hep.dataforge.vision.gdml.demo
import hep.dataforge.vision.gdml.LUnit
import hep.dataforge.vision.gdml.readFile import hep.dataforge.vision.gdml.readFile
import hep.dataforge.vision.gdml.toVision import hep.dataforge.vision.gdml.toVision
import hep.dataforge.vision.solid.stringify import hep.dataforge.vision.solid.encodeToString
import scientifik.gdml.GDML import kscience.gdml.GDML
import kscience.gdml.LUnit
import java.io.File import java.io.File
import java.nio.file.Paths import java.nio.file.Paths
@ -21,7 +21,7 @@ fun main(args: Array<String>) {
lUnit = LUnit.CM lUnit = LUnit.CM
} }
val json = visual.stringify() val json = visual.encodeToString()
println(json) println(json)
File(outputFileName).writeText(json) File(outputFileName).writeText(json)
//File("D:\\Work\\Projects\\gdml.kt\\gdml-source\\cubes.json").writeText(json) //File("D:\\Work\\Projects\\gdml.kt\\gdml-source\\cubes.json").writeText(json)

View File

@ -9,7 +9,7 @@ class FileSerializationTest {
@Ignore @Ignore
fun testFileRead(){ fun testFileRead(){
val text = this::class.java.getResourceAsStream("/cubes.json").readBytes().decodeToString() val text = this::class.java.getResourceAsStream("/cubes.json").readBytes().decodeToString()
val visual = SolidGroup.parseJson(text) val visual = SolidGroup.decodeFromString(text)
visual["composite_001".asName()] visual["composite_001".asName()]
} }
} }

View File

@ -1,44 +1,39 @@
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPILATION_NAME import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPILATION_NAME
import scientifik.jsDistDirectory
plugins { plugins {
id("scientifik.mpp") id("ru.mipt.npm.mpp")
id("application") application
} }
group = "ru.mipt.npm" group = "ru.mipt.npm"
val ktorVersion = "1.3.2" val ktorVersion: String by rootProject.extra
kscience {
application()
}
kotlin { kotlin {
afterEvaluate {
val installJS = tasks.getByName("jsBrowserDistribution") val jsBrowserDistribution by tasks.getting
js {
browser {
dceTask {
dceOptions {
keep("ktor-ktor-io.\$\$importsForInline\$\$.ktor-ktor-io.io.ktor.utils.io")
}
}
webpackTask {
mode = org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig.Mode.PRODUCTION
}
}
}
jvm { jvm {
withJava() withJava()
compilations[MAIN_COMPILATION_NAME]?.apply { compilations[MAIN_COMPILATION_NAME]?.apply {
tasks.getByName<ProcessResources>(processResourcesTaskName) { tasks.getByName<ProcessResources>(processResourcesTaskName) {
dependsOn(installJS) dependsOn(jsBrowserDistribution)
afterEvaluate { afterEvaluate {
from(project.jsDistDirectory) from(jsBrowserDistribution)
} }
} }
} }
} }
}
js {
useCommonJs()
}
sourceSets { sourceSets {
commonMain { commonMain {
@ -58,14 +53,6 @@ kotlin {
implementation(project(":ui:bootstrap")) implementation(project(":ui:bootstrap"))
implementation("io.ktor:ktor-client-js:$ktorVersion") implementation("io.ktor:ktor-client-js:$ktorVersion")
implementation("io.ktor:ktor-client-serialization-js:$ktorVersion") implementation("io.ktor:ktor-client-serialization-js:$ktorVersion")
implementation(npm("text-encoding"))
implementation(npm("abort-controller"))
implementation(npm("bufferutil"))
implementation(npm("utf-8-validate"))
implementation(npm("fs"))
// implementation(npm("jquery"))
// implementation(npm("popper.js"))
// implementation(npm("react-is"))
} }
} }
} }

View File

@ -4,6 +4,7 @@ import hep.dataforge.context.Context
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.NameToken import hep.dataforge.names.NameToken
import hep.dataforge.names.isEmpty import hep.dataforge.names.isEmpty
import hep.dataforge.names.length
import hep.dataforge.vision.Vision import hep.dataforge.vision.Vision
import hep.dataforge.vision.bootstrap.card import hep.dataforge.vision.bootstrap.card
import hep.dataforge.vision.react.component import hep.dataforge.vision.react.component

View File

@ -7,11 +7,11 @@ import hep.dataforge.vision.solid.SolidManager
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.features.json.JsonFeature import io.ktor.client.features.json.JsonFeature
import io.ktor.client.features.json.serializer.KotlinxSerializer import io.ktor.client.features.json.serializer.KotlinxSerializer
import kotlinx.browser.document
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import react.child import react.child
import react.dom.div import react.dom.div
import react.dom.render import react.dom.render
import kotlin.browser.document
private class MMDemoApp : Application { private class MMDemoApp : Application {
@ -19,7 +19,7 @@ private class MMDemoApp : Application {
private val connection = HttpClient { private val connection = HttpClient {
install(JsonFeature) { install(JsonFeature) {
serializer = KotlinxSerializer(Json(context = SolidManager.serialModule)) serializer = KotlinxSerializer(Json { serializersModule = SolidManager.serialModule })
} }
} }
@ -34,8 +34,8 @@ private class MMDemoApp : Application {
div("container-fluid h-100") { div("container-fluid h-100") {
child(MMApp) { child(MMApp) {
attrs { attrs {
model = this@MMDemoApp.model this.model = this@MMDemoApp.model
connection = this@MMDemoApp.connection this.connection = this@MMDemoApp.connection
this.context = context this.context = context
} }
} }

View File

@ -6,7 +6,7 @@
<title>Three js demo for particle physics</title> <title>Three js demo for particle physics</title>
<link rel="stylesheet" href="css/bootstrap.min.css"> <link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/main.css"> <link rel="stylesheet" href="css/main.css">
<script type="text/javascript" src="main.bundle.js"></script> <script type="text/javascript" src="muon-monitor.js"></script>
<script type="text/javascript" src ="js/jquery-3.4.1.min.js"></script> <script type="text/javascript" src ="js/jquery-3.4.1.min.js"></script>
<script type="text/javascript" src ="js/bootstrap.bundle.min.js"></script> <script type="text/javascript" src ="js/bootstrap.bundle.min.js"></script>
</head> </head>

View File

@ -10,6 +10,7 @@ import io.ktor.application.log
import io.ktor.features.CallLogging import io.ktor.features.CallLogging
import io.ktor.features.ContentNegotiation import io.ktor.features.ContentNegotiation
import io.ktor.features.DefaultHeaders import io.ktor.features.DefaultHeaders
import io.ktor.http.ContentType
import io.ktor.http.content.resources import io.ktor.http.content.resources
import io.ktor.http.content.static import io.ktor.http.content.static
import io.ktor.response.respond import io.ktor.response.respond
@ -19,6 +20,7 @@ import io.ktor.serialization.json
import io.ktor.server.cio.CIO import io.ktor.server.cio.CIO
import io.ktor.server.engine.embeddedServer import io.ktor.server.engine.embeddedServer
import io.ktor.util.KtorExperimentalAPI import io.ktor.util.KtorExperimentalAPI
import kotlinx.serialization.json.Json
import org.apache.commons.math3.random.JDKRandomGenerator import org.apache.commons.math3.random.JDKRandomGenerator
import ru.mipt.npm.muon.monitor.Model import ru.mipt.npm.muon.monitor.Model
import ru.mipt.npm.muon.monitor.sim.Cos2TrackGenerator import ru.mipt.npm.muon.monitor.sim.Cos2TrackGenerator
@ -38,7 +40,7 @@ fun Application.module() {
install(DefaultHeaders) install(DefaultHeaders)
install(CallLogging) install(CallLogging)
install(ContentNegotiation) { install(ContentNegotiation) {
json(module = SolidManager.serialModule) json(Json { serializersModule = SolidManager.serialModule }, ContentType.Application.Json)
} }
install(Routing) { install(Routing) {
get("/event") { get("/event") {

View File

@ -1,20 +1,23 @@
import scientifik.DependencyConfiguration import ru.mipt.npm.gradle.*
import scientifik.FXModule
import scientifik.useFx
plugins { plugins {
id("scientifik.mpp") id("ru.mipt.npm.mpp")
id("application") application
} }
kscience {
val fxVersion: String by rootProject.extra val fxVersion: String by rootProject.extra
useFx(FXModule.CONTROLS, version = fxVersion, configuration = DependencyConfiguration.IMPLEMENTATION) useFx(FXModule.CONTROLS, version = fxVersion, configuration = DependencyConfiguration.IMPLEMENTATION)
application()
}
kotlin { kotlin {
jvm { jvm {
afterEvaluate {
withJava() withJava()
} }
}
sourceSets { sourceSets {
commonMain { commonMain {

View File

@ -8,6 +8,7 @@ import hep.dataforge.vision.Colors
import hep.dataforge.vision.Vision import hep.dataforge.vision.Vision
import hep.dataforge.vision.solid.* import hep.dataforge.vision.solid.*
import hep.dataforge.vision.solid.specifications.Canvas3DOptions import hep.dataforge.vision.solid.specifications.Canvas3DOptions
import hep.dataforge.vision.visible
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlin.math.PI import kotlin.math.PI
import kotlin.math.cos import kotlin.math.cos

View File

@ -6,7 +6,7 @@
<title>Three js demo for particle physics</title> <title>Three js demo for particle physics</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous"> integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<script type="text/javascript" src="main.bundle.js"></script> <script type="text/javascript" src="spatial-showcase.js"></script>
</head> </head>
<body class="application"> <body class="application">
<div class="container"> <div class="container">

9
gradle.properties Normal file
View File

@ -0,0 +1,9 @@
kotlin.code.style=official
kotlin.parallel.tasks.in.project=true
kotlin.mpp.enableGranularSourceSetsMetadata=true
kotlin.native.enableDependencyPropagation=false
kotlin.mpp.stability.nowarn=true
org.gradle.jvmargs=-XX:MaxMetaspaceSize=512m
org.gradle.parallel=true
systemProp.org.gradle.internal.publish.checksums.insecure=true

View File

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

View File

@ -7,12 +7,12 @@ repositories{
maven("https://kotlin.bintray.com/kotlinx") maven("https://kotlin.bintray.com/kotlinx")
maven("https://dl.bintray.com/kotlin/kotlin-eap") maven("https://dl.bintray.com/kotlin/kotlin-eap")
maven("https://dl.bintray.com/mipt-npm/dataforge") maven("https://dl.bintray.com/mipt-npm/dataforge")
maven("https://dl.bintray.com/mipt-npm/scientifik") maven("https://dl.bintray.com/mipt-npm/kscience")
maven("https://dl.bintray.com/mipt-npm/dev") maven("https://dl.bintray.com/mipt-npm/dev")
} }
kotlin { kotlin {
js { js(IR) {
browser {} browser {}
} }

View File

@ -1,32 +1,27 @@
pluginManagement { pluginManagement {
val kotlinVersion = "1.3.72" val kotlinVersion = "1.4.20-M1"
val toolsVersion = "0.5.2" val toolsVersion = "0.6.3-dev-1.4.20-M1"
repositories { repositories {
mavenLocal() mavenLocal()
jcenter() jcenter()
gradlePluginPortal() gradlePluginPortal()
maven("https://kotlin.bintray.com/kotlinx")
maven("https://dl.bintray.com/kotlin/kotlin-eap") maven("https://dl.bintray.com/kotlin/kotlin-eap")
maven("https://dl.bintray.com/kotlin/kotlinx")
maven("https://dl.bintray.com/mipt-npm/dataforge") maven("https://dl.bintray.com/mipt-npm/dataforge")
maven("https://dl.bintray.com/mipt-npm/scientifik") maven("https://dl.bintray.com/mipt-npm/kscience")
maven("https://dl.bintray.com/mipt-npm/dev") maven("https://dl.bintray.com/mipt-npm/dev")
} }
plugins { plugins {
id("ru.mipt.npm.project") version toolsVersion
id("ru.mipt.npm.mpp") version toolsVersion
id("ru.mipt.npm.jvm") version toolsVersion
id("ru.mipt.npm.js") version toolsVersion
id("ru.mipt.npm.publish") version toolsVersion
kotlin("jvm") version kotlinVersion kotlin("jvm") version kotlinVersion
id("scientifik.mpp") version toolsVersion kotlin("js") version kotlinVersion
id("scientifik.jvm") version toolsVersion kotlin("multiplatform") version kotlinVersion
id("scientifik.js") version toolsVersion
id("scientifik.publish") version toolsVersion
}
resolutionStrategy {
eachPlugin {
when (requested.id.id) {
"scientifik.mpp", "scientifik.publish", "scientifik.jvm", "scientifik.js" -> useModule("scientifik:gradle-tools:${toolsVersion}")
}
}
} }
} }
@ -34,11 +29,12 @@ pluginManagement {
rootProject.name = "visionforge" rootProject.name = "visionforge"
include( include(
":ui", // ":ui",
":ui:react", ":ui:react",
":ui:ring", ":ui:ring",
":ui:material", // ":ui:material",
":ui:bootstrap", ":ui:bootstrap",
":visionforge-core", ":visionforge-core",
":visionforge-solid", ":visionforge-solid",

View File

@ -1,15 +1,9 @@
plugins { plugins {
id("scientifik.js") id("ru.mipt.npm.js")
} }
val dataforgeVersion: String by rootProject.extra val dataforgeVersion: String by rootProject.extra
kotlin {
target {
useCommonJs()
}
}
dependencies{ dependencies{
api(project(":ui:react")) api(project(":ui:react"))
} }

View File

@ -2,6 +2,7 @@ package hep.dataforge.vision.bootstrap
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.NameToken import hep.dataforge.names.NameToken
import hep.dataforge.names.length
import hep.dataforge.vision.Vision import hep.dataforge.vision.Vision
import hep.dataforge.vision.react.ObjectTree import hep.dataforge.vision.react.ObjectTree
import kotlinx.html.* import kotlinx.html.*
@ -17,7 +18,7 @@ import styled.StyledDOMBuilder
import styled.css import styled.css
import styled.styledDiv import styled.styledDiv
inline fun TagConsumer<HTMLElement>.card(title: String, crossinline block: TagConsumer<HTMLElement>.() -> Unit) { public inline fun TagConsumer<HTMLElement>.card(title: String, crossinline block: TagConsumer<HTMLElement>.() -> Unit) {
div("card w-100") { div("card w-100") {
div("card-body") { div("card-body") {
h3(classes = "card-title") { +title } h3(classes = "card-title") { +title }
@ -26,7 +27,7 @@ inline fun TagConsumer<HTMLElement>.card(title: String, crossinline block: TagCo
} }
} }
inline fun RBuilder.card(title: String, classes: String? = null, crossinline block: RBuilder.() -> Unit) { public inline fun RBuilder.card(title: String, classes: String? = null, crossinline block: RBuilder.() -> Unit) {
div("card w-100 $classes") { div("card w-100 $classes") {
div("card-body") { div("card-body") {
h3(classes = "card-title") { h3(classes = "card-title") {
@ -37,7 +38,7 @@ inline fun RBuilder.card(title: String, classes: String? = null, crossinline blo
} }
} }
fun TagConsumer<HTMLElement>.accordion(id: String, elements: List<Pair<String, DIV.() -> Unit>>) { public fun TagConsumer<HTMLElement>.accordion(id: String, elements: List<Pair<String, DIV.() -> Unit>>) {
div("container-fluid") { div("container-fluid") {
div("accordion") { div("accordion") {
this.id = id this.id = id
@ -69,18 +70,18 @@ fun TagConsumer<HTMLElement>.accordion(id: String, elements: List<Pair<String, D
} }
} }
typealias AccordionBuilder = MutableList<Pair<String, DIV.() -> Unit>> public typealias AccordionBuilder = MutableList<Pair<String, DIV.() -> Unit>>
fun AccordionBuilder.entry(title: String, builder: DIV.() -> Unit) { public fun AccordionBuilder.entry(title: String, builder: DIV.() -> Unit) {
add(title to builder) add(title to builder)
} }
fun TagConsumer<HTMLElement>.accordion(id: String, builder: AccordionBuilder.() -> Unit) { public fun TagConsumer<HTMLElement>.accordion(id: String, builder: AccordionBuilder.() -> Unit) {
val list = ArrayList<Pair<String, DIV.() -> Unit>>().apply(builder) val list = ArrayList<Pair<String, DIV.() -> Unit>>().apply(builder)
accordion(id, list) accordion(id, list)
} }
fun RBuilder.accordion(id: String, elements: List<Pair<String, RDOMBuilder<DIV>.() -> Unit>>): ReactElement { public fun RBuilder.accordion(id: String, elements: List<Pair<String, RDOMBuilder<DIV>.() -> Unit>>): ReactElement {
return div("container-fluid") { return div("container-fluid") {
div("accordion") { div("accordion") {
attrs { attrs {
@ -120,7 +121,7 @@ fun RBuilder.accordion(id: String, elements: List<Pair<String, RDOMBuilder<DIV>.
} }
} }
fun RBuilder.namecrumbs(name: Name?, rootTitle: String, link: (Name) -> Unit) { public fun RBuilder.namecrumbs(name: Name?, rootTitle: String, link: (Name) -> Unit) {
div("container-fluid p-0") { div("container-fluid p-0") {
nav { nav {
attrs { attrs {
@ -160,20 +161,18 @@ fun RBuilder.namecrumbs(name: Name?, rootTitle: String, link: (Name) -> Unit) {
} }
} }
typealias RAccordionBuilder = MutableList<Pair<String, RDOMBuilder<DIV>.() -> Unit>> public typealias RAccordionBuilder = MutableList<Pair<String, RDOMBuilder<DIV>.() -> Unit>>
fun RAccordionBuilder.entry(title: String, builder: RDOMBuilder<DIV>.() -> Unit) { public fun RAccordionBuilder.entry(title: String, builder: RDOMBuilder<DIV>.() -> Unit) {
add(title to builder) add(title to builder)
} }
fun RBuilder.accordion(id: String, builder: RAccordionBuilder.() -> Unit): ReactElement { public fun RBuilder.accordion(id: String, builder: RAccordionBuilder.() -> Unit): ReactElement {
val list = ArrayList<Pair<String, RDOMBuilder<DIV>.() -> Unit>>().apply(builder) val list = ArrayList<Pair<String, RDOMBuilder<DIV>.() -> Unit>>().apply(builder)
return accordion(id, list) return accordion(id, list)
} }
fun joinStyles(vararg styles: String?) = styles.joinToString(separator = " ") { it ?: "" } public enum class ContainerSize(public val suffix: String) {
enum class ContainerSize(val suffix: String) {
DEFAULT(""), DEFAULT(""),
SM("-sm"), SM("-sm"),
MD("-md"), MD("-md"),
@ -182,7 +181,7 @@ enum class ContainerSize(val suffix: String) {
FLUID("-fluid") FLUID("-fluid")
} }
inline fun RBuilder.container( public inline fun RBuilder.container(
size: ContainerSize = ContainerSize.FLUID, size: ContainerSize = ContainerSize.FLUID,
block: StyledDOMBuilder<DIV>.() -> Unit block: StyledDOMBuilder<DIV>.() -> Unit
): ReactElement = styledDiv{ ): ReactElement = styledDiv{
@ -193,7 +192,7 @@ inline fun RBuilder.container(
} }
enum class GridMaxSize(val suffix: String) { public enum class GridMaxSize(public val suffix: String) {
NONE(""), NONE(""),
SM("-sm"), SM("-sm"),
MD("-md"), MD("-md"),
@ -201,7 +200,7 @@ enum class GridMaxSize(val suffix: String) {
XL("-xl") XL("-xl")
} }
inline fun RBuilder.gridColumn( public inline fun RBuilder.gridColumn(
weight: Int? = null, weight: Int? = null,
maxSize: GridMaxSize = GridMaxSize.NONE, maxSize: GridMaxSize = GridMaxSize.NONE,
block: StyledDOMBuilder<DIV>.() -> Unit block: StyledDOMBuilder<DIV>.() -> Unit
@ -213,7 +212,7 @@ inline fun RBuilder.gridColumn(
block() block()
} }
inline fun RBuilder.gridRow( public inline fun RBuilder.gridRow(
block: StyledDOMBuilder<DIV>.() -> Unit block: StyledDOMBuilder<DIV>.() -> Unit
): ReactElement = styledDiv{ ): ReactElement = styledDiv{
css{ css{
@ -222,10 +221,10 @@ inline fun RBuilder.gridRow(
block() block()
} }
fun Element.renderObjectTree( public fun Element.renderObjectTree(
vision: Vision, vision: Vision,
clickCallback: (Name) -> Unit = {} clickCallback: (Name) -> Unit = {}
) = render(this) { ): Unit = render(this) {
card("Object tree") { card("Object tree") {
child(ObjectTree) { child(ObjectTree) {
attrs { attrs {

View File

@ -1,20 +1,14 @@
plugins { plugins {
id("scientifik.js") id("ru.mipt.npm.js")
} }
val dataforgeVersion: String by rootProject.extra val dataforgeVersion: String by rootProject.extra
kotlin {
target {
useCommonJs()
}
}
dependencies{ dependencies{
api(project(":ui:react")) api(project(":ui:react"))
api("subroh0508.net.kotlinmaterialui:core:0.4.0") api("subroh0508.net.kotlinmaterialui:core:0.4.5")
api("subroh0508.net.kotlinmaterialui:lab:0.4.0") api("subroh0508.net.kotlinmaterialui:lab:0.4.5")
api(npm("@material-ui/core","4.9.14")) api(npm("@material-ui/core","4.9.14"))
api(npm("@material-ui/lab","4.0.0-alpha.51")) api(npm("@material-ui/lab","4.0.0-alpha.51"))
//api(npm("@material-ui/icons","4.9.1")) //api(npm("@material-ui/icons","4.9.1"))

View File

@ -1,11 +1,5 @@
plugins { plugins {
id("scientifik.js") id("ru.mipt.npm.js")
}
kotlin {
target {
useCommonJs()
}
} }
val reactVersion by extra("16.13.1") val reactVersion by extra("16.13.1")
@ -14,7 +8,7 @@ dependencies{
api(project(":visionforge-core")) api(project(":visionforge-core"))
//api("org.jetbrains:kotlin-react:16.13.1-pre.104-kotlin-1.3.72") //api("org.jetbrains:kotlin-react:16.13.1-pre.104-kotlin-1.3.72")
api("org.jetbrains:kotlin-react-dom:$reactVersion-pre.104-kotlin-1.3.72") api("org.jetbrains:kotlin-react-dom:$reactVersion-pre.123-kotlin-1.4.10")
api(npm("react", reactVersion)) api(npm("react", reactVersion))
api(npm("react-dom", reactVersion)) api(npm("react-dom", reactVersion))

View File

@ -4,6 +4,7 @@ import hep.dataforge.meta.*
import hep.dataforge.meta.descriptors.* import hep.dataforge.meta.descriptors.*
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.NameToken import hep.dataforge.names.NameToken
import hep.dataforge.names.lastOrNull
import hep.dataforge.names.plus import hep.dataforge.names.plus
import hep.dataforge.values.Value import hep.dataforge.values.Value
import kotlinx.html.js.onClickFunction import kotlinx.html.js.onClickFunction
@ -47,7 +48,7 @@ private fun RFBuilder.configEditorItem(props: ConfigEditorItemProps) {
val defaultItem = props.default?.get(props.name) val defaultItem = props.default?.get(props.name)
var actualItem: MetaItem<Meta>? by state { item ?: defaultItem ?: descriptorItem?.defaultItem() } var actualItem: MetaItem<Meta>? by state { item ?: defaultItem ?: descriptorItem?.defaultItem() }
val token = props.name.last()?.toString() ?: "Properties" val token = props.name.lastOrNull()?.toString() ?: "Properties"
fun update() { fun update() {
item = props.root[props.name] item = props.root[props.name]

View File

@ -9,6 +9,7 @@ import hep.dataforge.meta.descriptors.get
import hep.dataforge.meta.get import hep.dataforge.meta.get
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.NameToken import hep.dataforge.names.NameToken
import hep.dataforge.names.lastOrNull
import hep.dataforge.names.plus import hep.dataforge.names.plus
import kotlinx.html.js.onClickFunction import kotlinx.html.js.onClickFunction
import org.w3c.dom.events.Event import org.w3c.dom.events.Event
@ -43,7 +44,7 @@ private fun RFBuilder.metaViewerItem(props: MetaViewerProps) {
val descriptorItem: ItemDescriptor? = props.descriptor?.get(props.name) val descriptorItem: ItemDescriptor? = props.descriptor?.get(props.name)
val actualItem = item ?: descriptorItem?.defaultItem() val actualItem = item ?: descriptorItem?.defaultItem()
val token = props.name.last()?.toString() ?: "Meta" val token = props.name.lastOrNull()?.toString() ?: "Meta"
val expanderClick: (Event) -> Unit = { val expanderClick: (Event) -> Unit = {
expanded = !expanded expanded = !expanded

View File

@ -1,6 +1,7 @@
package hep.dataforge.vision.react package hep.dataforge.vision.react
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.lastOrNull
import hep.dataforge.names.plus import hep.dataforge.names.plus
import hep.dataforge.names.startsWith import hep.dataforge.names.startsWith
import hep.dataforge.vision.Vision import hep.dataforge.vision.Vision
@ -42,7 +43,7 @@ private fun RFBuilder.objectTree(props: ObjectTreeProps): Unit {
} }
} }
val token = props.name.last()?.toString() ?: "World" val token = props.name.lastOrNull()?.toString() ?: "World"
val obj = props.obj val obj = props.obj
//display as node if any child is visible //display as node if any child is visible

View File

@ -1,22 +1,13 @@
plugins { plugins {
id("scientifik.js") id("ru.mipt.npm.js")
} }
val dataforgeVersion: String by rootProject.extra val dataforgeVersion: String by rootProject.extra
kotlin {
target {
useCommonJs()
}
}
dependencies{ dependencies{
api(project(":ui:react")) api(project(":ui:react"))
implementation(npm("@jetbrains/logos", "1.1.6")) implementation(npm("@jetbrains/logos", "1.1.6"))
implementation(npm("@jetbrains/ring-ui", "3.0.13")) implementation(npm("@jetbrains/ring-ui", "3.0.13"))
implementation(npm("svg-inline-loader", "0.8.0")) implementation(npm("svg-inline-loader", "0.8.0"))
} }

View File

@ -1,13 +1,10 @@
plugins { plugins {
id("scientifik.mpp") id("ru.mipt.npm.mpp")
} }
val dataforgeVersion: String by rootProject.extra val dataforgeVersion: String by rootProject.extra
kotlin { kotlin {
js {
useCommonJs()
}
sourceSets { sourceSets {
commonMain { commonMain {
@ -30,15 +27,15 @@ kotlin {
jsMain { jsMain {
dependencies { dependencies {
api("hep.dataforge:dataforge-output-html:$dataforgeVersion") api("hep.dataforge:dataforge-output-html:$dataforgeVersion")
api("org.jetbrains.kotlinx:kotlinx-html:0.6.12") api("org.jetbrains.kotlinx:kotlinx-html:0.7.2")
//api("org.jetbrains:kotlin-extensions:1.0.1-pre.105-kotlin-1.3.72") //api("org.jetbrains:kotlin-extensions:1.0.1-pre.105-kotlin-1.3.72")
//api("org.jetbrains:kotlin-css-js:1.0.0-pre.105-kotlin-1.3.72") //api("org.jetbrains:kotlin-css-js:1.0.0-pre.105-kotlin-1.3.72")
api("org.jetbrains:kotlin-styled:1.0.0-pre.104-kotlin-1.3.72") api("org.jetbrains:kotlin-styled:5.2.0-pre.123-kotlin-1.4.10")
api(npm("core-js", "2.6.5")) api(npm("core-js", "2.6.5"))
api(npm("inline-style-prefixer", "5.1.0")) api(npm("inline-style-prefixer", "5.1.0"))
api(npm("styled-components", "4.3.2")) api(npm("styled-components", "5.2.0"))
//api(project(":ringui-wrapper")) //api(project(":ringui-wrapper"))
} }
} }

View File

@ -4,7 +4,7 @@ import hep.dataforge.meta.*
import hep.dataforge.names.Name import hep.dataforge.names.Name
@DFExperimental @DFExperimental
class ConfigProperty(val config: Config, val name: Name) : Property<MetaItem<*>?> { internal class ConfigProperty(val config: Config, val name: Name) : Property<MetaItem<*>?> {
override var value: MetaItem<*>? override var value: MetaItem<*>?
get() = config[name] get() = config[name]
set(value) { set(value) {

View File

@ -87,13 +87,13 @@ abstract class AbstractVision : Vision {
/** /**
* Reset all properties to their default values * Reset all properties to their default values
*/ */
fun resetProperties() { public fun resetProperties() {
properties?.removeListener(this) properties?.removeListener(this)
properties = null properties = null
} }
companion object { public companion object {
val descriptor = NodeDescriptor { public val descriptor: NodeDescriptor = NodeDescriptor {
value(STYLE_KEY) { value(STYLE_KEY) {
type(ValueType.STRING) type(ValueType.STRING)
multiple = true multiple = true

View File

@ -1,9 +1,6 @@
package hep.dataforge.vision package hep.dataforge.vision
import hep.dataforge.names.Name import hep.dataforge.names.*
import hep.dataforge.names.NameToken
import hep.dataforge.names.asName
import hep.dataforge.names.isEmpty
import kotlinx.serialization.Transient import kotlinx.serialization.Transient
@ -105,7 +102,7 @@ abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup {
return when { return when {
name.isEmpty() -> error("Should be unreachable") name.isEmpty() -> error("Should be unreachable")
name.length == 1 -> { name.length == 1 -> {
val token = name.first()!! val token = name.tokens.first()
when (val current = children[token]) { when (val current = children[token]) {
null -> createGroup().also { child -> null -> createGroup().also { child ->
attach(child) attach(child)
@ -115,7 +112,7 @@ abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup {
else -> error("Can't create group with name $name because it exists and not a group") else -> error("Can't create group with name $name because it exists and not a group")
} }
} }
else -> createGroups(name.first()!!.asName()).createGroups(name.cutFirst()) else -> createGroups(name.tokens.first().asName()).createGroups(name.cutFirst())
} }
} }
@ -131,7 +128,7 @@ abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup {
} }
} }
name.length == 1 -> { name.length == 1 -> {
val token = name.first()!! val token = name.tokens.first()
if (child == null) { if (child == null) {
removeChild(token) removeChild(token)
} else { } else {
@ -142,7 +139,7 @@ abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup {
else -> { else -> {
//TODO add safety check //TODO add safety check
val parent = (get(name.cutLast()) as? MutableVisionGroup) ?: createGroups(name.cutLast()) val parent = (get(name.cutLast()) as? MutableVisionGroup) ?: createGroups(name.cutLast())
parent[name.last()!!.asName()] = child parent[name.tokens.last().asName()] = child
} }
} }
childrenChanged(name, child) childrenChanged(name, child)

View File

@ -8,20 +8,23 @@ import hep.dataforge.names.asName
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.builtins.MapSerializer import kotlinx.serialization.builtins.MapSerializer
import kotlinx.serialization.builtins.serializer import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
/** /**
* A container for styles * A container for styles
*/ */
@Serializable @Serializable
class StyleSheet private constructor(private val styleMap: MutableMap<String, Meta> = LinkedHashMap()) { public class StyleSheet private constructor(private val styleMap: MutableMap<String, Meta> = LinkedHashMap()) {
@Transient @Transient
internal var owner: Vision? = null internal var owner: Vision? = null
constructor(owner: Vision) : this() { public constructor(owner: Vision) : this() {
this.owner = owner this.owner = owner
} }
val items: Map<String, Meta> get() = styleMap public val items: Map<String, Meta> get() = styleMap
private fun Vision.styleChanged(key: String, oldStyle: Meta?, newStyle: Meta?) { private fun Vision.styleChanged(key: String, oldStyle: Meta?, newStyle: Meta?) {
@ -38,14 +41,14 @@ class StyleSheet private constructor(private val styleMap: MutableMap<String, Me
} }
} }
operator fun get(key: String): Meta? { public operator fun get(key: String): Meta? {
return styleMap[key] ?: owner?.parent?.styleSheet?.get(key) return styleMap[key] ?: owner?.parent?.styleSheet?.get(key)
} }
/** /**
* Define a style without notifying owner * Define a style without notifying owner
*/ */
fun define(key: String, style: Meta?) { public fun define(key: String, style: Meta?) {
if (style == null) { if (style == null) {
styleMap.remove(key) styleMap.remove(key)
} else { } else {
@ -56,7 +59,7 @@ class StyleSheet private constructor(private val styleMap: MutableMap<String, Me
/** /**
* Set or clear the style * Set or clear the style
*/ */
operator fun set(key: String, style: Meta?) { public operator fun set(key: String, style: Meta?) {
val oldStyle = styleMap[key] val oldStyle = styleMap[key]
define(key, style) define(key, style)
owner?.styleChanged(key, oldStyle, style) owner?.styleChanged(key, oldStyle, style)
@ -65,13 +68,14 @@ class StyleSheet private constructor(private val styleMap: MutableMap<String, Me
/** /**
* Create and set a style * Create and set a style
*/ */
operator fun set(key: String, builder: MetaBuilder.() -> Unit) { public operator fun set(key: String, builder: MetaBuilder.() -> Unit) {
val newStyle = get(key)?.edit(builder) ?: Meta(builder) val newStyle = get(key)?.edit(builder) ?: Meta(builder)
set(key, newStyle.seal()) set(key, newStyle.seal())
} }
@ExperimentalSerializationApi
@Serializer(StyleSheet::class) @Serializer(StyleSheet::class)
companion object : KSerializer<StyleSheet> { public companion object : KSerializer<StyleSheet> {
private val mapSerializer = MapSerializer(String.serializer(), MetaSerializer) private val mapSerializer = MapSerializer(String.serializer(), MetaSerializer)
override val descriptor: SerialDescriptor get() = mapSerializer.descriptor override val descriptor: SerialDescriptor get() = mapSerializer.descriptor
@ -91,14 +95,14 @@ class StyleSheet private constructor(private val styleMap: MutableMap<String, Me
/** /**
* Add style name to the list of styles to be resolved later. The style with given name does not necessary exist at the moment. * Add style name to the list of styles to be resolved later. The style with given name does not necessary exist at the moment.
*/ */
fun Vision.useStyle(name: String) { public fun Vision.useStyle(name: String) {
styles = properties[Vision.STYLE_KEY].stringList + name styles = (properties[Vision.STYLE_KEY]?.stringList ?: emptyList()) + name
} }
/** /**
* Resolve an item in all style layers * Resolve an item in all style layers
*/ */
fun Vision.getStyleItems(name: Name): Sequence<MetaItem<*>> { public fun Vision.getStyleItems(name: Name): Sequence<MetaItem<*>> {
return styles.asSequence().map { return styles.asSequence().map {
resolveStyle(it) resolveStyle(it)
}.map { }.map {
@ -109,4 +113,4 @@ fun Vision.getStyleItems(name: Name): Sequence<MetaItem<*>> {
/** /**
* Collect all styles for this object in a single laminate * Collect all styles for this object in a single laminate
*/ */
val Vision.allStyles: Laminate get() = Laminate(styles.mapNotNull(::resolveStyle)) public val Vision.allStyles: Laminate get() = Laminate(styles.mapNotNull(::resolveStyle))

View File

@ -5,7 +5,9 @@ import hep.dataforge.names.Name
import hep.dataforge.names.asName import hep.dataforge.names.asName
import hep.dataforge.names.toName import hep.dataforge.names.toName
import hep.dataforge.provider.Type import hep.dataforge.provider.Type
import hep.dataforge.values.asValue
import hep.dataforge.vision.Vision.Companion.TYPE import hep.dataforge.vision.Vision.Companion.TYPE
import hep.dataforge.vision.Vision.Companion.VISIBLE_KEY
import kotlinx.serialization.PolymorphicSerializer import kotlinx.serialization.PolymorphicSerializer
import kotlinx.serialization.Transient import kotlinx.serialization.Transient
@ -13,28 +15,28 @@ import kotlinx.serialization.Transient
* A root type for display hierarchy * A root type for display hierarchy
*/ */
@Type(TYPE) @Type(TYPE)
interface Vision : Configurable { public interface Vision : Configurable {
/** /**
* The parent object of this one. If null, this one is a root. * The parent object of this one. If null, this one is a root.
*/ */
@Transient @Transient
var parent: VisionGroup? public var parent: VisionGroup?
/** /**
* Nullable version of [config] used to check if this [Vision] has custom properties * Nullable version of [config] used to check if this [Vision] has custom properties
*/ */
val properties: Config? public val properties: Config?
/** /**
* All properties including styles and prototypes if present, including inherited ones * All properties including styles and prototypes if present, including inherited ones
*/ */
fun getAllProperties(): Laminate public fun getAllProperties(): Laminate
/** /**
* Get property (including styles). [inherit] toggles parent node property lookup * Get property (including styles). [inherit] toggles parent node property lookup
*/ */
fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? public fun getProperty(name: Name, inherit: Boolean): MetaItem<*>?
/** /**
* Ger a property including inherited values * Ger a property including inherited values
@ -44,46 +46,55 @@ interface Vision : Configurable {
/** /**
* Trigger property invalidation event. If [name] is empty, notify that the whole object is changed * Trigger property invalidation event. If [name] is empty, notify that the whole object is changed
*/ */
fun propertyChanged(name: Name): Unit public fun propertyChanged(name: Name): Unit
/** /**
* Add listener triggering on property change * Add listener triggering on property change
*/ */
fun onPropertyChange(owner: Any?, action: (Name) -> Unit): Unit public fun onPropertyChange(owner: Any?, action: (Name) -> Unit): Unit
/** /**
* Remove change listeners with given owner. * Remove change listeners with given owner.
*/ */
fun removeChangeListener(owner: Any?) public fun removeChangeListener(owner: Any?)
/** /**
* List of names of styles applied to this object. Order matters. Not inherited. * List of names of styles applied to this object. Order matters. Not inherited.
*/ */
var styles: List<String> public var styles: List<String>
get() = properties[STYLE_KEY].stringList get() = properties[STYLE_KEY]?.stringList?: emptyList()
set(value) { set(value) {
config[STYLE_KEY] = value config[STYLE_KEY] = value
} }
companion object { public companion object {
const val TYPE = "vision" public const val TYPE: String = "vision"
val STYLE_KEY = "@style".asName() public val STYLE_KEY: Name = "@style".asName()
private val VISION_SERIALIZER = PolymorphicSerializer(Vision::class) private val VISION_SERIALIZER = PolymorphicSerializer(Vision::class)
fun serializer() = VISION_SERIALIZER public fun serializer(): PolymorphicSerializer<Vision> = VISION_SERIALIZER
public val VISIBLE_KEY: Name = "visible".asName()
} }
} }
/** /**
* Get [Vision] property using key as a String * Get [Vision] property using key as a String
*/ */
fun Vision.getProperty(key: String, inherit: Boolean = true): MetaItem<*>? = public fun Vision.getProperty(key: String, inherit: Boolean = true): MetaItem<*>? =
getProperty(key.toName(), inherit) getProperty(key.toName(), inherit)
/** /**
* Find a style with given name for given [Vision]. The style is not necessary applied to this [Vision]. * Find a style with given name for given [Vision]. The style is not necessary applied to this [Vision].
*/ */
tailrec fun Vision.resolveStyle(name: String): Meta? = public tailrec fun Vision.resolveStyle(name: String): Meta? =
(this as? VisionGroup)?.styleSheet?.get(name) ?: parent?.resolveStyle(name) (this as? VisionGroup)?.styleSheet?.get(name) ?: parent?.resolveStyle(name)
/**
* Control visibility of the element
*/
public var Vision.visible: Boolean?
get() = getItem(VISIBLE_KEY).boolean
set(value) = setItem(VISIBLE_KEY, value?.asValue())

View File

@ -3,14 +3,18 @@ package hep.dataforge.vision
import hep.dataforge.names.* import hep.dataforge.names.*
import hep.dataforge.provider.Provider import hep.dataforge.provider.Provider
public interface VisionContainer<out V: Vision>{
public operator fun get(name: Name): V?
}
/** /**
* Represents a group of [Vision] instances * Represents a group of [Vision] instances
*/ */
interface VisionGroup : Provider, Vision { public interface VisionGroup : Provider, Vision, VisionContainer<Vision> {
/** /**
* A map of top level named children * A map of top level named children
*/ */
val children: Map<NameToken, Vision> public val children: Map<NameToken, Vision>
override val defaultTarget: String get() = Vision.TYPE override val defaultTarget: String get() = Vision.TYPE
@ -18,17 +22,17 @@ interface VisionGroup : Provider, Vision {
* A stylesheet for this group and its descendants. Stylesheet is not applied directly, * A stylesheet for this group and its descendants. Stylesheet is not applied directly,
* but instead is just a repository for named configurations. * but instead is just a repository for named configurations.
*/ */
val styleSheet: StyleSheet? public val styleSheet: StyleSheet?
/** /**
* A map of direct children for specific target * A map of direct children for specific target
* (currently "visual" or "style") * (currently "visual" or "style")
*/ */
override fun provideTop(target: String): Map<Name, Any> = override fun content(target: String): Map<Name, Any> =
when (target) { when (target) {
Vision.TYPE -> children.flatMap { (key, value) -> Vision.TYPE -> children.flatMap { (key, value) ->
val res: Map<Name, Any> = if (value is VisionGroup) { val res: Map<Name, Any> = if (value is VisionGroup) {
value.provideTop(target).mapKeys { key + it.key } value.content(target).mapKeys { key + it.key }
} else { } else {
mapOf(key.asName() to value) mapOf(key.asName() to value)
} }
@ -38,18 +42,18 @@ interface VisionGroup : Provider, Vision {
else -> emptyMap() else -> emptyMap()
} }
operator fun get(name: Name): Vision? { public override operator fun get(name: Name): Vision? {
return when { return when {
name.isEmpty() -> this name.isEmpty() -> this
name.length == 1 -> children[name.first()!!] name.length == 1 -> children[name.tokens.first()]
else -> (children[name.first()!!] as? VisionGroup)?.get(name.cutFirst()) else -> (children[name.tokens.first()] as? VisionGroup)?.get(name.cutFirst())
} }
} }
/** /**
* A fix for serialization bug that writes all proper parents inside the tree after deserialization * A fix for serialization bug that writes all proper parents inside the tree after deserialization
*/ */
fun attachChildren() { public fun attachChildren() {
styleSheet?.owner = this styleSheet?.owner = this
children.values.forEach { children.values.forEach {
it.parent = this it.parent = this
@ -57,41 +61,45 @@ interface VisionGroup : Provider, Vision {
} }
} }
companion object { public companion object {
const val STYLE_TARGET = "style" public const val STYLE_TARGET: String = "style"
} }
} }
/** /**
* Iterate over children of this group * Iterate over children of this group
*/ */
operator fun VisionGroup.iterator(): Iterator<Vision> = children.values.iterator() public operator fun VisionGroup.iterator(): Iterator<Vision> = children.values.iterator()
val VisionGroup.isEmpty: Boolean get() = this.children.isEmpty() public val VisionGroup.isEmpty: Boolean get() = this.children.isEmpty()
public interface VisionContainerBuilder<in V: Vision>{
public operator fun set(name: Name, child: V?)
}
/** /**
* Mutable version of [VisionGroup] * Mutable version of [VisionGroup]
*/ */
interface MutableVisionGroup : VisionGroup { public interface MutableVisionGroup : VisionGroup, VisionContainerBuilder<Vision> {
/** /**
* Add listener for children structure change. * Add listener for children structure change.
* @param owner the handler to properly remove listeners * @param owner the handler to properly remove listeners
* @param action First argument of the action is the name of changed child. Second argument is the new value of the object. * @param action First argument of the action is the name of changed child. Second argument is the new value of the object.
*/ */
fun onChildrenChange(owner: Any?, action: (Name, Vision?) -> Unit) public fun onChildrenChange(owner: Any?, action: (Name, Vision?) -> Unit)
/** /**
* Remove children change listener * Remove children change listener
*/ */
fun removeChildrenChangeListener(owner: Any?) public fun removeChildrenChangeListener(owner: Any?)
operator fun set(name: Name, child: Vision?) // public operator fun set(name: Name, child: Vision?)
} }
operator fun VisionGroup.get(str: String?): Vision? = get(str?.toName() ?: Name.EMPTY) public operator fun <V: Vision> VisionContainer<V>.get(str: String?): V? = get(str?.toName() ?: Name.EMPTY)
operator fun MutableVisionGroup.set(token: NameToken, child: Vision?): Unit = set(token.asName(), child) public operator fun <V: Vision> VisionContainerBuilder<V>.set(token: NameToken, child: V?): Unit = set(token.asName(), child)
operator fun MutableVisionGroup.set(key: String, child: Vision?): Unit = set(key.toName(), child) public operator fun <V: Vision> VisionContainerBuilder<V>.set(key: String, child: V?): Unit = set(key.toName(), child)
fun MutableVisionGroup.removeAll() = children.keys.map { it.asName() }.forEach { this[it] = null } public fun MutableVisionGroup.removeAll(): Unit = children.keys.map { it.asName() }.forEach { this[it] = null }

View File

@ -3,35 +3,37 @@ package hep.dataforge.vision
import hep.dataforge.context.* import hep.dataforge.context.*
import hep.dataforge.meta.* import hep.dataforge.meta.*
import hep.dataforge.meta.descriptors.NodeDescriptor import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.names.Name
import hep.dataforge.names.toName import hep.dataforge.names.toName
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.UnstableDefault
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration
import kotlinx.serialization.modules.SerialModule
import kotlinx.serialization.modules.SerializersModule import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.polymorphic
import kotlinx.serialization.modules.subclass
import kotlin.reflect.KClass import kotlin.reflect.KClass
@DFExperimental @DFExperimental
interface VisionForm<T : Vision> { public interface VisionForm<T : Vision> {
val type: KClass<out T> public val type: KClass<out T>
val serializer: KSerializer<T> public val serializer: KSerializer<T>
val name get() = serializer.descriptor.serialName.toName() public val name: Name
get() = serializer.descriptor.serialName.toName()
/** /**
* Apply a patch to given [Vision] * Apply a patch to given [Vision]
*/ */
fun patch(obj: T, meta: Meta) public fun patch(obj: T, meta: Meta)
companion object { public companion object {
const val TYPE = "visionForm" public const val TYPE: String = "visionForm"
} }
} }
@DFExperimental @DFExperimental
object SimpleGroupForm: VisionForm<SimpleVisionGroup>{ public object SimpleGroupForm : VisionForm<SimpleVisionGroup> {
override val type: KClass<out SimpleVisionGroup> = SimpleVisionGroup::class override val type: KClass<out SimpleVisionGroup> = SimpleVisionGroup::class
override val serializer: KSerializer<SimpleVisionGroup> = SimpleVisionGroup.serializer() override val serializer: KSerializer<SimpleVisionGroup> = SimpleVisionGroup.serializer()
@ -42,86 +44,93 @@ object SimpleGroupForm: VisionForm<SimpleVisionGroup>{
} }
@DFExperimental @DFExperimental
fun <T : Vision> VisionForm<T>.visionToMeta(vision: T, module: SerialModule, descriptor: NodeDescriptor? = null): Meta { public fun <T : Vision> VisionForm<T>.visionToMeta(
val engine = Json(VisionManager.jsonConfiguration, module) vision: T,
val json = engine.toJson<T>(serializer, vision) module: SerializersModule,
descriptor: NodeDescriptor? = null,
): Meta {
val engine = Json(VisionManager.jsonConfiguration) { serializersModule = module }
val json = engine.encodeToJsonElement(serializer, vision)
return json.toMetaItem(descriptor).node!! return json.toMetaItem(descriptor).node!!
} }
@DFExperimental @DFExperimental
fun <T : Vision> VisionForm<T>.buildVision(meta: Meta, module: SerialModule, descriptor: NodeDescriptor? = null): T { public fun <T : Vision> VisionForm<T>.buildVision(
val engine = Json(VisionManager.jsonConfiguration, module) meta: Meta,
module: SerializersModule,
descriptor: NodeDescriptor? = null,
): T {
val engine = Json(VisionManager.jsonConfiguration) { serializersModule = module }
val json = meta.toJson(descriptor) val json = meta.toJson(descriptor)
return engine.fromJson(serializer, json) return engine.decodeFromJsonElement(serializer, json)
} }
@DFExperimental @DFExperimental
class VisionManager(meta: Meta) : AbstractPlugin(meta) { public class VisionManager(meta: Meta) : AbstractPlugin(meta) {
override val tag: PluginTag get() = Companion.tag override val tag: PluginTag get() = Companion.tag
/** /**
* Create a list of factories on first call and cache it * Create a list of factories on first call and cache it
*/ */
private val forms by lazy { private val forms by lazy {
context.content<VisionForm<*>>(VisionForm.TYPE).mapKeys { it.value.type } context.gather<VisionForm<*>>(VisionForm.TYPE).mapKeys { it.value.type }
} }
val visionSerialModule public val visionSerialModule: SerializersModule
get() = SerializersModule { get() = SerializersModule {
include(defaultSerialModule) include(defaultSerialModule)
context.content<SerialModule>(VISION_SERIAL_MODULE_TARGET).values.forEach { context.gather<SerializersModule>(VISION_SERIAL_MODULE_TARGET).values.forEach {
include(it) include(it)
} }
} }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
fun <T : Vision> resolveVisionForm(type: KClass<out T>): VisionForm<T>? = public fun <T : Vision> resolveVisionForm(type: KClass<out T>): VisionForm<T> =
forms[type] as VisionForm<T> forms[type] as VisionForm<T>
inline fun <reified T : Vision> buildSpecificVision(meta: Meta): T { public inline fun <reified T : Vision> buildSpecificVision(meta: Meta): T {
val factory = resolveVisionForm(T::class) ?: error("Could not resolve a form for ${meta["type"].string}") val factory = resolveVisionForm(T::class) ?: error("Could not resolve a form for ${meta["type"].string}")
return factory.buildVision(meta, visionSerialModule) return factory.buildVision(meta, visionSerialModule)
} }
fun buildVision(meta: Meta): Vision { @OptIn(ExperimentalSerializationApi::class)
public fun buildVision(meta: Meta): Vision {
val type = meta["type"].string ?: Vision.serializer().descriptor.serialName val type = meta["type"].string ?: Vision.serializer().descriptor.serialName
val form = forms.values.find { it.name.toString() == type } ?: error("Could not resolve a form for type $type") val form = forms.values.find { it.name.toString() == type } ?: error("Could not resolve a form for type $type")
return form.buildVision(meta, visionSerialModule) return form.buildVision(meta, visionSerialModule)
} }
fun <T : Vision> writeVisionToMeta(vision: T): Meta { public fun <T : Vision> writeVisionToMeta(vision: T): Meta {
val form = resolveVisionForm(vision::class) ?: error("Could not resolve a form for $vision") val form = resolveVisionForm(vision::class) ?: error("Could not resolve a form for $vision")
val engine = Json(VisionManager.jsonConfiguration, visionSerialModule) val engine = Json(jsonConfiguration) { serializersModule = visionSerialModule }
val json = engine.toJson(form.serializer,vision) val json = engine.encodeToJsonElement(form.serializer, vision)
return json.toMetaItem().node!! return json.toMetaItem().node!!
} }
fun patchVision(vision: Vision, meta: Meta) { public fun patchVision(vision: Vision, meta: Meta) {
val form = resolveVisionForm(vision::class) ?: error("Could not resolve a form for $vision") val form = resolveVisionForm(vision::class) ?: error("Could not resolve a form for $vision")
form.patch(vision, meta) form.patch(vision, meta)
} }
companion object : PluginFactory<VisionManager> { public companion object : PluginFactory<VisionManager> {
override val tag: PluginTag = PluginTag(name = "vision", group = PluginTag.DATAFORGE_GROUP) override val tag: PluginTag = PluginTag(name = "vision", group = PluginTag.DATAFORGE_GROUP)
override val type: KClass<out VisionManager> = VisionManager::class override val type: KClass<out VisionManager> = VisionManager::class
const val VISION_SERIAL_MODULE_TARGET = "visionSerialModule" public const val VISION_SERIAL_MODULE_TARGET: String = "visionSerialModule"
override fun invoke(meta: Meta, context: Context): VisionManager = VisionManager(meta) override fun invoke(meta: Meta, context: Context): VisionManager = VisionManager(meta)
@OptIn(UnstableDefault::class) public val jsonConfiguration: Json = Json {
val jsonConfiguration = JsonConfiguration( prettyPrint = true
prettyPrint = true, useArrayPolymorphism = false
useArrayPolymorphism = false, encodeDefaults = false
encodeDefaults = false,
ignoreUnknownKeys = true ignoreUnknownKeys = true
) }
val defaultSerialModule = SerializersModule { public val defaultSerialModule: SerializersModule = SerializersModule {
polymorphic(Vision::class, VisionGroup::class) { polymorphic(Vision::class) {
subclass(SimpleVisionGroup.serializer()) subclass(SimpleVisionGroup.serializer())
} }
} }
} }
} }

View File

@ -1,27 +1,27 @@
package hep.dataforge.vision package hep.dataforge.vision
import hep.dataforge.meta.Meta import hep.dataforge.meta.*
import hep.dataforge.meta.descriptors.ValueDescriptor import hep.dataforge.meta.descriptors.ValueDescriptor
import hep.dataforge.meta.descriptors.setAttribute import hep.dataforge.meta.descriptors.attributes
import hep.dataforge.meta.get
import hep.dataforge.meta.node
import hep.dataforge.meta.string
import hep.dataforge.names.toName
/** /**
* Extension property to access the "widget" key of [ValueDescriptor] * Extension property to access the "widget" key of [ValueDescriptor]
*/ */
var ValueDescriptor.widget: Meta public var ValueDescriptor.widget: Meta
get() = attributes["widget"].node ?: Meta.EMPTY get() = attributes["widget"].node ?: Meta.EMPTY
set(value) { set(value) {
setAttribute("widget".toName(), value) attributes {
set("widget", value)
}
} }
/** /**
* Extension property to access the "widget.type" key of [ValueDescriptor] * Extension property to access the "widget.type" key of [ValueDescriptor]
*/ */
var ValueDescriptor.widgetType: String? public var ValueDescriptor.widgetType: String?
get() = attributes["widget.type"].string get() = attributes["widget.type"].string
set(value) { set(value) {
setAttribute("widget.type".toName(), value) attributes{
set("widget.type", value)
}
} }

View File

@ -1,6 +1,7 @@
package hep.dataforge.vision.visitor package hep.dataforge.vision.visitor
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.length
import hep.dataforge.vision.Vision import hep.dataforge.vision.Vision
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job import kotlinx.coroutines.Job

View File

@ -4,10 +4,7 @@ import hep.dataforge.meta.*
import hep.dataforge.meta.descriptors.ItemDescriptor import hep.dataforge.meta.descriptors.ItemDescriptor
import hep.dataforge.meta.descriptors.NodeDescriptor import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.meta.descriptors.ValueDescriptor import hep.dataforge.meta.descriptors.ValueDescriptor
import hep.dataforge.names.Name import hep.dataforge.names.*
import hep.dataforge.names.NameToken
import hep.dataforge.names.asName
import hep.dataforge.names.withIndex
import hep.dataforge.values.Null import hep.dataforge.values.Null
import hep.dataforge.values.Value import hep.dataforge.values.Value
import javafx.beans.binding.ListBinding import javafx.beans.binding.ListBinding
@ -137,12 +134,12 @@ class FXMetaNode<M : MetaNode<M>>(
} }
} }
class FXMetaValue<M : MetaNode<M>>( public class FXMetaValue<M : MetaNode<M>>(
override val name: NameToken, override val name: NameToken,
override val parent: FXMetaNode<M> override val parent: FXMetaNode<M>
) : FXMeta<M>() { ) : FXMeta<M>() {
val descriptorProperty = parent.descriptorProperty.objectBinding { public val descriptorProperty = parent.descriptorProperty.objectBinding {
it?.values?.get(name.body) it?.values?.get(name.body)
} }
@ -153,24 +150,24 @@ class FXMetaValue<M : MetaNode<M>>(
//private val innerValueProperty = SimpleObjectProperty(value) //private val innerValueProperty = SimpleObjectProperty(value)
val valueProperty = descriptorProperty.objectBinding { descriptor -> public val valueProperty = descriptorProperty.objectBinding { descriptor ->
parent.node[name].value ?: descriptor?.default parent.node[name].value ?: descriptor?.default
} }
override val hasValue: ObservableBooleanValue = parent.nodeProperty.booleanBinding { it[name] != null } override val hasValue: ObservableBooleanValue = parent.nodeProperty.booleanBinding { it[name] != null }
val value by valueProperty public val value by valueProperty
override val descriptionProperty = descriptorProperty.stringBinding { it?.info ?: "" } override val descriptionProperty = descriptorProperty.stringBinding { it?.info ?: "" }
} }
fun <M : MutableMeta<M>> FXMetaNode<M>.remove(name: NameToken) { public fun <M : MutableMeta<M>> FXMetaNode<M>.remove(name: NameToken) {
node?.remove(name.asName()) node?.remove(name.asName())
children.invalidate() children.invalidate()
} }
private fun <M : MutableMeta<M>> M.createEmptyNode(token: NameToken, append: Boolean): M { private fun <M : MutableMeta<M>> M.createEmptyNode(token: NameToken, append: Boolean): M {
return if (append && token.index.isNotEmpty()) { return if (append && token.hasIndex()) {
val name = token.asName() val name = token.asName()
val index = (getIndexed(name).keys.mapNotNull { it.toIntOrNull() }.max() ?: -1) + 1 val index = (getIndexed(name).keys.mapNotNull { it.toIntOrNull() }.max() ?: -1) + 1
val newName = name.withIndex(index.toString()) val newName = name.withIndex(index.toString())

View File

@ -1,5 +1,5 @@
plugins { plugins {
id("scientifik.mpp") id("ru.mipt.npm.mpp")
} }
kotlin { kotlin {
@ -7,7 +7,7 @@ kotlin {
val commonMain by getting { val commonMain by getting {
dependencies { dependencies {
api(project(":visionforge-solid")) api(project(":visionforge-solid"))
api("scientifik:gdml:0.1.8") api("kscience.gdml:gdml:0.2.0-dev-2")
} }
} }
} }

View File

@ -12,7 +12,7 @@ import hep.dataforge.vision.set
import hep.dataforge.vision.solid.* import hep.dataforge.vision.solid.*
import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY
import hep.dataforge.vision.useStyle import hep.dataforge.vision.useStyle
import scientifik.gdml.* import kscience.gdml.*
import kotlin.math.cos import kotlin.math.cos
import kotlin.math.sin import kotlin.math.sin
import kotlin.random.Random import kotlin.random.Random
@ -20,7 +20,7 @@ import kotlin.random.Random
private val solidsName = "solids".asName() private val solidsName = "solids".asName()
private val volumesName = "volumes".asName() private val volumesName = "volumes".asName()
class GDMLTransformer internal constructor(val root: GDML) { public class GDMLTransformer internal constructor(val root: GDML) {
//private val materialCache = HashMap<GDMLMaterial, Meta>() //private val materialCache = HashMap<GDMLMaterial, Meta>()
private val random = Random(222) private val random = Random(222)

View File

@ -1,70 +0,0 @@
package hep.dataforge.vision.gdml
import scientifik.gdml.AUnit
import scientifik.gdml.GDMLPosition
import scientifik.gdml.GDMLRotation
import scientifik.gdml.GDMLSolid
enum class LUnit(val value: Float) {
MM(1f),
CM(10f),
M(1000f)
}
fun GDMLPosition.unit(): LUnit = LUnit.valueOf(unit.toUpperCase())
fun GDMLPosition.x(unit: LUnit): Float = if (unit.name == this.unit) {
x.toFloat()
} else {
x.toFloat() / unit.value * unit().value
}
fun GDMLPosition.y(unit: LUnit): Float = if (unit.name == this.unit) {
y.toFloat()
} else {
y.toFloat() / unit.value * unit().value
}
fun GDMLPosition.z(unit: LUnit): Float = if (unit.name == this.unit) {
z.toFloat()
} else {
z.toFloat() / unit.value * unit().value
}
fun GDMLRotation.unit(): AUnit = AUnit.valueOf(unit.toUpperCase())
fun GDMLRotation.x(unit: AUnit = AUnit.RAD): Float = if (unit.name == this.unit) {
x.toFloat()
} else {
x.toFloat() / unit.value * unit().value
}
fun GDMLRotation.y(unit: AUnit = AUnit.RAD): Float = if (unit.name == this.unit) {
y.toFloat()
} else {
y.toFloat() / unit.value * unit().value
}
fun GDMLRotation.z(unit: AUnit = AUnit.RAD): Float = if (unit.name == this.unit) {
z.toFloat()
} else {
z.toFloat() / unit.value * unit().value
}
fun GDMLSolid.lscale(unit: LUnit): Float {
val solidUnit = lunit?.let { LUnit.valueOf(it.toUpperCase()) } ?: return 1f
return if (solidUnit == unit) {
1f
} else {
solidUnit.value / unit.value
}
}
fun GDMLSolid.ascale(unit: AUnit = AUnit.RAD): Float {
val solidUnit = aunit?.let { AUnit.valueOf(it.toUpperCase()) } ?: return 1f
return if (solidUnit == unit) {
1f
} else {
solidUnit.value / unit.value
}
}

View File

@ -2,7 +2,7 @@ package hep.dataforge.vision.gdml
import hep.dataforge.vision.solid.SolidGroup import hep.dataforge.vision.solid.SolidGroup
import nl.adaptivity.xmlutil.StAXReader import nl.adaptivity.xmlutil.StAXReader
import scientifik.gdml.GDML import kscience.gdml.GDML
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Path import java.nio.file.Path
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger

View File

@ -1,9 +1,9 @@
package hep.dataforge.vision.gdml package hep.dataforge.vision.gdml
import hep.dataforge.vision.solid.stringify import hep.dataforge.vision.solid.encodeToString
import nl.adaptivity.xmlutil.StAXReader import nl.adaptivity.xmlutil.StAXReader
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import scientifik.gdml.GDML import kscience.gdml.GDML
class TestConvertor { class TestConvertor {
@ -13,7 +13,7 @@ class TestConvertor {
val xmlReader = StAXReader(stream, "UTF-8") val xmlReader = StAXReader(stream, "UTF-8")
val xml = GDML.format.parse(GDML.serializer(), xmlReader) val xml = GDML.format.parse(GDML.serializer(), xmlReader)
val vision = xml.toVision() val vision = xml.toVision()
println(vision.stringify()) println(vision.encodeToString())
} }
@Test @Test
@ -33,6 +33,6 @@ class TestConvertor {
val xmlReader = StAXReader(stream, "UTF-8") val xmlReader = StAXReader(stream, "UTF-8")
val xml = GDML.format.parse(GDML.serializer(), xmlReader) val xml = GDML.format.parse(GDML.serializer(), xmlReader)
val visual = xml.toVision() val visual = xml.toVision()
println(visual.stringify()) println(visual.encodeToString())
} }
} }

View File

@ -8,7 +8,7 @@ import hep.dataforge.vision.visitor.flowStatistics
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import nl.adaptivity.xmlutil.StAXReader import nl.adaptivity.xmlutil.StAXReader
import scientifik.gdml.GDML import kscience.gdml.GDML
import java.io.File import java.io.File
import kotlin.reflect.KClass import kotlin.reflect.KClass

View File

@ -1,15 +1,14 @@
import scientifik.useSerialization import ru.mipt.npm.gradle.KScienceVersions.coroutinesVersion
plugins { plugins {
id("scientifik.mpp") id("ru.mipt.npm.mpp")
} }
kscience {
useSerialization() useSerialization()
}
kotlin { kotlin {
js {
useCommonJs()
}
sourceSets { sourceSets {
commonMain { commonMain {
@ -22,7 +21,7 @@ kotlin {
api("org.fxyz3d:fxyz3d:0.5.2") { api("org.fxyz3d:fxyz3d:0.5.2") {
exclude(module = "slf4j-simple") exclude(module = "slf4j-simple")
} }
api("org.jetbrains.kotlinx:kotlinx-coroutines-javafx:${Scientifik.coroutinesVersion}") api("org.jetbrains.kotlinx:kotlinx-coroutines-javafx:${coroutinesVersion}")
implementation("eu.mihosoft.vrl.jcsg:jcsg:0.5.7") { implementation("eu.mihosoft.vrl.jcsg:jcsg:0.5.7") {
exclude(module = "slf4j-simple") exclude(module = "slf4j-simple")
} }

View File

@ -5,6 +5,7 @@ package hep.dataforge.vision.solid
import hep.dataforge.meta.Config import hep.dataforge.meta.Config
import hep.dataforge.vision.AbstractVision import hep.dataforge.vision.AbstractVision
import hep.dataforge.vision.MutableVisionGroup import hep.dataforge.vision.MutableVisionGroup
import hep.dataforge.vision.VisionContainerBuilder
import hep.dataforge.vision.set import hep.dataforge.vision.set
import hep.dataforge.vision.solid.Solid.Companion.solidEquals import hep.dataforge.vision.solid.Solid.Companion.solidEquals
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
@ -13,10 +14,10 @@ import kotlinx.serialization.UseSerializers
@Serializable @Serializable
@SerialName("solid.box") @SerialName("solid.box")
class Box( public class Box(
val xSize: Float, public val xSize: Float,
val ySize: Float, public val ySize: Float,
val zSize: Float public val zSize: Float
) : AbstractVision(), GeometrySolid { ) : AbstractVision(), GeometrySolid {
override var position: Point3D? = null override var position: Point3D? = null
@ -67,15 +68,15 @@ class Box(
} }
companion object { public companion object {
} }
} }
inline fun MutableVisionGroup.box( public inline fun VisionContainerBuilder<Solid>.box(
xSize: Number, xSize: Number,
ySize: Number, ySize: Number,
zSize: Number, zSize: Number,
name: String = "", name: String = "",
action: Box.() -> Unit = {} action: Box.() -> Unit = {}
) = Box(xSize.toFloat(), ySize.toFloat(), zSize.toFloat()).apply(action).also { set(name, it) } ): Box = Box(xSize.toFloat(), ySize.toFloat(), zSize.toFloat()).apply(action).also { set(name, it) }

View File

@ -10,7 +10,7 @@ import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers import kotlinx.serialization.UseSerializers
enum class CompositeType { public enum class CompositeType {
UNION, UNION,
INTERSECT, INTERSECT,
SUBTRACT SUBTRACT
@ -18,10 +18,10 @@ enum class CompositeType {
@Serializable @Serializable
@SerialName("solid.composite") @SerialName("solid.composite")
class Composite( public class Composite(
val compositeType: CompositeType, public val compositeType: CompositeType,
val first: Solid, public val first: Solid,
val second: Solid public val second: Solid
) : AbstractVision(), Solid, VisionGroup { ) : AbstractVision(), Solid, VisionGroup {
init { init {
@ -42,7 +42,7 @@ class Composite(
get() = null get() = null
} }
inline fun MutableVisionGroup.composite( public inline fun MutableVisionGroup.composite(
type: CompositeType, type: CompositeType,
name: String = "", name: String = "",
builder: SolidGroup.() -> Unit builder: SolidGroup.() -> Unit
@ -67,11 +67,11 @@ inline fun MutableVisionGroup.composite(
} }
} }
inline fun MutableVisionGroup.union(name: String = "", builder: SolidGroup.() -> Unit) = public inline fun MutableVisionGroup.union(name: String = "", builder: SolidGroup.() -> Unit): Composite =
composite(CompositeType.UNION, name, builder = builder) composite(CompositeType.UNION, name, builder = builder)
inline fun MutableVisionGroup.subtract(name: String = "", builder: SolidGroup.() -> Unit) = public inline fun MutableVisionGroup.subtract(name: String = "", builder: SolidGroup.() -> Unit): Composite =
composite(CompositeType.SUBTRACT, name, builder = builder) composite(CompositeType.SUBTRACT, name, builder = builder)
inline fun MutableVisionGroup.intersect(name: String = "", builder: SolidGroup.() -> Unit) = public inline fun MutableVisionGroup.intersect(name: String = "", builder: SolidGroup.() -> Unit): Composite =
composite(CompositeType.INTERSECT, name, builder = builder) composite(CompositeType.INTERSECT, name, builder = builder)

View File

@ -5,6 +5,7 @@ package hep.dataforge.vision.solid
import hep.dataforge.meta.Config import hep.dataforge.meta.Config
import hep.dataforge.vision.AbstractVision import hep.dataforge.vision.AbstractVision
import hep.dataforge.vision.MutableVisionGroup import hep.dataforge.vision.MutableVisionGroup
import hep.dataforge.vision.VisionContainerBuilder
import hep.dataforge.vision.set import hep.dataforge.vision.set
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@ -17,12 +18,12 @@ import kotlin.math.sin
*/ */
@Serializable @Serializable
@SerialName("solid.cone") @SerialName("solid.cone")
class ConeSegment( public class ConeSegment(
var radius: Float, public var radius: Float,
var height: Float, public var height: Float,
var upperRadius: Float, public var upperRadius: Float,
var startAngle: Float = 0f, public var startAngle: Float = 0f,
var angle: Float = PI2 public var angle: Float = PI2
) : AbstractVision(), GeometrySolid { ) : AbstractVision(), GeometrySolid {
override var properties: Config? = null override var properties: Config? = null
@ -75,7 +76,7 @@ class ConeSegment(
} }
inline fun MutableVisionGroup.cylinder( public inline fun VisionContainerBuilder<Solid>.cylinder(
r: Number, r: Number,
height: Number, height: Number,
name: String = "", name: String = "",
@ -87,7 +88,7 @@ inline fun MutableVisionGroup.cylinder(
).apply(block).also { set(name, it) } ).apply(block).also { set(name, it) }
inline fun MutableVisionGroup.cone( public inline fun VisionContainerBuilder<Solid>.cone(
bottomRadius: Number, bottomRadius: Number,
height: Number, height: Number,
upperRadius: Number = 0.0, upperRadius: Number = 0.0,

View File

@ -5,6 +5,7 @@ package hep.dataforge.vision.solid
import hep.dataforge.meta.Config import hep.dataforge.meta.Config
import hep.dataforge.vision.AbstractVision import hep.dataforge.vision.AbstractVision
import hep.dataforge.vision.MutableVisionGroup import hep.dataforge.vision.MutableVisionGroup
import hep.dataforge.vision.VisionContainerBuilder
import hep.dataforge.vision.set import hep.dataforge.vision.set
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@ -12,7 +13,7 @@ import kotlinx.serialization.UseSerializers
@Serializable @Serializable
@SerialName("solid.convex") @SerialName("solid.convex")
class Convex(val points: List<Point3D>) : AbstractVision(), Solid { public class Convex(public val points: List<Point3D>) : AbstractVision(), Solid {
override var properties: Config? = null override var properties: Config? = null
@ -23,17 +24,17 @@ class Convex(val points: List<Point3D>) : AbstractVision(), Solid {
} }
inline fun MutableVisionGroup.convex(name: String = "", action: ConvexBuilder.() -> Unit = {}) = public inline fun VisionContainerBuilder<Solid>.convex(name: String = "", action: ConvexBuilder.() -> Unit = {}): Convex =
ConvexBuilder().apply(action).build().also { set(name, it) } ConvexBuilder().apply(action).build().also { set(name, it) }
class ConvexBuilder { public class ConvexBuilder {
private val points = ArrayList<Point3D>() private val points = ArrayList<Point3D>()
fun point(x: Number, y: Number, z: Number) { public fun point(x: Number, y: Number, z: Number) {
points.add(Point3D(x, y, z)) points.add(Point3D(x, y, z))
} }
fun build(): Convex { public fun build(): Convex {
return Convex(points) return Convex(points)
} }
} }

View File

@ -4,6 +4,7 @@ package hep.dataforge.vision.solid
import hep.dataforge.meta.Config import hep.dataforge.meta.Config
import hep.dataforge.vision.AbstractVision import hep.dataforge.vision.AbstractVision
import hep.dataforge.vision.MutableVisionGroup import hep.dataforge.vision.MutableVisionGroup
import hep.dataforge.vision.VisionContainerBuilder
import hep.dataforge.vision.set import hep.dataforge.vision.set
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@ -13,21 +14,21 @@ import kotlin.math.cos
import kotlin.math.sin import kotlin.math.sin
typealias Shape2D = List<Point2D> public typealias Shape2D = List<Point2D>
@Serializable @Serializable
class Shape2DBuilder(private val points: MutableList<Point2D> = ArrayList()) { public class Shape2DBuilder(private val points: MutableList<Point2D> = ArrayList()) {
fun point(x: Number, y: Number) { public fun point(x: Number, y: Number) {
points.add(Point2D(x, y)) points.add(Point2D(x, y))
} }
infix fun Number.to(y: Number) = point(this, y) public infix fun Number.to(y: Number): Unit = point(this, y)
fun build(): Shape2D = points public fun build(): Shape2D = points
} }
fun Shape2DBuilder.polygon(vertices: Int, radius: Number) { public fun Shape2DBuilder.polygon(vertices: Int, radius: Number) {
require(vertices > 2) { "Polygon must have more than 2 vertices" } require(vertices > 2) { "Polygon must have more than 2 vertices" }
val angle = 2 * PI / vertices val angle = 2 * PI / vertices
for (i in 0 until vertices) { for (i in 0 until vertices) {
@ -36,13 +37,13 @@ fun Shape2DBuilder.polygon(vertices: Int, radius: Number) {
} }
@Serializable @Serializable
data class Layer(var x: Float, var y: Float, var z: Float, var scale: Float) public data class Layer(var x: Float, var y: Float, var z: Float, var scale: Float)
@Serializable @Serializable
@SerialName("solid.extrude") @SerialName("solid.extrude")
class Extruded( public class Extruded(
var shape: List<Point2D> = ArrayList(), public var shape: List<Point2D> = ArrayList(),
var layers: MutableList<Layer> = ArrayList() public var layers: MutableList<Layer> = ArrayList()
) : AbstractVision(), GeometrySolid { ) : AbstractVision(), GeometrySolid {
override var properties: Config? = null override var properties: Config? = null
@ -51,12 +52,12 @@ class Extruded(
override var rotation: Point3D? = null override var rotation: Point3D? = null
override var scale: Point3D? = null override var scale: Point3D? = null
fun shape(block: Shape2DBuilder.() -> Unit) { public fun shape(block: Shape2DBuilder.() -> Unit) {
this.shape = Shape2DBuilder().apply(block).build() this.shape = Shape2DBuilder().apply(block).build()
//TODO send invalidation signal //TODO send invalidation signal
} }
fun layer(z: Number, x: Number = 0.0, y: Number = 0.0, scale: Number = 1.0) { public fun layer(z: Number, x: Number = 0.0, y: Number = 0.0, scale: Number = 1.0) {
layers.add(Layer(x.toFloat(), y.toFloat(), z.toFloat(), scale.toFloat())) layers.add(Layer(x.toFloat(), y.toFloat(), z.toFloat(), scale.toFloat()))
//TODO send invalidation signal //TODO send invalidation signal
} }
@ -107,10 +108,10 @@ class Extruded(
geometryBuilder.cap(layers.last()) geometryBuilder.cap(layers.last())
} }
companion object { public companion object {
const val TYPE = "geometry.3d.extruded" public const val TYPE: String = "solid.extruded"
} }
} }
fun MutableVisionGroup.extrude(name: String = "", action: Extruded.() -> Unit = {}) = public fun VisionContainerBuilder<Solid>.extrude(name: String = "", action: Extruded.() -> Unit = {}): Extruded =
Extruded().apply(action).also { set(name, it) } Extruded().apply(action).also { set(name, it) }

View File

@ -5,7 +5,7 @@ import hep.dataforge.meta.Meta
/** /**
* @param T the type of resulting geometry * @param T the type of resulting geometry
*/ */
interface GeometryBuilder<T : Any> { public interface GeometryBuilder<T : Any> {
/** /**
* Add a face to 3D model. If one of the vertices is not present in the current geometry model list of vertices, * Add a face to 3D model. If one of the vertices is not present in the current geometry model list of vertices,
* it is added automatically. * it is added automatically.
@ -13,12 +13,12 @@ interface GeometryBuilder<T : Any> {
* @param normal optional external normal to the face * @param normal optional external normal to the face
* @param meta optional additional platform-specific parameters like color or texture index * @param meta optional additional platform-specific parameters like color or texture index
*/ */
fun face(vertex1: Point3D, vertex2: Point3D, vertex3: Point3D, normal: Point3D? = null, meta: Meta = Meta.EMPTY) public fun face(vertex1: Point3D, vertex2: Point3D, vertex3: Point3D, normal: Point3D? = null, meta: Meta = Meta.EMPTY)
fun build(): T public fun build(): T
} }
fun GeometryBuilder<*>.face4( public fun GeometryBuilder<*>.face4(
vertex1: Point3D, vertex1: Point3D,
vertex2: Point3D, vertex2: Point3D,
vertex3: Point3D, vertex3: Point3D,
@ -33,11 +33,11 @@ fun GeometryBuilder<*>.face4(
/** /**
* [GeometrySolid] is a [Solid] that can represent its own geometry as a set of polygons. * [GeometrySolid] is a [Solid] that can represent its own geometry as a set of polygons.
*/ */
interface GeometrySolid : Solid { public interface GeometrySolid : Solid {
fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) public fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>)
} }
fun <T : Any> GeometryBuilder<T>.cap(shape: List<Point3D>, normal: Point3D? = null) { public fun <T : Any> GeometryBuilder<T>.cap(shape: List<Point3D>, normal: Point3D? = null) {
//FIXME won't work for non-convex shapes //FIXME won't work for non-convex shapes
val center = Point3D( val center = Point3D(
shape.map { it.x }.average(), shape.map { it.x }.average(),

View File

@ -4,10 +4,12 @@ package hep.dataforge.vision.solid
import hep.dataforge.meta.Config import hep.dataforge.meta.Config
import hep.dataforge.meta.number import hep.dataforge.meta.number
import hep.dataforge.names.Name
import hep.dataforge.names.asName import hep.dataforge.names.asName
import hep.dataforge.names.plus import hep.dataforge.names.plus
import hep.dataforge.vision.AbstractVision import hep.dataforge.vision.AbstractVision
import hep.dataforge.vision.MutableVisionGroup import hep.dataforge.vision.MutableVisionGroup
import hep.dataforge.vision.VisionContainerBuilder
import hep.dataforge.vision.set import hep.dataforge.vision.set
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@ -15,7 +17,7 @@ import kotlinx.serialization.UseSerializers
@Serializable @Serializable
@SerialName("solid.line") @SerialName("solid.line")
class PolyLine(var points: List<Point3D>) : AbstractVision(), Solid { public class PolyLine(public var points: List<Point3D>) : AbstractVision(), Solid {
override var properties: Config? = null override var properties: Config? = null
override var position: Point3D? = null override var position: Point3D? = null
@ -23,13 +25,13 @@ class PolyLine(var points: List<Point3D>) : AbstractVision(), Solid {
override var scale: Point3D? = null override var scale: Point3D? = null
//var lineType by string() //var lineType by string()
var thickness by number(1.0, key = SolidMaterial.MATERIAL_KEY + THICKNESS_KEY) public var thickness: Number by number(1.0, key = SolidMaterial.MATERIAL_KEY + THICKNESS_KEY)
companion object { public companion object {
val THICKNESS_KEY = "thickness".asName() public val THICKNESS_KEY: Name = "thickness".asName()
} }
} }
fun MutableVisionGroup.polyline(vararg points: Point3D, name: String = "", action: PolyLine.() -> Unit = {}) = public fun VisionContainerBuilder<Solid>.polyline(vararg points: Point3D, name: String = "", action: PolyLine.() -> Unit = {}): PolyLine =
PolyLine(points.toList()).apply(action).also { set(name, it) } PolyLine(points.toList()).apply(action).also { set(name, it) }

View File

@ -12,8 +12,8 @@ import kotlinx.serialization.Transient
import kotlinx.serialization.UseSerializers import kotlinx.serialization.UseSerializers
import kotlin.collections.set import kotlin.collections.set
abstract class AbstractProxy : AbstractVision(), VisionGroup { public abstract class AbstractProxy : AbstractVision(), VisionGroup {
abstract val prototype: Vision public abstract val prototype: Vision
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? { override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {
return if (inherit) { return if (inherit) {
@ -33,7 +33,7 @@ abstract class AbstractProxy : AbstractVision(), VisionGroup {
} }
override var styles: List<String> override var styles: List<String>
get() = properties[Vision.STYLE_KEY].stringList + prototype.styles get() = (properties[Vision.STYLE_KEY]?.stringList ?: emptyList()) + prototype.styles
set(value) { set(value) {
config[Vision.STYLE_KEY] = value config[Vision.STYLE_KEY] = value
} }
@ -53,11 +53,11 @@ abstract class AbstractProxy : AbstractVision(), VisionGroup {
*/ */
@Serializable @Serializable
@SerialName("solid.proxy") @SerialName("solid.proxy")
class Proxy private constructor( public class Proxy private constructor(
val templateName: Name public val templateName: Name
) : AbstractProxy(), Solid { ) : AbstractProxy(), Solid {
constructor(parent: SolidGroup, templateName: Name) : this(templateName) { public constructor(parent: SolidGroup, templateName: Name) : this(templateName) {
this.parent = parent this.parent = parent
} }
@ -104,7 +104,7 @@ class Proxy private constructor(
* A ProxyChild is created temporarily only to interact with properties, it does not store any values * A ProxyChild is created temporarily only to interact with properties, it does not store any values
* (properties are stored in external cache) and created and destroyed on-demand). * (properties are stored in external cache) and created and destroyed on-demand).
*/ */
inner class ProxyChild(val name: Name) : AbstractProxy() { public inner class ProxyChild(public val name: Name) : AbstractProxy() {
override val prototype: Vision get() = prototypeFor(name) override val prototype: Vision get() = prototypeFor(name)
@ -136,12 +136,15 @@ class Proxy private constructor(
} }
companion object { public companion object {
const val PROXY_CHILD_PROPERTY_PREFIX = "@child" public const val PROXY_CHILD_PROPERTY_PREFIX: String = "@child"
} }
} }
val Vision.prototype: Vision /**
* Get a vision prototype if it is a [Proxy] or vision itself if it is not
*/
public val Vision.prototype: Vision
get() = when (this) { get() = when (this) {
is AbstractProxy -> prototype is AbstractProxy -> prototype
else -> this else -> this
@ -150,7 +153,7 @@ val Vision.prototype: Vision
/** /**
* Create ref for existing prototype * Create ref for existing prototype
*/ */
fun SolidGroup.ref( public fun SolidGroup.ref(
templateName: Name, templateName: Name,
name: String = "" name: String = ""
): Proxy = Proxy(this, templateName).also { set(name, it) } ): Proxy = Proxy(this, templateName).also { set(name, it) }
@ -158,7 +161,7 @@ fun SolidGroup.ref(
/** /**
* Add new proxy wrapping given object and automatically adding it to the prototypes * Add new proxy wrapping given object and automatically adding it to the prototypes
*/ */
fun SolidGroup.proxy( public fun SolidGroup.proxy(
name: String, name: String,
obj: Solid, obj: Solid,
templateName: Name = name.toName() templateName: Name = name.toName()
@ -173,12 +176,3 @@ fun SolidGroup.proxy(
} }
return ref(templateName, name) return ref(templateName, name)
} }
fun SolidGroup.proxyGroup(
name: String,
templateName: Name = name.toName(),
block: MutableVisionGroup.() -> Unit
): Proxy {
val group = SolidGroup().apply(block)
return proxy(name, group, templateName)
}

View File

@ -4,65 +4,63 @@ package hep.dataforge.vision.solid
import hep.dataforge.meta.* import hep.dataforge.meta.*
import hep.dataforge.meta.descriptors.NodeDescriptor import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.names.Name
import hep.dataforge.names.asName import hep.dataforge.names.asName
import hep.dataforge.names.plus import hep.dataforge.names.plus
import hep.dataforge.output.Renderer import hep.dataforge.output.Renderer
import hep.dataforge.values.ValueType import hep.dataforge.values.ValueType
import hep.dataforge.values.asValue import hep.dataforge.values.asValue
import hep.dataforge.vision.Vision import hep.dataforge.vision.Vision
import hep.dataforge.vision.Vision.Companion.VISIBLE_KEY
import hep.dataforge.vision.enum import hep.dataforge.vision.enum
import hep.dataforge.vision.solid.Solid.Companion.DETAIL_KEY import hep.dataforge.vision.solid.Solid.Companion.DETAIL_KEY
import hep.dataforge.vision.solid.Solid.Companion.IGNORE_KEY import hep.dataforge.vision.solid.Solid.Companion.IGNORE_KEY
import hep.dataforge.vision.solid.Solid.Companion.LAYER_KEY import hep.dataforge.vision.solid.Solid.Companion.LAYER_KEY
import hep.dataforge.vision.solid.Solid.Companion.VISIBLE_KEY
import kotlinx.serialization.UseSerializers import kotlinx.serialization.UseSerializers
/** /**
* Interface for 3-dimensional [Vision] * Interface for 3-dimensional [Vision]
*/ */
interface Solid : Vision { public interface Solid : Vision {
var position: Point3D? public var position: Point3D?
var rotation: Point3D? public var rotation: Point3D?
var scale: Point3D? public var scale: Point3D?
override val descriptor: NodeDescriptor? get() = Companion.descriptor override val descriptor: NodeDescriptor? get() = Companion.descriptor
companion object { public companion object {
val VISIBLE_KEY = "visible".asName()
// val SELECTED_KEY = "selected".asName() // val SELECTED_KEY = "selected".asName()
val DETAIL_KEY = "detail".asName() public val DETAIL_KEY: Name = "detail".asName()
val LAYER_KEY = "layer".asName() public val LAYER_KEY: Name = "layer".asName()
val IGNORE_KEY = "ignore".asName() public val IGNORE_KEY: Name = "ignore".asName()
val GEOMETRY_KEY = "geometry".asName() public val GEOMETRY_KEY: Name = "geometry".asName()
val X_KEY = "x".asName() public val X_KEY: Name = "x".asName()
val Y_KEY = "y".asName() public val Y_KEY: Name = "y".asName()
val Z_KEY = "z".asName() public val Z_KEY: Name = "z".asName()
val POSITION_KEY = "pos".asName() public val POSITION_KEY: Name = "pos".asName()
val X_POSITION_KEY = POSITION_KEY + X_KEY public val X_POSITION_KEY: Name = POSITION_KEY + X_KEY
val Y_POSITION_KEY = POSITION_KEY + Y_KEY public val Y_POSITION_KEY: Name = POSITION_KEY + Y_KEY
val Z_POSITION_KEY = POSITION_KEY + Z_KEY public val Z_POSITION_KEY: Name = POSITION_KEY + Z_KEY
val ROTATION = "rotation".asName() public val ROTATION: Name = "rotation".asName()
val X_ROTATION_KEY = ROTATION + X_KEY public val X_ROTATION_KEY: Name = ROTATION + X_KEY
val Y_ROTATION_KEY = ROTATION + Y_KEY public val Y_ROTATION_KEY: Name = ROTATION + Y_KEY
val Z_ROTATION_KEY = ROTATION + Z_KEY public val Z_ROTATION_KEY: Name = ROTATION + Z_KEY
val ROTATION_ORDER_KEY = ROTATION + "order" public val ROTATION_ORDER_KEY: Name = ROTATION + "order"
val SCALE_KEY = "scale".asName() public val SCALE_KEY: Name = "scale".asName()
val X_SCALE_KEY = SCALE_KEY + X_KEY public val X_SCALE_KEY: Name = SCALE_KEY + X_KEY
val Y_SCALE_KEY = SCALE_KEY + Y_KEY public val Y_SCALE_KEY: Name = SCALE_KEY + Y_KEY
val Z_SCALE_KEY = SCALE_KEY + Z_KEY public val Z_SCALE_KEY: Name = SCALE_KEY + Z_KEY
val descriptor by lazy { public val descriptor: NodeDescriptor by lazy {
NodeDescriptor { NodeDescriptor {
value(VISIBLE_KEY) { value(VISIBLE_KEY) {
type(ValueType.BOOLEAN) type(ValueType.BOOLEAN)
@ -100,20 +98,20 @@ interface Solid : Vision {
} }
/** /**
* Count number of layers to the top object. Return 1 if this is top layer * Get the layer number this solid belongs to. Return 0 if layer is not defined.
*/ */
var Solid.layer: Int public var Solid.layer: Int
get() = properties?.getItem(LAYER_KEY).int ?: 0 get() = properties?.getItem(LAYER_KEY).int ?: 0
set(value) { set(value) {
config[LAYER_KEY] = value.asValue() config[LAYER_KEY] = value.asValue()
} }
fun Renderer<Solid>.render(meta: Meta = Meta.EMPTY, action: SolidGroup.() -> Unit) = public fun Renderer<Solid>.render(meta: Meta = Meta.EMPTY, action: SolidGroup.() -> Unit): Unit =
render(SolidGroup().apply(action), meta) render(SolidGroup().apply(action), meta)
// Common properties // Common properties
enum class RotationOrder { public enum class RotationOrder {
XYZ, XYZ,
YZX, YZX,
ZXY, ZXY,
@ -125,7 +123,7 @@ enum class RotationOrder {
/** /**
* Rotation order * Rotation order
*/ */
var Solid.rotationOrder: RotationOrder public var Solid.rotationOrder: RotationOrder
get() = getItem(Solid.ROTATION_ORDER_KEY).enum<RotationOrder>() ?: RotationOrder.XYZ get() = getItem(Solid.ROTATION_ORDER_KEY).enum<RotationOrder>() ?: RotationOrder.XYZ
set(value) = setItem(Solid.ROTATION_ORDER_KEY, value.name.asValue()) set(value) = setItem(Solid.ROTATION_ORDER_KEY, value.name.asValue())
@ -133,19 +131,15 @@ var Solid.rotationOrder: RotationOrder
/** /**
* Preferred number of polygons for displaying the object. If not defined, uses shape or renderer default. Not inherited * Preferred number of polygons for displaying the object. If not defined, uses shape or renderer default. Not inherited
*/ */
var Solid.detail: Int? public var Solid.detail: Int?
get() = getProperty(DETAIL_KEY, false).int get() = getProperty(DETAIL_KEY, false).int
set(value) = setItem(DETAIL_KEY, value?.asValue()) set(value) = setItem(DETAIL_KEY, value?.asValue())
var Vision.visible: Boolean?
get() = getItem(VISIBLE_KEY).boolean
set(value) = setItem(VISIBLE_KEY, value?.asValue())
/** /**
* If this property is true, the object will be ignored on render. * If this property is true, the object will be ignored on render.
* Property is not inherited. * Property is not inherited.
*/ */
var Vision.ignore: Boolean? public var Vision.ignore: Boolean?
get() = getProperty(IGNORE_KEY, false).boolean get() = getProperty(IGNORE_KEY, false).boolean
set(value) = setItem(IGNORE_KEY, value?.asValue()) set(value) = setItem(IGNORE_KEY, value?.asValue())
@ -156,21 +150,21 @@ var Vision.ignore: Boolean?
private fun Solid.position(): Point3D = private fun Solid.position(): Point3D =
position ?: Point3D(0.0, 0.0, 0.0).also { position = it } position ?: Point3D(0.0, 0.0, 0.0).also { position = it }
var Solid.x: Number public var Solid.x: Number
get() = position?.x ?: 0f get() = position?.x ?: 0f
set(value) { set(value) {
position().x = value.toDouble() position().x = value.toDouble()
propertyChanged(Solid.X_POSITION_KEY) propertyChanged(Solid.X_POSITION_KEY)
} }
var Solid.y: Number public var Solid.y: Number
get() = position?.y ?: 0f get() = position?.y ?: 0f
set(value) { set(value) {
position().y = value.toDouble() position().y = value.toDouble()
propertyChanged(Solid.Y_POSITION_KEY) propertyChanged(Solid.Y_POSITION_KEY)
} }
var Solid.z: Number public var Solid.z: Number
get() = position?.z ?: 0f get() = position?.z ?: 0f
set(value) { set(value) {
position().z = value.toDouble() position().z = value.toDouble()
@ -180,21 +174,21 @@ var Solid.z: Number
private fun Solid.rotation(): Point3D = private fun Solid.rotation(): Point3D =
rotation ?: Point3D(0.0, 0.0, 0.0).also { rotation = it } rotation ?: Point3D(0.0, 0.0, 0.0).also { rotation = it }
var Solid.rotationX: Number public var Solid.rotationX: Number
get() = rotation?.x ?: 0f get() = rotation?.x ?: 0f
set(value) { set(value) {
rotation().x = value.toDouble() rotation().x = value.toDouble()
propertyChanged(Solid.X_ROTATION_KEY) propertyChanged(Solid.X_ROTATION_KEY)
} }
var Solid.rotationY: Number public var Solid.rotationY: Number
get() = rotation?.y ?: 0f get() = rotation?.y ?: 0f
set(value) { set(value) {
rotation().y = value.toDouble() rotation().y = value.toDouble()
propertyChanged(Solid.Y_ROTATION_KEY) propertyChanged(Solid.Y_ROTATION_KEY)
} }
var Solid.rotationZ: Number public var Solid.rotationZ: Number
get() = rotation?.z ?: 0f get() = rotation?.z ?: 0f
set(value) { set(value) {
rotation().z = value.toDouble() rotation().z = value.toDouble()
@ -204,21 +198,21 @@ var Solid.rotationZ: Number
private fun Solid.scale(): Point3D = private fun Solid.scale(): Point3D =
scale ?: Point3D(1.0, 1.0, 1.0).also { scale = it } scale ?: Point3D(1.0, 1.0, 1.0).also { scale = it }
var Solid.scaleX: Number public var Solid.scaleX: Number
get() = scale?.x ?: 1f get() = scale?.x ?: 1f
set(value) { set(value) {
scale().x = value.toDouble() scale().x = value.toDouble()
propertyChanged(Solid.X_SCALE_KEY) propertyChanged(Solid.X_SCALE_KEY)
} }
var Solid.scaleY: Number public var Solid.scaleY: Number
get() = scale?.y ?: 1f get() = scale?.y ?: 1f
set(value) { set(value) {
scale().y = value.toDouble() scale().y = value.toDouble()
propertyChanged(Solid.Y_SCALE_KEY) propertyChanged(Solid.Y_SCALE_KEY)
} }
var Solid.scaleZ: Number public var Solid.scaleZ: Number
get() = scale?.z ?: 1f get() = scale?.z ?: 1f
set(value) { set(value) {
scale().z = value.toDouble() scale().z = value.toDouble()

View File

@ -15,9 +15,9 @@ import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers import kotlinx.serialization.UseSerializers
import kotlin.collections.set import kotlin.collections.set
interface PrototypeHolder { public interface PrototypeHolder {
val parent: VisionGroup? public val parent: VisionGroup?
val prototypes: MutableVisionGroup? public val prototypes: MutableVisionGroup?
} }
/** /**
@ -25,7 +25,7 @@ interface PrototypeHolder {
*/ */
@Serializable @Serializable
@SerialName("group.solid") @SerialName("group.solid")
class SolidGroup : AbstractVisionGroup(), Solid, PrototypeHolder { public class SolidGroup : AbstractVisionGroup(), Solid, PrototypeHolder {
override var styleSheet: StyleSheet? = null override var styleSheet: StyleSheet? = null
@ -39,7 +39,7 @@ class SolidGroup : AbstractVisionGroup(), Solid, PrototypeHolder {
/** /**
* Create or edit prototype node as a group * Create or edit prototype node as a group
*/ */
fun prototypes(builder: MutableVisionGroup.() -> Unit): Unit { public fun prototypes(builder: MutableVisionGroup.() -> Unit): Unit {
(prototypes ?: Prototypes().also { (prototypes ?: Prototypes().also {
prototypes = it prototypes = it
attach(it) attach(it)
@ -79,33 +79,33 @@ class SolidGroup : AbstractVisionGroup(), Solid, PrototypeHolder {
override fun createGroup(): SolidGroup = SolidGroup() override fun createGroup(): SolidGroup = SolidGroup()
companion object { public companion object {
// val PROTOTYPES_KEY = NameToken("@prototypes") // val PROTOTYPES_KEY = NameToken("@prototypes")
@OptIn(DFExperimental::class) @OptIn(DFExperimental::class)
fun parseJson(json: String): SolidGroup = public fun decodeFromString(json: String): SolidGroup =
SolidManager.jsonForSolids.parse(serializer(), json).also { it.attachChildren() } SolidManager.jsonForSolids.decodeFromString(serializer(), json).also { it.attachChildren() }
} }
} }
@Suppress("FunctionName") @Suppress("FunctionName")
fun SolidGroup(block: SolidGroup.() -> Unit): SolidGroup { public fun SolidGroup(block: SolidGroup.() -> Unit): SolidGroup {
return SolidGroup().apply(block) return SolidGroup().apply(block)
} }
/** /**
* Ger a prototype redirecting the request to the parent if prototype is not found * Ger a prototype redirecting the request to the parent if prototype is not found
*/ */
tailrec fun PrototypeHolder.getPrototype(name: Name): Solid? = public tailrec fun PrototypeHolder.getPrototype(name: Name): Solid? =
prototypes?.get(name) as? Solid ?: (parent as? PrototypeHolder)?.getPrototype(name) prototypes?.get(name) as? Solid ?: (parent as? PrototypeHolder)?.getPrototype(name)
fun MutableVisionGroup.group(name: Name = Name.EMPTY, action: SolidGroup.() -> Unit = {}): SolidGroup = public fun MutableVisionGroup.group(name: Name = Name.EMPTY, action: SolidGroup.() -> Unit = {}): SolidGroup =
SolidGroup().apply(action).also { set(name, it) } SolidGroup().apply(action).also { set(name, it) }
/** /**
* Define a group with given [name], attach it to this parent and return it. * Define a group with given [name], attach it to this parent and return it.
*/ */
fun MutableVisionGroup.group(name: String, action: SolidGroup.() -> Unit = {}): SolidGroup = public fun MutableVisionGroup.group(name: String, action: SolidGroup.() -> Unit = {}): SolidGroup =
SolidGroup().apply(action).also { set(name, it) } SolidGroup().apply(action).also { set(name, it) }
/** /**

View File

@ -5,6 +5,7 @@ package hep.dataforge.vision.solid
import hep.dataforge.meta.Config import hep.dataforge.meta.Config
import hep.dataforge.vision.AbstractVision import hep.dataforge.vision.AbstractVision
import hep.dataforge.vision.MutableVisionGroup import hep.dataforge.vision.MutableVisionGroup
import hep.dataforge.vision.VisionContainerBuilder
import hep.dataforge.vision.set import hep.dataforge.vision.set
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@ -12,7 +13,7 @@ import kotlinx.serialization.UseSerializers
@Serializable @Serializable
@SerialName("solid.label") @SerialName("solid.label")
class SolidLabel(var text: String, var fontSize: Double, var fontFamily: String) : AbstractVision(), Solid { public class SolidLabel(public var text: String, public var fontSize: Double, public var fontFamily: String) : AbstractVision(), Solid {
override var properties: Config? = null override var properties: Config? = null
override var position: Point3D? = null override var position: Point3D? = null
@ -21,11 +22,10 @@ class SolidLabel(var text: String, var fontSize: Double, var fontFamily: String)
} }
fun MutableVisionGroup.label( public fun VisionContainerBuilder<Solid>.label(
text: String, text: String,
fontSize: Number = 20, fontSize: Number = 20,
fontFamily: String = "Arial", fontFamily: String = "Arial",
name: String = "", name: String = "",
action: SolidLabel.() -> Unit = {} action: SolidLabel.() -> Unit = {},
) = ): SolidLabel = SolidLabel(text, fontSize.toDouble(), fontFamily).apply(action).also { set(name, it) }
SolidLabel(text, fontSize.toDouble(), fontFamily).apply(action).also { set(name, it) }

View File

@ -12,20 +12,17 @@ import hep.dataforge.vision.Vision
import hep.dataforge.vision.VisionForm import hep.dataforge.vision.VisionForm
import hep.dataforge.vision.VisionManager import hep.dataforge.vision.VisionManager
import hep.dataforge.vision.VisionManager.Companion.VISION_SERIAL_MODULE_TARGET import hep.dataforge.vision.VisionManager.Companion.VISION_SERIAL_MODULE_TARGET
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.UnstableDefault
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration import kotlinx.serialization.modules.*
import kotlinx.serialization.modules.SerialModule
import kotlinx.serialization.modules.SerialModuleCollector
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.contextual
import kotlin.reflect.KClass import kotlin.reflect.KClass
@DFExperimental @DFExperimental
private class SolidForm<T : Solid>( private class SolidForm<T : Solid>(
override val type: KClass<T>, override val type: KClass<T>,
override val serializer: KSerializer<T> override val serializer: KSerializer<T>,
) : VisionForm<T> { ) : VisionForm<T> {
private fun Solid.update(meta: Meta) { private fun Solid.update(meta: Meta) {
@ -46,12 +43,12 @@ private class SolidForm<T :Solid>(
} }
} }
@OptIn(ExperimentalSerializationApi::class)
@DFExperimental @DFExperimental
@OptIn(UnstableDefault::class) private fun SerializersModule.extractFactories(): List<SolidForm<*>> {
private fun SerialModule.extractFactories(): List<SolidForm<*>> {
val list = ArrayList<SolidForm<*>>() val list = ArrayList<SolidForm<*>>()
val collector = object : SerialModuleCollector { val collector = object : SerializersModuleCollector {
override fun <T : Any> contextual(kClass: KClass<T>, serializer: KSerializer<T>) { override fun <T : Any> contextual(kClass: KClass<T>, serializer: KSerializer<T>) {
//Do nothing //Do nothing
} }
@ -59,7 +56,7 @@ private fun SerialModule.extractFactories(): List<SolidForm<*>> {
override fun <Base : Any, Sub : Base> polymorphic( override fun <Base : Any, Sub : Base> polymorphic(
baseClass: KClass<Base>, baseClass: KClass<Base>,
actualClass: KClass<Sub>, actualClass: KClass<Sub>,
actualSerializer: KSerializer<Sub> actualSerializer: KSerializer<Sub>,
) { ) {
if (baseClass == Vision::class) { if (baseClass == Vision::class) {
@Suppress("UNCHECKED_CAST") val factory = SolidForm<Solid>( @Suppress("UNCHECKED_CAST") val factory = SolidForm<Solid>(
@ -70,34 +67,41 @@ private fun SerialModule.extractFactories(): List<SolidForm<*>> {
} }
} }
override fun <Base : Any> polymorphicDefault(
baseClass: KClass<Base>,
defaultSerializerProvider: (className: String?) -> DeserializationStrategy<out Base>?,
) {
TODO("Not yet implemented")
}
} }
dumpTo(collector) dumpTo(collector)
return list return list
} }
@DFExperimental @DFExperimental
class SolidManager(meta: Meta) : AbstractPlugin(meta) { public class SolidManager(meta: Meta) : AbstractPlugin(meta) {
val visionManager by require(VisionManager) public val visionManager: VisionManager by require(VisionManager)
override val tag: PluginTag get() = Companion.tag override val tag: PluginTag get() = Companion.tag
override fun provideTop(target: String): Map<Name, Any> = when (target) { override fun content(target: String): Map<Name, Any> = when (target) {
VisionForm.TYPE -> serialModule.extractFactories().associateBy { it.name } VisionForm.TYPE -> serialModule.extractFactories().associateBy { it.name }
VISION_SERIAL_MODULE_TARGET -> mapOf(tag.name.toName() to serialModule) VISION_SERIAL_MODULE_TARGET -> mapOf(tag.name.toName() to serialModule)
else -> super.provideTop(target) else -> super.content(target)
} }
companion object : PluginFactory<SolidManager> { public companion object : PluginFactory<SolidManager> {
override val tag: PluginTag = PluginTag(name = "visual.spatial", group = PluginTag.DATAFORGE_GROUP) override val tag: PluginTag = PluginTag(name = "visual.spatial", group = PluginTag.DATAFORGE_GROUP)
override val type: KClass<out SolidManager> = SolidManager::class override val type: KClass<out SolidManager> = SolidManager::class
override fun invoke(meta: Meta, context: Context): SolidManager = SolidManager(meta) override fun invoke(meta: Meta, context: Context): SolidManager = SolidManager(meta)
val serialModule = SerializersModule { public val serialModule: SerializersModule = SerializersModule {
contextual(Point3DSerializer) contextual(Point3DSerializer)
contextual(Point2DSerializer) contextual(Point2DSerializer)
polymorphic(Vision::class, Solid::class) { polymorphic(Vision::class) {
subclass(SimpleVisionGroup.serializer()) subclass(SimpleVisionGroup.serializer())
subclass(SolidGroup.serializer()) subclass(SolidGroup.serializer())
subclass(Proxy.serializer()) subclass(Proxy.serializer())
@ -112,15 +116,12 @@ class SolidManager(meta: Meta) : AbstractPlugin(meta) {
} }
} }
@OptIn(UnstableDefault::class) val jsonForSolids = Json {
val jsonForSolids = Json( prettyPrint = true
JsonConfiguration( useArrayPolymorphism = false
prettyPrint = true, encodeDefaults = false
useArrayPolymorphism = false,
encodeDefaults = false,
ignoreUnknownKeys = true ignoreUnknownKeys = true
), serializersModule = this@Companion.serialModule
context = serialModule }
)
} }
} }

View File

@ -3,6 +3,7 @@ package hep.dataforge.vision.solid
import hep.dataforge.meta.* import hep.dataforge.meta.*
import hep.dataforge.meta.descriptors.NodeDescriptor import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.meta.descriptors.attributes import hep.dataforge.meta.descriptors.attributes
import hep.dataforge.names.Name
import hep.dataforge.names.asName import hep.dataforge.names.asName
import hep.dataforge.names.plus import hep.dataforge.names.plus
import hep.dataforge.values.ValueType import hep.dataforge.values.ValueType
@ -13,41 +14,41 @@ import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_KEY
import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_OPACITY_KEY import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_OPACITY_KEY
import hep.dataforge.vision.widgetType import hep.dataforge.vision.widgetType
class SolidMaterial : Scheme() { public class SolidMaterial : Scheme() {
/** /**
* Primary web-color for the material * Primary web-color for the material
*/ */
var color by string(key = COLOR_KEY) public var color: String? by string(key = COLOR_KEY)
/** /**
* Specular color for phong material * Specular color for phong material
*/ */
var specularColor by string(key = SPECULAR_COLOR_KEY) public var specularColor: String? by string(key = SPECULAR_COLOR_KEY)
/** /**
* Opacity * Opacity
*/ */
var opacity by float(1f, key = OPACITY_KEY) public var opacity: Float by float(1f, key = OPACITY_KEY)
/** /**
* Replace material by wire frame * Replace material by wire frame
*/ */
var wireframe by boolean(false, WIREFRAME_KEY) public var wireframe: Boolean by boolean(false, WIREFRAME_KEY)
companion object : SchemeSpec<SolidMaterial>(::SolidMaterial) { public companion object : SchemeSpec<SolidMaterial>(::SolidMaterial) {
val MATERIAL_KEY = "material".asName() public val MATERIAL_KEY: Name = "material".asName()
internal val COLOR_KEY = "color".asName() internal val COLOR_KEY = "color".asName()
val MATERIAL_COLOR_KEY = MATERIAL_KEY + COLOR_KEY public val MATERIAL_COLOR_KEY: Name = MATERIAL_KEY + COLOR_KEY
internal val SPECULAR_COLOR_KEY = "specularColor".asName() internal val SPECULAR_COLOR_KEY = "specularColor".asName()
val MATERIAL_SPECULAR_COLOR_KEY = MATERIAL_KEY + SPECULAR_COLOR_KEY public val MATERIAL_SPECULAR_COLOR_KEY: Name = MATERIAL_KEY + SPECULAR_COLOR_KEY
internal val OPACITY_KEY = "opacity".asName() internal val OPACITY_KEY = "opacity".asName()
val MATERIAL_OPACITY_KEY = MATERIAL_KEY + OPACITY_KEY public val MATERIAL_OPACITY_KEY: Name = MATERIAL_KEY + OPACITY_KEY
internal val WIREFRAME_KEY = "wireframe".asName() internal val WIREFRAME_KEY = "wireframe".asName()
val MATERIAL_WIREFRAME_KEY = MATERIAL_KEY + WIREFRAME_KEY public val MATERIAL_WIREFRAME_KEY: Name = MATERIAL_KEY + WIREFRAME_KEY
val descriptor by lazy { public val descriptor: NodeDescriptor by lazy {
//must be lazy to avoid initialization bug //must be lazy to avoid initialization bug
NodeDescriptor { NodeDescriptor {
value(COLOR_KEY) { value(COLOR_KEY) {
@ -77,18 +78,18 @@ class SolidMaterial : Scheme() {
/** /**
* Set color as web-color * Set color as web-color
*/ */
fun Solid.color(webColor: String) { public fun Solid.color(webColor: String) {
setItem(MATERIAL_COLOR_KEY, webColor.asValue()) setItem(MATERIAL_COLOR_KEY, webColor.asValue())
} }
/** /**
* Set color as integer * Set color as integer
*/ */
fun Solid.color(rgb: Int) { public fun Solid.color(rgb: Int) {
setItem(MATERIAL_COLOR_KEY, rgb.asValue()) setItem(MATERIAL_COLOR_KEY, rgb.asValue())
} }
fun Solid.color(r: UByte, g: UByte, b: UByte) = setItem( public fun Solid.color(r: UByte, g: UByte, b: UByte): Unit = setItem(
MATERIAL_COLOR_KEY, MATERIAL_COLOR_KEY,
Colors.rgbToMeta(r, g, b) Colors.rgbToMeta(r, g, b)
) )
@ -96,16 +97,16 @@ fun Solid.color(r: UByte, g: UByte, b: UByte) = setItem(
/** /**
* Web colors representation of the color in `#rrggbb` format or HTML name * Web colors representation of the color in `#rrggbb` format or HTML name
*/ */
var Solid.color: String? public var Solid.color: String?
get() = getItem(MATERIAL_COLOR_KEY)?.let { Colors.fromMeta(it) } get() = getItem(MATERIAL_COLOR_KEY)?.let { Colors.fromMeta(it) }
set(value) { set(value) {
setItem(MATERIAL_COLOR_KEY, value?.asValue()) setItem(MATERIAL_COLOR_KEY, value?.asValue())
} }
val Solid.material: SolidMaterial? public val Solid.material: SolidMaterial?
get() = getItem(MATERIAL_KEY).node?.let { SolidMaterial.wrap(it) } get() = getItem(MATERIAL_KEY).node?.let { SolidMaterial.wrap(it) }
fun Solid.material(builder: SolidMaterial.() -> Unit) { public fun Solid.material(builder: SolidMaterial.() -> Unit) {
val node = config[MATERIAL_KEY].node val node = config[MATERIAL_KEY].node
if (node != null) { if (node != null) {
SolidMaterial.update(node, builder) SolidMaterial.update(node, builder)
@ -114,7 +115,7 @@ fun Solid.material(builder: SolidMaterial.() -> Unit) {
} }
} }
var Solid.opacity: Double? public var Solid.opacity: Double?
get() = getItem(MATERIAL_OPACITY_KEY).double get() = getItem(MATERIAL_OPACITY_KEY).double
set(value) { set(value) {
setItem(MATERIAL_OPACITY_KEY, value?.asValue()) setItem(MATERIAL_OPACITY_KEY, value?.asValue())

View File

@ -5,6 +5,7 @@ package hep.dataforge.vision.solid
import hep.dataforge.meta.Config import hep.dataforge.meta.Config
import hep.dataforge.vision.AbstractVision import hep.dataforge.vision.AbstractVision
import hep.dataforge.vision.MutableVisionGroup import hep.dataforge.vision.MutableVisionGroup
import hep.dataforge.vision.VisionContainerBuilder
import hep.dataforge.vision.set import hep.dataforge.vision.set
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@ -15,12 +16,12 @@ import kotlin.math.sin
@Serializable @Serializable
@SerialName("solid.sphere") @SerialName("solid.sphere")
class Sphere( public class Sphere(
var radius: Float, public var radius: Float,
var phiStart: Float = 0f, public var phiStart: Float = 0f,
var phi: Float = PI2, public var phi: Float = PI2,
var thetaStart: Float = 0f, public var thetaStart: Float = 0f,
var theta: Float = PI.toFloat() public var theta: Float = PI.toFloat()
) : AbstractVision(), GeometrySolid { ) : AbstractVision(), GeometrySolid {
override var properties: Config? = null override var properties: Config? = null
@ -60,13 +61,13 @@ class Sphere(
} }
} }
inline fun MutableVisionGroup.sphere( public inline fun VisionContainerBuilder<Solid>.sphere(
radius: Number, radius: Number,
phi: Number = 2 * PI, phi: Number = 2 * PI,
theta: Number = PI, theta: Number = PI,
name: String = "", name: String = "",
action: Sphere.() -> Unit = {} action: Sphere.() -> Unit = {}
) = Sphere( ): Sphere = Sphere(
radius.toFloat(), radius.toFloat(),
phi = phi.toFloat(), phi = phi.toFloat(),
theta = theta.toFloat() theta = theta.toFloat()

View File

@ -5,6 +5,7 @@ package hep.dataforge.vision.solid
import hep.dataforge.meta.Config import hep.dataforge.meta.Config
import hep.dataforge.vision.AbstractVision import hep.dataforge.vision.AbstractVision
import hep.dataforge.vision.MutableVisionGroup import hep.dataforge.vision.MutableVisionGroup
import hep.dataforge.vision.VisionContainerBuilder
import hep.dataforge.vision.set import hep.dataforge.vision.set
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@ -18,12 +19,12 @@ import kotlin.math.sin
*/ */
@Serializable @Serializable
@SerialName("solid.tube") @SerialName("solid.tube")
class Tube( public class Tube(
var radius: Float, public var radius: Float,
var height: Float, public var height: Float,
var innerRadius: Float = 0f, public var innerRadius: Float = 0f,
var startAngle: Float = 0f, public var startAngle: Float = 0f,
var angle: Float = PI2 public var angle: Float = PI2
) : AbstractVision(), GeometrySolid { ) : AbstractVision(), GeometrySolid {
override var position: Point3D? = null override var position: Point3D? = null
@ -129,7 +130,7 @@ class Tube(
} }
inline fun MutableVisionGroup.tube( public inline fun VisionContainerBuilder<Solid>.tube(
r: Number, r: Number,
height: Number, height: Number,
innerRadius: Number = 0f, innerRadius: Number = 0f,

View File

@ -1,47 +1,48 @@
package hep.dataforge.vision.solid package hep.dataforge.vision.solid
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaBuilder
import hep.dataforge.meta.get import hep.dataforge.meta.get
import hep.dataforge.meta.number import hep.dataforge.meta.number
import kotlin.math.PI import kotlin.math.PI
object World { public object World {
val ZERO = Point3D(0.0, 0.0, 0.0) public val ZERO: Point3D = Point3D(0.0, 0.0, 0.0)
val ONE = Point3D(1.0, 1.0, 1.0) public val ONE: Point3D = Point3D(1.0, 1.0, 1.0)
} }
const val PI2: Float = 2 * PI.toFloat() public const val PI2: Float = 2 * PI.toFloat()
expect class Point2D(x: Number, y: Number) { public expect class Point2D(x: Number, y: Number) {
var x: Double public var x: Double
var y: Double public var y: Double
} }
operator fun Point2D.component1() = x public operator fun Point2D.component1(): Double = x
operator fun Point2D.component2() = y public operator fun Point2D.component2(): Double = y
fun Point2D.toMeta() = Meta { public fun Point2D.toMeta(): Meta = Meta {
Solid.X_KEY put x Solid.X_KEY put x
Solid.Y_KEY put y Solid.Y_KEY put y
} }
fun Meta.point2D() = Point2D(this["x"].number ?: 0, this["y"].number ?: 0) internal fun Meta.point2D(): Point2D = Point2D(this["x"].number ?: 0, this["y"].number ?: 0)
expect class Point3D(x: Number, y: Number, z: Number) { public expect class Point3D(x: Number, y: Number, z: Number) {
var x: Double public var x: Double
var y: Double public var y: Double
var z: Double public var z: Double
} }
expect operator fun Point3D.plus(other: Point3D): Point3D public expect operator fun Point3D.plus(other: Point3D): Point3D
operator fun Point3D.component1() = x public operator fun Point3D.component1(): Double = x
operator fun Point3D.component2() = y public operator fun Point3D.component2(): Double = y
operator fun Point3D.component3() = z public operator fun Point3D.component3(): Double = z
fun Meta.point3D() = Point3D(this["x"].number ?: 0, this["y"].number ?: 0, this["y"].number ?: 0) internal fun Meta.point3D() = Point3D(this["x"].number ?: 0, this["y"].number ?: 0, this["y"].number ?: 0)
fun Point3D.toMeta() = Meta { public fun Point3D.toMeta(): MetaBuilder = Meta {
Solid.X_KEY put x Solid.X_KEY put x
Solid.Y_KEY put y Solid.Y_KEY put y
Solid.Z_KEY put z Solid.Z_KEY put z

View File

@ -2,6 +2,7 @@ package hep.dataforge.vision.solid
import hep.dataforge.meta.DFExperimental import hep.dataforge.meta.DFExperimental
import hep.dataforge.meta.double import hep.dataforge.meta.double
import hep.dataforge.meta.transformations.MetaConverter.Companion.double
import hep.dataforge.names.NameToken import hep.dataforge.names.NameToken
import hep.dataforge.vision.MutableVisionGroup import hep.dataforge.vision.MutableVisionGroup
import hep.dataforge.vision.Vision import hep.dataforge.vision.Vision
@ -10,34 +11,19 @@ import kotlinx.serialization.*
import kotlinx.serialization.builtins.MapSerializer import kotlinx.serialization.builtins.MapSerializer
import kotlinx.serialization.builtins.nullable import kotlinx.serialization.builtins.nullable
import kotlinx.serialization.builtins.serializer import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
import kotlinx.serialization.descriptors.element
import kotlinx.serialization.encoding.*
inline fun <R> Decoder.decodeStructure(
desc: SerialDescriptor,
vararg typeParams: KSerializer<*> = emptyArray(),
crossinline block: CompositeDecoder.() -> R
): R {
val decoder = beginStructure(desc, *typeParams)
val res = decoder.block()
decoder.endStructure(desc)
return res
}
inline fun Encoder.encodeStructure(
desc: SerialDescriptor,
vararg typeParams: KSerializer<*> = emptyArray(),
block: CompositeEncoder.() -> Unit
) {
val encoder = beginStructure(desc, *typeParams)
encoder.block()
encoder.endStructure(desc)
}
@OptIn(ExperimentalSerializationApi::class)
@Serializer(Point3D::class) @Serializer(Point3D::class)
object Point3DSerializer : KSerializer<Point3D> { public object Point3DSerializer : KSerializer<Point3D> {
override val descriptor: SerialDescriptor = SerialDescriptor("hep.dataforge.vis.spatial.Point3D") { override val descriptor: SerialDescriptor = buildClassSerialDescriptor("hep.dataforge.vis.spatial.Point3D") {
double("x", true) element<Double>("x")
double("y", true) element<Double>("y")
double("z", true) element<Double>("z")
} }
override fun deserialize(decoder: Decoder): Point3D { override fun deserialize(decoder: Decoder): Point3D {
@ -47,7 +33,7 @@ object Point3DSerializer : KSerializer<Point3D> {
decoder.decodeStructure(descriptor) { decoder.decodeStructure(descriptor) {
loop@ while (true) { loop@ while (true) {
when (val i = decodeElementIndex(descriptor)) { when (val i = decodeElementIndex(descriptor)) {
CompositeDecoder.READ_DONE -> break@loop CompositeDecoder.DECODE_DONE -> break@loop
0 -> x = decodeNullableSerializableElement(descriptor, 0, Double.serializer().nullable) ?: 0.0 0 -> x = decodeNullableSerializableElement(descriptor, 0, Double.serializer().nullable) ?: 0.0
1 -> y = decodeNullableSerializableElement(descriptor, 1, Double.serializer().nullable) ?: 0.0 1 -> y = decodeNullableSerializableElement(descriptor, 1, Double.serializer().nullable) ?: 0.0
2 -> z = decodeNullableSerializableElement(descriptor, 2, Double.serializer().nullable) ?: 0.0 2 -> z = decodeNullableSerializableElement(descriptor, 2, Double.serializer().nullable) ?: 0.0
@ -67,11 +53,12 @@ object Point3DSerializer : KSerializer<Point3D> {
} }
} }
@OptIn(ExperimentalSerializationApi::class)
@Serializer(Point2D::class) @Serializer(Point2D::class)
object Point2DSerializer : KSerializer<Point2D> { public object Point2DSerializer : KSerializer<Point2D> {
override val descriptor: SerialDescriptor = SerialDescriptor("hep.dataforge.vis.spatial.Point2D") { override val descriptor: SerialDescriptor = buildClassSerialDescriptor("hep.dataforge.vis.spatial.Point2D") {
double("x", true) element<Double>("x")
double("y", true) element<Double>("y")
} }
override fun deserialize(decoder: Decoder): Point2D { override fun deserialize(decoder: Decoder): Point2D {
@ -80,7 +67,7 @@ object Point2DSerializer : KSerializer<Point2D> {
decoder.decodeStructure(descriptor) { decoder.decodeStructure(descriptor) {
loop@ while (true) { loop@ while (true) {
when (val i = decodeElementIndex(descriptor)) { when (val i = decodeElementIndex(descriptor)) {
CompositeDecoder.READ_DONE -> break@loop CompositeDecoder.DECODE_DONE -> break@loop
0 -> x = decodeNullableSerializableElement(descriptor, 0, Double.serializer().nullable) ?: 0.0 0 -> x = decodeNullableSerializableElement(descriptor, 0, Double.serializer().nullable) ?: 0.0
1 -> y = decodeNullableSerializableElement(descriptor, 1, Double.serializer().nullable) ?: 0.0 1 -> y = decodeNullableSerializableElement(descriptor, 1, Double.serializer().nullable) ?: 0.0
else -> throw SerializationException("Unknown index $i") else -> throw SerializationException("Unknown index $i")
@ -98,6 +85,7 @@ object Point2DSerializer : KSerializer<Point2D> {
} }
} }
@OptIn(ExperimentalSerializationApi::class)
@Serializer(MutableVisionGroup::class) @Serializer(MutableVisionGroup::class)
internal object PrototypesSerializer : KSerializer<MutableVisionGroup> { internal object PrototypesSerializer : KSerializer<MutableVisionGroup> {
@ -120,10 +108,10 @@ internal object PrototypesSerializer : KSerializer<MutableVisionGroup> {
} }
@OptIn(DFExperimental::class) @OptIn(DFExperimental::class)
fun Vision.stringify(): String = SolidManager.jsonForSolids.stringify(Vision.serializer(), this) public fun Vision.encodeToString(): String = SolidManager.jsonForSolids.encodeToString(Vision.serializer(), this)
@OptIn(DFExperimental::class) @OptIn(DFExperimental::class)
fun Vision.Companion.parseJson(str: String) = SolidManager.jsonForSolids.parse(serializer(), str).also { public fun Vision.Companion.decodeFromString(str: String): Vision = SolidManager.jsonForSolids.decodeFromString(serializer(), str).also {
if(it is VisionGroup){ if(it is VisionGroup){
it.attachChildren() it.attachChildren()
} }

View File

@ -2,13 +2,13 @@ package hep.dataforge.vision.solid.specifications
import hep.dataforge.meta.* import hep.dataforge.meta.*
class Axes : Scheme() { public class Axes : Scheme() {
var visible by boolean(!config.isEmpty()) public var visible: Boolean by boolean(!config.isEmpty())
var size by double(AXIS_SIZE) public var size: Double by double(AXIS_SIZE)
var width by double(AXIS_WIDTH) public var width: Double by double(AXIS_WIDTH)
companion object : SchemeSpec<Axes>(::Axes) { public companion object : SchemeSpec<Axes>(::Axes) {
const val AXIS_SIZE = 1000.0 public const val AXIS_SIZE: Double = 1000.0
const val AXIS_WIDTH = 3.0 public const val AXIS_WIDTH: Double = 3.0
} }
} }

View File

@ -6,24 +6,24 @@ import hep.dataforge.meta.double
import hep.dataforge.meta.int import hep.dataforge.meta.int
import kotlin.math.PI import kotlin.math.PI
class Camera : Scheme() { public class Camera : Scheme() {
var fov by int(FIELD_OF_VIEW) public var fov: Int by int(FIELD_OF_VIEW)
//var aspect by double(1.0) //var aspect by double(1.0)
var nearClip by double(NEAR_CLIP) public var nearClip: Double by double(NEAR_CLIP)
var farClip by double(FAR_CLIP) public var farClip: Double by double(FAR_CLIP)
var distance by double(INITIAL_DISTANCE) public var distance: Double by double(INITIAL_DISTANCE)
var azimuth by double(INITIAL_AZIMUTH) public var azimuth: Double by double(INITIAL_AZIMUTH)
var latitude by double(INITIAL_LATITUDE) public var latitude: Double by double(INITIAL_LATITUDE)
val zenith: Double get() = PI / 2 - latitude public val zenith: Double get() = PI / 2 - latitude
companion object : SchemeSpec<Camera>(::Camera) { public companion object : SchemeSpec<Camera>(::Camera) {
const val INITIAL_DISTANCE = 300.0 public const val INITIAL_DISTANCE: Double = 300.0
const val INITIAL_AZIMUTH = 0.0 public const val INITIAL_AZIMUTH: Double = 0.0
const val INITIAL_LATITUDE = PI / 6 public const val INITIAL_LATITUDE: Double = PI / 6
const val NEAR_CLIP = 0.1 public const val NEAR_CLIP: Double = 0.1
const val FAR_CLIP = 10000.0 public const val FAR_CLIP: Double = 10000.0
const val FIELD_OF_VIEW = 75 public const val FIELD_OF_VIEW: Int = 75
} }
} }

View File

@ -5,11 +5,11 @@ import hep.dataforge.meta.SchemeSpec
import hep.dataforge.meta.int import hep.dataforge.meta.int
import hep.dataforge.meta.spec import hep.dataforge.meta.spec
class Canvas3DOptions : Scheme() { public class Canvas3DOptions : Scheme() {
var axes by spec(Axes, Axes.empty()) public var axes: Axes by spec(Axes, Axes.empty())
var camera by spec(Camera, Camera.empty()) public var camera: Camera by spec(Camera, Camera.empty())
var controls by spec(Controls, Controls.empty()) public var controls: Controls by spec(Controls, Controls.empty())
var minSize by int(300) public var minSize: Int by int(300)
companion object : SchemeSpec<Canvas3DOptions>(::Canvas3DOptions) public companion object : SchemeSpec<Canvas3DOptions>(::Canvas3DOptions)
} }

View File

@ -1,5 +1,6 @@
package hep.dataforge.vision.solid.transform package hep.dataforge.vision.solid.transform
import hep.dataforge.meta.DFExperimental
import hep.dataforge.meta.update import hep.dataforge.meta.update
import hep.dataforge.names.asName import hep.dataforge.names.asName
import hep.dataforge.vision.MutableVisionGroup import hep.dataforge.vision.MutableVisionGroup
@ -7,6 +8,7 @@ import hep.dataforge.vision.Vision
import hep.dataforge.vision.VisionGroup import hep.dataforge.vision.VisionGroup
import hep.dataforge.vision.solid.* import hep.dataforge.vision.solid.*
@DFExperimental
internal fun mergeChild(parent: VisionGroup, child: Vision): Vision { internal fun mergeChild(parent: VisionGroup, child: Vision): Vision {
return child.apply { return child.apply {
@ -32,6 +34,7 @@ internal fun mergeChild(parent: VisionGroup, child: Vision): Vision {
} }
} }
@DFExperimental
object RemoveSingleChild : VisualTreeTransform<SolidGroup>() { object RemoveSingleChild : VisualTreeTransform<SolidGroup>() {
override fun SolidGroup.transformInPlace() { override fun SolidGroup.transformInPlace() {

View File

@ -1,5 +1,6 @@
package hep.dataforge.vision.solid.transform package hep.dataforge.vision.solid.transform
import hep.dataforge.meta.DFExperimental
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.asName import hep.dataforge.names.asName
import hep.dataforge.vision.MutableVisionGroup import hep.dataforge.vision.MutableVisionGroup
@ -7,6 +8,7 @@ import hep.dataforge.vision.VisionGroup
import hep.dataforge.vision.solid.Proxy import hep.dataforge.vision.solid.Proxy
import hep.dataforge.vision.solid.SolidGroup import hep.dataforge.vision.solid.SolidGroup
@DFExperimental
object UnRef : VisualTreeTransform<SolidGroup>() { object UnRef : VisualTreeTransform<SolidGroup>() {
private fun VisionGroup.countRefs(): Map<Name, Int> { private fun VisionGroup.countRefs(): Map<Name, Int> {
return children.values.fold(HashMap()) { reducer, obj -> return children.values.fold(HashMap()) { reducer, obj ->

View File

@ -1,6 +1,7 @@
package hep.dataforge.vision.solid package hep.dataforge.vision.solid
import hep.dataforge.meta.* import hep.dataforge.meta.*
import kotlinx.serialization.json.toJson
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -24,7 +25,7 @@ class ConvexTest {
val convex = group.children.values.first() as Convex val convex = group.children.values.first() as Convex
val json = SolidManager.jsonForSolids.toJson(Convex.serializer(), convex) val json = SolidManager.jsonForSolids.encodeToJsonElement(Convex.serializer(), convex)
val meta = json.toMetaItem().node!! val meta = json.toMetaItem().node!!
val points = meta.getIndexed("points").values.map { (it as MetaItem.NodeItem<*>).node.point3D() } val points = meta.getIndexed("points").values.map { (it as MetaItem.NodeItem<*>).node.point3D() }

View File

@ -1,11 +1,26 @@
package hep.dataforge.vision.solid package hep.dataforge.vision.solid
import hep.dataforge.names.Name
import hep.dataforge.names.toName import hep.dataforge.names.toName
import hep.dataforge.vision.MutableVisionGroup
import hep.dataforge.vision.Vision import hep.dataforge.vision.Vision
import hep.dataforge.vision.get import hep.dataforge.vision.get
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
/**
* Create and attach new proxied group
*/
fun SolidGroup.proxyGroup(
name: String,
templateName: Name = name.toName(),
block: MutableVisionGroup.() -> Unit
): Proxy {
val group = SolidGroup().apply(block)
return proxy(name, group, templateName)
}
class SerializationTest { class SerializationTest {
@Test @Test
fun testCubeSerialization() { fun testCubeSerialization() {
@ -14,9 +29,9 @@ class SerializationTest {
x = 100 x = 100
z = -100 z = -100
} }
val string = cube.stringify() val string = cube.encodeToString()
println(string) println(string)
val newCube = Vision.parseJson(string) val newCube = Vision.decodeFromString(string)
assertEquals(cube.config, newCube.config) assertEquals(cube.config, newCube.config)
} }
@ -35,9 +50,9 @@ class SerializationTest {
} }
} }
} }
val string = group.stringify() val string = group.encodeToString()
println(string) println(string)
val reconstructed = SolidGroup.parseJson(string) val reconstructed = SolidGroup.decodeFromString(string)
assertEquals(group["cube"]?.config, reconstructed["cube"]?.config) assertEquals(group["cube"]?.config, reconstructed["cube"]?.config)
} }

View File

@ -5,10 +5,10 @@ import info.laht.threekt.math.Vector2
import info.laht.threekt.math.Vector3 import info.laht.threekt.math.Vector3
import info.laht.threekt.math.plus import info.laht.threekt.math.plus
actual typealias Point2D = Vector2 public actual typealias Point2D = Vector2
actual typealias Point3D = Vector3 public actual typealias Point3D = Vector3
actual operator fun Point3D.plus(other: Point3D): Point3D { public actual operator fun Point3D.plus(other: Point3D): Point3D {
return this.plus(other) return this.plus(other)
} }

View File

@ -8,6 +8,7 @@ import hep.dataforge.vision.solid.*
import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_KEY import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_KEY
import hep.dataforge.vision.solid.three.ThreeFactory.Companion.TYPE import hep.dataforge.vision.solid.three.ThreeFactory.Companion.TYPE
import hep.dataforge.vision.solid.three.ThreeMaterials.getMaterial import hep.dataforge.vision.solid.three.ThreeMaterials.getMaterial
import hep.dataforge.vision.visible
import info.laht.threekt.core.BufferGeometry import info.laht.threekt.core.BufferGeometry
import info.laht.threekt.core.Object3D import info.laht.threekt.core.Object3D
import info.laht.threekt.objects.Mesh import info.laht.threekt.objects.Mesh
@ -54,7 +55,7 @@ fun Object3D.updateProperty(source: Vision, propertyName: Name) {
) { ) {
//update position of mesh using this object //update position of mesh using this object
updatePosition(source) updatePosition(source)
} else if (propertyName == Solid.VISIBLE_KEY) { } else if (propertyName == Vision.VISIBLE_KEY) {
visible = source.visible ?: true visible = source.visible ?: true
} }
} }

View File

@ -5,6 +5,7 @@ import hep.dataforge.meta.Meta
import hep.dataforge.names.* import hep.dataforge.names.*
import hep.dataforge.vision.Vision import hep.dataforge.vision.Vision
import hep.dataforge.vision.solid.* import hep.dataforge.vision.solid.*
import hep.dataforge.vision.visible
import info.laht.threekt.core.Object3D import info.laht.threekt.core.Object3D
import kotlin.collections.set import kotlin.collections.set
import kotlin.reflect.KClass import kotlin.reflect.KClass
@ -30,7 +31,7 @@ class ThreePlugin : AbstractPlugin() {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
private fun findObjectFactory(type: KClass<out Vision>): ThreeFactory<Solid>? { private fun findObjectFactory(type: KClass<out Vision>): ThreeFactory<Solid>? {
return (objectFactories[type] return (objectFactories[type]
?: context.content<ThreeFactory<*>>(ThreeFactory.TYPE).values.find { it.type == type }) ?: context.gather<ThreeFactory<*>>(ThreeFactory.TYPE).values.find { it.type == type })
as ThreeFactory<Solid>? as ThreeFactory<Solid>?
} }
@ -63,7 +64,7 @@ class ThreePlugin : AbstractPlugin() {
) { ) {
//update position of mesh using this object //update position of mesh using this object
updatePosition(obj) updatePosition(obj)
} else if (name == Solid.VISIBLE_KEY) { } else if (name == Vision.VISIBLE_KEY) {
visible = obj.visible ?: true visible = obj.visible ?: true
} }
} }
@ -123,28 +124,28 @@ internal fun Object3D.getOrCreateGroup(name: Name): Object3D {
return when { return when {
name.isEmpty() -> this name.isEmpty() -> this
name.length == 1 -> { name.length == 1 -> {
val token = name.first()!! val token = name.tokens.first()
children.find { it.name == token.toString() } ?: info.laht.threekt.objects.Group().also { group -> children.find { it.name == token.toString() } ?: info.laht.threekt.objects.Group().also { group ->
group.name = token.toString() group.name = token.toString()
this.add(group) this.add(group)
} }
} }
else -> getOrCreateGroup(name.first()!!.asName()).getOrCreateGroup(name.cutFirst()) else -> getOrCreateGroup(name.tokens.first().asName()).getOrCreateGroup(name.cutFirst())
} }
} }
internal operator fun Object3D.set(name: Name, obj: Object3D) { internal operator fun Object3D.set(name: Name, obj: Object3D) {
when (name.length) { when (name.length) {
0 -> error("Can't set object with an empty name") 0 -> error("Can't set object with an empty name")
1 -> set(name.first()!!, obj) 1 -> set(name.tokens.first(), obj)
else -> getOrCreateGroup(name.cutLast())[name.last()!!] = obj else -> getOrCreateGroup(name.cutLast())[name.tokens.last()] = obj
} }
} }
internal fun Object3D.findChild(name: Name): Object3D? { internal fun Object3D.findChild(name: Name): Object3D? {
return when { return when {
name.isEmpty() -> this name.isEmpty() -> this
name.length == 1 -> this.children.find { it.name == name.first()!!.toString() } name.length == 1 -> this.children.find { it.name == name.tokens.first().toString() }
else -> findChild(name.first()!!.asName())?.findChild(name.cutFirst()) else -> findChild(name.tokens.first().asName())?.findChild(name.cutFirst())
} }
} }

View File

@ -1,5 +1,7 @@
package hep.dataforge.vision.solid.three package hep.dataforge.vision.solid.three
import hep.dataforge.names.cutFirst
import hep.dataforge.names.firstOrNull
import hep.dataforge.names.toName import hep.dataforge.names.toName
import hep.dataforge.vision.solid.Proxy import hep.dataforge.vision.solid.Proxy
import hep.dataforge.vision.solid.Proxy.Companion.PROXY_CHILD_PROPERTY_PREFIX import hep.dataforge.vision.solid.Proxy.Companion.PROXY_CHILD_PROPERTY_PREFIX
@ -42,8 +44,8 @@ class ThreeProxyFactory(val three: ThreePlugin) : ThreeFactory<Proxy> {
} }
obj.onPropertyChange(this) { name -> obj.onPropertyChange(this) { name ->
if (name.first()?.body == PROXY_CHILD_PROPERTY_PREFIX) { if (name.firstOrNull()?.body == PROXY_CHILD_PROPERTY_PREFIX) {
val childName = name.first()?.index?.toName() ?: error("Wrong syntax for proxy child property: '$name'") val childName = name.firstOrNull()?.index?.toName() ?: error("Wrong syntax for proxy child property: '$name'")
val propertyName = name.cutFirst() val propertyName = name.cutFirst()
val proxyChild = obj[childName] ?: error("Proxy child with name '$childName' not found") val proxyChild = obj[childName] ?: error("Proxy child with name '$childName' not found")
val child = object3D.findChild(childName) ?: error("Object child with name '$childName' not found") val child = object3D.findChild(childName) ?: error("Object child with name '$childName' not found")

View File

@ -55,7 +55,7 @@ fun RBuilder.canvasControls(canvas: ThreeCanvas) = accordion("controls") {
attrs { attrs {
onClickFunction = { onClickFunction = {
val json = (canvas.content as? SolidGroup)?.let { group -> val json = (canvas.content as? SolidGroup)?.let { group ->
SolidManager.jsonForSolids.stringify( SolidManager.jsonForSolids.encodeToString(
SolidGroup.serializer(), SolidGroup.serializer(),
group group
) )
@ -119,7 +119,7 @@ fun Element.displayCanvasControls(canvas: ThreeCanvas, block: TagConsumer<HTMLEl
+"Export" +"Export"
onClickFunction = { onClickFunction = {
val json = (canvas.content as? SolidGroup)?.let { group -> val json = (canvas.content as? SolidGroup)?.let { group ->
SolidManager.jsonForSolids.stringify( SolidManager.jsonForSolids.encodeToString(
SolidGroup.serializer(), SolidGroup.serializer(),
group group
) )

View File

@ -38,7 +38,7 @@ class FX3DPlugin : AbstractPlugin() {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
private fun findObjectFactory(type: KClass<out Solid>): FX3DFactory<Solid>? { private fun findObjectFactory(type: KClass<out Solid>): FX3DFactory<Solid>? {
return (objectFactories[type] ?: context.content<FX3DFactory<*>>(TYPE).values.find { it.type == type }) return (objectFactories[type] ?: context.gather<FX3DFactory<*>>(TYPE).values.find { it.type == type })
as FX3DFactory<Solid>? as FX3DFactory<Solid>?
} }

View File

@ -1,8 +1,6 @@
package hep.dataforge.vision.solid.fx package hep.dataforge.vision.solid.fx
import hep.dataforge.names.Name import hep.dataforge.names.*
import hep.dataforge.names.isEmpty
import hep.dataforge.names.toName
import hep.dataforge.vision.Vision import hep.dataforge.vision.Vision
import hep.dataforge.vision.solid.Proxy import hep.dataforge.vision.solid.Proxy
import javafx.scene.Group import javafx.scene.Group
@ -17,8 +15,8 @@ class FXProxyFactory(val plugin: FX3DPlugin) : FX3DFactory<Proxy> {
val node = plugin.buildNode(prototype) val node = plugin.buildNode(prototype)
obj.onPropertyChange(this) { name-> obj.onPropertyChange(this) { name->
if (name.first()?.body == Proxy.PROXY_CHILD_PROPERTY_PREFIX) { if (name.firstOrNull()?.body == Proxy.PROXY_CHILD_PROPERTY_PREFIX) {
val childName = name.first()?.index?.toName() ?: error("Wrong syntax for proxy child property: '$name'") val childName = name.firstOrNull()?.index?.toName() ?: error("Wrong syntax for proxy child property: '$name'")
val propertyName = name.cutFirst() val propertyName = name.cutFirst()
val proxyChild = obj[childName] ?: error("Proxy child with name '$childName' not found") val proxyChild = obj[childName] ?: error("Proxy child with name '$childName' not found")
val child = node.findChild(childName) ?: error("Object child with name '$childName' not found") val child = node.findChild(childName) ?: error("Object child with name '$childName' not found")
@ -35,7 +33,7 @@ private fun Node.findChild(name: Name): Node? {
} else { } else {
(this as? Group) (this as? Group)
?.children ?.children
?.find { it.properties["name"] as String == name.first()?.toString() } ?.find { it.properties["name"] as String == name.firstOrNull()?.toString() }
?.findChild(name.cutFirst()) ?.findChild(name.cutFirst())
} }
} }

View File

@ -1,205 +1,208 @@
package hep.dataforge.vision.solid //package hep.dataforge.vision.solid
//
import hep.dataforge.meta.JSON_PRETTY //import hep.dataforge.meta.JSON_PRETTY
import kotlinx.serialization.* //import kotlinx.serialization.*
import kotlinx.serialization.json.* //import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.modules.SerialModule //import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.modules.SerialModuleCollector //import kotlinx.serialization.descriptors.StructureKind
import kotlin.reflect.KClass //import kotlinx.serialization.descriptors.UnionKind
//import kotlinx.serialization.json.*
private fun SerialDescriptor.getJsonType() = when (this.kind) { //import kotlinx.serialization.modules.SerialModule
StructureKind.LIST -> "array" //import kotlin.reflect.KClass
PrimitiveKind.BYTE, PrimitiveKind.SHORT, PrimitiveKind.INT, PrimitiveKind.LONG, //
PrimitiveKind.FLOAT, PrimitiveKind.DOUBLE -> "number" //private fun SerialDescriptor.getJsonType() = when (this.kind) {
PrimitiveKind.STRING, PrimitiveKind.CHAR, UnionKind.ENUM_KIND -> "string" // StructureKind.LIST -> "array"
PrimitiveKind.BOOLEAN -> "boolean" // PrimitiveKind.BYTE, PrimitiveKind.SHORT, PrimitiveKind.INT, PrimitiveKind.LONG,
else -> "object" // PrimitiveKind.FLOAT, PrimitiveKind.DOUBLE -> "number"
} // PrimitiveKind.STRING, PrimitiveKind.CHAR, UnionKind.ENUM_KIND -> "string"
// PrimitiveKind.BOOLEAN -> "boolean"
private fun SerialDescriptor.isVisualObject() = serialName.startsWith("solid")||serialName.startsWith("group.solid") // else -> "object"
//}
private const val definitionNode = "\$defs" //
//private fun SerialDescriptor.isVisualObject() = serialName.startsWith("solid")||serialName.startsWith("group.solid")
private fun SerialModule.enumerate(type: KClass<*>): Sequence<SerialDescriptor> { //
val list = ArrayList<SerialDescriptor>() //private const val definitionNode = "\$defs"
fun send(descriptor: SerialDescriptor) = list.add(descriptor) //
//private fun SerialModule.enumerate(type: KClass<*>): Sequence<SerialDescriptor> {
val enumerator = object : SerialModuleCollector { // val list = ArrayList<SerialDescriptor>()
override fun <T : Any> contextual(kClass: KClass<T>, serializer: KSerializer<T>) { // fun send(descriptor: SerialDescriptor) = list.add(descriptor)
if (kClass == type) { //
send(serializer.descriptor) // val enumerator = object : SerialModuleCollector {
} // override fun <T : Any> contextual(kClass: KClass<T>, serializer: KSerializer<T>) {
} // if (kClass == type) {
// send(serializer.descriptor)
override fun <Base : Any, Sub : Base> polymorphic( // }
baseClass: KClass<Base>, // }
actualClass: KClass<Sub>, //
actualSerializer: KSerializer<Sub> // override fun <Base : Any, Sub : Base> polymorphic(
) { // baseClass: KClass<Base>,
if (baseClass == type) { // actualClass: KClass<Sub>,
send(actualSerializer.descriptor) // actualSerializer: KSerializer<Sub>
} // ) {
} // if (baseClass == type) {
// send(actualSerializer.descriptor)
} // }
dumpTo(enumerator) // }
return list.asSequence() //
} // }
// dumpTo(enumerator)
/** // return list.asSequence()
* Creates an [JsonObject] which contains Json Schema of given [descriptor]. //}
* //
* Schema can contain following fields: ///**
* `description`, `type` for all descriptors; // * Creates an [JsonObject] which contains Json Schema of given [descriptor].
* `properties` and `required` for objects; // *
* `enum` for enums; // * Schema can contain following fields:
* `items` for arrays. // * `description`, `type` for all descriptors;
* // * `properties` and `required` for objects;
* User can modify this schema to add additional validation keywords // * `enum` for enums;
* (as per [https://json-schema.org/latest/json-schema-validation.html]) // * `items` for arrays.
* if they want. // *
*/ // * User can modify this schema to add additional validation keywords
private fun jsonSchema(descriptor: SerialDescriptor, context: SerialModule): JsonObject { // * (as per [https://json-schema.org/latest/json-schema-validation.html])
// * if they want.
if (descriptor.serialName in arrayOf( // */
"hep.dataforge.vision.solid.Point3D", //private fun jsonSchema(descriptor: SerialDescriptor, context: SerialModule): JsonObject {
"hep.dataforge.vision.solid.Point3D?", //
"hep.dataforge.vision.solid.Point2D", // if (descriptor.serialName in arrayOf(
"hep.dataforge.vision.solid.Point2D?", // "hep.dataforge.vision.solid.Point3D",
"hep.dataforge.meta.Meta", // "hep.dataforge.vision.solid.Point3D?",
"hep.dataforge.meta.Meta?" // "hep.dataforge.vision.solid.Point2D",
) // "hep.dataforge.vision.solid.Point2D?",
) return json { // "hep.dataforge.meta.Meta",
"\$ref" to "#/$definitionNode/${descriptor.serialName.replace("?", "")}" // "hep.dataforge.meta.Meta?"
} // )
// ) return json {
// "\$ref" to "#/$definitionNode/${descriptor.serialName.replace("?", "")}"
val properties: MutableMap<String, JsonObject> = mutableMapOf() // }
val requiredProperties: MutableSet<String> = mutableSetOf() //
val isEnum = descriptor.kind == UnionKind.ENUM_KIND //
val isPolymorphic = descriptor.kind is PolymorphicKind // val properties: MutableMap<String, JsonObject> = mutableMapOf()
// val requiredProperties: MutableSet<String> = mutableSetOf()
// val isEnum = descriptor.kind == UnionKind.ENUM_KIND
if (!isEnum && !isPolymorphic) descriptor.elementDescriptors().forEachIndexed { index, child -> // val isPolymorphic = descriptor.kind is PolymorphicKind
val elementName = descriptor.getElementName(index) //
//
val elementSchema = when (elementName) { // if (!isEnum && !isPolymorphic) descriptor.elementDescriptors().forEachIndexed { index, child ->
"properties" -> json { // val elementName = descriptor.getElementName(index)
"\$ref" to "#/$definitionNode/hep.dataforge.meta.Meta" //
} // val elementSchema = when (elementName) {
"first", "second" -> json { // "properties" -> buildJsonObject {
"\$ref" to "#/$definitionNode/children" // put("\$ref", "#/$definitionNode/hep.dataforge.meta.Meta")
} // }
"styleSheet" -> json { // "first", "second" -> buildJsonObject {
"type" to "object" // put("\$ref", "#/$definitionNode/children")
"additionalProperties" to json { // }
"\$ref" to "#/$definitionNode/hep.dataforge.meta.Meta" // "styleSheet" -> buildJsonObject {
} // put("type", "object")
} // put("additionalProperties", buildJsonObject {
in arrayOf("children", "prototypes") -> json { // put("\$ref", "#/$definitionNode/hep.dataforge.meta.Meta")
"type" to "object" // })
"additionalProperties" to json { // }
"\$ref" to "#/$definitionNode/children" // in arrayOf("children", "prototypes") -> buildJsonObject {
} // put("type", "object")
} // put("additionalProperties", buildJsonObject {
else -> jsonSchema(child, context) // put("\$ref", "#/$definitionNode/children")
} // })
properties[elementName] = elementSchema // }
// else -> jsonSchema(child, context)
if (!descriptor.isElementOptional(index)) requiredProperties.add(elementName) // }
} // properties[elementName] = elementSchema
//
val jsonType = descriptor.getJsonType() // if (!descriptor.isElementOptional(index)) requiredProperties.add(elementName)
val objectData: MutableMap<String, JsonElement> = mutableMapOf( // }
"description" to JsonLiteral(descriptor.serialName), //
"type" to JsonLiteral(jsonType) // val jsonType = descriptor.getJsonType()
) // val objectData: MutableMap<String, JsonElement> = mutableMapOf(
if (isEnum) { // "description" to JsonLiteral(descriptor.serialName),
val allElementNames = (0 until descriptor.elementsCount).map(descriptor::getElementName) // "type" to JsonLiteral(jsonType)
objectData += "enum" to JsonArray(allElementNames.map(::JsonLiteral)) // )
} // if (isEnum) {
when (jsonType) { // val allElementNames = (0 until descriptor.elementsCount).map(descriptor::getElementName)
"object" -> { // objectData += "enum" to JsonArray(allElementNames.map(::JsonLiteral))
if(descriptor.isVisualObject()) { // }
properties["type"] = json { // when (jsonType) {
"const" to descriptor.serialName // "object" -> {
} // if(descriptor.isVisualObject()) {
} // properties["type"] = json {
objectData["properties"] = JsonObject(properties) // "const" to descriptor.serialName
val required = requiredProperties.map { JsonLiteral(it) } // }
if (required.isNotEmpty()) { // }
objectData["required"] = JsonArray(required) // objectData["properties"] = JsonObject(properties)
} // val required = requiredProperties.map { JsonLiteral(it) }
} // if (required.isNotEmpty()) {
"array" -> objectData["items"] = properties.values.let { // objectData["required"] = JsonArray(required)
check(it.size == 1) { "Array descriptor has returned inconsistent number of elements: expected 1, found ${it.size}" } // }
it.first() // }
} // "array" -> objectData["items"] = properties.values.let {
else -> { /* no-op */ // check(it.size == 1) { "Array descriptor has returned inconsistent number of elements: expected 1, found ${it.size}" }
} // it.first()
} // }
return JsonObject(objectData) // else -> { /* no-op */
} // }
// }
fun main() { // return JsonObject(objectData)
val context = SolidManager.serialModule //}
val definitions = json { //
"children" to json { //fun main() {
"anyOf" to jsonArray { // val context = SolidManager.serialModule
context.enumerate(Solid::class).forEach { // val definitions = json {
if (it.serialName == "hep.dataforge.vis.spatial.SolidGroup") { // "children" to json {
+json { // "anyOf" to jsonArray {
"\$ref" to "#/$definitionNode/${it.serialName}" // context.enumerate(Solid::class).forEach {
} // if (it.serialName == "hep.dataforge.vis.spatial.SolidGroup") {
} else { // +json {
+jsonSchema(it, context) // "\$ref" to "#/$definitionNode/${it.serialName}"
} // }
} // } else {
} // +jsonSchema(it, context)
} // }
"hep.dataforge.meta.Meta" to json { // }
"type" to "object" // }
} // }
"hep.dataforge.vision.solid.Point3D" to json { // "hep.dataforge.meta.Meta" to json {
"type" to "object" // "type" to "object"
"properties" to json { // }
"x" to json { // "hep.dataforge.vision.solid.Point3D" to json {
"type" to "number" // "type" to "object"
} // "properties" to json {
"y" to json { // "x" to json {
"type" to "number" // "type" to "number"
} // }
"z" to json { // "y" to json {
"type" to "number" // "type" to "number"
} // }
} // "z" to json {
} // "type" to "number"
"hep.dataforge.vision.solid.Point2D" to json { // }
"type" to "object" // }
"properties" to json { // }
"x" to json { // "hep.dataforge.vision.solid.Point2D" to json {
"type" to "number" // "type" to "object"
} // "properties" to json {
"y" to json { // "x" to json {
"type" to "number" // "type" to "number"
} // }
} // "y" to json {
} // "type" to "number"
"hep.dataforge.vision.solid.SolidGroup" to jsonSchema( // }
SolidGroup.serializer().descriptor, // }
context // }
) // "hep.dataforge.vision.solid.SolidGroup" to jsonSchema(
// SolidGroup.serializer().descriptor,
} // context
// )
println( //
JSON_PRETTY.stringify( // }
JsonObjectSerializer, //
json { // println(
"\$defs" to definitions // JSON_PRETTY.stringify(
"\$ref" to "#/$definitionNode/hep.dataforge.vision.solid.SolidGroup" // JsonObjectSerializer,
} // json {
) // "\$defs" to definitions
) // "\$ref" to "#/$definitionNode/hep.dataforge.vision.solid.SolidGroup"
} // }
// )
// )
//}
//

View File

@ -1,11 +1,11 @@
package hep.dataforge.vision.solid package hep.dataforge.vision.solid
import org.fxyz3d.geometry.Point3D as FXPoint3D import org.fxyz3d.geometry.Point3D as FXPoint3D
actual data class Point2D(actual var x: Double, actual var y: Double) { public actual data class Point2D(public actual var x: Double, public actual var y: Double) {
actual constructor(x: Number, y: Number) : this(x.toDouble(), y.toDouble()) actual constructor(x: Number, y: Number) : this(x.toDouble(), y.toDouble())
} }
actual class Point3D(val point: FXPoint3D) { public actual class Point3D(val point: FXPoint3D) {
actual constructor(x: Number, y: Number, z: Number) : this( actual constructor(x: Number, y: Number, z: Number) : this(
FXPoint3D( FXPoint3D(
x.toFloat(), x.toFloat(),
@ -14,19 +14,19 @@ actual class Point3D(val point: FXPoint3D) {
) )
) )
actual var x: Double public actual var x: Double
inline get() = point.x.toDouble() inline get() = point.x.toDouble()
inline set(value) { inline set(value) {
point.x = value.toFloat() point.x = value.toFloat()
} }
actual var y: Double public actual var y: Double
inline get() = point.y.toDouble() inline get() = point.y.toDouble()
inline set(value) { inline set(value) {
point.y = value.toFloat() point.y = value.toFloat()
} }
actual var z: Double public actual var z: Double
inline get() = point.z.toDouble() inline get() = point.z.toDouble()
inline set(value) { inline set(value) {
point.z = value.toFloat() point.z = value.toFloat()
@ -45,6 +45,6 @@ actual class Point3D(val point: FXPoint3D) {
} }
} }
actual operator fun Point3D.plus(other: Point3D): Point3D { public actual operator fun Point3D.plus(other: Point3D): Point3D {
return Point3D(point.add(other.point)) return Point3D(point.add(other.point))
} }