Serialization complete. Fixed tube geometry

This commit is contained in:
Alexander Nozik 2019-08-17 14:22:39 +03:00
parent 71c016d2fd
commit b50a9c590f
28 changed files with 396 additions and 151 deletions

View File

@ -1,4 +1,4 @@
val dataforgeVersion by extra("0.1.3-dev-10") val dataforgeVersion by extra("0.1.3")
plugins{ plugins{
val kotlinVersion = "1.3.50-eap-5" val kotlinVersion = "1.3.50-eap-5"

View File

@ -18,6 +18,7 @@ kotlin {
val jsMain by getting { val jsMain by getting {
dependencies { dependencies {
api("hep.dataforge:dataforge-output-html:$dataforgeVersion") api("hep.dataforge:dataforge-output-html:$dataforgeVersion")
api(npm("text-encoding"))
} }
} }
} }

View File

@ -1,17 +1,20 @@
package hep.dataforge.vis.common package hep.dataforge.vis.common
import hep.dataforge.meta.Config
import hep.dataforge.meta.MetaBuilder import hep.dataforge.meta.MetaBuilder
import hep.dataforge.meta.MetaItem import hep.dataforge.meta.MetaItem
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.get import hep.dataforge.names.toName
import hep.dataforge.provider.Provider import hep.dataforge.provider.Provider
import kotlinx.serialization.Transient import kotlinx.serialization.Transient
import kotlin.collections.set import kotlin.collections.set
open class VisualGroup<T : VisualObject> : AbstractVisualObject(), Iterable<T>, Provider { open class VisualGroup<T : VisualObject> : AbstractVisualObject(), Iterable<T>, Provider {
protected val namedChildren = HashMap<Name, T>() protected open val namedChildren: MutableMap<Name, T> = HashMap()
protected val unnamedChildren = ArrayList<T>() protected open val unnamedChildren: MutableList<T> = ArrayList()
override var properties: Config? = null
override val defaultTarget: String get() = VisualObject.TYPE override val defaultTarget: String get() = VisualObject.TYPE
@ -51,27 +54,25 @@ open class VisualGroup<T : VisualObject> : AbstractVisualObject(), Iterable<T>,
listeners.removeAll { it.owner === owner } listeners.removeAll { it.owner === owner }
} }
operator fun set(name: Name, child: T?) {
if (child == null) {
namedChildren.remove(name)
} else {
if (child.parent == null) {
child.parent = this
} else {
error("Can't reassign existing parent for $child")
}
namedChildren[name] = child
}
listeners.forEach { it.callback(name, child) }
}
/** /**
* Add named or unnamed child to the group. If key is [null] the child is considered unnamed. Both key and value are not * Add named or unnamed child to the group. If key is [null] the child is considered unnamed. Both key and value are not
* allowed to be null in the same time. If name is present and [child] is null, the appropriate element is removed. * allowed to be null in the same time. If name is present and [child] is null, the appropriate element is removed.
*/ */
operator fun set(name: Name?, child: T?) { operator fun set(name: Name?, child: T?) {
when { when {
name != null -> set(name, child) name != null -> {
if (child == null) {
namedChildren.remove(name)
} else {
if (child.parent == null) {
child.parent = this
} else {
error("Can't reassign existing parent for $child")
}
namedChildren[name] = child
}
listeners.forEach { it.callback(name, child) }
}
child != null -> add(child) child != null -> add(child)
else -> error("Both key and child element are empty") else -> error("Both key and child element are empty")
} }
@ -87,7 +88,7 @@ open class VisualGroup<T : VisualObject> : AbstractVisualObject(), Iterable<T>,
/** /**
* Get named child by string * Get named child by string
*/ */
operator fun get(key: String): T? = namedChildren.get(key) operator fun get(key: String): T? = namedChildren[key.toName()]
/** /**
* Get an unnamed child * Get an unnamed child

View File

@ -1,26 +0,0 @@
package hep.dataforge.vis.common
import hep.dataforge.meta.*
import hep.dataforge.names.Name
/**
* Basic [VisualObject] leaf element
*/
open class VisualLeaf(meta: Meta = EmptyMeta) : AbstractVisualObject(), Configurable {
val properties = Styled(meta)
override val config: Config = properties.style
override fun setProperty(name: Name, value: Any?) {
config[name] = value
}
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {
return if (inherit) {
properties[name] ?: parent?.getProperty(name, inherit)
} else {
properties[name]
}
}
}

View File

@ -1,12 +1,9 @@
package hep.dataforge.vis.common package hep.dataforge.vis.common
import hep.dataforge.io.ConfigSerializer
import hep.dataforge.meta.* import hep.dataforge.meta.*
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.provider.Type import hep.dataforge.provider.Type
import hep.dataforge.vis.common.VisualObject.Companion.TYPE import hep.dataforge.vis.common.VisualObject.Companion.TYPE
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient import kotlinx.serialization.Transient
private fun Laminate.withTop(meta: Meta): Laminate = Laminate(listOf(meta) + layers) private fun Laminate.withTop(meta: Meta): Laminate = Laminate(listOf(meta) + layers)
@ -18,8 +15,6 @@ private fun Laminate.withBottom(meta: Meta): Laminate = Laminate(layers + meta)
@Type(TYPE) @Type(TYPE)
interface VisualObject : MetaRepr, Configurable { interface VisualObject : MetaRepr, Configurable {
val type: String get() = this::class.simpleName ?: TYPE
/** /**
* The parent object of this one. If null, this one is a root. * The parent object of this one. If null, this one is a root.
*/ */
@ -64,7 +59,9 @@ internal data class MetaListener(
val action: (name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) -> Unit val action: (name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) -> Unit
) )
abstract class AbstractVisualObject : VisualObject { abstract class AbstractVisualObject: VisualObject {
@Transient
override var parent: VisualObject? = null override var parent: VisualObject? = null
@Transient @Transient
@ -84,12 +81,10 @@ abstract class AbstractVisualObject : VisualObject {
listeners.removeAll { it.owner == owner } listeners.removeAll { it.owner == owner }
} }
@Serializable(ConfigSerializer::class) abstract var properties: Config?
@SerialName("properties")
private var _config: Config? = null
override val config: Config override val config: Config
get() = _config ?: Config().also { config -> get() = properties ?: Config().also { config ->
_config = config properties = config
config.onChange(this, ::propertyChanged) config.onChange(this, ::propertyChanged)
} }
@ -99,19 +94,17 @@ abstract class AbstractVisualObject : VisualObject {
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? { override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {
return if (inherit) { return if (inherit) {
_config?.get(name) ?: parent?.getProperty(name, inherit) properties?.get(name) ?: parent?.getProperty(name, inherit)
} else { } else {
_config?.get(name) properties?.get(name)
} }
} }
protected open fun MetaBuilder.updateMeta() {} protected open fun MetaBuilder.updateMeta() {}
override fun toMeta(): Meta = buildMeta { override fun toMeta(): Meta = buildMeta {
"type" to type "type" to this::class.simpleName
"properties" to config "properties" to properties
updateMeta() updateMeta()
} }
} }

View File

@ -0,0 +1,26 @@
package hep.dataforge.vis.spatial.gdml
import hep.dataforge.vis.spatial.Visual3DPlugin
import hep.dataforge.vis.spatial.VisualGroup3D
import nl.adaptivity.xmlutil.StAXReader
import scientifik.gdml.GDML
import java.io.File
fun main() {
val file = File("D:\\Work\\Projects\\gdml.kt\\gdml-source\\BM@N_coil.gdml")
val xmlReader = StAXReader(file.inputStream(), "UTF-8")
val xml = GDML.format.parse(GDML.serializer(), xmlReader)
val visual = xml.toVisual {
lUnit = LUnit.CM
}
//val meta = visual.toMeta()
val str = Visual3DPlugin.json.stringify(VisualGroup3D.serializer(), visual)
println(str)
//println(Json.indented.stringify(meta.toJson()))
}

View File

@ -29,7 +29,7 @@ kotlin {
dependencies { dependencies {
api("info.laht.threekt:threejs-wrapper:0.106-npm-3") api("info.laht.threekt:threejs-wrapper:0.106-npm-3")
implementation(npm("three", "0.106.2")) implementation(npm("three", "0.106.2"))
implementation(npm("@hi-level/three-csg")) implementation(npm("@hi-level/three-csg", "1.0.6"))
implementation(npm("style-loader")) implementation(npm("style-loader"))
implementation(npm("element-resize-event")) implementation(npm("element-resize-event"))
} }

View File

@ -1,19 +1,29 @@
@file:UseSerializers(Point3DSerializer::class)
package hep.dataforge.vis.spatial package hep.dataforge.vis.spatial
import hep.dataforge.context.Context import hep.dataforge.context.Context
import hep.dataforge.meta.Meta import hep.dataforge.io.ConfigSerializer
import hep.dataforge.meta.MetaBuilder import hep.dataforge.meta.*
import hep.dataforge.meta.float import hep.dataforge.vis.common.AbstractVisualObject
import hep.dataforge.meta.get
import hep.dataforge.vis.common.VisualFactory import hep.dataforge.vis.common.VisualFactory
import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.common.VisualObject
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
import kotlin.reflect.KClass import kotlin.reflect.KClass
@Serializable
data class Box( data class Box(
val xSize: Float, val xSize: Float,
val ySize: Float, val ySize: Float,
val zSize: Float val zSize: Float
) : VisualLeaf3D(), Shape { ) : AbstractVisualObject(), VisualObject3D, Shape {
override var position: Point3D? = null
override var rotation: Point3D? = null
override var scale: Point3D? = null
@Serializable(ConfigSerializer::class)
override var properties: Config? = null
//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>) {
@ -40,8 +50,13 @@ data class Box(
"xSize" to xSize "xSize" to xSize
"ySize" to ySize "ySize" to ySize
"zSize" to ySize "zSize" to ySize
updatePosition()
} }
// override fun toMeta(): Meta {
// return (Visual3DPlugin.json.toJson(Box.serializer(), this) as JsonObject).toMeta()
// }
companion object : VisualFactory<Box> { companion object : VisualFactory<Box> {
const val TYPE = "geometry.3d.box" const val TYPE = "geometry.3d.box"

View File

@ -1,7 +1,13 @@
@file:UseSerializers(Point3DSerializer::class)
package hep.dataforge.vis.spatial package hep.dataforge.vis.spatial
import hep.dataforge.meta.isEmpty import hep.dataforge.io.ConfigSerializer
import hep.dataforge.meta.Config
import hep.dataforge.meta.MetaBuilder
import hep.dataforge.meta.update import hep.dataforge.meta.update
import hep.dataforge.vis.common.AbstractVisualObject
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
enum class CompositeType { enum class CompositeType {
UNION, UNION,
@ -9,11 +15,27 @@ enum class CompositeType {
SUBTRACT SUBTRACT
} }
open class Composite( @Serializable
class Composite(
val compositeType: CompositeType,
val first: VisualObject3D, val first: VisualObject3D,
val second: VisualObject3D, val second: VisualObject3D
val compositeType: CompositeType = CompositeType.UNION ) : AbstractVisualObject(), VisualObject3D {
) : VisualLeaf3D()
override var position: Point3D? = null
override var rotation: Point3D? = null
override var scale: Point3D? = null
@Serializable(ConfigSerializer::class)
override var properties: Config? = null
override fun MetaBuilder.updateMeta() {
"compositeType" to compositeType
"first" to first.toMeta()
"second" to second.toMeta()
updatePosition()
}
}
inline fun VisualGroup3D.composite( inline fun VisualGroup3D.composite(
type: CompositeType, type: CompositeType,
@ -23,14 +45,14 @@ inline fun VisualGroup3D.composite(
val group = VisualGroup3D().apply(builder) val group = VisualGroup3D().apply(builder)
val children = group.filterIsInstance<VisualObject3D>() val children = group.filterIsInstance<VisualObject3D>()
if (children.size != 2) error("Composite requires exactly two children") if (children.size != 2) error("Composite requires exactly two children")
return Composite(children[0], children[1], type).also { return Composite(type, children[0], children[1]).also {
if (!group.config.isEmpty()) { if (group.properties != null) {
it.config.update(group.config) it.config.update(group.config)
it.material = group.material
} }
it.position = group.position it.position = group.position
it.rotation = group.rotation it.rotation = group.rotation
it.scale = group.scale it.scale = group.scale
it.material = group.material
set(name, it) set(name, it)
} }
} }

View File

@ -0,0 +1,40 @@
@file:UseSerializers(Point3DSerializer::class)
package hep.dataforge.vis.spatial
import hep.dataforge.io.ConfigSerializer
import hep.dataforge.meta.Config
import hep.dataforge.vis.common.AbstractVisualObject
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
/**
* A cylinder or cut cone segment
*/
@Serializable
class ConeSegment(
var radius: Float,
var height: Float,
var upperRadius: Float,
var startAngle: Float = 0f,
var angle: Float = PI2
) : AbstractVisualObject(), VisualObject3D {
@Serializable(ConfigSerializer::class)
override var properties: Config? = null
override var position: Point3D? = null
override var rotation: Point3D? = null
override var scale: Point3D? = null
}
inline fun VisualGroup3D.cylinder(
r: Number,
height: Number,
name: String? = null,
block: ConeSegment.() -> Unit = {}
): ConeSegment = ConeSegment(
r.toFloat(),
height.toFloat(),
r.toFloat()
).apply(block).also { set(name, it) }

View File

@ -1,15 +1,29 @@
@file:UseSerializers(Point3DSerializer::class)
package hep.dataforge.vis.spatial package hep.dataforge.vis.spatial
import hep.dataforge.io.ConfigSerializer
import hep.dataforge.meta.Config
import hep.dataforge.meta.MetaBuilder import hep.dataforge.meta.MetaBuilder
import hep.dataforge.vis.common.AbstractVisualObject
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
class Convex( @Serializable
val points: List<Point3D> class Convex(val points: List<Point3D>) : AbstractVisualObject(), VisualObject3D {
) : VisualLeaf3D() {
@Serializable(ConfigSerializer::class)
override var properties: Config? = null
override var position: Point3D? = null
override var rotation: Point3D? = null
override var scale: Point3D? = null
override fun MetaBuilder.updateMeta() { override fun MetaBuilder.updateMeta() {
"points" to { "points" to {
"point" to points.map{it.toMeta()} "point" to points.map { it.toMeta() }
} }
updatePosition()
} }
companion object { companion object {

View File

@ -1,22 +0,0 @@
package hep.dataforge.vis.spatial
/**
* A cylinder or cut cone segment
*/
class Cylinder(
var radius: Float,
var height: Float,
var upperRadius: Float = radius,
var startAngle: Float = 0f,
var angle: Float = PI2
) : VisualLeaf3D()
inline fun VisualGroup3D.cylinder(
r: Number,
height: Number,
name: String? = null,
block: Cylinder.() -> Unit = {}
): Cylinder = Cylinder(
r.toFloat(),
height.toFloat()
).apply(block).also { set(name, it) }

View File

@ -1,5 +1,11 @@
@file:UseSerializers(Point2DSerializer::class, Point3DSerializer::class)
package hep.dataforge.vis.spatial package hep.dataforge.vis.spatial
import hep.dataforge.io.ConfigSerializer
import hep.dataforge.meta.Config
import hep.dataforge.vis.common.AbstractVisualObject
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
import kotlin.math.PI import kotlin.math.PI
import kotlin.math.cos import kotlin.math.cos
import kotlin.math.sin import kotlin.math.sin
@ -7,16 +13,16 @@ import kotlin.math.sin
typealias Shape2D = List<Point2D> typealias Shape2D = List<Point2D>
class Shape2DBuilder { @Serializable
private val list = ArrayList<Point2D>() class Shape2DBuilder(private val points: MutableList<Point2D> = ArrayList()) {
fun point(x: Number, y: Number) { fun point(x: Number, y: Number) {
list.add(Point2D(x, y)) points.add(Point2D(x, y))
} }
infix fun Number.to(y: Number) = point(this, y) infix fun Number.to(y: Number) = point(this, y)
fun build(): Shape2D = list fun build(): Shape2D = points
} }
fun Shape2DBuilder.polygon(vertices: Int, radius: Number) { fun Shape2DBuilder.polygon(vertices: Int, radius: Number) {
@ -27,19 +33,27 @@ fun Shape2DBuilder.polygon(vertices: Int, radius: Number) {
} }
} }
@Serializable
data class Layer(var x: Float, var y: Float, var z: Float, var scale: Float) data class Layer(var x: Float, var y: Float, var z: Float, var scale: Float)
class Extruded : VisualLeaf3D(), Shape { @Serializable
class Extruded(
var shape: List<Point2D> = ArrayList(),
var layers: MutableList<Layer> = ArrayList()
) : AbstractVisualObject(), VisualObject3D, Shape {
var shape: List<Point2D> = ArrayList() @Serializable(ConfigSerializer::class)
override var properties: Config? = null
override var position: Point3D? = null
override var rotation: Point3D? = null
override var scale: Point3D? = null
fun shape(block: Shape2DBuilder.() -> Unit) { fun shape(block: Shape2DBuilder.() -> Unit) {
this.shape = Shape2DBuilder().apply(block).build() this.shape = Shape2DBuilder().apply(block).build()
//TODO send invalidation signal //TODO send invalidation signal
} }
val layers: MutableList<Layer> = ArrayList()
fun layer(z: Number, x: Number = 0.0, y: Number = 0.0, scale: Number = 1.0) { fun layer(z: Number, x: Number = 0.0, y: Number = 0.0, scale: Number = 1.0) {
layers.add(Layer(x.toFloat(), y.toFloat(), z.toFloat(), scale.toFloat())) layers.add(Layer(x.toFloat(), y.toFloat(), z.toFloat(), scale.toFloat()))
//TODO send invalidation signal //TODO send invalidation signal

View File

@ -1,25 +1,37 @@
@file:UseSerializers(Point3DSerializer::class, NameSerializer::class)
package hep.dataforge.vis.spatial package hep.dataforge.vis.spatial
import hep.dataforge.io.ConfigSerializer
import hep.dataforge.io.NameSerializer
import hep.dataforge.meta.Config
import hep.dataforge.meta.MetaBuilder import hep.dataforge.meta.MetaBuilder
import hep.dataforge.meta.MetaItem import hep.dataforge.meta.MetaItem
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.vis.common.AbstractVisualObject import hep.dataforge.vis.common.AbstractVisualObject
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
/** /**
* A proxy [VisualObject3D] to reuse a template object * A proxy [VisualObject3D] to reuse a template object
*/ */
@Serializable
class Proxy(val templateName: Name) : AbstractVisualObject(), VisualObject3D { class Proxy(val templateName: Name) : AbstractVisualObject(), VisualObject3D {
override var position: Point3D? = null override var position: Point3D? = null
override var rotation: Point3D? = null override var rotation: Point3D? = null
override var scale: Point3D? = null override var scale: Point3D? = null
@Serializable(ConfigSerializer::class)
override var properties: Config? = null
/** /**
* Recursively search for defined template in the parent * Recursively search for defined template in the parent
*/ */
val template by lazy { val template: VisualObject3D
(parent as? VisualGroup3D)?.getTemplate(templateName) get() = (parent as? VisualGroup3D)?.getTemplate(templateName)
?: error("Template with name $templateName not found in $parent") ?: error("Template with name $templateName not found in $parent")
}
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? { override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {
return if (inherit) { return if (inherit) {

View File

@ -1,14 +1,30 @@
@file:UseSerializers(Point3DSerializer::class)
package hep.dataforge.vis.spatial package hep.dataforge.vis.spatial
import hep.dataforge.io.ConfigSerializer
import hep.dataforge.meta.Config
import hep.dataforge.vis.common.AbstractVisualObject
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
import kotlin.math.PI import kotlin.math.PI
@Serializable
class Sphere( class Sphere(
var radius: Float, var radius: Float,
var phiStart: Float = 0f, var phiStart: Float = 0f,
var phi: Float = PI2, var phi: Float = PI2,
var thetaStart: Float = 0f, var thetaStart: Float = 0f,
var theta: Float = PI.toFloat() var theta: Float = PI.toFloat()
) : VisualLeaf3D() ) : AbstractVisualObject(), VisualObject3D {
@Serializable(ConfigSerializer::class)
override var properties: Config? = null
override var position: Point3D? = null
override var rotation: Point3D? = null
override var scale: Point3D? = null
}
inline fun VisualGroup3D.sphere( inline fun VisualGroup3D.sphere(
radius: Number, radius: Number,

View File

@ -1,5 +1,11 @@
@file:UseSerializers(Point3DSerializer::class)
package hep.dataforge.vis.spatial package hep.dataforge.vis.spatial
import hep.dataforge.io.ConfigSerializer
import hep.dataforge.meta.Config
import hep.dataforge.vis.common.AbstractVisualObject
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
import kotlin.math.PI import kotlin.math.PI
import kotlin.math.cos import kotlin.math.cos
import kotlin.math.sin import kotlin.math.sin
@ -7,13 +13,21 @@ import kotlin.math.sin
/** /**
* Straight tube segment * Straight tube segment
*/ */
@Serializable
class Tube( class Tube(
var radius: Float, var radius: Float,
var height: Float, var height: Float,
var innerRadius: Float = 0f, var innerRadius: Float = 0f,
var startAngle: Float = 0f, var startAngle: Float = 0f,
var angle: Float = PI2 var angle: Float = PI2
) : VisualLeaf3D(), Shape { ) : AbstractVisualObject(), VisualObject3D, Shape {
override var position: Point3D? = null
override var rotation: Point3D? = null
override var scale: Point3D? = null
@Serializable(ConfigSerializer::class)
override var properties: Config? = null
init { init {
require(radius > 0) require(radius > 0)
@ -37,8 +51,8 @@ class Tube(
geometryBuilder.apply { geometryBuilder.apply {
//creating shape in x-y plane with z = 0 //creating shape in x-y plane with z = 0
val bottomOuterPoints = shape(radius, 0f) val bottomOuterPoints = shape(radius, -height/2)
val upperOuterPoints = shape(radius, height) val upperOuterPoints = shape(radius, height/2)
//outer face //outer face
(1 until segments).forEach { (1 until segments).forEach {
face4(bottomOuterPoints[it - 1], bottomOuterPoints[it], upperOuterPoints[it], upperOuterPoints[it - 1]) face4(bottomOuterPoints[it - 1], bottomOuterPoints[it], upperOuterPoints[it], upperOuterPoints[it - 1])
@ -62,8 +76,8 @@ class Tube(
face4(zeroTop, zeroBottom, bottomOuterPoints.last(), upperOuterPoints.last()) face4(zeroTop, zeroBottom, bottomOuterPoints.last(), upperOuterPoints.last())
} }
} else { } else {
val bottomInnerPoints = shape(innerRadius, 0f) val bottomInnerPoints = shape(innerRadius, -height/2)
val upperInnerPoints = shape(innerRadius, height) val upperInnerPoints = shape(innerRadius, height/2)
//outer face //outer face
(1 until segments).forEach { (1 until segments).forEach {
// inner surface // inner surface
@ -97,9 +111,14 @@ class Tube(
bottomOuterPoints.last() bottomOuterPoints.last()
) )
face4(upperInnerPoints[0], upperInnerPoints.last(), upperOuterPoints.last(), upperOuterPoints[0]) face4(upperInnerPoints[0], upperInnerPoints.last(), upperOuterPoints.last(), upperOuterPoints[0])
} else{ } else {
face4(bottomInnerPoints[0],bottomOuterPoints[0],upperOuterPoints[0],upperInnerPoints[0]) face4(bottomInnerPoints[0], bottomOuterPoints[0], upperOuterPoints[0], upperInnerPoints[0])
face4(bottomOuterPoints.last(),bottomInnerPoints.last(),upperInnerPoints.last(),upperOuterPoints.last()) face4(
bottomOuterPoints.last(),
bottomInnerPoints.last(),
upperInnerPoints.last(),
upperOuterPoints.last()
)
} }
} }
} }

View File

@ -6,6 +6,9 @@ import hep.dataforge.context.PluginTag
import hep.dataforge.meta.* import hep.dataforge.meta.*
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.vis.common.VisualPlugin import hep.dataforge.vis.common.VisualPlugin
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration
import kotlinx.serialization.modules.SerializersModule
import kotlin.reflect.KClass import kotlin.reflect.KClass
class Visual3DPlugin(meta: Meta) : AbstractPlugin(meta) { class Visual3DPlugin(meta: Meta) : AbstractPlugin(meta) {
@ -23,6 +26,26 @@ class Visual3DPlugin(meta: Meta) : AbstractPlugin(meta) {
override val tag: PluginTag = PluginTag(name = "visual.spatial", group = PluginTag.DATAFORGE_GROUP) override val tag: PluginTag = PluginTag(name = "visual.spatial", group = PluginTag.DATAFORGE_GROUP)
override val type: KClass<out Visual3DPlugin> = Visual3DPlugin::class override val type: KClass<out Visual3DPlugin> = Visual3DPlugin::class
override fun invoke(meta: Meta): Visual3DPlugin = Visual3DPlugin(meta) override fun invoke(meta: Meta): Visual3DPlugin = Visual3DPlugin(meta)
val serialModule = SerializersModule {
polymorphic(VisualObject3D::class) {
VisualGroup3D::class with VisualGroup3D.serializer()
Proxy::class with Proxy.serializer()
Composite::class with Composite.serializer()
Tube::class with Tube.serializer()
Box::class with Box.serializer()
Convex::class with Convex.serializer()
}
}
val json = Json(
JsonConfiguration(
prettyPrint = true,
useArrayPolymorphism = false,
encodeDefaults = false
),
context = serialModule
)
} }
} }

View File

@ -1,16 +1,21 @@
@file:UseSerializers(Point3DSerializer::class, NameSerializer::class)
package hep.dataforge.vis.spatial package hep.dataforge.vis.spatial
import hep.dataforge.io.ConfigSerializer
import hep.dataforge.io.NameSerializer
import hep.dataforge.meta.* import hep.dataforge.meta.*
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.plus import hep.dataforge.names.plus
import hep.dataforge.output.Output import hep.dataforge.output.Output
import hep.dataforge.vis.common.AbstractVisualObject
import hep.dataforge.vis.common.VisualGroup import hep.dataforge.vis.common.VisualGroup
import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.common.VisualObject
import hep.dataforge.vis.common.asName import hep.dataforge.vis.common.asName
import hep.dataforge.vis.spatial.VisualObject3D.Companion.DETAIL_KEY import hep.dataforge.vis.spatial.VisualObject3D.Companion.DETAIL_KEY
import hep.dataforge.vis.spatial.VisualObject3D.Companion.MATERIAL_KEY import hep.dataforge.vis.spatial.VisualObject3D.Companion.MATERIAL_KEY
import hep.dataforge.vis.spatial.VisualObject3D.Companion.VISIBLE_KEY import hep.dataforge.vis.spatial.VisualObject3D.Companion.VISIBLE_KEY
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
interface VisualObject3D : VisualObject { interface VisualObject3D : VisualObject {
var position: Point3D? var position: Point3D?
@ -60,18 +65,8 @@ interface VisualObject3D : VisualObject {
} }
} }
abstract class VisualLeaf3D : AbstractVisualObject(), VisualObject3D, Configurable { @Serializable
override var position: Point3D? = null
override var rotation: Point3D? = null
override var scale: Point3D? = null
}
class VisualGroup3D : VisualGroup<VisualObject3D>(), VisualObject3D, Configurable { class VisualGroup3D : VisualGroup<VisualObject3D>(), VisualObject3D, Configurable {
override var position: Point3D? = null
override var rotation: Point3D? = null
override var scale: Point3D? = null
/** /**
* A container for templates visible inside this group * A container for templates visible inside this group
*/ */
@ -81,12 +76,27 @@ class VisualGroup3D : VisualGroup<VisualObject3D>(), VisualObject3D, Configurabl
field = value field = value
} }
@Serializable(ConfigSerializer::class)
override var properties: Config? = null
override var position: Point3D? = null
override var rotation: Point3D? = null
override var scale: Point3D? = null
override val namedChildren: MutableMap<Name, VisualObject3D> = HashMap()
override val unnamedChildren: MutableList<VisualObject3D> = ArrayList()
fun getTemplate(name: Name): VisualObject3D? = templates?.get(name) ?: (parent as? VisualGroup3D)?.getTemplate(name) fun getTemplate(name: Name): VisualObject3D? = templates?.get(name) ?: (parent as? VisualGroup3D)?.getTemplate(name)
override fun MetaBuilder.updateMeta() { override fun MetaBuilder.updateMeta() {
set(TEMPLATES_KEY, templates?.toMeta())
updatePosition() updatePosition()
updateChildren() updateChildren()
} }
companion object {
const val TEMPLATES_KEY = "templates"
}
} }
fun VisualGroup3D.group(key: String? = null, action: VisualGroup3D.() -> Unit = {}): VisualGroup3D = fun VisualGroup3D.group(key: String? = null, action: VisualGroup3D.() -> Unit = {}): VisualGroup3D =
@ -213,5 +223,4 @@ var VisualObject3D.scaleZ: Number
set(value) { set(value) {
scale().z = value.toDouble() scale().z = value.toDouble()
propertyChanged(VisualObject3D.zScale) propertyChanged(VisualObject3D.zScale)
} }

View File

@ -0,0 +1,41 @@
package hep.dataforge.vis.spatial
import kotlinx.serialization.*
@Serializable
private data class Point2DSerial(val x: Double, val y: Double)
@Serializable
private data class Point3DSerial(val x: Double, val y: Double, val z: Double)
@Serializer(Point3D::class)
object Point3DSerializer : KSerializer<Point3D> {
private val serializer = Point3DSerial.serializer()
override val descriptor: SerialDescriptor get() = serializer.descriptor
override fun deserialize(decoder: Decoder): Point3D {
return serializer.deserialize(decoder).let {
Point3D(it.x, it.y, it.z)
}
}
override fun serialize(encoder: Encoder, obj: Point3D) {
serializer.serialize(encoder, Point3DSerial(obj.x, obj.y, obj.z) )
}
}
@Serializer(Point2D::class)
object Point2DSerializer : KSerializer<Point2D> {
private val serializer = Point2DSerial.serializer()
override val descriptor: SerialDescriptor get() = serializer.descriptor
override fun deserialize(decoder: Decoder): Point2D {
return serializer.deserialize(decoder).let {
Point2D(it.x, it.y)
}
}
override fun serialize(encoder: Encoder, obj: Point2D) {
serializer.serialize(encoder, Point2DSerial(obj.x, obj.y))
}
}

View File

@ -25,6 +25,8 @@ class ConvexTest {
val convex = group.first() as Convex val convex = group.first() as Convex
val meta = convex.toMeta()
val pointsNode = convex.toMeta()["points"].node val pointsNode = convex.toMeta()["points"].node
assertEquals(8, pointsNode?.items?.count()) assertEquals(8, pointsNode?.items?.count())

View File

@ -1,13 +1,15 @@
package hep.dataforge.vis.spatial package hep.dataforge.vis.spatial
import hep.dataforge.context.Global import hep.dataforge.context.Global
import kotlinx.serialization.ImplicitReflectionSerializer
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
class SerializationTest { class SerializationTest {
@ImplicitReflectionSerializer
@Test @Test
fun testCubeSerialization(){ fun testCubeSerialization(){
val cube = Box(null,100f,100f,100f).apply{ val cube = Box(100f,100f,100f).apply{
color(222) color(222)
} }
val meta = cube.toMeta() val meta = cube.toMeta()

View File

@ -3,7 +3,6 @@ package hep.dataforge.vis.spatial.three
import hep.dataforge.vis.spatial.Composite import hep.dataforge.vis.spatial.Composite
import hep.dataforge.vis.spatial.CompositeType import hep.dataforge.vis.spatial.CompositeType
import info.laht.threekt.core.BufferGeometry import info.laht.threekt.core.BufferGeometry
import info.laht.threekt.core.Geometry
import info.laht.threekt.objects.Mesh import info.laht.threekt.objects.Mesh
/** /**
@ -23,9 +22,7 @@ class ThreeCompositeFactory(val three: ThreePlugin) : MeshThreeFactory<Composite
CompositeType.INTERSECT -> firstCSG.intersect(secondCSG) CompositeType.INTERSECT -> firstCSG.intersect(secondCSG)
CompositeType.SUBTRACT -> firstCSG.subtract(secondCSG) CompositeType.SUBTRACT -> firstCSG.subtract(secondCSG)
} }
return resultCSG.toGeometry().toBufferGeometry()
val mesh = CSG.toMesh(resultCSG, second.matrix)
return (mesh.geometry as Geometry).toBufferGeometry()
} }
} }

View File

@ -1,14 +1,14 @@
package hep.dataforge.vis.spatial.three package hep.dataforge.vis.spatial.three
import hep.dataforge.vis.spatial.Cylinder import hep.dataforge.vis.spatial.ConeSegment
import hep.dataforge.vis.spatial.detail import hep.dataforge.vis.spatial.detail
import info.laht.threekt.core.BufferGeometry import info.laht.threekt.core.BufferGeometry
import info.laht.threekt.geometries.CylinderBufferGeometry import info.laht.threekt.geometries.CylinderBufferGeometry
import kotlin.math.PI import kotlin.math.PI
import kotlin.math.pow import kotlin.math.pow
object ThreeCylinderFactory : MeshThreeFactory<Cylinder>(Cylinder::class) { object ThreeCylinderFactory : MeshThreeFactory<ConeSegment>(ConeSegment::class) {
override fun buildGeometry(obj: Cylinder): BufferGeometry { override fun buildGeometry(obj: ConeSegment): BufferGeometry {
val cylinder = obj.detail?.let { val cylinder = obj.detail?.let {
val segments = it.toDouble().pow(0.5).toInt() val segments = it.toDouble().pow(0.5).toInt()
CylinderBufferGeometry( CylinderBufferGeometry(

View File

@ -37,6 +37,12 @@ interface ThreeFactory<T : VisualObject3D> {
*/ */
internal fun Object3D.updatePosition(obj: VisualObject3D) { internal fun Object3D.updatePosition(obj: VisualObject3D) {
visible = obj.visible ?: true visible = obj.visible ?: true
// Matrix4().apply {
// makeRotationFromEuler(obj.euler)
// applyMatrix(this)
// makeTranslation(obj.x.toDouble(), obj.y.toDouble(), obj.z.toDouble())
// applyMatrix(this)
// }
position.set(obj.x, obj.y, obj.z) position.set(obj.x, obj.y, obj.z)
setRotationFromEuler(obj.euler) setRotationFromEuler(obj.euler)
scale.set(obj.scaleX, obj.scaleY, obj.scaleZ) scale.set(obj.scaleX, obj.scaleY, obj.scaleZ)

View File

@ -27,7 +27,7 @@ class ThreePlugin : AbstractPlugin() {
objectFactories[Box::class] = ThreeBoxFactory objectFactories[Box::class] = ThreeBoxFactory
objectFactories[Convex::class] = ThreeConvexFactory objectFactories[Convex::class] = ThreeConvexFactory
objectFactories[Sphere::class] = ThreeSphereFactory objectFactories[Sphere::class] = ThreeSphereFactory
objectFactories[Cylinder::class] = ThreeCylinderFactory objectFactories[ConeSegment::class] = ThreeCylinderFactory
} }
private fun findObjectFactory(type: KClass<out VisualObject3D>): ThreeFactory<*>? { private fun findObjectFactory(type: KClass<out VisualObject3D>): ThreeFactory<*>? {

View File

@ -13,10 +13,11 @@ package hep.dataforge.vis.spatial.three
import info.laht.threekt.math.Matrix4 import info.laht.threekt.math.Matrix4
import info.laht.threekt.math.Vector3
import info.laht.threekt.objects.Mesh import info.laht.threekt.objects.Mesh
open external class CSG { open external class CSG {
open var polygons: Any open var polygons: Array<Polygon>
open fun clone(): CSG open fun clone(): CSG
open fun toPolygons(): Array<Polygon> open fun toPolygons(): Array<Polygon>
open fun union(csg: CSG): CSG open fun union(csg: CSG): CSG
@ -40,8 +41,7 @@ open external class CSG {
} }
} }
open external class Vector(x: Number, y: Number, z: Number) { open external class Vector(x: Number, y: Number, z: Number): Vector3 {
open fun clone(): Any
open fun negated(): Vector open fun negated(): Vector
open fun plus(a: Vector): Vector open fun plus(a: Vector): Vector
open fun minus(a: Vector): Vector open fun minus(a: Vector): Vector

View File

@ -6,6 +6,7 @@ import hep.dataforge.meta.get
import hep.dataforge.meta.node import hep.dataforge.meta.node
import hep.dataforge.vis.spatial.* import hep.dataforge.vis.spatial.*
import info.laht.threekt.core.BufferGeometry import info.laht.threekt.core.BufferGeometry
import info.laht.threekt.core.Face3
import info.laht.threekt.core.Geometry import info.laht.threekt.core.Geometry
import info.laht.threekt.core.Object3D import info.laht.threekt.core.Object3D
import info.laht.threekt.math.Euler import info.laht.threekt.math.Euler
@ -25,4 +26,42 @@ val VisualObject3D.euler get() = Euler(rotationX, rotationY, rotationZ, rotation
val MetaItem<*>.vector get() = Vector3(node["x"].float ?: 0f, node["y"].float ?: 0f, node["z"].float ?: 0f) val MetaItem<*>.vector get() = Vector3(node["x"].float ?: 0f, node["y"].float ?: 0f, node["z"].float ?: 0f)
fun Geometry.toBufferGeometry(): BufferGeometry = BufferGeometry().apply { fromGeometry(this@toBufferGeometry) } fun Geometry.toBufferGeometry(): BufferGeometry = BufferGeometry().apply { fromGeometry(this@toBufferGeometry) }
fun CSG.toGeometry(): Geometry {
val geom = Geometry()
val vertices = ArrayList<Vector3>()
val faces = ArrayList<Face3>()
for (polygon in polygons) {
val v0 = vertices.size
val pvs = polygon.vertices
for (pv in pvs) {
vertices.add(Vector3().copy(pv.pos))
}
for (j in 3..polygon.vertices.size) {
val fc = Face3(v0, v0 + j - 2, v0 + j - 1, zero)
fc.vertexNormals = arrayOf(
Vector3().copy(pvs[0].normal),
Vector3().copy(pvs[j - 2].normal),
Vector3().copy(pvs[j - 1].normal)
)
fc.normal = Vector3().copy(polygon.plane.normal)
faces.add(fc)
}
}
geom.vertices = vertices.toTypedArray()
geom.faces = faces.toTypedArray()
// val inv: Matrix4 = Matrix4().apply { getInverse(toMatrix) }
// geom.applyMatrix(toMatrix)
geom.verticesNeedUpdate = true
geom.elementsNeedUpdate = true
geom.normalsNeedUpdate = true
geom.computeBoundingSphere()
geom.computeBoundingBox()
return geom
}

View File

@ -45,6 +45,7 @@ class ThreeDemoGrid(meta: Meta) : AbstractPlugin(meta), OutputManager {
element.append(gridRoot) element.append(gridRoot)
} }
@Suppress("UNCHECKED_CAST")
override fun <T : Any> get(type: KClass<out T>, name: Name, stage: Name, meta: Meta): Output<T> { override fun <T : Any> get(type: KClass<out T>, name: Name, stage: Name, meta: Meta): Output<T> {
val three = context.plugins.get<ThreePlugin>()!! val three = context.plugins.get<ThreePlugin>()!!