Fix CME in solid children clearing. Add documentation. Splic client

This commit is contained in:
Alexander Nozik 2023-10-18 21:48:50 +03:00
parent cf6d73305b
commit 9c1246fb26
23 changed files with 155 additions and 195 deletions

View File

@ -8,7 +8,7 @@ import space.kscience.plotly.models.Trace
import space.kscience.plotly.scatter import space.kscience.plotly.scatter
import space.kscience.visionforge.Application import space.kscience.visionforge.Application
import space.kscience.visionforge.Colors import space.kscience.visionforge.Colors
import space.kscience.visionforge.VisionClient import space.kscience.visionforge.JsVisionClient
import space.kscience.visionforge.plotly.PlotlyPlugin import space.kscience.visionforge.plotly.PlotlyPlugin
import space.kscience.visionforge.react.createRoot import space.kscience.visionforge.react.createRoot
import space.kscience.visionforge.react.render import space.kscience.visionforge.react.render
@ -34,7 +34,7 @@ private class JsPlaygroundApp : Application {
val playgroundContext = Context { val playgroundContext = Context {
plugin(ThreeWithControlsPlugin) plugin(ThreeWithControlsPlugin)
plugin(VisionClient) plugin(JsVisionClient)
plugin(PlotlyPlugin) plugin(PlotlyPlugin)
} }

View File

@ -13,6 +13,7 @@ kscience {
useKtor() useKtor()
fullStack( fullStack(
"muon-monitor.js", "muon-monitor.js",
development = true,
jvmConfig = { withJava() }, jvmConfig = { withJava() },
jsConfig = { useCommonJs() } jsConfig = { useCommonJs() }
) { ) {

View File

@ -3,6 +3,7 @@ package ru.mipt.npm.muon.monitor
import ru.mipt.npm.muon.monitor.Monitor.CENTRAL_LAYER_Z import ru.mipt.npm.muon.monitor.Monitor.CENTRAL_LAYER_Z
import ru.mipt.npm.muon.monitor.Monitor.LOWER_LAYER_Z import ru.mipt.npm.muon.monitor.Monitor.LOWER_LAYER_Z
import ru.mipt.npm.muon.monitor.Monitor.UPPER_LAYER_Z import ru.mipt.npm.muon.monitor.Monitor.UPPER_LAYER_Z
import space.kscience.dataforge.names.asName
import space.kscience.visionforge.MutableVisionContainer import space.kscience.visionforge.MutableVisionContainer
import space.kscience.visionforge.VisionManager import space.kscience.visionforge.VisionManager
import space.kscience.visionforge.setAsRoot import space.kscience.visionforge.setAsRoot
@ -34,7 +35,7 @@ class Model(val manager: VisionManager) {
} }
} }
var tracks: SolidGroup val tracks: SolidGroup = SolidGroup()
val root: SolidGroup = SolidGroup().apply { val root: SolidGroup = SolidGroup().apply {
setAsRoot(this@Model.manager) setAsRoot(this@Model.manager)
@ -59,7 +60,8 @@ class Model(val manager: VisionManager) {
detector(it) detector(it)
} }
} }
tracks = solidGroup("tracks")
setChild("tracks".asName(), tracks)
} }
private fun highlight(pixel: String) { private fun highlight(pixel: String) {

View File

@ -0,0 +1,42 @@
package space.kscience.visionforge
import kotlinx.coroutines.launch
import space.kscience.dataforge.context.Plugin
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MetaRepr
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.parseAsName
/**
* A feedback client that communicates with a server and provides ability to propagate events and changes back to the model
*/
public interface VisionClient: Plugin {
public val visionManager: VisionManager
public suspend fun sendEvent(event: VisionEvent)
public fun notifyPropertyChanged(visionName: Name, propertyName: Name, item: Meta?)
}
public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: Meta?) {
notifyPropertyChanged(visionName, propertyName.parseAsName(true), item)
}
public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: Number) {
notifyPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item))
}
public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: String) {
notifyPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item))
}
public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: Boolean) {
notifyPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item))
}
public fun VisionClient.sendEvent(visionName: Name, event: MetaRepr): Unit {
context.launch {
sendEvent(VisionMetaEvent(visionName, event.toMeta()))
}
}

View File

@ -187,30 +187,10 @@ internal abstract class VisionChildrenImpl(
} }
override fun clear() { override fun clear() {
items?.forEach { set(it.key, null) } items?.clear()
// if (!items.isNullOrEmpty()) { updateJobs.values.forEach { it.cancel() }
// updateJobs.values.forEach { updateJobs.clear()
// it.cancel() onChange(Name.EMPTY)
// }
// updateJobs.clear()
// items?.clear()
// }
} }
} }
//
//internal object VisionChildrenContainerSerializer : KSerializer<MutableVisionChildren> {
// private val mapSerializer = serializer<Map<NameToken, Vision>>()
//
// override val descriptor: SerialDescriptor = mapSerializer.descriptor
//
// override fun deserialize(decoder: Decoder): MutableVisionChildren {
// val map = decoder.decodeSerializableValue(mapSerializer)
// return VisionChildrenImpl(map)
// }
//
// override fun serialize(encoder: Encoder, value: MutableVisionChildren) {
// val map = value.keys.associateWith { value[it]!! }
// encoder.encodeSerializableValue(mapSerializer, map)
// }
//
//}

View File

@ -3,6 +3,8 @@ package space.kscience.visionforge
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.set
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
/** /**
@ -11,6 +13,10 @@ import space.kscience.dataforge.names.Name
@Serializable @Serializable
public sealed interface VisionEvent{ public sealed interface VisionEvent{
public val targetName: Name public val targetName: Name
public companion object{
public val CLICK_EVENT_KEY: Name get() = Name.of("events", "click", "payload")
}
} }
/** /**
@ -22,4 +28,13 @@ public class VisionMetaEvent(override val targetName: Name, public val meta: Met
@Serializable @Serializable
@SerialName("change") @SerialName("change")
public class VisionChangeEvent(override val targetName: Name, public val change: VisionChange) : VisionEvent public class VisionChangeEvent(override val targetName: Name, public val change: VisionChange) : VisionEvent
public val Vision.Companion.CLICK_EVENT_KEY: Name get() = Name.of("events", "click", "payload")
/**
* Set the payload to be sent to server on click
*/
public fun Vision.onClickPayload(payloadBuilder: MutableMeta.() -> Unit){
properties[VisionEvent.CLICK_EVENT_KEY] = Meta(payloadBuilder)
}

View File

@ -15,7 +15,10 @@ import kotlinx.coroutines.sync.withLock
import org.w3c.dom.* import org.w3c.dom.*
import org.w3c.dom.url.URL import org.w3c.dom.url.URL
import space.kscience.dataforge.context.* import space.kscience.dataforge.context.*
import space.kscience.dataforge.meta.* import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MetaSerializer
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.int
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.parseAsName import space.kscience.dataforge.names.parseAsName
import space.kscience.visionforge.html.VisionTagConsumer import space.kscience.visionforge.html.VisionTagConsumer
@ -29,9 +32,9 @@ import kotlin.time.Duration.Companion.milliseconds
/** /**
* A Kotlin-browser plugin that renders visions based on provided renderers and governs communication with the server. * A Kotlin-browser plugin that renders visions based on provided renderers and governs communication with the server.
*/ */
public class VisionClient : AbstractPlugin() { public class JsVisionClient : AbstractPlugin(), VisionClient {
override val tag: PluginTag get() = Companion.tag override val tag: PluginTag get() = Companion.tag
private val visionManager: VisionManager by require(VisionManager) override val visionManager: VisionManager by require(VisionManager)
/** /**
* Up-going tree traversal in search for endpoint attribute. If element is null, return window URL * Up-going tree traversal in search for endpoint attribute. If element is null, return window URL
@ -69,7 +72,7 @@ public class VisionClient : AbstractPlugin() {
/** /**
* Communicate vision property changed from rendering engine to model * Communicate vision property changed from rendering engine to model
*/ */
public fun notifyPropertyChanged(visionName: Name, propertyName: Name, item: Meta?) { override fun notifyPropertyChanged(visionName: Name, propertyName: Name, item: Meta?) {
context.launch { context.launch {
mutex.withLock { mutex.withLock {
changeCollector.propertyChanged(visionName, propertyName, item) changeCollector.propertyChanged(visionName, propertyName, item)
@ -85,7 +88,7 @@ public class VisionClient : AbstractPlugin() {
/** /**
* Send a custom feedback event * Send a custom feedback event
*/ */
public suspend fun sendEvent(event: VisionEvent) { override suspend fun sendEvent(event: VisionEvent) {
eventCollector.emit(event) eventCollector.emit(event)
} }
@ -252,37 +255,15 @@ public class VisionClient : AbstractPlugin() {
textVisionRenderer(this), textVisionRenderer(this),
formVisionRenderer(this) formVisionRenderer(this)
).associateByName() ).associateByName()
} else super.content(target) } else super<AbstractPlugin>.content(target)
public companion object : PluginFactory<VisionClient> { public companion object : PluginFactory<JsVisionClient> {
override fun build(context: Context, meta: Meta): VisionClient = VisionClient() override fun build(context: Context, meta: Meta): JsVisionClient = JsVisionClient()
override val tag: PluginTag = PluginTag(name = "vision.client.js", group = PluginTag.DATAFORGE_GROUP) override val tag: PluginTag = PluginTag(name = "vision.client.js", group = PluginTag.DATAFORGE_GROUP)
} }
} }
public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: Meta?) {
notifyPropertyChanged(visionName, propertyName.parseAsName(true), item)
}
public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: Number) {
notifyPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item))
}
public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: String) {
notifyPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item))
}
public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: String, item: Boolean) {
notifyPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item))
}
public fun VisionClient.sendEvent(visionName: Name, event: MetaRepr): Unit {
context.launch {
sendEvent(VisionMetaEvent(visionName, event.toMeta()))
}
}
private fun whenDocumentLoaded(block: Document.() -> Unit): Unit { private fun whenDocumentLoaded(block: Document.() -> Unit): Unit {
if (document.body != null) { if (document.body != null) {
block(document) block(document)
@ -294,7 +275,7 @@ private fun whenDocumentLoaded(block: Document.() -> Unit): Unit {
/** /**
* Fetch and render visions for all elements with [VisionTagConsumer.OUTPUT_CLASS] class inside given [element]. * Fetch and render visions for all elements with [VisionTagConsumer.OUTPUT_CLASS] class inside given [element].
*/ */
public fun VisionClient.renderAllVisionsIn(element: Element) { public fun JsVisionClient.renderAllVisionsIn(element: Element) {
val elements = element.getElementsByClassName(VisionTagConsumer.OUTPUT_CLASS) val elements = element.getElementsByClassName(VisionTagConsumer.OUTPUT_CLASS)
logger.info { "Finished search for outputs. Found ${elements.length} items" } logger.info { "Finished search for outputs. Found ${elements.length} items" }
elements.asList().forEach { child -> elements.asList().forEach { child ->
@ -305,7 +286,7 @@ public fun VisionClient.renderAllVisionsIn(element: Element) {
/** /**
* Render all visions in an element with a given [id] * Render all visions in an element with a given [id]
*/ */
public fun VisionClient.renderAllVisionsById(document: Document, id: String): Unit { public fun JsVisionClient.renderAllVisionsById(document: Document, id: String): Unit {
val element = document.getElementById(id) val element = document.getElementById(id)
if (element != null) { if (element != null) {
renderAllVisionsIn(element) renderAllVisionsIn(element)
@ -318,13 +299,13 @@ public fun VisionClient.renderAllVisionsById(document: Document, id: String): Un
/** /**
* Fetch visions from the server for all elements with [VisionTagConsumer.OUTPUT_CLASS] class in the document body * Fetch visions from the server for all elements with [VisionTagConsumer.OUTPUT_CLASS] class in the document body
*/ */
public fun VisionClient.renderAllVisions(): Unit = whenDocumentLoaded { public fun JsVisionClient.renderAllVisions(): Unit = whenDocumentLoaded {
val element = body ?: error("Document does not have a body") val element = body ?: error("Document does not have a body")
renderAllVisionsIn(element) renderAllVisionsIn(element)
} }
public class VisionClientApplication(public val context: Context) : Application { public class VisionClientApplication(public val context: Context) : Application {
private val client = context.request(VisionClient) private val client = context.request(JsVisionClient)
override fun start(document: Document, state: Map<String, Any>) { override fun start(document: Document, state: Map<String, Any>) {
context.logger.info { context.logger.info {
@ -348,7 +329,7 @@ public fun runVisionClient(contextBuilder: ContextBuilder.() -> Unit) {
Global.logger.info { "Starting VisionForge context" } Global.logger.info { "Starting VisionForge context" }
val context = Context("VisionForge") { val context = Context("VisionForge") {
plugin(VisionClient) plugin(JsVisionClient)
contextBuilder() contextBuilder()
} }

View File

@ -20,7 +20,7 @@ import space.kscience.visionforge.html.VisionOfNumberField
import space.kscience.visionforge.html.VisionOfTextField import space.kscience.visionforge.html.VisionOfTextField
internal fun textVisionRenderer( internal fun textVisionRenderer(
client: VisionClient, client: JsVisionClient,
): ElementVisionRenderer = ElementVisionRenderer<VisionOfTextField> { name, vision, _ -> ): ElementVisionRenderer = ElementVisionRenderer<VisionOfTextField> { name, vision, _ ->
val fieldName = vision.name ?: "input[${vision.hashCode().toUInt()}]" val fieldName = vision.name ?: "input[${vision.hashCode().toUInt()}]"
vision.label?.let { vision.label?.let {
@ -42,7 +42,7 @@ internal fun textVisionRenderer(
} }
internal fun numberVisionRenderer( internal fun numberVisionRenderer(
client: VisionClient, client: JsVisionClient,
): ElementVisionRenderer = ElementVisionRenderer<VisionOfNumberField> { name, vision, _ -> ): ElementVisionRenderer = ElementVisionRenderer<VisionOfNumberField> { name, vision, _ ->
val fieldName = vision.name ?: "input[${vision.hashCode().toUInt()}]" val fieldName = vision.name ?: "input[${vision.hashCode().toUInt()}]"
vision.label?.let { vision.label?.let {
@ -87,7 +87,7 @@ internal fun FormData.toMeta(): Meta {
} }
internal fun formVisionRenderer( internal fun formVisionRenderer(
client: VisionClient, client: JsVisionClient,
): ElementVisionRenderer = ElementVisionRenderer<VisionOfHtmlForm> { name, vision, _ -> ): ElementVisionRenderer = ElementVisionRenderer<VisionOfHtmlForm> { name, vision, _ ->
val form = document.getElementById(vision.formId) as? HTMLFormElement val form = document.getElementById(vision.formId) as? HTMLFormElement

View File

@ -8,14 +8,14 @@ import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.PluginFactory import space.kscience.dataforge.context.PluginFactory
import space.kscience.dataforge.context.PluginTag import space.kscience.dataforge.context.PluginTag
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.visionforge.VisionClient import space.kscience.visionforge.JsVisionClient
import space.kscience.visionforge.renderAllVisions import space.kscience.visionforge.renderAllVisions
import space.kscience.visionforge.renderAllVisionsById import space.kscience.visionforge.renderAllVisionsById
import space.kscience.visionforge.renderAllVisionsIn import space.kscience.visionforge.renderAllVisionsIn
@JsExport @JsExport
public class VFNotebookClient : AbstractPlugin() { public class VFNotebookClient : AbstractPlugin() {
private val client by require(VisionClient) private val client by require(JsVisionClient)
public fun renderAllVisionsIn(element: Element) { public fun renderAllVisionsIn(element: Element) {
client.renderAllVisionsIn(element) client.renderAllVisionsIn(element)

View File

@ -18,7 +18,7 @@ import space.kscience.visionforge.markup.VisionOfMarkup.Companion.COMMONMARK_FOR
import space.kscience.visionforge.markup.VisionOfMarkup.Companion.GFM_FORMAT import space.kscience.visionforge.markup.VisionOfMarkup.Companion.GFM_FORMAT
public actual class MarkupPlugin : VisionPlugin(), ElementVisionRenderer { public actual class MarkupPlugin : VisionPlugin(), ElementVisionRenderer {
public val visionClient: VisionClient by require(VisionClient) public val visionClient: JsVisionClient by require(JsVisionClient)
override val tag: PluginTag get() = Companion.tag override val tag: PluginTag get() = Companion.tag
override val visionSerializersModule: SerializersModule get() = markupSerializersModule override val visionSerializersModule: SerializersModule get() = markupSerializersModule

View File

@ -11,12 +11,12 @@ import space.kscience.dataforge.names.asName
import space.kscience.plotly.PlotlyConfig import space.kscience.plotly.PlotlyConfig
import space.kscience.plotly.plot import space.kscience.plotly.plot
import space.kscience.visionforge.ElementVisionRenderer import space.kscience.visionforge.ElementVisionRenderer
import space.kscience.visionforge.JsVisionClient
import space.kscience.visionforge.Vision import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionClient
import space.kscience.visionforge.VisionPlugin import space.kscience.visionforge.VisionPlugin
public actual class PlotlyPlugin : VisionPlugin(), ElementVisionRenderer { public actual class PlotlyPlugin : VisionPlugin(), ElementVisionRenderer {
public val visionClient: VisionClient by require(VisionClient) public val visionClient: JsVisionClient by require(JsVisionClient)
override val tag: PluginTag get() = Companion.tag override val tag: PluginTag get() = Companion.tag

View File

@ -15,6 +15,9 @@ public enum class CompositeType {
SUBTRACT SUBTRACT
} }
/**
* A CSG-based composite solid
*/
@Serializable @Serializable
@SerialName("solid.composite") @SerialName("solid.composite")
public class Composite( public class Composite(

View File

@ -5,6 +5,9 @@ import kotlinx.serialization.Serializable
import space.kscience.visionforge.MutableVisionContainer import space.kscience.visionforge.MutableVisionContainer
import space.kscience.visionforge.setChild import space.kscience.visionforge.setChild
/**
* A convex hull shape
*/
@Serializable @Serializable
@SerialName("solid.convex") @SerialName("solid.convex")
public class Convex(public val points: List<Float32Vector3D>) : SolidBase<Convex>() public class Convex(public val points: List<Float32Vector3D>) : SolidBase<Convex>()

View File

@ -12,7 +12,7 @@ import space.kscience.dataforge.names.asName
import space.kscience.visionforge.* import space.kscience.visionforge.*
@Serializable @Serializable
public abstract class LightSource : SolidBase<LightSource>() { public abstract class LightSource : MiscSolid() {
override val descriptor: MetaDescriptor get() = LightSource.descriptor override val descriptor: MetaDescriptor get() = LightSource.descriptor
public val color: ColorAccessor by colorProperty(SolidMaterial.COLOR_KEY) public val color: ColorAccessor by colorProperty(SolidMaterial.COLOR_KEY)

View File

@ -6,13 +6,19 @@ import space.kscience.visionforge.MutableVisionContainer
import space.kscience.visionforge.VisionBuilder import space.kscience.visionforge.VisionBuilder
import space.kscience.visionforge.setChild import space.kscience.visionforge.setChild
/**
* Utility solids
*/
public abstract class MiscSolid: SolidBase<MiscSolid>() public abstract class MiscSolid: SolidBase<MiscSolid>()
/**
* X-Y-Z axes
*/
@Serializable @Serializable
@SerialName("solid.axes") @SerialName("solid.axes")
public class AxesSolid(public val size: Double): MiscSolid(){ public class AxesSolid(public val size: Double): MiscSolid(){
public companion object{ public companion object{
public const val AXES_NAME: String = "@xes" public const val AXES_NAME: String = "@axes"
} }
} }

View File

@ -7,6 +7,9 @@ import kotlin.math.sin
public typealias Shape2D = List<Float32Vector2D> public typealias Shape2D = List<Float32Vector2D>
/**
* A builder for 2D shapes
*/
@Serializable @Serializable
public class Shape2DBuilder(private val points: ArrayList<Float32Vector2D> = ArrayList()) { public class Shape2DBuilder(private val points: ArrayList<Float32Vector2D> = ArrayList()) {

View File

@ -152,7 +152,10 @@ public var Vision.ignore: Boolean?
// get() = getProperty(SELECTED_KEY).boolean // get() = getProperty(SELECTED_KEY).boolean
// set(value) = setProperty(SELECTED_KEY, value) // set(value) = setProperty(SELECTED_KEY, value)
internal fun float(name: Name, default: Number): ReadWriteProperty<Solid, Number> = /**
*A [Float] solid property delegate
*/
internal fun float32(name: Name, default: Number): ReadWriteProperty<Solid, Number> =
object : ReadWriteProperty<Solid, Number> { object : ReadWriteProperty<Solid, Number> {
override fun getValue(thisRef: Solid, property: KProperty<*>): Number { override fun getValue(thisRef: Solid, property: KProperty<*>): Number {
return thisRef.properties.getValue(name)?.number ?: default return thisRef.properties.getValue(name)?.number ?: default
@ -163,7 +166,10 @@ internal fun float(name: Name, default: Number): ReadWriteProperty<Solid, Number
} }
} }
internal fun point( /**
* A [Float32Vector3D] solid property delegate
*/
internal fun float32Vector(
name: Name, name: Name,
defaultX: Float, defaultX: Float,
defaultY: Float = defaultX, defaultY: Float = defaultX,
@ -193,17 +199,17 @@ internal fun point(
} }
} }
public var Solid.position: Float32Vector3D? by point(POSITION_KEY, 0f) public var Solid.position: Float32Vector3D? by float32Vector(POSITION_KEY, 0f)
public var Solid.rotation: Float32Vector3D? by point(ROTATION_KEY, 0f) public var Solid.rotation: Float32Vector3D? by float32Vector(ROTATION_KEY, 0f)
public var Solid.scale: Float32Vector3D? by point(SCALE_KEY, 1f) public var Solid.scale: Float32Vector3D? by float32Vector(SCALE_KEY, 1f)
public var Solid.x: Number by float(X_POSITION_KEY, 0f) public var Solid.x: Number by float32(X_POSITION_KEY, 0f)
public var Solid.y: Number by float(Y_POSITION_KEY, 0f) public var Solid.y: Number by float32(Y_POSITION_KEY, 0f)
public var Solid.z: Number by float(Z_POSITION_KEY, 0f) public var Solid.z: Number by float32(Z_POSITION_KEY, 0f)
public var Solid.rotationX: Number by float(X_ROTATION_KEY, 0f) public var Solid.rotationX: Number by float32(X_ROTATION_KEY, 0f)
public var Solid.rotationY: Number by float(Y_ROTATION_KEY, 0f) public var Solid.rotationY: Number by float32(Y_ROTATION_KEY, 0f)
public var Solid.rotationZ: Number by float(Z_ROTATION_KEY, 0f) public var Solid.rotationZ: Number by float32(Z_ROTATION_KEY, 0f)
/** /**
* Raw quaternion value defined in properties * Raw quaternion value defined in properties
@ -241,9 +247,9 @@ public var Solid.quaternion: Quaternion
quaternionOrNull = value quaternionOrNull = value
} }
public var Solid.scaleX: Number by float(X_SCALE_KEY, 1f) public var Solid.scaleX: Number by float32(X_SCALE_KEY, 1f)
public var Solid.scaleY: Number by float(Y_SCALE_KEY, 1f) public var Solid.scaleY: Number by float32(Y_SCALE_KEY, 1f)
public var Solid.scaleZ: Number by float(Z_SCALE_KEY, 1f) public var Solid.scaleZ: Number by float32(Z_SCALE_KEY, 1f)
/** /**
* Add rotation with given [angle] relative to given [axis] * Add rotation with given [angle] relative to given [axis]

View File

@ -5,6 +5,9 @@ import kotlinx.serialization.Serializable
import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.visionforge.AbstractVision import space.kscience.visionforge.AbstractVision
/**
* An abstract solid that is both [Solid] and [AbstractVision]
*/
@Serializable @Serializable
@SerialName("solid") @SerialName("solid")
public open class SolidBase<T : Solid> : AbstractVision(), Solid { public open class SolidBase<T : Solid> : AbstractVision(), Solid {

View File

@ -12,6 +12,9 @@ import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_COLOR_K
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_KEY import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_KEY
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_OPACITY_KEY import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_OPACITY_KEY
/**
* A scheme for vision material
*/
@VisionBuilder @VisionBuilder
public class SolidMaterial : Scheme() { public class SolidMaterial : Scheme() {

View File

@ -21,6 +21,7 @@ import space.kscience.visionforge.solid.SolidReference.Companion.REFERENCE_CHILD
* Get a vision prototype if it is a [SolidReference] or vision itself if it is not. * Get a vision prototype if it is a [SolidReference] or vision itself if it is not.
* Unref is recursive, so it always returns a non-reference. * Unref is recursive, so it always returns a non-reference.
*/ */
@Suppress("RecursivePropertyAccessor")
public val Vision.prototype: Solid public val Vision.prototype: Solid
get() = when (this) { get() = when (this) {
is SolidReference -> prototype.prototype is SolidReference -> prototype.prototype
@ -239,95 +240,4 @@ public fun SolidGroup.newRef(
error("Can't add different prototype on top of existing one") error("Can't add different prototype on top of existing one")
} }
return children.ref(prototypeName, name?.parseAsName()) return children.ref(prototypeName, name?.parseAsName())
} }
//
//
///**
// * A reference [Solid] to reuse a template object
// */
//@Serializable
//@SerialName("solid.ref")
//public class SolidReferenceGroup(
// public val refName: Name,
//) : VisionGroup(), SolidReference, VisionGroup<Solid>, Solid {
//
// /**
// * Recursively search for defined template in the parent
// */
// override val prototype: Solid by lazy {
// if (parent == null) error("No parent is present for SolidReferenceGroup")
// if (parent !is PrototypeHolder) error("Parent does not hold prototypes")
// (parent as? PrototypeHolder)?.getPrototype(refName) ?: error("Prototype with name $refName not found")
// }
//
// override val items: Map<NameToken, VisionGroupItem<Solid>>
// get() = (prototype as? VisionGroup<*>)?.items
// ?.filter { it.key != SolidGroup.PROTOTYPES_TOKEN }
// ?.mapValues {
// VisionGroupItem.Node(ReferenceChild(this, it.key.asName()))
// } ?: emptyMap()
//
// override val descriptor: MetaDescriptor get() = prototype.descriptor
//
//
// /**
// * A ProxyChild is created temporarily only to interact with properties, it does not store any values
// * (properties are stored in external cache) and created and destroyed on-demand).
// */
// private class ReferenceChild(
// val owner: SolidReferenceGroup,
// private val refName: Name,
// ) : SolidReference, VisionGroup<Solid>, Solid {
//
// override val prototype: Solid by lazy {
// if (refName.isEmpty()) {
// owner.prototype
// } else {
// val proto = (owner.prototype).children.get(refName)
// ?: error("Prototype with name $refName not found in SolidReferenceGroup ${owner.refName}")
// proto as? Solid ?: error("Prototype with name $refName is ${proto::class} but expected Solid")
//// proto.unref as? Solid
//// ?: error("Prototype with name $refName is ${proto::class} but expected Solid")
// }
// }
//
// override val meta: ObservableMutableMeta by lazy {
// owner.meta.getOrCreate(childToken(refName).asName())
// }
//
// override val items: Map<NameToken, VisionGroupItem<Solid>>
// get() = (prototype as? VisionGroup<*>)?.items
// ?.filter { it.key != SolidGroup.PROTOTYPES_TOKEN }
// ?.mapValues { (key, _) ->
// VisionGroupItem.Node(ReferenceChild(owner, refName + key.asName()))
// } ?: emptyMap()
//
// override var parent: VisionGroup<*>?
// get() {
// val parentName = refName.cutLast()
// return if (parentName.isEmpty()) owner else ReferenceChild(owner, parentName)
// }
// set(_) {
// error("Setting a parent for a reference child is not possible")
// }
//
// override fun invalidateProperty(propertyName: Name) {
// owner.invalidateProperty(childPropertyName(refName, propertyName))
// }
//
// override fun update(change: VisionChange) {
// change.properties?.let {
// updateProperties(it, Name.EMPTY)
// }
// }
//
// override val descriptor: MetaDescriptor get() = prototype.descriptor
//
// }
//
// public companion object {
// public const val REFERENCE_CHILD_PROPERTY_PREFIX: String = "@child"
// }
//}

View File

@ -12,13 +12,13 @@ import space.kscience.dataforge.meta.toDynamic
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.asName
import space.kscience.visionforge.ElementVisionRenderer import space.kscience.visionforge.ElementVisionRenderer
import space.kscience.visionforge.JsVisionClient
import space.kscience.visionforge.Vision import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionClient
import tabulator.Tabulator import tabulator.Tabulator
import tabulator.TabulatorFull import tabulator.TabulatorFull
public class TableVisionJsPlugin : AbstractPlugin(), ElementVisionRenderer { public class TableVisionJsPlugin : AbstractPlugin(), ElementVisionRenderer {
public val visionClient: VisionClient by require(VisionClient) public val visionClient: JsVisionClient by require(JsVisionClient)
public val tablesBase: TableVisionPlugin by require(TableVisionPlugin) public val tablesBase: TableVisionPlugin by require(TableVisionPlugin)
override val tag: PluginTag get() = Companion.tag override val tag: PluginTag get() = Companion.tag

View File

@ -123,8 +123,8 @@ public class ThreeCanvas(
element.appendChild(canvas) element.appendChild(canvas)
updateSize() updateSize()
canvas.addEventListener("pointerdown", { canvas.addEventListener("pointerdown", {
val picked = pick() val newPicked = pick()
options.onSelect?.invoke(picked?.fullName()) options.onSelect?.invoke(newPicked?.fullName())
}, false) }, false)
//Attach listener to track mouse changes //Attach listener to track mouse changes
@ -143,12 +143,12 @@ public class ThreeCanvas(
addControls(canvas, options.controls) addControls(canvas, options.controls)
renderer.setAnimationLoop { renderer.setAnimationLoop {
val picked = pick() val newPicked = pick()
if (picked != null && this.picked != picked) { if (newPicked != null && picked !== newPicked) {
this.picked?.toggleHighlight(false, HIGHLIGHT_NAME, HIGHLIGHT_MATERIAL) picked?.toggleHighlight(false, HIGHLIGHT_NAME, HIGHLIGHT_MATERIAL)
picked.toggleHighlight(true, HIGHLIGHT_NAME, HIGHLIGHT_MATERIAL) newPicked.toggleHighlight(true, HIGHLIGHT_NAME, HIGHLIGHT_MATERIAL)
this.picked = picked picked = newPicked
} }
renderer.render(scene, camera) renderer.render(scene, camera)
@ -326,7 +326,7 @@ public class ThreeCanvas(
public val HIGHLIGHT_MATERIAL: MeshLineMaterial = MeshLineMaterial().apply { public val HIGHLIGHT_MATERIAL: MeshLineMaterial = MeshLineMaterial().apply {
color.set(Colors.blue) color.set(Colors.blue)
thickness = 2f thickness = 1f
cached = true cached = true
} }
// //

View File

@ -7,12 +7,10 @@ import org.w3c.dom.HTMLElement
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.names.* import space.kscience.dataforge.names.*
import space.kscience.visionforge.ElementVisionRenderer import space.kscience.visionforge.*
import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionChildren
import space.kscience.visionforge.solid.* import space.kscience.visionforge.solid.*
import space.kscience.visionforge.solid.specifications.Canvas3DOptions import space.kscience.visionforge.solid.specifications.Canvas3DOptions
import space.kscience.visionforge.visible import space.kscience.visionforge.solid.three.set
import three.core.Object3D import three.core.Object3D
import kotlin.collections.set import kotlin.collections.set
import kotlin.reflect.KClass import kotlin.reflect.KClass
@ -23,6 +21,8 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
public val solids: Solids by require(Solids) public val solids: Solids by require(Solids)
public val client: VisionClient? get() = context.plugins.get<VisionClient>()
private val objectFactories = HashMap<KClass<out Solid>, ThreeFactory<*>>() private val objectFactories = HashMap<KClass<out Solid>, ThreeFactory<*>>()
private val compositeFactory = ThreeCompositeFactory(this) private val compositeFactory = ThreeCompositeFactory(this)
@ -90,6 +90,8 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
val child = vision.children.getChild(childName) val child = vision.children.getChild(childName)
logger.debug { "Changing vision $childName to $child" }
//removing old object //removing old object
findChild(childName)?.let { oldChild -> findChild(childName)?.let { oldChild ->
oldChild.parent?.remove(oldChild) oldChild.parent?.remove(oldChild)