Extruded shape demo

This commit is contained in:
Alexander Nozik 2019-07-02 14:50:02 +03:00
parent aa867af3c3
commit 397cc4b679
4 changed files with 127 additions and 30 deletions

View File

@ -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))
}
}
}
}

View File

@ -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()) }
}
}
}

View File

@ -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) }

View File

@ -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 {