A lot of fixes
This commit is contained in:
parent
7b78052f61
commit
5721bb9456
@ -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")
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -14,7 +14,7 @@ class FXDemoApp : App(FXDemoGrid::class) {
|
||||
stage.height = 600.0
|
||||
|
||||
view.showcase()
|
||||
view.showcaseCSG()
|
||||
//view.showcaseCSG()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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") {
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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]
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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?
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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") {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -37,8 +37,7 @@ 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 {
|
||||
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
|
||||
@ -54,7 +53,6 @@ public fun Meta.color(opacity: Double = 1.0): Color {
|
||||
this[Colors.BLUE_KEY]?.int ?: 0,
|
||||
this[SolidMaterial.OPACITY_KEY]?.double ?: opacity
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Infer FX material based on meta item
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -1,28 +1,27 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
val res = Composite(type, children[0], children[1])
|
||||
|
||||
res.meta.update(group.meta)
|
||||
|
||||
if (group.position != null) {
|
||||
position = group.position
|
||||
res.position = group.position
|
||||
}
|
||||
if (group.rotation != null) {
|
||||
rotation = group.rotation
|
||||
res.rotation = group.rotation
|
||||
}
|
||||
if (group.scale != null) {
|
||||
scale = group.scale
|
||||
}
|
||||
set(name, this)
|
||||
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)
|
@ -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) {
|
||||
|
@ -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?
|
||||
|
@ -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) }
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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(
|
||||
|
@ -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()
|
||||
|
@ -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,44 +61,46 @@ 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 {
|
||||
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 ->
|
||||
public fun Meta.threeColor(): Color = getValue(Name.EMPTY)?.let { value ->
|
||||
if (value.type == ValueType.NUMBER) {
|
||||
val int = value.int
|
||||
Color(int)
|
||||
@ -101,11 +108,10 @@ public fun Meta.threeColor(): Color {
|
||||
Color(value.string)
|
||||
}
|
||||
} ?: Color(
|
||||
this[Colors.RED_KEY]?.int ?: 0,
|
||||
this[Colors.GREEN_KEY]?.int ?: 0,
|
||||
this[Colors.BLUE_KEY]?.int ?: 0
|
||||
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,33 +120,21 @@ 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 {
|
||||
} else {
|
||||
material = vision.computePropertyNode(SolidMaterial.MATERIAL_KEY)?.let {
|
||||
ThreeMaterials.buildMaterial(it)
|
||||
} ?: ThreeMaterials.DEFAULT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) {
|
||||
if (material.cached || propertyName == SolidMaterial.MATERIAL_KEY) {
|
||||
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user