Refactor serialization

This commit is contained in:
Alexander Nozik 2020-10-31 19:03:55 +03:00
parent 8f6c3822ff
commit 6b4bc6912f
30 changed files with 221 additions and 267 deletions

View File

@ -10,6 +10,7 @@ import hep.dataforge.vision.gdml.toVision
import hep.dataforge.vision.react.objectTree
import hep.dataforge.vision.solid.Solid
import hep.dataforge.vision.solid.SolidGroup
import hep.dataforge.vision.solid.SolidManager
import hep.dataforge.vision.solid.three.ThreeCanvas
import hep.dataforge.vision.solid.three.ThreeCanvasComponent
import kotlinx.browser.window
@ -50,12 +51,13 @@ val GDMLApp = functionalComponent<GDMLAppProps>("GDMLApp") { props ->
}
fun loadData(name: String, data: String) {
val visionManager = props.context.plugins.fetch(SolidManager).visionManager
val parsedVision = when {
name.endsWith(".gdml") || name.endsWith(".xml") -> {
val gdml = GDML.decodeFromString(data)
gdml.toVision()
}
name.endsWith(".json") -> SolidGroup.decodeFromString(data)
name.endsWith(".json") -> visionManager.decodeFromString(data)
else -> {
window.alert("File extension is not recognized: $name")
error("File extension is not recognized: $name")

View File

@ -4,6 +4,8 @@ import hep.dataforge.context.Global
import hep.dataforge.vision.editor.VisualObjectEditorFragment
import hep.dataforge.vision.editor.VisualObjectTreeFragment
import hep.dataforge.vision.gdml.toVision
import hep.dataforge.vision.VisionManager
import hep.dataforge.vision.solid.Solid
import hep.dataforge.vision.solid.SolidManager
import hep.dataforge.vision.solid.SolidMaterial
import hep.dataforge.vision.solid.fx.FX3DPlugin
@ -17,6 +19,7 @@ class GDMLDemoApp : App(GDMLView::class)
class GDMLView : View() {
private val fx3d = Global.plugins.fetch(FX3DPlugin)
private val visionManager = Global.plugins.fetch(VisionManager)
private val canvas = FXCanvas3D(fx3d)
private val treeFragment = VisualObjectTreeFragment().apply {
@ -39,7 +42,7 @@ class GDMLView : View() {
val file = chooseFile("Select a GDML/json file", filters = fileNameFilter).firstOrNull()
if(file!= null) {
runAsync {
SolidManager.readFile(file)
visionManager.readFile(file) as Solid
} ui {
canvas.render(it)
}

View File

@ -8,13 +8,15 @@ import hep.dataforge.vision.gdml.toVision
import hep.dataforge.vision.solid.SolidGroup
import hep.dataforge.vision.solid.SolidManager
import hep.dataforge.vision.solid.SolidMaterial
import hep.dataforge.vision.Vision
import hep.dataforge.vision.VisionManager
import kscience.gdml.GDML
import java.io.File
import java.util.zip.GZIPInputStream
import java.util.zip.ZipInputStream
@OptIn(DFExperimental::class)
fun SolidManager.Companion.readFile(file: File): SolidGroup = when {
fun VisionManager.readFile(file: File): Vision = when {
file.extension == "gdml" || file.extension == "xml" -> {
GDML.readFile(file.toPath()).toVision {
// lUnit = LUnit.CM
@ -31,23 +33,23 @@ fun SolidManager.Companion.readFile(file: File): SolidGroup = when {
// }
}
}
file.extension == "json" -> SolidGroup.decodeFromString(file.readText())
file.extension == "json" -> decodeFromString(file.readText())
file.name.endsWith("json.zip") -> {
file.inputStream().use {
val unzip = ZipInputStream(it, Charsets.UTF_8)
val text = unzip.readBytes().decodeToString()
SolidGroup.decodeFromString(text)
decodeFromString(text)
}
}
file.name.endsWith("json.gz") -> {
file.inputStream().use {
val unzip = GZIPInputStream(it)
val text = unzip.readBytes().decodeToString()
SolidGroup.decodeFromString(text)
decodeFromString(text)
}
}
else -> error("Unknown extension ${file.extension}")
}
@OptIn(DFExperimental::class)
fun SolidManager.Companion.readFile(fileName: String): SolidGroup = readFile(File(fileName))
fun VisionManager.readFile(fileName: String): Vision = readFile(File(fileName))

View File

@ -2,7 +2,7 @@ package hep.dataforge.vision.gdml.demo
import hep.dataforge.vision.gdml.readFile
import hep.dataforge.vision.gdml.toVision
import hep.dataforge.vision.solid.encodeToString
import hep.dataforge.vision.solid.SolidManager
import kscience.gdml.GDML
import kscience.gdml.LUnit
import java.io.File
@ -17,11 +17,11 @@ fun main(args: Array<String>) {
val gdml = GDML.readFile(Paths.get(inputFileName))
//GDML.readFile(Paths.get("D:\\Work\\Projects\\visionforge\\visionforge-spatial-gdml\\src\\jvmTest\\resources\\gdml\\simple1.gdml"))
val visual = gdml.toVision {
val vision = gdml.toVision {
lUnit = LUnit.CM
}
val json = visual.encodeToString()
val json = SolidManager.encodeToString(vision)
println(json)
File(outputFileName).writeText(json)
//File("D:\\Work\\Projects\\gdml.kt\\gdml-source\\cubes.json").writeText(json)

View File

@ -9,7 +9,7 @@ class FileSerializationTest {
@Ignore
fun testFileRead(){
val text = this::class.java.getResourceAsStream("/cubes.json").readBytes().decodeToString()
val visual = SolidGroup.decodeFromString(text)
val visual = SolidManager.decodeFromString(text) as SolidGroup
visual["composite_001".asName()]
}
}

View File

@ -19,7 +19,7 @@ private class MMDemoApp : Application {
private val connection = HttpClient {
install(JsonFeature) {
serializer = KotlinxSerializer(Json { serializersModule = SolidManager.serializersModule })
serializer = KotlinxSerializer(Json { serializersModule = SolidManager.serializersModuleForSolids })
}
}

View File

@ -1,6 +1,8 @@
package ru.mipt.npm.muon.monitor.server
import hep.dataforge.context.Context
import hep.dataforge.context.Global
import hep.dataforge.meta.DFExperimental
import hep.dataforge.vision.solid.SolidManager
import io.ktor.application.Application
@ -32,15 +34,15 @@ import java.net.URI
private val generator = Cos2TrackGenerator(JDKRandomGenerator(223))
@OptIn(DFExperimental::class)
fun Application.module() {
fun Application.module(context: Context = Global) {
val currentDir = File(".").absoluteFile
environment.log.info("Current directory: $currentDir")
val solidManager = context.plugins.load(SolidManager)
install(DefaultHeaders)
install(CallLogging)
install(ContentNegotiation) {
json(Json { serializersModule = SolidManager.serialModule }, ContentType.Application.Json)
json(solidManager.visionManager.jsonFormat, ContentType.Application.Json)
}
install(Routing) {
get("/event") {

View File

@ -94,6 +94,10 @@ public open class AbstractVision : Vision {
properties = null
}
override fun update(meta: Meta) {
meta[Vision::properties.name].node?.let { configure(it) }
}
public companion object {
public val descriptor: NodeDescriptor = NodeDescriptor {
value(STYLE_KEY) {

View File

@ -68,13 +68,16 @@ public interface Vision : Configurable {
config[STYLE_KEY] = value
}
/**
* Update this vision using external meta.
*/
public fun update(meta: Meta)
public companion object {
public const val TYPE: String = "vision"
public val STYLE_KEY: Name = "@style".asName()
private val VISION_SERIALIZER = PolymorphicSerializer(Vision::class)
public fun serializer(): PolymorphicSerializer<Vision> = VISION_SERIALIZER
public fun serializer(): PolymorphicSerializer<Vision> = PolymorphicSerializer(Vision::class)
public val VISIBLE_KEY: Name = "visible".asName()
}

View File

@ -3,80 +3,21 @@ package hep.dataforge.vision
import hep.dataforge.context.*
import hep.dataforge.meta.*
import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.names.Name
import hep.dataforge.names.toName
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.polymorphic
import kotlinx.serialization.modules.subclass
import kotlin.reflect.KClass
@DFExperimental
public interface VisionForm<T : Vision> {
public val type: KClass<out T>
public val serializer: KSerializer<T>
public val name: Name
get() = serializer.descriptor.serialName.toName()
/**
* Apply a patch to given [Vision]
*/
public fun patch(obj: T, meta: Meta)
public companion object {
public const val TYPE: String = "visionForm"
}
}
@DFExperimental
public object SimpleGroupForm : VisionForm<SimpleVisionGroup> {
override val type: KClass<out SimpleVisionGroup> = SimpleVisionGroup::class
override val serializer: KSerializer<SimpleVisionGroup> = SimpleVisionGroup.serializer()
override fun patch(obj: SimpleVisionGroup, meta: Meta) {
TODO("Not yet implemented")
}
}
@DFExperimental
public fun <T : Vision> VisionForm<T>.visionToMeta(
vision: T,
module: SerializersModule,
descriptor: NodeDescriptor? = null,
): Meta {
val engine = Json(VisionManager.jsonConfiguration) { serializersModule = module }
val json = engine.encodeToJsonElement(serializer, vision)
return json.toMetaItem(descriptor).node!!
}
@DFExperimental
public fun <T : Vision> VisionForm<T>.buildVision(
meta: Meta,
module: SerializersModule,
descriptor: NodeDescriptor? = null,
): T {
val engine = Json(VisionManager.jsonConfiguration) { serializersModule = module }
val json = meta.toJson(descriptor)
return engine.decodeFromJsonElement(serializer, json)
}
@DFExperimental
public class VisionManager(meta: Meta) : AbstractPlugin(meta) {
override val tag: PluginTag get() = Companion.tag
/**
* Create a list of factories on first call and cache it
* Combined [SerializersModule] for all registered visions
*/
private val forms by lazy {
context.gather<VisionForm<*>>(VisionForm.TYPE).mapKeys { it.value.type }
}
public val visionSerialModule: SerializersModule
public val serializersModule: SerializersModule
get() = SerializersModule {
include(defaultSerialModule)
context.gather<SerializersModule>(VISION_SERIAL_MODULE_TARGET).values.forEach {
@ -84,33 +25,60 @@ public class VisionManager(meta: Meta) : AbstractPlugin(meta) {
}
}
@Suppress("UNCHECKED_CAST")
public fun <T : Vision> resolveVisionForm(type: KClass<out T>): VisionForm<T> =
forms[type] as VisionForm<T>
public val jsonFormat: Json
get() = Json {
prettyPrint = true
useArrayPolymorphism = false
encodeDefaults = false
ignoreUnknownKeys = true
serializersModule = this@VisionManager.serializersModule
}
public fun decodeFromString(string: String): Vision = jsonFormat.decodeFromString(Vision.serializer(), string)
public fun encodeToString(vision: Vision): String = jsonFormat.encodeToString(Vision.serializer(), vision)
public fun decodeFromJson(json: JsonElement): Vision = jsonFormat.decodeFromJsonElement(Vision.serializer(), json)
public fun encodeToJsonElement(vision: Vision): JsonElement =
jsonFormat.encodeToJsonElement(Vision.serializer(), vision)
//TODO remove double transformation with dedicated Meta serial format
public fun decodeFromMeta(meta: Meta, descriptor: NodeDescriptor? = null): Vision =
decodeFromJson(meta.toJson(descriptor))
public fun encodeToMeta(vision: Vision, descriptor: NodeDescriptor? = null): Meta =
encodeToJsonElement(vision).toMetaItem(descriptor).node
?: error("Expected node, but value found. Check your serializer!")
public fun updateVision(vision: Vision, meta: Meta) {
public inline fun <reified T : Vision> buildSpecificVision(meta: Meta): T {
val factory = resolveVisionForm(T::class) ?: error("Could not resolve a form for ${meta["type"].string}")
return factory.buildVision(meta, visionSerialModule)
}
@OptIn(ExperimentalSerializationApi::class)
public fun buildVision(meta: Meta): Vision {
val type = meta["type"].string ?: Vision.serializer().descriptor.serialName
val form = forms.values.find { it.name.toString() == type } ?: error("Could not resolve a form for type $type")
return form.buildVision(meta, visionSerialModule)
}
public fun <T : Vision> writeVisionToMeta(vision: T): Meta {
val form = resolveVisionForm(vision::class) ?: error("Could not resolve a form for $vision")
val engine = Json(jsonConfiguration) { serializersModule = visionSerialModule }
val json = engine.encodeToJsonElement(form.serializer, vision)
return json.toMetaItem().node!!
}
public fun patchVision(vision: Vision, meta: Meta) {
val form = resolveVisionForm(vision::class) ?: error("Could not resolve a form for $vision")
form.patch(vision, meta)
}
// public fun <T : Vision> VisionForm<T>.buildVision(meta: Meta, descriptor: NodeDescriptor? = null): T {
// val json = meta.toJson(descriptor)
// return jsonFormat.decodeFromJsonElement(serializer, json)
// }
//
// @OptIn(ExperimentalSerializationApi::class)
// public fun buildVision(meta: Meta): Vision {
// val type = meta["type"].string ?: Vision.serializer().descriptor.serialName
// val form = forms.values.find { it.name.toString() == type } ?: error("Could not resolve a form for type $type")
// return form.buildVision(meta)
// }
//
// public inline fun <reified T : Vision> buildSpecificVision(meta: Meta): T {
// val factory = resolveVisionForm(T::class)
// return factory.buildVision(meta)
// }
//
// public fun <T : Vision> writeVisionToMeta(vision: T): Meta {
// val form = resolveVisionForm(vision::class) ?: error("Could not resolve a form for $vision")
// val json = jsonFormat.encodeToJsonElement(form.serializer, vision)
// return json.toMetaItem().node!!
// }
//
// public fun updateVision(vision: Vision, meta: Meta) {
// resolveVisionForm(vision::class).patch(vision, meta)
// }
public companion object : PluginFactory<VisionManager> {
override val tag: PluginTag = PluginTag(name = "vision", group = PluginTag.DATAFORGE_GROUP)
@ -120,14 +88,7 @@ public class VisionManager(meta: Meta) : AbstractPlugin(meta) {
override fun invoke(meta: Meta, context: Context): VisionManager = VisionManager(meta)
public val jsonConfiguration: Json = Json {
prettyPrint = true
useArrayPolymorphism = false
encodeDefaults = false
ignoreUnknownKeys = true
}
public val defaultSerialModule: SerializersModule = SerializersModule {
private val defaultSerialModule: SerializersModule = SerializersModule {
polymorphic(Vision::class) {
subclass(SimpleVisionGroup.serializer())
}

View File

@ -8,7 +8,7 @@ import hep.dataforge.names.Name
import hep.dataforge.values.ValueType
import hep.dataforge.values.asValue
fun Sequence<MetaItem<*>?>.merge(): MetaItem<*>? {
public fun Sequence<MetaItem<*>?>.merge(): MetaItem<*>? {
return when (val first = firstOrNull { it != null }) {
null -> null
is MetaItem.ValueItem -> first //fast search for first entry if it is value
@ -20,7 +20,7 @@ fun Sequence<MetaItem<*>?>.merge(): MetaItem<*>? {
}
}
inline fun <reified E : Enum<E>> NodeDescriptor.enum(key: Name, default: E?) = value(key) {
public inline fun <reified E : Enum<E>> NodeDescriptor.enum(key: Name, default: E?): Unit = value(key) {
type(ValueType.STRING)
default?.let {
default(default)

View File

@ -1,6 +1,6 @@
package hep.dataforge.vision.gdml
import hep.dataforge.vision.solid.encodeToString
import hep.dataforge.vision.solid.SolidManager
import kscience.gdml.GDML
import nl.adaptivity.xmlutil.StAXReader
import org.junit.jupiter.api.Test
@ -13,7 +13,7 @@ class TestConvertor {
val xmlReader = StAXReader(stream, "UTF-8")
val xml = GDML.format.parse(GDML.serializer(), xmlReader)
val vision = xml.toVision()
println(vision.encodeToString())
println(SolidManager.encodeToString(vision))
}
@Test
@ -32,7 +32,7 @@ class TestConvertor {
val xmlReader = StAXReader(stream, "UTF-8")
val xml = GDML.format.parse(GDML.serializer(), xmlReader)
val visual = xml.toVision()
println(visual.encodeToString())
val vision = xml.toVision()
println(SolidManager.encodeToString(vision))
}
}

View File

@ -1,17 +0,0 @@
package hep.dataforge.vision.solid
import hep.dataforge.vision.AbstractVision
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
@Serializable
public open class AbstractSolid: AbstractVision(), Solid {
@Serializable(Point3DSerializer::class)
override var position: Point3D? = null
@Serializable(Point3DSerializer::class)
override var rotation: Point3D? = null
@Serializable(Point3DSerializer::class)
override var scale: Point3D? = null
}

View File

@ -0,0 +1,34 @@
package hep.dataforge.vision.solid
import hep.dataforge.meta.*
import hep.dataforge.vision.AbstractVision
import hep.dataforge.vision.Vision
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
@Serializable
@SerialName("solid")
public open class BasicSolid: AbstractVision(), Solid {
@Serializable(Point3DSerializer::class)
override var position: Point3D? = null
@Serializable(Point3DSerializer::class)
override var rotation: Point3D? = null
@Serializable(Point3DSerializer::class)
override var scale: Point3D? = null
override fun update(meta: Meta) {
fun Meta.toVector(default: Float = 0f) = Point3D(
this[Solid.X_KEY].float ?: default,
this[Solid.Y_KEY].float ?: default,
this[Solid.Z_KEY].float ?: default
)
meta[Solid.POSITION_KEY].node?.toVector()?.let { position = it }
meta[Solid.ROTATION].node?.toVector()?.let { rotation = it }
meta[Solid.SCALE_KEY].node?.toVector(1f)?.let { scale = it }
super.update(meta)
}
}

View File

@ -2,9 +2,6 @@
package hep.dataforge.vision.solid
import hep.dataforge.meta.Config
import hep.dataforge.vision.AbstractVision
import hep.dataforge.vision.MutableVisionGroup
import hep.dataforge.vision.VisionContainerBuilder
import hep.dataforge.vision.set
import hep.dataforge.vision.solid.Solid.Companion.solidEquals
@ -18,7 +15,7 @@ public class Box(
public val xSize: Float,
public val ySize: Float,
public val zSize: Float
) : AbstractSolid(), GeometrySolid {
) : BasicSolid(), GeometrySolid {
//TODO add helper for color configuration
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {

View File

@ -2,7 +2,6 @@
package hep.dataforge.vision.solid
import hep.dataforge.meta.Config
import hep.dataforge.meta.update
import hep.dataforge.names.NameToken
import hep.dataforge.vision.*
@ -22,7 +21,7 @@ public class Composite(
public val compositeType: CompositeType,
public val first: Solid,
public val second: Solid
) : AbstractSolid(), Solid, VisionGroup {
) : BasicSolid(), Solid, VisionGroup {
init {
first.parent = this

View File

@ -2,9 +2,6 @@
package hep.dataforge.vision.solid
import hep.dataforge.meta.Config
import hep.dataforge.vision.AbstractVision
import hep.dataforge.vision.MutableVisionGroup
import hep.dataforge.vision.VisionContainerBuilder
import hep.dataforge.vision.set
import kotlinx.serialization.SerialName
@ -24,7 +21,7 @@ public class ConeSegment(
public var upperRadius: Float,
public var startAngle: Float = 0f,
public var angle: Float = PI2
) : AbstractSolid(), GeometrySolid {
) : BasicSolid(), GeometrySolid {
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {
val segments = detail ?: 8

View File

@ -2,9 +2,6 @@
package hep.dataforge.vision.solid
import hep.dataforge.meta.Config
import hep.dataforge.vision.AbstractVision
import hep.dataforge.vision.MutableVisionGroup
import hep.dataforge.vision.VisionContainerBuilder
import hep.dataforge.vision.set
import kotlinx.serialization.SerialName
@ -13,7 +10,7 @@ import kotlinx.serialization.UseSerializers
@Serializable
@SerialName("solid.convex")
public class Convex(public val points: List<Point3D>) : AbstractSolid(), Solid
public class Convex(public val points: List<Point3D>) : BasicSolid(), Solid
public inline fun VisionContainerBuilder<Solid>.convex(name: String = "", action: ConvexBuilder.() -> Unit = {}): Convex =
ConvexBuilder().apply(action).build().also { set(name, it) }

View File

@ -1,9 +1,6 @@
@file:UseSerializers(Point2DSerializer::class, Point3DSerializer::class)
package hep.dataforge.vision.solid
import hep.dataforge.meta.Config
import hep.dataforge.vision.AbstractVision
import hep.dataforge.vision.MutableVisionGroup
import hep.dataforge.vision.VisionContainerBuilder
import hep.dataforge.vision.set
import kotlinx.serialization.SerialName
@ -44,7 +41,7 @@ public data class Layer(var x: Float, var y: Float, var z: Float, var scale: Flo
public class Extruded(
public var shape: List<Point2D> = ArrayList(),
public var layers: MutableList<Layer> = ArrayList()
) : AbstractSolid(), GeometrySolid {
) : BasicSolid(), GeometrySolid {
public fun shape(block: Shape2DBuilder.() -> Unit) {
this.shape = Shape2DBuilder().apply(block).build()

View File

@ -14,7 +14,7 @@ import kotlinx.serialization.UseSerializers
@Serializable
@SerialName("solid.line")
public class PolyLine(public var points: List<Point3D>) : AbstractSolid(), Solid {
public class PolyLine(public var points: List<Point3D>) : BasicSolid(), Solid {
//var lineType by string()
public var thickness: Number by number(1.0, key = SolidMaterial.MATERIAL_KEY + THICKNESS_KEY)

View File

@ -9,7 +9,7 @@ import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import kotlin.collections.set
public abstract class AbstractProxy : AbstractSolid(), VisionGroup {
public abstract class AbstractProxy : BasicSolid(), VisionGroup {
public abstract val prototype: Vision
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {

View File

@ -8,7 +8,9 @@ import hep.dataforge.names.asName
import hep.dataforge.vision.*
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.Serializer
import kotlinx.serialization.UseSerializers
import kotlinx.serialization.json.Json
import kotlin.collections.set
public interface PrototypeHolder {
@ -45,8 +47,13 @@ public class SolidGroup : AbstractVisionGroup(), Solid, PrototypeHolder {
//FIXME to be lifted to AbstractVisualGroup after https://github.com/Kotlin/kotlinx.serialization/issues/378 is fixed
override var properties: Config? = null
@Serializable(Point3DSerializer::class)
override var position: Point3D? = null
@Serializable(Point3DSerializer::class)
override var rotation: Point3D? = null
@Serializable(Point3DSerializer::class)
override var scale: Point3D? = null
@SerialName("children")
@ -77,10 +84,6 @@ public class SolidGroup : AbstractVisionGroup(), Solid, PrototypeHolder {
public companion object {
// val PROTOTYPES_KEY = NameToken("@prototypes")
@OptIn(DFExperimental::class)
public fun decodeFromString(json: String): SolidGroup =
SolidManager.jsonForSolids.decodeFromString(serializer(), json).also { it.attachChildren() }
}
}

View File

@ -11,7 +11,7 @@ public class SolidLabel(
public var text: String,
public var fontSize: Double,
public var fontFamily: String,
) : AbstractSolid(), Solid
) : BasicSolid(), Solid
public fun VisionContainerBuilder<Solid>.label(
text: String,

View File

@ -9,73 +9,48 @@ import hep.dataforge.names.Name
import hep.dataforge.names.toName
import hep.dataforge.vision.SimpleVisionGroup
import hep.dataforge.vision.Vision
import hep.dataforge.vision.VisionForm
import hep.dataforge.vision.VisionGroup
import hep.dataforge.vision.VisionManager
import hep.dataforge.vision.VisionManager.Companion.VISION_SERIAL_MODULE_TARGET
import kotlinx.serialization.*
import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.*
import kotlin.reflect.KClass
@DFExperimental
private class SolidForm<T : Solid>(
override val type: KClass<T>,
override val serializer: KSerializer<T>,
) : VisionForm<T> {
private fun Solid.update(meta: Meta) {
fun Meta.toVector(default: Float = 0f) = Point3D(
this[Solid.X_KEY].float ?: default,
this[Solid.Y_KEY].float ?: default,
this[Solid.Z_KEY].float ?: default
)
meta[Solid.POSITION_KEY].node?.toVector()?.let { position = it }
meta[Solid.ROTATION].node?.toVector()?.let { rotation = it }
meta[Solid.SCALE_KEY].node?.toVector(1f)?.let { scale = it }
meta["properties"].node?.let { configure(it) }
}
override fun patch(obj: T, meta: Meta) {
TODO("Not yet implemented")
}
}
@OptIn(ExperimentalSerializationApi::class)
@DFExperimental
private fun SerializersModule.extractFactories(): List<SolidForm<*>> {
val list = ArrayList<SolidForm<*>>()
val collector = object : SerializersModuleCollector {
override fun <T : Any> contextual(kClass: KClass<T>, serializer: KSerializer<T>) {
//Do nothing
}
override fun <Base : Any, Sub : Base> polymorphic(
baseClass: KClass<Base>,
actualClass: KClass<Sub>,
actualSerializer: KSerializer<Sub>,
) {
if (baseClass == Vision::class) {
@Suppress("UNCHECKED_CAST") val factory = SolidForm<Solid>(
actualClass as KClass<Solid>,
actualSerializer as KSerializer<Solid>
)
list.add(factory)
}
}
override fun <Base : Any> polymorphicDefault(
baseClass: KClass<Base>,
defaultSerializerProvider: (className: String?) -> DeserializationStrategy<out Base>?,
) {
TODO("Not yet implemented")
}
}
dumpTo(collector)
return list
}
//@OptIn(ExperimentalSerializationApi::class)
//@DFExperimental
//private fun SerializersModule.extractFactories(): List<SolidForm<*>> {
// val list = ArrayList<SolidForm<*>>()
//
// val collector = object : SerializersModuleCollector {
// override fun <T : Any> contextual(kClass: KClass<T>, serializer: KSerializer<T>) {
// //Do nothing
// }
//
// override fun <Base : Any, Sub : Base> polymorphic(
// baseClass: KClass<Base>,
// actualClass: KClass<Sub>,
// actualSerializer: KSerializer<Sub>,
// ) {
// if (baseClass == Vision::class) {
// @Suppress("UNCHECKED_CAST") val factory: SolidForm<Solid> = SolidForm(
// actualClass as KClass<Solid>,
// actualSerializer as KSerializer<Solid>
// )
// list.add(factory)
// }
// }
//
// override fun <Base : Any> polymorphicDefault(
// baseClass: KClass<Base>,
// defaultSerializerProvider: (className: String?) -> DeserializationStrategy<out Base>?,
// ) {
// TODO("Not yet implemented")
// }
//
// }
// dumpTo(collector)
// return list
//}
@DFExperimental
public class SolidManager(meta: Meta) : AbstractPlugin(meta) {
@ -85,8 +60,7 @@ public class SolidManager(meta: Meta) : AbstractPlugin(meta) {
override val tag: PluginTag get() = Companion.tag
override fun content(target: String): Map<Name, Any> = when (target) {
VisionForm.TYPE -> serializersModule.extractFactories().associateBy { it.name }
VISION_SERIAL_MODULE_TARGET -> mapOf(tag.name.toName() to serializersModule)
VISION_SERIAL_MODULE_TARGET -> mapOf(tag.name.toName() to serializersModuleForSolids)
else -> super.content(target)
}
@ -95,44 +69,49 @@ public class SolidManager(meta: Meta) : AbstractPlugin(meta) {
override val type: KClass<out SolidManager> = SolidManager::class
override fun invoke(meta: Meta, context: Context): SolidManager = SolidManager(meta)
public val serializersModule: SerializersModule = SerializersModule {
private fun PolymorphicModuleBuilder<Solid>.solids() {
subclass(SolidGroup.serializer())
subclass(Proxy.serializer())
subclass(Composite.serializer())
subclass(Tube.serializer())
subclass(Box.serializer())
subclass(Convex.serializer())
subclass(Extruded.serializer())
subclass(PolyLine.serializer())
subclass(SolidLabel.serializer())
subclass(Sphere.serializer())
}
public val serializersModuleForSolids: SerializersModule = SerializersModule {
contextual(Point3DSerializer)
contextual(Point2DSerializer)
polymorphic(Vision::class) {
subclass(SimpleVisionGroup.serializer())
subclass(SolidGroup.serializer())
subclass(Proxy.serializer())
subclass(Composite.serializer())
subclass(Tube.serializer())
subclass(Box.serializer())
subclass(Convex.serializer())
subclass(Extruded.serializer())
subclass(PolyLine.serializer())
subclass(SolidLabel.serializer())
subclass(Sphere.serializer())
solids()
}
polymorphic(Solid::class) {
subclass(SolidGroup.serializer())
subclass(Proxy.serializer())
subclass(Composite.serializer())
subclass(Tube.serializer())
subclass(Box.serializer())
subclass(Convex.serializer())
subclass(Extruded.serializer())
subclass(PolyLine.serializer())
subclass(SolidLabel.serializer())
subclass(Sphere.serializer())
solids()
}
}
val jsonForSolids = Json {
public val jsonForSolids = Json{
prettyPrint = true
useArrayPolymorphism = false
encodeDefaults = false
ignoreUnknownKeys = true
serializersModule = this@Companion.serializersModule
serializersModule = SolidManager.serializersModuleForSolids
}
@OptIn(DFExperimental::class)
public fun encodeToString(solid: Solid): String = jsonForSolids.encodeToString(Vision.serializer(), solid)
@OptIn(DFExperimental::class)
public fun decodeFromString(str: String): Vision = jsonForSolids.decodeFromString(Vision.serializer(), str).also {
if(it is VisionGroup){
it.attachChildren()
}
}
}
}

View File

@ -16,7 +16,7 @@ public class Sphere(
public var phi: Float = PI2,
public var thetaStart: Float = 0f,
public var theta: Float = PI.toFloat(),
) : AbstractSolid(), GeometrySolid {
) : BasicSolid(), GeometrySolid {
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {
fun point3DfromSphCoord(r: Float, theta: Float, phi: Float): Point3D {

View File

@ -19,7 +19,7 @@ public class Tube(
public var innerRadius: Float = 0f,
public var startAngle: Float = 0f,
public var angle: Float = PI2,
) : AbstractSolid(), GeometrySolid {
) : BasicSolid(), GeometrySolid {
init {
require(radius > 0)

View File

@ -106,13 +106,3 @@ internal object PrototypesSerializer : KSerializer<MutableVisionGroup> {
mapSerializer.serialize(encoder, value.children)
}
}
@OptIn(DFExperimental::class)
public fun Vision.encodeToString(): String = SolidManager.jsonForSolids.encodeToString(Vision.serializer(), this)
@OptIn(DFExperimental::class)
public fun Vision.Companion.decodeFromString(str: String): Vision = SolidManager.jsonForSolids.decodeFromString(serializer(), str).also {
if(it is VisionGroup){
it.attachChildren()
}
}

View File

@ -8,6 +8,7 @@ import hep.dataforge.vision.get
import kotlin.test.Test
import kotlin.test.assertEquals
/**
* Create and attach new proxied group
*/
@ -29,9 +30,9 @@ class SerializationTest {
x = 100
z = -100
}
val string = cube.encodeToString()
val string = SolidManager.encodeToString(cube)
println(string)
val newCube = Vision.decodeFromString(string)
val newCube = SolidManager.decodeFromString(string)
assertEquals(cube.config, newCube.config)
}
@ -50,9 +51,9 @@ class SerializationTest {
}
}
}
val string = group.encodeToString()
val string = SolidManager.encodeToString(group)
println(string)
val reconstructed = SolidGroup.decodeFromString(string)
val reconstructed = SolidManager.decodeFromString(string) as SolidGroup
assertEquals(group["cube"]?.config, reconstructed["cube"]?.config)
}

View File

@ -18,10 +18,10 @@ class SolidPluginTest {
@DFExperimental
@Test
fun testPluginConverter(){
val plugin = Global.plugins.fetch(SolidManager).visionManager
val meta = plugin.writeVisionToMeta(vision)
val visionManager = Global.plugins.fetch(SolidManager).visionManager
val meta = visionManager.encodeToMeta(vision)
val reconstructed = plugin.buildSpecificVision<SolidGroup>(meta)
val reconstructed = visionManager.decodeFromMeta(meta) as SolidGroup
assertEquals(vision["aBox"],reconstructed["aBox"])
}

View File

@ -1,6 +1,6 @@
package hep.dataforge.vision.solid.three
import hep.dataforge.vision.solid.AbstractSolid
import hep.dataforge.vision.solid.BasicSolid
import hep.dataforge.vision.solid.Solid
import info.laht.threekt.core.Object3D
import kotlinx.serialization.Serializable
@ -13,6 +13,6 @@ public interface ThreeVision : Solid {
}
@Serializable
public class CustomThreeVision(public val threeFactory: ThreeFactory<Solid>) : AbstractSolid(), ThreeVision {
public class CustomThreeVision(public val threeFactory: ThreeFactory<Solid>) : BasicSolid(), ThreeVision {
override fun toObject3D(): Object3D = threeFactory(this)
}