JS 3d Visualization

This commit is contained in:
Alexander Nozik 2019-03-06 18:15:30 +03:00
parent 8c77d3800b
commit ec01b0d7a8
28 changed files with 682 additions and 207 deletions

View File

@ -58,6 +58,28 @@ subprojects {
}
}
}
js{
configure(listOf(compilations["main"], compilations["test"])) {
tasks.getByName(compileKotlinTaskName) {
kotlinOptions {
metaInfo = true
sourceMap = true
sourceMapEmbedSources = "always"
moduleKind = "umd"
}
}
}
configure(listOf(compilations["main"])) {
tasks.getByName(compileKotlinTaskName) {
kotlinOptions {
main = "call"
}
}
}
}
targets.all {
sourceSets.all {
languageSettings.progressiveMode = true
@ -119,6 +141,4 @@ subprojects {
}
}
}
}

View File

@ -1,59 +0,0 @@
plugins {
id "org.jetbrains.kotlin.multiplatform"
}
description = "IO for meta"
kotlin {
targets {
fromPreset(presets.jvm, 'jvm')
fromPreset(presets.js, 'js')
// For ARM, preset should be changed to presets.iosArm32 or presets.iosArm64
// For Linux, preset should be changed to e.g. presets.linuxX64
// For MacOS, preset should be changed to e.g. presets.macosX64
//fromPreset(presets.iosX64, 'ios')
}
sourceSets {
commonMain {
dependencies {
api project(":dataforge-meta")
//implementation 'org.jetbrains.kotlin:kotlin-reflect'
api "org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:$serializationVersion"
api "org.jetbrains.kotlinx:kotlinx-io:$ioVersion"
}
}
commonTest {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-test-common'
implementation 'org.jetbrains.kotlin:kotlin-test-annotations-common'
}
}
jvmMain {
dependencies {
api "org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serializationVersion"
api "org.jetbrains.kotlinx:kotlinx-io-jvm:$ioVersion"
}
}
jvmTest {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-test'
implementation 'org.jetbrains.kotlin:kotlin-test-junit'
}
}
jsMain {
dependencies {
api "org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:$serializationVersion"
api "org.jetbrains.kotlinx:kotlinx-io-js:$ioVersion"
}
}
jsTest {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-test-js'
}
}
// iosMain {
// }
// iosTest {
// }
}
}

View File

@ -0,0 +1,57 @@
plugins {
kotlin("multiplatform")
}
description = "IO for meta"
val ioVersion: String by rootProject.extra
val serializationVersion: String by rootProject.extra
kotlin {
jvm()
js()
sourceSets {
val commonMain by getting{
dependencies {
api(project(":dataforge-meta"))
//implementation 'org.jetbrains.kotlin:kotlin-reflect'
api("org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:$serializationVersion")
api("org.jetbrains.kotlinx:kotlinx-io:$ioVersion")
}
}
val commonTest by getting {
dependencies {
implementation("org.jetbrains.kotlin:kotlin-test-common")
implementation("org.jetbrains.kotlin:kotlin-test-annotations-common")
}
}
val jvmMain by getting {
dependencies {
api("org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serializationVersion")
api("org.jetbrains.kotlinx:kotlinx-io-jvm:$ioVersion")
}
}
val jvmTest by getting {
dependencies {
implementation("org.jetbrains.kotlin:kotlin-test")
implementation("org.jetbrains.kotlin:kotlin-test-junit")
}
}
val jsMain by getting {
dependencies {
api("org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:$serializationVersion")
api("org.jetbrains.kotlinx:kotlinx-io-js:$ioVersion")
}
}
val jsTest by getting {
dependencies {
implementation("org.jetbrains.kotlin:kotlin-test-js")
}
}
// iosMain {
// }
// iosTest {
// }
}
}

View File

@ -1,5 +1,8 @@
import org.openjfx.gradle.JavaFXOptions
plugins {
kotlin("multiplatform")
id("org.openjfx.javafxplugin")
}
kotlin {
@ -14,6 +17,7 @@ kotlin {
}
val jvmMain by getting {
dependencies {
//api("no.tornado:tornadofx:1.7.18")
}
}
val jsMain by getting {
@ -21,4 +25,8 @@ kotlin {
}
}
}
}
configure<JavaFXOptions>{
modules("javafx.controls")
}

View File

@ -1,23 +0,0 @@
package hep.dataforge.vis
import javafx.scene.paint.Color
import javafx.scene.paint.PhongMaterial
object Materials{
val RED = PhongMaterial().apply {
diffuseColor = Color.DARKRED
specularColor = Color.RED
}
val WHITE = PhongMaterial().apply {
diffuseColor = Color.WHITE
specularColor = Color.LIGHTBLUE
}
val GREY = PhongMaterial().apply {
diffuseColor = Color.DARKGREY
specularColor = Color.GREY
}
val BLUE = PhongMaterial(Color.BLUE)
}

View File

@ -1,48 +0,0 @@
package hep.dataforge.vis.spatial
import hep.dataforge.context.Context
import hep.dataforge.io.Output
import hep.dataforge.meta.Meta
import hep.dataforge.meta.int
import hep.dataforge.vis.DisplayGroup
import hep.dataforge.vis.DisplayObject
import hep.dataforge.vis.DisplayObjectPropertyListener
import hep.dataforge.vis.transform
import javafx.scene.Group
import javafx.scene.Node
import javafx.scene.paint.Color
import org.fxyz3d.geometry.Point3D
import org.fxyz3d.shapes.primitives.CuboidMesh
/**
* https://github.com/miho/JCSG for operations
*
*/
class FXSpatialRenderer(override val context: Context) : Output<DisplayObject> {
val canvas by lazy { Canvas3D() }
private fun buildObject(obj: DisplayObject): Node {
return when (obj) {
is DisplayGroup -> Group(obj.children.map { buildObject(it) })
is Box -> CuboidMesh(obj.xSize, obj.ySize, obj.zSize).apply {
val listener = DisplayObjectPropertyListener(obj)
this.center = Point3D(obj.x.toFloat(), obj.y.toFloat(), obj.z.toFloat())
this.diffuseColorProperty().bind(listener["color"].transform {
//TODO Move to extension
val int = it.int ?: 0
val red = int and 0x00ff0000 shr 16
val green = int and 0x0000ff00 shr 8
val blue = int and 0x000000ff
return@transform Color.rgb(red, green, blue)
})
}
else -> TODO()
}
}
override fun render(obj: DisplayObject, meta: Meta) {
canvas.world.children.add(buildObject(obj))
}
}

View File

@ -1,42 +0,0 @@
plugins{
kotlin("js")
id("kotlin")
}
// configure(listOf(compilations.main, compilations.test)) {
// tasks.getByName(compileKotlinTaskName).kotlinOptions {
// sourceMap = true
// moduleKind = "umd"
// metaInfo = true
// }
// }
//
// configure(compilations.main) {
// tasks.getByName(compileKotlinTaskName).kotlinOptions {
// main = "call"
// }
// }
dependencies {
implementation("info.laht.threekt:threejs-wrapper:0.88-npm-1")
}
extensions.findByType<KotlinFrontendExtension>()?.apply {
extensions.findByType<NpmExtension>()?.apply {
dependency("three")
dependency("three-orbitcontrols")
devDependency("karma")
}
sourceMaps = true
bundle("webpack") {
this as WebPackExtension
bundleName = "main"
proxyUrl = "http://localhost:8080"
contentPath = file("src/main/web")
sourceMapEnabled = true
mode = "development"
}
}

View File

@ -12,7 +12,7 @@ dependencies{
implementation("org.fxyz3d:fxyz3d:0.4.0")
}
extensions.findByType<JavaFXOptions>()?.apply {
configure<JavaFXOptions> {
modules("javafx.controls")
}

View File

@ -1,8 +1,5 @@
package hep.dataforge.vis
import hep.dataforge.meta.*
import hep.dataforge.names.Name
import hep.dataforge.names.toName
import javafx.beans.binding.ObjectBinding
import tornadofx.*

View File

@ -19,21 +19,34 @@ class Canvas3D : Fragment() {
translateZ = CAMERA_INITIAL_DISTANCE
}
//TODO move up
val cameraShift = CameraTransformer().apply {
private val cameraShift = CameraTransformer().apply {
val cameraFlip = CameraTransformer()
cameraFlip.children.add(camera)
cameraFlip.setRotateZ(180.0)
children.add(cameraFlip)
}
val cameraRotation = CameraTransformer().apply {
val translationXProperty get() = cameraShift.t.xProperty()
var translateX by translationXProperty
val translationYProperty get() = cameraShift.t.yProperty()
var translateY by translationYProperty
val translationZProperty get() = cameraShift.t.zProperty()
var translateZ by translationZProperty
private val cameraRotation = CameraTransformer().apply {
children.add(cameraShift)
ry.angle = CAMERA_INITIAL_Y_ANGLE
rx.angle = CAMERA_INITIAL_X_ANGLE
rz.angle = CAMERA_INITIAL_Z_ANGLE
}
val rotationXProperty get() = cameraRotation.rx.angleProperty()
var angleX by rotationXProperty
val rotationYProperty get() = cameraRotation.ry.angleProperty()
var angleY by rotationYProperty
val rotationZProperty get() = cameraRotation.rz.angleProperty()
var angleZ by rotationZProperty
override val root =borderpane {
center = SubScene(
@ -122,10 +135,6 @@ class Canvas3D : Fragment() {
cameraRotation.rz.angle + mouseDeltaX * MOUSE_SPEED * modifier * ROTATION_SPEED
cameraRotation.rx.angle =
cameraRotation.rx.angle + mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED
// } else if (me.isSecondaryButtonDown()) {
// double z = camera.getTranslateZ();
// double newZ = z + mouseDeltaX * MOUSE_SPEED * modifier*100;
// camera.setTranslateZ(newZ);
} else if (me.isSecondaryButtonDown) {
cameraShift.t.x = cameraShift.t.x + mouseDeltaX * MOUSE_SPEED * modifier * TRACK_SPEED
cameraShift.t.y = cameraShift.t.y + mouseDeltaY * MOUSE_SPEED * modifier * TRACK_SPEED

View File

@ -0,0 +1,54 @@
package hep.dataforge.vis.spatial
import hep.dataforge.vis.DisplayObjectPropertyListener
import javafx.scene.Group
import javafx.scene.Node
import org.fxyz3d.shapes.primitives.CuboidMesh
import tornadofx.*
/**
* https://github.com/miho/JCSG for operations
*
*/
class FX3DOutput(override val context: Context) : Output<Any> {
val canvas by lazy { Canvas3D() }
private fun buildNode(obj: Any): Node? {
return when (obj) {
is DisplayShape3D -> {
val listener = DisplayObjectPropertyListener(obj)
val x = listener["x"].float()
val y = listener["y"].float()
val z = listener["z"].float()
val center = objectBinding(x, y, z) {
Point3D(x.value ?: 0f, y.value ?: 0f, z.value ?: 0f)
}
when (obj) {
is DisplayGroup3D -> Group(obj.children.map { buildNode(it) }).apply {
this.translateXProperty().bind(x)
this.translateYProperty().bind(y)
this.translateZProperty().bind(z)
}
is Box -> CuboidMesh(obj.xSize, obj.ySize, obj.zSize).apply {
this.centerProperty().bind(center)
this.materialProperty().bind(listener["color"].transform { it.material() })
}
else -> {
logger.error { "No renderer defined for ${obj::class}" }
null
}
}
}
is DisplayGroup -> Group(obj.children.map { buildNode(it) }) // a logical group
else -> {
logger.error { "No renderer defined for ${obj::class}" }
null
}
}
}
override fun render(obj: Any, meta: Meta) {
buildNode(obj)?.let { canvas.world.children.add(it) }
}
}

View File

@ -0,0 +1,63 @@
package hep.dataforge.vis.spatial
import javafx.scene.paint.Color
import javafx.scene.paint.Material
import javafx.scene.paint.PhongMaterial
object Materials {
val RED = PhongMaterial().apply {
diffuseColor = Color.DARKRED
specularColor = Color.RED
}
val WHITE = PhongMaterial().apply {
diffuseColor = Color.WHITE
specularColor = Color.LIGHTBLUE
}
val GREY = PhongMaterial().apply {
diffuseColor = Color.DARKGREY
specularColor = Color.GREY
}
val BLUE = PhongMaterial(Color.BLUE)
}
/**
* Infer color based on meta item
*/
fun MetaItem<*>.color(): Color {
return when (this) {
is MetaItem.ValueItem -> if (this.value.type == ValueType.STRING) {
Color.web(this.value.string)
} else {
val int = value.number.toInt()
val red = int and 0x00ff0000 shr 16
val green = int and 0x0000ff00 shr 8
val blue = int and 0x000000ff
Color.rgb(red, green, blue)
}
is MetaItem.NodeItem -> {
Color.rgb(
node["red"]?.int ?: 0,
node["green"]?.int ?: 0,
node["blue"]?.int ?: 0,
node["opacity"]?.double ?: 1.0
)
}
}
}
/**
* Infer FX material based on meta item
*/
fun MetaItem<*>.material(): Material {
return when (this) {
is MetaItem.ValueItem -> PhongMaterial(color())
is MetaItem.NodeItem -> PhongMaterial().apply {
node["color"]?.let { diffuseColor = it.color() }
node["specularColor"]?.let { specularColor = it.color() }
}
}
}

View File

@ -1,8 +1,5 @@
package hep.dataforge.vis.spatial
import hep.dataforge.context.Global
import hep.dataforge.meta.number
import hep.dataforge.vis.DisplayGroup
import javafx.scene.Parent
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
@ -16,7 +13,7 @@ class RendererDemoApp : App(RendererDemoView::class)
class RendererDemoView : View() {
val renderer = FXSpatialRenderer(Global)
val renderer = FX3DOutput(Global)
override val root: Parent = borderpane {
center = renderer.canvas.root
}
@ -51,9 +48,9 @@ class RendererDemoView : View() {
}
}
renderer.canvas.cameraRotation.apply {
ry.angle = -30.0
rx.angle = -15.0
renderer.canvas.apply {
angleY = -30.0
angleX = -15.0
}
}
}

View File

@ -0,0 +1,59 @@
import org.jetbrains.kotlin.gradle.frontend.KotlinFrontendExtension
import org.jetbrains.kotlin.gradle.frontend.npm.NpmExtension
import org.jetbrains.kotlin.gradle.frontend.webpack.WebPackExtension
plugins {
id("kotlin2js")
id("kotlin-dce-js")
id("org.jetbrains.kotlin.frontend")
}
dependencies {
api(project(":dataforge-vis:dataforge-vis-spatial"))
implementation("info.laht.threekt:threejs-wrapper:0.88-npm-1")
}
configure<KotlinFrontendExtension> {
downloadNodeJsVersion = "latest"
configure<NpmExtension> {
dependency("three")
dependency("three-orbitcontrols")
dependency("style-loader")
devDependency("karma")
}
sourceMaps = true
bundle("webpack") {
this as WebPackExtension
bundleName = "main"
proxyUrl = "http://localhost:8080"
contentPath = file("src/main/web")
sourceMapEnabled = true
//mode = "production"
mode = "development"
}
}
tasks{
compileKotlin2Js{
kotlinOptions{
metaInfo = true
outputFile = "${project.buildDir.path}/js/${project.name}.js"
sourceMap = true
moduleKind = "umd"
main = "call"
}
}
compileTestKotlin2Js{
kotlinOptions{
metaInfo = true
outputFile = "${project.buildDir.path}/js/${project.name}-test.js"
sourceMap = true
moduleKind = "umd"
}
}
}

View File

@ -0,0 +1,3 @@
{
"description": "A demo project for particle visualization in JS"
}

View File

@ -0,0 +1,19 @@
package hep.dataforge.vis.hmr
external val module: Module
external interface Module {
val hot: Hot?
}
external interface Hot {
val data: dynamic
fun accept()
fun accept(dependency: String, callback: () -> Unit)
fun accept(dependencies: Array<String>, callback: (updated: Array<String>) -> Unit)
fun dispose(callback: (data: dynamic) -> Unit)
}
external fun require(name: String): dynamic

View File

@ -0,0 +1,50 @@
package hep.dataforge.vis
import hep.dataforge.vis.hmr.module
import hep.dataforge.vis.spatial.ThreeDemoApp
import kotlin.browser.document
import kotlin.dom.hasClass
abstract class ApplicationBase {
abstract val stateKeys: List<String>
abstract fun start(state: Map<String, Any>)
abstract fun dispose(): Map<String, Any>
}
fun main() {
var application: ApplicationBase? = null
val state: dynamic = module.hot?.let { hot ->
hot.accept()
hot.dispose { data ->
data.appState = application?.dispose()
application = null
}
hot.data
}
if (document.body != null) {
application = start(state)
} else {
application = null
document.addEventListener("DOMContentLoaded", { application = start(state) })
}
}
fun start(state: dynamic): ApplicationBase? {
return if (document.body?.hasClass("testApp") == true) {
val application = ThreeDemoApp()
@Suppress("UnsafeCastFromDynamic")
application.start(state?.appState ?: emptyMap())
application
} else {
null
}
}

View File

@ -0,0 +1,64 @@
package hep.dataforge.vis.spatial
import hep.dataforge.context.Global
import hep.dataforge.meta.number
import hep.dataforge.vis.ApplicationBase
import hep.dataforge.vis.DisplayGroup
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlin.browser.document
import kotlin.random.Random
class ThreeDemoApp : ApplicationBase() {
override val stateKeys: List<String> = emptyList()
override fun start(state: Map<String, Any>) {
println("started")
val renderer = ThreeOutput(Global)
document.getElementById("canvas")?.appendChild(renderer.root)
lateinit var group: DisplayGroup
renderer.render {
group = group {
box {
xSize = 100.0
ySize = 100.0
zSize = 100.0
}
box {
x = 110.0
xSize = 100.0
ySize = 100.0
zSize = 100.0
}
}
}
var color by group.properties.number(1530).int
GlobalScope.launch {
val random = Random(111)
while (isActive) {
delay(1000)
color = random.nextInt(0, Int.MAX_VALUE)
}
}
// view.animate()
// view = WebLinesView(document.getElementById("lines")!!, document.getElementById("addForm")!!)
// presenter = LinesPresenter(view)
//
// state["lines"]?.let { linesState ->
// @Suppress("UNCHECKED_CAST")
// presenter.restore(linesState as Array<String>)
// }
}
override fun dispose() = emptyMap<String,Any>()//mapOf("lines" to presenter.dispose())
}

View File

@ -0,0 +1,140 @@
package hep.dataforge.vis.spatial
import hep.dataforge.context.Context
import hep.dataforge.io.Output
import hep.dataforge.meta.Meta
import hep.dataforge.vis.DisplayGroup
import info.laht.threekt.WebGLRenderer
import info.laht.threekt.cameras.PerspectiveCamera
import info.laht.threekt.core.Object3D
import info.laht.threekt.external.controls.OrbitControls
import info.laht.threekt.geometries.BoxBufferGeometry
import info.laht.threekt.lights.AmbientLight
import info.laht.threekt.materials.MeshPhongMaterial
import info.laht.threekt.math.ColorConstants
import info.laht.threekt.objects.Mesh
import info.laht.threekt.scenes.Scene
import kotlin.browser.window
class ThreeOutput(override val context: Context) : Output<Any> {
private val renderer = WebGLRenderer { antialias = true }.apply {
setClearColor(ColorConstants.skyblue, 1)
setSize(window.innerWidth, window.innerHeight)
}
private val scene: Scene = Scene().apply {
add(AmbientLight())
}
private val camera = PerspectiveCamera(
75,
window.innerWidth.toDouble() / window.innerHeight,
0.1,
10000
).apply {
position.z = 4500.0
}
private val controls: OrbitControls = OrbitControls(camera, renderer.domElement)
val root by lazy {
window.addEventListener("resize", {
camera.aspect = window.innerWidth.toDouble() / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight)
}, false)
renderer.domElement
}
private fun buildNode(obj: Any): Object3D? {
return when (obj) {
is DisplayShape3D -> {
// val listener = DisplayObjectPropertyListener(obj)
// val x = listener["x"].float()
// val y = listener["y"].float()
// val z = listener["z"].float()
// val center = objectBinding(x, y, z) {
// Vector3(x.value ?: 0f, y.value ?: 0f, z.value ?: 0f)
// }
when (obj) {
is DisplayGroup3D -> Group(obj.children.mapNotNull { buildNode(it) }).apply {
this.translateX(obj.x)
this.translateY(obj.y)
this.translateZ(obj.z)
}
is Box -> {
val geometry = BoxBufferGeometry(obj.xSize, obj.ySize, obj.zSize)
.translate(obj.x, obj.y, obj.z)
val material = MeshPhongMaterial().apply {
this.color.set(ColorConstants.darkgreen)
}
Mesh(geometry, material)
}
else -> {
logger.error { "No renderer defined for ${obj::class}" }
null
}
}
}
is DisplayGroup -> Group(obj.children.mapNotNull { buildNode(it) }) // a logical group
else -> {
logger.error { "No renderer defined for ${obj::class}" }
null
}
}
}
override fun render(obj: Any, meta: Meta) {
buildNode(obj)?.let { scene.add(it) }
}
// init {
// val cube: Mesh
// cube = Mesh(
// BoxBufferGeometry(1, 1, 1),
// MeshPhongMaterial().apply {
// this.color.set(ColorConstants.darkgreen)
// }
// ).also(scene::add)
//
// Mesh(cube.geometry as BufferGeometry,
// MeshBasicMaterial().apply {
// this.wireframe = true
// this.color.set(ColorConstants.black)
// }
// ).also(cube::add)
//
// val points = CatmullRomCurve3(
// arrayOf(
// Vector3(-10, 0, 10),
// Vector3(-5, 5, 5),
// Vector3(0, 0, 0),
// Vector3(5, -5, 5),
// Vector3(10, 0, 10)
// )
// ).getPoints(50)
//
// val geometry = BufferGeometry().setFromPoints(points)
//
// val material = LineBasicMaterial().apply {
// color.set(0xff0000)
// }
//
// // Create the final object to add to the scene
// Line(geometry, material).apply(scene::add)
// }
// fun animate() {
// window.requestAnimationFrame {
// cube.rotation.x += 0.01
// cube.rotation.y += 0.01
// animate()
// }
// renderer.render(scene, camera)
// }
}

View File

@ -0,0 +1,13 @@
package hep.dataforge.vis.spatial
import info.laht.threekt.core.Object3D
/**
* Utility methods for three.kt.
* TODO move to three project
*/
@Suppress("FunctionName")
fun Group(children: Collection<Object3D>) = info.laht.threekt.objects.Group().apply {
children.forEach { this.add(it) }
}

View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<title>Three js demo for particle physics</title>
<style>
body {
margin: 0px;
overflow: hidden;
}
</style>
<!--<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/three.js/88/three.min.js"></script>-->
<!--<script type="text/javascript" src="js/OrbitControls.js"></script>-->
<script type="text/javascript" language="JavaScript" src="main.bundle.js"></script>
</head>
<body class="testApp">
<h1>Demo canvas</h1>
<div id="canvas"></div>
</body>
</html>

View File

@ -0,0 +1 @@
config.module.rules.push({ test: /\.css$/, loader: "style!css" });

View File

@ -4,7 +4,26 @@ plugins {
kotlin {
jvm()
js()
js {
configure(listOf(compilations["main"], compilations["test"])) {
tasks.getByName(compileKotlinTaskName) {
kotlinOptions {
metaInfo = true
sourceMap = true
sourceMapEmbedSources = "always"
moduleKind = "umd"
}
}
}
configure(listOf(compilations["main"])) {
tasks.getByName(compileKotlinTaskName) {
kotlinOptions {
main = "call"
}
}
}
}
sourceSets {
val commonMain by getting {
@ -23,4 +42,5 @@ kotlin {
}
}
}
}
}

View File

@ -6,7 +6,7 @@ import hep.dataforge.vis.DisplayGroup
import hep.dataforge.vis.DisplayObject
import hep.dataforge.vis.double
class Box(parent: DisplayObject?, meta: Meta) : DisplayObject3D(parent, TYPE, meta) {
class Box(parent: DisplayObject?, meta: Meta) : DisplayShape3D(parent, TYPE, meta) {
var xSize by double(1.0)
var ySize by double(1.0)
var zSize by double(1.0)

View File

@ -7,18 +7,32 @@ import hep.dataforge.vis.*
import hep.dataforge.vis.DisplayObject.Companion.DEFAULT_TYPE
open class DisplayObject3D(parent: DisplayObject?, type: String, meta: Meta) : DisplayLeaf(parent, type, meta) {
var x by double(0.0)
var y by double(0.0)
var z by double(0.0)
interface DisplayObject3D : DisplayObject {
val x: Double
val y: Double
val z: Double
companion object {
const val TYPE = "geometry.spatial"
}
}
open class DisplayShape3D(parent: DisplayObject?, type: String, meta: Meta) :
DisplayLeaf(parent, type, meta), DisplayObject3D {
override var x by double(0.0, inherited = false)
override var y by double(0.0, inherited = false)
override var z by double(0.0, inherited = false)
}
class DisplayGroup3D(parent: DisplayObject?, type: String, meta: Meta) : DisplayNode(parent, type, meta),
DisplayObject3D {
override var x by double(0.0, inherited = false)
override var y by double(0.0, inherited = false)
override var z by double(0.0, inherited = false)
}
fun DisplayGroup.group(meta: Meta = EmptyMeta, action: DisplayGroup.() -> Unit = {}) =
DisplayNode(this, DEFAULT_TYPE, meta).apply(action).also{addChild(it)}
DisplayNode(this, DEFAULT_TYPE, meta).apply(action).also { addChild(it) }
fun Output<DisplayObject>.render(meta: Meta = EmptyMeta, action: DisplayGroup.() -> Unit) =

View File

@ -0,0 +1,17 @@
package hep.dataforge.vis.spatial
import hep.dataforge.meta.EmptyMeta
import hep.dataforge.meta.Meta
import hep.dataforge.vis.DisplayGroup
import hep.dataforge.vis.DisplayObject
class Extruded(parent: DisplayObject?, meta: Meta) : DisplayShape3D(parent, TYPE, meta) {
companion object {
const val TYPE = "geometry.spatial.extruded"
}
}
fun DisplayGroup.extrude(meta: Meta = EmptyMeta, action: Extruded.() -> Unit = {}) =
Extruded(this, meta).apply(action).also { addChild(it) }

View File

@ -5,6 +5,7 @@ import hep.dataforge.names.Name
import hep.dataforge.names.toName
import hep.dataforge.values.Value
import kotlin.jvm.JvmName
import kotlin.properties.ReadOnlyProperty
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
@ -95,4 +96,25 @@ fun DisplayObject.double(default: Double, key: String? = null, inherited: Boolea
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.double }
inline fun <reified E : Enum<E>> DisplayObject.enum(default: E, key: String? = null, inherited: Boolean = true) =
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { item -> item.string?.let { enumValueOf<E>(it) } }
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { item -> item.string?.let { enumValueOf<E>(it) } }
//merge properties
fun <T> DisplayObject.merge(
key: String? = null,
transformer: (Sequence<MetaItem<*>>) -> T
): ReadOnlyProperty<DisplayObject, T> {
return object : ReadOnlyProperty<DisplayObject, T> {
override fun getValue(thisRef: DisplayObject, property: KProperty<*>): T {
val name = key?.toName() ?: property.name.toName()
val sequence = sequence<MetaItem<*>> {
var thisObj: DisplayObject? = thisRef
while (thisObj != null) {
thisObj.properties[name]?.let { yield(it) }
thisObj = thisObj.parent
}
}
return transformer(sequence)
}
}
}

View File

@ -1,16 +1,16 @@
pluginManagement {
repositories {
mavenCentral()
jcenter()
gradlePluginPortal()
maven("https://dl.bintray.com/kotlin/kotlin-eap/")
maven("https://dl.bintray.com/kotlin/kotlin-eap")
}
resolutionStrategy {
eachPlugin {
when (requested.id.id) {
"kotlinx-atomicfu" -> useModule("org.jetbrains.kotlinx:atomicfu-gradle-plugin:${requested.version}")
"kotlin-multiplatform" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${requested.version}")
"org.jetbrains.kotlin.frontend" -> useModule("org.jetbrains.kotlin:kotlin-frontend-plugin:0.0.45")
"kotlin2js" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${requested.version}")
"org.jetbrains.kotlin.frontend" -> useModule("org.jetbrains.kotlin:kotlin-frontend-plugin:0.0.45")
}
}
}
@ -29,5 +29,6 @@ include(
":dataforge-scripting",
":dataforge-vis",
":dataforge-vis:dataforge-vis-spatial",
":dataforge-vis:dataforge-vis-fx"
)
":dataforge-vis:dataforge-vis-spatial-fx",
":dataforge-vis:dataforge-vis-spatial-js"
)