Working on convex geometry for three

This commit is contained in:
Alexander Nozik 2019-03-09 11:39:01 +03:00
parent c2d15ded20
commit a7432a2b33
9 changed files with 190 additions and 44 deletions

View File

@ -18,8 +18,8 @@ configure<KotlinFrontendExtension> {
downloadNodeJsVersion = "latest" downloadNodeJsVersion = "latest"
configure<NpmExtension> { configure<NpmExtension> {
dependency("three") dependency("three-full")
dependency("three-orbitcontrols") //dependency("three-orbitcontrols")
dependency("style-loader") dependency("style-loader")
devDependency("karma") devDependency("karma")
} }

View File

@ -18,6 +18,9 @@ class ThreeDemoApp : ApplicationBase() {
override val stateKeys: List<String> = emptyList() override val stateKeys: List<String> = emptyList()
override fun start(state: Map<String, Any>) { override fun start(state: Map<String, Any>) {
//require("three-full")
//require("three/examples/js/geometries/ConvexGeometry")
val renderer = ThreeOutput(Global) val renderer = ThreeOutput(Global)
renderer.start(document.getElementById("canvas")!!) renderer.start(document.getElementById("canvas")!!)
println("started") println("started")
@ -39,6 +42,17 @@ class ThreeDemoApp : ApplicationBase() {
properties.style["color"] = 1530 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 var color by group.properties.number(1530).int

View File

@ -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<in T : DisplayObject> {
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<in T : DisplayObject, R : Object3D> : ThreeObjectBuilder<T> {
/**
* 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<Box, Mesh>() {
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<Convex,Mesh>(){
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()
}
}

View File

@ -5,18 +5,13 @@ import hep.dataforge.io.Output
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import hep.dataforge.vis.DisplayGroup import hep.dataforge.vis.DisplayGroup
import hep.dataforge.vis.DisplayObject import hep.dataforge.vis.DisplayObject
import hep.dataforge.vis.get import hep.dataforge.vis.spatial.three.Group
import hep.dataforge.vis.onChange
import info.laht.threekt.WebGLRenderer import info.laht.threekt.WebGLRenderer
import info.laht.threekt.cameras.PerspectiveCamera import info.laht.threekt.cameras.PerspectiveCamera
import info.laht.threekt.core.Object3D import info.laht.threekt.core.Object3D
import info.laht.threekt.external.controls.OrbitControls 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.lights.AmbientLight
import info.laht.threekt.math.ColorConstants 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 info.laht.threekt.scenes.Scene
import org.w3c.dom.Element import org.w3c.dom.Element
import kotlin.browser.window import kotlin.browser.window
@ -66,47 +61,24 @@ class ThreeOutput(override val context: Context) : Output<DisplayObject> {
private fun buildNode(obj: DisplayObject): Object3D? { 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) { return when (obj) {
is DisplayGroup -> Group(obj.children.mapNotNull { buildNode(it) }) is DisplayGroup -> Group(obj.children.mapNotNull { buildNode(it) }).apply {
is Box -> { ThreeObjectBuilder.updatePosition(obj, this)
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)
}
}
} }
else -> { is Box -> ThreeBoxBuilder(obj)
logger.error { "No renderer defined for ${obj::class}" } //is Convex -> ThreeConvexBuilder(obj)
return null else -> null
}
}.apply {
updateProperties(obj)
} }
} }
override fun render(obj: DisplayObject, meta: Meta) { override fun render(obj: DisplayObject, meta: Meta) {
buildNode(obj)?.let { buildNode(obj)?.let {
scene.add(it) scene.add(it)
} } ?: error("Renderer for ${obj::class} not found")
} }
}
// init { // init {
// val cube: Mesh // val cube: Mesh
// //
@ -142,6 +114,4 @@ class ThreeOutput(override val context: Context) : Output<DisplayObject> {
// //
// // Create the final object to add to the scene // // Create the final object to add to the scene
// Line(geometry, material).apply(scene::add) // Line(geometry, material).apply(scene::add)
// } // }
}

View File

@ -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<Vector3>) : BufferGeometry

View File

@ -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)
}

View File

@ -1,10 +1,14 @@
package hep.dataforge.vis.spatial package hep.dataforge.vis.spatial.three
import hep.dataforge.meta.MetaItem import hep.dataforge.meta.MetaItem
import hep.dataforge.meta.float import hep.dataforge.meta.float
import hep.dataforge.meta.get import hep.dataforge.meta.get
import hep.dataforge.meta.node import hep.dataforge.meta.node
import hep.dataforge.vis.DisplayObject 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.core.Object3D
import info.laht.threekt.math.Euler import info.laht.threekt.math.Euler
import info.laht.threekt.math.Vector3 import info.laht.threekt.math.Vector3

View File

@ -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<Point3D> {
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<Point3D>()
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())
}
}

View File

@ -1,6 +1,18 @@
package hep.dataforge.vis.spatial 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) data class Point2D(val x: Number, val y: Number)
typealias Shape2D = List<Point2D> typealias Shape2D = List<Point2D>
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
}
}