Extruded shape demo
This commit is contained in:
parent
aa867af3c3
commit
397cc4b679
@ -9,6 +9,9 @@ import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
import kotlin.random.Random
|
||||
|
||||
|
||||
@ -68,6 +71,17 @@ class ThreeDemoApp : ApplicationBase() {
|
||||
color(12285)
|
||||
}
|
||||
}
|
||||
|
||||
demo("extrude", "extruded shape") {
|
||||
extrude {
|
||||
shape {
|
||||
polygon(8, 50)
|
||||
}
|
||||
for(i in 0..100) {
|
||||
layer(i*5, 20*sin(2*PI/100*i), 20*cos(2*PI/100*i))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -50,9 +50,9 @@ class ThreeDemoGrid(meta: Meta) : AbstractPlugin(meta), OutputManager {
|
||||
gridRoot.append {
|
||||
span("border") {
|
||||
div("col-4") {
|
||||
h2 { +(meta["title"].string ?: name.toString()) }
|
||||
output.attach(div { id = "output-$name" }){300}
|
||||
hr()
|
||||
output.attach(div { id = "output-$name" })
|
||||
h2 { +(meta["title"].string ?: name.toString()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,45 +1,123 @@
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.vis.common.DisplayLeaf
|
||||
import hep.dataforge.vis.common.DisplayObject
|
||||
import hep.dataforge.vis.common.DisplayObjectList
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
||||
|
||||
typealias Shape2D = List<Point2D>
|
||||
|
||||
data class Layer(val z: Number, val x: Number = 0.0, val y: Number = 0.0, val scale: Number = 1.0)
|
||||
class Shape2DBuilder {
|
||||
private val list = ArrayList<Point2D>()
|
||||
|
||||
class Extruded(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, meta) {
|
||||
fun point(x: Number, y: Number) {
|
||||
list.add(Point2D(x, y))
|
||||
}
|
||||
|
||||
fun build(): Shape2D = list
|
||||
}
|
||||
|
||||
fun Shape2DBuilder.polygon(vertices: Int, radius: Number) {
|
||||
require(vertices > 2) { "Polygon must have more than 2 vertices" }
|
||||
val angle = 2 * PI / vertices
|
||||
for (i in 0 until vertices) {
|
||||
point(radius.toDouble() * cos(angle * i), radius.toDouble() * sin(angle * i))
|
||||
}
|
||||
}
|
||||
|
||||
class Layer(override val config: Config) : Specific {
|
||||
var z by number(0.0)
|
||||
var x by number(0.0)
|
||||
var y by number(0.0)
|
||||
var scale by number(1.0)
|
||||
|
||||
companion object : Specification<Layer> {
|
||||
override fun wrap(config: Config): Layer = Layer(config)
|
||||
}
|
||||
}
|
||||
|
||||
//class Layer(val z: Number, val x: Number = 0.0, val y: Number = 0.0, val scale: Number = 1.0)
|
||||
|
||||
class Extruded(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, meta), Shape {
|
||||
|
||||
val shape
|
||||
get() = shape(properties["shape"] ?: error("Shape not defined"))
|
||||
get() = properties.getAll("shape.point").map { (_, value) ->
|
||||
Point2D(value.node["x"].number ?: 0, value.node["y"].number ?: 0)
|
||||
}
|
||||
|
||||
fun shape(block: Shape2DBuilder.() -> Unit) {
|
||||
val points = Shape2DBuilder().apply(block).build().map { it.toMeta() }
|
||||
properties["shape.point"] = points
|
||||
}
|
||||
|
||||
val layers
|
||||
get() = properties.getAll("layer").values.map {
|
||||
layer(it.node ?: error("layer item is not a node"))
|
||||
Layer.wrap(it.node ?: error("layer item is not a node"))
|
||||
}
|
||||
|
||||
fun layer(z: Number, x: Number = 0.0, y: Number = 0.0, scale: Number = 1.0): Layer {
|
||||
val layer = Layer.build {
|
||||
this.x = x
|
||||
this.y = y
|
||||
this.z = z
|
||||
this.scale = scale
|
||||
}
|
||||
properties.append("layer", layer)
|
||||
return layer
|
||||
}
|
||||
|
||||
override fun <T : Any> GeometryBuilder<T>.buildGeometry() {
|
||||
val shape: Shape2D = shape
|
||||
|
||||
if (shape.size < 3) error("Extruded shape requires more than points per layer")
|
||||
|
||||
/**
|
||||
* Expand the shape for specific layers
|
||||
*/
|
||||
val layers: List<List<Point3D>> = layers.map { layer ->
|
||||
shape.map { (x, y) ->
|
||||
val newX = layer.x.toDouble() + x.toDouble() * layer.scale.toDouble()
|
||||
val newY = layer.y.toDouble() + y.toDouble() * layer.scale.toDouble()
|
||||
Point3D(newX, newY, layer.z)
|
||||
}
|
||||
}
|
||||
|
||||
if (layers.size < 2) error("Extruded shape requires more than one layer")
|
||||
|
||||
var lowerLayer = layers.first()
|
||||
var upperLayer: List<Point3D>
|
||||
|
||||
for (i in (1 until layers.size)) {
|
||||
upperLayer = layers[i]
|
||||
for (j in (0 until shape.size - 1)) {
|
||||
//counter clockwise
|
||||
face4(
|
||||
lowerLayer[j],
|
||||
lowerLayer[j + 1],
|
||||
upperLayer[j + 1],
|
||||
upperLayer[j]
|
||||
)
|
||||
}
|
||||
|
||||
// final face
|
||||
face4(
|
||||
lowerLayer[shape.size - 1],
|
||||
lowerLayer[0],
|
||||
upperLayer[0],
|
||||
upperLayer[shape.size - 1]
|
||||
)
|
||||
lowerLayer = upperLayer
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TYPE = "geometry.3d.extruded"
|
||||
|
||||
private fun shape(item: MetaItem<*>): Shape2D {
|
||||
return item.node?.getAll("xyPoint".toName())?.map { (_, value) ->
|
||||
Point2D(value.node["x"].number ?: 0, value.node["y"].number ?: 0)
|
||||
} ?: emptyList()
|
||||
}
|
||||
|
||||
private fun layer(meta: Meta): Layer {
|
||||
val x by meta.number(0.0)
|
||||
val y by meta.number(0.0)
|
||||
val z by meta.number { error("z is undefined in layer") }
|
||||
val scale by meta.number(1.0)
|
||||
return Layer(z, x, y, scale)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun DisplayObjectList.extrude(meta: Meta = EmptyMeta, action: Extruded.() -> Unit = {}) =
|
||||
Extruded(this, meta).apply(action).also { addChild(it) }
|
@ -6,7 +6,12 @@ import hep.dataforge.meta.MetaRepr
|
||||
import hep.dataforge.meta.buildMeta
|
||||
import hep.dataforge.vis.common.DisplayObject
|
||||
|
||||
data class Point2D(val x: Number, val y: Number)
|
||||
data class Point2D(val x: Number, val y: Number): MetaRepr{
|
||||
override fun toMeta(): Meta = buildMeta {
|
||||
"x" to x
|
||||
"y" to y
|
||||
}
|
||||
}
|
||||
|
||||
data class Point3D(val x: Number, val y: Number, val z: Number) : MetaRepr {
|
||||
override fun toMeta(): Meta = buildMeta {
|
||||
|
Loading…
Reference in New Issue
Block a user