Update architecture

This commit is contained in:
Alexander Nozik 2019-03-25 22:12:22 +03:00
parent 4865c76158
commit d874c3cdd6
15 changed files with 227 additions and 138 deletions

View File

@ -9,7 +9,7 @@ buildscript {
val dokkaVersion: String by rootProject.extra("0.9.17")
val serializationVersion: String by rootProject.extra("0.10.0")
val dataforgeVersion: String by rootProject.extra("0.1.1-dev-5")
val dataforgeVersion: String by rootProject.extra("0.1.2-dev-1")
repositories {
jcenter()
@ -40,6 +40,7 @@ allprojects {
jcenter()
maven("https://kotlin.bintray.com/kotlinx")
maven("http://npm.mipt.ru:8081/artifactory/gradle-dev")
mavenLocal()
}
group = "hep.dataforge"

View File

@ -11,19 +11,19 @@ kotlin {
sourceSets {
val commonMain by getting {
dependencies {
api("hep.dataforge:dataforge-io:$dataforgeVersion")
api("hep.dataforge:dataforge-io-metadata:$dataforgeVersion")
api("hep.dataforge:dataforge-output:$dataforgeVersion")
//api("hep.dataforge:dataforge-output-metadata:$dataforgeVersion")
}
}
val jvmMain by getting {
dependencies {
api("hep.dataforge:dataforge-io-jvm:$dataforgeVersion")
api("hep.dataforge:dataforge-output-jvm:$dataforgeVersion")
//api("no.tornado:tornadofx:1.7.18")
}
}
val jsMain by getting {
dependencies {
api("hep.dataforge:dataforge-io-js:$dataforgeVersion")
api("hep.dataforge:dataforge-output-js:$dataforgeVersion")
}
}
}

View File

@ -1,12 +1,14 @@
package hep.dataforge.vis.spatial
import hep.dataforge.context.Global
import hep.dataforge.context.members
import hep.dataforge.meta.number
import hep.dataforge.meta.set
import hep.dataforge.vis.ApplicationBase
import hep.dataforge.vis.DisplayGroup
import hep.dataforge.vis.require
import hep.dataforge.vis.spatial.gdml.gdml
import hep.dataforge.vis.spatial.jsroot.JSRootPlugin
import hep.dataforge.vis.spatial.jsroot.jsRoot
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
@ -22,6 +24,23 @@ class ThreeDemoApp : ApplicationBase() {
override fun start(state: Map<String, Any>) {
require("JSRootGeoBase.js")
//TODO remove after DI fix
Global.plugins.load(ThreePlugin())
Global.plugins.load(JSRootPlugin())
// Global.plugins.load(JSRootPlugin)
println(Global.plugins.count())
Global.plugins.forEach {
println(it)
}
Global.members<ThreeFactory<*>>(ThreeFactory.TYPE).forEach {
println(it)
}
val renderer = ThreeOutput(Global)
renderer.start(document.getElementById("canvas")!!)
println("started")
@ -53,7 +72,7 @@ class ThreeDemoApp : ApplicationBase() {
// point(-50, -50, 50)
// point(-50, 50, 50)
// }
gdml {
jsRoot {
y = 110.0
shape = box(50, 50, 50)
}

View File

@ -0,0 +1,100 @@
package hep.dataforge.vis.spatial
import hep.dataforge.meta.boolean
import hep.dataforge.provider.Type
import hep.dataforge.vis.DisplayObject
import hep.dataforge.vis.get
import hep.dataforge.vis.onChange
import hep.dataforge.vis.spatial.ThreeFactory.Companion.TYPE
import hep.dataforge.vis.spatial.ThreeFactory.Companion.buildMesh
import hep.dataforge.vis.spatial.ThreeFactory.Companion.updateMesh
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.BufferGeometry
import info.laht.threekt.core.Object3D
import info.laht.threekt.geometries.BoxBufferGeometry
import info.laht.threekt.geometries.WireframeGeometry
import info.laht.threekt.math.Vector3
import info.laht.threekt.objects.LineSegments
import info.laht.threekt.objects.Mesh
import kotlin.reflect.KClass
internal val DisplayObject.material get() = this["color"].material()
/**
* Builder and updater for three.js object
*/
@Type(TYPE)
interface ThreeFactory<T : DisplayObject> {
val type: KClass<out T>
operator fun invoke(obj: T): Object3D
companion object {
const val TYPE = "threeFactory"
/**
* 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
}
}
internal fun buildMesh(obj: DisplayObject, geometry: BufferGeometry): Mesh {
val mesh = Mesh(geometry, obj.material)
if (obj["edges.enabled"]?.boolean != false) {
val material = obj["edges.material"]?.material() ?: Materials.DEFAULT
mesh.add(LineSegments(EdgesGeometry(mesh.geometry as BufferGeometry), material))
}
if (obj["wireframe.enabled"]?.boolean == true) {
val material = obj["edges.material"]?.material() ?: Materials.DEFAULT
mesh.add(LineSegments(WireframeGeometry(mesh.geometry as BufferGeometry), material))
}
return mesh
}
internal fun updateMesh(obj: DisplayObject, geometry: BufferGeometry, mesh: Mesh) {
mesh.geometry = geometry
mesh.material = obj.material
}
}
}
abstract class MeshThreeFactory<T : DisplayObject>(override val type: KClass<out T>) : ThreeFactory<T> {
/**
* Build an object
*/
abstract fun buildGeometry(obj: T): BufferGeometry
override fun invoke(obj: T): Mesh {
val geometry = buildGeometry(obj)
val mesh = buildMesh(obj, geometry)
ThreeFactory.updatePosition(obj, mesh)
obj.onChange(this) { _, _, _ ->
ThreeFactory.updatePosition(obj, mesh)
updateMesh(obj, buildGeometry(obj), mesh)
}
return mesh
}
}
object ThreeBoxFactory : MeshThreeFactory<Box>(Box::class) {
override fun buildGeometry(obj: Box) =
BoxBufferGeometry(obj.xSize, obj.ySize, obj.zSize)
}
fun Point3D.asVector(): Vector3 = this.asDynamic() as Vector3
object ThreeConvexFactory : MeshThreeFactory<Convex>(Convex::class) {
override fun buildGeometry(obj: Convex) =
ConvexGeometry(obj.points.map { it.asVector() }.toTypedArray())
}

View File

@ -1,87 +0,0 @@
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

@ -1,12 +1,11 @@
package hep.dataforge.vis.spatial
import hep.dataforge.context.Context
import hep.dataforge.io.Output
import hep.dataforge.context.members
import hep.dataforge.meta.Meta
import hep.dataforge.output.Output
import hep.dataforge.vis.DisplayGroup
import hep.dataforge.vis.DisplayObject
import hep.dataforge.vis.spatial.gdml.GDMLObject
import hep.dataforge.vis.spatial.gdml.ThreeGDMLBuilder
import hep.dataforge.vis.spatial.three.Group
import info.laht.threekt.WebGLRenderer
import info.laht.threekt.cameras.PerspectiveCamera
@ -17,6 +16,7 @@ import info.laht.threekt.math.ColorConstants
import info.laht.threekt.scenes.Scene
import org.w3c.dom.Element
import kotlin.browser.window
import kotlin.reflect.KClass
class ThreeOutput(override val context: Context) : Output<DisplayObject> {
@ -65,15 +65,19 @@ class ThreeOutput(override val context: Context) : Output<DisplayObject> {
private fun buildNode(obj: DisplayObject): Object3D? {
return when (obj) {
is DisplayGroup -> Group(obj.children.mapNotNull { buildNode(it) }).apply {
ThreeObjectBuilder.updatePosition(obj, this)
ThreeFactory.updatePosition(obj, this)
}
is Box -> ThreeBoxBuilder(obj)
is GDMLObject -> ThreeGDMLBuilder(obj)
//is Convex -> ThreeConvexBuilder(obj)
else -> null
//is Box -> ThreeBoxFactory(obj)
//is JSRootObject -> ThreeJSRootFactory(obj)
//is Convex -> ThreeConvexFactory(obj)
else -> findFactory(obj::class)?.invoke(obj)?: error("Factory not found")
}
}
private fun <T : DisplayObject> findFactory(type: KClass<out T>): ThreeFactory<T>? {
return context.members<ThreeFactory<*>>(ThreeFactory.TYPE).find { it.type == type } as? ThreeFactory<T>?
}
override fun render(obj: DisplayObject, meta: Meta) {
buildNode(obj)?.let {
scene.add(it)

View File

@ -0,0 +1,38 @@
package hep.dataforge.vis.spatial
import hep.dataforge.context.AbstractPlugin
import hep.dataforge.context.PluginFactory
import hep.dataforge.context.PluginTag
import hep.dataforge.names.Name
import hep.dataforge.names.toName
class ThreePlugin : AbstractPlugin() {
override val tag: PluginTag get() = ThreePlugin.tag
val factories = HashMap<Name, ThreeFactory<*>>()
init {
factories["box".toName()] = ThreeBoxFactory
factories["convex".toName()] = ThreeConvexFactory
}
override fun listTop(target: String): Sequence<Name> {
return when (target) {
ThreeFactory.TYPE -> factories.keys.asSequence()
else -> return super.listTop(target)
}
}
override fun provideTop(target: String, name: Name): Any? {
return when (target) {
ThreeFactory.TYPE -> factories[name]
else -> return super.provideTop(target, name)
}
}
companion object : PluginFactory<ThreePlugin> {
override val tag = PluginTag("vis.three", "hep.dataforge")
override val type = ThreePlugin::class
override fun build() = ThreePlugin()
}
}

View File

@ -1,7 +0,0 @@
@file:JsModule("JSRootGeoBase.js")
@file:JsNonModule
package hep.dataforge.vis.spatial.gdml
import info.laht.threekt.core.Geometry
external fun createGeometry(shape: dynamic, limit: Int): Geometry

View File

@ -0,0 +1,8 @@
@file:JsModule("JSRootGeoBase.js")
@file:JsNonModule
package hep.dataforge.vis.spatial.jsroot
import info.laht.threekt.core.BufferGeometry
external fun createGeometry(shape: dynamic, limit: Int): BufferGeometry

View File

@ -1,18 +1,14 @@
package hep.dataforge.vis.spatial.gdml
package hep.dataforge.vis.spatial.jsroot
import hep.dataforge.meta.EmptyMeta
import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaItem
import hep.dataforge.meta.buildMeta
import hep.dataforge.vis.*
import hep.dataforge.vis.spatial.GenericThreeBuilder
import hep.dataforge.vis.spatial.Materials
import hep.dataforge.vis.spatial.material
import hep.dataforge.vis.spatial.three.EdgesGeometry
import info.laht.threekt.objects.LineSegments
import info.laht.threekt.objects.Mesh
import hep.dataforge.vis.spatial.MeshThreeFactory
import info.laht.threekt.core.BufferGeometry
class GDMLObject(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, TYPE, meta) {
class JSRootObject(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, TYPE, meta) {
var shape by node()
@ -45,6 +41,9 @@ class GDMLObject(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, TYPE,
"fNode._typename" to "TGeoSubtraction"
}
/**
* Intersect two GDML geometries
*/
infix fun Meta.intersect(other: Meta) = buildMeta {
"fNode.fLeft" to this
"fNode.fRight" to other
@ -52,13 +51,12 @@ class GDMLObject(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, TYPE,
}
companion object {
const val TYPE = "geometry.spatial.gdml"
const val TYPE = "geometry.spatial.jsRoot"
}
}
//TODO add Zelenyy GDML builder here
fun DisplayGroup.gdml(meta: Meta = EmptyMeta, action: GDMLObject.() -> Unit = {}) =
GDMLObject(this, meta).apply(action).also { addChild(it) }
fun DisplayGroup.jsRoot(meta: Meta = EmptyMeta, action: JSRootObject.() -> Unit = {}) =
JSRootObject(this, meta).apply(action).also { addChild(it) }
fun Meta.toDynamic(): dynamic {
fun MetaItem<*>.toDynamic(): dynamic = when (this) {
@ -78,19 +76,9 @@ fun Meta.toDynamic(): dynamic {
}
object ThreeGDMLBuilder : GenericThreeBuilder<GDMLObject, Mesh>() {
override fun build(obj: GDMLObject): Mesh {
object ThreeJSRootFactory : MeshThreeFactory<JSRootObject>(JSRootObject::class) {
override fun buildGeometry(obj: JSRootObject): BufferGeometry {
val shapeMeta = obj.shape?.toDynamic() ?: error("The shape not defined")
println(shapeMeta)
val geometry = createGeometry(shapeMeta, obj.facesLimit)
return Mesh(geometry, obj.color.material()).also { mesh ->
mesh.add(LineSegments(EdgesGeometry(geometry), Materials.DEFAULT))
}
}
override fun update(obj: GDMLObject, target: Mesh) {
val shapeMeta: dynamic = obj.shape?.toDynamic()
target.geometry = createGeometry(shapeMeta, obj.facesLimit)
target.material = obj.color.material()
return createGeometry(shapeMeta, obj.facesLimit)
}
}

View File

@ -0,0 +1,25 @@
package hep.dataforge.vis.spatial.jsroot
import hep.dataforge.context.AbstractPlugin
import hep.dataforge.context.Context
import hep.dataforge.context.PluginFactory
import hep.dataforge.context.PluginTag
import hep.dataforge.names.toName
import hep.dataforge.vis.spatial.ThreePlugin
class JSRootPlugin : AbstractPlugin() {
override val tag: PluginTag get() = JSRootPlugin.tag
override fun dependsOn() = listOf(ThreePlugin)
override fun attach(context: Context) {
super.attach(context)
context.plugins.get<ThreePlugin>()?.factories?.set("ThreeJSRootFactory".toName(), ThreeJSRootFactory)
}
companion object: PluginFactory<JSRootPlugin> {
override val tag = PluginTag("vis.jsroot", "hep.dataforge")
override val type = JSRootPlugin::class
override fun build() = JSRootPlugin()
}
}

View File

@ -15,7 +15,7 @@ class Box(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, TYPE, meta)
//TODO add helper for color configuration
companion object {
const val TYPE = "geometry.spatial.box"
const val TYPE = "geometry.3d.box"
}
}

View File

@ -11,7 +11,7 @@ class Convex(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, TYPE, met
val points = points(properties["points"] ?: error("Vertices not defined"))
companion object {
const val TYPE = "geometry.spatial.convex"
const val TYPE = "geometry.3d.convex"
fun points(item: MetaItem<*>): List<Point3D> {
return item.node?.getAll("point".toName())?.map { (_, value) ->

View File

@ -11,7 +11,7 @@ class Extruded(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, TYPE, m
val shape get() = shape(properties["shape"] ?: error("Shape not defined"))
companion object {
const val TYPE = "geometry.spatial.extruded"
const val TYPE = "geometry.3d.extruded"
fun shape(item: MetaItem<*>): Shape2D {
return item.node?.getAll("xyPoint".toName())?.map { (_, value) ->

View File

@ -1,7 +1,7 @@
package hep.dataforge.vis.spatial
import hep.dataforge.io.Output
import hep.dataforge.meta.*
import hep.dataforge.output.Output
import hep.dataforge.vis.DisplayGroup
import hep.dataforge.vis.DisplayNode
import hep.dataforge.vis.DisplayObject