0.2.0 #71
@ -17,6 +17,7 @@ internal fun visionOfSatellite(
|
|||||||
ySegmentSize: Number = xSegmentSize,
|
ySegmentSize: Number = xSegmentSize,
|
||||||
fiberDiameter: Number = 1.0,
|
fiberDiameter: Number = 1.0,
|
||||||
): SolidGroup = SolidGroup {
|
): SolidGroup = SolidGroup {
|
||||||
|
color("darkgreen")
|
||||||
val transparent by style {
|
val transparent by style {
|
||||||
this[SolidMaterial.MATERIAL_OPACITY_KEY] = 0.3
|
this[SolidMaterial.MATERIAL_OPACITY_KEY] = 0.3
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ internal data class MetaListener(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A full base implementation for a [Vision]
|
* A full base implementation for a [Vision]
|
||||||
* @param properties Object own properties excluding styles and inheritance
|
* @param parent the parent object for this vision. Could ve set later. Not serialized.
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("vision")
|
@SerialName("vision")
|
||||||
|
@ -82,6 +82,7 @@ public inline fun VisionChange(manager: VisionManager, block: VisionChangeBuilde
|
|||||||
VisionChangeBuilder().apply(block).isolate(manager)
|
VisionChangeBuilder().apply(block).isolate(manager)
|
||||||
|
|
||||||
|
|
||||||
|
@OptIn(DFExperimental::class)
|
||||||
private fun CoroutineScope.collectChange(
|
private fun CoroutineScope.collectChange(
|
||||||
name: Name,
|
name: Name,
|
||||||
source: Vision,
|
source: Vision,
|
||||||
@ -102,11 +103,13 @@ private fun CoroutineScope.collectChange(
|
|||||||
|
|
||||||
//Subscribe for structure change
|
//Subscribe for structure change
|
||||||
if (source is MutableVisionGroup) {
|
if (source is MutableVisionGroup) {
|
||||||
source.structureChanges.onEach { (token, _, after) ->
|
source.structureChanges.onEach { changedName ->
|
||||||
|
val after = source[changedName]
|
||||||
|
val fullName = name + changedName
|
||||||
if (after != null) {
|
if (after != null) {
|
||||||
collectChange(name + token, after, collector)
|
collectChange(fullName, after, collector)
|
||||||
}
|
}
|
||||||
collector()[name + token] = after
|
collector()[fullName] = after
|
||||||
}.launchIn(this)
|
}.launchIn(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
package space.kscience.visionforge
|
package space.kscience.visionforge
|
||||||
|
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import space.kscience.dataforge.misc.DFExperimental
|
||||||
import space.kscience.dataforge.names.*
|
import space.kscience.dataforge.names.*
|
||||||
import space.kscience.dataforge.provider.Provider
|
import space.kscience.dataforge.provider.Provider
|
||||||
|
|
||||||
@ -69,15 +74,30 @@ public interface VisionContainerBuilder<in V : Vision> {
|
|||||||
* Mutable version of [VisionGroup]
|
* Mutable version of [VisionGroup]
|
||||||
*/
|
*/
|
||||||
public interface MutableVisionGroup : VisionGroup, VisionContainerBuilder<Vision> {
|
public interface MutableVisionGroup : VisionGroup, VisionContainerBuilder<Vision> {
|
||||||
|
public fun onStructureChanged(owner: Any?, block: VisionGroup.(Name) -> Unit)
|
||||||
|
|
||||||
public data class StructureChange(val token: NameToken, val before: Vision?, val after: Vision?)
|
public fun removeStructureListener(owner: Any?)
|
||||||
|
|
||||||
/**
|
|
||||||
* Flow structure changes of this group. Unconsumed changes are discarded
|
|
||||||
*/
|
|
||||||
public val structureChanges: Flow<StructureChange>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flow structure changes of this group. Unconsumed changes are discarded
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@DFExperimental
|
||||||
|
public val MutableVisionGroup.structureChanges: Flow<Name>
|
||||||
|
get() = callbackFlow {
|
||||||
|
meta.onChange(this) { name ->
|
||||||
|
launch {
|
||||||
|
send(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
awaitClose {
|
||||||
|
removeStructureListener(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public operator fun <V : Vision> VisionContainer<V>.get(str: String): V? = get(Name.parse(str))
|
public operator fun <V : Vision> VisionContainer<V>.get(str: String): V? = get(Name.parse(str))
|
||||||
|
|
||||||
public operator fun <V : Vision> VisionContainerBuilder<V>.set(token: NameToken, child: V?): Unit =
|
public operator fun <V : Vision> VisionContainerBuilder<V>.set(token: NameToken, child: V?): Unit =
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
package space.kscience.visionforge
|
package space.kscience.visionforge
|
||||||
|
|
||||||
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.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.Transient
|
import kotlinx.serialization.Transient
|
||||||
import space.kscience.dataforge.names.*
|
import space.kscience.dataforge.names.*
|
||||||
|
import kotlin.jvm.Synchronized
|
||||||
|
|
||||||
|
private class StructureChangeListener(val owner: Any?, val callback: VisionGroup.(Name) -> Unit)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract implementation of mutable group of [Vision]
|
* Abstract implementation of mutable group of [Vision]
|
||||||
@ -40,16 +39,24 @@ public open class VisionGroupBase(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
private val _structureChanges: MutableSharedFlow<MutableVisionGroup.StructureChange> = MutableSharedFlow()
|
private val structureListeners = HashSet<StructureChangeListener>()
|
||||||
|
|
||||||
override val structureChanges: SharedFlow<MutableVisionGroup.StructureChange> get() = _structureChanges
|
@Synchronized
|
||||||
|
override fun onStructureChanged(owner: Any?, block: VisionGroup.(Name) -> Unit) {
|
||||||
|
structureListeners.add(StructureChangeListener(owner, block))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
override fun removeStructureListener(owner: Any?) {
|
||||||
|
structureListeners.removeAll { it.owner == owner }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Propagate children change event upwards
|
* Propagate children change event upwards
|
||||||
*/
|
*/
|
||||||
private fun childrenChanged(name: NameToken, before: Vision?, after: Vision?) {
|
protected fun childrenChanged(name: Name) {
|
||||||
(manager?.context?: GlobalScope).launch {
|
structureListeners.forEach {
|
||||||
_structureChanges.emit(MutableVisionGroup.StructureChange(name, before, after))
|
it.callback(this, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +90,12 @@ public open class VisionGroupBase(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (before != child) {
|
if (before != child) {
|
||||||
childrenChanged(token, before, child)
|
childrenChanged(token.asName())
|
||||||
|
if (child is MutableVisionGroup) {
|
||||||
|
child.onStructureChanged(this) { changedName ->
|
||||||
|
this@VisionGroupBase.childrenChanged(token + changedName)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,28 +49,4 @@ class VisionUpdateTest {
|
|||||||
val reconstructed = visionManager.jsonFormat.decodeFromString(VisionChange.serializer(), serialized)
|
val reconstructed = visionManager.jsonFormat.decodeFromString(VisionChange.serializer(), serialized)
|
||||||
assertEquals(change.properties,reconstructed.properties)
|
assertEquals(change.properties,reconstructed.properties)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testDeserialization(){
|
|
||||||
val str = """
|
|
||||||
{
|
|
||||||
"propertyChange": {
|
|
||||||
"layer[4]": {
|
|
||||||
"material": {
|
|
||||||
"color": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"layer[2]": {
|
|
||||||
"material": {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"childrenChange": {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
""".trimIndent()
|
|
||||||
|
|
||||||
val reconstructed = visionManager.jsonFormat.decodeFromString(VisionChange.serializer(), str)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -2,8 +2,6 @@ package space.kscience.visionforge.solid.three
|
|||||||
|
|
||||||
import info.laht.threekt.core.Object3D
|
import info.laht.threekt.core.Object3D
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.flow.launchIn
|
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
import org.w3c.dom.HTMLElement
|
import org.w3c.dom.HTMLElement
|
||||||
import space.kscience.dataforge.context.*
|
import space.kscience.dataforge.context.*
|
||||||
@ -15,6 +13,7 @@ import space.kscience.visionforge.Vision
|
|||||||
import space.kscience.visionforge.onPropertyChange
|
import space.kscience.visionforge.onPropertyChange
|
||||||
import space.kscience.visionforge.solid.*
|
import space.kscience.visionforge.solid.*
|
||||||
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
||||||
|
import space.kscience.visionforge.solid.three.set
|
||||||
import space.kscience.visionforge.visible
|
import space.kscience.visionforge.visible
|
||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
@ -82,9 +81,11 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.structureChanges.onEach { (nameToken, _, child) ->
|
obj.onStructureChanged(this){ childName ->
|
||||||
|
val child = get(childName)
|
||||||
|
|
||||||
//removing old object
|
//removing old object
|
||||||
findChild(nameToken.asName())?.let { oldChild ->
|
findChild(childName)?.let { oldChild ->
|
||||||
oldChild.parent?.remove(oldChild)
|
oldChild.parent?.remove(oldChild)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,12 +93,12 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
|
|||||||
if (child != null && child is Solid) {
|
if (child != null && child is Solid) {
|
||||||
try {
|
try {
|
||||||
val object3D = buildObject3D(child)
|
val object3D = buildObject3D(child)
|
||||||
set(nameToken, object3D)
|
set(childName, object3D)
|
||||||
} catch (ex: Throwable) {
|
} catch (ex: Throwable) {
|
||||||
logger.error(ex) { "Failed to render $child" }
|
logger.error(ex) { "Failed to render $child" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.launchIn(updateScope)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is Composite -> compositeFactory(this, obj)
|
is Composite -> compositeFactory(this, obj)
|
||||||
|
Loading…
Reference in New Issue
Block a user