diff --git a/demo/playground/src/jvmMain/kotlin/extruded.kt b/demo/playground/src/jvmMain/kotlin/extruded.kt index fb4707eb..af8fe6d0 100644 --- a/demo/playground/src/jvmMain/kotlin/extruded.kt +++ b/demo/playground/src/jvmMain/kotlin/extruded.kt @@ -1,6 +1,9 @@ package space.kscience.visionforge.examples -import space.kscience.visionforge.solid.* +import space.kscience.visionforge.solid.ambientLight +import space.kscience.visionforge.solid.extruded +import space.kscience.visionforge.solid.polygon +import space.kscience.visionforge.solid.solid fun main() = makeVisionFile { vision("canvas") { @@ -12,8 +15,6 @@ fun main() = makeVisionFile { } layer(-30) layer(30) - }.apply { - edges(false) } } } diff --git a/demo/playground/src/jvmMain/kotlin/surface.kt b/demo/playground/src/jvmMain/kotlin/surface.kt index a13644bf..9bcc9e2f 100644 --- a/demo/playground/src/jvmMain/kotlin/surface.kt +++ b/demo/playground/src/jvmMain/kotlin/surface.kt @@ -1,16 +1,19 @@ package space.kscience.visionforge.examples -//fun main() = makeVisionFile { -// vision("canvas") { -// solid { -// ambientLight() -// surface("surface") { -// shape{ -// polygon(8, 100) -// layer(-30) -// layer(30) -// } -// } -// } -// } -//} \ No newline at end of file +import space.kscience.visionforge.solid.ambientLight +import space.kscience.visionforge.solid.polygon +import space.kscience.visionforge.solid.solid +import space.kscience.visionforge.solid.surface + +fun main() = makeVisionFile { + vision("canvas") { + solid { + ambientLight() + surface("surface") { + layer(0, {polygon(8,10)}, {polygon(8,20)}) + layer(10, {polygon(8,10)}, {polygon(8,30)}) + + } + } + } +} \ No newline at end of file diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Extruded.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Extruded.kt index 70de06db..8276722e 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Extruded.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Extruded.kt @@ -9,37 +9,8 @@ import space.kscience.kmath.geometry.component2 import space.kscience.visionforge.MutableVisionContainer import space.kscience.visionforge.VisionBuilder import space.kscience.visionforge.setChild -import kotlin.math.PI -import kotlin.math.cos -import kotlin.math.sin -public typealias Shape2D = List - -@Serializable -public class Shape2DBuilder(private val points: ArrayList = ArrayList()) { - - public fun point(x: Number, y: Number) { - points.add(Float32Vector2D(x, y)) - } - - public fun build(): Shape2D = points -} - -public 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)) - } -} - -/** - * A layer for extruded shape - */ -@Serializable -public data class Layer(var x: Float, var y: Float, var z: Float, var scale: Float) - /** * An extruded shape with the same number of points on each layer. */ @@ -50,6 +21,12 @@ public class Extruded( public val layers: List, ) : SolidBase(), GeometrySolid { + /** + * A layer for extruded shape + */ + @Serializable + public data class Layer(var x: Float, var y: Float, var z: Float, var scale: Float) + init { require(shape.size > 2) { "Extruded shape requires more than 2 points per layer" } } @@ -72,6 +49,8 @@ public class Extruded( var lowerLayer = layers.first() var upperLayer: List + geometryBuilder.cap(layers.first().reversed()) + for (i in (1 until layers.size)) { upperLayer = layers[i] for (j in (0 until shape.size - 1)) { @@ -93,7 +72,7 @@ public class Extruded( ) lowerLayer = upperLayer } - geometryBuilder.cap(layers.first().reversed()) + geometryBuilder.cap(layers.last()) } @@ -102,10 +81,12 @@ public class Extruded( public var layers: MutableList = ArrayList(), public val properties: MutableMeta = MutableMeta(), ) { + @VisionBuilder public fun shape(block: Shape2DBuilder.() -> Unit) { this.shape = Shape2DBuilder().apply(block).build() } + @VisionBuilder public 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())) } diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Shape2D.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Shape2D.kt new file mode 100644 index 00000000..4f5d48a4 --- /dev/null +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Shape2D.kt @@ -0,0 +1,26 @@ +package space.kscience.visionforge.solid + +import kotlinx.serialization.Serializable +import kotlin.math.PI +import kotlin.math.cos +import kotlin.math.sin + +public typealias Shape2D = List + +@Serializable +public class Shape2DBuilder(private val points: ArrayList = ArrayList()) { + + public fun point(x: Number, y: Number) { + points.add(Float32Vector2D(x, y)) + } + + public fun build(): Shape2D = points +} + +public 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)) + } +} \ No newline at end of file diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solids.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solids.kt index 1477c2a0..2a2e86fc 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solids.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solids.kt @@ -41,6 +41,7 @@ public class Solids(meta: Meta) : VisionPlugin(meta), MutableVisionContainer Iterable.sumOf(selector: (T) -> Float32): Float32 { @@ -58,7 +63,7 @@ public class Surface( //outer and inner for (i in 0 until layers.size - 1) { val bottom = layers[i] - val top = layers[i+1] + val top = layers[i + 1] //creating shape in x-y plane with z = 0 val bottomOuterPoints = bottom.outerPoints() @@ -130,7 +135,39 @@ public class Surface( } } + public class Builder( + public var layers: MutableList = ArrayList(), + public val properties: MutableMeta = MutableMeta(), + ) { + + public fun layer( + z: Number, + innerBuilder: (Shape2DBuilder.() -> Unit)? = null, + outerBuilder: Shape2DBuilder.() -> Unit, + ) { + layers.add( + Layer( + z.toFloat(), + outer = Shape2DBuilder().apply(outerBuilder).build(), + inner = innerBuilder?.let { Shape2DBuilder().apply(innerBuilder).build() } + ) + ) + } + + internal fun build(): Surface = Surface(layers).apply { + properties.setMeta(Name.EMPTY, this@Builder.properties) + } + } + + public companion object { public const val TYPE: String = "solid.surface" } } + + +@VisionBuilder +public fun MutableVisionContainer.surface( + name: String? = null, + action: Surface.Builder.() -> Unit = {}, +): Surface = Surface.Builder().apply(action).build().also { setChild(name, it) }