Add surface geometry

This commit is contained in:
Alexander Nozik 2023-10-07 15:27:28 +03:00
parent 00213c089d
commit c7640a686a
6 changed files with 97 additions and 48 deletions

View File

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

View File

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

View File

@ -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<Float32Vector2D>
@Serializable
public class Shape2DBuilder(private val points: ArrayList<Float32Vector2D> = 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<Layer>,
) : SolidBase<Extruded>(), 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<Float32Vector3D>
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<Layer> = 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()))
}

View File

@ -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<Float32Vector2D>
@Serializable
public class Shape2DBuilder(private val points: ArrayList<Float32Vector2D> = 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))
}
}

View File

@ -41,6 +41,7 @@ public class Solids(meta: Meta) : VisionPlugin(meta), MutableVisionContainer<Sol
subclass(ConeSurface.serializer())
subclass(Convex.serializer())
subclass(Extruded.serializer())
subclass(Surface.serializer())
subclass(PolyLine.serializer())
subclass(SolidLabel.serializer())
subclass(Sphere.serializer())

View File

@ -2,9 +2,14 @@ package space.kscience.visionforge.solid
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.names.Name
import space.kscience.kmath.geometry.component1
import space.kscience.kmath.geometry.component2
import space.kscience.kmath.structures.Float32
import space.kscience.visionforge.MutableVisionContainer
import space.kscience.visionforge.VisionBuilder
import space.kscience.visionforge.setChild
private inline fun <T> Iterable<T>.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<Layer> = 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<Solid>.surface(
name: String? = null,
action: Surface.Builder.() -> Unit = {},
): Surface = Surface.Builder().apply(action).build().also { setChild(name, it) }