0.2.0 #71

Merged
altavir merged 139 commits from dev into master 2022-01-24 09:44:18 +03:00
43 changed files with 382 additions and 323 deletions
Showing only changes of commit 5721bb9456 - Show all commits

View File

@ -2,14 +2,13 @@ plugins {
id("ru.mipt.npm.gradle.project") id("ru.mipt.npm.gradle.project")
} }
val dataforgeVersion by extra("0.5.0-dev-10") val dataforgeVersion by extra("0.5.0-dev-11")
val fxVersion by extra("11") val fxVersion by extra("11")
allprojects { allprojects {
repositories { repositories {
mavenLocal() mavenLocal()
mavenCentral() mavenCentral()
jcenter()
maven("https://repo.kotlin.link") maven("https://repo.kotlin.link")
maven("https://maven.jzy3d.org/releases") maven("https://maven.jzy3d.org/releases")
} }

View File

@ -4,27 +4,36 @@ import space.kscience.dataforge.names.Name
import space.kscience.dataforge.values.asValue import space.kscience.dataforge.values.asValue
import space.kscience.dataforge.values.string import space.kscience.dataforge.values.string
import space.kscience.gdml.GdmlShowCase import space.kscience.gdml.GdmlShowCase
import space.kscience.visionforge.Vision
import space.kscience.visionforge.computeProperties
import space.kscience.visionforge.get
import space.kscience.visionforge.setProperty import space.kscience.visionforge.setProperty
import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.SolidMaterial import space.kscience.visionforge.solid.SolidMaterial
import space.kscience.visionforge.solid.material
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertNotNull import kotlin.test.assertNotNull
class GDMLVisionTest { class GDMLVisionTest {
private val cubes = GdmlShowCase.cubes().toVision()
// @Test @Test
// fun testCubesStyles(){ fun testCubesStyles(){
// val cubes = gdml.toVision() val segment = cubes["composite-000.segment-0"] as Solid
// val segment = cubes["composite000.segment_0".toName()] as Solid println(segment.computeProperties().getValue(Vision.STYLE_KEY))
// println(segment.styles) // println(segment.computePropertyNode(SolidMaterial.MATERIAL_KEY))
// println(segment.material) // println(segment.computeProperty(SolidMaterial.MATERIAL_COLOR_KEY))
// }
println(segment.material?.meta)
//println(Solids.encodeToString(cubes))
}
@Test @Test
fun testPrototypeProperty() { fun testPrototypeProperty() {
val vision = GdmlShowCase.cubes().toVision() val child = cubes[Name.of("composite-000","segment-0")]
val child = vision[Name.of("composite-000","segment-0")]
assertNotNull(child) assertNotNull(child)
child.setProperty(SolidMaterial.MATERIAL_COLOR_KEY, "red".asValue()) child.setProperty(SolidMaterial.MATERIAL_COLOR_KEY, "red".asValue())
assertEquals("red", child.getPropertyValue(SolidMaterial.MATERIAL_COLOR_KEY)?.string) assertEquals("red", child.getPropertyValue(SolidMaterial.MATERIAL_COLOR_KEY)?.string)

View File

@ -7,7 +7,6 @@ import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.fetch import space.kscience.dataforge.context.fetch
import space.kscience.gdml.GdmlShowCase import space.kscience.gdml.GdmlShowCase
import space.kscience.visionforge.VisionManager import space.kscience.visionforge.VisionManager
import space.kscience.visionforge.computeProperties
import space.kscience.visionforge.editor.VisionEditorFragment import space.kscience.visionforge.editor.VisionEditorFragment
import space.kscience.visionforge.editor.VisionTreeFragment import space.kscience.visionforge.editor.VisionTreeFragment
import space.kscience.visionforge.gdml.toVision import space.kscience.visionforge.gdml.toVision
@ -33,9 +32,7 @@ class GDMLView : View() {
this.itemProperty.bind(canvas.rootObjectProperty) this.itemProperty.bind(canvas.rootObjectProperty)
} }
private val propertyEditor = VisionEditorFragment { private val propertyEditor = VisionEditorFragment().apply {
it.computeProperties()
}.apply {
descriptorProperty.set(SolidMaterial.descriptor) descriptorProperty.set(SolidMaterial.descriptor)
visionProperty.bind(treeFragment.selectedProperty) visionProperty.bind(treeFragment.selectedProperty)
} }

View File

@ -28,6 +28,7 @@ class Model(val manager: VisionManager) {
private fun SolidGroup.detector(detector: SC16) { private fun SolidGroup.detector(detector: SC16) {
group(detector.name) { group(detector.name) {
position = detector.center
detector.pixels.forEach { detector.pixels.forEach {
pixel(it) pixel(it)
} }
@ -38,6 +39,10 @@ class Model(val manager: VisionManager) {
val root: SolidGroup = SolidGroup().apply { val root: SolidGroup = SolidGroup().apply {
root(this@Model.manager) root(this@Model.manager)
material {
wireframe
color("darkgreen")
}
rotationX = PI / 2 rotationX = PI / 2
group("bottom") { group("bottom") {
Monitor.detectors.filter { it.center.z == LOWER_LAYER_Z }.forEach { Monitor.detectors.filter { it.center.z == LOWER_LAYER_Z }.forEach {

View File

@ -3,7 +3,6 @@ package ru.mipt.npm.muon.monitor
import ru.mipt.npm.muon.monitor.Monitor.PIXEL_XY_SIZE import ru.mipt.npm.muon.monitor.Monitor.PIXEL_XY_SIZE
import ru.mipt.npm.muon.monitor.Monitor.PIXEL_Z_SIZE import ru.mipt.npm.muon.monitor.Monitor.PIXEL_Z_SIZE
import space.kscience.visionforge.solid.Point3D import space.kscience.visionforge.solid.Point3D
import space.kscience.visionforge.solid.plus
/** /**
* A single pixel * A single pixel
@ -98,7 +97,7 @@ class SC16(
} }
val offset = Point3D(-y, x, 0)//rotateDetector(Point3D(x, y, 0.0)); val offset = Point3D(-y, x, 0)//rotateDetector(Point3D(x, y, 0.0));
val pixelName = "${name}_${index}" val pixelName = "${name}_${index}"
SC1(pixelName, center + offset) SC1(pixelName, offset)
} }
} }
} }

View File

@ -2,6 +2,7 @@ package ru.mipt.npm.muon.monitor
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.request.get import io.ktor.client.request.get
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.css.* import kotlinx.css.*
@ -23,6 +24,7 @@ import space.kscience.visionforge.react.flexColumn
import space.kscience.visionforge.react.visionTree import space.kscience.visionforge.react.visionTree
import space.kscience.visionforge.solid.specifications.Camera import space.kscience.visionforge.solid.specifications.Camera
import space.kscience.visionforge.solid.specifications.Canvas3DOptions import space.kscience.visionforge.solid.specifications.Canvas3DOptions
import space.kscience.visionforge.solid.three.edges
import styled.css import styled.css
import styled.styledDiv import styled.styledDiv
import kotlin.math.PI import kotlin.math.PI
@ -34,6 +36,7 @@ external interface MMAppProps : RProps {
var selected: Name? var selected: Name?
} }
@OptIn(DelicateCoroutinesApi::class)
@JsExport @JsExport
val MMApp = functionalComponent<MMAppProps>("Muon monitor") { props -> val MMApp = functionalComponent<MMAppProps>("Muon monitor") { props ->
var selected by useState { props.selected } var selected by useState { props.selected }
@ -53,7 +56,9 @@ val MMApp = functionalComponent<MMAppProps>("Muon monitor") { props ->
} }
} }
val root = props.model.root val root = props.model.root.apply {
edges()
}
gridRow { gridRow {
flexColumn { flexColumn {

View File

@ -7,18 +7,15 @@ import kotlinx.browser.document
import react.child import react.child
import react.dom.render import react.dom.render
import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.Global
import space.kscience.dataforge.context.fetch import space.kscience.dataforge.context.fetch
import space.kscience.visionforge.Application import space.kscience.visionforge.Application
import space.kscience.visionforge.VisionManager import space.kscience.visionforge.VisionManager
import space.kscience.visionforge.bootstrap.useBootstrap import space.kscience.visionforge.bootstrap.useBootstrap
import space.kscience.visionforge.solid.three.ThreePlugin
import space.kscience.visionforge.startApplication import space.kscience.visionforge.startApplication
private class MMDemoApp : Application { private class MMDemoApp : Application {
private val visionManager = Global.fetch(VisionManager)
private val model = Model(visionManager)
private val connection = HttpClient { private val connection = HttpClient {
install(JsonFeature) { install(JsonFeature) {
serializer = KotlinxSerializer() serializer = KotlinxSerializer()
@ -28,13 +25,18 @@ private class MMDemoApp : Application {
override fun start(state: Map<String, Any>) { override fun start(state: Map<String, Any>) {
useBootstrap() useBootstrap()
val element = document.getElementById("app") ?: error("Element with id 'app' not found on page") val context = Context("MM-demo"){
plugin(ThreePlugin)
}
val visionManager = context.fetch(VisionManager)
val context = Context("demo") val model = Model(visionManager)
val element = document.getElementById("app") ?: error("Element with id 'app' not found on page")
render(element) { render(element) {
child(MMApp) { child(MMApp) {
attrs { attrs {
this.model = this@MMDemoApp.model this.model = model
this.connection = this@MMDemoApp.connection this.connection = this@MMDemoApp.connection
this.context = context this.context = context
} }

View File

@ -19,7 +19,7 @@ fun VisionLayout<Solid>.demo(name: String, title: String = name, block: SolidGro
"title" put title "title" put title
} }
val vision = SolidGroup(block) val vision = SolidGroup(block)
render(Name.parse(name), vision) render(Name.parse(name), vision, meta)
} }
val canvasOptions = Canvas3DOptions { val canvasOptions = Canvas3DOptions {
@ -36,6 +36,7 @@ val canvasOptions = Canvas3DOptions {
} }
} }
@OptIn(DelicateCoroutinesApi::class)
fun VisionLayout<Solid>.showcase() { fun VisionLayout<Solid>.showcase() {
demo("shapes", "Basic shapes") { demo("shapes", "Basic shapes") {
box(100.0, 100.0, 100.0) { box(100.0, 100.0, 100.0) {

View File

@ -14,7 +14,7 @@ class FXDemoApp : App(FXDemoGrid::class) {
stage.height = 600.0 stage.height = 600.0
view.showcase() view.showcase()
view.showcaseCSG() //view.showcaseCSG()
} }
} }

View File

@ -1,7 +1,6 @@
package space.kscience.visionforge.demo package space.kscience.visionforge.demo
import javafx.geometry.Orientation import javafx.geometry.Orientation
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.descriptors.node import space.kscience.dataforge.meta.descriptors.node
@ -46,12 +45,12 @@ class MetaEditorDemo : View("Meta editor demo") {
} }
} }
private val rootNode = FXMetaModel.root(meta, descriptor) private val rootNode:FXMetaModel<MutableMeta> = FXMetaModel.root(meta, descriptor)
override val root = splitpane( override val root = splitpane(
Orientation.HORIZONTAL, Orientation.HORIZONTAL,
MetaViewer(rootNode as Meta).root, MetaViewer(rootNode).root,
MutableMetaEditor(rootNode as FXMetaModel<MutableMeta>).root MutableMetaEditor(rootNode).root
) )
} }

View File

@ -12,9 +12,9 @@ import org.w3c.files.BlobPropertyBag
import react.* import react.*
import react.dom.attrs import react.dom.attrs
import react.dom.button import react.dom.button
import space.kscience.dataforge.meta.descriptors.defaultNode
import space.kscience.dataforge.meta.withDefault import space.kscience.dataforge.meta.withDefault
import space.kscience.visionforge.Vision import space.kscience.visionforge.Vision
import space.kscience.visionforge.encodeToString
import space.kscience.visionforge.react.flexColumn import space.kscience.visionforge.react.flexColumn
import space.kscience.visionforge.react.flexRow import space.kscience.visionforge.react.flexRow
import space.kscience.visionforge.react.propertyEditor import space.kscience.visionforge.react.propertyEditor
@ -51,12 +51,12 @@ public val CanvasControls: FunctionComponent<CanvasControlsProps> = functionalCo
border(1.px, BorderStyle.solid, Color.blue) border(1.px, BorderStyle.solid, Color.blue)
padding(4.px) padding(4.px)
} }
props.vision?.manager?.let { manager -> props.vision?.let{ vision ->
button { button {
+"Export" +"Export"
attrs { attrs {
onClickFunction = { onClickFunction = {
val json = manager.encodeToString(props.vision!!) val json = vision.encodeToString()
saveData(it, "object.json", "text/json") { saveData(it, "object.json", "text/json") {
json json
} }

View File

@ -21,7 +21,7 @@ public external interface ThreeControlsProps : RProps {
} }
@JsExport @JsExport
public val ThreeControls: FunctionalComponent<ThreeControlsProps> = functionalComponent { props -> public val ThreeControls: FunctionComponent<ThreeControlsProps> = functionalComponent { props ->
tabPane(if (props.selected != null) "Properties" else null) { tabPane(if (props.selected != null) "Properties" else null) {
tab("Canvas") { tab("Canvas") {
card("Canvas configuration") { card("Canvas configuration") {

View File

@ -9,7 +9,6 @@ import react.dom.a
import react.dom.attrs import react.dom.attrs
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.descriptors.defaultNode
import space.kscience.dataforge.meta.descriptors.get import space.kscience.dataforge.meta.descriptors.get
import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.isLeaf import space.kscience.dataforge.meta.isLeaf

View File

@ -121,7 +121,7 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
}?.forEach { }?.forEach {
add(NameToken(it.key)) add(NameToken(it.key))
} }
ownProperty?.items?.keys?.filterNot { it.body.startsWith("@") }?.let { addAll(it) } //ownProperty?.items?.keys?.filterNot { it.body.startsWith("@") }?.let { addAll(it) }
} }
flexRow { flexRow {

View File

@ -15,7 +15,6 @@ import react.dom.button
import ringui.Island import ringui.Island
import ringui.SmartTabs import ringui.SmartTabs
import ringui.Tab import ringui.Tab
import space.kscience.dataforge.meta.descriptors.defaultNode
import space.kscience.dataforge.meta.withDefault import space.kscience.dataforge.meta.withDefault
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.visionforge.Vision import space.kscience.visionforge.Vision

View File

@ -1,53 +1,84 @@
package space.kscience.visionforge package space.kscience.visionforge
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.ObservableMutableMeta
import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.descriptors.get import space.kscience.dataforge.meta.descriptors.get
import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.get
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.NameToken import space.kscience.dataforge.names.NameToken
import space.kscience.dataforge.names.plus import space.kscience.dataforge.names.plus
import space.kscience.dataforge.values.MutableValueProvider
import space.kscience.dataforge.values.Value import space.kscience.dataforge.values.Value
private class ComputedVisionProperties( private class ComputedVisionProperties(
public val vision: Vision, val vision: Vision,
public val rootName: Name, val pathName: Name,
public val visionDescriptor: MetaDescriptor val visionDescriptor: MetaDescriptor,
) : ObservableMutableMeta by vision.meta { val parentInheritFlag: Boolean?,
val parentStylesFlag: Boolean?
) : Meta {
public val descriptor: MetaDescriptor? = visionDescriptor[rootName] val descriptor: MetaDescriptor? by lazy { visionDescriptor[pathName] }
override val items: Map<NameToken, ObservableMutableMeta> override val items: Map<NameToken, Meta>
get() { get() {
val metaKeys = vision.meta.items.keys val metaKeys = vision.meta.getMeta(pathName)?.items?.keys ?: emptySet()
val descriptorKeys = descriptor?.children?.map { NameToken(it.key) } ?: emptySet() val descriptorKeys = descriptor?.children?.map { NameToken(it.key) } ?: emptySet()
return (metaKeys + descriptorKeys).associateWith { getMeta(rootName + it) } val inheritFlag = descriptor?.inherited ?: parentInheritFlag
val stylesFlag = descriptor?.usesStyles ?: parentStylesFlag
return (metaKeys + descriptorKeys).associateWith {
ComputedVisionProperties(
vision,
pathName + it,
visionDescriptor,
inheritFlag,
stylesFlag
)
}
} }
override var value: Value? override val value: Value?
get() { get() {
val inheritFlag = descriptor?.inherited ?: false val inheritFlag = descriptor?.inherited ?: parentInheritFlag ?: false
val stylesFlag = descriptor?.usesStyles ?: true val stylesFlag = descriptor?.usesStyles ?: parentStylesFlag ?: true
return vision.getPropertyValue(rootName, inheritFlag, stylesFlag, true) return vision.getPropertyValue(pathName, inheritFlag, stylesFlag, true)
}
set(value) {
vision.meta.setValue(rootName, value)
} }
override fun getMeta(name: Name): ObservableMutableMeta = override fun toString(): String = Meta.toString(this)
ComputedVisionProperties(vision, rootName + name, visionDescriptor) override fun equals(other: Any?): Boolean = Meta.equals(this, other as? Meta)
override fun hashCode(): Int = Meta.hashCode(this)
override fun getOrCreate(name: Name): ObservableMutableMeta = getMeta(name)
override fun toMeta(): Meta = this
} }
/** /**
* Compute property node based on inheritance and style information from the descriptor * Compute property node based on inheritance and style information from the descriptor
*/ */
public fun Vision.computeProperties(descriptor: MetaDescriptor? = this.descriptor): ObservableMutableMeta = public fun Vision.computeProperties(descriptor: MetaDescriptor? = this.descriptor): Meta =
if (descriptor == null) meta else ComputedVisionProperties(this, Name.EMPTY, descriptor) if (descriptor == null) meta else ComputedVisionProperties(this, Name.EMPTY, descriptor, null, null)
public fun Vision.computePropertyNode(
name: Name,
descriptor: MetaDescriptor? = this.descriptor
): Meta? = computeProperties(descriptor)[name]
/**
* Compute the property based on the provided value descriptor. By default, use Vision own descriptor
*/
public fun Vision.computeProperty(name: Name, valueDescriptor: MetaDescriptor? = descriptor?.get(name)): Value? {
val inheritFlag = valueDescriptor?.inherited ?: false
val stylesFlag = valueDescriptor?.usesStyles ?: true
return getPropertyValue(name, inheritFlag, stylesFlag)
}
/**
* Accessor to all vision properties
*/
public fun Vision.computePropertyValues(
descriptor: MetaDescriptor? = this.descriptor
): MutableValueProvider = object : MutableValueProvider {
override fun getValue(name: Name): Value? = computeProperty(name, descriptor?.get(name))
override fun setValue(name: Name, value: Value?) {
setProperty(name, value)
}
}
public fun Vision.computePropertyNode(name: Name, descriptor: MetaDescriptor? = this.descriptor): ObservableMutableMeta? =
computeProperties(descriptor)[name]

View File

@ -7,6 +7,7 @@ import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.plus import space.kscience.dataforge.names.plus
import space.kscience.dataforge.values.Value import space.kscience.dataforge.values.Value
import space.kscience.dataforge.values.asValue import space.kscience.dataforge.values.asValue
import space.kscience.dataforge.values.stringList
import kotlin.jvm.JvmInline import kotlin.jvm.JvmInline
/** /**
@ -72,7 +73,7 @@ internal fun Vision.styleChanged(key: String, oldStyle: Meta?, newStyle: Meta?)
* List of names of styles applied to this object. Order matters. Not inherited. * List of names of styles applied to this object. Order matters. Not inherited.
*/ */
public var Vision.styles: List<String> public var Vision.styles: List<String>
get() = meta.getMeta(Vision.STYLE_KEY)?.stringList ?: emptyList() get() = meta.getValue(Vision.STYLE_KEY)?.stringList ?: emptyList()
set(value) { set(value) {
meta.setValue(Vision.STYLE_KEY, value.map { it.asValue() }.asValue()) meta.setValue(Vision.STYLE_KEY, value.map { it.asValue() }.asValue())
} }
@ -105,7 +106,7 @@ public fun Vision.getStyleProperty(name: Name): Value? = styles.firstNotNullOfOr
/** /**
* Resolve an item in all style layers * Resolve an item in all style layers
*/ */
public fun Vision.getStyleItems(name: Name): List<Meta> = styles.mapNotNull { public fun Vision.getStyleNodes(name: Name): List<Meta> = styles.mapNotNull {
getStyle(it)?.get(name) getStyle(it)?.get(name)
} }

View File

@ -7,7 +7,6 @@ import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.ObservableMutableMeta import space.kscience.dataforge.meta.ObservableMutableMeta
import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.descriptors.defaultNode
import space.kscience.dataforge.meta.descriptors.value import space.kscience.dataforge.meta.descriptors.value
import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.get
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.DFExperimental
@ -30,9 +29,11 @@ internal data class MetaListener(
@SerialName("vision") @SerialName("vision")
public open class VisionBase( public open class VisionBase(
@Transient override var parent: VisionGroup? = null, @Transient override var parent: VisionGroup? = null,
protected var properties: MutableMeta? = null
) : Vision { ) : Vision {
@Transient
protected open var properties: MutableMeta? = null
@Synchronized @Synchronized
protected fun getOrCreateProperties(): MutableMeta { protected fun getOrCreateProperties(): MutableMeta {
if (properties == null) { if (properties == null) {
@ -45,50 +46,55 @@ public open class VisionBase(
@Transient @Transient
private val listeners = HashSet<MetaListener>() private val listeners = HashSet<MetaListener>()
private inner class VisionBaseProperties(val rootName: Name) : ObservableMutableMeta { private inner class VisionProperties(val pathName: Name) : ObservableMutableMeta {
override val items: Map<NameToken, ObservableMutableMeta> override val items: Map<NameToken, ObservableMutableMeta>
get() = properties?.get(rootName)?.items?.mapValues { entry -> get() = properties?.get(pathName)?.items?.mapValues { entry ->
VisionBaseProperties(rootName + entry.key) VisionProperties(pathName + entry.key)
} ?: emptyMap() } ?: emptyMap()
override var value: Value? override var value: Value?
get() = properties?.get(rootName)?.value get() = properties?.get(pathName)?.value
set(value) { set(value) {
getOrCreateProperties().setValue(rootName, value) val oldValue = properties?.get(pathName)?.value
getOrCreateProperties().setValue(pathName, value)
if (oldValue != value) {
invalidate(Name.EMPTY)
}
} }
override fun getOrCreate(name: Name): ObservableMutableMeta = VisionBaseProperties(this.rootName + name) override fun getOrCreate(name: Name): ObservableMutableMeta = VisionProperties(pathName + name)
override fun setMeta(name: Name, node: Meta?) { override fun setMeta(name: Name, node: Meta?) {
getOrCreateProperties().setMeta(name, node) getOrCreateProperties().setMeta(pathName + name, node)
invalidate(name)
} }
@DFExperimental @DFExperimental
override fun attach(name: Name, node: ObservableMutableMeta) { override fun attach(name: Name, node: ObservableMutableMeta) {
val ownProperties = getOrCreateProperties() val ownProperties = getOrCreateProperties()
if (ownProperties is ObservableMutableMeta) { if (ownProperties is ObservableMutableMeta) {
ownProperties.attach(rootName + name, node) ownProperties.attach(pathName + name, node)
} else { } else {
ownProperties.setMeta(rootName + name, node) ownProperties.setMeta(pathName + name, node)
node.onChange(this) { childName -> node.onChange(this) { childName ->
ownProperties.setMeta(rootName + name + childName, this[childName]) ownProperties.setMeta(pathName + name + childName, this[childName])
} }
} }
} }
override fun invalidate(name: Name) { override fun invalidate(name: Name) {
invalidateProperty(rootName + name) invalidateProperty(pathName + name)
} }
@Synchronized @Synchronized
override fun onChange(owner: Any?, callback: Meta.(name: Name) -> Unit) { override fun onChange(owner: Any?, callback: Meta.(name: Name) -> Unit) {
if (rootName.isEmpty()) { if (pathName.isEmpty()) {
listeners.add((MetaListener(owner, callback))) listeners.add((MetaListener(owner, callback)))
} else { } else {
listeners.add(MetaListener(owner) { name -> listeners.add(MetaListener(owner) { name ->
if (name.startsWith(rootName)) { if (name.startsWith(pathName)) {
(get(rootName) ?: Meta.EMPTY).callback(name.removeHeadOrNull(rootName)!!) (this@MetaListener[pathName] ?: Meta.EMPTY).callback(name.removeHeadOrNull(pathName)!!)
} }
}) })
} }
@ -104,7 +110,7 @@ public open class VisionBase(
override fun hashCode(): Int = Meta.hashCode(this) override fun hashCode(): Int = Meta.hashCode(this)
} }
override val meta: ObservableMutableMeta get() = VisionBaseProperties(Name.EMPTY) override val meta: ObservableMutableMeta get() = VisionProperties(Name.EMPTY)
override fun getPropertyValue( override fun getPropertyValue(
name: Name, name: Name,

View File

@ -4,6 +4,9 @@ import kotlinx.coroutines.flow.Flow
import space.kscience.dataforge.names.* import space.kscience.dataforge.names.*
import space.kscience.dataforge.provider.Provider import space.kscience.dataforge.provider.Provider
@DslMarker
public annotation class VisionBuilder
public interface VisionContainer<out V : Vision> { public interface VisionContainer<out V : Vision> {
public operator fun get(name: Name): V? public operator fun get(name: Name): V?
} }

View File

@ -1,17 +0,0 @@
package space.kscience.visionforge
import space.kscience.dataforge.meta.Laminate
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.isLeaf
@DslMarker
public annotation class VisionBuilder
public fun List<Meta?>.merge(): Meta? {
val first = firstOrNull { it != null }
return when {
first == null -> null
first.isLeaf -> first //fast search for first entry if it is value
else -> Laminate(filterNotNull()) //merge nodes if first encountered node is meta
}
}

View File

@ -7,20 +7,20 @@ import space.kscience.dataforge.values.asValue
private const val INHERITED_DESCRIPTOR_ATTRIBUTE = "inherited" private const val INHERITED_DESCRIPTOR_ATTRIBUTE = "inherited"
private const val STYLE_DESCRIPTOR_ATTRIBUTE = "useStyles" private const val STYLE_DESCRIPTOR_ATTRIBUTE = "useStyles"
public val MetaDescriptor.inherited: Boolean public val MetaDescriptor.inherited: Boolean?
get() = attributes[INHERITED_DESCRIPTOR_ATTRIBUTE].boolean ?: false get() = attributes[INHERITED_DESCRIPTOR_ATTRIBUTE].boolean
public var MetaDescriptorBuilder.inherited: Boolean public var MetaDescriptorBuilder.inherited: Boolean?
get() = attributes[INHERITED_DESCRIPTOR_ATTRIBUTE].boolean ?: false get() = attributes[INHERITED_DESCRIPTOR_ATTRIBUTE].boolean
set(value) = attributes.set(INHERITED_DESCRIPTOR_ATTRIBUTE, value) set(value) = attributes.set(INHERITED_DESCRIPTOR_ATTRIBUTE, value?.asValue())
public val MetaDescriptor.usesStyles: Boolean public val MetaDescriptor.usesStyles: Boolean?
get() = attributes[STYLE_DESCRIPTOR_ATTRIBUTE].boolean ?: true get() = attributes[STYLE_DESCRIPTOR_ATTRIBUTE].boolean
public var MetaDescriptorBuilder.usesStyles: Boolean public var MetaDescriptorBuilder.usesStyles: Boolean?
get() = attributes[STYLE_DESCRIPTOR_ATTRIBUTE].boolean ?: true get() = attributes[STYLE_DESCRIPTOR_ATTRIBUTE].boolean
set(value) = attributes.set(STYLE_DESCRIPTOR_ATTRIBUTE, value) set(value) = attributes.set(STYLE_DESCRIPTOR_ATTRIBUTE, value?.asValue())
public val MetaDescriptor.widget: Meta public val MetaDescriptor.widget: Meta
get() = attributes["widget"] ?: Meta.EMPTY get() = attributes["widget"] ?: Meta.EMPTY
@ -38,7 +38,7 @@ public val MetaDescriptor.widgetType: String?
get() = attributes["widget.type"].string get() = attributes["widget.type"].string
/** /**
* Extension property to access the "widget.type" key of [ValueDescriptor] * Extension property to access the "widget.type" key of [MetaDescriptorBuilder]
*/ */
public var MetaDescriptorBuilder.widgetType: String? public var MetaDescriptorBuilder.widgetType: String?
get() = attributes["widget.type"].string get() = attributes["widget.type"].string

View File

@ -12,9 +12,6 @@ import space.kscience.dataforge.names.Name
import space.kscience.visionforge.Vision import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionBase import space.kscience.visionforge.VisionBase
import space.kscience.visionforge.VisionManager import space.kscience.visionforge.VisionManager
import kotlin.collections.HashMap
import kotlin.collections.Map
import kotlin.collections.forEach
import kotlin.collections.set import kotlin.collections.set
import kotlin.test.Test import kotlin.test.Test

View File

@ -14,17 +14,10 @@ dependencies {
api("no.tornado:tornadofx:1.7.20") api("no.tornado:tornadofx:1.7.20")
api("de.jensd:fontawesomefx-fontawesome:4.7.0-11") {
exclude(group = "org.openjfx")
}
api("de.jensd:fontawesomefx-commons:11.0") {
exclude(group = "org.openjfx")
}
api("org.fxyz3d:fxyz3d:0.5.4") { api("org.fxyz3d:fxyz3d:0.5.4") {
exclude(module = "slf4j-simple") exclude(module = "slf4j-simple")
} }
api("org.jetbrains.kotlinx:kotlinx-coroutines-javafx:${ru.mipt.npm.gradle.KScienceVersions.coroutinesVersion}") api("org.jetbrains.kotlinx:kotlinx-coroutines-javafx:${ru.mipt.npm.gradle.KScienceVersions.coroutinesVersion}")
implementation("eu.mihosoft.vrl.jcsg:jcsg:0.5.7") { implementation("eu.mihosoft.vrl.jcsg:jcsg:0.5.7") {

View File

@ -21,23 +21,29 @@ import tornadofx.*
public class FXMetaModel<M : Meta>( public class FXMetaModel<M : Meta>(
public val root: M, public val root: M,
public val rootDescriptor: MetaDescriptor?, public val rootDescriptor: MetaDescriptor?,
public val nodeName: Name, public val defaultRoot: Meta?,
public val title: String = nodeName.lastOrNull()?.toString() ?: "Meta" public val pathName: Name,
public val title: String = pathName.lastOrNull()?.toString() ?: "Meta"
) : Comparable<FXMetaModel<*>> { ) : Comparable<FXMetaModel<*>> {
private val existingNode = object: ObjectBinding<Meta?>() { private val existingNode = object: ObjectBinding<Meta?>() {
override fun computeValue(): Meta? =root[nodeName] override fun computeValue(): Meta? = root[pathName]
} }
private val defaultNode: Meta? get() = defaultRoot?.getMeta(pathName)
public val descriptor: MetaDescriptor? = rootDescriptor?.get(pathName)
public val children: ListBinding<FXMetaModel<M>> = object : ListBinding<FXMetaModel<M>>() { public val children: ListBinding<FXMetaModel<M>> = object : ListBinding<FXMetaModel<M>>() {
override fun computeValue(): ObservableList<FXMetaModel<M>> { override fun computeValue(): ObservableList<FXMetaModel<M>> {
val nodeKeys = existingNode.get()?.items?.keys?: emptySet() val nodeKeys = existingNode.get()?.items?.keys?: emptySet()
val descriptorKeys = descriptor?.children?.keys?.map { NameToken(it) } ?: emptySet() val defaultKeys = defaultNode?.items?.keys ?: emptySet()
return (nodeKeys + descriptorKeys).map { return (nodeKeys + defaultKeys).map {
FXMetaModel( FXMetaModel(
root, root,
rootDescriptor, rootDescriptor,
nodeName + it defaultRoot,
pathName + it
) )
}.filter(filter).asObservable() }.filter(filter).asObservable()
} }
@ -47,16 +53,14 @@ public class FXMetaModel<M : Meta>(
//add listener to the root node if possible //add listener to the root node if possible
if (root is ObservableMeta) { if (root is ObservableMeta) {
root.onChange(this) { changed -> root.onChange(this) { changed ->
if (changed.startsWith(nodeName)) { if (changed.startsWith(pathName)) {
if (nodeName.length == changed.length) existingNode.invalidate() if (pathName.length == changed.length) existingNode.invalidate()
else if (changed.length == nodeName.length + 1) children.invalidate() else if (changed.length == pathName.length + 1) children.invalidate()
} }
} }
} }
} }
public val descriptor: MetaDescriptor? = rootDescriptor?.get(nodeName)
public val existsProperty: BooleanBinding = existingNode.isNotNull public val existsProperty: BooleanBinding = existingNode.isNotNull
public val exists: Boolean by existsProperty public val exists: Boolean by existsProperty
@ -66,7 +70,7 @@ public class FXMetaModel<M : Meta>(
} }
override fun compareTo(other: FXMetaModel<*>): Int = if (this.exists == other.exists) { override fun compareTo(other: FXMetaModel<*>): Int = if (this.exists == other.exists) {
this.nodeName.toString().compareTo(other.nodeName.toString()) this.pathName.toString().compareTo(other.pathName.toString())
} else { } else {
this.exists.compareTo(other.exists) this.exists.compareTo(other.exists)
} }
@ -79,7 +83,8 @@ public class FXMetaModel<M : Meta>(
public fun <M : Meta> root( public fun <M : Meta> root(
node: M, node: M,
descriptor: MetaDescriptor? = null, descriptor: MetaDescriptor? = null,
defaultRoot: Meta? = null,
rootName: String = "root" rootName: String = "root"
): FXMetaModel<M> = FXMetaModel(node, descriptor, Name.EMPTY, title = rootName) ): FXMetaModel<M> = FXMetaModel(node, descriptor, defaultRoot, Name.EMPTY, title = rootName)
} }
} }

View File

@ -26,14 +26,12 @@ import space.kscience.visionforge.dfIconView
import tornadofx.* import tornadofx.*
public class MetaViewer( public class MetaViewer(
private val rootNode: FXMetaModel<Meta>, private val rootNode: FXMetaModel<out Meta>,
title: String = "Meta viewer" title: String = "Meta viewer"
) : Fragment(title, dfIconView) { ) : Fragment(title, dfIconView) {
public constructor(meta: Meta, title: String = "Meta viewer") : this( public constructor(meta: Meta, title: String = "Meta viewer") : this(
FXMetaModel.root( FXMetaModel.root(meta), title = title
meta
), title = title
) )
override val root: BorderPane = borderpane { override val root: BorderPane = borderpane {

View File

@ -13,7 +13,6 @@ import javafx.scene.paint.Color
import javafx.scene.text.Text import javafx.scene.text.Text
import space.kscience.dataforge.context.Global import space.kscience.dataforge.context.Global
import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.remove import space.kscience.dataforge.meta.remove
import space.kscience.visionforge.dfIconView import space.kscience.visionforge.dfIconView
import tornadofx.* import tornadofx.*
@ -25,16 +24,16 @@ import tornadofx.*
*/ */
public class MutableMetaEditor( public class MutableMetaEditor(
public val rootNode: FXMetaModel<MutableMeta>, public val rootNode: FXMetaModel<MutableMeta>,
public val allowNew: Boolean = true, //public val allowNew: Boolean = true,
title: String = "Configuration editor" title: String = "Meta editor"
) : Fragment(title = title, icon = dfIconView) { ) : Fragment(title = title, icon = dfIconView) {
//TODO replace parameters by properties //TODO replace parameters by properties
//
public constructor( // public constructor(
MutableMeta: MutableMeta, // MutableMeta: MutableMeta,
descriptor: MetaDescriptor?, // descriptor: MetaDescriptor?,
title: String = "Configuration editor" // title: String = "Configuration editor"
) : this(FXMetaModel.root(MutableMeta, descriptor = descriptor), title = title) // ) : this(FXMetaModel.root(MutableMeta, descriptor = descriptor), title = title)
override val root: BorderPane = borderpane { override val root: BorderPane = borderpane {
center = treetableview<FXMetaModel<MutableMeta>> { center = treetableview<FXMetaModel<MutableMeta>> {
@ -65,7 +64,7 @@ public class MutableMetaEditor(
contextmenu { contextmenu {
item("Remove") { item("Remove") {
action { action {
content.root.remove(content.nodeName) content.root.remove(content.pathName)
} }
} }
} }
@ -128,7 +127,7 @@ public class MutableMetaEditor(
item.valueProperty, item.valueProperty,
item.descriptor item.descriptor
) { value -> ) { value ->
item.root.setValue(item.nodeName, value) item.root.setValue(item.pathName, value)
} }
graphic = chooser.node graphic = chooser.node

View File

@ -5,31 +5,40 @@ import javafx.beans.property.SimpleObjectProperty
import javafx.scene.Node import javafx.scene.Node
import javafx.scene.Parent import javafx.scene.Parent
import javafx.scene.layout.VBox import javafx.scene.layout.VBox
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.ObservableMutableMeta import space.kscience.dataforge.meta.ObservableMutableMeta
import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.names.Name
import space.kscience.visionforge.Vision import space.kscience.visionforge.Vision
import space.kscience.visionforge.computeProperties import space.kscience.visionforge.computeProperties
import space.kscience.visionforge.getStyle import space.kscience.visionforge.getStyle
import space.kscience.visionforge.styles import space.kscience.visionforge.styles
import tornadofx.* import tornadofx.*
public class VisionEditorFragment(public val selector: (Vision) -> ObservableMutableMeta = {it.computeProperties()}) : Fragment() { public class VisionEditorFragment : Fragment() {
public val visionProperty: SimpleObjectProperty<Vision> = SimpleObjectProperty<Vision>() public val visionProperty: SimpleObjectProperty<Vision> = SimpleObjectProperty<Vision>()
public var vision: Vision? by visionProperty public var vision: Vision? by visionProperty
public val descriptorProperty: SimpleObjectProperty<MetaDescriptor> = SimpleObjectProperty<MetaDescriptor>() public val descriptorProperty: SimpleObjectProperty<MetaDescriptor> = SimpleObjectProperty<MetaDescriptor>()
private val configProperty: Binding<ObservableMutableMeta?> = visionProperty.objectBinding { vision -> private val configProperty: Binding<ObservableMutableMeta?> = visionProperty.objectBinding { vision ->
vision?.let(selector) vision?.meta
} }
private val configEditorProperty: Binding<Node?> = configProperty.objectBinding(descriptorProperty) { private val configEditorProperty: Binding<Node?> = configProperty.objectBinding(descriptorProperty) {
it?.let { it?.let { meta ->
MutableMetaEditor(it, descriptorProperty.get()).root val node:FXMetaModel<MutableMeta> = FXMetaModel(
meta,
vision?.descriptor,
vision?.computeProperties(),
Name.EMPTY,
"Vision properties"
)
MutableMetaEditor(node).root
} }
} }
private val styleBoxProperty: Binding<Node?> = configProperty.objectBinding() { private val styleBoxProperty: Binding<Node?> = configProperty.objectBinding {
VBox().apply { VBox().apply {
vision?.styles?.forEach { styleName -> vision?.styles?.forEach { styleName ->
val styleMeta = vision?.getStyle(styleName) val styleMeta = vision?.getStyle(styleName)

View File

@ -24,7 +24,7 @@ import kotlin.collections.set
import kotlin.math.PI import kotlin.math.PI
import kotlin.reflect.KClass import kotlin.reflect.KClass
class FX3DPlugin : AbstractPlugin() { public class FX3DPlugin : AbstractPlugin() {
override val tag: PluginTag get() = Companion.tag override val tag: PluginTag get() = Companion.tag
private val objectFactories = HashMap<KClass<out Solid>, FX3DFactory<*>>() private val objectFactories = HashMap<KClass<out Solid>, FX3DFactory<*>>()
@ -43,7 +43,7 @@ class FX3DPlugin : AbstractPlugin() {
as FX3DFactory<Solid>? as FX3DFactory<Solid>?
} }
fun buildNode(obj: Solid): Node { public fun buildNode(obj: Solid): Node {
val binding = VisualObjectFXBinding(this, obj) val binding = VisualObjectFXBinding(this, obj)
return when (obj) { return when (obj) {
is SolidReferenceGroup -> referenceFactory(obj, binding) is SolidReferenceGroup -> referenceFactory(obj, binding)

View File

@ -37,8 +37,7 @@ public object FXMaterials {
* Infer color based on meta item * Infer color based on meta item
* @param opacity default opacity * @param opacity default opacity
*/ */
public fun Meta.color(opacity: Double = 1.0): Color { public fun Meta.color(opacity: Double = 1.0): Color = value?.let {
return value?.let {
if (it.type == ValueType.NUMBER) { if (it.type == ValueType.NUMBER) {
val int = it.int val int = it.int
val red = int and 0x00ff0000 shr 16 val red = int and 0x00ff0000 shr 16
@ -54,7 +53,6 @@ public fun Meta.color(opacity: Double = 1.0): Color {
this[Colors.BLUE_KEY]?.int ?: 0, this[Colors.BLUE_KEY]?.int ?: 0,
this[SolidMaterial.OPACITY_KEY]?.double ?: opacity this[SolidMaterial.OPACITY_KEY]?.double ?: opacity
) )
}
/** /**
* Infer FX material based on meta item * Infer FX material based on meta item

View File

@ -10,7 +10,7 @@ import space.kscience.visionforge.Vision
import space.kscience.visionforge.onPropertyChange import space.kscience.visionforge.onPropertyChange
import kotlin.reflect.KClass import kotlin.reflect.KClass
class FXReferenceFactory(val plugin: FX3DPlugin) : FX3DFactory<SolidReferenceGroup> { public class FXReferenceFactory(public val plugin: FX3DPlugin) : FX3DFactory<SolidReferenceGroup> {
override val type: KClass<in SolidReferenceGroup> get() = SolidReferenceGroup::class override val type: KClass<in SolidReferenceGroup> get() = SolidReferenceGroup::class
override fun invoke(obj: SolidReferenceGroup, binding: VisualObjectFXBinding): Node { override fun invoke(obj: SolidReferenceGroup, binding: VisualObjectFXBinding): Node {

View File

@ -441,20 +441,6 @@ private class GdmlTransformerEnv(val settings: GdmlTransformer) {
} }
final.useStyle(rootStyle) final.useStyle(rootStyle)
//inline prototypes
// referenceStore.forEach { (protoName, list) ->
// val proxy = list.singleOrNull() ?: return@forEach
// val parent = proxy.parent as? MutableVisionGroup ?: return@forEach
// val token = parent.children.entries.find { it.value == proxy }?.key ?: error("Inconsistent reference cache")
// val prototype = proto[protoName] as? Solid ?: error("Inconsistent reference cache")
// prototype.parent = null
// parent[token] = prototype
// prototype.updateFrom(proxy)
//
// //FIXME update prototype
// proto[protoName] = null
// }
final.prototypes { final.prototypes {
proto.children.forEach { (token, item) -> proto.children.forEach { (token, item) ->
item.parent = null item.parent = null

View File

@ -15,7 +15,6 @@ public class VisionOfPlotly private constructor() : VisionBase() {
public constructor(plot: Plot) : this() { public constructor(plot: Plot) : this() {
properties = plot.meta properties = plot.meta
} }
public val plot: Plot get() = Plot(meta) public val plot: Plot get() = Plot(meta)
} }

View File

@ -1,28 +1,27 @@
package space.kscience.visionforge.solid package space.kscience.visionforge.solid
import space.kscience.dataforge.meta.*
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.plus
import space.kscience.dataforge.values.MutableValueProvider
import space.kscience.dataforge.values.Value import space.kscience.dataforge.values.Value
import space.kscience.dataforge.values.asValue import space.kscience.dataforge.values.asValue
import space.kscience.dataforge.values.string import space.kscience.dataforge.values.string
import space.kscience.visionforge.Colors import space.kscience.visionforge.Colors
import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionBuilder import space.kscience.visionforge.VisionBuilder
import space.kscience.visionforge.VisionPropertyContainer
import kotlin.jvm.JvmInline
@VisionBuilder @VisionBuilder
public class ColorAccessor(private val colorKey: Name, private val parent: () -> MutableMetaProvider) { public class ColorAccessor(private val provider: MutableValueProvider, private val colorKey: Name) :
MutableValueProvider {
public var value: Value? public var value: Value?
get() = parent().getMeta(colorKey)?.value get() = provider.getValue(colorKey)
set(value) { set(value) {
parent().setValue(colorKey,value) provider.setValue(colorKey, value)
} }
public var item: Meta? override fun getValue(name: Name): Value? = provider.getValue(colorKey + name)
get() = parent().getMeta(colorKey)
set(value) { override fun setValue(name: Name, value: Value?) {
parent().setMeta(colorKey,value) provider.setValue(colorKey + name, value)
} }
} }

View File

@ -2,9 +2,10 @@ package space.kscience.visionforge.solid
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import space.kscience.dataforge.meta.configure
import space.kscience.dataforge.meta.update import space.kscience.dataforge.meta.update
import space.kscience.visionforge.* import space.kscience.visionforge.VisionBuilder
import space.kscience.visionforge.VisionContainerBuilder
import space.kscience.visionforge.set
public enum class CompositeType { public enum class CompositeType {
SUM, // Dumb sum of meshes SUM, // Dumb sum of meshes
@ -30,34 +31,38 @@ public inline fun VisionContainerBuilder<Solid>.composite(
val group = SolidGroup().apply(builder) val group = SolidGroup().apply(builder)
val children = group.children.values.filterIsInstance<Solid>() val children = group.children.values.filterIsInstance<Solid>()
if (children.size != 2) error("Composite requires exactly two children") if (children.size != 2) error("Composite requires exactly two children")
return Composite(type, children[0], children[1]).apply { val res = Composite(type, children[0], children[1])
configure {
update(group.meta) res.meta.update(group.meta)
}
if (group.position != null) { if (group.position != null) {
position = group.position res.position = group.position
} }
if (group.rotation != null) { if (group.rotation != null) {
rotation = group.rotation res.rotation = group.rotation
} }
if (group.scale != null) { if (group.scale != null) {
scale = group.scale res.scale = group.scale
}
set(name, this)
} }
set(name, res)
return res
} }
@VisionBuilder @VisionBuilder
public inline fun VisionContainerBuilder<Solid>.union(name: String? = null, builder: SolidGroup.() -> Unit): Composite = public inline fun VisionContainerBuilder<Solid>.union(
composite(CompositeType.UNION, name, builder = builder) name: String? = null,
builder: SolidGroup.() -> Unit
): Composite = composite(CompositeType.UNION, name, builder = builder)
@VisionBuilder @VisionBuilder
public inline fun VisionContainerBuilder<Solid>.subtract(name: String? = null, builder: SolidGroup.() -> Unit): Composite = public inline fun VisionContainerBuilder<Solid>.subtract(
composite(CompositeType.SUBTRACT, name, builder = builder) name: String? = null,
builder: SolidGroup.() -> Unit
): Composite = composite(CompositeType.SUBTRACT, name, builder = builder)
@VisionBuilder @VisionBuilder
public inline fun VisionContainerBuilder<Solid>.intersect( public inline fun VisionContainerBuilder<Solid>.intersect(
name: String? = null, name: String? = null,
builder: SolidGroup.() -> Unit, builder: SolidGroup.() -> Unit,
): Composite = ): Composite = composite(CompositeType.INTERSECT, name, builder = builder)
composite(CompositeType.INTERSECT, name, builder = builder)

View File

@ -2,6 +2,7 @@ package space.kscience.visionforge.solid
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.visionforge.VisionBase import space.kscience.visionforge.VisionBase
import space.kscience.visionforge.VisionChange import space.kscience.visionforge.VisionChange
@ -9,6 +10,9 @@ import space.kscience.visionforge.VisionChange
@Serializable @Serializable
@SerialName("solid") @SerialName("solid")
public open class SolidBase : VisionBase(), Solid { public open class SolidBase : VisionBase(), Solid {
//FIXME to be removed after https://github.com/Kotlin/kotlinx.serialization/issues/1602 fix
override var properties: MutableMeta? = null
override val descriptor: MetaDescriptor get() = Solid.descriptor override val descriptor: MetaDescriptor get() = Solid.descriptor
override fun update(change: VisionChange) { override fun update(change: VisionChange) {

View File

@ -2,6 +2,7 @@ package space.kscience.visionforge.solid
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.NameToken import space.kscience.dataforge.names.NameToken
@ -31,6 +32,9 @@ public interface PrototypeHolder {
@SerialName("group.solid") @SerialName("group.solid")
public class SolidGroup : VisionGroupBase(), Solid, PrototypeHolder { public class SolidGroup : VisionGroupBase(), Solid, PrototypeHolder {
//FIXME to be removed after https://github.com/Kotlin/kotlinx.serialization/issues/1602 fix
override var properties: MutableMeta? = null
override val children: Map<NameToken, Vision> get() = super.childrenInternal.filter { it.key != PROTOTYPES_TOKEN } override val children: Map<NameToken, Vision> get() = super.childrenInternal.filter { it.key != PROTOTYPES_TOKEN }
private var prototypes: MutableVisionGroup? private var prototypes: MutableVisionGroup?

View File

@ -20,14 +20,14 @@ public class SolidMaterial : Scheme() {
/** /**
* Primary web-color for the material * Primary web-color for the material
*/ */
public val color: ColorAccessor = ColorAccessor(COLOR_KEY) { meta } public val color: ColorAccessor = ColorAccessor(meta, COLOR_KEY)
/** /**
* Specular color for phong material * Specular color for phong material
*/ */
public val specularColor: ColorAccessor = ColorAccessor(SPECULAR_COLOR_KEY) { meta } public val specularColor: ColorAccessor = ColorAccessor(meta, SPECULAR_COLOR_KEY)
public val emissiveColor: ColorAccessor = ColorAccessor("emissiveColor".asName()) { meta } public val emissiveColor: ColorAccessor = ColorAccessor(meta, "emissiveColor".asName())
/** /**
* Opacity * Opacity
@ -55,33 +55,29 @@ public class SolidMaterial : Scheme() {
//must be lazy to avoid initialization bug //must be lazy to avoid initialization bug
MetaDescriptor { MetaDescriptor {
inherited = true inherited = true
usesStyles = true
value(COLOR_KEY, ValueType.STRING, ValueType.NUMBER) { value(COLOR_KEY, ValueType.STRING, ValueType.NUMBER) {
inherited = true inherited = true
usesStyles = true
widgetType = "color" widgetType = "color"
} }
value(SPECULAR_COLOR_KEY, ValueType.STRING, ValueType.NUMBER) { value(SPECULAR_COLOR_KEY, ValueType.STRING, ValueType.NUMBER) {
inherited = true inherited = true
usesStyles = true
widgetType = "color" widgetType = "color"
hide() hide()
} }
value(OPACITY_KEY, ValueType.NUMBER) { value(OPACITY_KEY, ValueType.NUMBER) {
inherited = true inherited = true
usesStyles = true
default(1.0) default(1.0)
attributes["min"] = 0.0 attributes["min"] = 0.0
attributes["max"] = 1.0 attributes["max"] = 1.0
attributes["step"] = 0.1 attributes["step"] = 0.1
widgetType = "slider" widgetType = "slider"
} }
value(WIREFRAME_KEY, ValueType.BOOLEAN) { value(WIREFRAME_KEY, ValueType.BOOLEAN) {
inherited = true inherited = true
usesStyles = true
default(false) default(false)
} }
} }
@ -90,7 +86,7 @@ public class SolidMaterial : Scheme() {
} }
public val Solid.color: ColorAccessor public val Solid.color: ColorAccessor
get() = ColorAccessor(MATERIAL_COLOR_KEY) { computeProperties() } get() = ColorAccessor(computePropertyValues(), MATERIAL_COLOR_KEY)
public var Solid.material: SolidMaterial? public var Solid.material: SolidMaterial?
get() = computePropertyNode(MATERIAL_KEY)?.let { SolidMaterial.read(it) } get() = computePropertyNode(MATERIAL_KEY)?.let { SolidMaterial.read(it) }

View File

@ -2,6 +2,7 @@ package space.kscience.visionforge.solid
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.ObservableMutableMeta import space.kscience.dataforge.meta.ObservableMutableMeta
import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.get
@ -12,11 +13,16 @@ import space.kscience.visionforge.*
public interface SolidReference : VisionGroup { public interface SolidReference : VisionGroup {
/** /**
* The prototype for this reference. Always returns a "real" prototype, not a reference * The prototype for this reference.
*/ */
public val prototype: Solid public val prototype: Solid
override fun getPropertyValue(name: Name, inherit: Boolean, includeStyles: Boolean, includeDefaults: Boolean): Value? { override fun getPropertyValue(
name: Name,
inherit: Boolean,
includeStyles: Boolean,
includeDefaults: Boolean
): Value? {
meta[name]?.value?.let { return it } meta[name]?.value?.let { return it }
if (includeStyles) { if (includeStyles) {
getStyleProperty(name)?.let { return it } getStyleProperty(name)?.let { return it }
@ -56,6 +62,8 @@ public class SolidReferenceGroup(
public val refName: Name, public val refName: Name,
) : VisionBase(), SolidReference, VisionGroup, Solid { ) : VisionBase(), SolidReference, VisionGroup, Solid {
override var properties: MutableMeta? = null
/** /**
* Recursively search for defined template in the parent * Recursively search for defined template in the parent
*/ */
@ -72,8 +80,12 @@ public class SolidReferenceGroup(
ReferenceChild(this, it.key.asName()) ReferenceChild(this, it.key.asName())
} ?: emptyMap() } ?: emptyMap()
override fun getPropertyValue(name: Name, inherit: Boolean, includeStyles: Boolean, includeDefaults: Boolean): Value? = override fun getPropertyValue(
super<SolidReference>.getPropertyValue(name, inherit, includeStyles, includeDefaults) name: Name,
inherit: Boolean,
includeStyles: Boolean,
includeDefaults: Boolean
): Value? = super<SolidReference>.getPropertyValue(name, inherit, includeStyles, includeDefaults)
override val descriptor: MetaDescriptor get() = prototype.descriptor override val descriptor: MetaDescriptor get() = prototype.descriptor
@ -88,11 +100,14 @@ public class SolidReferenceGroup(
) : SolidReference, VisionGroup, Solid { ) : SolidReference, VisionGroup, Solid {
override val prototype: Solid by lazy { override val prototype: Solid by lazy {
if (refName.isEmpty()) owner.prototype else { if (refName.isEmpty()) {
owner.prototype
} else {
val proto = (owner.prototype as? VisionGroup)?.get(refName) val proto = (owner.prototype as? VisionGroup)?.get(refName)
?: error("Prototype with name $refName not found in SolidReferenceGroup ${owner.refName}") ?: error("Prototype with name $refName not found in SolidReferenceGroup ${owner.refName}")
proto.unref as? Solid proto as? Solid ?: error("Prototype with name $refName is ${proto::class} but expected 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")
} }
} }

View File

@ -1,6 +1,7 @@
package space.kscience.visionforge.solid package space.kscience.visionforge.solid
import space.kscience.dataforge.meta.* import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.string
import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.asName
import space.kscience.dataforge.values.int import space.kscience.dataforge.values.int
import space.kscience.visionforge.* import space.kscience.visionforge.*
@ -10,13 +11,32 @@ import kotlin.test.assertEquals
@Suppress("UNUSED_VARIABLE") @Suppress("UNUSED_VARIABLE")
class PropertyTest { class PropertyTest {
@Test @Test
fun testColorUpdate(){ fun testColor(){
val box = Box(10.0f, 10.0f,10.0f) val box = Box(10.0f, 10.0f,10.0f)
box.material { box.material {
//meta["color"] = "pink" //meta["color"] = "pink"
color("pink") color("pink")
} }
assertEquals("pink", box.meta["material.color"]?.string) assertEquals("pink", box.meta["material.color"]?.string)
assertEquals("pink", box.color.string)
}
@Test
fun testColorUpdate(){
val box = Box(10.0f, 10.0f,10.0f)
var c: String? = null
box.onPropertyChange {
if(it == SolidMaterial.MATERIAL_COLOR_KEY){
c = box.color.string
}
}
box.material {
color("pink")
}
assertEquals("pink", c)
} }
@Test @Test

View File

@ -4,17 +4,20 @@ import info.laht.threekt.core.BufferGeometry
import info.laht.threekt.geometries.EdgesGeometry import info.laht.threekt.geometries.EdgesGeometry
import info.laht.threekt.objects.LineSegments import info.laht.threekt.objects.LineSegments
import info.laht.threekt.objects.Mesh import info.laht.threekt.objects.Mesh
import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.updateWith
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.dataforge.names.plus import space.kscience.dataforge.names.plus
import space.kscience.dataforge.names.startsWith import space.kscience.dataforge.names.startsWith
import space.kscience.dataforge.values.boolean import space.kscience.dataforge.values.boolean
import space.kscience.visionforge.computeProperties import space.kscience.visionforge.computePropertyNode
import space.kscience.visionforge.onPropertyChange import space.kscience.visionforge.onPropertyChange
import space.kscience.visionforge.setProperty
import space.kscience.visionforge.solid.Solid import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.SolidMaterial import space.kscience.visionforge.solid.SolidMaterial
import space.kscience.visionforge.solid.layer import space.kscience.visionforge.solid.layer
import space.kscience.visionforge.solid.three.MeshThreeFactory.Companion.EDGES_ENABLED_KEY
import space.kscience.visionforge.solid.three.MeshThreeFactory.Companion.EDGES_MATERIAL_KEY
import kotlin.reflect.KClass import kotlin.reflect.KClass
/** /**
@ -62,6 +65,7 @@ public abstract class MeshThreeFactory<in T : Solid>(
public companion object { public companion object {
public val EDGES_KEY: Name = "edges".asName() public val EDGES_KEY: Name = "edges".asName()
//public val WIREFRAME_KEY: Name = "wireframe".asName() //public val WIREFRAME_KEY: Name = "wireframe".asName()
public val ENABLED_KEY: Name = "enabled".asName() public val ENABLED_KEY: Name = "enabled".asName()
public val EDGES_ENABLED_KEY: Name = EDGES_KEY + ENABLED_KEY public val EDGES_ENABLED_KEY: Name = EDGES_KEY + ENABLED_KEY
@ -71,6 +75,11 @@ public abstract class MeshThreeFactory<in T : Solid>(
} }
} }
public fun Solid.edges(enabled: Boolean = true, block: SolidMaterial.() -> Unit = {}) {
setProperty(EDGES_ENABLED_KEY, enabled)
meta.getOrCreate(EDGES_MATERIAL_KEY).updateWith(SolidMaterial, block)
}
internal fun Mesh.applyProperties(obj: Solid): Mesh = apply { internal fun Mesh.applyProperties(obj: Solid): Mesh = apply {
updateMaterial(obj) updateMaterial(obj)
applyEdges(obj) applyEdges(obj)
@ -84,12 +93,9 @@ internal fun Mesh.applyProperties(obj: Solid): Mesh = apply {
public fun Mesh.applyEdges(obj: Solid) { public fun Mesh.applyEdges(obj: Solid) {
val edges = children.find { it.name == "@edges" } as? LineSegments val edges = children.find { it.name == "@edges" } as? LineSegments
//inherited edges definition, enabled by default //inherited edges definition, enabled by default
if (obj.getPropertyValue(MeshThreeFactory.EDGES_ENABLED_KEY, inherit = true, includeStyles = true)?.boolean != false) { if (obj.getPropertyValue(EDGES_ENABLED_KEY, inherit = true)?.boolean != false) {
val bufferGeometry = geometry as? BufferGeometry ?: return val bufferGeometry = geometry as? BufferGeometry ?: return
val material = ThreeMaterials.getLineMaterial( val material = ThreeMaterials.getLineMaterial(obj.computePropertyNode(EDGES_MATERIAL_KEY), true)
obj.computeProperties().get(MeshThreeFactory.EDGES_MATERIAL_KEY),
true
)
if (edges == null) { if (edges == null) {
add( add(
LineSegments( LineSegments(

View File

@ -12,7 +12,7 @@ import org.w3c.dom.CanvasTextBaseline
import org.w3c.dom.HTMLCanvasElement import org.w3c.dom.HTMLCanvasElement
import org.w3c.dom.MIDDLE import org.w3c.dom.MIDDLE
import space.kscience.visionforge.solid.SolidLabel import space.kscience.visionforge.solid.SolidLabel
import space.kscience.visionforge.solid.color import space.kscience.visionforge.solid.SolidMaterial
import space.kscience.visionforge.solid.three.ThreeCanvas.Companion.DO_NOT_HIGHLIGHT_TAG import space.kscience.visionforge.solid.three.ThreeCanvas.Companion.DO_NOT_HIGHLIGHT_TAG
import kotlin.reflect.KClass import kotlin.reflect.KClass
@ -26,7 +26,7 @@ public object ThreeCanvasLabelFactory : ThreeFactory<SolidLabel> {
val canvas = document.createElement("canvas") as HTMLCanvasElement val canvas = document.createElement("canvas") as HTMLCanvasElement
val context = canvas.getContext("2d") as CanvasRenderingContext2D val context = canvas.getContext("2d") as CanvasRenderingContext2D
context.font = "Bold ${obj.fontSize}pt ${obj.fontFamily}" context.font = "Bold ${obj.fontSize}pt ${obj.fontFamily}"
context.fillStyle = obj.color.value ?: "black" context.fillStyle = obj.getPropertyValue(SolidMaterial.MATERIAL_COLOR_KEY)?.value ?: "black"
context.textBaseline = CanvasTextBaseline.MIDDLE context.textBaseline = CanvasTextBaseline.MIDDLE
val metrics = context.measureText(obj.text) val metrics = context.measureText(obj.text)
//canvas.width = metrics.width.toInt() //canvas.width = metrics.width.toInt()

View File

@ -3,16 +3,21 @@ package space.kscience.visionforge.solid.three
import info.laht.threekt.materials.LineBasicMaterial import info.laht.threekt.materials.LineBasicMaterial
import info.laht.threekt.materials.Material import info.laht.threekt.materials.Material
import info.laht.threekt.materials.MeshBasicMaterial import info.laht.threekt.materials.MeshBasicMaterial
import info.laht.threekt.materials.MeshPhongMaterial
import info.laht.threekt.math.Color import info.laht.threekt.math.Color
import info.laht.threekt.objects.Mesh import info.laht.threekt.objects.Mesh
import space.kscience.dataforge.meta.* import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.boolean
import space.kscience.dataforge.meta.double
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName
import space.kscience.dataforge.values.* import space.kscience.dataforge.values.*
import space.kscience.visionforge.Colors import space.kscience.visionforge.Colors
import space.kscience.visionforge.Vision import space.kscience.visionforge.Vision
import space.kscience.visionforge.computePropertyNode import space.kscience.visionforge.computePropertyNode
import space.kscience.visionforge.getStyleNodes
import space.kscience.visionforge.solid.SolidMaterial import space.kscience.visionforge.solid.SolidMaterial
import space.kscience.visionforge.solid.SolidReference
public object ThreeMaterials { public object ThreeMaterials {
@ -56,44 +61,46 @@ public object ThreeMaterials {
private val materialCache = HashMap<Meta, Material>() private val materialCache = HashMap<Meta, Material>()
internal fun buildMaterial(meta: Meta): Material { internal fun buildMaterial(meta: Meta): Material = MeshBasicMaterial().apply {
val material = SolidMaterial.read(meta)
return meta[SolidMaterial.SPECULAR_COLOR_KEY]?.let { specularColor ->
MeshPhongMaterial().apply {
color = meta[SolidMaterial.COLOR_KEY]?.threeColor() ?: DEFAULT_COLOR
specular = specularColor.threeColor()
emissive = material.emissiveColor.item?.threeColor() ?: specular
reflectivity = 0.5
refractionRatio = 1.0
shininess = 100.0
opacity = meta[SolidMaterial.OPACITY_KEY]?.double ?: 1.0
transparent = opacity < 1.0
wireframe = meta[SolidMaterial.WIREFRAME_KEY].boolean ?: false
needsUpdate = true
}
} ?: MeshBasicMaterial().apply {
color = meta[SolidMaterial.COLOR_KEY]?.threeColor() ?: DEFAULT_COLOR color = meta[SolidMaterial.COLOR_KEY]?.threeColor() ?: DEFAULT_COLOR
opacity = meta[SolidMaterial.OPACITY_KEY]?.double ?: 1.0 opacity = meta[SolidMaterial.OPACITY_KEY]?.double ?: 1.0
transparent = opacity < 1.0 transparent = opacity < 1.0
wireframe = meta[SolidMaterial.WIREFRAME_KEY].boolean ?: false wireframe = meta[SolidMaterial.WIREFRAME_KEY].boolean ?: false
needsUpdate = true needsUpdate = true
} }
// val material = SolidMaterial.read(meta)
} // return meta[SolidMaterial.SPECULAR_COLOR_KEY]?.let { specularColor ->
// MeshPhongMaterial().apply {
// color = meta[SolidMaterial.COLOR_KEY]?.threeColor() ?: DEFAULT_COLOR
// specular = specularColor.threeColor()
// emissive = material.emissiveColor.threeColor() ?: specular
// reflectivity = 0.5
// refractionRatio = 1.0
// shininess = 100.0
// opacity = meta[SolidMaterial.OPACITY_KEY]?.double ?: 1.0
// transparent = opacity < 1.0
// wireframe = meta[SolidMaterial.WIREFRAME_KEY].boolean ?: false
// needsUpdate = true
// }
// } ?: MeshBasicMaterial().apply {
// color = meta[SolidMaterial.COLOR_KEY]?.threeColor() ?: DEFAULT_COLOR
// opacity = meta[SolidMaterial.OPACITY_KEY]?.double ?: 1.0
// transparent = opacity < 1.0
// wireframe = meta[SolidMaterial.WIREFRAME_KEY].boolean ?: false
// needsUpdate = true
// }
internal fun cacheMaterial(meta: Meta): Material = materialCache.getOrPut(meta) { internal fun cacheMaterial(meta: Meta): Material = materialCache.getOrPut(meta) {
buildMaterial(meta).apply { buildMaterial(meta).apply {
cached = true cached = true
} }
} }
} }
/** /**
* Infer color based on meta item * Compute color
*/ */
public fun Meta.threeColor(): Color { public fun Meta.threeColor(): Color = getValue(Name.EMPTY)?.let { value ->
return value?.let { value ->
if (value.type == ValueType.NUMBER) { if (value.type == ValueType.NUMBER) {
val int = value.int val int = value.int
Color(int) Color(int)
@ -101,11 +108,10 @@ public fun Meta.threeColor(): Color {
Color(value.string) Color(value.string)
} }
} ?: Color( } ?: Color(
this[Colors.RED_KEY]?.int ?: 0, getValue(Colors.RED_KEY.asName())?.int ?: 0,
this[Colors.GREEN_KEY]?.int ?: 0, getValue(Colors.GREEN_KEY.asName())?.int ?: 0,
this[Colors.BLUE_KEY]?.int ?: 0 getValue(Colors.BLUE_KEY.asName())?.int ?: 0
) )
}
private var Material.cached: Boolean private var Material.cached: Boolean
get() = userData["cached"] == true get() = userData["cached"] == true
@ -114,33 +120,21 @@ private var Material.cached: Boolean
} }
public fun Mesh.updateMaterial(vision: Vision) { public fun Mesh.updateMaterial(vision: Vision) {
//val meta = vision.getProperty(SolidMaterial.MATERIAL_KEY, inherit = true).node
val ownMaterialMeta = vision.meta.getMeta(SolidMaterial.MATERIAL_KEY) val ownMaterialMeta = vision.meta.getMeta(SolidMaterial.MATERIAL_KEY)
val parentMaterialMeta = vision.parent?.getPropertyValue( if (ownMaterialMeta == null) {
SolidMaterial.MATERIAL_KEY, if (vision is SolidReference && vision.getStyleNodes(SolidMaterial.MATERIAL_KEY).isEmpty()) {
inherit = true, updateMaterial(vision.prototype)
includeStyles = false, } else {
includeDefaults = false material = vision.computePropertyNode(SolidMaterial.MATERIAL_KEY)?.let {
)
material = when {
ownMaterialMeta == null && parentMaterialMeta == null -> {
//If material is style-based, use cached
vision.computePropertyNode(
SolidMaterial.MATERIAL_KEY,
)?.let {
ThreeMaterials.cacheMaterial(it) ThreeMaterials.cacheMaterial(it)
} ?: ThreeMaterials.DEFAULT } ?: ThreeMaterials.DEFAULT
} }
else -> { } else {
vision.computePropertyNode( material = vision.computePropertyNode(SolidMaterial.MATERIAL_KEY)?.let {
SolidMaterial.MATERIAL_KEY,
)?.let {
ThreeMaterials.buildMaterial(it) ThreeMaterials.buildMaterial(it)
} ?: ThreeMaterials.DEFAULT } ?: ThreeMaterials.DEFAULT
} }
} }
}
public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) { public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) {
if (material.cached || propertyName == SolidMaterial.MATERIAL_KEY) { if (material.cached || propertyName == SolidMaterial.MATERIAL_KEY) {
@ -149,17 +143,14 @@ public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) {
} else { } else {
when (propertyName) { when (propertyName) {
SolidMaterial.MATERIAL_COLOR_KEY -> { SolidMaterial.MATERIAL_COLOR_KEY -> {
material.asDynamic().color = vision.computePropertyNode( material.asDynamic().color = vision.computePropertyNode(SolidMaterial.MATERIAL_COLOR_KEY)?.threeColor()
SolidMaterial.MATERIAL_COLOR_KEY, ?: ThreeMaterials.DEFAULT_COLOR
)?.threeColor() ?: ThreeMaterials.DEFAULT_COLOR
material.needsUpdate = true material.needsUpdate = true
} }
SolidMaterial.MATERIAL_OPACITY_KEY -> { SolidMaterial.MATERIAL_OPACITY_KEY -> {
val opacity = vision.getPropertyValue( val opacity = vision.getPropertyValue(
SolidMaterial.MATERIAL_OPACITY_KEY, SolidMaterial.MATERIAL_OPACITY_KEY,
inherit = true, inherit = true,
includeStyles = true,
includeDefaults = false
)?.double ?: 1.0 )?.double ?: 1.0
material.opacity = opacity material.opacity = opacity
material.transparent = opacity < 1.0 material.transparent = opacity < 1.0
@ -169,8 +160,6 @@ public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) {
material.asDynamic().wireframe = vision.getPropertyValue( material.asDynamic().wireframe = vision.getPropertyValue(
SolidMaterial.MATERIAL_WIREFRAME_KEY, SolidMaterial.MATERIAL_WIREFRAME_KEY,
inherit = true, inherit = true,
includeStyles = true,
includeDefaults = false
)?.boolean ?: false )?.boolean ?: false
material.needsUpdate = true material.needsUpdate = true
} }

View File

@ -1,6 +1,5 @@
package space.kscience.visionforge.solid.three package space.kscience.visionforge.solid.three
import info.laht.threekt.core.BufferGeometry
import info.laht.threekt.core.Object3D import info.laht.threekt.core.Object3D
import info.laht.threekt.objects.Mesh import info.laht.threekt.objects.Mesh
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
@ -19,7 +18,7 @@ public object ThreeReferenceFactory : ThreeFactory<SolidReferenceGroup> {
private fun Object3D.replicate(): Object3D { private fun Object3D.replicate(): Object3D {
return when (this) { return when (this) {
is Mesh -> Mesh(geometry as BufferGeometry, material).also { is Mesh -> Mesh(geometry, material).also {
it.applyMatrix4(matrix) it.applyMatrix4(matrix)
} }
else -> clone(false) else -> clone(false)