Conflicts:
	dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualObject.kt
This commit is contained in:
Peter Klimai 2019-10-10 21:29:47 +03:00
commit 7f0b08fcc9
45 changed files with 870 additions and 523 deletions

View File

@ -19,6 +19,8 @@ kotlin {
dependencies { dependencies {
api("hep.dataforge:dataforge-output-html:$dataforgeVersion") api("hep.dataforge:dataforge-output-html:$dataforgeVersion")
api(npm("text-encoding")) api(npm("text-encoding"))
api("org.jetbrains:kotlin-extensions:1.0.1-pre.83-kotlin-1.3.50")
api(npm("core-js"))
} }
} }
} }

View File

@ -19,14 +19,17 @@ abstract class AbstractVisualGroup : AbstractVisualObject(), MutableVisualGroup
*/ */
abstract override val children: Map<NameToken, VisualObject> //get() = _children abstract override val children: Map<NameToken, VisualObject> //get() = _children
//TODO replace by custom object with get/set functionality /**
protected abstract val styles: MutableMap<Name, Meta> * Styles, defined in this group. A style could be defined but not applied
* TODO replace by custom object with get/set functionality
*/
protected abstract val styleSheet: MutableMap<Name, Meta>
override fun getStyle(name: Name): Meta? = styles[name] override fun getStyle(name: Name): Meta? = styleSheet[name]
override fun setStyle(name: Name, meta: Meta) { override fun addStyle(name: Name, meta: Meta, apply: Boolean) {
fun VisualObject.applyStyle(name: Name, meta: Meta) { fun VisualObject.applyStyle(name: Name, meta: Meta) {
if (style.contains(name.toString())) { if (styles.contains(name)) {
//full update //full update
//TODO do a fine grained update //TODO do a fine grained update
if (this is AbstractVisualObject) { if (this is AbstractVisualObject) {
@ -41,9 +44,11 @@ abstract class AbstractVisualGroup : AbstractVisualObject(), MutableVisualGroup
} }
} }
} }
styles[name] = meta styleSheet[name] = meta
if (apply) {
applyStyle(name, meta) applyStyle(name, meta)
} }
}
// init { // init {

View File

@ -12,9 +12,6 @@ internal data class PropertyListener(
val action: (name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) -> Unit val action: (name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) -> Unit
) )
/**
* Abstract implementation of [VisualObject]
*/
abstract class AbstractVisualObject : VisualObject { abstract class AbstractVisualObject : VisualObject {
@Transient @Transient
@ -22,13 +19,10 @@ abstract class AbstractVisualObject : VisualObject {
abstract override var properties: Config? abstract override var properties: Config?
/** override var styles: List<Name>
* Style(s) of the object get() = properties?.get(STYLE_KEY).stringList.map(String::toName)
*/
override var style: List<String>
get() = properties?.let { it[STYLE_KEY].stringList } ?: emptyList()
set(value) { set(value) {
setProperty(STYLE_KEY, value) setProperty(STYLE_KEY, value.map { it.toString() })
styleChanged() styleChanged()
} }
@ -67,8 +61,10 @@ abstract class AbstractVisualObject : VisualObject {
/** /**
* Collect all styles for this object in a laminate * Collect all styles for this object in a laminate
*/ */
protected val appliedStyles: Meta protected val mergedStyles: Meta
get() = styleCache ?: Laminate(style.map { it.toName() }.mapNotNull(::findStyle)).merge().also { styleCache = it } get() = styleCache ?: findAllStyles().merge().also {
styleCache = it
}
/** /**
@ -81,9 +77,9 @@ abstract class AbstractVisualObject : VisualObject {
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? { override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {
return if (inherit) { return if (inherit) {
properties?.get(name) ?: appliedStyles[name] ?: parent?.getProperty(name, inherit) properties?.get(name) ?: mergedStyles[name] ?: parent?.getProperty(name, inherit)
} else { } else {
properties?.get(name) ?: appliedStyles[name] properties?.get(name) ?: mergedStyles[name]
} }
} }
@ -96,7 +92,7 @@ abstract class AbstractVisualObject : VisualObject {
} }
} }
internal fun VisualObject.findStyle(styleName: Name): Meta? { fun VisualObject.findStyle(styleName: Name): Meta? {
if (this is VisualGroup) { if (this is VisualGroup) {
val style = getStyle(styleName) val style = getStyle(styleName)
if (style != null) return style if (style != null) return style

View File

@ -44,7 +44,7 @@ interface VisualGroup : Provider, Iterable<VisualObject>, VisualObject {
/** /**
* Add or replace style with given name * Add or replace style with given name
*/ */
fun setStyle(name: Name, meta: Meta) fun addStyle(name: Name, meta: Meta, apply: Boolean = true)
operator fun get(name: Name): VisualObject? { operator fun get(name: Name): VisualObject? {
return when { return when {

View File

@ -1,9 +1,6 @@
package hep.dataforge.vis.common package hep.dataforge.vis.common
import hep.dataforge.meta.Config import hep.dataforge.meta.*
import hep.dataforge.meta.Configurable
import hep.dataforge.meta.MetaItem
import hep.dataforge.meta.MetaRepr
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.asName import hep.dataforge.names.asName
import hep.dataforge.names.toName import hep.dataforge.names.toName
@ -56,11 +53,16 @@ interface VisualObject : MetaRepr, Configurable {
*/ */
fun removeChangeListener(owner: Any?) fun removeChangeListener(owner: Any?)
var style: List<String> /**
* List of names of styles applied to this object
*/
var styles: List<Name>
fun findAllStyles(): Laminate = Laminate(styles.distinct().mapNotNull(::findStyle))
companion object { companion object {
const val TYPE = "visual" const val TYPE = "visual"
val STYLE_KEY = "style".asName() val STYLE_KEY = "@style".asName()
//const val META_KEY = "@meta" //const val META_KEY = "@meta"
//const val TAGS_KEY = "@tags" //const val TAGS_KEY = "@tags"
@ -81,5 +83,5 @@ fun VisualObject.setProperty(key: String, value: Any?) = setProperty(key.toName(
* Apply style to [VisualObject] by adding it to the [style] list * Apply style to [VisualObject] by adding it to the [style] list
*/ */
fun VisualObject.applyStyle(name: String) { fun VisualObject.applyStyle(name: String) {
style = style + name styles = styles + name.toName()
} }

View File

@ -4,6 +4,7 @@ import hep.dataforge.meta.*
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.NameToken import hep.dataforge.names.NameToken
import hep.dataforge.names.asName import hep.dataforge.names.asName
import hep.dataforge.names.toName
import hep.dataforge.values.Value import hep.dataforge.values.Value
import kotlin.jvm.JvmName import kotlin.jvm.JvmName
import kotlin.properties.ReadOnlyProperty import kotlin.properties.ReadOnlyProperty
@ -35,81 +36,79 @@ class VisualObjectDelegate(
} }
class VisualObjectDelegateWrapper<T>( class VisualObjectDelegateWrapper<T>(
val obj: VisualObject,
val key: Name?, val key: Name?,
val default: T, val default: T,
val inherited: Boolean, val inherited: Boolean,
val write: Config.(name: Name, value: T) -> Unit = { name, value -> set(name, value) }, val write: Config.(name: Name, value: T) -> Unit = { name, value -> set(name, value) },
val read: (MetaItem<*>?) -> T? val read: (MetaItem<*>?) -> T?
) : ReadWriteProperty<VisualObject, T> { ) : ReadWriteProperty<Any?, T> {
//private var cachedName: Name? = null //private var cachedName: Name? = null
override fun getValue(thisRef: VisualObject, property: KProperty<*>): T { override fun getValue(thisRef: Any?, property: KProperty<*>): T {
val name = key ?: property.name.asName() val name = key ?: property.name.asName()
return if (inherited) { return read(obj.getProperty(name,inherited))?:default
read(thisRef.getProperty(name))
} else {
read(thisRef.config[name])
} ?: default
} }
override fun setValue(thisRef: VisualObject, property: KProperty<*>, value: T) { override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
val name = key ?: property.name.asName() val name = key ?: property.name.asName()
thisRef.config[name] = value obj.config[name] = value
} }
} }
fun VisualObject.value(default: Value? = null, key: String? = null, inherited: Boolean = false) = fun VisualObject.value(default: Value? = null, key: String? = null, inherited: Boolean = false) =
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.value } VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.value }
fun VisualObject.string(default: String? = null, key: String? = null, inherited: Boolean = false) = fun VisualObject.string(default: String? = null, key: String? = null, inherited: Boolean = false) =
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.string } VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.string }
fun VisualObject.boolean(default: Boolean? = null, key: String? = null, inherited: Boolean = false) = fun VisualObject.boolean(default: Boolean? = null, key: String? = null, inherited: Boolean = false) =
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.boolean } VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.boolean }
fun VisualObject.number(default: Number? = null, key: String? = null, inherited: Boolean = false) = fun VisualObject.number(default: Number? = null, key: String? = null, inherited: Boolean = false) =
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.number } VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.number }
fun VisualObject.double(default: Double? = null, key: String? = null, inherited: Boolean = false) = fun VisualObject.double(default: Double? = null, key: String? = null, inherited: Boolean = false) =
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.double } VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.double }
fun VisualObject.int(default: Int? = null, key: String? = null, inherited: Boolean = false) = fun VisualObject.int(default: Int? = null, key: String? = null, inherited: Boolean = false) =
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.int } VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.int }
fun VisualObject.node(key: String? = null, inherited: Boolean = true) = fun VisualObject.node(key: String? = null, inherited: Boolean = true) =
VisualObjectDelegateWrapper(key?.asName(), null, inherited) { it.node } VisualObjectDelegateWrapper(this, key?.toName(), null, inherited) { it.node }
fun VisualObject.item(key: String? = null, inherited: Boolean = true) = fun VisualObject.item(key: String? = null, inherited: Boolean = true) =
VisualObjectDelegateWrapper(key?.asName(), null, inherited) { it } VisualObjectDelegateWrapper(this, key?.toName(), null, inherited) { it }
//fun <T : Configurable> Configurable.spec(spec: Specification<T>, key: String? = null) = ChildConfigDelegate<T>(key) { spec.wrap(this) } //fun <T : Configurable> Configurable.spec(spec: Specification<T>, key: String? = null) = ChildConfigDelegate<T>(key) { spec.wrap(this) }
@JvmName("safeString") @JvmName("safeString")
fun VisualObject.string(default: String, key: String? = null, inherited: Boolean = false) = fun VisualObject.string(default: String, key: String? = null, inherited: Boolean = false) =
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.string } VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.string }
@JvmName("safeBoolean") @JvmName("safeBoolean")
fun VisualObject.boolean(default: Boolean, key: String? = null, inherited: Boolean = false) = fun VisualObject.boolean(default: Boolean, key: String? = null, inherited: Boolean = false) =
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.boolean } VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.boolean }
@JvmName("safeNumber") @JvmName("safeNumber")
fun VisualObject.number(default: Number, key: String? = null, inherited: Boolean = false) = fun VisualObject.number(default: Number, key: String? = null, inherited: Boolean = false) =
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.number } VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.number }
@JvmName("safeDouble") @JvmName("safeDouble")
fun VisualObject.double(default: Double, key: String? = null, inherited: Boolean = false) = fun VisualObject.double(default: Double, key: String? = null, inherited: Boolean = false) =
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.double } VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.double }
@JvmName("safeInt") @JvmName("safeInt")
fun VisualObject.int(default: Int, key: String? = null, inherited: Boolean = false) = fun VisualObject.int(default: Int, key: String? = null, inherited: Boolean = false) =
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.int } VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.int }
inline fun <reified E : Enum<E>> VisualObject.enum(default: E, key: String? = null, inherited: Boolean = false) = inline fun <reified E : Enum<E>> VisualObject.enum(default: E, key: String? = null, inherited: Boolean = false) =
VisualObjectDelegateWrapper( VisualObjectDelegateWrapper(
this,
key?.let { NameToken(it).asName() }, key?.let { NameToken(it).asName() },
default, default,
inherited inherited
@ -121,11 +120,11 @@ fun <T> VisualObject.merge(
key: String? = null, key: String? = null,
transformer: (Sequence<MetaItem<*>>) -> T transformer: (Sequence<MetaItem<*>>) -> T
): ReadOnlyProperty<VisualObject, T> { ): ReadOnlyProperty<VisualObject, T> {
return object : ReadOnlyProperty<VisualObject, T> { return object : ReadOnlyProperty<Any?, T> {
override fun getValue(thisRef: VisualObject, property: KProperty<*>): T { override fun getValue(thisRef: Any?, property: KProperty<*>): T {
val name = key?.asName() ?: property.name.asName() val name = key?.toName() ?: property.name.asName()
val sequence = sequence<MetaItem<*>> { val sequence = sequence<MetaItem<*>> {
var thisObj: VisualObject? = thisRef var thisObj: VisualObject? = this@merge
while (thisObj != null) { while (thisObj != null) {
thisObj.config[name]?.let { yield(it) } thisObj.config[name]?.let { yield(it) }
thisObj = thisObj.parent thisObj = thisObj.parent

View File

@ -1,4 +1,4 @@
package hep.dataforge.vis.hmr package hep.dataforge.vis
import kotlin.browser.document import kotlin.browser.document
import kotlin.dom.hasClass import kotlin.dom.hasClass

View File

@ -0,0 +1,21 @@
package hep.dataforge.vis
inline fun <T : Any> jsObject(builder: T.() -> Unit): T {
val obj: T = js("({})") as T
return obj.apply {
builder()
}
}
inline fun js(builder: dynamic.() -> Unit): dynamic = jsObject(builder)
//fun <T : Any> clone(obj: T) = objectAssign(jsObject<T> {}, obj)
//inline fun <T : Any> assign(obj: T, builder: T.() -> Unit) = clone(obj).apply(builder)
fun toPlainObjectStripNull(obj: Any) = js {
for (key in Object.keys(obj)) {
val value = obj.asDynamic()[key]
if (value != null) this[key] = value
}
}

View File

@ -14,7 +14,6 @@ import hep.dataforge.vis.spatial.VisualGroup3D
import hep.dataforge.vis.spatial.VisualObject3D import hep.dataforge.vis.spatial.VisualObject3D
import hep.dataforge.vis.spatial.rotationOrder import hep.dataforge.vis.spatial.rotationOrder
import scientifik.gdml.* import scientifik.gdml.*
import kotlin.collections.set
import kotlin.random.Random import kotlin.random.Random
class GDMLTransformer(val root: GDML) { class GDMLTransformer(val root: GDML) {
@ -31,7 +30,7 @@ class GDMLTransformer(val root: GDML) {
* A special group for local templates * A special group for local templates
*/ */
val templates by lazy { VisualGroup3D() } val templates by lazy { VisualGroup3D() }
private val styles = HashMap<Name, Meta>() private val styleCache = HashMap<Name, Meta>()
var lUnit: LUnit = LUnit.MM var lUnit: LUnit = LUnit.MM
@ -42,7 +41,7 @@ class GDMLTransformer(val root: GDML) {
var solidConfiguration: VisualObject3D.(parent: GDMLVolume, solid: GDMLSolid) -> Unit = { _, _ -> } var solidConfiguration: VisualObject3D.(parent: GDMLVolume, solid: GDMLSolid) -> Unit = { _, _ -> }
fun VisualObject.useStyle(name: String, builder: MetaBuilder.() -> Unit) { fun VisualObject.useStyle(name: String, builder: MetaBuilder.() -> Unit) {
styles.getOrPut(name.toName()){ styleCache.getOrPut(name.toName()){
buildMeta(builder) buildMeta(builder)
} }
applyStyle(name) applyStyle(name)
@ -60,35 +59,17 @@ class GDMLTransformer(val root: GDML) {
obj.solidConfiguration(parent, solid) obj.solidConfiguration(parent, solid)
} }
//
fun printStatistics() { // internal fun solidAdded(solid: GDMLSolid) {
println("Solids:") // solidCounter[solid.name] = (solidCounter[solid.name] ?: 0) + 1
solidCounter.entries.sortedByDescending { it.value }.forEach { // }
println("\t$it")
}
println("Solids total: ${solidCounter.values.sum()}")
}
private val solidCounter = HashMap<String, Int>()
internal fun solidAdded(solid: GDMLSolid) {
solidCounter[solid.name] = (solidCounter[solid.name] ?: 0) + 1
}
var onFinish: GDMLTransformer.() -> Unit = {} var onFinish: GDMLTransformer.() -> Unit = {}
var optimizeSingleChild = false
//var optimizations: List<GDMLOptimization> = emptyList()
internal fun finalize(final: VisualGroup3D): VisualGroup3D { internal fun finalize(final: VisualGroup3D): VisualGroup3D {
// var res = final
// optimizations.forEach {
// res = it(res)
// }
final.templates = templates final.templates = templates
styles.forEach { styleCache.forEach {
final.setStyle(it.key, it.value) final.addStyle(it.key, it.value, false)
} }
final.rotationOrder = RotationOrder.ZXY final.rotationOrder = RotationOrder.ZXY
onFinish(this@GDMLTransformer) onFinish(this@GDMLTransformer)

View File

@ -1,58 +0,0 @@
package hep.dataforge.vis.spatial.gdml
import hep.dataforge.meta.update
import hep.dataforge.names.asName
import hep.dataforge.vis.common.MutableVisualGroup
import hep.dataforge.vis.spatial.Point3D
import hep.dataforge.vis.spatial.VisualGroup3D
import hep.dataforge.vis.spatial.VisualObject3D
import hep.dataforge.vis.spatial.plus
import kotlin.collections.component1
import kotlin.collections.component2
typealias GDMLOptimization = GDMLTransformer.(VisualGroup3D) -> VisualGroup3D
/**
* Collapse nodes with single child
*/
val optimizeSingleChild: GDMLOptimization = { tree ->
fun MutableVisualGroup.replaceChildren() {
children.forEach { (key, child) ->
if (child is VisualGroup3D && child.children.size == 1) {
val newChild = child.children.values.first().apply {
config.update(child.config)
}
if (newChild is VisualObject3D) {
newChild.apply {
position += child.position
rotation += child.rotation
scale = when {
scale == null && child.scale == null -> null
scale == null -> child.scale
child.scale == null -> scale
else -> Point3D(
scale!!.x * child.scale!!.x,
scale!!.y * child.scale!!.y,
scale!!.z * child.scale!!.z
)
}
}
}
if (newChild is MutableVisualGroup) {
newChild.replaceChildren()
}
//actual replacement
set(key.asName(), newChild)
} else if (child is MutableVisualGroup) {
child.replaceChildren()
}
}
}
tree.replaceChildren()
tree
}

View File

@ -47,7 +47,7 @@ private fun VisualGroup3D.addSolid(
name: String = "", name: String = "",
block: VisualObject3D.() -> Unit = {} block: VisualObject3D.() -> Unit = {}
): VisualObject3D { ): VisualObject3D {
context.solidAdded(solid) //context.solidAdded(solid)
val lScale = solid.lscale(context.lUnit) val lScale = solid.lscale(context.lUnit)
val aScale = solid.ascale() val aScale = solid.ascale()
return when (solid) { return when (solid) {
@ -150,23 +150,6 @@ private fun VisualGroup3D.addPhysicalVolume(
when (context.volumeAction(volume)) { when (context.volumeAction(volume)) {
GDMLTransformer.Action.ACCEPT -> { GDMLTransformer.Action.ACCEPT -> {
val group = volume(context, volume) val group = volume(context, volume)
//optimizing single child case
if (context.optimizeSingleChild && group.children.size == 1) {
this[physVolume.name ?: ""] = group.children.values.first().apply {
//Must set this to avoid parent reset error
parent = null
//setting offset from physical volume
withPosition(
context.lUnit,
physVolume.resolvePosition(context.root),
physVolume.resolveRotation(context.root),
physVolume.resolveScale(context.root)
)
// in case when both phys volume and underlying volume have offset
position += group.position
rotation += group.rotation
}
} else {
this[physVolume.name ?: ""] = group.apply { this[physVolume.name ?: ""] = group.apply {
withPosition( withPosition(
context.lUnit, context.lUnit,
@ -176,7 +159,6 @@ private fun VisualGroup3D.addPhysicalVolume(
) )
} }
} }
}
GDMLTransformer.Action.CACHE -> { GDMLTransformer.Action.CACHE -> {
val fullName = volumesName + volume.name.asName() val fullName = volumesName + volume.name.asName()
if (context.templates[fullName] == null) { if (context.templates[fullName] == null) {

View File

@ -1,33 +1,26 @@
package hep.dataforge.vis.spatial.gdml.demo package hep.dataforge.vis.spatial.gdml.demo
import hep.dataforge.context.Global import hep.dataforge.context.Global
import hep.dataforge.vis.common.VisualGroup import hep.dataforge.vis.ApplicationBase
import hep.dataforge.vis.hmr.ApplicationBase
import hep.dataforge.vis.hmr.startApplication
import hep.dataforge.vis.spatial.Material3D.Companion.OPACITY_KEY import hep.dataforge.vis.spatial.Material3D.Companion.OPACITY_KEY
import hep.dataforge.vis.spatial.Visual3DPlugin import hep.dataforge.vis.spatial.Visual3DPlugin
import hep.dataforge.vis.spatial.VisualGroup3D import hep.dataforge.vis.spatial.VisualGroup3D
import hep.dataforge.vis.spatial.VisualObject3D import hep.dataforge.vis.spatial.VisualObject3D
import hep.dataforge.vis.spatial.attachChildren import hep.dataforge.vis.spatial.attachChildren
import hep.dataforge.vis.spatial.editor.propertyEditor
import hep.dataforge.vis.spatial.editor.threeOutputConfig
import hep.dataforge.vis.spatial.editor.visualObjectTree
import hep.dataforge.vis.spatial.gdml.GDMLTransformer import hep.dataforge.vis.spatial.gdml.GDMLTransformer
import hep.dataforge.vis.spatial.gdml.LUnit import hep.dataforge.vis.spatial.gdml.LUnit
import hep.dataforge.vis.spatial.gdml.toVisual import hep.dataforge.vis.spatial.gdml.toVisual
import hep.dataforge.vis.spatial.three.ThreeOutput
import hep.dataforge.vis.spatial.three.ThreePlugin import hep.dataforge.vis.spatial.three.ThreePlugin
import hep.dataforge.vis.spatial.three.output import hep.dataforge.vis.spatial.three.output
import hep.dataforge.vis.spatial.tree.propertyEditor import hep.dataforge.vis.startApplication
import hep.dataforge.vis.spatial.tree.render
import hep.dataforge.vis.spatial.tree.toTree
import kotlinx.html.InputType
import kotlinx.html.dom.append import kotlinx.html.dom.append
import kotlinx.html.js.input
import kotlinx.html.js.li
import kotlinx.html.js.p import kotlinx.html.js.p
import kotlinx.html.js.ul import org.w3c.dom.DragEvent
import org.w3c.dom.Element
import org.w3c.dom.HTMLDivElement import org.w3c.dom.HTMLDivElement
import org.w3c.dom.HTMLElement import org.w3c.dom.HTMLElement
import org.w3c.dom.events.Event
import org.w3c.files.FileList import org.w3c.files.FileList
import org.w3c.files.FileReader import org.w3c.files.FileReader
import org.w3c.files.get import org.w3c.files.get
@ -40,33 +33,27 @@ private class GDMLDemoApp : ApplicationBase() {
/** /**
* Handle mouse drag according to https://www.html5rocks.com/en/tutorials/file/dndfiles/ * Handle mouse drag according to https://www.html5rocks.com/en/tutorials/file/dndfiles/
*/ */
private fun handleDragOver(event: Event) { private fun handleDragOver(event: DragEvent) {
event.stopPropagation() event.stopPropagation()
event.preventDefault() event.preventDefault()
event.asDynamic().dataTransfer.dropEffect = "copy" event.dataTransfer?.dropEffect = "copy"
} }
/** /**
* Load data from text file * Load data from text file
*/ */
private fun loadData(event: Event, block: (name: String, data: String) -> Unit) { private fun loadData(event: DragEvent, block: (name: String, data: String) -> Unit) {
event.stopPropagation() event.stopPropagation()
event.preventDefault() event.preventDefault()
val file = (event.asDynamic().dataTransfer.files as FileList)[0] val file = (event.dataTransfer?.files as FileList)[0]
?: throw RuntimeException("Failed to load file") ?: throw RuntimeException("Failed to load file")
FileReader().apply { FileReader().apply {
onload = { onload = {
val string = result as String val string = result as String
// try {
block(file.name, string) block(file.name, string)
// } catch (ex: Exception) {
// console.error(ex)
// }
} }
readAsText(file) readAsText(file)
} }
@ -99,53 +86,24 @@ private class GDMLDemoApp : ApplicationBase() {
} }
} }
fun setupLayers(element: Element, output: ThreeOutput) {
element.clear()
element.append {
ul("list-group") {
(0..9).forEach { layer ->
li("list-group-item") {
+"layer $layer"
input(type = InputType.checkBox).apply {
if (layer == 0) {
checked = true
}
onchange = {
if (checked) {
output.camera.layers.enable(layer)
} else {
output.camera.layers.disable(layer)
}
}
}
}
}
}
}
}
private val gdmlConfiguration: GDMLTransformer.() -> Unit = { private val gdmlConfiguration: GDMLTransformer.() -> Unit = {
lUnit = LUnit.CM lUnit = LUnit.CM
volumeAction = { volume -> volumeAction = { volume ->
when { when {
volume.name.startsWith("ecal01lay") -> GDMLTransformer.Action.REJECT volume.name.startsWith("ecal01lay") -> GDMLTransformer.Action.REJECT
volume.name.startsWith("ecal") -> GDMLTransformer.Action.CACHE
volume.name.startsWith("UPBL") -> GDMLTransformer.Action.REJECT volume.name.startsWith("UPBL") -> GDMLTransformer.Action.REJECT
volume.name.startsWith("USCL") -> GDMLTransformer.Action.REJECT volume.name.startsWith("USCL") -> GDMLTransformer.Action.REJECT
volume.name.startsWith("U") -> GDMLTransformer.Action.CACHE
volume.name.startsWith("VPBL") -> GDMLTransformer.Action.REJECT volume.name.startsWith("VPBL") -> GDMLTransformer.Action.REJECT
volume.name.startsWith("VSCL") -> GDMLTransformer.Action.REJECT volume.name.startsWith("VSCL") -> GDMLTransformer.Action.REJECT
volume.name.startsWith("V") -> GDMLTransformer.Action.CACHE else -> GDMLTransformer.Action.CACHE
else -> GDMLTransformer.Action.ACCEPT
} }
} }
solidConfiguration = { parent, solid -> solidConfiguration = { parent, solid ->
if (parent.physVolumes.isNotEmpty() if (
|| solid.name.startsWith("Coil") solid.name.startsWith("Yoke")
|| solid.name.startsWith("Yoke")
|| solid.name.startsWith("Magnet")
|| solid.name.startsWith("Pole") || solid.name.startsWith("Pole")
|| parent.physVolumes.isNotEmpty()
) { ) {
useStyle("opaque") { useStyle("opaque") {
OPACITY_KEY to 0.3 OPACITY_KEY to 0.3
@ -185,18 +143,17 @@ private class GDMLDemoApp : ApplicationBase() {
} }
} }
//Optimize tree
//(visual as? VisualGroup3D)?.transformInPlace(UnRef, RemoveSingleChild)
message("Rendering") message("Rendering")
val output = three.output(canvas as HTMLElement)
//output.camera.layers.enable(1) //output.camera.layers.enable(1)
output.camera.layers.set(0) val output = three.output(canvas as HTMLElement)
setupLayers(layers, output)
if (visual is VisualGroup) { output.camera.layers.set(0)
visual.toTree(editor::propertyEditor).render(tree as HTMLElement) { layers.threeOutputConfig(output)
showCheckboxes = false tree.visualObjectTree(visual, editor::propertyEditor)
}
}
output.render(visual) output.render(visual)
message(null) message(null)
@ -204,8 +161,8 @@ private class GDMLDemoApp : ApplicationBase() {
} }
(document.getElementById("drop_zone") as? HTMLDivElement)?.apply { (document.getElementById("drop_zone") as? HTMLDivElement)?.apply {
addEventListener("dragover", { handleDragOver(it) }, false) addEventListener("dragover", { handleDragOver(it as DragEvent) }, false)
addEventListener("drop", { loadData(it, action) }, false) addEventListener("drop", { loadData(it as DragEvent, action) }, false)
} }
} }

View File

@ -29,45 +29,12 @@
<div class="container-fluid"> <div class="container-fluid">
<div class="row"> <div class="row">
<div class="col-9" id="canvas"></div> <div class="col-lg-3" id="tree"></div>
<div class="col-3"> <div class="col-lg-6">
<div class="row" id="layers"></div>
<div id="editor"></div> <div class="row container" id="canvas"></div>
<div class="accordion" id="accordion">
<div class="card">
<div class="card-header" id="layers-header">
<h2 class="mb-0">
<button class="btn btn-link" type="button" data-toggle="collapse" data-target="#layers-body"
aria-expanded="true" aria-controls="layers-body">
Layers
</button>
</h2>
</div>
<div id="layers-body" class="collapse show" aria-labelledby="layers-header"
data-parent="#accordion">
<div class="card-body">
<div id="layers"></div>
</div>
</div>
</div>
<div class="card">
<div class="card-header" id="tree-header">
<h2 class="mb-0">
<button class="btn btn-link collapsed" type="button" data-toggle="collapse"
data-target="#tree-body" aria-expanded="false" aria-controls="tree-body">
Object tree
</button>
</h2>
</div>
<div id="tree-body" class="collapse" aria-labelledby="tree-header" data-parent="#accordion">
<div class="card-body">
<div id="tree"></div>
</div>
</div>
</div>
</div>
</div> </div>
<div class="col-lg-3" id="editor"></div>
</div> </div>
</div> </div>

View File

@ -0,0 +1,40 @@
package hep.dataforge.vis.spatial.gdml
import hep.dataforge.vis.spatial.Material3D
import hep.dataforge.vis.spatial.Visual3DPlugin
import hep.dataforge.vis.spatial.VisualGroup3D
import hep.dataforge.vis.spatial.VisualObject3D
import hep.dataforge.vis.spatial.transform.RemoveSingleChild
import hep.dataforge.vis.spatial.transform.UnRef
import nl.adaptivity.xmlutil.StAXReader
import scientifik.gdml.GDML
import java.io.File
fun main() {
val file = File("D:\\Work\\Projects\\gdml.kt\\gdml-source\\cubes.gdml")
val xmlReader = StAXReader(file.inputStream(), "UTF-8")
val xml = GDML.format.parse(GDML.serializer(), xmlReader)
val visual = xml.toVisual {
lUnit = LUnit.CM
solidConfiguration = { parent, solid ->
if (parent.physVolumes.isNotEmpty()) {
useStyle("opaque") {
Material3D.OPACITY_KEY to 0.3
VisualObject3D.LAYER_KEY to 2
}
}
}
}
(visual as? VisualGroup3D)?.let { UnRef(it) }?.let { RemoveSingleChild(it) }
val string = Visual3DPlugin.json.stringify(VisualGroup3D.serializer(), visual)
val tmpFile = File.createTempFile("dataforge-visual", ".json")
tmpFile.writeText(string)
println(tmpFile.canonicalPath)
}

View File

@ -1,21 +1,30 @@
package hep.dataforge.vis.spatial.gdml package hep.dataforge.vis.spatial.gdml
import hep.dataforge.vis.spatial.Material3D
import hep.dataforge.vis.spatial.Visual3DPlugin import hep.dataforge.vis.spatial.Visual3DPlugin
import hep.dataforge.vis.spatial.VisualGroup3D import hep.dataforge.vis.spatial.VisualGroup3D
import hep.dataforge.vis.spatial.opacity import hep.dataforge.vis.spatial.opacity
import hep.dataforge.vis.spatial.transform.RemoveSingleChild
import hep.dataforge.vis.spatial.transform.UnRef
import nl.adaptivity.xmlutil.StAXReader import nl.adaptivity.xmlutil.StAXReader
import scientifik.gdml.GDML import scientifik.gdml.GDML
import java.io.File import java.io.File
fun main() { fun main() {
val file = File("D:\\Work\\Projects\\gdml.kt\\gdml-source\\BM@N.gdml") val file = File("D:\\Work\\Projects\\gdml.kt\\gdml-source\\BM@N.gdml")
//val file = File("D:\\Work\\Projects\\gdml.kt\\gdml-source\\cubes.gdml")
val xmlReader = StAXReader(file.inputStream(), "UTF-8") val xmlReader = StAXReader(file.inputStream(), "UTF-8")
val xml = GDML.format.parse(GDML.serializer(), xmlReader) val xml = GDML.format.parse(GDML.serializer(), xmlReader)
val visual = xml.toVisual { val visual = xml.toVisual {
lUnit = LUnit.CM lUnit = LUnit.CM
volumeAction = { volume ->
when {
volume.name.startsWith("ecal01lay") -> GDMLTransformer.Action.REJECT
else -> GDMLTransformer.Action.CACHE
}
}
solidConfiguration = { parent, solid -> solidConfiguration = { parent, solid ->
if (parent.physVolumes.isNotEmpty() if (parent.physVolumes.isNotEmpty()
|| solid.name.startsWith("Coil") || solid.name.startsWith("Coil")
@ -24,15 +33,13 @@ fun main() {
|| solid.name.startsWith("Pole") || solid.name.startsWith("Pole")
) { ) {
useStyle("opaque") { useStyle("opaque") {
opacity = 0.3 Material3D.OPACITY_KEY to 0.3
}
} }
} }
} }
// optimizeSingleChild = true // (visual as? VisualGroup3D)?.let { UnRef(it) }?.let { RemoveSingleChild(it) }
//optimizations = listOf(optimizeSingleChild)
onFinish = { printStatistics() }
}
val string = Visual3DPlugin.json.stringify(VisualGroup3D.serializer(), visual) val string = Visual3DPlugin.json.stringify(VisualGroup3D.serializer(), visual)

View File

@ -27,14 +27,9 @@ kotlin {
} }
jsMain { jsMain {
dependencies { dependencies {
api(project(":wrappers"))
implementation(npm("three", "0.106.2")) implementation(npm("three", "0.106.2"))
implementation(npm("@hi-level/three-csg", "1.0.6")) implementation(npm("@hi-level/three-csg", "1.0.6"))
implementation(npm("style-loader"))
implementation(npm("inspire-tree","6.0.1"))
implementation(npm("inspire-tree-dom","4.0.6"))
implementation(npm("jsoneditor"))
// api("org.jetbrains:kotlin-extensions:1.0.1-pre.83-kotlin-1.3.50")
// api(npm("core-js"))
} }
} }
} }

View File

@ -0,0 +1,26 @@
@file:UseSerializers(Point3DSerializer::class)
package hep.dataforge.vis.spatial
import hep.dataforge.io.ConfigSerializer
import hep.dataforge.meta.Config
import hep.dataforge.vis.common.AbstractVisualObject
import hep.dataforge.vis.common.number
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
@Serializable
class PolyLine(var points: List<Point3D>) : AbstractVisualObject(), VisualObject3D {
@Serializable(ConfigSerializer::class)
override var properties: Config? = null
override var position: Point3D? = null
override var rotation: Point3D? = null
override var scale: Point3D? = null
//var lineType by string()
var thickness by number(1.0, key = "material.thickness")
}
fun VisualGroup3D.polyline(vararg points: Point3D, name: String = "", action: PolyLine.() -> Unit = {}) =
PolyLine(points.toList()).apply(action).also { set(name, it) }

View File

@ -35,21 +35,27 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua
/** /**
* Recursively search for defined template in the parent * Recursively search for defined template in the parent
*/ */
val prototype: VisualObject3D get() = (parent as? VisualGroup3D)?.getTemplate(templateName) val prototype: VisualObject3D
get() = (parent as? VisualGroup3D)?.getTemplate(templateName)
?: error("Template with name $templateName not found in $parent") ?: error("Template with name $templateName not found in $parent")
override fun getStyle(name: Name): Meta? = (parent as VisualGroup?)?.getStyle(name) override fun getStyle(name: Name): Meta? = (parent as VisualGroup?)?.getStyle(name)
override fun setStyle(name: Name, meta: Meta) { override fun addStyle(name: Name, meta: Meta, apply: Boolean) {
(parent as VisualGroup?)?.setStyle(name, meta) (parent as VisualGroup?)?.addStyle(name, meta, apply)
//do nothing //do nothing
} }
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? { override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {
return if (inherit) { return if (inherit) {
super.getProperty(name, false) ?: prototype.getProperty(name, false) ?: parent?.getProperty(name, inherit) properties?.get(name)
?: mergedStyles[name]
?: prototype.getProperty(name, false)
?: parent?.getProperty(name, inherit)
} else { } else {
super.getProperty(name, false) ?: prototype.getProperty(name, false) properties?.get(name)
?: mergedStyles[name]
?: prototype.getProperty(name, false)
} }
} }
@ -74,6 +80,15 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua
?: error("Prototype with name $name not found in ${this@Proxy}") ?: error("Prototype with name $name not found in ${this@Proxy}")
override var styles: List<Name>
get() = super.styles + prototype.styles
set(value) {
setProperty(VisualObject.STYLE_KEY, value.map { it.toString() })
styleChanged()
}
//override fun findAllStyles(): Laminate = Laminate((styles + prototype.styles).mapNotNull { findStyle(it) })
inner class ProxyChild(val name: Name) : AbstractVisualObject(), VisualGroup { inner class ProxyChild(val name: Name) : AbstractVisualObject(), VisualGroup {
val prototype: VisualObject by lazy { val prototype: VisualObject by lazy {
@ -89,8 +104,8 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua
override fun getStyle(name: Name): Meta? = this@Proxy.getStyle(name) override fun getStyle(name: Name): Meta? = this@Proxy.getStyle(name)
override fun setStyle(name: Name, meta: Meta) { override fun addStyle(name: Name, meta: Meta, apply: Boolean) {
this@Proxy.setStyle(name, meta) this@Proxy.addStyle(name, meta, apply)
} }
override var properties: Config? override var properties: Config?
@ -113,12 +128,12 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? { override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {
return if (inherit) { return if (inherit) {
properties?.get(name) properties?.get(name)
?: appliedStyles[name] ?: mergedStyles[name]
?: parent?.getProperty(name, inherit)
?: prototype.getProperty(name, inherit) ?: prototype.getProperty(name, inherit)
?: parent?.getProperty(name, inherit)
} else { } else {
properties?.get(name) properties?.get(name)
?: appliedStyles[name] ?: mergedStyles[name]
?: prototype.getProperty(name, inherit) ?: prototype.getProperty(name, inherit)
} }
} }

View File

@ -43,7 +43,7 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D {
//FIXME to be lifted to AbstractVisualGroup after https://github.com/Kotlin/kotlinx.serialization/issues/378 is fixed //FIXME to be lifted to AbstractVisualGroup after https://github.com/Kotlin/kotlinx.serialization/issues/378 is fixed
override var properties: Config? = null override var properties: Config? = null
override val styles = HashMap<Name, Meta>() override val styleSheet = HashMap<Name, Meta>()
override var position: Point3D? = null override var position: Point3D? = null
override var rotation: Point3D? = null override var rotation: Point3D? = null

View File

@ -10,6 +10,7 @@ import hep.dataforge.output.Output
import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.common.VisualObject
import hep.dataforge.vis.spatial.VisualObject3D.Companion.DETAIL_KEY import hep.dataforge.vis.spatial.VisualObject3D.Companion.DETAIL_KEY
import hep.dataforge.vis.spatial.VisualObject3D.Companion.LAYER_KEY import hep.dataforge.vis.spatial.VisualObject3D.Companion.LAYER_KEY
import hep.dataforge.vis.spatial.VisualObject3D.Companion.IGNORE_KEY
import hep.dataforge.vis.spatial.VisualObject3D.Companion.SELECTED_KEY import hep.dataforge.vis.spatial.VisualObject3D.Companion.SELECTED_KEY
import hep.dataforge.vis.spatial.VisualObject3D.Companion.VISIBLE_KEY import hep.dataforge.vis.spatial.VisualObject3D.Companion.VISIBLE_KEY
import kotlinx.serialization.UseSerializers import kotlinx.serialization.UseSerializers
@ -40,6 +41,7 @@ interface VisualObject3D : VisualObject {
val SELECTED_KEY = "selected".asName() val SELECTED_KEY = "selected".asName()
val DETAIL_KEY = "detail".asName() val DETAIL_KEY = "detail".asName()
val LAYER_KEY = "layer".asName() val LAYER_KEY = "layer".asName()
val IGNORE_KEY = "ignore".asName()
val GEOMETRY_KEY = "geometey".asName() val GEOMETRY_KEY = "geometey".asName()
@ -111,6 +113,14 @@ var VisualObject.visible: Boolean?
get() = getProperty(VISIBLE_KEY).boolean get() = getProperty(VISIBLE_KEY).boolean
set(value) = setProperty(VISIBLE_KEY, value) set(value) = setProperty(VISIBLE_KEY, value)
/**
* If this property is true, the object will be ignored on render.
* Property is not inherited.
*/
var VisualObject.ignore: Boolean?
get() = getProperty(IGNORE_KEY,false).boolean
set(value) = setProperty(IGNORE_KEY, value)
var VisualObject.selected: Boolean? var VisualObject.selected: Boolean?
get() = getProperty(SELECTED_KEY).boolean get() = getProperty(SELECTED_KEY).boolean
set(value) = setProperty(SELECTED_KEY, value) set(value) = setProperty(SELECTED_KEY, value)

View File

@ -0,0 +1,58 @@
package hep.dataforge.vis.spatial.transform
import hep.dataforge.meta.update
import hep.dataforge.names.asName
import hep.dataforge.vis.common.MutableVisualGroup
import hep.dataforge.vis.common.VisualGroup
import hep.dataforge.vis.common.VisualObject
import hep.dataforge.vis.spatial.*
internal fun mergeChild(parent: VisualGroup, child: VisualObject): VisualObject {
return child.apply {
parent.properties?.let { config.update(it) }
if (this is VisualObject3D && parent is VisualObject3D) {
position += parent.position
rotation += parent.rotation
scale = when {
scale == null && parent.scale == null -> null
scale == null -> parent.scale
parent.scale == null -> scale
else -> Point3D(
scale!!.x * parent.scale!!.x,
scale!!.y * parent.scale!!.y,
scale!!.z * parent.scale!!.z
)
}
}
}
}
object RemoveSingleChild : VisualTreeTransform<VisualGroup3D>() {
override fun VisualGroup3D.transformInPlace() {
fun MutableVisualGroup.replaceChildren() {
children.forEach { (childName, parent) ->
if (parent is Proxy) return@forEach //ignore refs
if (parent is MutableVisualGroup) {
parent.replaceChildren()
}
if (parent is VisualGroup && parent.children.size == 1) {
val child = parent.children.values.first()
val newParent = mergeChild(parent, child)
newParent.parent = null
set(childName.asName(), newParent)
}
}
}
replaceChildren()
templates?.replaceChildren()
}
override fun VisualGroup3D.clone(): VisualGroup3D {
TODO()
}
}

View File

@ -0,0 +1,49 @@
package hep.dataforge.vis.spatial.transform
import hep.dataforge.names.Name
import hep.dataforge.names.asName
import hep.dataforge.vis.common.MutableVisualGroup
import hep.dataforge.vis.common.VisualGroup
import hep.dataforge.vis.spatial.Proxy
import hep.dataforge.vis.spatial.VisualGroup3D
object UnRef : VisualTreeTransform<VisualGroup3D>() {
private fun VisualGroup.countRefs(): Map<Name, Int> {
return children.values.fold(HashMap()) { reducer, obj ->
if (obj is VisualGroup) {
val counter = obj.countRefs()
counter.forEach { (key, value) ->
reducer[key] = (reducer[key] ?: 0) + value
}
} else if (obj is Proxy) {
reducer[obj.templateName] = (reducer[obj.templateName] ?: 0) + 1
}
return reducer
}
}
private fun MutableVisualGroup.unref(name: Name) {
(this as? VisualGroup3D)?.templates?.set(name, null)
children.filter { (it.value as? Proxy)?.templateName == name }.forEach { (key, value) ->
val proxy = value as Proxy
val newChild = mergeChild(proxy, proxy.prototype)
newChild.parent = null
set(key.asName(), newChild) // replace proxy with merged object
}
children.values.filterIsInstance<MutableVisualGroup>().forEach { it.unref(name) }
}
override fun VisualGroup3D.transformInPlace() {
val counts = countRefs()
counts.filter { it.value <= 1 }.forEach {
this.unref(it.key)
}
}
override fun VisualGroup3D.clone(): VisualGroup3D {
TODO()
}
}

View File

@ -0,0 +1,34 @@
package hep.dataforge.vis.spatial.transform
import hep.dataforge.vis.common.VisualObject
/**
* A root class for [VisualObject] tree optimization
*/
abstract class VisualTreeTransform<T : VisualObject> {
protected abstract fun T.transformInPlace()
protected abstract fun T.clone(): T
operator fun invoke(source: T, inPlace: Boolean = true): T {
val newSource = if (inPlace) {
source
} else {
source.clone()
}
newSource.transformInPlace()
return newSource
}
}
fun <T : VisualObject> T.transform(vararg transform: VisualTreeTransform<T>): T {
var res = this
transform.forEach {
res = it(res)
}
return res
}
fun <T : VisualObject> T.transformInPlace(vararg transform: VisualTreeTransform<in T>) {
transform.forEach { it(this) }
}

View File

@ -1,6 +1,6 @@
package hep.dataforge.vis.spatial package hep.dataforge.vis.spatial
import hep.dataforge.context.Global import hep.dataforge.vis.spatial.Visual3DPlugin.Companion.json
import kotlinx.serialization.ImplicitReflectionSerializer import kotlinx.serialization.ImplicitReflectionSerializer
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -12,9 +12,9 @@ class SerializationTest {
val cube = Box(100f,100f,100f).apply{ val cube = Box(100f,100f,100f).apply{
color(222) color(222)
} }
val meta = cube.toMeta() val string = json.stringify(Box.serializer(),cube)
println(meta) println(string)
val newCube = Box(Global,null, meta) val newCube = json.parse(Box.serializer(),string)
assertEquals(cube.toMeta(),newCube.toMeta()) assertEquals(cube.toMeta(),newCube.toMeta())
} }
} }

View File

@ -0,0 +1,15 @@
package hep.dataforge.vis.spatial.editor
import kotlinx.html.TagConsumer
import kotlinx.html.js.div
import kotlinx.html.js.h3
import org.w3c.dom.HTMLElement
inline fun TagConsumer<HTMLElement>.card(title: String, crossinline block: TagConsumer<HTMLElement>.() -> Unit) {
div("card w-100") {
div("card-body") {
h3(classes = "card-title") { +title }
block()
}
}
}

View File

@ -1,6 +1,6 @@
@file:Suppress("UNCHECKED_CAST_TO_EXTERNAL_INTERFACE") @file:Suppress("UNCHECKED_CAST_TO_EXTERNAL_INTERFACE")
package hep.dataforge.vis.spatial.tree package hep.dataforge.vis.spatial.editor
import hep.dataforge.meta.string import hep.dataforge.meta.string
import hep.dataforge.names.EmptyName import hep.dataforge.names.EmptyName
@ -9,21 +9,19 @@ import hep.dataforge.names.NameToken
import hep.dataforge.vis.common.VisualGroup import hep.dataforge.vis.common.VisualGroup
import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.common.VisualObject
import hep.dataforge.vis.common.getProperty import hep.dataforge.vis.common.getProperty
import hep.dataforge.vis.jsObject
import hep.dataforge.vis.spatial.Proxy import hep.dataforge.vis.spatial.Proxy
import hep.dataforge.vis.spatial.visible import hep.dataforge.vis.spatial.visible
import org.w3c.dom.HTMLElement import info.laht.threekt.loaders.Cache.clear
import kotlinx.html.div
import kotlinx.html.dom.append
import org.w3c.dom.Element
import kotlin.js.json import kotlin.js.json
operator fun Name.plus(other: NameToken): Name = Name(tokens + other) operator fun Name.plus(other: NameToken): Name = Name(tokens + other)
fun InspireTree.render(element: HTMLElement, block: DomConfig.() -> Unit = {}) {
val config = (json(
"target" to element
) as DomConfig).apply(block)
InspireTreeDOM(this, config)
}
internal fun createInspireTree(block: Config.() -> Unit = {}): InspireTree { private fun createInspireTree(block: Config.() -> Unit = {}): InspireTree {
val config = (json( val config = (json(
"checkbox" to json( "checkbox" to json(
"autoCheckChildren" to false "autoCheckChildren" to false
@ -32,7 +30,7 @@ internal fun createInspireTree(block: Config.() -> Unit = {}): InspireTree {
return InspireTree(config) return InspireTree(config)
} }
fun VisualGroup.toTree(onFocus: (VisualObject?, String?) -> Unit = { _, _ -> }): InspireTree { private fun VisualObject.toTree(onFocus: (VisualObject?, String?) -> Unit = { _, _ -> }): InspireTree {
val map = HashMap<String, VisualObject>() val map = HashMap<String, VisualObject>()
@ -67,8 +65,10 @@ fun VisualGroup.toTree(onFocus: (VisualObject?, String?) -> Unit = { _, _ -> }):
} }
fun TreeNode.fillChildren(group: VisualGroup, groupName: Name) { fun TreeNode.fillChildren(group: VisualObject, groupName: Name) {
if(group is VisualGroup) {
group.children.forEach { (token, obj) -> group.children.forEach { (token, obj) ->
if (!token.body.startsWith("@")) {
val name = groupName + token val name = groupName + token
val nodeConfig = generateNodeConfig(obj, name) val nodeConfig = generateNodeConfig(obj, name)
val childNode = addChild(nodeConfig) val childNode = addChild(nodeConfig)
@ -78,6 +78,8 @@ fun VisualGroup.toTree(onFocus: (VisualObject?, String?) -> Unit = { _, _ -> }):
} }
} }
} }
}
}
val inspireTree = createInspireTree { val inspireTree = createInspireTree {
@ -119,3 +121,16 @@ fun VisualGroup.toTree(onFocus: (VisualObject?, String?) -> Unit = { _, _ -> }):
return inspireTree return inspireTree
} }
fun Element.visualObjectTree(group: VisualObject, onFocus: (VisualObject?, String?) -> Unit) {
clear()
append {
card("Visual object tree") {
val domConfig = jsObject<DomConfig> {
target = div()
showCheckboxes = false
}
InspireTreeDOM(group.toTree(onFocus), domConfig)
}
}
}

View File

@ -0,0 +1,37 @@
package hep.dataforge.vis.spatial.editor
import hep.dataforge.vis.spatial.three.ThreeOutput
import kotlinx.html.InputType
import kotlinx.html.dom.append
import kotlinx.html.js.div
import kotlinx.html.js.input
import kotlinx.html.js.label
import org.w3c.dom.Element
import kotlin.dom.clear
fun Element.threeOutputConfig(output: ThreeOutput) {
clear()
append {
card("Layers"){
div("row") {
(0..11).forEach { layer ->
div("col-1") {
label { +layer.toString() }
input(type = InputType.checkBox).apply {
if (layer == 0) {
checked = true
}
onchange = {
if (checked) {
output.camera.layers.enable(layer)
} else {
output.camera.layers.disable(layer)
}
}
}
}
}
}
}
}
}

View File

@ -0,0 +1,63 @@
package hep.dataforge.vis.spatial.editor
import hep.dataforge.io.toJson
import hep.dataforge.meta.*
import hep.dataforge.vis.common.VisualObject
import hep.dataforge.vis.common.findStyle
import hep.dataforge.vis.jsObject
import hep.dataforge.vis.spatial.Material3D.Companion.COLOR_KEY
import hep.dataforge.vis.spatial.Material3D.Companion.OPACITY_KEY
import hep.dataforge.vis.spatial.VisualObject3D.Companion.VISIBLE_KEY
import hep.dataforge.vis.spatial.color
import hep.dataforge.vis.spatial.opacity
import hep.dataforge.vis.spatial.prototype
import hep.dataforge.vis.spatial.visible
import kotlinx.html.dom.append
import kotlinx.html.js.div
import kotlinx.html.js.h4
import org.w3c.dom.Element
import kotlin.dom.clear
//FIXME something rotten in JS-Meta converter
fun Meta.toDynamic() = JSON.parse<dynamic>(toJson().toString())
fun Element.propertyEditor(item: VisualObject?, name: String?) {
clear()
if (item != null) {
append {
card("Properties") {
val config = (item.properties ?: item.prototype?.properties) ?: EmptyMeta
val metaToEdit = config.builder().apply {
VISIBLE_KEY to (item.visible ?: true)
COLOR_KEY to (item.color ?: "#ffffff")
OPACITY_KEY to (item.opacity ?: 1.0)
}
val dMeta: dynamic = metaToEdit.toDynamic()
val options: JSONEditorOptions = jsObject {
mode = "form"
onChangeJSON = { item.config.update(DynamicMeta(it.asDynamic())) }
}
JSONEditor(div(), options, dMeta)
}
val styles = item.styles
if (styles.isNotEmpty()) {
card("Styles") {
item.styles.forEach { style ->
val styleMeta = item.findStyle(style)
h4("container") { +style.toString() }
if (styleMeta != null) {
div("container").apply {
val options: JSONEditorOptions = jsObject {
mode = "view"
}
JSONEditor(this, options, styleMeta.toDynamic())
}
}
}
}
}
}
}
}

View File

@ -4,6 +4,7 @@ import hep.dataforge.meta.*
import hep.dataforge.values.ValueType import hep.dataforge.values.ValueType
import hep.dataforge.vis.common.Colors import hep.dataforge.vis.common.Colors
import hep.dataforge.vis.spatial.Material3D import hep.dataforge.vis.spatial.Material3D
import info.laht.threekt.materials.LineBasicMaterial
import info.laht.threekt.materials.Material import info.laht.threekt.materials.Material
import info.laht.threekt.materials.MeshBasicMaterial import info.laht.threekt.materials.MeshBasicMaterial
import info.laht.threekt.materials.MeshPhongMaterial import info.laht.threekt.materials.MeshPhongMaterial
@ -13,8 +14,37 @@ import info.laht.threekt.math.Color
object Materials { object Materials {
val DEFAULT_COLOR = Color(Colors.darkgreen) val DEFAULT_COLOR = Color(Colors.darkgreen)
val DEFAULT = MeshPhongMaterial().apply { val DEFAULT = MeshPhongMaterial().apply {
this.color.set(DEFAULT_COLOR) color.set(DEFAULT_COLOR)
} }
val DEFAULT_LINE_COLOR = Color(Colors.black)
val DEFAULT_LINE = LineBasicMaterial().apply {
color.set(DEFAULT_LINE_COLOR)
}
private val materialCache = HashMap<Meta, Material>()
private val lineMaterialCache = HashMap<Meta, Material>()
fun getMaterial(meta: Meta): Material = materialCache.getOrPut(meta) {
MeshBasicMaterial().apply {
color = meta["color"]?.color() ?: DEFAULT_COLOR
opacity = meta["opacity"]?.double ?: 1.0
transparent = meta["transparent"].boolean ?: (opacity < 1.0)
//node["specularColor"]?.let { specular = it.color() }
//side = 2
}
}
fun getLineMaterial(meta: Meta): Material = lineMaterialCache.getOrPut(meta) {
LineBasicMaterial().apply {
color = meta["color"]?.color() ?: DEFAULT_LINE_COLOR
opacity = meta["opacity"].double ?: 1.0
transparent = meta["transparent"].boolean ?: (opacity < 1.0)
linewidth = meta["thickness"].double ?: 1.0
}
}
} }
/** /**
@ -41,26 +71,26 @@ fun MetaItem<*>.color(): Color {
} }
} }
private val materialCache = HashMap<Meta, Material>()
/** /**
* Infer Three material based on meta item * Infer Three material based on meta item
*/ */
fun Meta?.jsMaterial(): Material { fun Meta?.jsMaterial(): Material {
return if (this == null) { return if (this == null) {
Materials.DEFAULT Materials.DEFAULT
} else } else {
//TODO add more options for material Materials.getMaterial(this)
return materialCache.getOrPut(this) {
MeshBasicMaterial().apply {
color = get("color")?.color() ?: Materials.DEFAULT_COLOR
opacity = get("opacity")?.double ?: 1.0
transparent = get("transparent").boolean ?: (opacity < 1.0)
//node["specularColor"]?.let { specular = it.color() }
//side = 2
} }
} }
fun Meta?.jsLineMaterial(): Material {
return if (this == null) {
Materials.DEFAULT_LINE
} else{
Materials.getLineMaterial(this)
} }
}
fun Material3D?.jsMaterial(): Material = this?.config.jsMaterial() fun Material3D?.jsMaterial(): Material = this?.config.jsMaterial()
fun Material3D?.jsLineMaterial(): Material = this?.config.jsLineMaterial()

View File

@ -0,0 +1,99 @@
package hep.dataforge.vis.spatial.three
import hep.dataforge.meta.boolean
import hep.dataforge.meta.node
import hep.dataforge.names.asName
import hep.dataforge.names.plus
import hep.dataforge.names.startsWith
import hep.dataforge.vis.spatial.Material3D
import hep.dataforge.vis.spatial.VisualObject3D
import hep.dataforge.vis.spatial.layer
import hep.dataforge.vis.spatial.material
import info.laht.threekt.core.BufferGeometry
import info.laht.threekt.geometries.EdgesGeometry
import info.laht.threekt.geometries.WireframeGeometry
import info.laht.threekt.objects.LineSegments
import info.laht.threekt.objects.Mesh
import kotlin.reflect.KClass
/**
* Basic geometry-based factory
*/
abstract class MeshThreeFactory<T : VisualObject3D>(
override val type: KClass<out T>
) : ThreeFactory<T> {
/**
* Build a geometry for an object
*/
abstract fun buildGeometry(obj: T): BufferGeometry
private fun Mesh.applyEdges(obj: T) {
children.find { it.name == "edges" }?.let { remove(it) }
//inherited edges definition, enabled by default
if (obj.getProperty(EDGES_ENABLED_KEY).boolean != false) {
val material = obj.getProperty(EDGES_MATERIAL_KEY).node.jsLineMaterial()
add(
LineSegments(
EdgesGeometry(geometry as BufferGeometry),
material
)
)
}
}
private fun Mesh.applyWireFrame(obj: T) {
children.find { it.name == "wireframe" }?.let { remove(it) }
//inherited wireframe definition, disabled by default
if (obj.getProperty(WIREFRAME_ENABLED_KEY).boolean == true) {
val material = obj.getProperty(WIREFRAME_MATERIAL_KEY).node.jsLineMaterial()
add(
LineSegments(
WireframeGeometry(geometry as BufferGeometry),
material
)
)
}
}
override fun invoke(obj: T): Mesh {
//TODO add caching for geometries using templates
val geometry = buildGeometry(obj)
//JS sometimes tries to pass Geometry as BufferGeometry
@Suppress("USELESS_IS_CHECK") if (geometry !is BufferGeometry) error("BufferGeometry expected")
val mesh = Mesh(geometry, obj.material.jsMaterial()).apply {
matrixAutoUpdate = false
applyEdges(obj)
applyWireFrame(obj)
//set position for mesh
updatePosition(obj)
layers.enable(obj.layer)
children.forEach {
it.layers.enable(obj.layer)
}
}
//add listener to object properties
obj.onPropertyChange(this) { name, _, _ ->
when {
name.startsWith(VisualObject3D.GEOMETRY_KEY) -> mesh.geometry = buildGeometry(obj)
name.startsWith(WIREFRAME_KEY) -> mesh.applyWireFrame(obj)
name.startsWith(EDGES_KEY) -> mesh.applyEdges(obj)
else -> mesh.updateProperty(obj, name)
}
}
return mesh
}
companion object {
val EDGES_KEY = "edges".asName()
val WIREFRAME_KEY = "wireframe".asName()
val ENABLED_KEY = "enabled".asName()
val EDGES_ENABLED_KEY = EDGES_KEY + ENABLED_KEY
val EDGES_MATERIAL_KEY = EDGES_KEY + Material3D.MATERIAL_KEY
val WIREFRAME_ENABLED_KEY = WIREFRAME_KEY + ENABLED_KEY
val WIREFRAME_MATERIAL_KEY = WIREFRAME_KEY + Material3D.MATERIAL_KEY
}
}

View File

@ -1,22 +1,14 @@
package hep.dataforge.vis.spatial.three package hep.dataforge.vis.spatial.three
import hep.dataforge.meta.boolean
import hep.dataforge.meta.node
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.asName
import hep.dataforge.names.plus
import hep.dataforge.names.startsWith import hep.dataforge.names.startsWith
import hep.dataforge.provider.Type import hep.dataforge.provider.Type
import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.common.VisualObject
import hep.dataforge.vis.spatial.* import hep.dataforge.vis.spatial.*
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_KEY import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_KEY
import hep.dataforge.vis.spatial.VisualObject3D.Companion.GEOMETRY_KEY
import hep.dataforge.vis.spatial.three.ThreeFactory.Companion.TYPE import hep.dataforge.vis.spatial.three.ThreeFactory.Companion.TYPE
import info.laht.threekt.core.BufferGeometry import info.laht.threekt.core.BufferGeometry
import info.laht.threekt.core.Object3D import info.laht.threekt.core.Object3D
import info.laht.threekt.geometries.EdgesGeometry
import info.laht.threekt.geometries.WireframeGeometry
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
@ -46,30 +38,6 @@ internal fun Object3D.updatePosition(obj: VisualObject3D) {
updateMatrix() updateMatrix()
} }
internal fun <T : VisualObject3D> Mesh.updateFrom(obj: T) {
matrixAutoUpdate = false
//inherited edges definition, enabled by default
if (obj.getProperty(MeshThreeFactory.EDGES_ENABLED_KEY).boolean != false) {
val material = obj.getProperty(MeshThreeFactory.EDGES_MATERIAL_KEY).node?.jsMaterial() ?: Materials.DEFAULT
add(LineSegments(EdgesGeometry(geometry as BufferGeometry), material))
}
//inherited wireframe definition, disabled by default
if (obj.getProperty(MeshThreeFactory.WIREFRAME_ENABLED_KEY).boolean == true) {
val material = obj.getProperty(MeshThreeFactory.WIREFRAME_MATERIAL_KEY).node?.jsMaterial() ?: Materials.DEFAULT
add(LineSegments(WireframeGeometry(geometry as BufferGeometry), material))
}
//set position for mesh
updatePosition(obj)
layers.enable(obj.layer)
children.forEach {
it.layers.enable(obj.layer)
}
}
/** /**
* Unsafe invocation of a factory * Unsafe invocation of a factory
*/ */
@ -82,53 +50,6 @@ operator fun <T : VisualObject3D> ThreeFactory<T>.invoke(obj: Any): Object3D {
} }
} }
/**
* Basic geometry-based factory
*/
abstract class MeshThreeFactory<T : VisualObject3D>(override val type: KClass<out T>) : ThreeFactory<T> {
/**
* Build a geometry for an object
*/
abstract fun buildGeometry(obj: T): BufferGeometry
override fun invoke(obj: T): Mesh {
//create mesh from geometry
return buildMesh(obj) { buildGeometry(it) }
}
companion object {
val EDGES_KEY = "edges".asName()
val WIREFRAME_KEY = "wireframe".asName()
val ENABLED_KEY = "enabled".asName()
val EDGES_ENABLED_KEY = EDGES_KEY + ENABLED_KEY
val EDGES_MATERIAL_KEY = EDGES_KEY + MATERIAL_KEY
val WIREFRAME_ENABLED_KEY = WIREFRAME_KEY + ENABLED_KEY
val WIREFRAME_MATERIAL_KEY = WIREFRAME_KEY + MATERIAL_KEY
fun <T : VisualObject3D> buildMesh(obj: T, geometryBuilder: (T) -> BufferGeometry): Mesh {
//TODO add caching for geometries using templates
val geometry = geometryBuilder(obj)
//JS sometimes tries to pass Geometry as BufferGeometry
@Suppress("USELESS_IS_CHECK") if (geometry !is BufferGeometry) error("BufferGeometry expected")
val mesh = Mesh(geometry, obj.material.jsMaterial())
mesh.updateFrom(obj)
//add listener to object properties
obj.onPropertyChange(this) { name, _, _ ->
mesh.updateProperty(obj, name)
if (name.startsWith(GEOMETRY_KEY)) {
mesh.geometry = geometryBuilder(obj)
}
}
return mesh
}
}
}
fun Object3D.updateProperty(source: VisualObject, propertyName: Name) { fun Object3D.updateProperty(source: VisualObject, propertyName: Name) {
if (this is Mesh && propertyName.startsWith(MATERIAL_KEY)) { if (this is Mesh && propertyName.startsWith(MATERIAL_KEY)) {
//updated material //updated material

View File

@ -0,0 +1,32 @@
package hep.dataforge.vis.spatial.three
import hep.dataforge.vis.spatial.PolyLine
import hep.dataforge.vis.spatial.layer
import hep.dataforge.vis.spatial.material
import info.laht.threekt.core.Geometry
import info.laht.threekt.core.Object3D
import info.laht.threekt.objects.LineSegments
import kotlin.reflect.KClass
object ThreeLineFactory : ThreeFactory<PolyLine> {
override val type: KClass<out PolyLine> get() = PolyLine::class
override fun invoke(obj: PolyLine): Object3D {
val geometry = Geometry().apply {
vertices = obj.points.toTypedArray()
}
val material = obj.material.jsLineMaterial()
return LineSegments(geometry, material).apply {
updatePosition(obj)
layers.enable(obj.layer)
//add listener to object properties
obj.onPropertyChange(this) { propertyName, _, _ ->
updateProperty(obj, propertyName)
}
}
}
}

View File

@ -33,6 +33,7 @@ class ThreePlugin : AbstractPlugin() {
objectFactories[Convex::class] = ThreeConvexFactory objectFactories[Convex::class] = ThreeConvexFactory
objectFactories[Sphere::class] = ThreeSphereFactory objectFactories[Sphere::class] = ThreeSphereFactory
objectFactories[ConeSegment::class] = ThreeCylinderFactory objectFactories[ConeSegment::class] = ThreeCylinderFactory
objectFactories[PolyLine::class] = ThreeLineFactory
} }
private fun findObjectFactory(type: KClass<out VisualObject3D>): ThreeFactory<*>? { private fun findObjectFactory(type: KClass<out VisualObject3D>): ThreeFactory<*>? {
@ -46,7 +47,7 @@ class ThreePlugin : AbstractPlugin() {
is VisualGroup3D -> { is VisualGroup3D -> {
val group = ThreeGroup() val group = ThreeGroup()
obj.children.forEach { (name, child) -> obj.children.forEach { (name, child) ->
if (child is VisualObject3D) { if (child is VisualObject3D && child.ignore != true) {
try { try {
val object3D = buildObject3D(child) val object3D = buildObject3D(child)
object3D.name = name.toString() object3D.name = name.toString()

View File

@ -1,98 +0,0 @@
package hep.dataforge.vis.spatial.tree
import hep.dataforge.io.toJson
import hep.dataforge.meta.DynamicMeta
import hep.dataforge.meta.builder
import hep.dataforge.meta.update
import hep.dataforge.vis.common.VisualObject
import hep.dataforge.vis.spatial.Material3D.Companion.COLOR_KEY
import hep.dataforge.vis.spatial.Material3D.Companion.OPACITY_KEY
import hep.dataforge.vis.spatial.VisualObject3D.Companion.VISIBLE_KEY
import hep.dataforge.vis.spatial.color
import hep.dataforge.vis.spatial.opacity
import hep.dataforge.vis.spatial.prototype
import hep.dataforge.vis.spatial.visible
import kotlinx.html.InputType
import kotlinx.html.dom.append
import kotlinx.html.js.*
import org.w3c.dom.Element
import kotlin.dom.clear
fun Element.propertyEditor(item: VisualObject?, name: String?) {
clear()
if (item != null) {
append {
div("card") {
div("card-body") {
h3(classes = "card-title") {
+(name ?: "")
}
form {
div("form-group row") {
label("col-form-label col-4") {
+"Color: "
}
input(InputType.color, classes = "form-control col-8") {
value = item.color ?: "#ffffff"
}.apply {
onInputFunction = {
item.color = value
}
}
}
div("form-group row") {
label("col-form-label col-4") {
+"Opacity: "
}
input(InputType.range, classes = "form-control col-8") {
min = "0.0"
max = "1.0"
step = "0.1"
value = item.opacity.toString()
}.apply {
onInputFunction = {
item.opacity = value.toDouble()
}
}
}
div("form-group row") {
label("col-form-label col-4") { +"Visible: " }
div("col-8") {
div("form-check") {
input(InputType.checkBox, classes = "form-check-input").apply {
this.checked = item.visible ?: true
onInputFunction = {
item.visible = checked
}
}
}
}
}
}
}
}
(item.properties ?: item.prototype?.properties)?.let { config ->
div("card") {
div("card-body") {
h3(classes = "card-title") { +"Properties" }
}.apply {
val metaToEdit = config.builder().apply {
VISIBLE_KEY to (item.visible ?: true)
COLOR_KEY to (item.color ?: "#ffffff")
OPACITY_KEY to (item.opacity ?: 1.0)
}
//FIXME something rotten in JS-Meta converter
val jsObject: dynamic = JSON.parse(metaToEdit.toJson().toString())
//jsObject.material.color != null
val options = (js("{}") as JSONEditorOptions).apply {
mode = "form"
onChangeJSON = { item.config.update(DynamicMeta(it.asDynamic())) }
}
JSONEditor(this, options, jsObject)
}
}
}
}
}
}

View File

@ -28,7 +28,10 @@
package info.laht.threekt.objects package info.laht.threekt.objects
import info.laht.threekt.core.BufferGeometry import info.laht.threekt.core.BufferGeometry
import info.laht.threekt.core.Geometry
import info.laht.threekt.core.Object3D import info.laht.threekt.core.Object3D
import info.laht.threekt.materials.Material import info.laht.threekt.materials.Material
open external class LineSegments(geometry: BufferGeometry, material: Material) : Object3D open external class LineSegments(geometry: BufferGeometry, material: Material) : Object3D {
constructor(geometry: Geometry, material: Material)
}

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.5-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

4
gradlew vendored
View File

@ -125,8 +125,8 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi fi
# For Cygwin, switch paths to Windows format before running java # For Cygwin or MSYS, switch paths to Windows format before running java
if $cygwin ; then if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"` APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"` JAVACMD=`cygpath --unix "$JAVACMD"`

View File

@ -5,6 +5,7 @@ pluginManagement {
gradlePluginPortal() gradlePluginPortal()
maven("https://kotlin.bintray.com/kotlinx") maven("https://kotlin.bintray.com/kotlinx")
maven("https://dl.bintray.com/kotlin/kotlin-eap") maven("https://dl.bintray.com/kotlin/kotlin-eap")
maven("https://dl.bintray.com/mipt-npm/dataforge")
maven("https://dl.bintray.com/mipt-npm/scientifik") maven("https://dl.bintray.com/mipt-npm/scientifik")
maven("https://dl.bintray.com/mipt-npm/dev") maven("https://dl.bintray.com/mipt-npm/dev")
} }
@ -17,7 +18,6 @@ pluginManagement {
"org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${requested.version}") "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${requested.version}")
"org.jetbrains.kotlin.js" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${requested.version}") "org.jetbrains.kotlin.js" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${requested.version}")
"kotlin-dce-js" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${requested.version}") "kotlin-dce-js" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${requested.version}")
"kotlin2js" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${requested.version}")
"org.jetbrains.kotlin.frontend" -> useModule("org.jetbrains.kotlin:kotlin-frontend-plugin:${requested.version}") "org.jetbrains.kotlin.frontend" -> useModule("org.jetbrains.kotlin:kotlin-frontend-plugin:${requested.version}")
"scientifik.mpp", "scientifik.publish", "scientifik.jvm", "scientifik.js" -> useModule("scientifik:gradle-tools:${requested.version}") "scientifik.mpp", "scientifik.publish", "scientifik.jvm", "scientifik.js" -> useModule("scientifik:gradle-tools:${requested.version}")
"org.openjfx.javafxplugin" -> useModule("org.openjfx:javafx-plugin:${requested.version}") "org.openjfx.javafxplugin" -> useModule("org.openjfx:javafx-plugin:${requested.version}")
@ -32,6 +32,7 @@ rootProject.name = "dataforge-vis"
include( include(
":dataforge-vis-common", ":dataforge-vis-common",
":wrappers",
":dataforge-vis-fx", ":dataforge-vis-fx",
":dataforge-vis-spatial", ":dataforge-vis-spatial",
":dataforge-vis-spatial-gdml", ":dataforge-vis-spatial-gdml",

View File

@ -1,10 +1,10 @@
package hep.dataforge.vis.spatial.demo package hep.dataforge.vis.spatial.demo
import hep.dataforge.context.ContextBuilder import hep.dataforge.context.ContextBuilder
import hep.dataforge.vis.ApplicationBase
import hep.dataforge.vis.common.Colors import hep.dataforge.vis.common.Colors
import hep.dataforge.vis.hmr.ApplicationBase
import hep.dataforge.vis.hmr.startApplication
import hep.dataforge.vis.spatial.* import hep.dataforge.vis.spatial.*
import hep.dataforge.vis.startApplication
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
@ -130,6 +130,21 @@ private class ThreeDemoApp : ApplicationBase() {
} }
} }
} }
demo("lines", "Track / line segments") {
sphere(100) {
color(Colors.blue)
detail = 50
opacity = 0.4
}
repeat(20) {
polyline(Point3D(100, 100, 100), Point3D(-100, -100, -100)) {
thickness = 208.0
rotationX = it * PI2 / 20
color(Colors.green)
//rotationY = it * PI2 / 20
}
}
}
} }

23
wrappers/build.gradle.kts Normal file
View File

@ -0,0 +1,23 @@
plugins {
id("scientifik.js")
//id("kotlin-dce-js")
}
dependencies {
api(project(":dataforge-vis-common"))
testCompile(kotlin("test-js"))
}
kotlin{
sourceSets["main"].apply{
dependencies{
api(npm("style-loader"))
api(npm("inspire-tree","6.0.1"))
api(npm("inspire-tree-dom","4.0.6"))
api(npm("jsoneditor"))
api(npm("dat.gui"))
//api("org.jetbrains:kotlin-extensions:1.0.1-pre.83-kotlin-1.3.50")
}
}
}

View File

@ -0,0 +1,102 @@
@file:Suppress(
"INTERFACE_WITH_SUPERCLASS",
"OVERRIDING_FINAL_MEMBER",
"RETURN_TYPE_MISMATCH_ON_OVERRIDE",
"CONFLICTING_OVERLOADS",
"EXTERNAL_DELEGATION"
)
@file:JsModule("dat.gui")
@file:JsNonModule
package hep.dataforge.vis.spatial.editor
import org.w3c.dom.HTMLElement
external interface GUIParams {
var autoPlace: Boolean? get() = definedExternally; set(value) = definedExternally
var closed: Boolean? get() = definedExternally; set(value) = definedExternally
var closeOnTop: Boolean? get() = definedExternally; set(value) = definedExternally
var hideable: Boolean? get() = definedExternally; set(value) = definedExternally
var load: Any? get() = definedExternally; set(value) = definedExternally
var name: String? get() = definedExternally; set(value) = definedExternally
var preset: String? get() = definedExternally; set(value) = definedExternally
var width: Number? get() = definedExternally; set(value) = definedExternally
}
external open class GUI(option: GUIParams? = definedExternally /* null */) {
open var __controllers: Array<GUIController>
open var __folders: Array<GUI>
open var domElement: HTMLElement
open fun add(
target: Any,
propName: String,
min: Number? = definedExternally /* null */,
max: Number? = definedExternally /* null */,
step: Number? = definedExternally /* null */
): GUIController
open fun add(target: Any, propName: String, status: Boolean): GUIController
open fun add(target: Any, propName: String, items: Array<String>): GUIController
open fun add(target: Any, propName: String, items: Array<Number>): GUIController
open fun add(target: Any, propName: String, items: Any): GUIController
open fun addColor(target: Any, propName: String): GUIController
open fun remove(controller: GUIController)
open fun destroy()
open fun addFolder(propName: String): GUI
open fun removeFolder(subFolder: GUI)
open fun open()
open fun close()
open fun hide()
open fun show()
open fun remember(target: Any, vararg additionalTargets: Any)
open fun getRoot(): GUI
open fun getSaveObject(): Any
open fun save()
open fun saveAs(presetName: String)
open fun revert(gui: GUI)
open fun listen(controller: GUIController)
open fun updateDisplay()
open var parent: GUI
open var scrollable: Boolean
open var autoPlace: Boolean
open var preset: String
open var width: Number
open var name: String
open var closed: Boolean
open var load: Any
open var useLocalStorage: Boolean
companion object {
var CLASS_AUTO_PLACE: String
var CLASS_AUTO_PLACE_CONTAINER: String
var CLASS_MAIN: String
var CLASS_CONTROLLER_ROW: String
var CLASS_TOO_TALL: String
var CLASS_CLOSED: String
var CLASS_CLOSE_BUTTON: String
var CLASS_CLOSE_TOP: String
var CLASS_CLOSE_BOTTOM: String
var CLASS_DRAG: String
var DEFAULT_WIDTH: Number
var TEXT_CLOSED: String
var TEXT_OPEN: String
}
}
external open class GUIController {
open fun destroy()
open var onChange: (value: Any? /* = null */) -> GUIController
open var onFinishChange: (value: Any? /* = null */) -> GUIController
open fun setValue(value: Any): GUIController
open fun getValue(): Any
open fun updateDisplay(): GUIController
open fun isModified(): Boolean
open fun min(n: Number): GUIController
open fun max(n: Number): GUIController
open fun step(n: Number): GUIController
open fun fire(): GUIController
open fun options(option: Any): GUIController
open fun name(s: String): GUIController
open fun listen(): GUIController
open fun remove(): GUIController
}

View File

@ -8,7 +8,7 @@
@file:JsModule("eventemitter2") @file:JsModule("eventemitter2")
@file: JsNonModule @file: JsNonModule
package hep.dataforge.vis.spatial.tree package hep.dataforge.vis.spatial.editor
import kotlin.js.Promise import kotlin.js.Promise

View File

@ -6,7 +6,7 @@
"EXTERNAL_DELEGATION" "EXTERNAL_DELEGATION"
) )
package hep.dataforge.vis.spatial.tree package hep.dataforge.vis.spatial.editor
import org.w3c.dom.HTMLElement import org.w3c.dom.HTMLElement

View File

@ -7,7 +7,7 @@
"unused" "unused"
) )
package hep.dataforge.vis.spatial.tree package hep.dataforge.vis.spatial.editor
import kotlin.js.Promise import kotlin.js.Promise
import kotlin.js.RegExp import kotlin.js.RegExp

View File

@ -6,7 +6,7 @@
"EXTERNAL_DELEGATION" "EXTERNAL_DELEGATION"
) )
package hep.dataforge.vis.spatial.tree package hep.dataforge.vis.spatial.editor
import org.w3c.dom.HTMLElement import org.w3c.dom.HTMLElement