Add multi-select value chooser for layers

This commit is contained in:
Alexander Nozik 2021-05-08 23:14:15 +03:00
parent 2798439582
commit faf3fa8512
20 changed files with 295 additions and 152 deletions

View File

@ -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">

View File

@ -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
} }
} }
} }

View File

@ -10,9 +10,7 @@ fun main() {
plugin(Solids) plugin(Solids)
} }
context.makeVisionFile{ context.makeVisionFile {
vision("canvas") { vision("canvas") { GdmlShowCase.babyIaxo().toVision() }
GdmlShowCase.babyIaxo().toVision()
}
} }
} }

View File

@ -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 ->

View File

@ -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"))
} }

View File

@ -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
}
}
}
}

View File

@ -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)

View File

@ -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)
}

View File

@ -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
} }

View File

@ -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)

View File

@ -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))

View File

@ -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,15 +68,11 @@ class HtmlTagTest {
} }
} }
val groupRenderer: HtmlVisionRenderer = { _, _, _ ->
p { +"This is group" }
}
@Test @Test
fun testStringRender() { fun testStringRender() {
println( println(
createHTML().div { createHTML().div{
renderVisionFragment(simpleVisionRenderer, fragment = fragment) renderVisionFragment(simpleVisionRenderer, fragment = fragment)
} }
) )

View File

@ -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()
} }

View File

@ -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
}
}
/**
* 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 GdmlTransformer(val settings: GdmlTransformerSettings) { 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)

View File

@ -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)

View File

@ -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"
} }
} }
} }

View File

@ -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)
}
} }
} }
} }

View File

@ -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)
}
} }
} }
} }

View File

@ -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)
}
} }
} }
} }

View File

@ -52,7 +52,7 @@ public class ThreeCanvas(
private set private set
private val scene: Scene = Scene().apply { private val scene: Scene = Scene().apply {
options.useProperty(Canvas3DOptions::axes){axesConfig-> options.useProperty(Canvas3DOptions::axes) { axesConfig ->
getObjectByName(AXES_NAME)?.let { remove(it) } getObjectByName(AXES_NAME)?.let { remove(it) }
val axesObject = AxesHelper(axes.size.toInt()).apply { visible = axes.visible } val axesObject = AxesHelper(axes.size.toInt()).apply { visible = axes.visible }
axesObject.name = AXES_NAME axesObject.name = AXES_NAME
@ -60,7 +60,7 @@ public class ThreeCanvas(
} }
//Set up light //Set up light
options.useProperty(Canvas3DOptions::light){lightConfig-> options.useProperty(Canvas3DOptions::light) { lightConfig ->
//remove old light if present //remove old light if present
getObjectByName(LIGHT_NAME)?.let { remove(it) } getObjectByName(LIGHT_NAME)?.let { remove(it) }
//add new light //add new light
@ -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)