forked from kscience/visionforge
A major change in DisplayGroup implementation
This commit is contained in:
parent
4274dfff88
commit
697e7908a7
@ -14,6 +14,7 @@ allprojects {
|
||||
jcenter()
|
||||
maven("https://kotlin.bintray.com/kotlinx")
|
||||
maven("http://npm.mipt.ru:8081/artifactory/gradle-dev-local")
|
||||
maven("https://kotlin.bintray.com/js-externals")
|
||||
}
|
||||
|
||||
group = "hep.dataforge"
|
||||
|
@ -0,0 +1,83 @@
|
||||
package hep.dataforge.vis.common
|
||||
|
||||
import hep.dataforge.meta.EmptyMeta
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.Styled
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.provider.Provider
|
||||
|
||||
/**
|
||||
* A display group which allows both named and unnamed children
|
||||
*/
|
||||
class DisplayGroup(
|
||||
override val parent: DisplayObject? = null, meta: Meta = EmptyMeta
|
||||
) : DisplayObject, Iterable<DisplayObject>, Provider {
|
||||
|
||||
private val namedChildren = HashMap<Name, DisplayObject>()
|
||||
private val unnamedChildren = ArrayList<DisplayObject>()
|
||||
|
||||
override val defaultTarget: String get() = DisplayObject.TARGET
|
||||
override val properties: Styled = Styled(meta)
|
||||
|
||||
override fun iterator(): Iterator<DisplayObject> = (namedChildren.values + unnamedChildren).iterator()
|
||||
|
||||
override fun listNames(target: String): Sequence<Name> =
|
||||
namedChildren.keys.asSequence()
|
||||
|
||||
override fun provideTop(target: String, name: Name): Any? {
|
||||
return if (target == defaultTarget) {
|
||||
namedChildren[name]
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private data class Listener(val owner: Any?, val callback: (Name?, DisplayObject?) -> Unit)
|
||||
|
||||
private val listeners = HashSet<Listener>()
|
||||
|
||||
/**
|
||||
* Add listener for children change
|
||||
*/
|
||||
fun onChildrenChange(owner: Any?, action: (Name?, DisplayObject?) -> Unit) {
|
||||
listeners.add(Listener(owner, action))
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove children change listener
|
||||
*/
|
||||
fun removeChildrenChangeListener(owner: Any?) {
|
||||
listeners.removeAll { it.owner === owner }
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
operator fun set(key: String, child: DisplayObject?) {
|
||||
val name = key.toName()
|
||||
if (child == null) {
|
||||
namedChildren.remove(name)
|
||||
} else {
|
||||
namedChildren[name] = child
|
||||
}
|
||||
listeners.forEach { it.callback(name, child) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Append unnamed child
|
||||
*/
|
||||
fun add(child: DisplayObject) {
|
||||
unnamedChildren.add(child)
|
||||
listeners.forEach { it.callback(null, child) }
|
||||
}
|
||||
|
||||
/**
|
||||
* remove unnamed child
|
||||
*/
|
||||
fun remove(child: DisplayObject) {
|
||||
unnamedChildren.remove(child)
|
||||
listeners.forEach { it.callback(null, null) }
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
package hep.dataforge.vis.common
|
||||
|
||||
import hep.dataforge.meta.EmptyMeta
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.Styled
|
||||
|
||||
internal data class InvalidationListener(
|
||||
val owner: Any?,
|
||||
val action: () -> Unit
|
||||
)
|
||||
|
||||
/**
|
||||
* A [DisplayGroup] containing ordered list of elements
|
||||
*/
|
||||
class DisplayObjectList(
|
||||
override val parent: DisplayObject? = null,
|
||||
// override val type: String = DisplayObject.DEFAULT_TYPE,
|
||||
meta: Meta = EmptyMeta
|
||||
) : DisplayGroup {
|
||||
private val _children = ArrayList<DisplayObject>()
|
||||
|
||||
/**
|
||||
* An ordered list of direct descendants
|
||||
*/
|
||||
val children: List<DisplayObject> get() = _children
|
||||
|
||||
override fun iterator(): Iterator<DisplayObject> = children.iterator()
|
||||
|
||||
|
||||
override val properties = Styled(meta)
|
||||
private val listeners = HashSet<InvalidationListener>()
|
||||
|
||||
/**
|
||||
* Add a child object and notify listeners
|
||||
*/
|
||||
fun addChild(obj: DisplayObject) {
|
||||
_children.add(obj)
|
||||
listeners.forEach { it.action() }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove a specific child and notify listeners
|
||||
*/
|
||||
fun removeChild(obj: DisplayObject) {
|
||||
if (_children.remove(obj)) {
|
||||
listeners.forEach { it.action }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add listener for children change
|
||||
* TODO add detailed information into change listener
|
||||
*/
|
||||
fun onChildrenChange(owner: Any?, action: () -> Unit) {
|
||||
listeners.add(InvalidationListener(owner, action))
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove children change listener
|
||||
*/
|
||||
fun removeChildrenChangeListener(owner: Any?) {
|
||||
listeners.removeAll { it.owner === owner }
|
||||
}
|
||||
}
|
||||
|
@ -16,14 +16,11 @@ interface DisplayObject {
|
||||
*/
|
||||
val parent: DisplayObject?
|
||||
|
||||
// /**
|
||||
// * The type of this object. Uses `.` notation. Empty type means untyped group
|
||||
// */
|
||||
// val type: String
|
||||
|
||||
val properties: Styled
|
||||
|
||||
companion object {
|
||||
const val TARGET = "display"
|
||||
|
||||
const val DEFAULT_TYPE = ""
|
||||
//const val TYPE_KEY = "@type"
|
||||
//const val CHILDREN_KEY = "@children"
|
||||
@ -73,4 +70,11 @@ open class DisplayLeaf(
|
||||
final override val properties = Styled(meta)
|
||||
}
|
||||
|
||||
interface DisplayGroup: DisplayObject, Iterable<DisplayObject>
|
||||
///**
|
||||
// * A group that could contain both named and unnamed children. Unnamed children could be accessed only via
|
||||
// */
|
||||
//interface DisplayGroup : DisplayObject, Iterable<DisplayObject>, Provider {
|
||||
// override val defaultTarget: String get() = DisplayObject.TARGET
|
||||
//
|
||||
// val children
|
||||
//}
|
||||
|
@ -1,43 +0,0 @@
|
||||
package hep.dataforge.vis.common
|
||||
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.NameToken
|
||||
|
||||
/**
|
||||
* A navigable hierarchical display node
|
||||
*/
|
||||
interface DisplayTree : DisplayGroup {
|
||||
operator fun get(nameToken: NameToken): DisplayObject?
|
||||
}
|
||||
|
||||
interface MutableDisplayTree : DisplayTree {
|
||||
operator fun set(nameToken: NameToken, group: DisplayObject)
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively get a child
|
||||
*/
|
||||
tailrec operator fun DisplayTree.get(name: Name): DisplayObject? = when (name.length) {
|
||||
0 -> this
|
||||
1 -> this[name[0]]
|
||||
else -> name.first()?.let { this[it] as? DisplayTree }?.get(name.cutFirst())
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set given object creating intermediate empty groups if needed
|
||||
* @param name - the full name of a child
|
||||
* @param objFactory - a function that creates child object from parent (to avoid mutable parent parameter)
|
||||
*/
|
||||
fun MutableDisplayTree.set(name: Name, objFactory: (parent: DisplayObject) -> DisplayObject): Unit =
|
||||
when (name.length) {
|
||||
0 -> error("Can't set object with empty name")
|
||||
1 -> set(name[0], objFactory(this))
|
||||
else -> (this[name.first()!!] ?: DisplayObjectList(this)).run {
|
||||
if (this is MutableDisplayTree) {
|
||||
this.set(name.cutFirst(), objFactory)
|
||||
} else {
|
||||
error("Can't assign child to a leaf element $this")
|
||||
}
|
||||
}
|
||||
}
|
@ -9,7 +9,6 @@ plugins {
|
||||
id("org.jetbrains.kotlin.frontend")
|
||||
}
|
||||
|
||||
|
||||
val kotlinVersion: String by rootProject.extra
|
||||
|
||||
dependencies {
|
||||
@ -24,6 +23,7 @@ configure<KotlinFrontendExtension> {
|
||||
|
||||
configure<NpmExtension> {
|
||||
dependency("three-full")
|
||||
dependency("@hi-level/three-csg")
|
||||
dependency("style-loader")
|
||||
dependency("element-resize-event")
|
||||
devDependency("karma")
|
||||
|
@ -1,13 +1,14 @@
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.meta.boolean
|
||||
import hep.dataforge.names.startsWith
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.provider.Type
|
||||
import hep.dataforge.vis.common.DisplayObject
|
||||
import hep.dataforge.vis.common.getProperty
|
||||
import hep.dataforge.vis.common.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.ConvexBufferGeometry
|
||||
import hep.dataforge.vis.spatial.three.EdgesGeometry
|
||||
import hep.dataforge.vis.spatial.three.euler
|
||||
@ -15,12 +16,11 @@ 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() = getProperty("color").material()
|
||||
internal val DisplayObject.material get() = getProperty("material").material()
|
||||
|
||||
/**
|
||||
* Builder and updater for three.js object
|
||||
@ -35,39 +35,38 @@ interface ThreeFactory<T : DisplayObject> {
|
||||
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.getProperty("edges.enabled")?.boolean != false) {
|
||||
|
||||
//inherited edges definition, enabled by default
|
||||
if (obj.getProperty("edges.enabled").boolean != false) {
|
||||
val material = obj.getProperty("edges.material")?.material() ?: Materials.DEFAULT
|
||||
mesh.add(LineSegments(EdgesGeometry(mesh.geometry as BufferGeometry), material))
|
||||
}
|
||||
|
||||
if (obj.getProperty("wireframe.enabled")?.boolean == true) {
|
||||
//inherited wireframe definition, disabled by default
|
||||
if (obj.getProperty("wireframe.enabled").boolean == true) {
|
||||
val material = obj.getProperty("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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update position, rotation and visibility
|
||||
*/
|
||||
internal fun Object3D.updatePosition(obj: DisplayObject) {
|
||||
position.set(obj.x, obj.y, obj.z)
|
||||
setRotationFromEuler(obj.euler)
|
||||
scale.set(obj.scaleX, obj.scaleY, obj.scaleZ)
|
||||
visible = obj.visible
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsafe invocation of a factory
|
||||
*/
|
||||
operator fun <T : DisplayObject> ThreeFactory<T>.invoke(obj: Any): Object3D {
|
||||
if (type.isInstance(obj)) {
|
||||
return invoke(obj as T)
|
||||
@ -76,9 +75,12 @@ operator fun <T : DisplayObject> ThreeFactory<T>.invoke(obj: Any): Object3D {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic geometry-based factory
|
||||
*/
|
||||
abstract class MeshThreeFactory<T : DisplayObject>(override val type: KClass<out T>) : ThreeFactory<T> {
|
||||
/**
|
||||
* Build an object
|
||||
* Build a geometry for an object
|
||||
*/
|
||||
abstract fun buildGeometry(obj: T): BufferGeometry
|
||||
|
||||
@ -86,13 +88,33 @@ abstract class MeshThreeFactory<T : DisplayObject>(override val type: KClass<out
|
||||
override fun invoke(obj: T): Mesh {
|
||||
val geometry = buildGeometry(obj)
|
||||
|
||||
//JS sometimes tries to pass Geometry as BufferGeometry
|
||||
@Suppress("USELESS_IS_CHECK") if (geometry !is BufferGeometry) error("BufferGeometry expected")
|
||||
|
||||
//create mesh from geometry
|
||||
val mesh = buildMesh(obj, geometry)
|
||||
ThreeFactory.updatePosition(obj, mesh)
|
||||
obj.onChange(this) { _, _, _ ->
|
||||
ThreeFactory.updatePosition(obj, mesh)
|
||||
updateMesh(obj, buildGeometry(obj), mesh)
|
||||
|
||||
//set position for meseh
|
||||
mesh.updatePosition(obj)
|
||||
|
||||
//add listener to object properties
|
||||
obj.onChange(this) { name, _, _ ->
|
||||
if (name.toString() == "material") {
|
||||
//updated material
|
||||
mesh.material = obj.material
|
||||
} else if (
|
||||
name.startsWith("pos".toName()) ||
|
||||
name.startsWith("scale".toName()) ||
|
||||
name.startsWith("rotation".toName()) ||
|
||||
name.toString() == "visible"
|
||||
) {
|
||||
//update position of mesh using this object
|
||||
mesh.updatePosition(obj)
|
||||
} else {
|
||||
//full update
|
||||
mesh.geometry = buildGeometry(obj)
|
||||
mesh.material = obj.material
|
||||
}
|
||||
}
|
||||
return mesh
|
||||
}
|
||||
@ -104,7 +126,7 @@ abstract class MeshThreeFactory<T : DisplayObject>(override val type: KClass<out
|
||||
object ThreeShapeFactory : MeshThreeFactory<Shape>(Shape::class) {
|
||||
override fun buildGeometry(obj: Shape): BufferGeometry {
|
||||
return obj.run {
|
||||
ThreeGeometryBuilder().apply { buildGeometry() }.build()
|
||||
ThreeGeometryBuilder().apply { toGeometry(this) }.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -114,8 +136,7 @@ object ThreeBoxFactory : MeshThreeFactory<Box>(Box::class) {
|
||||
BoxBufferGeometry(obj.xSize, obj.ySize, obj.zSize)
|
||||
}
|
||||
|
||||
fun Point3D.asVector(): Vector3 = Vector3(this.x, this.y, this.z)
|
||||
|
||||
//FIXME not functional yet
|
||||
object ThreeConvexFactory : MeshThreeFactory<Convex>(Convex::class) {
|
||||
override fun buildGeometry(obj: Convex): ConvexBufferGeometry {
|
||||
val vectors = obj.points.map { it.asVector() }.toTypedArray()
|
||||
|
@ -10,6 +10,9 @@ import info.laht.threekt.core.Geometry
|
||||
import info.laht.threekt.math.Color
|
||||
import info.laht.threekt.math.Vector3
|
||||
|
||||
// TODO use unsafe cast instead
|
||||
fun Point3D.asVector(): Vector3 = Vector3(this.x, this.y, this.z)
|
||||
|
||||
class ThreeGeometryBuilder : GeometryBuilder<BufferGeometry> {
|
||||
|
||||
private val vertices = ArrayList<Point3D>()
|
||||
|
@ -73,9 +73,12 @@ class ThreeOutput(override val context: Context, val meta: Meta = EmptyMeta) : O
|
||||
}
|
||||
|
||||
private fun buildNode(obj: DisplayObject): Object3D? {
|
||||
return if (obj is DisplayGroup) Group(obj.mapNotNull { buildNode(it) }).apply {
|
||||
ThreeFactory.updatePosition(obj, this)
|
||||
return if (obj is DisplayGroup) {
|
||||
Group(obj.mapNotNull { buildNode(it) }).apply {
|
||||
updatePosition(obj)
|
||||
}
|
||||
} else {
|
||||
//find specialized factory for this type if it is present
|
||||
val factory = context.content<ThreeFactory<*>>(ThreeFactory.TYPE).values.find { it.type == obj::class }
|
||||
when {
|
||||
factory != null -> factory(obj)
|
||||
@ -94,6 +97,6 @@ class ThreeOutput(override val context: Context, val meta: Meta = EmptyMeta) : O
|
||||
|
||||
companion object {
|
||||
fun build(context: Context, meta: Meta = EmptyMeta, override: MetaBuilder.() -> Unit) =
|
||||
ThreeOutput(context, buildMeta(meta,override))
|
||||
ThreeOutput(context, buildMeta(meta, override))
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ import hep.dataforge.context.PluginFactory
|
||||
import hep.dataforge.context.PluginTag
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.names.set
|
||||
|
||||
class ThreePlugin : AbstractPlugin() {
|
||||
override val tag: PluginTag get() = ThreePlugin.tag
|
||||
@ -13,8 +13,8 @@ class ThreePlugin : AbstractPlugin() {
|
||||
val factories = HashMap<Name, ThreeFactory<*>>()
|
||||
|
||||
init {
|
||||
//factories["box".toName()] = ThreeBoxFactory
|
||||
factories["convex".toName()] = ThreeConvexFactory
|
||||
factories["box"] = ThreeBoxFactory
|
||||
factories["convex"] = ThreeConvexFactory
|
||||
}
|
||||
|
||||
override fun listNames(target: String): Sequence<Name> {
|
||||
|
@ -27,7 +27,7 @@ class ThreeDemoApp : ApplicationBase() {
|
||||
plugin(JSRootPlugin())
|
||||
}.build()
|
||||
|
||||
val grid = context.plugins.load(ThreeDemoGrid()).apply {
|
||||
context.plugins.load(ThreeDemoGrid()).run {
|
||||
demo("group", "Group demo") {
|
||||
val group = group {
|
||||
box {
|
||||
@ -77,8 +77,8 @@ class ThreeDemoApp : ApplicationBase() {
|
||||
shape {
|
||||
polygon(8, 50)
|
||||
}
|
||||
for(i in 0..100) {
|
||||
layer(i*5, 20*sin(2*PI/100*i), 20*cos(2*PI/100*i))
|
||||
for (i in 0..100) {
|
||||
layer(i * 5, 20 * sin(2 * PI / 100 * i), 20 * cos(2 * PI / 100 * i))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,8 +12,8 @@ import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.output.Output
|
||||
import hep.dataforge.output.OutputManager
|
||||
import hep.dataforge.vis.common.DisplayGroup
|
||||
import hep.dataforge.vis.common.DisplayObject
|
||||
import hep.dataforge.vis.common.DisplayObjectList
|
||||
import hep.dataforge.vis.spatial.ThreeOutput
|
||||
import hep.dataforge.vis.spatial.render
|
||||
import kotlinx.html.dom.append
|
||||
@ -24,6 +24,7 @@ import kotlinx.html.id
|
||||
import kotlinx.html.js.div
|
||||
import kotlinx.html.span
|
||||
import kotlin.browser.document
|
||||
import kotlin.dom.clear
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
class ThreeDemoGrid(meta: Meta) : AbstractPlugin(meta), OutputManager {
|
||||
@ -36,6 +37,7 @@ class ThreeDemoGrid(meta: Meta) : AbstractPlugin(meta), OutputManager {
|
||||
super.attach(context)
|
||||
val elementId = meta["elementID"].string ?: "canvas"
|
||||
val element = document.getElementById(elementId) ?: error("Element with id $elementId not found on page")
|
||||
element.clear()
|
||||
element.append(gridRoot)
|
||||
}
|
||||
|
||||
@ -47,10 +49,11 @@ class ThreeDemoGrid(meta: Meta) : AbstractPlugin(meta), OutputManager {
|
||||
"size" to 500
|
||||
}
|
||||
}
|
||||
//TODO calculate cell width here using jquery
|
||||
gridRoot.append {
|
||||
span("border") {
|
||||
div("col-4") {
|
||||
output.attach(div { id = "output-$name" }){300}
|
||||
output.attach(div { id = "output-$name" }){ 300}
|
||||
hr()
|
||||
h2 { +(meta["title"].string ?: name.toString()) }
|
||||
}
|
||||
@ -70,7 +73,7 @@ class ThreeDemoGrid(meta: Meta) : AbstractPlugin(meta), OutputManager {
|
||||
}
|
||||
}
|
||||
|
||||
fun ThreeDemoGrid.demo(name: String, title: String = name, block: DisplayObjectList.() -> Unit) {
|
||||
fun ThreeDemoGrid.demo(name: String, title: String = name, block: DisplayGroup.() -> Unit) {
|
||||
val meta = buildMeta {
|
||||
"title" to title
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ class JSRootDemoApp : ApplicationBase() {
|
||||
|
||||
renderer.render {
|
||||
val json = parse(string)
|
||||
JSRootObject(this, EmptyMeta, json).also { addChild(it) }
|
||||
JSRootObject(this, EmptyMeta, json).also { add(it) }
|
||||
}
|
||||
}
|
||||
readAsText(file)
|
||||
|
@ -4,7 +4,6 @@ import hep.dataforge.meta.EmptyMeta
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.buildMeta
|
||||
import hep.dataforge.meta.toDynamic
|
||||
import hep.dataforge.vis.*
|
||||
import hep.dataforge.vis.common.*
|
||||
import hep.dataforge.vis.spatial.MeshThreeFactory
|
||||
import info.laht.threekt.core.BufferGeometry
|
||||
@ -54,8 +53,8 @@ class JSRootGeometry(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, m
|
||||
}
|
||||
}
|
||||
|
||||
fun DisplayObjectList.jsRootGeometry(meta: Meta = EmptyMeta, action: JSRootGeometry.() -> Unit = {}) =
|
||||
JSRootGeometry(this, meta).apply(action).also { addChild(it) }
|
||||
fun DisplayGroup.jsRootGeometry(meta: Meta = EmptyMeta, action: JSRootGeometry.() -> Unit = {}) =
|
||||
JSRootGeometry(this, meta).apply(action).also { add(it) }
|
||||
|
||||
//fun Meta.toDynamic(): dynamic {
|
||||
// fun MetaItem<*>.toDynamic(): dynamic = when (this) {
|
||||
|
@ -3,9 +3,9 @@ package hep.dataforge.vis.spatial.jsroot
|
||||
import hep.dataforge.meta.EmptyMeta
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.toDynamic
|
||||
import hep.dataforge.vis.common.DisplayGroup
|
||||
import hep.dataforge.vis.common.DisplayLeaf
|
||||
import hep.dataforge.vis.common.DisplayObject
|
||||
import hep.dataforge.vis.common.DisplayObjectList
|
||||
import hep.dataforge.vis.common.node
|
||||
import hep.dataforge.vis.spatial.ThreeFactory
|
||||
import info.laht.threekt.core.Object3D
|
||||
@ -28,7 +28,7 @@ object ThreeJSRootObjectFactory : ThreeFactory<JSRootObject> {
|
||||
}
|
||||
}
|
||||
|
||||
fun DisplayObjectList.jsRootObject(str: String) {
|
||||
fun DisplayGroup.jsRootObject(str: String) {
|
||||
val json = JSON.parse<Any>(str)
|
||||
JSRootObject(this, EmptyMeta, json).also { addChild(it) }
|
||||
JSRootObject(this, EmptyMeta, json).also { add(it) }
|
||||
}
|
@ -4,18 +4,6 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>Three js demo for particle physics</title>
|
||||
<!-- <style>-->
|
||||
<!-- body {-->
|
||||
<!-- margin: 0;-->
|
||||
<!-- 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" src="js/three.min.js"></script>-->
|
||||
<!--<script type="text/javascript" src="js/ThreeCSG.js"></script>-->
|
||||
<!--<script type="text/javascript" src="js/JSRootCore.js"></script>-->
|
||||
<!--<script type="text/javascript" src="js/JSRootGeoBase.js"></script>-->
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
|
||||
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
|
||||
<script type="text/javascript" src="main.bundle.js"></script>
|
||||
@ -34,9 +22,9 @@
|
||||
</div>
|
||||
<div class="container" id="canvas"></div>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
|
||||
integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
|
||||
crossorigin="anonymous"></script>
|
||||
<!--<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"-->
|
||||
<!-- integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"-->
|
||||
<!-- crossorigin="anonymous"></script>-->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
|
||||
integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
|
||||
crossorigin="anonymous"></script>
|
||||
|
@ -2,9 +2,9 @@ package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.meta.EmptyMeta
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.vis.common.DisplayGroup
|
||||
import hep.dataforge.vis.common.DisplayLeaf
|
||||
import hep.dataforge.vis.common.DisplayObject
|
||||
import hep.dataforge.vis.common.DisplayObjectList
|
||||
import hep.dataforge.vis.common.double
|
||||
|
||||
class Box(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, meta), Shape {
|
||||
@ -14,7 +14,7 @@ class Box(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, meta), Shape
|
||||
|
||||
//TODO add helper for color configuration
|
||||
|
||||
override fun <T : Any> GeometryBuilder<T>.buildGeometry() {
|
||||
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {
|
||||
val dx = xSize / 2
|
||||
val dy = ySize / 2
|
||||
val dz = zSize / 2
|
||||
@ -26,12 +26,12 @@ class Box(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, meta), Shape
|
||||
val node6 = Point3D(dx, -dy, dz)
|
||||
val node7 = Point3D(dx, dy, dz)
|
||||
val node8 = Point3D(-dx, dy, dz)
|
||||
face4(node1, node4, node3, node2, Point3D(0, 0, -1))
|
||||
face4(node1, node2, node6, node5, Point3D(0, -1, 0))
|
||||
face4(node2, node3, node7, node6, Point3D(1, 0, 0))
|
||||
face4(node4, node8, node7, node3, Point3D(0, 1, 0))
|
||||
face4(node1, node5, node8, node4, Point3D(-1, 0, 0))
|
||||
face4(node8, node5, node6, node7, Point3D(0, 0, 1))
|
||||
geometryBuilder.face4(node1, node4, node3, node2, Point3D(0, 0, -1))
|
||||
geometryBuilder.face4(node1, node2, node6, node5, Point3D(0, -1, 0))
|
||||
geometryBuilder.face4(node2, node3, node7, node6, Point3D(1, 0, 0))
|
||||
geometryBuilder.face4(node4, node8, node7, node3, Point3D(0, 1, 0))
|
||||
geometryBuilder.face4(node1, node5, node8, node4, Point3D(-1, 0, 0))
|
||||
geometryBuilder.face4(node8, node5, node6, node7, Point3D(0, 0, 1))
|
||||
}
|
||||
|
||||
companion object {
|
||||
@ -39,5 +39,5 @@ class Box(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, meta), Shape
|
||||
}
|
||||
}
|
||||
|
||||
fun DisplayObjectList.box(meta: Meta = EmptyMeta, action: Box.() -> Unit = {}) =
|
||||
Box(this, meta).apply(action).also { addChild(it) }
|
||||
fun DisplayGroup.box(meta: Meta = EmptyMeta, action: Box.() -> Unit = {}) =
|
||||
Box(this, meta).apply(action).also { add(it) }
|
@ -0,0 +1,13 @@
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.meta.EmptyMeta
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.vis.common.DisplayLeaf
|
||||
import hep.dataforge.vis.common.DisplayObject
|
||||
|
||||
class Composite(
|
||||
parent: DisplayObject?,
|
||||
val first: DisplayObject,
|
||||
val second: DisplayObject,
|
||||
meta: Meta = EmptyMeta
|
||||
) : DisplayLeaf(parent,meta)
|
@ -1,10 +1,9 @@
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.vis.common.DisplayGroup
|
||||
import hep.dataforge.vis.common.DisplayLeaf
|
||||
import hep.dataforge.vis.common.DisplayObject
|
||||
import hep.dataforge.vis.common.DisplayObjectList
|
||||
|
||||
class Convex(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, meta) {
|
||||
|
||||
@ -14,15 +13,15 @@ class Convex(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, meta) {
|
||||
const val TYPE = "geometry.3d.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)
|
||||
return item.node?.getAll("point")?.map { (_, value) ->
|
||||
Point3D.from(value.node?: error("Point definition is not a node"))
|
||||
} ?: emptyList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun DisplayObjectList.convex(meta: Meta = EmptyMeta, action: ConvexBuilder.() -> Unit = {}) =
|
||||
ConvexBuilder().apply(action).build(this, meta).also { addChild(it) }
|
||||
fun DisplayGroup.convex(meta: Meta = EmptyMeta, action: ConvexBuilder.() -> Unit = {}) =
|
||||
ConvexBuilder().apply(action).build(this, meta).also { add(it) }
|
||||
|
||||
class ConvexBuilder {
|
||||
private val points = ArrayList<Point3D>()
|
||||
|
@ -1,9 +1,9 @@
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.vis.common.DisplayGroup
|
||||
import hep.dataforge.vis.common.DisplayLeaf
|
||||
import hep.dataforge.vis.common.DisplayObject
|
||||
import hep.dataforge.vis.common.DisplayObjectList
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
@ -46,7 +46,7 @@ class Extruded(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, meta),
|
||||
|
||||
val shape
|
||||
get() = properties.getAll("shape.point").map { (_, value) ->
|
||||
Point2D(value.node["x"].number ?: 0, value.node["y"].number ?: 0)
|
||||
Point2D.from(value.node ?: error("Point definition is not a node"))
|
||||
}
|
||||
|
||||
fun shape(block: Shape2DBuilder.() -> Unit) {
|
||||
@ -70,7 +70,7 @@ class Extruded(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, meta),
|
||||
return layer
|
||||
}
|
||||
|
||||
override fun <T : Any> GeometryBuilder<T>.buildGeometry() {
|
||||
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {
|
||||
val shape: Shape2D = shape
|
||||
|
||||
if (shape.size < 3) error("Extruded shape requires more than points per layer")
|
||||
@ -95,7 +95,7 @@ class Extruded(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, meta),
|
||||
upperLayer = layers[i]
|
||||
for (j in (0 until shape.size - 1)) {
|
||||
//counter clockwise
|
||||
face4(
|
||||
geometryBuilder.face4(
|
||||
lowerLayer[j],
|
||||
lowerLayer[j + 1],
|
||||
upperLayer[j + 1],
|
||||
@ -104,7 +104,7 @@ class Extruded(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, meta),
|
||||
}
|
||||
|
||||
// final face
|
||||
face4(
|
||||
geometryBuilder.face4(
|
||||
lowerLayer[shape.size - 1],
|
||||
lowerLayer[0],
|
||||
upperLayer[0],
|
||||
@ -119,5 +119,5 @@ class Extruded(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, meta),
|
||||
}
|
||||
}
|
||||
|
||||
fun DisplayObjectList.extrude(meta: Meta = EmptyMeta, action: Extruded.() -> Unit = {}) =
|
||||
Extruded(this, meta).apply(action).also { addChild(it) }
|
||||
fun DisplayGroup.extrude(meta: Meta = EmptyMeta, action: Extruded.() -> Unit = {}) =
|
||||
Extruded(this, meta).apply(action).also { add(it) }
|
@ -1,16 +1,19 @@
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.meta.EmptyMeta
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.MetaRepr
|
||||
import hep.dataforge.meta.buildMeta
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.vis.common.DisplayObject
|
||||
|
||||
data class Point2D(val x: Number, val y: Number): MetaRepr{
|
||||
data class Point2D(val x: Number, val y: Number) : MetaRepr {
|
||||
override fun toMeta(): Meta = buildMeta {
|
||||
"x" to x
|
||||
"y" to y
|
||||
}
|
||||
|
||||
companion object{
|
||||
fun from(meta: Meta): Point2D{
|
||||
return Point2D(meta["x"].number ?: 0, meta["y"].number ?: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class Point3D(val x: Number, val y: Number, val z: Number) : MetaRepr {
|
||||
@ -19,12 +22,18 @@ data class Point3D(val x: Number, val y: Number, val z: Number) : MetaRepr {
|
||||
"y" to y
|
||||
"z" to z
|
||||
}
|
||||
|
||||
companion object{
|
||||
fun from(meta: Meta): Point3D{
|
||||
return Point3D(meta["x"].number ?: 0, meta["y"].number ?: 0, meta["y"].number ?: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param T the type of resulting geometry
|
||||
*/
|
||||
interface GeometryBuilder<T: Any> {
|
||||
interface GeometryBuilder<T : Any> {
|
||||
/**
|
||||
* Add a face to 3D model. If one of the vertices is not present in the current geometry model list of vertices,
|
||||
* it is added automatically.
|
||||
@ -35,7 +44,6 @@ interface GeometryBuilder<T: Any> {
|
||||
fun face(vertex1: Point3D, vertex2: Point3D, vertex3: Point3D, normal: Point3D? = null, meta: Meta = EmptyMeta)
|
||||
|
||||
fun build(): T
|
||||
|
||||
}
|
||||
|
||||
fun GeometryBuilder<*>.face4(
|
||||
@ -50,6 +58,6 @@ fun GeometryBuilder<*>.face4(
|
||||
face(vertex1, vertex3, vertex4, normal, meta)
|
||||
}
|
||||
|
||||
interface Shape: DisplayObject {
|
||||
fun <T: Any> GeometryBuilder<T>.buildGeometry()
|
||||
interface Shape : DisplayObject {
|
||||
fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>)
|
||||
}
|
@ -4,15 +4,14 @@ import hep.dataforge.meta.*
|
||||
import hep.dataforge.output.Output
|
||||
import hep.dataforge.vis.common.DisplayGroup
|
||||
import hep.dataforge.vis.common.DisplayObject
|
||||
import hep.dataforge.vis.common.DisplayObjectList
|
||||
import hep.dataforge.vis.common.getProperty
|
||||
|
||||
fun DisplayObjectList.group(meta: Meta = EmptyMeta, action: DisplayObjectList.() -> Unit = {}): DisplayGroup =
|
||||
DisplayObjectList(this, meta).apply(action).also { addChild(it) }
|
||||
fun DisplayGroup.group(meta: Meta = EmptyMeta, action: DisplayGroup.() -> Unit = {}): DisplayGroup =
|
||||
DisplayGroup(this, meta).apply(action).also { add(it) }
|
||||
|
||||
|
||||
fun Output<DisplayObject>.render(meta: Meta = EmptyMeta, action: DisplayObjectList.() -> Unit) =
|
||||
render(DisplayObjectList(null, EmptyMeta).apply(action), meta)
|
||||
fun Output<DisplayObject>.render(meta: Meta = EmptyMeta, action: DisplayGroup.() -> Unit) =
|
||||
render(DisplayGroup(null, EmptyMeta).apply(action), meta)
|
||||
|
||||
//TODO replace properties by containers?
|
||||
|
||||
@ -133,11 +132,11 @@ var DisplayObject.scaleZ
|
||||
}
|
||||
|
||||
fun DisplayObject.color(rgb: Int) {
|
||||
this.properties["color"] = rgb
|
||||
this.properties["material"] = rgb
|
||||
}
|
||||
|
||||
fun DisplayObject.color(meta: Meta) {
|
||||
this.properties["color"] = meta
|
||||
this.properties["material"] = meta
|
||||
}
|
||||
|
||||
fun DisplayObject.color(r: Int, g: Int, b: Int) = color(buildMeta {
|
||||
|
@ -4,14 +4,14 @@ import hep.dataforge.meta.get
|
||||
import hep.dataforge.meta.getAll
|
||||
import hep.dataforge.meta.node
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.vis.common.DisplayObjectList
|
||||
import hep.dataforge.vis.common.DisplayGroup
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class ConvexTest {
|
||||
@Test
|
||||
fun testConvexBuilder() {
|
||||
val group = DisplayObjectList().apply {
|
||||
val group = DisplayGroup().apply {
|
||||
convex {
|
||||
point(50, 50, -50)
|
||||
point(50, -50, -50)
|
||||
@ -24,7 +24,7 @@ class ConvexTest {
|
||||
}
|
||||
}
|
||||
|
||||
val convex = group.children.first() as Convex
|
||||
val convex = group.first() as Convex
|
||||
|
||||
val pointsNode = convex.properties["points"].node
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user