0.2.0 #71

Merged
altavir merged 139 commits from dev into master 2022-01-24 09:44:18 +03:00
7 changed files with 63 additions and 50 deletions
Showing only changes of commit c44162671f - Show all commits

View File

@ -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
} }

View File

@ -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")

View File

@ -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)
} }
} }

View File

@ -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,14 +74,29 @@ 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 fun removeStructureListener(owner: Any?)
}
public data class StructureChange(val token: NameToken, val before: Vision?, val after: Vision?)
/** /**
* Flow structure changes of this group. Unconsumed changes are discarded * Flow structure changes of this group. Unconsumed changes are discarded
*/ */
public val structureChanges: Flow<StructureChange> @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))

View File

@ -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)
}
}
} }
} }

View File

@ -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)
}
} }

View File

@ -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)