From a7432a2b33bf434beee8d0cf82fa0e7140b539d9 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 9 Mar 2019 11:39:01 +0300 Subject: [PATCH] Working on convex geometry for three --- dataforge-vis-spatial-js/build.gradle.kts | 4 +- .../hep/dataforge/vis/spatial/ThreeDemoApp.kt | 14 +++ .../vis/spatial/ThreeObjectBuilder.kt | 87 +++++++++++++++++++ .../hep/dataforge/vis/spatial/ThreeOutput.kt | 50 +++-------- .../vis/spatial/three/ConvexGeometry.kt | 7 ++ .../vis/spatial/three/EdgesGeometry.kt | 11 +++ .../vis/spatial/{ => three}/three.kt | 6 +- .../hep/dataforge/vis/spatial/Convex.kt | 41 +++++++++ .../hep/dataforge/vis/spatial/Geometry.kt | 14 ++- 9 files changed, 190 insertions(+), 44 deletions(-) create mode 100644 dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/ThreeObjectBuilder.kt create mode 100644 dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/three/ConvexGeometry.kt create mode 100644 dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/three/EdgesGeometry.kt rename dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/{ => three}/three.kt (71%) create mode 100644 dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Convex.kt diff --git a/dataforge-vis-spatial-js/build.gradle.kts b/dataforge-vis-spatial-js/build.gradle.kts index d183766b..ec5f9fec 100644 --- a/dataforge-vis-spatial-js/build.gradle.kts +++ b/dataforge-vis-spatial-js/build.gradle.kts @@ -18,8 +18,8 @@ configure { downloadNodeJsVersion = "latest" configure { - dependency("three") - dependency("three-orbitcontrols") + dependency("three-full") + //dependency("three-orbitcontrols") dependency("style-loader") devDependency("karma") } diff --git a/dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/ThreeDemoApp.kt b/dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/ThreeDemoApp.kt index 2e46f0db..c0b4dd46 100644 --- a/dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/ThreeDemoApp.kt +++ b/dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/ThreeDemoApp.kt @@ -18,6 +18,9 @@ class ThreeDemoApp : ApplicationBase() { override val stateKeys: List = emptyList() override fun start(state: Map) { + //require("three-full") + //require("three/examples/js/geometries/ConvexGeometry") + val renderer = ThreeOutput(Global) renderer.start(document.getElementById("canvas")!!) println("started") @@ -39,6 +42,17 @@ class ThreeDemoApp : ApplicationBase() { properties.style["color"] = 1530 } } + convex { + point(50,50,-50) + point(50,-50,-50) + point(-50,-50,-50) + point(-50,50,-50) + point(50,50,50) + point(50,-50,50) + point(-50,-50,50) + point(-50,50,50) + + } } var color by group.properties.number(1530).int diff --git a/dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/ThreeObjectBuilder.kt b/dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/ThreeObjectBuilder.kt new file mode 100644 index 00000000..c3e672b4 --- /dev/null +++ b/dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/ThreeObjectBuilder.kt @@ -0,0 +1,87 @@ +package hep.dataforge.vis.spatial + +import hep.dataforge.vis.DisplayObject +import hep.dataforge.vis.get +import hep.dataforge.vis.onChange +import hep.dataforge.vis.spatial.three.ConvexGeometry +import hep.dataforge.vis.spatial.three.EdgesGeometry +import hep.dataforge.vis.spatial.three.euler +import info.laht.threekt.core.Object3D +import info.laht.threekt.geometries.BoxBufferGeometry +import info.laht.threekt.math.Vector3 +import info.laht.threekt.objects.LineSegments +import info.laht.threekt.objects.Mesh + +/** + * Builder and updater for three.js object + */ +interface ThreeObjectBuilder { + + operator fun invoke(obj: T): Object3D + + companion object { + /** + * Update position, rotation and visibility + */ + internal fun updatePosition(obj: DisplayObject, target: Object3D) { + target.apply { + position.set(obj.x, obj.y, obj.z) + setRotationFromEuler(obj.euler) + scale.set(obj.scaleX, obj.scaleY, obj.scaleZ) + visible = obj.visible + } + } + } +} + +abstract class GenericThreeBuilder : ThreeObjectBuilder { + /** + * Build an object + */ + abstract fun build(obj: T): R + + /** + * Update an object + */ + abstract fun update(obj: T, target: R) + + override fun invoke(obj: T): R { + val target = build(obj) + ThreeObjectBuilder.updatePosition(obj, target) + obj.onChange(this) { _, _, _ -> + ThreeObjectBuilder.updatePosition(obj, target) + update(obj, target) + } + return target + } +} + +object ThreeBoxBuilder : GenericThreeBuilder() { + override fun build(obj: Box): Mesh { + val geometry = BoxBufferGeometry(obj.xSize, obj.ySize, obj.zSize) + return Mesh(geometry, obj["color"].material()).also { mesh -> + mesh.add(LineSegments(EdgesGeometry(geometry), Materials.DEFAULT)) + } + } + + override fun update(obj: Box, target: Mesh) { + target.geometry = BoxBufferGeometry(obj.xSize, obj.ySize, obj.zSize) + target.material = obj["color"].material() + } +} + +fun Point3D.asVector(): Vector3 = this.asDynamic() as Vector3 + +object ThreeConvexBuilder: GenericThreeBuilder(){ + override fun build(obj: Convex): Mesh { + val geometry = ConvexGeometry(obj.points.map { it.asVector() }.toTypedArray()) + return Mesh(geometry, obj["color"].material()).also { mesh -> + mesh.add(LineSegments(EdgesGeometry(geometry), Materials.DEFAULT)) + } + } + + override fun update(obj: Convex, target: Mesh) { + target.geometry = ConvexGeometry(obj.points.map { it.asVector() }.toTypedArray()) + target.material = obj["color"].material() + } +} \ No newline at end of file diff --git a/dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/ThreeOutput.kt b/dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/ThreeOutput.kt index 3d8aaae8..f06a920d 100644 --- a/dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/ThreeOutput.kt +++ b/dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/ThreeOutput.kt @@ -5,18 +5,13 @@ import hep.dataforge.io.Output import hep.dataforge.meta.Meta import hep.dataforge.vis.DisplayGroup import hep.dataforge.vis.DisplayObject -import hep.dataforge.vis.get -import hep.dataforge.vis.onChange +import hep.dataforge.vis.spatial.three.Group 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.geometries.WireframeGeometry import info.laht.threekt.lights.AmbientLight import info.laht.threekt.math.ColorConstants -import info.laht.threekt.objects.LineSegments -import info.laht.threekt.objects.Mesh import info.laht.threekt.scenes.Scene import org.w3c.dom.Element import kotlin.browser.window @@ -66,47 +61,24 @@ class ThreeOutput(override val context: Context) : Output { private fun buildNode(obj: DisplayObject): Object3D? { - - // general properties updater - val updateProperties: Object3D.(DisplayObject) -> Unit = { - position.set(obj.x, obj.y, obj.z) - setRotationFromEuler(obj.euler) - scale.set(obj.scaleX, obj.scaleY, obj.scaleZ) - visible = obj.visible - } - return when (obj) { - is DisplayGroup -> Group(obj.children.mapNotNull { buildNode(it) }) - is Box -> { - val geometry = BoxBufferGeometry(obj.xSize, obj.ySize, obj.zSize) - val update: Mesh.(Box) -> Unit = { box -> - this.geometry = BoxBufferGeometry(box.xSize, box.ySize, box.zSize) - material = box["color"].material() - } - Mesh(geometry, obj["color"].material()).also { mesh -> - //TODO replace by edges after adding it to three.kt - mesh.add(LineSegments(WireframeGeometry(geometry),Materials.DEFAULT)) - obj.onChange(this) { _, _, _ -> - mesh.updateProperties(obj) - mesh.update(obj) - } - } + is DisplayGroup -> Group(obj.children.mapNotNull { buildNode(it) }).apply { + ThreeObjectBuilder.updatePosition(obj, this) } - else -> { - logger.error { "No renderer defined for ${obj::class}" } - return null - } - }.apply { - updateProperties(obj) + is Box -> ThreeBoxBuilder(obj) + //is Convex -> ThreeConvexBuilder(obj) + else -> null } } override fun render(obj: DisplayObject, meta: Meta) { buildNode(obj)?.let { scene.add(it) - } + } ?: error("Renderer for ${obj::class} not found") } +} + // init { // val cube: Mesh // @@ -142,6 +114,4 @@ class ThreeOutput(override val context: Context) : Output { // // // Create the final object to add to the scene // Line(geometry, material).apply(scene::add) -// } - -} \ No newline at end of file +// } \ No newline at end of file diff --git a/dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/three/ConvexGeometry.kt b/dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/three/ConvexGeometry.kt new file mode 100644 index 00000000..5d1c1f44 --- /dev/null +++ b/dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/three/ConvexGeometry.kt @@ -0,0 +1,7 @@ +@file:JsQualifier("THREE") +package hep.dataforge.vis.spatial.three + +import info.laht.threekt.core.BufferGeometry +import info.laht.threekt.math.Vector3 + +external class ConvexGeometry(points: Array) : BufferGeometry \ No newline at end of file diff --git a/dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/three/EdgesGeometry.kt b/dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/three/EdgesGeometry.kt new file mode 100644 index 00000000..fb85241d --- /dev/null +++ b/dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/three/EdgesGeometry.kt @@ -0,0 +1,11 @@ +@file:JsModule("three") +@file:JsNonModule + +package hep.dataforge.vis.spatial.three + +import info.laht.threekt.core.BufferGeometry +import info.laht.threekt.core.Geometry + +external class EdgesGeometry(geometry: Geometry, thresholdAngle: Int = definedExternally) : BufferGeometry { + constructor(geometry: BufferGeometry, thresholdAngle: Int = definedExternally) +} \ No newline at end of file diff --git a/dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/three.kt b/dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/three/three.kt similarity index 71% rename from dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/three.kt rename to dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/three/three.kt index 987f2f0c..c00eee28 100644 --- a/dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/three.kt +++ b/dataforge-vis-spatial-js/src/main/kotlin/hep/dataforge/vis/spatial/three/three.kt @@ -1,10 +1,14 @@ -package hep.dataforge.vis.spatial +package hep.dataforge.vis.spatial.three import hep.dataforge.meta.MetaItem import hep.dataforge.meta.float import hep.dataforge.meta.get import hep.dataforge.meta.node import hep.dataforge.vis.DisplayObject +import hep.dataforge.vis.spatial.rotationOrder +import hep.dataforge.vis.spatial.rotationX +import hep.dataforge.vis.spatial.rotationY +import hep.dataforge.vis.spatial.rotationZ import info.laht.threekt.core.Object3D import info.laht.threekt.math.Euler import info.laht.threekt.math.Vector3 diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Convex.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Convex.kt new file mode 100644 index 00000000..59444de6 --- /dev/null +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Convex.kt @@ -0,0 +1,41 @@ +package hep.dataforge.vis.spatial + +import hep.dataforge.meta.* +import hep.dataforge.names.toName +import hep.dataforge.vis.DisplayGroup +import hep.dataforge.vis.DisplayLeaf +import hep.dataforge.vis.DisplayObject + +class Convex(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, TYPE, meta) { + + val points = points(properties["points"] ?: error("Vertices not defined")) + + companion object { + const val TYPE = "geometry.spatial.convex" + + fun points(item: MetaItem<*>): List { + return item.node?.getAll("point".toName())?.map { (_, value) -> + Point3D(value.node["x"].number ?: 0, value.node["y"].number ?: 0, value.node["y"].number ?: 0) + } ?: emptyList() + } + } +} + +fun DisplayGroup.convex(meta: Meta = EmptyMeta, action: ConvexBuilder.() -> Unit = {}) = + ConvexBuilder().apply(action).build(this, meta).also { addChild(it) } + +class ConvexBuilder { + private val points = ArrayList() + + fun point(x: Number, y: Number, z: Number) { + points.add(Point3D(x, y, z)) + } + + fun build(parent: DisplayObject?, meta: Meta): Convex { + val builder = meta.builder() + points.forEachIndexed { index, value -> + builder["points.point[$index]"] = value.toMeta() + } + return Convex(parent, builder.seal()) + } +} \ No newline at end of file diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Geometry.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Geometry.kt index af41b44d..6391b3d2 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Geometry.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Geometry.kt @@ -1,6 +1,18 @@ package hep.dataforge.vis.spatial +import hep.dataforge.meta.Meta +import hep.dataforge.meta.MetaRepr +import hep.dataforge.meta.buildMeta + data class Point2D(val x: Number, val y: Number) -typealias Shape2D = List \ No newline at end of file +typealias Shape2D = List + +data class Point3D(val x: Number, val y: Number, val z: Number): MetaRepr{ + override fun toMeta(): Meta = buildMeta { + "x" to x + "y" to y + "z" to z + } +} \ No newline at end of file