A major change in DisplayGroup implementation
This commit is contained in:
parent
4274dfff88
commit
697e7908a7
@ -14,6 +14,7 @@ allprojects {
|
|||||||
jcenter()
|
jcenter()
|
||||||
maven("https://kotlin.bintray.com/kotlinx")
|
maven("https://kotlin.bintray.com/kotlinx")
|
||||||
maven("http://npm.mipt.ru:8081/artifactory/gradle-dev-local")
|
maven("http://npm.mipt.ru:8081/artifactory/gradle-dev-local")
|
||||||
|
maven("https://kotlin.bintray.com/js-externals")
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "hep.dataforge"
|
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?
|
val parent: DisplayObject?
|
||||||
|
|
||||||
// /**
|
|
||||||
// * The type of this object. Uses `.` notation. Empty type means untyped group
|
|
||||||
// */
|
|
||||||
// val type: String
|
|
||||||
|
|
||||||
val properties: Styled
|
val properties: Styled
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
const val TARGET = "display"
|
||||||
|
|
||||||
const val DEFAULT_TYPE = ""
|
const val DEFAULT_TYPE = ""
|
||||||
//const val TYPE_KEY = "@type"
|
//const val TYPE_KEY = "@type"
|
||||||
//const val CHILDREN_KEY = "@children"
|
//const val CHILDREN_KEY = "@children"
|
||||||
@ -73,4 +70,11 @@ open class DisplayLeaf(
|
|||||||
final override val properties = Styled(meta)
|
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")
|
id("org.jetbrains.kotlin.frontend")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val kotlinVersion: String by rootProject.extra
|
val kotlinVersion: String by rootProject.extra
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@ -24,6 +23,7 @@ configure<KotlinFrontendExtension> {
|
|||||||
|
|
||||||
configure<NpmExtension> {
|
configure<NpmExtension> {
|
||||||
dependency("three-full")
|
dependency("three-full")
|
||||||
|
dependency("@hi-level/three-csg")
|
||||||
dependency("style-loader")
|
dependency("style-loader")
|
||||||
dependency("element-resize-event")
|
dependency("element-resize-event")
|
||||||
devDependency("karma")
|
devDependency("karma")
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.meta.boolean
|
import hep.dataforge.meta.boolean
|
||||||
|
import hep.dataforge.names.startsWith
|
||||||
|
import hep.dataforge.names.toName
|
||||||
import hep.dataforge.provider.Type
|
import hep.dataforge.provider.Type
|
||||||
import hep.dataforge.vis.common.DisplayObject
|
import hep.dataforge.vis.common.DisplayObject
|
||||||
import hep.dataforge.vis.common.getProperty
|
import hep.dataforge.vis.common.getProperty
|
||||||
import hep.dataforge.vis.common.onChange
|
import hep.dataforge.vis.common.onChange
|
||||||
import hep.dataforge.vis.spatial.ThreeFactory.Companion.TYPE
|
import hep.dataforge.vis.spatial.ThreeFactory.Companion.TYPE
|
||||||
import hep.dataforge.vis.spatial.ThreeFactory.Companion.buildMesh
|
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.ConvexBufferGeometry
|
||||||
import hep.dataforge.vis.spatial.three.EdgesGeometry
|
import hep.dataforge.vis.spatial.three.EdgesGeometry
|
||||||
import hep.dataforge.vis.spatial.three.euler
|
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.core.Object3D
|
||||||
import info.laht.threekt.geometries.BoxBufferGeometry
|
import info.laht.threekt.geometries.BoxBufferGeometry
|
||||||
import info.laht.threekt.geometries.WireframeGeometry
|
import info.laht.threekt.geometries.WireframeGeometry
|
||||||
import info.laht.threekt.math.Vector3
|
|
||||||
import info.laht.threekt.objects.LineSegments
|
import info.laht.threekt.objects.LineSegments
|
||||||
import info.laht.threekt.objects.Mesh
|
import info.laht.threekt.objects.Mesh
|
||||||
import kotlin.reflect.KClass
|
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
|
* Builder and updater for three.js object
|
||||||
@ -35,39 +35,38 @@ interface ThreeFactory<T : DisplayObject> {
|
|||||||
companion object {
|
companion object {
|
||||||
const val TYPE = "threeFactory"
|
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 {
|
internal fun buildMesh(obj: DisplayObject, geometry: BufferGeometry): Mesh {
|
||||||
val mesh = Mesh(geometry, obj.material)
|
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
|
val material = obj.getProperty("edges.material")?.material() ?: Materials.DEFAULT
|
||||||
mesh.add(LineSegments(EdgesGeometry(mesh.geometry as BufferGeometry), material))
|
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
|
val material = obj.getProperty("edges.material")?.material() ?: Materials.DEFAULT
|
||||||
mesh.add(LineSegments(WireframeGeometry(mesh.geometry as BufferGeometry), material))
|
mesh.add(LineSegments(WireframeGeometry(mesh.geometry as BufferGeometry), material))
|
||||||
}
|
}
|
||||||
return mesh
|
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 {
|
operator fun <T : DisplayObject> ThreeFactory<T>.invoke(obj: Any): Object3D {
|
||||||
if (type.isInstance(obj)) {
|
if (type.isInstance(obj)) {
|
||||||
return invoke(obj as T)
|
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> {
|
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
|
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 {
|
override fun invoke(obj: T): Mesh {
|
||||||
val geometry = buildGeometry(obj)
|
val geometry = buildGeometry(obj)
|
||||||
|
|
||||||
|
//JS sometimes tries to pass Geometry as BufferGeometry
|
||||||
@Suppress("USELESS_IS_CHECK") if (geometry !is BufferGeometry) error("BufferGeometry expected")
|
@Suppress("USELESS_IS_CHECK") if (geometry !is BufferGeometry) error("BufferGeometry expected")
|
||||||
|
|
||||||
|
//create mesh from geometry
|
||||||
val mesh = buildMesh(obj, geometry)
|
val mesh = buildMesh(obj, geometry)
|
||||||
ThreeFactory.updatePosition(obj, mesh)
|
|
||||||
obj.onChange(this) { _, _, _ ->
|
//set position for meseh
|
||||||
ThreeFactory.updatePosition(obj, mesh)
|
mesh.updatePosition(obj)
|
||||||
updateMesh(obj, buildGeometry(obj), mesh)
|
|
||||||
|
//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
|
return mesh
|
||||||
}
|
}
|
||||||
@ -104,7 +126,7 @@ abstract class MeshThreeFactory<T : DisplayObject>(override val type: KClass<out
|
|||||||
object ThreeShapeFactory : MeshThreeFactory<Shape>(Shape::class) {
|
object ThreeShapeFactory : MeshThreeFactory<Shape>(Shape::class) {
|
||||||
override fun buildGeometry(obj: Shape): BufferGeometry {
|
override fun buildGeometry(obj: Shape): BufferGeometry {
|
||||||
return obj.run {
|
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)
|
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) {
|
object ThreeConvexFactory : MeshThreeFactory<Convex>(Convex::class) {
|
||||||
override fun buildGeometry(obj: Convex): ConvexBufferGeometry {
|
override fun buildGeometry(obj: Convex): ConvexBufferGeometry {
|
||||||
val vectors = obj.points.map { it.asVector() }.toTypedArray()
|
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.Color
|
||||||
import info.laht.threekt.math.Vector3
|
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> {
|
class ThreeGeometryBuilder : GeometryBuilder<BufferGeometry> {
|
||||||
|
|
||||||
private val vertices = ArrayList<Point3D>()
|
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? {
|
private fun buildNode(obj: DisplayObject): Object3D? {
|
||||||
return if (obj is DisplayGroup) Group(obj.mapNotNull { buildNode(it) }).apply {
|
return if (obj is DisplayGroup) {
|
||||||
ThreeFactory.updatePosition(obj, this)
|
Group(obj.mapNotNull { buildNode(it) }).apply {
|
||||||
|
updatePosition(obj)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
//find specialized factory for this type if it is present
|
||||||
val factory = context.content<ThreeFactory<*>>(ThreeFactory.TYPE).values.find { it.type == obj::class }
|
val factory = context.content<ThreeFactory<*>>(ThreeFactory.TYPE).values.find { it.type == obj::class }
|
||||||
when {
|
when {
|
||||||
factory != null -> factory(obj)
|
factory != null -> factory(obj)
|
||||||
@ -94,6 +97,6 @@ class ThreeOutput(override val context: Context, val meta: Meta = EmptyMeta) : O
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun build(context: Context, meta: Meta = EmptyMeta, override: MetaBuilder.() -> Unit) =
|
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.context.PluginTag
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.toName
|
import hep.dataforge.names.set
|
||||||
|
|
||||||
class ThreePlugin : AbstractPlugin() {
|
class ThreePlugin : AbstractPlugin() {
|
||||||
override val tag: PluginTag get() = ThreePlugin.tag
|
override val tag: PluginTag get() = ThreePlugin.tag
|
||||||
@ -13,8 +13,8 @@ class ThreePlugin : AbstractPlugin() {
|
|||||||
val factories = HashMap<Name, ThreeFactory<*>>()
|
val factories = HashMap<Name, ThreeFactory<*>>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
//factories["box".toName()] = ThreeBoxFactory
|
factories["box"] = ThreeBoxFactory
|
||||||
factories["convex".toName()] = ThreeConvexFactory
|
factories["convex"] = ThreeConvexFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun listNames(target: String): Sequence<Name> {
|
override fun listNames(target: String): Sequence<Name> {
|
||||||
|
@ -27,7 +27,7 @@ class ThreeDemoApp : ApplicationBase() {
|
|||||||
plugin(JSRootPlugin())
|
plugin(JSRootPlugin())
|
||||||
}.build()
|
}.build()
|
||||||
|
|
||||||
val grid = context.plugins.load(ThreeDemoGrid()).apply {
|
context.plugins.load(ThreeDemoGrid()).run {
|
||||||
demo("group", "Group demo") {
|
demo("group", "Group demo") {
|
||||||
val group = group {
|
val group = group {
|
||||||
box {
|
box {
|
||||||
@ -77,8 +77,8 @@ class ThreeDemoApp : ApplicationBase() {
|
|||||||
shape {
|
shape {
|
||||||
polygon(8, 50)
|
polygon(8, 50)
|
||||||
}
|
}
|
||||||
for(i in 0..100) {
|
for (i in 0..100) {
|
||||||
layer(i*5, 20*sin(2*PI/100*i), 20*cos(2*PI/100*i))
|
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.names.toName
|
||||||
import hep.dataforge.output.Output
|
import hep.dataforge.output.Output
|
||||||
import hep.dataforge.output.OutputManager
|
import hep.dataforge.output.OutputManager
|
||||||
|
import hep.dataforge.vis.common.DisplayGroup
|
||||||
import hep.dataforge.vis.common.DisplayObject
|
import hep.dataforge.vis.common.DisplayObject
|
||||||
import hep.dataforge.vis.common.DisplayObjectList
|
|
||||||
import hep.dataforge.vis.spatial.ThreeOutput
|
import hep.dataforge.vis.spatial.ThreeOutput
|
||||||
import hep.dataforge.vis.spatial.render
|
import hep.dataforge.vis.spatial.render
|
||||||
import kotlinx.html.dom.append
|
import kotlinx.html.dom.append
|
||||||
@ -24,6 +24,7 @@ import kotlinx.html.id
|
|||||||
import kotlinx.html.js.div
|
import kotlinx.html.js.div
|
||||||
import kotlinx.html.span
|
import kotlinx.html.span
|
||||||
import kotlin.browser.document
|
import kotlin.browser.document
|
||||||
|
import kotlin.dom.clear
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
class ThreeDemoGrid(meta: Meta) : AbstractPlugin(meta), OutputManager {
|
class ThreeDemoGrid(meta: Meta) : AbstractPlugin(meta), OutputManager {
|
||||||
@ -36,6 +37,7 @@ class ThreeDemoGrid(meta: Meta) : AbstractPlugin(meta), OutputManager {
|
|||||||
super.attach(context)
|
super.attach(context)
|
||||||
val elementId = meta["elementID"].string ?: "canvas"
|
val elementId = meta["elementID"].string ?: "canvas"
|
||||||
val element = document.getElementById(elementId) ?: error("Element with id $elementId not found on page")
|
val element = document.getElementById(elementId) ?: error("Element with id $elementId not found on page")
|
||||||
|
element.clear()
|
||||||
element.append(gridRoot)
|
element.append(gridRoot)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,10 +49,11 @@ class ThreeDemoGrid(meta: Meta) : AbstractPlugin(meta), OutputManager {
|
|||||||
"size" to 500
|
"size" to 500
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//TODO calculate cell width here using jquery
|
||||||
gridRoot.append {
|
gridRoot.append {
|
||||||
span("border") {
|
span("border") {
|
||||||
div("col-4") {
|
div("col-4") {
|
||||||
output.attach(div { id = "output-$name" }){300}
|
output.attach(div { id = "output-$name" }){ 300}
|
||||||
hr()
|
hr()
|
||||||
h2 { +(meta["title"].string ?: name.toString()) }
|
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 {
|
val meta = buildMeta {
|
||||||
"title" to title
|
"title" to title
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ class JSRootDemoApp : ApplicationBase() {
|
|||||||
|
|
||||||
renderer.render {
|
renderer.render {
|
||||||
val json = parse(string)
|
val json = parse(string)
|
||||||
JSRootObject(this, EmptyMeta, json).also { addChild(it) }
|
JSRootObject(this, EmptyMeta, json).also { add(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
readAsText(file)
|
readAsText(file)
|
||||||
|
@ -4,7 +4,6 @@ import hep.dataforge.meta.EmptyMeta
|
|||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.meta.buildMeta
|
import hep.dataforge.meta.buildMeta
|
||||||
import hep.dataforge.meta.toDynamic
|
import hep.dataforge.meta.toDynamic
|
||||||
import hep.dataforge.vis.*
|
|
||||||
import hep.dataforge.vis.common.*
|
import hep.dataforge.vis.common.*
|
||||||
import hep.dataforge.vis.spatial.MeshThreeFactory
|
import hep.dataforge.vis.spatial.MeshThreeFactory
|
||||||
import info.laht.threekt.core.BufferGeometry
|
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 = {}) =
|
fun DisplayGroup.jsRootGeometry(meta: Meta = EmptyMeta, action: JSRootGeometry.() -> Unit = {}) =
|
||||||
JSRootGeometry(this, meta).apply(action).also { addChild(it) }
|
JSRootGeometry(this, meta).apply(action).also { add(it) }
|
||||||
|
|
||||||
//fun Meta.toDynamic(): dynamic {
|
//fun Meta.toDynamic(): dynamic {
|
||||||
// fun MetaItem<*>.toDynamic(): dynamic = when (this) {
|
// 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.EmptyMeta
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.meta.toDynamic
|
import hep.dataforge.meta.toDynamic
|
||||||
|
import hep.dataforge.vis.common.DisplayGroup
|
||||||
import hep.dataforge.vis.common.DisplayLeaf
|
import hep.dataforge.vis.common.DisplayLeaf
|
||||||
import hep.dataforge.vis.common.DisplayObject
|
import hep.dataforge.vis.common.DisplayObject
|
||||||
import hep.dataforge.vis.common.DisplayObjectList
|
|
||||||
import hep.dataforge.vis.common.node
|
import hep.dataforge.vis.common.node
|
||||||
import hep.dataforge.vis.spatial.ThreeFactory
|
import hep.dataforge.vis.spatial.ThreeFactory
|
||||||
import info.laht.threekt.core.Object3D
|
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)
|
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 charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
<title>Three js demo for particle physics</title>
|
<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"
|
<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">
|
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
|
||||||
<script type="text/javascript" src="main.bundle.js"></script>
|
<script type="text/javascript" src="main.bundle.js"></script>
|
||||||
@ -34,9 +22,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="container" id="canvas"></div>
|
<div class="container" id="canvas"></div>
|
||||||
|
|
||||||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
|
<!--<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"-->
|
||||||
integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
|
<!-- integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"-->
|
||||||
crossorigin="anonymous"></script>
|
<!-- crossorigin="anonymous"></script>-->
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
|
||||||
integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
|
integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
|
||||||
crossorigin="anonymous"></script>
|
crossorigin="anonymous"></script>
|
||||||
|
@ -2,9 +2,9 @@ package hep.dataforge.vis.spatial
|
|||||||
|
|
||||||
import hep.dataforge.meta.EmptyMeta
|
import hep.dataforge.meta.EmptyMeta
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.vis.common.DisplayGroup
|
||||||
import hep.dataforge.vis.common.DisplayLeaf
|
import hep.dataforge.vis.common.DisplayLeaf
|
||||||
import hep.dataforge.vis.common.DisplayObject
|
import hep.dataforge.vis.common.DisplayObject
|
||||||
import hep.dataforge.vis.common.DisplayObjectList
|
|
||||||
import hep.dataforge.vis.common.double
|
import hep.dataforge.vis.common.double
|
||||||
|
|
||||||
class Box(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, meta), Shape {
|
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
|
//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 dx = xSize / 2
|
||||||
val dy = ySize / 2
|
val dy = ySize / 2
|
||||||
val dz = zSize / 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 node6 = Point3D(dx, -dy, dz)
|
||||||
val node7 = Point3D(dx, dy, dz)
|
val node7 = Point3D(dx, dy, dz)
|
||||||
val node8 = Point3D(-dx, dy, dz)
|
val node8 = Point3D(-dx, dy, dz)
|
||||||
face4(node1, node4, node3, node2, Point3D(0, 0, -1))
|
geometryBuilder.face4(node1, node4, node3, node2, Point3D(0, 0, -1))
|
||||||
face4(node1, node2, node6, node5, Point3D(0, -1, 0))
|
geometryBuilder.face4(node1, node2, node6, node5, Point3D(0, -1, 0))
|
||||||
face4(node2, node3, node7, node6, Point3D(1, 0, 0))
|
geometryBuilder.face4(node2, node3, node7, node6, Point3D(1, 0, 0))
|
||||||
face4(node4, node8, node7, node3, Point3D(0, 1, 0))
|
geometryBuilder.face4(node4, node8, node7, node3, Point3D(0, 1, 0))
|
||||||
face4(node1, node5, node8, node4, Point3D(-1, 0, 0))
|
geometryBuilder.face4(node1, node5, node8, node4, Point3D(-1, 0, 0))
|
||||||
face4(node8, node5, node6, node7, Point3D(0, 0, 1))
|
geometryBuilder.face4(node8, node5, node6, node7, Point3D(0, 0, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
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 = {}) =
|
fun DisplayGroup.box(meta: Meta = EmptyMeta, action: Box.() -> Unit = {}) =
|
||||||
Box(this, meta).apply(action).also { addChild(it) }
|
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
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.meta.*
|
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.DisplayLeaf
|
||||||
import hep.dataforge.vis.common.DisplayObject
|
import hep.dataforge.vis.common.DisplayObject
|
||||||
import hep.dataforge.vis.common.DisplayObjectList
|
|
||||||
|
|
||||||
class Convex(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, meta) {
|
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"
|
const val TYPE = "geometry.3d.convex"
|
||||||
|
|
||||||
fun points(item: MetaItem<*>): List<Point3D> {
|
fun points(item: MetaItem<*>): List<Point3D> {
|
||||||
return item.node?.getAll("point".toName())?.map { (_, value) ->
|
return item.node?.getAll("point")?.map { (_, value) ->
|
||||||
Point3D(value.node["x"].number ?: 0, value.node["y"].number ?: 0, value.node["y"].number ?: 0)
|
Point3D.from(value.node?: error("Point definition is not a node"))
|
||||||
} ?: emptyList()
|
} ?: emptyList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun DisplayObjectList.convex(meta: Meta = EmptyMeta, action: ConvexBuilder.() -> Unit = {}) =
|
fun DisplayGroup.convex(meta: Meta = EmptyMeta, action: ConvexBuilder.() -> Unit = {}) =
|
||||||
ConvexBuilder().apply(action).build(this, meta).also { addChild(it) }
|
ConvexBuilder().apply(action).build(this, meta).also { add(it) }
|
||||||
|
|
||||||
class ConvexBuilder {
|
class ConvexBuilder {
|
||||||
private val points = ArrayList<Point3D>()
|
private val points = ArrayList<Point3D>()
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
|
import hep.dataforge.vis.common.DisplayGroup
|
||||||
import hep.dataforge.vis.common.DisplayLeaf
|
import hep.dataforge.vis.common.DisplayLeaf
|
||||||
import hep.dataforge.vis.common.DisplayObject
|
import hep.dataforge.vis.common.DisplayObject
|
||||||
import hep.dataforge.vis.common.DisplayObjectList
|
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
import kotlin.math.cos
|
import kotlin.math.cos
|
||||||
import kotlin.math.sin
|
import kotlin.math.sin
|
||||||
@ -46,7 +46,7 @@ class Extruded(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, meta),
|
|||||||
|
|
||||||
val shape
|
val shape
|
||||||
get() = properties.getAll("shape.point").map { (_, value) ->
|
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) {
|
fun shape(block: Shape2DBuilder.() -> Unit) {
|
||||||
@ -70,7 +70,7 @@ class Extruded(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, meta),
|
|||||||
return layer
|
return layer
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <T : Any> GeometryBuilder<T>.buildGeometry() {
|
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {
|
||||||
val shape: Shape2D = shape
|
val shape: Shape2D = shape
|
||||||
|
|
||||||
if (shape.size < 3) error("Extruded shape requires more than points per layer")
|
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]
|
upperLayer = layers[i]
|
||||||
for (j in (0 until shape.size - 1)) {
|
for (j in (0 until shape.size - 1)) {
|
||||||
//counter clockwise
|
//counter clockwise
|
||||||
face4(
|
geometryBuilder.face4(
|
||||||
lowerLayer[j],
|
lowerLayer[j],
|
||||||
lowerLayer[j + 1],
|
lowerLayer[j + 1],
|
||||||
upperLayer[j + 1],
|
upperLayer[j + 1],
|
||||||
@ -104,7 +104,7 @@ class Extruded(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, meta),
|
|||||||
}
|
}
|
||||||
|
|
||||||
// final face
|
// final face
|
||||||
face4(
|
geometryBuilder.face4(
|
||||||
lowerLayer[shape.size - 1],
|
lowerLayer[shape.size - 1],
|
||||||
lowerLayer[0],
|
lowerLayer[0],
|
||||||
upperLayer[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 = {}) =
|
fun DisplayGroup.extrude(meta: Meta = EmptyMeta, action: Extruded.() -> Unit = {}) =
|
||||||
Extruded(this, meta).apply(action).also { addChild(it) }
|
Extruded(this, meta).apply(action).also { add(it) }
|
@ -1,16 +1,19 @@
|
|||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.meta.EmptyMeta
|
import hep.dataforge.meta.*
|
||||||
import hep.dataforge.meta.Meta
|
|
||||||
import hep.dataforge.meta.MetaRepr
|
|
||||||
import hep.dataforge.meta.buildMeta
|
|
||||||
import hep.dataforge.vis.common.DisplayObject
|
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 {
|
override fun toMeta(): Meta = buildMeta {
|
||||||
"x" to x
|
"x" to x
|
||||||
"y" to y
|
"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 {
|
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
|
"y" to y
|
||||||
"z" to z
|
"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
|
* @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,
|
* 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.
|
* 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 face(vertex1: Point3D, vertex2: Point3D, vertex3: Point3D, normal: Point3D? = null, meta: Meta = EmptyMeta)
|
||||||
|
|
||||||
fun build(): T
|
fun build(): T
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun GeometryBuilder<*>.face4(
|
fun GeometryBuilder<*>.face4(
|
||||||
@ -50,6 +58,6 @@ fun GeometryBuilder<*>.face4(
|
|||||||
face(vertex1, vertex3, vertex4, normal, meta)
|
face(vertex1, vertex3, vertex4, normal, meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Shape: DisplayObject {
|
interface Shape : DisplayObject {
|
||||||
fun <T: Any> GeometryBuilder<T>.buildGeometry()
|
fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>)
|
||||||
}
|
}
|
@ -4,15 +4,14 @@ import hep.dataforge.meta.*
|
|||||||
import hep.dataforge.output.Output
|
import hep.dataforge.output.Output
|
||||||
import hep.dataforge.vis.common.DisplayGroup
|
import hep.dataforge.vis.common.DisplayGroup
|
||||||
import hep.dataforge.vis.common.DisplayObject
|
import hep.dataforge.vis.common.DisplayObject
|
||||||
import hep.dataforge.vis.common.DisplayObjectList
|
|
||||||
import hep.dataforge.vis.common.getProperty
|
import hep.dataforge.vis.common.getProperty
|
||||||
|
|
||||||
fun DisplayObjectList.group(meta: Meta = EmptyMeta, action: DisplayObjectList.() -> Unit = {}): DisplayGroup =
|
fun DisplayGroup.group(meta: Meta = EmptyMeta, action: DisplayGroup.() -> Unit = {}): DisplayGroup =
|
||||||
DisplayObjectList(this, meta).apply(action).also { addChild(it) }
|
DisplayGroup(this, meta).apply(action).also { add(it) }
|
||||||
|
|
||||||
|
|
||||||
fun Output<DisplayObject>.render(meta: Meta = EmptyMeta, action: DisplayObjectList.() -> Unit) =
|
fun Output<DisplayObject>.render(meta: Meta = EmptyMeta, action: DisplayGroup.() -> Unit) =
|
||||||
render(DisplayObjectList(null, EmptyMeta).apply(action), meta)
|
render(DisplayGroup(null, EmptyMeta).apply(action), meta)
|
||||||
|
|
||||||
//TODO replace properties by containers?
|
//TODO replace properties by containers?
|
||||||
|
|
||||||
@ -133,11 +132,11 @@ var DisplayObject.scaleZ
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun DisplayObject.color(rgb: Int) {
|
fun DisplayObject.color(rgb: Int) {
|
||||||
this.properties["color"] = rgb
|
this.properties["material"] = rgb
|
||||||
}
|
}
|
||||||
|
|
||||||
fun DisplayObject.color(meta: Meta) {
|
fun DisplayObject.color(meta: Meta) {
|
||||||
this.properties["color"] = meta
|
this.properties["material"] = meta
|
||||||
}
|
}
|
||||||
|
|
||||||
fun DisplayObject.color(r: Int, g: Int, b: Int) = color(buildMeta {
|
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.getAll
|
||||||
import hep.dataforge.meta.node
|
import hep.dataforge.meta.node
|
||||||
import hep.dataforge.names.toName
|
import hep.dataforge.names.toName
|
||||||
import hep.dataforge.vis.common.DisplayObjectList
|
import hep.dataforge.vis.common.DisplayGroup
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
class ConvexTest {
|
class ConvexTest {
|
||||||
@Test
|
@Test
|
||||||
fun testConvexBuilder() {
|
fun testConvexBuilder() {
|
||||||
val group = DisplayObjectList().apply {
|
val group = DisplayGroup().apply {
|
||||||
convex {
|
convex {
|
||||||
point(50, 50, -50)
|
point(50, 50, -50)
|
||||||
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
|
val pointsNode = convex.properties["points"].node
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user