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 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 { fun main() = makeVisionFile {
vision("canvas") { vision("canvas") {
@ -12,8 +15,6 @@ fun main() = makeVisionFile {
} }
layer(-30) layer(-30)
layer(30) layer(30)
}.apply {
edges(false)
} }
} }
} }

View File

@ -1,16 +1,19 @@
package space.kscience.visionforge.examples package space.kscience.visionforge.examples
//fun main() = makeVisionFile { import space.kscience.visionforge.solid.ambientLight
// vision("canvas") { import space.kscience.visionforge.solid.polygon
// solid { import space.kscience.visionforge.solid.solid
// ambientLight() import space.kscience.visionforge.solid.surface
// surface("surface") {
// shape{ fun main() = makeVisionFile {
// polygon(8, 100) vision("canvas") {
// layer(-30) solid {
// layer(30) 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.MutableVisionContainer
import space.kscience.visionforge.VisionBuilder import space.kscience.visionforge.VisionBuilder
import space.kscience.visionforge.setChild 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. * An extruded shape with the same number of points on each layer.
*/ */
@ -50,6 +21,12 @@ public class Extruded(
public val layers: List<Layer>, public val layers: List<Layer>,
) : SolidBase<Extruded>(), GeometrySolid { ) : 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 { init {
require(shape.size > 2) { "Extruded shape requires more than 2 points per layer" } 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 lowerLayer = layers.first()
var upperLayer: List<Float32Vector3D> var upperLayer: List<Float32Vector3D>
geometryBuilder.cap(layers.first().reversed())
for (i in (1 until layers.size)) { for (i in (1 until layers.size)) {
upperLayer = layers[i] upperLayer = layers[i]
for (j in (0 until shape.size - 1)) { for (j in (0 until shape.size - 1)) {
@ -93,7 +72,7 @@ public class Extruded(
) )
lowerLayer = upperLayer lowerLayer = upperLayer
} }
geometryBuilder.cap(layers.first().reversed())
geometryBuilder.cap(layers.last()) geometryBuilder.cap(layers.last())
} }
@ -102,10 +81,12 @@ public class Extruded(
public var layers: MutableList<Layer> = ArrayList(), public var layers: MutableList<Layer> = ArrayList(),
public val properties: MutableMeta = MutableMeta(), public val properties: MutableMeta = MutableMeta(),
) { ) {
@VisionBuilder
public fun shape(block: Shape2DBuilder.() -> Unit) { public fun shape(block: Shape2DBuilder.() -> Unit) {
this.shape = Shape2DBuilder().apply(block).build() this.shape = Shape2DBuilder().apply(block).build()
} }
@VisionBuilder
public fun layer(z: Number, x: Number = 0.0, y: Number = 0.0, scale: Number = 1.0) { 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())) 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(ConeSurface.serializer())
subclass(Convex.serializer()) subclass(Convex.serializer())
subclass(Extruded.serializer()) subclass(Extruded.serializer())
subclass(Surface.serializer())
subclass(PolyLine.serializer()) subclass(PolyLine.serializer())
subclass(SolidLabel.serializer()) subclass(SolidLabel.serializer())
subclass(Sphere.serializer()) subclass(Sphere.serializer())

View File

@ -2,9 +2,14 @@ package space.kscience.visionforge.solid
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable 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.component1
import space.kscience.kmath.geometry.component2 import space.kscience.kmath.geometry.component2
import space.kscience.kmath.structures.Float32 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 { private inline fun <T> Iterable<T>.sumOf(selector: (T) -> Float32): Float32 {
@ -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 companion object {
public const val TYPE: String = "solid.surface" 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) }