Skip to main content Skip to docs navigation

VectorPath, VectorBuilder, Shape2d, Shape2d union, difference, Triangulation, Vector Collision, Bezier...

Document not reviewed yet, might be outdated. Please, let us know if you find something invalid here.
On this page

KorMA provide several vectorial capabilities to generate all kind of vectorial shapes formed from lines, polygons and curves.

VectorPath and VectorBuilder

open class VectorPath(
    val commands: IntArrayList = IntArrayList(),
    val data: DoubleArrayList = DoubleArrayList(),
    val winding: Winding = Winding.EVEN_ODD
) : VectorBuilder

interface VectorBuilder {
    val totalPoints: Int
    val lastX: Double
    val lastY: Double
    fun moveTo(x: Double, y: Double)
    fun lineTo(x: Double, y: Double)
    fun quadTo(cx: Double, cy: Double, ax: Double, ay: Double)
    fun cubicTo(cx1: Double, cy1: Double, cx2: Double, cy2: Double, ax: Double, ay: Double)
    fun close()
}

Constructing vectors with lines and curves

The basic classes for vector building are VectorPath and VectorBuilder. They do not include color information, but just the vector shape. You can make other classes to implement the VectorBuilder interface by delegation to for example provide a Context2D-like interface with filling and stroking including all the extension methods provided.

Extension methods using the basic interface:

fun VectorBuilder.isEmpty(): Boolean
fun VectorBuilder.isNotEmpty(): Boolean

fun VectorBuilder.arcTo(ax: Double, ay: Double, cx: Double, cy: Double, r: Double)
fun VectorBuilder.rect(x: Double, y: Double, width: Double, height: Double)
fun VectorBuilder.rectHole(x: Double, y: Double, width: Double, height: Double)
fun VectorBuilder.roundRect(x: Double, y: Double, w: Double, h: Double, rx: Double, ry: Double = rx)
fun VectorBuilder.arc(x: Double, y: Double, r: Double, start: Double, end: Double)
fun VectorBuilder.circle(x: Double, y: Double, radius: Double)
fun VectorBuilder.ellipse(x: Double, y: Double, rw: Double, rh: Double)
fun VectorBuilder.moveTo(p: Point)
fun VectorBuilder.lineTo(p: Point)
fun VectorBuilder.quadTo(c: Point, a: Point)
fun VectorBuilder.cubicTo(c1: Point, c2: Point, a: Point)

inline fun VectorBuilder.moveTo(x: Number, y: Number)
inline fun VectorBuilder.lineTo(x: Number, y: Number)
inline fun VectorBuilder.quadTo(controlX: Number, controlY: Number, anchorX: Number, anchorY: Number)
inline fun VectorBuilder.cubicTo(cx1: Number, cy1: Number, cx2: Number, cy2: Number, ax: Number, ay: Number)

inline fun VectorBuilder.moveToH(x: Number)
inline fun VectorBuilder.rMoveToH(x: Number)

inline fun VectorBuilder.moveToV(y: Number)
inline fun VectorBuilder.rMoveToV(y: Number)

inline fun VectorBuilder.lineToH(x: Number)
inline fun VectorBuilder.rLineToH(x: Number)

inline fun VectorBuilder.lineToV(y: Number)
inline fun VectorBuilder.rLineToV(y: Number)

inline fun VectorBuilder.rMoveTo(x: Number, y: Number)
inline fun VectorBuilder.rLineTo(x: Number, y: Number)

inline fun VectorBuilder.rQuadTo(cx: Number, cy: Number, ax: Number, ay: Number)
inline fun VectorBuilder.rCubicTo(cx1: Number, cy1: Number, cx2: Number, cy2: Number, ax: Number, ay: Number)
inline fun VectorBuilder.arcTo(ax: Number, ay: Number, cx: Number, cy: Number, r: Number)
inline fun VectorBuilder.rect(x: Number, y: Number, width: Number, height: Number)
inline fun VectorBuilder.rectHole(x: Number, y: Number, width: Number, height: Number)
inline fun VectorBuilder.roundRect(x: Number, y: Number, w: Number, h: Number, rx: Number, ry: Number = rx)
inline fun VectorBuilder.arc(x: Number, y: Number, r: Number, start: Number, end: Number)
inline fun VectorBuilder.circle(x: Number, y: Number, radius: Number)
inline fun VectorBuilder.ellipse(x: Number, y: Number, rw: Number, rh: Number)

You can also determine if a point is contained inside a VectorPath:

fun VectorPath.containsPoint(x: Double, y: Double): Boolean

Shape2d

Several algorithms require to work with simple straight segments. Korma provides a Shape2d set of classes to describe shapes.

You can convert a VectorPath to a Shape2d using the toShape2d extension method:

val shape = VectorPath {
    moveTo(0, 0)
    lineTo(100, 0)
    lineTo(100, 100)
    close()
}.toShape2d()

Shape2d Operations

Intersection, Union, Xor, Difference, Collision Test, Growing/Shrinking

Korma provides a separate artifact called korma-shape-ops that includes a Kotlin port of the Clipper library integrated with the Shape2D API. It provides boolean methods to operate with two paths.

infix fun Shape2d.collidesWith(other: Shape2d): Boolean

infix fun Shape2d.intersection(other: Shape2d): Shape2d
infix fun Shape2d.union(other: Shape2d): Shape2d
infix fun Shape2d.xor(other: Shape2d): Shape2d
infix fun Shape2d.difference(other: Shape2d): Shape2d

operator fun Shape2d.plus(other: Shape2d): Shape2d
operator fun Shape2d.minus(other: Shape2d): Shape2d

fun Shape2d.extend(size: Double, cap: VectorPath.LineCap = VectorPath.LineCap.ROUND): Shape2d
fun Shape2d.extendLine(size: Double, join: VectorPath.LineJoin = VectorPath.LineJoin.SQUARE, cap: VectorPath.LineCap = VectorPath.LineCap.SQUARE): Shape2d 

Triangulation

Shape2d: Triangulation and Triangulation-based Node and Point Path Finding

Korma provides a separate artifact called korma-triangulate-pathfind to do triangulation and triangulation-based path finding.

Triangulating a set of polygons (or curves too after converting them into polygons with toShape2d) has several use cases like drawing a vectorial shape into the GPU, doing physics or doing path finding.

To triangulate a set of points, a Shape2d or a VectorPath:

fun List<IPoint>.triangulate(): List<Triangle>
fun Shape2d.triangulate(): List<List<Triangle>>
fun Shape2d.triangulateFlat(): List<Triangle>
fun VectorPath.triangulate(): List<List<Triangle>>
fun VectorPath.triangulateFlat(): List<Triangle>

For pathfinding:

fun List<Triangle>.toSpatialMesh(): SpatialMesh
fun List<Triangle>.pathFind(): SpatialMeshFind
fun SpatialMeshFind.funnel(p0: IPoint, p1: IPoint): List<IPoint>
fun List<Triangle>.funnel(p0: IPoint, p1: IPoint): List<IPoint>
fun List<Triangle>.pathFind(p0: IPoint, p1: IPoint): List<IPoint>
fun Shape2d.toSpatialMesh(): SpatialMesh
fun Shape2d.pathFind(): SpatialMeshFind
fun Shape2d.pathFind(p0: IPoint, p1: IPoint): List<IPoint>

Additionally this library allows to compute the area of Shape2d by doing triangulation:

val Shape2d.area: Double

Extra: Bezier tools

Korma provides a Bezier object with several methods to compute in a bezier curve (quadratic and cubic) their points, their length or their bounds.

Was this article useful?