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.react.objectTree
import hep.dataforge.vision.solid.Solid import hep.dataforge.vision.solid.Solid
import hep.dataforge.vision.solid.SolidGroup 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.ThreeCanvas
import hep.dataforge.vision.solid.three.ThreeCanvasComponent import hep.dataforge.vision.solid.three.ThreeCanvasComponent
import kotlinx.browser.window import kotlinx.browser.window
@ -50,12 +51,13 @@ val GDMLApp = functionalComponent<GDMLAppProps>("GDMLApp") { props ->
} }
fun loadData(name: String, data: String) { fun loadData(name: String, data: String) {
val visionManager = props.context.plugins.fetch(SolidManager).visionManager
val parsedVision = when { val parsedVision = when {
name.endsWith(".gdml") || name.endsWith(".xml") -> { name.endsWith(".gdml") || name.endsWith(".xml") -> {
val gdml = GDML.decodeFromString(data) val gdml = GDML.decodeFromString(data)
gdml.toVision() gdml.toVision()
} }
name.endsWith(".json") -> SolidGroup.decodeFromString(data) name.endsWith(".json") -> visionManager.decodeFromString(data)
else -> { else -> {
window.alert("File extension is not recognized: $name") window.alert("File extension is not recognized: $name")
error("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.VisualObjectEditorFragment
import hep.dataforge.vision.editor.VisualObjectTreeFragment import hep.dataforge.vision.editor.VisualObjectTreeFragment
import hep.dataforge.vision.gdml.toVision 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.SolidManager
import hep.dataforge.vision.solid.SolidMaterial import hep.dataforge.vision.solid.SolidMaterial
import hep.dataforge.vision.solid.fx.FX3DPlugin import hep.dataforge.vision.solid.fx.FX3DPlugin
@ -17,6 +19,7 @@ class GDMLDemoApp : App(GDMLView::class)
class GDMLView : View() { class GDMLView : View() {
private val fx3d = Global.plugins.fetch(FX3DPlugin) private val fx3d = Global.plugins.fetch(FX3DPlugin)
private val visionManager = Global.plugins.fetch(VisionManager)
private val canvas = FXCanvas3D(fx3d) private val canvas = FXCanvas3D(fx3d)
private val treeFragment = VisualObjectTreeFragment().apply { private val treeFragment = VisualObjectTreeFragment().apply {
@ -39,7 +42,7 @@ class GDMLView : View() {
val file = chooseFile("Select a GDML/json file", filters = fileNameFilter).firstOrNull() val file = chooseFile("Select a GDML/json file", filters = fileNameFilter).firstOrNull()
if(file!= null) { if(file!= null) {
runAsync { runAsync {
SolidManager.readFile(file) visionManager.readFile(file) as Solid
} ui { } ui {
canvas.render(it) 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.SolidGroup
import hep.dataforge.vision.solid.SolidManager import hep.dataforge.vision.solid.SolidManager
import hep.dataforge.vision.solid.SolidMaterial import hep.dataforge.vision.solid.SolidMaterial
import hep.dataforge.vision.Vision
import hep.dataforge.vision.VisionManager
import kscience.gdml.GDML import kscience.gdml.GDML
import java.io.File import java.io.File
import java.util.zip.GZIPInputStream import java.util.zip.GZIPInputStream
import java.util.zip.ZipInputStream import java.util.zip.ZipInputStream
@OptIn(DFExperimental::class) @OptIn(DFExperimental::class)
fun SolidManager.Companion.readFile(file: File): SolidGroup = when { fun VisionManager.readFile(file: File): Vision = when {
file.extension == "gdml" || file.extension == "xml" -> { file.extension == "gdml" || file.extension == "xml" -> {
GDML.readFile(file.toPath()).toVision { GDML.readFile(file.toPath()).toVision {
// lUnit = LUnit.CM // 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.name.endsWith("json.zip") -> {
file.inputStream().use { file.inputStream().use {
val unzip = ZipInputStream(it, Charsets.UTF_8) val unzip = ZipInputStream(it, Charsets.UTF_8)
val text = unzip.readBytes().decodeToString() val text = unzip.readBytes().decodeToString()
SolidGroup.decodeFromString(text) decodeFromString(text)
} }
} }
file.name.endsWith("json.gz") -> { file.name.endsWith("json.gz") -> {
file.inputStream().use { file.inputStream().use {
val unzip = GZIPInputStream(it) val unzip = GZIPInputStream(it)
val text = unzip.readBytes().decodeToString() val text = unzip.readBytes().decodeToString()
SolidGroup.decodeFromString(text) decodeFromString(text)
} }
} }
else -> error("Unknown extension ${file.extension}") else -> error("Unknown extension ${file.extension}")
} }
@OptIn(DFExperimental::class) @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.readFile
import hep.dataforge.vision.gdml.toVision 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.GDML
import kscience.gdml.LUnit import kscience.gdml.LUnit
import java.io.File import java.io.File
@ -17,11 +17,11 @@ fun main(args: Array<String>) {
val gdml = GDML.readFile(Paths.get(inputFileName)) val gdml = GDML.readFile(Paths.get(inputFileName))
//GDML.readFile(Paths.get("D:\\Work\\Projects\\visionforge\\visionforge-spatial-gdml\\src\\jvmTest\\resources\\gdml\\simple1.gdml")) //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 lUnit = LUnit.CM
} }
val json = visual.encodeToString() val json = SolidManager.encodeToString(vision)
println(json) println(json)
File(outputFileName).writeText(json) File(outputFileName).writeText(json)
//File("D:\\Work\\Projects\\gdml.kt\\gdml-source\\cubes.json").writeText(json) //File("D:\\Work\\Projects\\gdml.kt\\gdml-source\\cubes.json").writeText(json)

View File

@ -9,7 +9,7 @@ class FileSerializationTest {
@Ignore @Ignore
fun testFileRead(){ fun testFileRead(){
val text = this::class.java.getResourceAsStream("/cubes.json").readBytes().decodeToString() 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()] visual["composite_001".asName()]
} }
} }

View File

@ -19,7 +19,7 @@ private class MMDemoApp : Application {
private val connection = HttpClient { private val connection = HttpClient {
install(JsonFeature) { 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 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.meta.DFExperimental
import hep.dataforge.vision.solid.SolidManager import hep.dataforge.vision.solid.SolidManager
import io.ktor.application.Application import io.ktor.application.Application
@ -32,15 +34,15 @@ import java.net.URI
private val generator = Cos2TrackGenerator(JDKRandomGenerator(223)) private val generator = Cos2TrackGenerator(JDKRandomGenerator(223))
@OptIn(DFExperimental::class) @OptIn(DFExperimental::class)
fun Application.module() { fun Application.module(context: Context = Global) {
val currentDir = File(".").absoluteFile val currentDir = File(".").absoluteFile
environment.log.info("Current directory: $currentDir") environment.log.info("Current directory: $currentDir")
val solidManager = context.plugins.load(SolidManager)
install(DefaultHeaders) install(DefaultHeaders)
install(CallLogging) install(CallLogging)
install(ContentNegotiation) { install(ContentNegotiation) {
json(Json { serializersModule = SolidManager.serialModule }, ContentType.Application.Json) json(solidManager.visionManager.jsonFormat, ContentType.Application.Json)
} }
install(Routing) { install(Routing) {
get("/event") { get("/event") {

View File

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

View File

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

View File

@ -3,80 +3,21 @@ package hep.dataforge.vision
import hep.dataforge.context.* import hep.dataforge.context.*
import hep.dataforge.meta.* import hep.dataforge.meta.*
import hep.dataforge.meta.descriptors.NodeDescriptor 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.Json
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.modules.SerializersModule import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.polymorphic import kotlinx.serialization.modules.polymorphic
import kotlinx.serialization.modules.subclass import kotlinx.serialization.modules.subclass
import kotlin.reflect.KClass 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 @DFExperimental
public class VisionManager(meta: Meta) : AbstractPlugin(meta) { public class VisionManager(meta: Meta) : AbstractPlugin(meta) {
override val tag: PluginTag get() = Companion.tag 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 { public val serializersModule: SerializersModule
context.gather<VisionForm<*>>(VisionForm.TYPE).mapKeys { it.value.type }
}
public val visionSerialModule: SerializersModule
get() = SerializersModule { get() = SerializersModule {
include(defaultSerialModule) include(defaultSerialModule)
context.gather<SerializersModule>(VISION_SERIAL_MODULE_TARGET).values.forEach { context.gather<SerializersModule>(VISION_SERIAL_MODULE_TARGET).values.forEach {
@ -84,33 +25,60 @@ public class VisionManager(meta: Meta) : AbstractPlugin(meta) {
} }
} }
@Suppress("UNCHECKED_CAST") public val jsonFormat: Json
public fun <T : Vision> resolveVisionForm(type: KClass<out T>): VisionForm<T> = get() = Json {
forms[type] as VisionForm<T> prettyPrint = true
useArrayPolymorphism = false
public inline fun <reified T : Vision> buildSpecificVision(meta: Meta): T { encodeDefaults = false
val factory = resolveVisionForm(T::class) ?: error("Could not resolve a form for ${meta["type"].string}") ignoreUnknownKeys = true
return factory.buildVision(meta, visionSerialModule) serializersModule = this@VisionManager.serializersModule
} }
@OptIn(ExperimentalSerializationApi::class) public fun decodeFromString(string: String): Vision = jsonFormat.decodeFromString(Vision.serializer(), string)
public fun buildVision(meta: Meta): Vision { public fun encodeToString(vision: Vision): String = jsonFormat.encodeToString(Vision.serializer(), 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") public fun decodeFromJson(json: JsonElement): Vision = jsonFormat.decodeFromJsonElement(Vision.serializer(), json)
return form.buildVision(meta, visionSerialModule) 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 fun <T : Vision> writeVisionToMeta(vision: T): Meta { // public fun <T : Vision> VisionForm<T>.buildVision(meta: Meta, descriptor: NodeDescriptor? = null): T {
val form = resolveVisionForm(vision::class) ?: error("Could not resolve a form for $vision") // val json = meta.toJson(descriptor)
val engine = Json(jsonConfiguration) { serializersModule = visionSerialModule } // return jsonFormat.decodeFromJsonElement(serializer, json)
val json = engine.encodeToJsonElement(form.serializer, vision) // }
return json.toMetaItem().node!! //
} // @OptIn(ExperimentalSerializationApi::class)
// public fun buildVision(meta: Meta): Vision {
public fun patchVision(vision: Vision, meta: Meta) { // val type = meta["type"].string ?: Vision.serializer().descriptor.serialName
val form = resolveVisionForm(vision::class) ?: error("Could not resolve a form for $vision") // val form = forms.values.find { it.name.toString() == type } ?: error("Could not resolve a form for type $type")
form.patch(vision, meta) // 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> { public companion object : PluginFactory<VisionManager> {
override val tag: PluginTag = PluginTag(name = "vision", group = PluginTag.DATAFORGE_GROUP) 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) override fun invoke(meta: Meta, context: Context): VisionManager = VisionManager(meta)
public val jsonConfiguration: Json = Json { private val defaultSerialModule: SerializersModule = SerializersModule {
prettyPrint = true
useArrayPolymorphism = false
encodeDefaults = false
ignoreUnknownKeys = true
}
public val defaultSerialModule: SerializersModule = SerializersModule {
polymorphic(Vision::class) { polymorphic(Vision::class) {
subclass(SimpleVisionGroup.serializer()) subclass(SimpleVisionGroup.serializer())
} }

View File

@ -8,7 +8,7 @@ import hep.dataforge.names.Name
import hep.dataforge.values.ValueType import hep.dataforge.values.ValueType
import hep.dataforge.values.asValue import hep.dataforge.values.asValue
fun Sequence<MetaItem<*>?>.merge(): MetaItem<*>? { public fun Sequence<MetaItem<*>?>.merge(): MetaItem<*>? {
return when (val first = firstOrNull { it != null }) { return when (val first = firstOrNull { it != null }) {
null -> null null -> null
is MetaItem.ValueItem -> first //fast search for first entry if it is value 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) type(ValueType.STRING)
default?.let { default?.let {
default(default) default(default)

View File

@ -1,6 +1,6 @@
package hep.dataforge.vision.gdml package hep.dataforge.vision.gdml
import hep.dataforge.vision.solid.encodeToString import hep.dataforge.vision.solid.SolidManager
import kscience.gdml.GDML import kscience.gdml.GDML
import nl.adaptivity.xmlutil.StAXReader import nl.adaptivity.xmlutil.StAXReader
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
@ -13,7 +13,7 @@ class TestConvertor {
val xmlReader = StAXReader(stream, "UTF-8") val xmlReader = StAXReader(stream, "UTF-8")
val xml = GDML.format.parse(GDML.serializer(), xmlReader) val xml = GDML.format.parse(GDML.serializer(), xmlReader)
val vision = xml.toVision() val vision = xml.toVision()
println(vision.encodeToString()) println(SolidManager.encodeToString(vision))
} }
@Test @Test
@ -32,7 +32,7 @@ class TestConvertor {
val xmlReader = StAXReader(stream, "UTF-8") val xmlReader = StAXReader(stream, "UTF-8")
val xml = GDML.format.parse(GDML.serializer(), xmlReader) val xml = GDML.format.parse(GDML.serializer(), xmlReader)
val visual = xml.toVision() val vision = xml.toVision()
println(visual.encodeToString()) 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 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.VisionContainerBuilder
import hep.dataforge.vision.set import hep.dataforge.vision.set
import hep.dataforge.vision.solid.Solid.Companion.solidEquals import hep.dataforge.vision.solid.Solid.Companion.solidEquals
@ -18,7 +15,7 @@ public class Box(
public val xSize: Float, public val xSize: Float,
public val ySize: Float, public val ySize: Float,
public val zSize: Float public val zSize: Float
) : AbstractSolid(), GeometrySolid { ) : BasicSolid(), GeometrySolid {
//TODO add helper for color configuration //TODO add helper for color configuration
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) { override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {

View File

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

View File

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

View File

@ -2,9 +2,6 @@
package hep.dataforge.vision.solid 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.VisionContainerBuilder
import hep.dataforge.vision.set import hep.dataforge.vision.set
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
@ -13,7 +10,7 @@ import kotlinx.serialization.UseSerializers
@Serializable @Serializable
@SerialName("solid.convex") @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 = public inline fun VisionContainerBuilder<Solid>.convex(name: String = "", action: ConvexBuilder.() -> Unit = {}): Convex =
ConvexBuilder().apply(action).build().also { set(name, it) } ConvexBuilder().apply(action).build().also { set(name, it) }

View File

@ -1,9 +1,6 @@
@file:UseSerializers(Point2DSerializer::class, Point3DSerializer::class) @file:UseSerializers(Point2DSerializer::class, Point3DSerializer::class)
package hep.dataforge.vision.solid 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.VisionContainerBuilder
import hep.dataforge.vision.set import hep.dataforge.vision.set
import kotlinx.serialization.SerialName 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 class Extruded(
public var shape: List<Point2D> = ArrayList(), public var shape: List<Point2D> = ArrayList(),
public var layers: MutableList<Layer> = ArrayList() public var layers: MutableList<Layer> = ArrayList()
) : AbstractSolid(), GeometrySolid { ) : BasicSolid(), GeometrySolid {
public fun shape(block: Shape2DBuilder.() -> Unit) { public fun shape(block: Shape2DBuilder.() -> Unit) {
this.shape = Shape2DBuilder().apply(block).build() this.shape = Shape2DBuilder().apply(block).build()

View File

@ -14,7 +14,7 @@ import kotlinx.serialization.UseSerializers
@Serializable @Serializable
@SerialName("solid.line") @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() //var lineType by string()
public var thickness: Number by number(1.0, key = SolidMaterial.MATERIAL_KEY + THICKNESS_KEY) 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 kotlinx.serialization.Transient
import kotlin.collections.set import kotlin.collections.set
public abstract class AbstractProxy : AbstractSolid(), VisionGroup { public abstract class AbstractProxy : BasicSolid(), VisionGroup {
public abstract val prototype: Vision public abstract val prototype: Vision
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? { override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {

View File

@ -8,7 +8,9 @@ import hep.dataforge.names.asName
import hep.dataforge.vision.* import hep.dataforge.vision.*
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.Serializer
import kotlinx.serialization.UseSerializers import kotlinx.serialization.UseSerializers
import kotlinx.serialization.json.Json
import kotlin.collections.set import kotlin.collections.set
public interface PrototypeHolder { 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 //FIXME to be lifted to AbstractVisualGroup after https://github.com/Kotlin/kotlinx.serialization/issues/378 is fixed
override var properties: Config? = null override var properties: Config? = null
@Serializable(Point3DSerializer::class)
override var position: Point3D? = null override var position: Point3D? = null
@Serializable(Point3DSerializer::class)
override var rotation: Point3D? = null override var rotation: Point3D? = null
@Serializable(Point3DSerializer::class)
override var scale: Point3D? = null override var scale: Point3D? = null
@SerialName("children") @SerialName("children")
@ -77,10 +84,6 @@ public class SolidGroup : AbstractVisionGroup(), Solid, PrototypeHolder {
public companion object { public companion object {
// val PROTOTYPES_KEY = NameToken("@prototypes") // 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 text: String,
public var fontSize: Double, public var fontSize: Double,
public var fontFamily: String, public var fontFamily: String,
) : AbstractSolid(), Solid ) : BasicSolid(), Solid
public fun VisionContainerBuilder<Solid>.label( public fun VisionContainerBuilder<Solid>.label(
text: String, text: String,

View File

@ -9,73 +9,48 @@ import hep.dataforge.names.Name
import hep.dataforge.names.toName import hep.dataforge.names.toName
import hep.dataforge.vision.SimpleVisionGroup import hep.dataforge.vision.SimpleVisionGroup
import hep.dataforge.vision.Vision 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
import hep.dataforge.vision.VisionManager.Companion.VISION_SERIAL_MODULE_TARGET import hep.dataforge.vision.VisionManager.Companion.VISION_SERIAL_MODULE_TARGET
import kotlinx.serialization.*
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.* import kotlinx.serialization.modules.*
import kotlin.reflect.KClass import kotlin.reflect.KClass
@DFExperimental //@OptIn(ExperimentalSerializationApi::class)
private class SolidForm<T : Solid>( //@DFExperimental
override val type: KClass<T>, //private fun SerializersModule.extractFactories(): List<SolidForm<*>> {
override val serializer: KSerializer<T>, // val list = ArrayList<SolidForm<*>>()
) : VisionForm<T> { //
// val collector = object : SerializersModuleCollector {
private fun Solid.update(meta: Meta) { // override fun <T : Any> contextual(kClass: KClass<T>, serializer: KSerializer<T>) {
fun Meta.toVector(default: Float = 0f) = Point3D( // //Do nothing
this[Solid.X_KEY].float ?: default, // }
this[Solid.Y_KEY].float ?: default, //
this[Solid.Z_KEY].float ?: default // override fun <Base : Any, Sub : Base> polymorphic(
) // baseClass: KClass<Base>,
// actualClass: KClass<Sub>,
meta[Solid.POSITION_KEY].node?.toVector()?.let { position = it } // actualSerializer: KSerializer<Sub>,
meta[Solid.ROTATION].node?.toVector()?.let { rotation = it } // ) {
meta[Solid.SCALE_KEY].node?.toVector(1f)?.let { scale = it } // if (baseClass == Vision::class) {
meta["properties"].node?.let { configure(it) } // @Suppress("UNCHECKED_CAST") val factory: SolidForm<Solid> = SolidForm(
} // actualClass as KClass<Solid>,
// actualSerializer as KSerializer<Solid>
override fun patch(obj: T, meta: Meta) { // )
TODO("Not yet implemented") // list.add(factory)
} // }
} // }
//
@OptIn(ExperimentalSerializationApi::class) // override fun <Base : Any> polymorphicDefault(
@DFExperimental // baseClass: KClass<Base>,
private fun SerializersModule.extractFactories(): List<SolidForm<*>> { // defaultSerializerProvider: (className: String?) -> DeserializationStrategy<out Base>?,
val list = ArrayList<SolidForm<*>>() // ) {
// TODO("Not yet implemented")
val collector = object : SerializersModuleCollector { // }
override fun <T : Any> contextual(kClass: KClass<T>, serializer: KSerializer<T>) { //
//Do nothing // }
} // dumpTo(collector)
// return list
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
}
@DFExperimental @DFExperimental
public class SolidManager(meta: Meta) : AbstractPlugin(meta) { 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 val tag: PluginTag get() = Companion.tag
override fun content(target: String): Map<Name, Any> = when (target) { 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 serializersModuleForSolids)
VISION_SERIAL_MODULE_TARGET -> mapOf(tag.name.toName() to serializersModule)
else -> super.content(target) else -> super.content(target)
} }
@ -95,44 +69,49 @@ public class SolidManager(meta: Meta) : AbstractPlugin(meta) {
override val type: KClass<out SolidManager> = SolidManager::class override val type: KClass<out SolidManager> = SolidManager::class
override fun invoke(meta: Meta, context: Context): SolidManager = SolidManager(meta) 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(Point3DSerializer)
contextual(Point2DSerializer) contextual(Point2DSerializer)
polymorphic(Vision::class) { polymorphic(Vision::class) {
subclass(SimpleVisionGroup.serializer()) subclass(SimpleVisionGroup.serializer())
subclass(SolidGroup.serializer()) solids()
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())
} }
polymorphic(Solid::class) { polymorphic(Solid::class) {
subclass(SolidGroup.serializer()) solids()
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())
} }
} }
val jsonForSolids = Json { public val jsonForSolids = Json{
prettyPrint = true prettyPrint = true
useArrayPolymorphism = false useArrayPolymorphism = false
encodeDefaults = false encodeDefaults = false
ignoreUnknownKeys = true 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 phi: Float = PI2,
public var thetaStart: Float = 0f, public var thetaStart: Float = 0f,
public var theta: Float = PI.toFloat(), public var theta: Float = PI.toFloat(),
) : AbstractSolid(), GeometrySolid { ) : BasicSolid(), GeometrySolid {
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) { override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {
fun point3DfromSphCoord(r: Float, theta: Float, phi: Float): Point3D { 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 innerRadius: Float = 0f,
public var startAngle: Float = 0f, public var startAngle: Float = 0f,
public var angle: Float = PI2, public var angle: Float = PI2,
) : AbstractSolid(), GeometrySolid { ) : BasicSolid(), GeometrySolid {
init { init {
require(radius > 0) require(radius > 0)

View File

@ -106,13 +106,3 @@ internal object PrototypesSerializer : KSerializer<MutableVisionGroup> {
mapSerializer.serialize(encoder, value.children) 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.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
/** /**
* Create and attach new proxied group * Create and attach new proxied group
*/ */
@ -29,9 +30,9 @@ class SerializationTest {
x = 100 x = 100
z = -100 z = -100
} }
val string = cube.encodeToString() val string = SolidManager.encodeToString(cube)
println(string) println(string)
val newCube = Vision.decodeFromString(string) val newCube = SolidManager.decodeFromString(string)
assertEquals(cube.config, newCube.config) assertEquals(cube.config, newCube.config)
} }
@ -50,9 +51,9 @@ class SerializationTest {
} }
} }
} }
val string = group.encodeToString() val string = SolidManager.encodeToString(group)
println(string) println(string)
val reconstructed = SolidGroup.decodeFromString(string) val reconstructed = SolidManager.decodeFromString(string) as SolidGroup
assertEquals(group["cube"]?.config, reconstructed["cube"]?.config) assertEquals(group["cube"]?.config, reconstructed["cube"]?.config)
} }

View File

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

View File

@ -1,6 +1,6 @@
package hep.dataforge.vision.solid.three 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 hep.dataforge.vision.solid.Solid
import info.laht.threekt.core.Object3D import info.laht.threekt.core.Object3D
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@ -13,6 +13,6 @@ public interface ThreeVision : Solid {
} }
@Serializable @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) override fun toObject3D(): Object3D = threeFactory(this)
} }