A lot of fixes

This commit is contained in:
Alexander Nozik 2021-08-11 16:52:36 +03:00
parent 7b78052f61
commit 5721bb9456
43 changed files with 382 additions and 323 deletions

View File

@ -2,14 +2,13 @@ plugins {
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")
allprojects {
repositories {
mavenLocal()
mavenCentral()
jcenter()
maven("https://repo.kotlin.link")
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.string
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.solid.Solid
import space.kscience.visionforge.solid.SolidMaterial
import space.kscience.visionforge.solid.material
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
class GDMLVisionTest {
private val cubes = GdmlShowCase.cubes().toVision()
// @Test
// fun testCubesStyles(){
// val cubes = gdml.toVision()
// val segment = cubes["composite000.segment_0".toName()] as Solid
// println(segment.styles)
// println(segment.material)
// }
@Test
fun testCubesStyles(){
val segment = cubes["composite-000.segment-0"] as Solid
println(segment.computeProperties().getValue(Vision.STYLE_KEY))
// println(segment.computePropertyNode(SolidMaterial.MATERIAL_KEY))
// println(segment.computeProperty(SolidMaterial.MATERIAL_COLOR_KEY))
println(segment.material?.meta)
//println(Solids.encodeToString(cubes))
}
@Test
fun testPrototypeProperty() {
val vision = GdmlShowCase.cubes().toVision()
val child = vision[Name.of("composite-000","segment-0")]
val child = cubes[Name.of("composite-000","segment-0")]
assertNotNull(child)
child.setProperty(SolidMaterial.MATERIAL_COLOR_KEY, "red".asValue())
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.gdml.GdmlShowCase
import space.kscience.visionforge.VisionManager
import space.kscience.visionforge.computeProperties
import space.kscience.visionforge.editor.VisionEditorFragment
import space.kscience.visionforge.editor.VisionTreeFragment
import space.kscience.visionforge.gdml.toVision
@ -33,9 +32,7 @@ class GDMLView : View() {
this.itemProperty.bind(canvas.rootObjectProperty)
}
private val propertyEditor = VisionEditorFragment {
it.computeProperties()
}.apply {
private val propertyEditor = VisionEditorFragment().apply {
descriptorProperty.set(SolidMaterial.descriptor)
visionProperty.bind(treeFragment.selectedProperty)
}

View File

@ -28,6 +28,7 @@ class Model(val manager: VisionManager) {
private fun SolidGroup.detector(detector: SC16) {
group(detector.name) {
position = detector.center
detector.pixels.forEach {
pixel(it)
}
@ -38,6 +39,10 @@ class Model(val manager: VisionManager) {
val root: SolidGroup = SolidGroup().apply {
root(this@Model.manager)
material {
wireframe
color("darkgreen")
}
rotationX = PI / 2
group("bottom") {
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_Z_SIZE
import space.kscience.visionforge.solid.Point3D
import space.kscience.visionforge.solid.plus
/**
* A single pixel
@ -98,7 +97,7 @@ class SC16(
}
val offset = Point3D(-y, x, 0)//rotateDetector(Point3D(x, y, 0.0));
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.request.get
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.css.*
@ -23,6 +24,7 @@ import space.kscience.visionforge.react.flexColumn
import space.kscience.visionforge.react.visionTree
import space.kscience.visionforge.solid.specifications.Camera
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
import space.kscience.visionforge.solid.three.edges
import styled.css
import styled.styledDiv
import kotlin.math.PI
@ -34,6 +36,7 @@ external interface MMAppProps : RProps {
var selected: Name?
}
@OptIn(DelicateCoroutinesApi::class)
@JsExport
val MMApp = functionalComponent<MMAppProps>("Muon monitor") { props ->
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 {
flexColumn {

View File

@ -7,18 +7,15 @@ import kotlinx.browser.document
import react.child
import react.dom.render
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.Global
import space.kscience.dataforge.context.fetch
import space.kscience.visionforge.Application
import space.kscience.visionforge.VisionManager
import space.kscience.visionforge.bootstrap.useBootstrap
import space.kscience.visionforge.solid.three.ThreePlugin
import space.kscience.visionforge.startApplication
private class MMDemoApp : Application {
private val visionManager = Global.fetch(VisionManager)
private val model = Model(visionManager)
private val connection = HttpClient {
install(JsonFeature) {
serializer = KotlinxSerializer()
@ -28,13 +25,18 @@ private class MMDemoApp : Application {
override fun start(state: Map<String, Any>) {
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) {
child(MMApp) {
attrs {
this.model = this@MMDemoApp.model
this.model = model
this.connection = this@MMDemoApp.connection
this.context = context
}

View File

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

View File

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

View File

@ -1,7 +1,6 @@
package space.kscience.visionforge.demo
import javafx.geometry.Orientation
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
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(
Orientation.HORIZONTAL,
MetaViewer(rootNode as Meta).root,
MutableMetaEditor(rootNode as FXMetaModel<MutableMeta>).root
MetaViewer(rootNode).root,
MutableMetaEditor(rootNode).root
)
}

View File

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

View File

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

View File

@ -9,7 +9,6 @@ import react.dom.a
import react.dom.attrs
import space.kscience.dataforge.meta.Meta
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.get
import space.kscience.dataforge.meta.isLeaf

View File

@ -121,7 +121,7 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
}?.forEach {
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 {

View File

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

View File

@ -1,53 +1,84 @@
package space.kscience.visionforge
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.get
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.NameToken
import space.kscience.dataforge.names.plus
import space.kscience.dataforge.values.MutableValueProvider
import space.kscience.dataforge.values.Value
private class ComputedVisionProperties(
public val vision: Vision,
public val rootName: Name,
public val visionDescriptor: MetaDescriptor
) : ObservableMutableMeta by vision.meta {
val vision: Vision,
val pathName: Name,
val visionDescriptor: MetaDescriptor,
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() {
val metaKeys = vision.meta.items.keys
val metaKeys = vision.meta.getMeta(pathName)?.items?.keys ?: 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() {
val inheritFlag = descriptor?.inherited ?: false
val stylesFlag = descriptor?.usesStyles ?: true
return vision.getPropertyValue(rootName, inheritFlag, stylesFlag, true)
}
set(value) {
vision.meta.setValue(rootName, value)
val inheritFlag = descriptor?.inherited ?: parentInheritFlag ?: false
val stylesFlag = descriptor?.usesStyles ?: parentStylesFlag ?: true
return vision.getPropertyValue(pathName, inheritFlag, stylesFlag, true)
}
override fun getMeta(name: Name): ObservableMutableMeta =
ComputedVisionProperties(vision, rootName + name, visionDescriptor)
override fun getOrCreate(name: Name): ObservableMutableMeta = getMeta(name)
override fun toMeta(): Meta = this
override fun toString(): String = Meta.toString(this)
override fun equals(other: Any?): Boolean = Meta.equals(this, other as? Meta)
override fun hashCode(): Int = Meta.hashCode(this)
}
/**
* Compute property node based on inheritance and style information from the descriptor
*/
public fun Vision.computeProperties(descriptor: MetaDescriptor? = this.descriptor): ObservableMutableMeta =
if (descriptor == null) meta else ComputedVisionProperties(this, Name.EMPTY, descriptor)
public fun Vision.computeProperties(descriptor: MetaDescriptor? = this.descriptor): Meta =
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.values.Value
import space.kscience.dataforge.values.asValue
import space.kscience.dataforge.values.stringList
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.
*/
public var Vision.styles: List<String>
get() = meta.getMeta(Vision.STYLE_KEY)?.stringList ?: emptyList()
get() = meta.getValue(Vision.STYLE_KEY)?.stringList ?: emptyList()
set(value) {
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
*/
public fun Vision.getStyleItems(name: Name): List<Meta> = styles.mapNotNull {
public fun Vision.getStyleNodes(name: Name): List<Meta> = styles.mapNotNull {
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.ObservableMutableMeta
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.get
import space.kscience.dataforge.misc.DFExperimental
@ -30,9 +29,11 @@ internal data class MetaListener(
@SerialName("vision")
public open class VisionBase(
@Transient override var parent: VisionGroup? = null,
protected var properties: MutableMeta? = null
) : Vision {
@Transient
protected open var properties: MutableMeta? = null
@Synchronized
protected fun getOrCreateProperties(): MutableMeta {
if (properties == null) {
@ -45,50 +46,55 @@ public open class VisionBase(
@Transient
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>
get() = properties?.get(rootName)?.items?.mapValues { entry ->
VisionBaseProperties(rootName + entry.key)
get() = properties?.get(pathName)?.items?.mapValues { entry ->
VisionProperties(pathName + entry.key)
} ?: emptyMap()
override var value: Value?
get() = properties?.get(rootName)?.value
get() = properties?.get(pathName)?.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?) {
getOrCreateProperties().setMeta(name, node)
getOrCreateProperties().setMeta(pathName + name, node)
invalidate(name)
}
@DFExperimental
override fun attach(name: Name, node: ObservableMutableMeta) {
val ownProperties = getOrCreateProperties()
if (ownProperties is ObservableMutableMeta) {
ownProperties.attach(rootName + name, node)
ownProperties.attach(pathName + name, node)
} else {
ownProperties.setMeta(rootName + name, node)
ownProperties.setMeta(pathName + name, node)
node.onChange(this) { childName ->
ownProperties.setMeta(rootName + name + childName, this[childName])
ownProperties.setMeta(pathName + name + childName, this[childName])
}
}
}
override fun invalidate(name: Name) {
invalidateProperty(rootName + name)
invalidateProperty(pathName + name)
}
@Synchronized
override fun onChange(owner: Any?, callback: Meta.(name: Name) -> Unit) {
if (rootName.isEmpty()) {
if (pathName.isEmpty()) {
listeners.add((MetaListener(owner, callback)))
} else {
listeners.add(MetaListener(owner) { name ->
if (name.startsWith(rootName)) {
(get(rootName) ?: Meta.EMPTY).callback(name.removeHeadOrNull(rootName)!!)
if (name.startsWith(pathName)) {
(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 val meta: ObservableMutableMeta get() = VisionBaseProperties(Name.EMPTY)
override val meta: ObservableMutableMeta get() = VisionProperties(Name.EMPTY)
override fun getPropertyValue(
name: Name,

View File

@ -4,6 +4,9 @@ import kotlinx.coroutines.flow.Flow
import space.kscience.dataforge.names.*
import space.kscience.dataforge.provider.Provider
@DslMarker
public annotation class VisionBuilder
public interface VisionContainer<out V : Vision> {
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 STYLE_DESCRIPTOR_ATTRIBUTE = "useStyles"
public val MetaDescriptor.inherited: Boolean
get() = attributes[INHERITED_DESCRIPTOR_ATTRIBUTE].boolean ?: false
public val MetaDescriptor.inherited: Boolean?
get() = attributes[INHERITED_DESCRIPTOR_ATTRIBUTE].boolean
public var MetaDescriptorBuilder.inherited: Boolean
get() = attributes[INHERITED_DESCRIPTOR_ATTRIBUTE].boolean ?: false
set(value) = attributes.set(INHERITED_DESCRIPTOR_ATTRIBUTE, value)
public var MetaDescriptorBuilder.inherited: Boolean?
get() = attributes[INHERITED_DESCRIPTOR_ATTRIBUTE].boolean
set(value) = attributes.set(INHERITED_DESCRIPTOR_ATTRIBUTE, value?.asValue())
public val MetaDescriptor.usesStyles: Boolean
get() = attributes[STYLE_DESCRIPTOR_ATTRIBUTE].boolean ?: true
public val MetaDescriptor.usesStyles: Boolean?
get() = attributes[STYLE_DESCRIPTOR_ATTRIBUTE].boolean
public var MetaDescriptorBuilder.usesStyles: Boolean
get() = attributes[STYLE_DESCRIPTOR_ATTRIBUTE].boolean ?: true
set(value) = attributes.set(STYLE_DESCRIPTOR_ATTRIBUTE, value)
public var MetaDescriptorBuilder.usesStyles: Boolean?
get() = attributes[STYLE_DESCRIPTOR_ATTRIBUTE].boolean
set(value) = attributes.set(STYLE_DESCRIPTOR_ATTRIBUTE, value?.asValue())
public val MetaDescriptor.widget: Meta
get() = attributes["widget"] ?: Meta.EMPTY
@ -38,7 +38,7 @@ public val MetaDescriptor.widgetType: 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?
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.VisionBase
import space.kscience.visionforge.VisionManager
import kotlin.collections.HashMap
import kotlin.collections.Map
import kotlin.collections.forEach
import kotlin.collections.set
import kotlin.test.Test

View File

@ -14,17 +14,10 @@ dependencies {
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") {
exclude(module = "slf4j-simple")
}
api("org.jetbrains.kotlinx:kotlinx-coroutines-javafx:${ru.mipt.npm.gradle.KScienceVersions.coroutinesVersion}")
implementation("eu.mihosoft.vrl.jcsg:jcsg:0.5.7") {

View File

@ -21,23 +21,29 @@ import tornadofx.*
public class FXMetaModel<M : Meta>(
public val root: M,
public val rootDescriptor: MetaDescriptor?,
public val nodeName: Name,
public val title: String = nodeName.lastOrNull()?.toString() ?: "Meta"
public val defaultRoot: Meta?,
public val pathName: Name,
public val title: String = pathName.lastOrNull()?.toString() ?: "Meta"
) : Comparable<FXMetaModel<*>> {
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>>() {
override fun computeValue(): ObservableList<FXMetaModel<M>> {
val nodeKeys = existingNode.get()?.items?.keys?: emptySet()
val descriptorKeys = descriptor?.children?.keys?.map { NameToken(it) } ?: emptySet()
return (nodeKeys + descriptorKeys).map {
val defaultKeys = defaultNode?.items?.keys ?: emptySet()
return (nodeKeys + defaultKeys).map {
FXMetaModel(
root,
rootDescriptor,
nodeName + it
defaultRoot,
pathName + it
)
}.filter(filter).asObservable()
}
@ -47,16 +53,14 @@ public class FXMetaModel<M : Meta>(
//add listener to the root node if possible
if (root is ObservableMeta) {
root.onChange(this) { changed ->
if (changed.startsWith(nodeName)) {
if (nodeName.length == changed.length) existingNode.invalidate()
else if (changed.length == nodeName.length + 1) children.invalidate()
if (changed.startsWith(pathName)) {
if (pathName.length == changed.length) existingNode.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 exists: Boolean by existsProperty
@ -66,7 +70,7 @@ public class FXMetaModel<M : Meta>(
}
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 {
this.exists.compareTo(other.exists)
}
@ -79,7 +83,8 @@ public class FXMetaModel<M : Meta>(
public fun <M : Meta> root(
node: M,
descriptor: MetaDescriptor? = null,
defaultRoot: Meta? = null,
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.*
public class MetaViewer(
private val rootNode: FXMetaModel<Meta>,
private val rootNode: FXMetaModel<out Meta>,
title: String = "Meta viewer"
) : Fragment(title, dfIconView) {
public constructor(meta: Meta, title: String = "Meta viewer") : this(
FXMetaModel.root(
meta
), title = title
FXMetaModel.root(meta), title = title
)
override val root: BorderPane = borderpane {

View File

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

View File

@ -5,31 +5,40 @@ import javafx.beans.property.SimpleObjectProperty
import javafx.scene.Node
import javafx.scene.Parent
import javafx.scene.layout.VBox
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.ObservableMutableMeta
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.names.Name
import space.kscience.visionforge.Vision
import space.kscience.visionforge.computeProperties
import space.kscience.visionforge.getStyle
import space.kscience.visionforge.styles
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 var vision: Vision? by visionProperty
public val descriptorProperty: SimpleObjectProperty<MetaDescriptor> = SimpleObjectProperty<MetaDescriptor>()
private val configProperty: Binding<ObservableMutableMeta?> = visionProperty.objectBinding { vision ->
vision?.let(selector)
vision?.meta
}
private val configEditorProperty: Binding<Node?> = configProperty.objectBinding(descriptorProperty) {
it?.let {
MutableMetaEditor(it, descriptorProperty.get()).root
it?.let { meta ->
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 {
vision?.styles?.forEach { styleName ->
val styleMeta = vision?.getStyle(styleName)

View File

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

View File

@ -37,24 +37,22 @@ public object FXMaterials {
* Infer color based on meta item
* @param opacity default opacity
*/
public fun Meta.color(opacity: Double = 1.0): Color {
return value?.let {
if (it.type == ValueType.NUMBER) {
val int = it.int
val red = int and 0x00ff0000 shr 16
val green = int and 0x0000ff00 shr 8
val blue = int and 0x000000ff
Color.rgb(red, green, blue, opacity)
} else {
Color.web(it.string)
}
} ?: Color.rgb(
this[Colors.RED_KEY]?.int ?: 0,
this[Colors.GREEN_KEY]?.int ?: 0,
this[Colors.BLUE_KEY]?.int ?: 0,
this[SolidMaterial.OPACITY_KEY]?.double ?: opacity
)
}
public fun Meta.color(opacity: Double = 1.0): Color = value?.let {
if (it.type == ValueType.NUMBER) {
val int = it.int
val red = int and 0x00ff0000 shr 16
val green = int and 0x0000ff00 shr 8
val blue = int and 0x000000ff
Color.rgb(red, green, blue, opacity)
} else {
Color.web(it.string)
}
} ?: Color.rgb(
this[Colors.RED_KEY]?.int ?: 0,
this[Colors.GREEN_KEY]?.int ?: 0,
this[Colors.BLUE_KEY]?.int ?: 0,
this[SolidMaterial.OPACITY_KEY]?.double ?: opacity
)
/**
* Infer FX material based on meta item

View File

@ -10,7 +10,7 @@ import space.kscience.visionforge.Vision
import space.kscience.visionforge.onPropertyChange
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 fun invoke(obj: SolidReferenceGroup, binding: VisualObjectFXBinding): Node {

View File

@ -441,20 +441,6 @@ private class GdmlTransformerEnv(val settings: GdmlTransformer) {
}
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 {
proto.children.forEach { (token, item) ->
item.parent = null

View File

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

View File

@ -1,29 +1,28 @@
package space.kscience.visionforge.solid
import space.kscience.dataforge.meta.*
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.asValue
import space.kscience.dataforge.values.string
import space.kscience.visionforge.Colors
import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionBuilder
import space.kscience.visionforge.VisionPropertyContainer
import kotlin.jvm.JvmInline
@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?
get() = parent().getMeta(colorKey)?.value
get() = provider.getValue(colorKey)
set(value) {
parent().setValue(colorKey,value)
provider.setValue(colorKey, value)
}
public var item: Meta?
get() = parent().getMeta(colorKey)
set(value) {
parent().setMeta(colorKey,value)
}
override fun getValue(name: Name): Value? = provider.getValue(colorKey + name)
override fun setValue(name: Name, value: Value?) {
provider.setValue(colorKey + name, value)
}
}
public var ColorAccessor?.string: String?

View File

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

View File

@ -2,6 +2,7 @@ package space.kscience.visionforge.solid
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.visionforge.VisionBase
import space.kscience.visionforge.VisionChange
@ -9,6 +10,9 @@ import space.kscience.visionforge.VisionChange
@Serializable
@SerialName("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 fun update(change: VisionChange) {

View File

@ -2,6 +2,7 @@ package space.kscience.visionforge.solid
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.NameToken
@ -31,6 +32,9 @@ public interface PrototypeHolder {
@SerialName("group.solid")
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 }
private var prototypes: MutableVisionGroup?

View File

@ -20,14 +20,14 @@ public class SolidMaterial : Scheme() {
/**
* 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
*/
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
@ -55,33 +55,29 @@ public class SolidMaterial : Scheme() {
//must be lazy to avoid initialization bug
MetaDescriptor {
inherited = true
usesStyles = true
value(COLOR_KEY, ValueType.STRING, ValueType.NUMBER) {
inherited = true
usesStyles = true
widgetType = "color"
}
value(SPECULAR_COLOR_KEY, ValueType.STRING, ValueType.NUMBER) {
inherited = true
usesStyles = true
widgetType = "color"
hide()
}
value(OPACITY_KEY, ValueType.NUMBER) {
inherited = true
usesStyles = true
default(1.0)
attributes["min"] = 0.0
attributes["max"] = 1.0
attributes["step"] = 0.1
widgetType = "slider"
}
value(WIREFRAME_KEY, ValueType.BOOLEAN) {
inherited = true
usesStyles = true
default(false)
}
}
@ -90,7 +86,7 @@ public class SolidMaterial : Scheme() {
}
public val Solid.color: ColorAccessor
get() = ColorAccessor(MATERIAL_COLOR_KEY) { computeProperties() }
get() = ColorAccessor(computePropertyValues(), MATERIAL_COLOR_KEY)
public var Solid.material: SolidMaterial?
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.Serializable
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.ObservableMutableMeta
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.get
@ -12,11 +13,16 @@ import space.kscience.visionforge.*
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
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 }
if (includeStyles) {
getStyleProperty(name)?.let { return it }
@ -56,6 +62,8 @@ public class SolidReferenceGroup(
public val refName: Name,
) : VisionBase(), SolidReference, VisionGroup, Solid {
override var properties: MutableMeta? = null
/**
* Recursively search for defined template in the parent
*/
@ -72,8 +80,12 @@ public class SolidReferenceGroup(
ReferenceChild(this, it.key.asName())
} ?: emptyMap()
override fun getPropertyValue(name: Name, inherit: Boolean, includeStyles: Boolean, includeDefaults: Boolean): Value? =
super<SolidReference>.getPropertyValue(name, inherit, includeStyles, includeDefaults)
override fun getPropertyValue(
name: Name,
inherit: Boolean,
includeStyles: Boolean,
includeDefaults: Boolean
): Value? = super<SolidReference>.getPropertyValue(name, inherit, includeStyles, includeDefaults)
override val descriptor: MetaDescriptor get() = prototype.descriptor
@ -88,11 +100,14 @@ public class SolidReferenceGroup(
) : SolidReference, VisionGroup, Solid {
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)
?: error("Prototype with name $refName not found in SolidReferenceGroup ${owner.refName}")
proto.unref as? Solid
?: error("Prototype with name $refName is ${proto::class} but expected Solid")
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")
}
}

View File

@ -1,6 +1,7 @@
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.values.int
import space.kscience.visionforge.*
@ -10,13 +11,32 @@ import kotlin.test.assertEquals
@Suppress("UNUSED_VARIABLE")
class PropertyTest {
@Test
fun testColorUpdate(){
fun testColor(){
val box = Box(10.0f, 10.0f,10.0f)
box.material {
//meta["color"] = "pink"
color("pink")
}
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

View File

@ -4,17 +4,20 @@ import info.laht.threekt.core.BufferGeometry
import info.laht.threekt.geometries.EdgesGeometry
import info.laht.threekt.objects.LineSegments
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.asName
import space.kscience.dataforge.names.plus
import space.kscience.dataforge.names.startsWith
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.setProperty
import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.SolidMaterial
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
/**
@ -62,6 +65,7 @@ public abstract class MeshThreeFactory<in T : Solid>(
public companion object {
public val EDGES_KEY: Name = "edges".asName()
//public val WIREFRAME_KEY: Name = "wireframe".asName()
public val ENABLED_KEY: Name = "enabled".asName()
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 {
updateMaterial(obj)
applyEdges(obj)
@ -84,12 +93,9 @@ internal fun Mesh.applyProperties(obj: Solid): Mesh = apply {
public fun Mesh.applyEdges(obj: Solid) {
val edges = children.find { it.name == "@edges" } as? LineSegments
//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 material = ThreeMaterials.getLineMaterial(
obj.computeProperties().get(MeshThreeFactory.EDGES_MATERIAL_KEY),
true
)
val material = ThreeMaterials.getLineMaterial(obj.computePropertyNode(EDGES_MATERIAL_KEY), true)
if (edges == null) {
add(
LineSegments(

View File

@ -12,7 +12,7 @@ import org.w3c.dom.CanvasTextBaseline
import org.w3c.dom.HTMLCanvasElement
import org.w3c.dom.MIDDLE
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 kotlin.reflect.KClass
@ -26,7 +26,7 @@ public object ThreeCanvasLabelFactory : ThreeFactory<SolidLabel> {
val canvas = document.createElement("canvas") as HTMLCanvasElement
val context = canvas.getContext("2d") as CanvasRenderingContext2D
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
val metrics = context.measureText(obj.text)
//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.Material
import info.laht.threekt.materials.MeshBasicMaterial
import info.laht.threekt.materials.MeshPhongMaterial
import info.laht.threekt.math.Color
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.asName
import space.kscience.dataforge.values.*
import space.kscience.visionforge.Colors
import space.kscience.visionforge.Vision
import space.kscience.visionforge.computePropertyNode
import space.kscience.visionforge.getStyleNodes
import space.kscience.visionforge.solid.SolidMaterial
import space.kscience.visionforge.solid.SolidReference
public object ThreeMaterials {
@ -56,56 +61,57 @@ public object ThreeMaterials {
private val materialCache = HashMap<Meta, Material>()
internal fun buildMaterial(meta: Meta): Material {
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
opacity = meta[SolidMaterial.OPACITY_KEY]?.double ?: 1.0
transparent = opacity < 1.0
wireframe = meta[SolidMaterial.WIREFRAME_KEY].boolean ?: false
needsUpdate = true
}
internal fun buildMaterial(meta: Meta): Material = 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
}
// 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) {
buildMaterial(meta).apply {
cached = true
}
}
}
/**
* Infer color based on meta item
* Compute color
*/
public fun Meta.threeColor(): Color {
return value?.let { value ->
if (value.type == ValueType.NUMBER) {
val int = value.int
Color(int)
} else {
Color(value.string)
}
} ?: Color(
this[Colors.RED_KEY]?.int ?: 0,
this[Colors.GREEN_KEY]?.int ?: 0,
this[Colors.BLUE_KEY]?.int ?: 0
)
}
public fun Meta.threeColor(): Color = getValue(Name.EMPTY)?.let { value ->
if (value.type == ValueType.NUMBER) {
val int = value.int
Color(int)
} else {
Color(value.string)
}
} ?: Color(
getValue(Colors.RED_KEY.asName())?.int ?: 0,
getValue(Colors.GREEN_KEY.asName())?.int ?: 0,
getValue(Colors.BLUE_KEY.asName())?.int ?: 0
)
private var Material.cached: Boolean
get() = userData["cached"] == true
@ -114,31 +120,19 @@ private var Material.cached: Boolean
}
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 parentMaterialMeta = vision.parent?.getPropertyValue(
SolidMaterial.MATERIAL_KEY,
inherit = true,
includeStyles = false,
includeDefaults = false
)
material = when {
ownMaterialMeta == null && parentMaterialMeta == null -> {
//If material is style-based, use cached
vision.computePropertyNode(
SolidMaterial.MATERIAL_KEY,
)?.let {
if (ownMaterialMeta == null) {
if (vision is SolidReference && vision.getStyleNodes(SolidMaterial.MATERIAL_KEY).isEmpty()) {
updateMaterial(vision.prototype)
} else {
material = vision.computePropertyNode(SolidMaterial.MATERIAL_KEY)?.let {
ThreeMaterials.cacheMaterial(it)
} ?: ThreeMaterials.DEFAULT
}
else -> {
vision.computePropertyNode(
SolidMaterial.MATERIAL_KEY,
)?.let {
ThreeMaterials.buildMaterial(it)
} ?: ThreeMaterials.DEFAULT
}
} else {
material = vision.computePropertyNode(SolidMaterial.MATERIAL_KEY)?.let {
ThreeMaterials.buildMaterial(it)
} ?: ThreeMaterials.DEFAULT
}
}
@ -149,17 +143,14 @@ public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) {
} else {
when (propertyName) {
SolidMaterial.MATERIAL_COLOR_KEY -> {
material.asDynamic().color = vision.computePropertyNode(
SolidMaterial.MATERIAL_COLOR_KEY,
)?.threeColor() ?: ThreeMaterials.DEFAULT_COLOR
material.asDynamic().color = vision.computePropertyNode(SolidMaterial.MATERIAL_COLOR_KEY)?.threeColor()
?: ThreeMaterials.DEFAULT_COLOR
material.needsUpdate = true
}
SolidMaterial.MATERIAL_OPACITY_KEY -> {
val opacity = vision.getPropertyValue(
SolidMaterial.MATERIAL_OPACITY_KEY,
inherit = true,
includeStyles = true,
includeDefaults = false
)?.double ?: 1.0
material.opacity = opacity
material.transparent = opacity < 1.0
@ -169,8 +160,6 @@ public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) {
material.asDynamic().wireframe = vision.getPropertyValue(
SolidMaterial.MATERIAL_WIREFRAME_KEY,
inherit = true,
includeStyles = true,
includeDefaults = false
)?.boolean ?: false
material.needsUpdate = true
}

View File

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