New properties #34

Merged
altavir merged 19 commits from new-properties into dev 2020-12-29 13:35:01 +03:00
24 changed files with 279 additions and 166 deletions
Showing only changes of commit 51af6b9378 - Show all commits

View File

@ -1,12 +1,11 @@
package ru.mipt.npm.sat
import hep.dataforge.context.Global
import hep.dataforge.names.toName
import hep.dataforge.vision.solid.Solid
import hep.dataforge.vision.solid.clear
import hep.dataforge.vision.solid.color
import hep.dataforge.vision.solid.invoke
import hep.dataforge.vision.solid.*
import hep.dataforge.vision.three.server.*
import hep.dataforge.vision.visionManager
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
@ -16,10 +15,14 @@ import kotlinx.html.h1
import kotlin.random.Random
fun main() {
val satContext = Global.context("sat") {
plugin(SolidManager)
}
//Create a geometry
val sat = visionOfSatellite(ySegments = 3)
val server = visionManager.serve {
val server = satContext.visionManager.serve {
//use client library
useThreeJs()
//use css

View File

@ -12,6 +12,16 @@ repositories{
}
kotlin {
js(IR) {
browser {
webpackTask {
this.outputFileName = "js/visionforge-playground.js"
}
}
binaries.executable()
}
jvm{
compilations.all {
kotlinOptions.jvmTarget = "11"
@ -20,30 +30,39 @@ kotlin {
useJUnitPlatform()
}
}
js(IR) {
browser {
afterEvaluate {
val jsBrowserDistribution by tasks.getting
tasks.getByName<ProcessResources>("jvmProcessResources") {
dependsOn(jsBrowserDistribution)
afterEvaluate {
from(jsBrowserDistribution)
}
}
binaries.executable()
}
sourceSets {
commonMain {
val commonMain by getting {
dependencies {
implementation(project(":visionforge-solid"))
implementation(project(":visionforge-gdml"))
implementation(project(":visionforge-plotly"))
}
}
}
}
val jsMain by getting{
dependencies {
implementation(project(":ui:bootstrap"))
implementation(project(":visionforge-threejs"))
}
}
val jvmMain by getting{
dependencies {
implementation(project(":visionforge-server"))
implementation("com.github.Ricky12Awesome:json-schema-serialization:0.6.6")
implementation(project(":visionforge-threejs:visionforge-threejs-server"))
}
}
}

View File

@ -0,0 +1,2 @@

View File

@ -1,58 +1,67 @@
import hep.dataforge.Application
import hep.dataforge.startApplication
import hep.dataforge.vision.bootstrap.visionPropertyEditor
import hep.dataforge.vision.react.ThreeCanvasComponent
import hep.dataforge.vision.react.objectTree
import hep.dataforge.vision.solid.*
import hep.dataforge.vision.solid.specifications.Canvas3DOptions
import kotlinx.browser.document
import org.w3c.dom.HTMLElement
import react.RBuilder
import react.child
import react.dom.div
import react.dom.render
fun RBuilder.threeCanvas(object3D: Solid, options: Canvas3DOptions.() -> Unit = {}) {
child(ThreeCanvasComponent) {
attrs {
this.obj = object3D
this.options = Canvas3DOptions(options)
}
}
}
private class PlayGroundApp : Application {
override fun start(state: Map<String, Any>) {
val element =
document.getElementById("app") as? HTMLElement ?: error("Element with id 'canvas' not found on page")
val obj = SolidGroup().apply {
box(100, 100, 100, name = "A")
group("B") {
position = Point3D(120, 0, 0)
box(100, 100, 100, name = "C")
}
}
render(element) {
div("row") {
div("col-3") {
objectTree(obj)
}
div("col-6") {
threeCanvas(obj)
}
div("col-3") {
visionPropertyEditor(obj)
}
}
}
}
import hep.dataforge.context.Context
import hep.dataforge.context.Global
import hep.dataforge.meta.DFExperimental
import hep.dataforge.vision.client.VisionClient
import hep.dataforge.vision.client.renderAllVisions
import hep.dataforge.vision.plotly.PlotlyPlugin
import hep.dataforge.vision.solid.three.ThreePlugin
import kotlinx.browser.window
//fun RBuilder.threeCanvas(object3D: Solid, options: Canvas3DOptions.() -> Unit = {}) {
// child(ThreeCanvasComponent) {
// attrs {
// this.obj = object3D
// this.options = Canvas3DOptions(options)
// }
// }
//}
//
//private class PlayGroundApp : Application {
//
// override fun start(state: Map<String, Any>) {
//
// val element =
// document.getElementById("app") as? HTMLElement ?: error("Element with id 'canvas' not found on page")
//
// val obj = SolidGroup().apply {
// box(100, 100, 100, name = "A")
// group("B") {
// position = Point3D(120, 0, 0)
// box(100, 100, 100, name = "C")
// }
// }
//
// render(element) {
// div("row") {
// div("col-3") {
// objectTree(obj)
// }
// div("col-6") {
// threeCanvas(obj)
// }
// div("col-3") {
// visionPropertyEditor(obj)
// }
// }
// }
// }
//
//}
public val visionContext: Context = Global.context("VISION") {
plugin(ThreePlugin)
plugin(PlotlyPlugin)
plugin(VisionClient)
}
@DFExperimental
fun main() {
startApplication(::PlayGroundApp)
//Loading three-js renderer
val clientManager = visionContext.plugins.fetch(VisionClient)
//Fetch from server and render visions for all outputs
window.onload = {
clientManager.renderAllVisions()
}
//startApplication(::PlayGroundApp)
}

View File

@ -4,21 +4,20 @@ import hep.dataforge.meta.DFExperimental
import hep.dataforge.vision.ResourceLocation
import hep.dataforge.vision.VisionManager
import hep.dataforge.vision.html.fragment
import hep.dataforge.vision.three.server.makeFile
import hep.dataforge.vision.three.server.solid
import kotlinx.html.h1
import java.nio.file.Paths
import kotlin.random.Random
@OptIn(DFExperimental::class)
fun main() {
val random = Random(112233)
val fragment = VisionManager.fragment {
h1 { +"Happy new year!" }
vision {
solid {
repeat(100) {
sphere(5) {
sphere(5, name = "sphere[$it]") {
x = random.nextDouble(-300.0, 300.0)
y = random.nextDouble(-300.0, 300.0)
z = random.nextDouble(-300.0, 300.0)
@ -33,5 +32,9 @@ fun main() {
}
}
fragment.makeFile(Paths.get("stars.html"), resourceLocation = ResourceLocation.EMBED)
visionContext.makeVisionFile(
fragment,
Paths.get("randomSpheres.html"),
resourceLocation = ResourceLocation.EMBED
)
}

View File

@ -0,0 +1,38 @@
package hep.dataforge.vision.solid
import hep.dataforge.context.Context
import hep.dataforge.context.Global
import hep.dataforge.meta.DFExperimental
import hep.dataforge.vision.ResourceLocation
import hep.dataforge.vision.VisionManager
import hep.dataforge.vision.html.HtmlVisionFragment
import hep.dataforge.vision.makeVisionFile
import hep.dataforge.vision.scriptHeader
import hep.dataforge.vision.three.server.VisionServer
import hep.dataforge.vision.three.server.useScript
import java.nio.file.Path
/**
* A global vision context used to resolve different vision renderers
*/
@DFExperimental
public val visionContext: Context = Global.context("VISION") {
plugin(VisionManager)
plugin(SolidManager)
}
public fun VisionServer.usePlayground(): Unit {
useScript("js/visionforge-playground.js")
}
@DFExperimental
public fun Context.makeVisionFile(
fragment: HtmlVisionFragment,
path: Path? = null,
title: String = "VisionForge page",
resourceLocation: ResourceLocation = ResourceLocation.SYSTEM,
show: Boolean = true,
): Unit = makeVisionFile(fragment, path = path, title = title, show = show) { actualPath ->
scriptHeader("js/visionforge-playground.js", actualPath, resourceLocation)
}

View File

@ -4,8 +4,6 @@ import hep.dataforge.meta.DFExperimental
import hep.dataforge.vision.ResourceLocation
import hep.dataforge.vision.VisionManager
import hep.dataforge.vision.html.fragment
import hep.dataforge.vision.three.server.makeFile
import hep.dataforge.vision.three.server.solid
@OptIn(DFExperimental::class)
fun main() {
@ -17,5 +15,5 @@ fun main() {
}
}
fragment.makeFile(resourceLocation = ResourceLocation.SYSTEM)
visionContext.makeVisionFile(fragment = fragment, resourceLocation = ResourceLocation.SYSTEM)
}

View File

@ -33,7 +33,7 @@ rootProject.name = "visionforge"
include(
// ":ui",
":ui:react",
":ui:ring",
// ":ui:ring",
// ":ui:material",
":ui:bootstrap",
":visionforge-core",
@ -43,6 +43,7 @@ include(
":visionforge-threejs:visionforge-threejs-server",
":visionforge-gdml",
":visionforge-server",
":visionforge-plotly",
":demo:spatial-showcase",
":demo:gdml",
":demo:muon-monitor",

View File

@ -16,7 +16,6 @@ import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.css.th
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
@ -27,7 +26,6 @@ internal data class PropertyListener(
val action: (name: Name) -> Unit,
)
/**
* A full base implementation for a [Vision]
* @param properties Object own properties excluding styles and inheritance
@ -53,7 +51,7 @@ public open class VisionBase(internal var properties: Config? = null) : Vision {
override val meta: Meta get() = properties ?: Meta.EMPTY
@Synchronized
private fun getOrCreateConfig(): Config {
protected fun getOrCreateConfig(): Config {
if (properties == null) {
val newProperties = Config()
newProperties.onChange(this) { name, oldItem, newItem ->
@ -91,7 +89,6 @@ public open class VisionBase(internal var properties: Config? = null) : Vision {
yield(descriptor?.get(name)?.defaultItem())
}.merge()
@Synchronized
override fun setProperty(name: Name, item: MetaItem?, notify: Boolean) {
getOrCreateConfig().setItem(name, item)
if (notify) {
@ -117,6 +114,7 @@ public open class VisionBase(internal var properties: Config? = null) : Vision {
@Transient
private val propertyInvalidationFlow: MutableSharedFlow<Name> = MutableSharedFlow()
@DFExperimental
override val propertyChanges: Flow<Name> get() = propertyInvalidationFlow
override fun onPropertyChange(scope: CoroutineScope, callback: suspend (Name) -> Unit) {

View File

@ -42,8 +42,8 @@ internal const val VISIONFORGE_ASSETS_PATH = ".dataforge/vision/assets"
* Check if the asset exists in given local location and put it there if it does not
* @param
*/
internal fun checkOrStoreFile(basePath: Path, filePath: Path, resource: String): Path {
val fullPath = basePath.resolveSibling(filePath).toAbsolutePath().resolve(resource)
internal fun checkOrStoreFile(htmlPath: Path, filePath: Path, resource: String): Path {
val fullPath = htmlPath.resolveSibling(filePath).toAbsolutePath().resolve(resource)
if (Files.exists(fullPath)) {
//TODO checksum
@ -55,8 +55,8 @@ internal fun checkOrStoreFile(basePath: Path, filePath: Path, resource: String):
Files.write(fullPath, bytes, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)
}
return if (basePath.isAbsolute && fullPath.startsWith(basePath)) {
basePath.relativize(fullPath)
return if (htmlPath.isAbsolute && fullPath.startsWith(htmlPath.parent)) {
htmlPath.parent.relativize(fullPath)
} else {
fullPath
}
@ -100,14 +100,14 @@ internal fun fileCssHeader(
* Make a script header, automatically copying file to appropriate location
*/
@DFExperimental
public fun Context.Companion.scriptHeader(
public fun Context.scriptHeader(
scriptResource: String,
basePath: Path,
htmlPath: Path,
resourceLocation: ResourceLocation,
): HtmlFragment {
val targetPath = when (resourceLocation) {
ResourceLocation.LOCAL -> checkOrStoreFile(
basePath,
htmlPath,
Path.of(VISIONFORGE_ASSETS_PATH),
scriptResource
)

View File

@ -1,9 +1,16 @@
package hep.dataforge.vision
import hep.dataforge.context.Context
import hep.dataforge.meta.DFExperimental
import hep.dataforge.vision.html.*
import kotlinx.html.*
import hep.dataforge.vision.html.HtmlFragment
import hep.dataforge.vision.html.HtmlVisionFragment
import hep.dataforge.vision.html.embedVisionFragment
import hep.dataforge.vision.html.fragment
import kotlinx.html.body
import kotlinx.html.head
import kotlinx.html.meta
import kotlinx.html.stream.createHTML
import kotlinx.html.title
import java.awt.Desktop
import java.nio.file.Files
import java.nio.file.Path
@ -13,12 +20,12 @@ import java.nio.file.Path
* Make a file with the embedded vision data
*/
@DFExperimental
public fun HtmlVisionFragment.makeFile(
manager: VisionManager,
vararg headers: HtmlFragment,
public fun Context.makeVisionFile(
fragment: HtmlVisionFragment,
path: Path? = null,
title: String = "VisionForge page",
show: Boolean = true,
headerBuilder: (Path) -> HtmlFragment,
) {
val actualFile = path?.let {
Path.of(System.getProperty("user.home")).resolve(path)
@ -28,14 +35,12 @@ public fun HtmlVisionFragment.makeFile(
head {
meta {
charset = "utf-8"
headers.forEach {
fragment(it)
}
fragment(headerBuilder(actualFile))
}
title(title)
}
body {
embedVisionFragment(manager, fragment = this@makeFile)
embedVisionFragment(visionManager, fragment = fragment)
}
}.finalize()

View File

@ -0,0 +1,20 @@
plugins {
id("ru.mipt.npm.mpp")
}
kscience {
useSerialization()
}
val plotlyVersion = "0.3.1-dev"
kotlin {
sourceSets {
commonMain {
dependencies {
api(project(":visionforge-core"))
api("kscience.plotlykt:plotlykt-core:${plotlyVersion}")
}
}
}
}

View File

@ -0,0 +1,12 @@
package hep.dataforge.vision.plotly
import hep.dataforge.meta.DFExperimental
import hep.dataforge.vision.VisionBase
import hep.dataforge.vision.html.VisionOutput
import kscience.plotly.Plot
import kscience.plotly.Plotly
public class VisionOfPlotly(public val plot: Plot): VisionBase(plot.config)
@DFExperimental
public inline fun VisionOutput.plotly(block: Plot.() -> Unit): VisionOfPlotly = VisionOfPlotly(Plotly.plot(block))

View File

@ -0,0 +1,33 @@
package hep.dataforge.vision.plotly
import hep.dataforge.context.AbstractPlugin
import hep.dataforge.context.Context
import hep.dataforge.context.PluginFactory
import hep.dataforge.context.PluginTag
import hep.dataforge.meta.Meta
import hep.dataforge.vision.Vision
import hep.dataforge.vision.client.ElementVisionRenderer
import kscience.plotly.PlotlyConfig
import kscience.plotly.plot
import org.w3c.dom.Element
import kotlin.reflect.KClass
public class PlotlyPlugin : AbstractPlugin(), ElementVisionRenderer {
override val tag: PluginTag get() = Companion.tag
override fun rateVision(vision: Vision): Int =
if (vision is VisionOfPlotly) ElementVisionRenderer.DEFAULT_RATING else ElementVisionRenderer.ZERO_RATING
override fun render(element: Element, vision: Vision, meta: Meta) {
val plot = (vision as? VisionOfPlotly)?.plot ?: error("Only VisionOfPlotly visions are supported")
val config = PlotlyConfig.read(meta)
element.plot(plot, config)
}
public companion object : PluginFactory<PlotlyPlugin> {
override val tag: PluginTag = PluginTag("vision.plotly", PluginTag.DATAFORGE_GROUP)
override val type: KClass<PlotlyPlugin> = PlotlyPlugin::class
override fun invoke(meta: Meta, context: Context): PlotlyPlugin = PlotlyPlugin()
}
}

View File

@ -0,0 +1,15 @@
package hep.dataforge.vision.plotly
//public fun main() {
// val visionContext: Context = Global.context("vision-client")
//
// //Loading three-js renderer
// val threePlugin = visionContext.plugins.fetch(PlotlyPlugin)
//
// val clientManager = visionContext.plugins.fetch(VisionClient)
//
// //Fetch from server and render visions for all outputs
// window.onload = {
// clientManager.renderAllVisions()
// }
//}

View File

@ -4,6 +4,7 @@ import hep.dataforge.context.AbstractPlugin
import hep.dataforge.context.Context
import hep.dataforge.context.PluginFactory
import hep.dataforge.context.PluginTag
import hep.dataforge.meta.DFExperimental
import hep.dataforge.meta.Meta
import hep.dataforge.names.Name
import hep.dataforge.names.toName
@ -12,6 +13,7 @@ import hep.dataforge.vision.VisionBase
import hep.dataforge.vision.VisionGroupBase
import hep.dataforge.vision.VisionManager
import hep.dataforge.vision.VisionManager.Companion.VISION_SERIALIZER_MODULE_TARGET
import hep.dataforge.vision.html.VisionOutput
import kotlinx.serialization.PolymorphicSerializer
import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.PolymorphicModuleBuilder
@ -73,3 +75,6 @@ public class SolidManager(meta: Meta) : AbstractPlugin(meta) {
public fun decodeFromString(str: String): Solid = jsonForSolids.decodeFromString(PolymorphicSerializer(Solid::class), str)
}
}
@DFExperimental
public inline fun VisionOutput.solid(block: SolidGroup.() -> Unit): SolidGroup = SolidGroup().apply(block)

View File

@ -5,6 +5,7 @@ import hep.dataforge.names.Name
public class Canvas3DOptions : Scheme() {
public var axes: Axes by spec(Axes)
public var light: Light by spec(Light)
public var camera: Camera by spec(Camera)
public var controls: Controls by spec(Controls)

View File

@ -0,0 +1,8 @@
package hep.dataforge.vision.solid.specifications
import hep.dataforge.meta.Scheme
import hep.dataforge.meta.SchemeSpec
public class Light : Scheme() {
public companion object : SchemeSpec<Light>(::Light)
}

View File

@ -51,7 +51,7 @@ public class ThreeCanvas(
public var axes: AxesHelper = AxesHelper(options.axes.size.toInt()).apply { visible = options.axes.visible }
private set
private val light = AmbientLight(0x404040)
private var light = buildLight(options.light)
private val scene: Scene = Scene().apply {
add(axes)
@ -169,6 +169,7 @@ public class ThreeCanvas(
}
}
private fun buildLight(spec: Light): info.laht.threekt.lights.Light = AmbientLight(0x404040)
private fun buildCamera(spec: Camera) = PerspectiveCamera(
spec.fov,

View File

@ -28,7 +28,7 @@
package info.laht.threekt.helpers
import info.laht.threekt.core.Object3D
import info.laht.threekt.lights.HemiSphereLight
import info.laht.threekt.lights.HemisphereLight
import info.laht.threekt.lights.Light
/**
@ -39,7 +39,7 @@ import info.laht.threekt.lights.Light
* @param color (optional) if this is not the set the helper will take the color of the light.
*/
external class HemisphereLightHelper(
light: HemiSphereLight,
light: HemisphereLight,
size: Number,
color: Int = definedExternally
) : Object3D {

View File

@ -34,7 +34,7 @@ import info.laht.threekt.math.Color
*
* This light cannot be used to cast shadows.
*/
external class HemiSphereLight(
external class HemisphereLight(
skyColor: Int = definedExternally,
groundColor: Int = definedExternally,
intensity: Number = definedExternally
@ -42,6 +42,6 @@ external class HemiSphereLight(
var groundColor: Color
fun copy(light: HemiSphereLight): HemiSphereLight
fun copy(light: HemisphereLight): HemisphereLight
}

View File

@ -1,8 +0,0 @@
package hep.dataforge.vision.three.server
import hep.dataforge.context.Context
import hep.dataforge.vision.VisionManager
public expect val visionContext: Context
public val visionManager: VisionManager get() = visionContext.plugins.fetch(VisionManager)

View File

@ -1,46 +1,18 @@
package hep.dataforge.vision.three.server
import hep.dataforge.context.Context
import hep.dataforge.context.Global
import hep.dataforge.vision.client.VisionClient
import hep.dataforge.vision.client.renderAllVisions
import hep.dataforge.vision.solid.three.ThreePlugin
import kotlinx.browser.window
//FIXME check plugin loading in JS
//public actual val visionContext: Context = Global.context("vision-client") {
// //Loading three-js renderer
// plugin(ThreePlugin)
//}
public actual val visionContext: Context = Global.context("vision-client").apply {
//Loading three-js renderer
plugins.fetch(ThreePlugin)
}
public val clientManager: VisionClient get() = visionContext.plugins.fetch(VisionClient)
///**
// * Render all visions in the document using registered renderers
// */
//@JsExport
//public fun renderVisions() {
// //Fetch from server and render visions for all outputs
// window.onload = {
// clientManager.renderAllVisions()
// }
//}
//
///**
// * Render all visions in a given element, using registered renderers
// */
//@JsExport
//public fun renderAllVisionsAt(element: Element) {
// clientManager.renderAllVisionsAt(element)
//}
public fun main() {
//Loading three-js renderer
val visionContext = Global.context("threejs") {
plugin(ThreePlugin)
}
val clientManager = visionContext.plugins.fetch(VisionClient)
//Fetch from server and render visions for all outputs
window.onload = {
clientManager.renderAllVisions()

View File

@ -1,47 +1,25 @@
package hep.dataforge.vision.three.server
import hep.dataforge.context.Context
import hep.dataforge.context.Global
import hep.dataforge.meta.DFExperimental
import hep.dataforge.vision.ResourceLocation
import hep.dataforge.vision.html.HtmlVisionFragment
import hep.dataforge.vision.html.VisionOutput
import hep.dataforge.vision.makeFile
import hep.dataforge.vision.makeVisionFile
import hep.dataforge.vision.scriptHeader
import hep.dataforge.vision.solid.SolidGroup
import hep.dataforge.vision.solid.SolidManager
import java.nio.file.Files
import java.nio.file.Path
public actual val visionContext: Context = Global.context("vision-server") {
//Loading solid manager for the backend (it does not know about three
plugin(SolidManager)
}
public fun VisionServer.useThreeJs(): Unit {
useScript("js/visionforge-three.js")
// header {
// script {
// unsafe {
// +"renderThreeVisions()"
// }
// }
// }
}
@DFExperimental
public inline fun VisionOutput.solid(block: SolidGroup.() -> Unit): SolidGroup = SolidGroup().apply(block)
@OptIn(DFExperimental::class)
public fun HtmlVisionFragment.makeFile(
public fun Context.makeVisionFile(
fragment: HtmlVisionFragment,
path: Path? = null,
title: String = "VisionForge page",
resourceLocation: ResourceLocation = ResourceLocation.SYSTEM,
show: Boolean = true,
) {
val actualPath = path?.let {
Path.of(System.getProperty("user.home")).resolve(path)
} ?: Files.createTempFile("tempPlot", ".html")
val scriptHeader = Context.scriptHeader("js/visionforge-three.js", actualPath, resourceLocation)
makeFile(visionManager, path = path, show = show, title = title, headers = arrayOf(scriptHeader))
): Unit = makeVisionFile(fragment, path = path, title = title, show = show) { actualPath ->
scriptHeader("js/visionforge-three.js", actualPath, resourceLocation)
}