Add multi-select value chooser for layers
This commit is contained in:
parent
2798439582
commit
faf3fa8512
@ -5,7 +5,6 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>Three js demo for particle physics</title>
|
<title>Three js demo for particle physics</title>
|
||||||
<script type="text/javascript" src="gdml.js"></script>
|
<script type="text/javascript" src="gdml.js"></script>
|
||||||
<link rel="stylesheet" href="css/custom-bootstrap.css">
|
|
||||||
<link rel="stylesheet" href="css/fileDrop.css">
|
<link rel="stylesheet" href="css/fileDrop.css">
|
||||||
</head>
|
</head>
|
||||||
<body class="application">
|
<body class="application">
|
||||||
|
@ -2,7 +2,7 @@ package space.kscience.visionforge.examples
|
|||||||
|
|
||||||
import space.kscience.dataforge.context.Context
|
import space.kscience.dataforge.context.Context
|
||||||
import space.kscience.gdml.*
|
import space.kscience.gdml.*
|
||||||
import space.kscience.visionforge.gdml.gdml
|
import space.kscience.visionforge.gdml.toVision
|
||||||
import space.kscience.visionforge.solid.Solids
|
import space.kscience.visionforge.solid.Solids
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
@ -12,7 +12,7 @@ fun main() {
|
|||||||
|
|
||||||
context.makeVisionFile {
|
context.makeVisionFile {
|
||||||
vision("canvas") {
|
vision("canvas") {
|
||||||
gdml {
|
Gdml {
|
||||||
// geometry variables
|
// geometry variables
|
||||||
val worldSize = 500
|
val worldSize = 500
|
||||||
// chamber
|
// chamber
|
||||||
@ -220,6 +220,8 @@ fun main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}.toVision {
|
||||||
|
this.solidAction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,6 @@ fun main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
context.makeVisionFile {
|
context.makeVisionFile {
|
||||||
vision("canvas") {
|
vision("canvas") { GdmlShowCase.babyIaxo().toVision() }
|
||||||
GdmlShowCase.babyIaxo().toVision()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,10 +1,6 @@
|
|||||||
package space.kscience.visionforge.gdml.jupyter
|
package space.kscience.visionforge.gdml.jupyter
|
||||||
|
|
||||||
import kotlinx.html.div
|
|
||||||
import kotlinx.html.id
|
|
||||||
import kotlinx.html.script
|
|
||||||
import kotlinx.html.stream.createHTML
|
import kotlinx.html.stream.createHTML
|
||||||
import kotlinx.html.unsafe
|
|
||||||
import org.jetbrains.kotlinx.jupyter.api.HTML
|
import org.jetbrains.kotlinx.jupyter.api.HTML
|
||||||
import org.jetbrains.kotlinx.jupyter.api.annotations.JupyterLibrary
|
import org.jetbrains.kotlinx.jupyter.api.annotations.JupyterLibrary
|
||||||
import org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration
|
import org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration
|
||||||
@ -16,7 +12,7 @@ import space.kscience.visionforge.Vision
|
|||||||
import space.kscience.visionforge.gdml.toVision
|
import space.kscience.visionforge.gdml.toVision
|
||||||
import space.kscience.visionforge.html.HtmlVisionFragment
|
import space.kscience.visionforge.html.HtmlVisionFragment
|
||||||
import space.kscience.visionforge.html.Page
|
import space.kscience.visionforge.html.Page
|
||||||
import space.kscience.visionforge.html.embedVisionFragment
|
import space.kscience.visionforge.html.embedAndRenderVisionFragment
|
||||||
import space.kscience.visionforge.solid.Solids
|
import space.kscience.visionforge.solid.Solids
|
||||||
import space.kscience.visionforge.visionManager
|
import space.kscience.visionforge.visionManager
|
||||||
|
|
||||||
@ -30,17 +26,9 @@ internal class GdmlForJupyter : JupyterIntegration() {
|
|||||||
|
|
||||||
private var counter = 0
|
private var counter = 0
|
||||||
|
|
||||||
private fun produceHtmlVisionString(fragment: HtmlVisionFragment) = createHTML().div {
|
private fun produceHtmlVisionString(fragment: HtmlVisionFragment) = createHTML().apply {
|
||||||
val id = "visionforge.vision[${counter++}]"
|
embedAndRenderVisionFragment(context.visionManager, counter++, fragment)
|
||||||
div {
|
}.finalize()
|
||||||
this.id = id
|
|
||||||
embedVisionFragment(context.visionManager, fragment = fragment)
|
|
||||||
}
|
|
||||||
script {
|
|
||||||
type = "text/javascript"
|
|
||||||
unsafe { +"VisionForge.renderVisionsAt(\"$id\");" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun Builder.onLoaded() {
|
override fun Builder.onLoaded() {
|
||||||
|
|
||||||
@ -62,19 +50,12 @@ internal class GdmlForJupyter : JupyterIntegration() {
|
|||||||
"space.kscience.visionforge.gdml.jupyter.*"
|
"space.kscience.visionforge.gdml.jupyter.*"
|
||||||
)
|
)
|
||||||
|
|
||||||
render<Gdml> { gdmlModel ->
|
|
||||||
val fragment = HtmlVisionFragment {
|
|
||||||
vision(gdmlModel.toVision())
|
|
||||||
}
|
|
||||||
HTML(produceHtmlVisionString(fragment))
|
|
||||||
}
|
|
||||||
|
|
||||||
render<Vision> { vision ->
|
render<Vision> { vision ->
|
||||||
val fragment = HtmlVisionFragment {
|
HTML(produceHtmlVisionString { vision(vision) })
|
||||||
vision(vision)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HTML(produceHtmlVisionString(fragment))
|
render<Gdml> { gdmlModel ->
|
||||||
|
HTML(produceHtmlVisionString { vision(gdmlModel.toVision()) })
|
||||||
}
|
}
|
||||||
|
|
||||||
render<Page> { page ->
|
render<Page> { page ->
|
||||||
|
@ -8,5 +8,6 @@ dependencies{
|
|||||||
api(project(":visionforge-solid"))
|
api(project(":visionforge-solid"))
|
||||||
api("org.jetbrains:kotlin-styled:5.2.3-$kotlinWrappersVersion")
|
api("org.jetbrains:kotlin-styled:5.2.3-$kotlinWrappersVersion")
|
||||||
api("org.jetbrains:kotlin-react-dom:17.0.2-$kotlinWrappersVersion")
|
api("org.jetbrains:kotlin-react-dom:17.0.2-$kotlinWrappersVersion")
|
||||||
|
// implementation(npm("react-select","4.3.0"))
|
||||||
implementation(project(":visionforge-threejs"))
|
implementation(project(":visionforge-threejs"))
|
||||||
}
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package space.kscience.visionforge.react
|
||||||
|
|
||||||
|
import kotlinx.html.js.onChangeFunction
|
||||||
|
import org.w3c.dom.HTMLOptionElement
|
||||||
|
import org.w3c.dom.HTMLSelectElement
|
||||||
|
import org.w3c.dom.asList
|
||||||
|
import org.w3c.dom.events.Event
|
||||||
|
import react.FunctionalComponent
|
||||||
|
import react.dom.option
|
||||||
|
import react.dom.select
|
||||||
|
import react.functionalComponent
|
||||||
|
import react.useState
|
||||||
|
import space.kscience.dataforge.meta.value
|
||||||
|
import space.kscience.dataforge.values.asValue
|
||||||
|
import space.kscience.dataforge.values.string
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
public val MultiSelectChooser: FunctionalComponent<ValueChooserProps> =
|
||||||
|
functionalComponent("MultiSelectChooser") { props ->
|
||||||
|
var selectedItems by useState { props.item.value?.list ?: emptyList() }
|
||||||
|
|
||||||
|
val onChange: (Event) -> Unit = { event: Event ->
|
||||||
|
val newSelected= (event.target as HTMLSelectElement).selectedOptions.asList()
|
||||||
|
.map { (it as HTMLOptionElement).value.asValue() }
|
||||||
|
props.valueChanged?.invoke(newSelected.asValue())
|
||||||
|
selectedItems = newSelected
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
attrs {
|
||||||
|
multiple = true
|
||||||
|
values = selectedItems.mapTo(HashSet()) { it.string }
|
||||||
|
onChangeFunction = onChange
|
||||||
|
}
|
||||||
|
props.descriptor?.allowedValues?.forEach { optionValue ->
|
||||||
|
option {
|
||||||
|
+optionValue.string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -152,6 +152,7 @@ public val ValueChooser: FunctionalComponent<ValueChooserProps> = functionalComp
|
|||||||
when {
|
when {
|
||||||
rawInput -> child(StringValueChooser, props)
|
rawInput -> child(StringValueChooser, props)
|
||||||
descriptor?.widgetType == "color" -> child(ColorValueChooser, props)
|
descriptor?.widgetType == "color" -> child(ColorValueChooser, props)
|
||||||
|
descriptor?.widgetType == "multiSelect" -> child(MultiSelectChooser, props)
|
||||||
type == ValueType.BOOLEAN -> child(BooleanValueChooser, props)
|
type == ValueType.BOOLEAN -> child(BooleanValueChooser, props)
|
||||||
type == ValueType.NUMBER -> child(NumberValueChooser, props)
|
type == ValueType.NUMBER -> child(NumberValueChooser, props)
|
||||||
descriptor?.allowedValues?.isNotEmpty() ?: false -> child(ComboValueChooser, props)
|
descriptor?.allowedValues?.isNotEmpty() ?: false -> child(ComboValueChooser, props)
|
||||||
|
@ -2,7 +2,8 @@ package space.kscience.visionforge
|
|||||||
|
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.MetaBuilder
|
import space.kscience.dataforge.meta.MetaBuilder
|
||||||
import space.kscience.dataforge.misc.DFExperimental
|
import space.kscience.dataforge.meta.Scheme
|
||||||
|
import space.kscience.dataforge.meta.Specification
|
||||||
import kotlin.properties.ReadOnlyProperty
|
import kotlin.properties.ReadOnlyProperty
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -23,11 +24,23 @@ public fun Vision.useStyle(reference: StyleReference) {
|
|||||||
useStyle(reference.name)
|
useStyle(reference.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@DFExperimental
|
|
||||||
@VisionBuilder
|
@VisionBuilder
|
||||||
public fun VisionGroup.style(builder: MetaBuilder.() -> Unit): ReadOnlyProperty<Any?, StyleReference> =
|
public fun VisionGroup.style(
|
||||||
ReadOnlyProperty { _, property ->
|
styleKey: String? = null,
|
||||||
val styleName = property.name
|
builder: MetaBuilder.() -> Unit,
|
||||||
|
): ReadOnlyProperty<Any?, StyleReference> = ReadOnlyProperty { _, property ->
|
||||||
|
val styleName = styleKey ?: property.name
|
||||||
styleSheet.define(styleName, Meta(builder))
|
styleSheet.define(styleName, Meta(builder))
|
||||||
StyleReference(this, styleName)
|
StyleReference(this, styleName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisionBuilder
|
||||||
|
public fun <T : Scheme> VisionGroup.style(
|
||||||
|
spec: Specification<T>,
|
||||||
|
styleKey: String? = null,
|
||||||
|
builder: T.() -> Unit,
|
||||||
|
): ReadOnlyProperty<Any?, StyleReference> = ReadOnlyProperty { _, property ->
|
||||||
|
val styleName = styleKey ?: property.name
|
||||||
|
styleSheet.define(styleName, spec(builder).toMeta())
|
||||||
|
StyleReference(this, styleName)
|
||||||
|
}
|
@ -2,6 +2,7 @@ package space.kscience.visionforge.html
|
|||||||
|
|
||||||
import kotlinx.html.*
|
import kotlinx.html.*
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
import space.kscience.dataforge.misc.DFExperimental
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.VisionManager
|
import space.kscience.visionforge.VisionManager
|
||||||
@ -35,20 +36,19 @@ public fun FlowContent.embedVisionFragment(
|
|||||||
fragment: HtmlVisionFragment,
|
fragment: HtmlVisionFragment,
|
||||||
): Map<Name, Vision> = consumer.embedVisionFragment(manager, idPrefix, fragment)
|
): Map<Name, Vision> = consumer.embedVisionFragment(manager, idPrefix, fragment)
|
||||||
|
|
||||||
public typealias HtmlVisionRenderer = FlowContent.(name: Name, vision: Vision, meta: Meta) -> Unit
|
|
||||||
|
|
||||||
public fun FlowContent.renderVisionFragment(
|
internal const val RENDER_FUNCTION_NAME = "renderAllVisionsById"
|
||||||
renderer: DIV.(name: Name, vision: Vision, meta: Meta) -> Unit,
|
|
||||||
idPrefix: String? = null,
|
@DFExperimental
|
||||||
fragment: HtmlVisionFragment,
|
public fun TagConsumer<*>.embedAndRenderVisionFragment(manager: VisionManager, id: Any, fragment: HtmlVisionFragment){
|
||||||
): Map<Name, Vision> {
|
div {
|
||||||
val visionMap = HashMap<Name, Vision>()
|
div {
|
||||||
val consumer = object : VisionTagConsumer<Any?>(consumer, idPrefix) {
|
this.id = id.toString()
|
||||||
override fun DIV.renderVision(name: Name, vision: Vision, outputMeta: Meta) {
|
embedVisionFragment(manager, fragment = fragment)
|
||||||
visionMap[name] = vision
|
}
|
||||||
renderer(name, vision, outputMeta)
|
script {
|
||||||
|
type = "text/javascript"
|
||||||
|
unsafe { +"window.${RENDER_FUNCTION_NAME}(\"$id\");" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fragment(consumer)
|
|
||||||
return visionMap
|
|
||||||
}
|
}
|
@ -66,7 +66,9 @@ public abstract class VisionTagConsumer<R>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vision?.let { renderVision(name, it, outputMeta) }
|
vision?.let {
|
||||||
|
renderVision(name, it, outputMeta)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(DFExperimental::class)
|
@OptIn(DFExperimental::class)
|
||||||
|
@ -4,7 +4,7 @@ import space.kscience.dataforge.meta.Scheme
|
|||||||
import space.kscience.dataforge.meta.SchemeSpec
|
import space.kscience.dataforge.meta.SchemeSpec
|
||||||
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
|
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
|
||||||
import space.kscience.dataforge.meta.descriptors.NodeDescriptorBuilder
|
import space.kscience.dataforge.meta.descriptors.NodeDescriptorBuilder
|
||||||
import space.kscience.dataforge.meta.descriptors.ValueDescriptor
|
import space.kscience.dataforge.meta.descriptors.ValueDescriptorBuilder
|
||||||
import space.kscience.dataforge.meta.toConfig
|
import space.kscience.dataforge.meta.toConfig
|
||||||
import space.kscience.dataforge.values.ValueType
|
import space.kscience.dataforge.values.ValueType
|
||||||
import kotlin.reflect.KProperty1
|
import kotlin.reflect.KProperty1
|
||||||
@ -15,7 +15,7 @@ import kotlin.reflect.typeOf
|
|||||||
*/
|
*/
|
||||||
public inline fun <S : Scheme, reified T> NodeDescriptorBuilder.value(
|
public inline fun <S : Scheme, reified T> NodeDescriptorBuilder.value(
|
||||||
property: KProperty1<S, T>,
|
property: KProperty1<S, T>,
|
||||||
noinline block: ValueDescriptor.() -> Unit = {},
|
noinline block: ValueDescriptorBuilder.() -> Unit = {},
|
||||||
) {
|
) {
|
||||||
when (typeOf<T>()) {
|
when (typeOf<T>()) {
|
||||||
typeOf<Number>(), typeOf<Int>(), typeOf<Double>(), typeOf<Short>(), typeOf<Long>(), typeOf<Float>() ->
|
typeOf<Number>(), typeOf<Int>(), typeOf<Double>(), typeOf<Short>(), typeOf<Long>(), typeOf<Float>() ->
|
||||||
@ -54,7 +54,7 @@ public fun NodeDescriptor.copy(block: NodeDescriptorBuilder.() -> Unit = {}): No
|
|||||||
public inline fun <S : Scheme, reified T : Scheme> NodeDescriptorBuilder.scheme(
|
public inline fun <S : Scheme, reified T : Scheme> NodeDescriptorBuilder.scheme(
|
||||||
property: KProperty1<S, T>,
|
property: KProperty1<S, T>,
|
||||||
spec: SchemeSpec<T>,
|
spec: SchemeSpec<T>,
|
||||||
noinline block: NodeDescriptor.() -> Unit = {},
|
noinline block: NodeDescriptorBuilder.() -> Unit = {},
|
||||||
) {
|
) {
|
||||||
spec.descriptor?.let { descriptor ->
|
spec.descriptor?.let { descriptor ->
|
||||||
item(property.name, descriptor.copy(block))
|
item(property.name, descriptor.copy(block))
|
||||||
|
@ -2,13 +2,35 @@ package space.kscience.visionforge.html
|
|||||||
|
|
||||||
import kotlinx.html.*
|
import kotlinx.html.*
|
||||||
import kotlinx.html.stream.createHTML
|
import kotlinx.html.stream.createHTML
|
||||||
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.set
|
import space.kscience.dataforge.meta.set
|
||||||
import space.kscience.dataforge.misc.DFExperimental
|
import space.kscience.dataforge.misc.DFExperimental
|
||||||
|
import space.kscience.dataforge.names.Name
|
||||||
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.VisionBase
|
import space.kscience.visionforge.VisionBase
|
||||||
import space.kscience.visionforge.configure
|
import space.kscience.visionforge.configure
|
||||||
import space.kscience.visionforge.meta
|
import space.kscience.visionforge.meta
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
|
|
||||||
|
typealias HtmlVisionRenderer = FlowContent.(name: Name, vision: Vision, meta: Meta) -> Unit
|
||||||
|
|
||||||
|
fun FlowContent.renderVisionFragment(
|
||||||
|
renderer: DIV.(name: Name, vision: Vision, meta: Meta) -> Unit,
|
||||||
|
idPrefix: String? = null,
|
||||||
|
fragment: HtmlVisionFragment,
|
||||||
|
): Map<Name, Vision> {
|
||||||
|
val visionMap = HashMap<Name, Vision>()
|
||||||
|
val consumer = object : VisionTagConsumer<Any?>(consumer, idPrefix) {
|
||||||
|
override fun DIV.renderVision(name: Name, vision: Vision, outputMeta: Meta) {
|
||||||
|
visionMap[name] = vision
|
||||||
|
renderer(name, vision, outputMeta)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fragment(consumer)
|
||||||
|
return visionMap
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@DFExperimental
|
@DFExperimental
|
||||||
class HtmlTagTest {
|
class HtmlTagTest {
|
||||||
|
|
||||||
@ -46,10 +68,6 @@ class HtmlTagTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val groupRenderer: HtmlVisionRenderer = { _, _, _ ->
|
|
||||||
p { +"This is group" }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testStringRender() {
|
fun testStringRender() {
|
||||||
|
@ -7,6 +7,7 @@ import org.w3c.dom.url.URL
|
|||||||
import space.kscience.dataforge.context.*
|
import space.kscience.dataforge.context.*
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.MetaSerializer
|
import space.kscience.dataforge.meta.MetaSerializer
|
||||||
|
import space.kscience.visionforge.html.RENDER_FUNCTION_NAME
|
||||||
import space.kscience.visionforge.html.VisionTagConsumer
|
import space.kscience.visionforge.html.VisionTagConsumer
|
||||||
import space.kscience.visionforge.html.VisionTagConsumer.Companion.OUTPUT_CONNECT_ATTRIBUTE
|
import space.kscience.visionforge.html.VisionTagConsumer.Companion.OUTPUT_CONNECT_ATTRIBUTE
|
||||||
import space.kscience.visionforge.html.VisionTagConsumer.Companion.OUTPUT_ENDPOINT_ATTRIBUTE
|
import space.kscience.visionforge.html.VisionTagConsumer.Companion.OUTPUT_ENDPOINT_ATTRIBUTE
|
||||||
@ -221,7 +222,7 @@ public fun runVisionClient(contextBuilder: ContextBuilder.() -> Unit) {
|
|||||||
//plugin(VisionClient)
|
//plugin(VisionClient)
|
||||||
}
|
}
|
||||||
val visionClient = context.fetch(VisionClient)
|
val visionClient = context.fetch(VisionClient)
|
||||||
window.asDynamic()["renderAllVisionsById"] = visionClient::renderAllVisionsById
|
window.asDynamic()[RENDER_FUNCTION_NAME] = visionClient::renderAllVisionsById
|
||||||
|
|
||||||
visionClient.renderAllVisions()
|
visionClient.renderAllVisions()
|
||||||
}
|
}
|
@ -25,8 +25,7 @@ private inline operator fun Number.times(d: Double) = toDouble() * d
|
|||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
private inline operator fun Number.times(f: Float) = toFloat() * f
|
private inline operator fun Number.times(f: Float) = toFloat() * f
|
||||||
|
|
||||||
public class GdmlTransformerSettings {
|
public class GdmlTransformer {
|
||||||
public val random: Random = Random(222)
|
|
||||||
|
|
||||||
public enum class Action {
|
public enum class Action {
|
||||||
ADD,
|
ADD,
|
||||||
@ -40,12 +39,70 @@ public class GdmlTransformerSettings {
|
|||||||
public var solidAction: (GdmlSolid) -> Action = { Action.PROTOTYPE }
|
public var solidAction: (GdmlSolid) -> Action = { Action.PROTOTYPE }
|
||||||
public var volumeAction: (GdmlGroup) -> Action = { Action.PROTOTYPE }
|
public var volumeAction: (GdmlGroup) -> Action = { Action.PROTOTYPE }
|
||||||
|
|
||||||
public var paint: SolidMaterial.(material: GdmlMaterial) -> Unit = { _ ->
|
internal val styleCache = HashMap<Name, Meta>()
|
||||||
color(random.nextInt(16777216))
|
|
||||||
|
public fun Solid.useStyle(name: String, builder: MetaBuilder.() -> Unit) {
|
||||||
|
styleCache.getOrPut(name.toName()) {
|
||||||
|
Meta(builder)
|
||||||
|
}
|
||||||
|
useStyle(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun Solid.opaque() {
|
||||||
|
useStyle("opaque") {
|
||||||
|
SolidMaterial.MATERIAL_OPACITY_KEY put 0.3
|
||||||
|
"edges.enabled" put true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class GdmlTransformer(val settings: GdmlTransformerSettings) {
|
/**
|
||||||
|
* Configure paint for given solid with given [GdmlMaterial]
|
||||||
|
*/
|
||||||
|
public var configurePaint: SolidMaterial.(material: GdmlMaterial, solid: GdmlSolid) -> Unit =
|
||||||
|
{ material, _ -> color(randomColor(material)) }
|
||||||
|
private set
|
||||||
|
|
||||||
|
public fun paint(block: SolidMaterial.(material: GdmlMaterial, solid: GdmlSolid) -> Unit) {
|
||||||
|
configurePaint = block
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure given solid
|
||||||
|
*/
|
||||||
|
public var configureSolid: Solid.(parent: GdmlVolume, solid: GdmlSolid, material: GdmlMaterial) -> Unit =
|
||||||
|
{ parent, solid, material ->
|
||||||
|
val styleName = "materials.${material.name}"
|
||||||
|
|
||||||
|
if (parent.physVolumes.isNotEmpty()) opaque()
|
||||||
|
|
||||||
|
useStyle(styleName) {
|
||||||
|
val vfMaterial = SolidMaterial().apply {
|
||||||
|
configurePaint(material, solid)
|
||||||
|
}
|
||||||
|
MATERIAL_KEY put vfMaterial.toMeta()
|
||||||
|
"Gdml.material" put material.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private set
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
private val random: Random = Random(222)
|
||||||
|
|
||||||
|
private val colorCache = HashMap<GdmlMaterial, Int>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use random color and cache it based on the material. Meaning that colors are random, but always the same for the
|
||||||
|
* same material.
|
||||||
|
*/
|
||||||
|
public fun randomColor(material: GdmlMaterial): Int {
|
||||||
|
return colorCache.getOrPut(material) { random.nextInt(16777216) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class GdmlTransformerEnv(val settings: GdmlTransformer) {
|
||||||
//private val materialCache = HashMap<GdmlMaterial, Meta>()
|
//private val materialCache = HashMap<GdmlMaterial, Meta>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,9 +114,13 @@ private class GdmlTransformer(val settings: GdmlTransformerSettings) {
|
|||||||
setProperty("edges.enabled", false)
|
setProperty("edges.enabled", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private val referenceStore = HashMap<Name, MutableList<SolidReferenceGroup>>()
|
private val referenceStore = HashMap<Name, MutableList<SolidReferenceGroup>>()
|
||||||
|
|
||||||
|
fun Solid.configureSolid(root: Gdml, parent: GdmlVolume, solid: GdmlSolid) {
|
||||||
|
val material = parent.materialref.resolve(root) ?: GdmlElement(parent.materialref.ref)
|
||||||
|
settings.run { configureSolid(parent, solid, material) }
|
||||||
|
}
|
||||||
|
|
||||||
private fun proxySolid(root: Gdml, group: SolidGroup, solid: GdmlSolid, name: String): SolidReferenceGroup {
|
private fun proxySolid(root: Gdml, group: SolidGroup, solid: GdmlSolid, name: String): SolidReferenceGroup {
|
||||||
val templateName = solidsName + name
|
val templateName = solidsName + name
|
||||||
if (proto[templateName] == null) {
|
if (proto[templateName] == null) {
|
||||||
@ -85,38 +146,6 @@ private class GdmlTransformer(val settings: GdmlTransformerSettings) {
|
|||||||
return ref
|
return ref
|
||||||
}
|
}
|
||||||
|
|
||||||
private val styleCache = HashMap<Name, Meta>()
|
|
||||||
|
|
||||||
var solidConfiguration: Solid.(parent: GdmlVolume, solid: GdmlSolid) -> Unit = { parent, _ ->
|
|
||||||
if (parent.physVolumes.isNotEmpty()) {
|
|
||||||
useStyle("opaque") {
|
|
||||||
SolidMaterial.MATERIAL_OPACITY_KEY put 0.3
|
|
||||||
"edges.enabled" put true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Solid.useStyle(name: String, builder: MetaBuilder.() -> Unit) {
|
|
||||||
styleCache.getOrPut(name.toName()) {
|
|
||||||
Meta(builder)
|
|
||||||
}
|
|
||||||
useStyle(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun configureSolid(root: Gdml, obj: Solid, parent: GdmlVolume, solid: GdmlSolid) {
|
|
||||||
val material = parent.materialref.resolve(root) ?: GdmlElement(parent.materialref.ref)
|
|
||||||
|
|
||||||
val styleName = "materials.${material.name}"
|
|
||||||
|
|
||||||
obj.useStyle(styleName) {
|
|
||||||
val vfMaterial = settings.run { SolidMaterial().apply { paint(material) } }
|
|
||||||
MATERIAL_KEY put vfMaterial.toMeta()
|
|
||||||
"Gdml.material" put material.name
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.solidConfiguration(parent, solid)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T : Solid> T.withPosition(
|
fun <T : Solid> T.withPosition(
|
||||||
newPos: GdmlPosition? = null,
|
newPos: GdmlPosition? = null,
|
||||||
newRotation: GdmlRotation? = null,
|
newRotation: GdmlRotation? = null,
|
||||||
@ -314,13 +343,13 @@ private class GdmlTransformer(val settings: GdmlTransformerSettings) {
|
|||||||
): Solid? {
|
): Solid? {
|
||||||
require(name != "") { "Can't use empty solid name. Use null instead." }
|
require(name != "") { "Can't use empty solid name. Use null instead." }
|
||||||
return when (settings.solidAction(solid)) {
|
return when (settings.solidAction(solid)) {
|
||||||
GdmlTransformerSettings.Action.ADD -> {
|
GdmlTransformer.Action.ADD -> {
|
||||||
addSolid(root, solid, name)
|
addSolid(root, solid, name)
|
||||||
}
|
}
|
||||||
GdmlTransformerSettings.Action.PROTOTYPE -> {
|
GdmlTransformer.Action.PROTOTYPE -> {
|
||||||
proxySolid(root, this, solid, name ?: solid.name)
|
proxySolid(root, this, solid, name ?: solid.name)
|
||||||
}
|
}
|
||||||
GdmlTransformerSettings.Action.REJECT -> {
|
GdmlTransformer.Action.REJECT -> {
|
||||||
//ignore
|
//ignore
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
@ -339,21 +368,21 @@ private class GdmlTransformer(val settings: GdmlTransformerSettings) {
|
|||||||
val solid = volume.solidref.resolve(root)
|
val solid = volume.solidref.resolve(root)
|
||||||
?: error("Solid with tag ${volume.solidref.ref} for volume ${volume.name} not defined")
|
?: error("Solid with tag ${volume.solidref.ref} for volume ${volume.name} not defined")
|
||||||
addSolidWithCaching(root, solid, physVolume.name)?.apply {
|
addSolidWithCaching(root, solid, physVolume.name)?.apply {
|
||||||
configureSolid(root, this, volume, solid)
|
configureSolid(root, volume, solid)
|
||||||
withPosition(root, physVolume)
|
withPosition(root, physVolume)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
when (settings.volumeAction(volume)) {
|
when (settings.volumeAction(volume)) {
|
||||||
GdmlTransformerSettings.Action.ADD -> {
|
GdmlTransformer.Action.ADD -> {
|
||||||
val group: SolidGroup = volume(root, volume)
|
val group: SolidGroup = volume(root, volume)
|
||||||
this[physVolume.name] = group.withPosition(root, physVolume)
|
this[physVolume.name] = group.withPosition(root, physVolume)
|
||||||
}
|
}
|
||||||
GdmlTransformerSettings.Action.PROTOTYPE -> {
|
GdmlTransformer.Action.PROTOTYPE -> {
|
||||||
proxyVolume(root, this, physVolume, volume)
|
proxyVolume(root, this, physVolume, volume)
|
||||||
}
|
}
|
||||||
GdmlTransformerSettings.Action.REJECT -> {
|
GdmlTransformer.Action.REJECT -> {
|
||||||
//ignore
|
//ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -379,7 +408,7 @@ private class GdmlTransformer(val settings: GdmlTransformerSettings) {
|
|||||||
?: error("Solid with tag ${group.solidref.ref} for volume ${group.name} not defined")
|
?: error("Solid with tag ${group.solidref.ref} for volume ${group.name} not defined")
|
||||||
|
|
||||||
addSolidWithCaching(root, solid, null)?.apply {
|
addSolidWithCaching(root, solid, null)?.apply {
|
||||||
configureSolid(root, this, group, solid)
|
this.configureSolid(root, group, solid)
|
||||||
}
|
}
|
||||||
|
|
||||||
when (val vol: GdmlPlacement? = group.placement) {
|
when (val vol: GdmlPlacement? = group.placement) {
|
||||||
@ -394,10 +423,10 @@ private class GdmlTransformer(val settings: GdmlTransformerSettings) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun finalize(final: SolidGroup): SolidGroup {
|
private fun finalize(final: SolidGroup): SolidGroup {
|
||||||
//final.prototypes = proto
|
val rootStyle by final.style("gdml") {
|
||||||
final.useStyle("gdml") {
|
|
||||||
Solid.ROTATION_ORDER_KEY put RotationOrder.ZXY
|
Solid.ROTATION_ORDER_KEY put RotationOrder.ZXY
|
||||||
}
|
}
|
||||||
|
final.useStyle(rootStyle)
|
||||||
|
|
||||||
//inline prototypes
|
//inline prototypes
|
||||||
// referenceStore.forEach { (protoName, list) ->
|
// referenceStore.forEach { (protoName, list) ->
|
||||||
@ -419,7 +448,7 @@ private class GdmlTransformer(val settings: GdmlTransformerSettings) {
|
|||||||
set(token.asName(), item as? Solid)
|
set(token.asName(), item as? Solid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
styleCache.forEach {
|
settings.styleCache.forEach {
|
||||||
final.styleSheet {
|
final.styleSheet {
|
||||||
define(it.key.toString(), it.value)
|
define(it.key.toString(), it.value)
|
||||||
}
|
}
|
||||||
@ -432,15 +461,16 @@ private class GdmlTransformer(val settings: GdmlTransformerSettings) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public fun Gdml.toVision(block: GdmlTransformerSettings.() -> Unit = {}): SolidGroup {
|
public fun Gdml.toVision(block: GdmlTransformer.() -> Unit = {}): SolidGroup {
|
||||||
val context = GdmlTransformer(GdmlTransformerSettings().apply(block))
|
val settings = GdmlTransformer().apply(block)
|
||||||
|
val context = GdmlTransformerEnv(settings)
|
||||||
return context.transform(this)
|
return context.transform(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append Gdml node to the group
|
* Append Gdml node to the group
|
||||||
*/
|
*/
|
||||||
public fun SolidGroup.gdml(gdml: Gdml, key: String? = null, transformer: GdmlTransformerSettings.() -> Unit = {}) {
|
public fun SolidGroup.gdml(gdml: Gdml, key: String? = null, transformer: GdmlTransformer.() -> Unit = {}) {
|
||||||
val visual = gdml.toVision(transformer)
|
val visual = gdml.toVision(transformer)
|
||||||
//println(Visual3DPlugin.json.stringify(VisualGroup3D.serializer(), visual))
|
//println(Visual3DPlugin.json.stringify(VisualGroup3D.serializer(), visual))
|
||||||
set(key, visual)
|
set(key, visual)
|
@ -12,7 +12,7 @@ public fun SolidGroup.gdml(
|
|||||||
file: Path,
|
file: Path,
|
||||||
key: String = "",
|
key: String = "",
|
||||||
usePreprocessor: Boolean = false,
|
usePreprocessor: Boolean = false,
|
||||||
transformer: GdmlTransformerSettings.() -> Unit = {},
|
transformer: GdmlTransformer.() -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val gdml = Gdml.decodeFromFile(file, usePreprocessor)
|
val gdml = Gdml.decodeFromFile(file, usePreprocessor)
|
||||||
gdml(gdml, key, transformer)
|
gdml(gdml, key, transformer)
|
||||||
|
@ -89,7 +89,7 @@ public class VisionServer internal constructor(
|
|||||||
script {
|
script {
|
||||||
attributes["class"] = OUTPUT_DATA_CLASS
|
attributes["class"] = OUTPUT_DATA_CLASS
|
||||||
unsafe {
|
unsafe {
|
||||||
+visionManager.encodeToString(vision)
|
+"\n${visionManager.encodeToString(vision)}\n"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,9 +18,15 @@ public class Axes : Scheme() {
|
|||||||
|
|
||||||
override val descriptor: NodeDescriptor by lazy {
|
override val descriptor: NodeDescriptor by lazy {
|
||||||
NodeDescriptor {
|
NodeDescriptor {
|
||||||
value(Axes::visible)
|
value(Axes::visible){
|
||||||
value(Axes::size)
|
default(false)
|
||||||
value(Axes::width)
|
}
|
||||||
|
value(Axes::size){
|
||||||
|
default(AXIS_SIZE)
|
||||||
|
}
|
||||||
|
value(Axes::width){
|
||||||
|
default(AXIS_WIDTH)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,12 +30,24 @@ public class Camera : Scheme() {
|
|||||||
|
|
||||||
override val descriptor: NodeDescriptor by lazy {
|
override val descriptor: NodeDescriptor by lazy {
|
||||||
NodeDescriptor {
|
NodeDescriptor {
|
||||||
value(Camera::fov)
|
value(Camera::fov){
|
||||||
value(Camera::nearClip)
|
default(FIELD_OF_VIEW)
|
||||||
value(Camera::farClip)
|
}
|
||||||
value(Camera::distance)
|
value(Camera::nearClip){
|
||||||
value(Camera::azimuth)
|
default(NEAR_CLIP)
|
||||||
value(Camera::zenith)
|
}
|
||||||
|
value(Camera::farClip){
|
||||||
|
default(FAR_CLIP)
|
||||||
|
}
|
||||||
|
value(Camera::distance){
|
||||||
|
default(INITIAL_DISTANCE)
|
||||||
|
}
|
||||||
|
value(Camera::azimuth){
|
||||||
|
default(INITIAL_AZIMUTH)
|
||||||
|
}
|
||||||
|
value(Camera::latitude){
|
||||||
|
default(INITIAL_LATITUDE)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,11 @@ package space.kscience.visionforge.solid.specifications
|
|||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
|
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
|
import space.kscience.dataforge.values.ValueType
|
||||||
|
import space.kscience.visionforge.hide
|
||||||
import space.kscience.visionforge.scheme
|
import space.kscience.visionforge.scheme
|
||||||
import space.kscience.visionforge.value
|
import space.kscience.visionforge.value
|
||||||
|
import space.kscience.visionforge.widgetType
|
||||||
|
|
||||||
public class Canvas3DOptions : Scheme() {
|
public class Canvas3DOptions : Scheme() {
|
||||||
public var axes: Axes by spec(Axes)
|
public var axes: Axes by spec(Axes)
|
||||||
@ -20,6 +23,8 @@ public class Canvas3DOptions : Scheme() {
|
|||||||
public var maxWith: Number by number { maxSize }
|
public var maxWith: Number by number { maxSize }
|
||||||
public var maxHeight: Number by number { maxSize }
|
public var maxHeight: Number by number { maxSize }
|
||||||
|
|
||||||
|
public var layers: List<Number> by numberList(0)
|
||||||
|
|
||||||
public var onSelect: ((Name?) -> Unit)? = null
|
public var onSelect: ((Name?) -> Unit)? = null
|
||||||
|
|
||||||
|
|
||||||
@ -28,14 +33,37 @@ public class Canvas3DOptions : Scheme() {
|
|||||||
NodeDescriptor {
|
NodeDescriptor {
|
||||||
scheme(Canvas3DOptions::axes, Axes)
|
scheme(Canvas3DOptions::axes, Axes)
|
||||||
scheme(Canvas3DOptions::light, Light)
|
scheme(Canvas3DOptions::light, Light)
|
||||||
scheme(Canvas3DOptions::camera, Camera)
|
scheme(Canvas3DOptions::camera, Camera) {
|
||||||
scheme(Canvas3DOptions::controls, Controls)
|
hide()
|
||||||
value(Canvas3DOptions::minSize)
|
}
|
||||||
value(Canvas3DOptions::minWith)
|
scheme(Canvas3DOptions::controls, Controls) {
|
||||||
value(Canvas3DOptions::minHeight)
|
hide()
|
||||||
value(Canvas3DOptions::maxSize)
|
}
|
||||||
value(Canvas3DOptions::maxWith)
|
value(Canvas3DOptions::minSize) {
|
||||||
value(Canvas3DOptions::maxHeight)
|
hide()
|
||||||
|
}
|
||||||
|
value(Canvas3DOptions::minWith) {
|
||||||
|
hide()
|
||||||
|
}
|
||||||
|
value(Canvas3DOptions::minHeight) {
|
||||||
|
hide()
|
||||||
|
}
|
||||||
|
value(Canvas3DOptions::maxSize) {
|
||||||
|
hide()
|
||||||
|
}
|
||||||
|
value(Canvas3DOptions::maxWith) {
|
||||||
|
hide()
|
||||||
|
}
|
||||||
|
value(Canvas3DOptions::maxHeight) {
|
||||||
|
hide()
|
||||||
|
}
|
||||||
|
value(Canvas3DOptions::layers) {
|
||||||
|
type(ValueType.NUMBER)
|
||||||
|
multiple = true
|
||||||
|
default(listOf(0))
|
||||||
|
widgetType = "multiSelect"
|
||||||
|
allow(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,8 +70,29 @@ public class ThreeCanvas(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public var camera: PerspectiveCamera = buildCamera(options.camera)
|
|
||||||
private set
|
private fun buildCamera(spec: Camera) = PerspectiveCamera(
|
||||||
|
spec.fov,
|
||||||
|
1.0,
|
||||||
|
spec.nearClip,
|
||||||
|
spec.farClip
|
||||||
|
).apply {
|
||||||
|
translateX(spec.distance * sin(spec.zenith) * sin(spec.azimuth))
|
||||||
|
translateY(spec.distance * cos(spec.zenith))
|
||||||
|
translateZ(spec.distance * sin(spec.zenith) * cos(spec.azimuth))
|
||||||
|
options.useProperty(Canvas3DOptions::layers) { selectedLayers ->
|
||||||
|
(0..31).forEach {
|
||||||
|
if (it in selectedLayers) {
|
||||||
|
this@apply.layers.enable(it)
|
||||||
|
} else{
|
||||||
|
this@apply.layers.disable(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public val camera: PerspectiveCamera = buildCamera(options.camera)
|
||||||
|
|
||||||
private var picked: Object3D? = null
|
private var picked: Object3D? = null
|
||||||
|
|
||||||
@ -127,7 +148,6 @@ public class ThreeCanvas(
|
|||||||
mousePosition.x = ((event.clientX - rect.left) / canvas.clientWidth) * 2 - 1
|
mousePosition.x = ((event.clientX - rect.left) / canvas.clientWidth) * 2 - 1
|
||||||
mousePosition.y = -((event.clientY - rect.top) / canvas.clientHeight) * 2 + 1
|
mousePosition.y = -((event.clientY - rect.top) / canvas.clientHeight) * 2 + 1
|
||||||
}
|
}
|
||||||
event.preventDefault()
|
|
||||||
}, false)
|
}, false)
|
||||||
|
|
||||||
canvas.onresize = {
|
canvas.onresize = {
|
||||||
@ -185,17 +205,6 @@ public class ThreeCanvas(
|
|||||||
|
|
||||||
private fun buildLight(spec: Light?): info.laht.threekt.lights.Light = AmbientLight(0x404040)
|
private fun buildLight(spec: Light?): info.laht.threekt.lights.Light = AmbientLight(0x404040)
|
||||||
|
|
||||||
private fun buildCamera(spec: Camera) = PerspectiveCamera(
|
|
||||||
spec.fov,
|
|
||||||
1.0,
|
|
||||||
spec.nearClip,
|
|
||||||
spec.farClip
|
|
||||||
).apply {
|
|
||||||
translateX(spec.distance * sin(spec.zenith) * sin(spec.azimuth))
|
|
||||||
translateY(spec.distance * cos(spec.zenith))
|
|
||||||
translateZ(spec.distance * sin(spec.zenith) * cos(spec.azimuth))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addControls(element: Node, controls: Controls) {
|
private fun addControls(element: Node, controls: Controls) {
|
||||||
when (controls["type"].string) {
|
when (controls["type"].string) {
|
||||||
"trackball" -> TrackballControls(camera, element)
|
"trackball" -> TrackballControls(camera, element)
|
||||||
|
Loading…
Reference in New Issue
Block a user