forked from kscience/visionforge
Serialization complete. Fixed tube geometry
This commit is contained in:
parent
71c016d2fd
commit
b50a9c590f
@ -1,4 +1,4 @@
|
||||
val dataforgeVersion by extra("0.1.3-dev-10")
|
||||
val dataforgeVersion by extra("0.1.3")
|
||||
|
||||
plugins{
|
||||
val kotlinVersion = "1.3.50-eap-5"
|
||||
|
@ -18,6 +18,7 @@ kotlin {
|
||||
val jsMain by getting {
|
||||
dependencies {
|
||||
api("hep.dataforge:dataforge-output-html:$dataforgeVersion")
|
||||
api(npm("text-encoding"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,20 @@
|
||||
package hep.dataforge.vis.common
|
||||
|
||||
import hep.dataforge.meta.Config
|
||||
import hep.dataforge.meta.MetaBuilder
|
||||
import hep.dataforge.meta.MetaItem
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.get
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.provider.Provider
|
||||
import kotlinx.serialization.Transient
|
||||
import kotlin.collections.set
|
||||
|
||||
open class VisualGroup<T : VisualObject> : AbstractVisualObject(), Iterable<T>, Provider {
|
||||
|
||||
protected val namedChildren = HashMap<Name, T>()
|
||||
protected val unnamedChildren = ArrayList<T>()
|
||||
protected open val namedChildren: MutableMap<Name, T> = HashMap()
|
||||
protected open val unnamedChildren: MutableList<T> = ArrayList()
|
||||
|
||||
override var properties: Config? = null
|
||||
|
||||
override val defaultTarget: String get() = VisualObject.TYPE
|
||||
|
||||
@ -51,7 +54,13 @@ open class VisualGroup<T : VisualObject> : AbstractVisualObject(), Iterable<T>,
|
||||
listeners.removeAll { it.owner === owner }
|
||||
}
|
||||
|
||||
operator fun set(name: Name, child: T?) {
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
operator fun set(name: Name?, child: T?) {
|
||||
when {
|
||||
name != null -> {
|
||||
if (child == null) {
|
||||
namedChildren.remove(name)
|
||||
} else {
|
||||
@ -64,14 +73,6 @@ open class VisualGroup<T : VisualObject> : AbstractVisualObject(), Iterable<T>,
|
||||
}
|
||||
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
|
||||
* 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?) {
|
||||
when {
|
||||
name != null -> set(name, child)
|
||||
child != null -> add(child)
|
||||
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
|
||||
*/
|
||||
operator fun get(key: String): T? = namedChildren.get(key)
|
||||
operator fun get(key: String): T? = namedChildren[key.toName()]
|
||||
|
||||
/**
|
||||
* Get an unnamed child
|
||||
|
@ -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]
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +1,9 @@
|
||||
package hep.dataforge.vis.common
|
||||
|
||||
import hep.dataforge.io.ConfigSerializer
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.provider.Type
|
||||
import hep.dataforge.vis.common.VisualObject.Companion.TYPE
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.Transient
|
||||
|
||||
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)
|
||||
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.
|
||||
*/
|
||||
@ -64,7 +59,9 @@ internal data class MetaListener(
|
||||
val action: (name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) -> Unit
|
||||
)
|
||||
|
||||
abstract class AbstractVisualObject : VisualObject {
|
||||
abstract class AbstractVisualObject: VisualObject {
|
||||
|
||||
@Transient
|
||||
override var parent: VisualObject? = null
|
||||
|
||||
@Transient
|
||||
@ -84,12 +81,10 @@ abstract class AbstractVisualObject : VisualObject {
|
||||
listeners.removeAll { it.owner == owner }
|
||||
}
|
||||
|
||||
@Serializable(ConfigSerializer::class)
|
||||
@SerialName("properties")
|
||||
private var _config: Config? = null
|
||||
abstract var properties: Config?
|
||||
override val config: Config
|
||||
get() = _config ?: Config().also { config ->
|
||||
_config = config
|
||||
get() = properties ?: Config().also { config ->
|
||||
properties = config
|
||||
config.onChange(this, ::propertyChanged)
|
||||
}
|
||||
|
||||
@ -99,19 +94,17 @@ abstract class AbstractVisualObject : VisualObject {
|
||||
|
||||
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {
|
||||
return if (inherit) {
|
||||
_config?.get(name) ?: parent?.getProperty(name, inherit)
|
||||
properties?.get(name) ?: parent?.getProperty(name, inherit)
|
||||
} else {
|
||||
_config?.get(name)
|
||||
properties?.get(name)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun MetaBuilder.updateMeta() {}
|
||||
|
||||
override fun toMeta(): Meta = buildMeta {
|
||||
"type" to type
|
||||
"properties" to config
|
||||
"type" to this::class.simpleName
|
||||
"properties" to properties
|
||||
updateMeta()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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()))
|
||||
}
|
@ -29,7 +29,7 @@ kotlin {
|
||||
dependencies {
|
||||
api("info.laht.threekt:threejs-wrapper:0.106-npm-3")
|
||||
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("element-resize-event"))
|
||||
}
|
||||
|
@ -1,19 +1,29 @@
|
||||
@file:UseSerializers(Point3DSerializer::class)
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.context.Context
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.MetaBuilder
|
||||
import hep.dataforge.meta.float
|
||||
import hep.dataforge.meta.get
|
||||
import hep.dataforge.io.ConfigSerializer
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.vis.common.AbstractVisualObject
|
||||
import hep.dataforge.vis.common.VisualFactory
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.UseSerializers
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@Serializable
|
||||
data class Box(
|
||||
val xSize: Float,
|
||||
val ySize: 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
|
||||
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {
|
||||
@ -40,8 +50,13 @@ data class Box(
|
||||
"xSize" to xSize
|
||||
"ySize" to ySize
|
||||
"zSize" to ySize
|
||||
updatePosition()
|
||||
}
|
||||
|
||||
// override fun toMeta(): Meta {
|
||||
// return (Visual3DPlugin.json.toJson(Box.serializer(), this) as JsonObject).toMeta()
|
||||
// }
|
||||
|
||||
companion object : VisualFactory<Box> {
|
||||
const val TYPE = "geometry.3d.box"
|
||||
|
||||
|
@ -1,7 +1,13 @@
|
||||
@file:UseSerializers(Point3DSerializer::class)
|
||||
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.vis.common.AbstractVisualObject
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.UseSerializers
|
||||
|
||||
enum class CompositeType {
|
||||
UNION,
|
||||
@ -9,11 +15,27 @@ enum class CompositeType {
|
||||
SUBTRACT
|
||||
}
|
||||
|
||||
open class Composite(
|
||||
@Serializable
|
||||
class Composite(
|
||||
val compositeType: CompositeType,
|
||||
val first: VisualObject3D,
|
||||
val second: VisualObject3D,
|
||||
val compositeType: CompositeType = CompositeType.UNION
|
||||
) : VisualLeaf3D()
|
||||
val second: VisualObject3D
|
||||
) : AbstractVisualObject(), VisualObject3D {
|
||||
|
||||
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(
|
||||
type: CompositeType,
|
||||
@ -23,14 +45,14 @@ inline fun VisualGroup3D.composite(
|
||||
val group = VisualGroup3D().apply(builder)
|
||||
val children = group.filterIsInstance<VisualObject3D>()
|
||||
if (children.size != 2) error("Composite requires exactly two children")
|
||||
return Composite(children[0], children[1], type).also {
|
||||
if (!group.config.isEmpty()) {
|
||||
return Composite(type, children[0], children[1]).also {
|
||||
if (group.properties != null) {
|
||||
it.config.update(group.config)
|
||||
it.material = group.material
|
||||
}
|
||||
it.position = group.position
|
||||
it.rotation = group.rotation
|
||||
it.scale = group.scale
|
||||
it.material = group.material
|
||||
set(name, it)
|
||||
}
|
||||
}
|
||||
|
@ -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) }
|
@ -1,15 +1,29 @@
|
||||
@file:UseSerializers(Point3DSerializer::class)
|
||||
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.io.ConfigSerializer
|
||||
import hep.dataforge.meta.Config
|
||||
import hep.dataforge.meta.MetaBuilder
|
||||
import hep.dataforge.vis.common.AbstractVisualObject
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.UseSerializers
|
||||
|
||||
class Convex(
|
||||
val points: List<Point3D>
|
||||
) : VisualLeaf3D() {
|
||||
@Serializable
|
||||
class Convex(val points: List<Point3D>) : 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
|
||||
|
||||
override fun MetaBuilder.updateMeta() {
|
||||
"points" to {
|
||||
"point" to points.map{it.toMeta()}
|
||||
"point" to points.map { it.toMeta() }
|
||||
}
|
||||
updatePosition()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -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) }
|
@ -1,5 +1,11 @@
|
||||
@file:UseSerializers(Point2DSerializer::class, 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
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
@ -7,16 +13,16 @@ import kotlin.math.sin
|
||||
|
||||
typealias Shape2D = List<Point2D>
|
||||
|
||||
class Shape2DBuilder {
|
||||
private val list = ArrayList<Point2D>()
|
||||
@Serializable
|
||||
class Shape2DBuilder(private val points: MutableList<Point2D> = ArrayList()) {
|
||||
|
||||
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)
|
||||
|
||||
fun build(): Shape2D = list
|
||||
fun build(): Shape2D = points
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
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) {
|
||||
this.shape = Shape2DBuilder().apply(block).build()
|
||||
//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) {
|
||||
layers.add(Layer(x.toFloat(), y.toFloat(), z.toFloat(), scale.toFloat()))
|
||||
//TODO send invalidation signal
|
||||
|
@ -1,25 +1,37 @@
|
||||
@file:UseSerializers(Point3DSerializer::class, NameSerializer::class)
|
||||
|
||||
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.MetaItem
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.vis.common.AbstractVisualObject
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.UseSerializers
|
||||
|
||||
/**
|
||||
* A proxy [VisualObject3D] to reuse a template object
|
||||
*/
|
||||
@Serializable
|
||||
class Proxy(val templateName: Name) : AbstractVisualObject(), VisualObject3D {
|
||||
|
||||
override var position: Point3D? = null
|
||||
override var rotation: Point3D? = null
|
||||
override var scale: Point3D? = null
|
||||
|
||||
@Serializable(ConfigSerializer::class)
|
||||
override var properties: Config? = null
|
||||
|
||||
/**
|
||||
* Recursively search for defined template in the parent
|
||||
*/
|
||||
val template by lazy {
|
||||
(parent as? VisualGroup3D)?.getTemplate(templateName)
|
||||
val template: VisualObject3D
|
||||
get() = (parent as? VisualGroup3D)?.getTemplate(templateName)
|
||||
?: error("Template with name $templateName not found in $parent")
|
||||
}
|
||||
|
||||
|
||||
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {
|
||||
return if (inherit) {
|
||||
|
@ -1,14 +1,30 @@
|
||||
@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
|
||||
import kotlin.math.PI
|
||||
|
||||
@Serializable
|
||||
class Sphere(
|
||||
var radius: Float,
|
||||
var phiStart: Float = 0f,
|
||||
var phi: Float = PI2,
|
||||
var thetaStart: Float = 0f,
|
||||
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(
|
||||
radius: Number,
|
||||
|
@ -1,5 +1,11 @@
|
||||
@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
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
@ -7,13 +13,21 @@ import kotlin.math.sin
|
||||
/**
|
||||
* Straight tube segment
|
||||
*/
|
||||
@Serializable
|
||||
class Tube(
|
||||
var radius: Float,
|
||||
var height: Float,
|
||||
var innerRadius: Float = 0f,
|
||||
var startAngle: Float = 0f,
|
||||
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 {
|
||||
require(radius > 0)
|
||||
@ -37,8 +51,8 @@ class Tube(
|
||||
geometryBuilder.apply {
|
||||
|
||||
//creating shape in x-y plane with z = 0
|
||||
val bottomOuterPoints = shape(radius, 0f)
|
||||
val upperOuterPoints = shape(radius, height)
|
||||
val bottomOuterPoints = shape(radius, -height/2)
|
||||
val upperOuterPoints = shape(radius, height/2)
|
||||
//outer face
|
||||
(1 until segments).forEach {
|
||||
face4(bottomOuterPoints[it - 1], bottomOuterPoints[it], upperOuterPoints[it], upperOuterPoints[it - 1])
|
||||
@ -62,8 +76,8 @@ class Tube(
|
||||
face4(zeroTop, zeroBottom, bottomOuterPoints.last(), upperOuterPoints.last())
|
||||
}
|
||||
} else {
|
||||
val bottomInnerPoints = shape(innerRadius, 0f)
|
||||
val upperInnerPoints = shape(innerRadius, height)
|
||||
val bottomInnerPoints = shape(innerRadius, -height/2)
|
||||
val upperInnerPoints = shape(innerRadius, height/2)
|
||||
//outer face
|
||||
(1 until segments).forEach {
|
||||
// inner surface
|
||||
@ -97,9 +111,14 @@ class Tube(
|
||||
bottomOuterPoints.last()
|
||||
)
|
||||
face4(upperInnerPoints[0], upperInnerPoints.last(), upperOuterPoints.last(), upperOuterPoints[0])
|
||||
} else{
|
||||
face4(bottomInnerPoints[0],bottomOuterPoints[0],upperOuterPoints[0],upperInnerPoints[0])
|
||||
face4(bottomOuterPoints.last(),bottomInnerPoints.last(),upperInnerPoints.last(),upperOuterPoints.last())
|
||||
} else {
|
||||
face4(bottomInnerPoints[0], bottomOuterPoints[0], upperOuterPoints[0], upperInnerPoints[0])
|
||||
face4(
|
||||
bottomOuterPoints.last(),
|
||||
bottomInnerPoints.last(),
|
||||
upperInnerPoints.last(),
|
||||
upperOuterPoints.last()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,9 @@ import hep.dataforge.context.PluginTag
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.names.Name
|
||||
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
|
||||
|
||||
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 type: KClass<out Visual3DPlugin> = Visual3DPlugin::class
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,21 @@
|
||||
@file:UseSerializers(Point3DSerializer::class, NameSerializer::class)
|
||||
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.io.ConfigSerializer
|
||||
import hep.dataforge.io.NameSerializer
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.plus
|
||||
import hep.dataforge.output.Output
|
||||
import hep.dataforge.vis.common.AbstractVisualObject
|
||||
import hep.dataforge.vis.common.VisualGroup
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
import hep.dataforge.vis.common.asName
|
||||
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.VISIBLE_KEY
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.UseSerializers
|
||||
|
||||
interface VisualObject3D : VisualObject {
|
||||
var position: Point3D?
|
||||
@ -60,18 +65,8 @@ interface VisualObject3D : VisualObject {
|
||||
}
|
||||
}
|
||||
|
||||
abstract class VisualLeaf3D : AbstractVisualObject(), VisualObject3D, Configurable {
|
||||
override var position: Point3D? = null
|
||||
override var rotation: Point3D? = null
|
||||
override var scale: Point3D? = null
|
||||
}
|
||||
|
||||
@Serializable
|
||||
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
|
||||
*/
|
||||
@ -81,12 +76,27 @@ class VisualGroup3D : VisualGroup<VisualObject3D>(), VisualObject3D, Configurabl
|
||||
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)
|
||||
|
||||
override fun MetaBuilder.updateMeta() {
|
||||
set(TEMPLATES_KEY, templates?.toMeta())
|
||||
updatePosition()
|
||||
updateChildren()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TEMPLATES_KEY = "templates"
|
||||
}
|
||||
}
|
||||
|
||||
fun VisualGroup3D.group(key: String? = null, action: VisualGroup3D.() -> Unit = {}): VisualGroup3D =
|
||||
@ -214,4 +224,3 @@ var VisualObject3D.scaleZ: Number
|
||||
scale().z = value.toDouble()
|
||||
propertyChanged(VisualObject3D.zScale)
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
@ -25,6 +25,8 @@ class ConvexTest {
|
||||
|
||||
val convex = group.first() as Convex
|
||||
|
||||
val meta = convex.toMeta()
|
||||
|
||||
val pointsNode = convex.toMeta()["points"].node
|
||||
|
||||
assertEquals(8, pointsNode?.items?.count())
|
||||
|
@ -1,13 +1,15 @@
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.context.Global
|
||||
import kotlinx.serialization.ImplicitReflectionSerializer
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class SerializationTest {
|
||||
@ImplicitReflectionSerializer
|
||||
@Test
|
||||
fun testCubeSerialization(){
|
||||
val cube = Box(null,100f,100f,100f).apply{
|
||||
val cube = Box(100f,100f,100f).apply{
|
||||
color(222)
|
||||
}
|
||||
val meta = cube.toMeta()
|
||||
|
@ -3,7 +3,6 @@ package hep.dataforge.vis.spatial.three
|
||||
import hep.dataforge.vis.spatial.Composite
|
||||
import hep.dataforge.vis.spatial.CompositeType
|
||||
import info.laht.threekt.core.BufferGeometry
|
||||
import info.laht.threekt.core.Geometry
|
||||
import info.laht.threekt.objects.Mesh
|
||||
|
||||
/**
|
||||
@ -23,9 +22,7 @@ class ThreeCompositeFactory(val three: ThreePlugin) : MeshThreeFactory<Composite
|
||||
CompositeType.INTERSECT -> firstCSG.intersect(secondCSG)
|
||||
CompositeType.SUBTRACT -> firstCSG.subtract(secondCSG)
|
||||
}
|
||||
|
||||
val mesh = CSG.toMesh(resultCSG, second.matrix)
|
||||
return (mesh.geometry as Geometry).toBufferGeometry()
|
||||
return resultCSG.toGeometry().toBufferGeometry()
|
||||
}
|
||||
|
||||
}
|
@ -1,14 +1,14 @@
|
||||
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 info.laht.threekt.core.BufferGeometry
|
||||
import info.laht.threekt.geometries.CylinderBufferGeometry
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.pow
|
||||
|
||||
object ThreeCylinderFactory : MeshThreeFactory<Cylinder>(Cylinder::class) {
|
||||
override fun buildGeometry(obj: Cylinder): BufferGeometry {
|
||||
object ThreeCylinderFactory : MeshThreeFactory<ConeSegment>(ConeSegment::class) {
|
||||
override fun buildGeometry(obj: ConeSegment): BufferGeometry {
|
||||
val cylinder = obj.detail?.let {
|
||||
val segments = it.toDouble().pow(0.5).toInt()
|
||||
CylinderBufferGeometry(
|
||||
|
@ -37,6 +37,12 @@ interface ThreeFactory<T : VisualObject3D> {
|
||||
*/
|
||||
internal fun Object3D.updatePosition(obj: VisualObject3D) {
|
||||
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)
|
||||
setRotationFromEuler(obj.euler)
|
||||
scale.set(obj.scaleX, obj.scaleY, obj.scaleZ)
|
||||
|
@ -27,7 +27,7 @@ class ThreePlugin : AbstractPlugin() {
|
||||
objectFactories[Box::class] = ThreeBoxFactory
|
||||
objectFactories[Convex::class] = ThreeConvexFactory
|
||||
objectFactories[Sphere::class] = ThreeSphereFactory
|
||||
objectFactories[Cylinder::class] = ThreeCylinderFactory
|
||||
objectFactories[ConeSegment::class] = ThreeCylinderFactory
|
||||
}
|
||||
|
||||
private fun findObjectFactory(type: KClass<out VisualObject3D>): ThreeFactory<*>? {
|
||||
|
@ -13,10 +13,11 @@ package hep.dataforge.vis.spatial.three
|
||||
|
||||
|
||||
import info.laht.threekt.math.Matrix4
|
||||
import info.laht.threekt.math.Vector3
|
||||
import info.laht.threekt.objects.Mesh
|
||||
|
||||
open external class CSG {
|
||||
open var polygons: Any
|
||||
open var polygons: Array<Polygon>
|
||||
open fun clone(): CSG
|
||||
open fun toPolygons(): Array<Polygon>
|
||||
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 fun clone(): Any
|
||||
open external class Vector(x: Number, y: Number, z: Number): Vector3 {
|
||||
open fun negated(): Vector
|
||||
open fun plus(a: Vector): Vector
|
||||
open fun minus(a: Vector): Vector
|
||||
|
@ -6,6 +6,7 @@ import hep.dataforge.meta.get
|
||||
import hep.dataforge.meta.node
|
||||
import hep.dataforge.vis.spatial.*
|
||||
import info.laht.threekt.core.BufferGeometry
|
||||
import info.laht.threekt.core.Face3
|
||||
import info.laht.threekt.core.Geometry
|
||||
import info.laht.threekt.core.Object3D
|
||||
import info.laht.threekt.math.Euler
|
||||
@ -26,3 +27,41 @@ 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)
|
||||
|
||||
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
|
||||
}
|
@ -45,6 +45,7 @@ class ThreeDemoGrid(meta: Meta) : AbstractPlugin(meta), OutputManager {
|
||||
element.append(gridRoot)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : Any> get(type: KClass<out T>, name: Name, stage: Name, meta: Meta): Output<T> {
|
||||
val three = context.plugins.get<ThreePlugin>()!!
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user