Encapsulate prototypes.

This commit is contained in:
Alexander Nozik 2020-12-19 17:44:24 +03:00
parent 6939fba292
commit ccb916cff7
6 changed files with 96 additions and 80 deletions

View File

@ -39,9 +39,10 @@ fun main() {
val randomI = Random.nextInt(1, 4)
val randomJ = Random.nextInt(1, 4)
val target = "layer[$randomLayer].segment[$randomI,$randomJ]".toName()
(sat[target] as? Solid)?.color("red")
val targetVision = sat[target] as Solid
targetVision.color("red")
delay(300)
(sat[target] as? Solid)?.color("green")
targetVision.color("green")
delay(10)
}
}

View File

@ -11,8 +11,10 @@ import hep.dataforge.names.Name
import hep.dataforge.names.asName
import hep.dataforge.values.ValueType
import hep.dataforge.vision.Vision.Companion.STYLE_KEY
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.launch
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
@ -68,7 +70,7 @@ public open class VisionBase : Vision {
yieldAll(getStyleItems(name))
}
if (inherit ?: descriptor?.get(name)?.inherited == true) {
yield(parent?.getProperty(name, inherit))
yield(parent?.getProperty(name, inherit, includeStyles, includeDefaults))
}
yield(descriptor?.get(name)?.defaultItem())
}.merge()
@ -101,8 +103,9 @@ public open class VisionBase : Vision {
if (propertyName == STYLE_KEY) {
updateStyles(styles)
}
_propertyInvalidationFlow.tryEmit(propertyName)
GlobalScope.launch {
_propertyInvalidationFlow.emit(propertyName)
}
}
public fun configure(block: MutableMeta<*>.() -> Unit) {

View File

@ -1,8 +1,10 @@
package hep.dataforge.vision
import hep.dataforge.names.*
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.launch
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
@ -43,7 +45,9 @@ public open class VisionGroupBase : VisionBase(), MutableVisionGroup {
* Propagate children change event upwards
*/
private fun childrenChanged(name: NameToken, before: Vision?, after: Vision?) {
_structureChanges.tryEmit(MutableVisionGroup.StructureChange(name, before, after))
GlobalScope.launch {
_structureChanges.emit(MutableVisionGroup.StructureChange(name, before, after))
}
}
/**

View File

@ -16,7 +16,11 @@ import kotlinx.serialization.encoding.Encoder
public interface PrototypeHolder {
public val parent: VisionGroup?
public val prototypes: MutableVisionGroup?
@VisionBuilder
public fun prototypes(builder: VisionContainerBuilder<Solid>.() -> Unit)
public fun getPrototype(name: Name): Solid?
}
/**
@ -28,18 +32,24 @@ public class SolidGroup : VisionGroupBase(), Solid, PrototypeHolder {
override val descriptor: NodeDescriptor get() = Solid.descriptor
/**
* A container for templates visible inside this group
*/
@Serializable(Prototypes.Companion::class)
override var prototypes: MutableVisionGroup? = null
private set
@SerialName("prototypes")
internal var prototypes: MutableVisionGroup? = null
/**
* Ger a prototype redirecting the request to the parent if prototype is not found
*/
override fun getPrototype(name: Name): Solid? =
prototypes?.get(name) as? Solid ?: (parent as? PrototypeHolder)?.getPrototype(name)
/**
* Create or edit prototype node as a group
*/
@VisionBuilder
public fun prototypes(builder: VisionContainerBuilder<Solid>.() -> Unit): Unit {
override fun prototypes(builder: VisionContainerBuilder<Solid>.() -> Unit): Unit {
(prototypes ?: Prototypes().also {
prototypes = it
it.parent = this
@ -81,12 +91,6 @@ public fun SolidGroup(block: SolidGroup.() -> Unit): SolidGroup {
return SolidGroup().apply(block)
}
/**
* Ger a prototype redirecting the request to the parent if prototype is not found
*/
public tailrec fun PrototypeHolder.getPrototype(name: Name): Solid? =
prototypes?.get(name) as? Solid ?: (parent as? PrototypeHolder)?.getPrototype(name)
@VisionBuilder
public fun VisionContainerBuilder<Vision>.group(
name: Name = Name.EMPTY,
@ -106,14 +110,12 @@ public fun VisionContainerBuilder<Vision>.group(name: String, action: SolidGroup
@Serializable(Prototypes.Companion::class)
internal class Prototypes(
children: Map<NameToken, Vision> = emptyMap(),
) : VisionGroupBase(), PrototypeHolder {
) : VisionGroupBase() {
init {
childrenInternal.putAll(children)
}
override val prototypes: MutableVisionGroup get() = this
override fun attachChildren() {
children.values.forEach {
it.parent = parent
@ -131,7 +133,7 @@ internal class Prototypes(
): MetaItem<*>? = null
override fun setProperty(name: Name, item: MetaItem<*>?, notify: Boolean) {
TODO("Not yet implemented")
error("Can't ser property of prototypes container")
}
override val descriptor: NodeDescriptor? = null

View File

@ -90,10 +90,20 @@ public class SolidMaterial : Scheme() {
//must be lazy to avoid initialization bug
NodeDescriptor {
value(COLOR_KEY) {
inherited = true
usesStyles = true
type(ValueType.STRING, ValueType.NUMBER)
widgetType = "color"
}
// value(SPECULAR_COLOR_KEY) {
// inherited = true
// usesStyles = true
// type(ValueType.STRING, ValueType.NUMBER)
// widgetType = "color"
// }
value(OPACITY_KEY) {
inherited = true
usesStyles = true
type(ValueType.NUMBER)
default(1.0)
attributes {
@ -104,6 +114,8 @@ public class SolidMaterial : Scheme() {
widgetType = "slider"
}
value(WIREFRAME_KEY) {
inherited = true
usesStyles = true
type(ValueType.BOOLEAN)
default(false)
}
@ -124,11 +136,7 @@ public var Solid.material: SolidMaterial?
@VisionBuilder
public fun Solid.material(builder: SolidMaterial.() -> Unit) {
val node = allProperties(
inherit = true,
includeStyles = true,
includeDefaults = true
).getItem(MATERIAL_KEY).node
val node = allProperties(inherit = true).getItem(MATERIAL_KEY).node
if (node != null) {
SolidMaterial.update(node, builder)
} else {

View File

@ -46,42 +46,41 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
as ThreeFactory<Solid>?
}
public fun buildObject3D(obj: Solid): Object3D {
return when (obj) {
is ThreeVision -> obj.render(this)
is SolidReferenceGroup -> ThreeReferenceFactory(this, obj)
is SolidGroup -> {
val group = ThreeGroup()
obj.children.forEach { (token, child) ->
if (child is Solid && child.ignore != true) {
try {
val object3D = buildObject3D(child)
group[token] = object3D
} catch (ex: Throwable) {
logger.error(ex) { "Failed to render $child" }
ex.printStackTrace()
}
public fun buildObject3D(obj: Solid): Object3D = when (obj) {
is ThreeVision -> obj.render(this)
is SolidReferenceGroup -> ThreeReferenceFactory(this, obj)
is SolidGroup -> {
val group = ThreeGroup()
obj.children.forEach { (token, child) ->
if (child is Solid && child.ignore != true) {
try {
val object3D = buildObject3D(child)
group[token] = object3D
} catch (ex: Throwable) {
logger.error(ex) { "Failed to render $child" }
ex.printStackTrace()
}
}
}
group.apply {
updatePosition(obj)
//obj.onChildrenChange()
group.apply {
updatePosition(obj)
//obj.onChildrenChange()
obj.propertyNameFlow.onEach { name ->
if (
name.startsWith(Solid.POSITION_KEY) ||
name.startsWith(Solid.ROTATION) ||
name.startsWith(Solid.SCALE_KEY)
) {
//update position of mesh using this object
updatePosition(obj)
} else if (name == Vision.VISIBLE_KEY) {
visible = obj.visible ?: true
}
}.launchIn(updateScope)
obj.propertyNameFlow.onEach { name ->
if (
name.startsWith(Solid.POSITION_KEY) ||
name.startsWith(Solid.ROTATION) ||
name.startsWith(Solid.SCALE_KEY)
) {
//update position of mesh using this object
updatePosition(obj)
} else if (name == Vision.VISIBLE_KEY) {
visible = obj.visible ?: true
}
}.launchIn(updateScope)
obj.structureChanges.onEach { (nameToken, _, child) ->
obj.structureChanges.onEach { (nameToken, _, child) ->
// if (name.isEmpty()) {
// logger.error { "Children change with empty name on $group" }
// return@onChildrenChange
@ -90,32 +89,31 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
// val parentName = name.cutLast()
// val childName = name.last()!!
//removing old object
findChild(nameToken.asName())?.let { oldChild ->
oldChild.parent?.remove(oldChild)
}
//removing old object
findChild(nameToken.asName())?.let { oldChild ->
oldChild.parent?.remove(oldChild)
}
//adding new object
if (child != null && child is Solid) {
try {
val object3D = buildObject3D(child)
set(nameToken, object3D)
} catch (ex: Throwable) {
logger.error(ex) { "Failed to render $child" }
}
//adding new object
if (child != null && child is Solid) {
try {
val object3D = buildObject3D(child)
set(nameToken, object3D)
} catch (ex: Throwable) {
logger.error(ex) { "Failed to render $child" }
}
}.launchIn(updateScope)
}
}
}.launchIn(updateScope)
}
is Composite -> compositeFactory(this, obj)
else -> {
//find specialized factory for this type if it is present
val factory: ThreeFactory<Solid>? = findObjectFactory(obj::class)
when {
factory != null -> factory(this, obj)
obj is GeometrySolid -> ThreeShapeFactory(this, obj)
else -> error("Renderer for ${obj::class} not found")
}
}
is Composite -> compositeFactory(this, obj)
else -> {
//find specialized factory for this type if it is present
val factory: ThreeFactory<Solid>? = findObjectFactory(obj::class)
when {
factory != null -> factory(this, obj)
obj is GeometrySolid -> ThreeShapeFactory(this, obj)
else -> error("Renderer for ${obj::class} not found")
}
}
}