src/bezier

    Dark Mode
Search:
Group by:

Bezier curve library

Based off the work found here:

Types

Bezier[N] = object
  points: array[N + 1, Vec2]
A bezier curve of order N
DynBezier = object
  points: seq[Vec2]
Bezier curve where the order isn't known at compile time
LUT[T] {.byref.} = object
  table: seq[tuple[t: float, point: Vec2, distanceFrom0: float]]
  curve: T
A lookup table of precalculated points within a curve

Procs

proc `$`(curve: Bezier | DynBezier): string
Create a string representation of a bezier curve
proc `[]`(curve: DynBezier; point: Natural): Vec2 {....raises: [], tags: [].}
Returns a control point within this curve
proc `[]`[N](curve: Bezier[N]; point: range[0 .. N]): Vec2
Returns a control point within this curve
proc align(curve: Bezier | DynBezier; p1, p2: Vec2): auto
Rotates this bezier curve so it aligns with the given line
proc approxLen(curve: Bezier | DynBezier; steps: Positive): float
Calculates the approximate length of a curve. This is a faster algorithm than calling length directly
proc approxLen[T](lut: LUT[T]): float
Uses a LUT to determine the approximate length of a curve. This is a bit innacurate, but faster than calling length
proc boundingBox(curve: Bezier | DynBezier): tuple[minX, minY, maxX, maxY: float]
Returns the bounding box for a curve
proc compute(curve: DynBezier; t: float): Vec2 {....raises: [], tags: [].}
Computes the position of a point along the curve, where t is a value between 0.0 and 1.0.
proc compute[N](curve: Bezier[N]; t: float): Vec2
Computes the position of a point along the curve, where t is a value between 0.0 and 1.0.
proc derivative(curve: DynBezier): DynBezier {....raises: [], tags: [].}
Computes the derivative of a bezier curve. The result of this is a new bezier curve with an order of N - 1
proc derivative[N](curve: Bezier[N]): auto
Computes the derivative of a bezier curve. The result of this is a new bezier curve with an order of N - 1
proc findMaxY(curve: Bezier | DynBezier; x: float): Option[Vec2]
Finds the maximum y on a curve for a given x.
proc findMinY(curve: Bezier | DynBezier; x: float): Option[Vec2]
Finds the maximum y on a curve for a given x.
proc length(curve: Bezier | DynBezier): float
Calculates the length of a curve. This can be expensive, so if you need a faster version consider using approxLen instead.
proc lut[T: Bezier | DynBezier](curve: T; steps: range[2 .. high(int)]): LUT[T]
Creates a lookup table of indexes into this curve, where steps is the number of points to sample along the curve.
proc newBezier[N](points: varargs[Vec2]): Bezier[N]
Creates a new Bezier curve where the curve order is known at build time. For example, passing in N = 3 is a cubic curve.
proc newDynBezier(points: varargs[Vec2]): DynBezier {....raises: [], tags: [].}
Creates a new Bezier curve where the curve order is only known at runtime
proc normal(curve: Bezier | DynBezier; t: float): Vec2
Returns the tangent vector at a given location, where t is avalue between 0.0 and 1.0
proc order(curve: DynBezier): Natural {....raises: [], tags: [].}
The order of the curve is the number of points used to define the curve, starting at 0. N = 1 is linear (2 points), N = 2 is quadratic (3 points), N = 3 is cubic (4 points)
proc order[N](curve: Bezier[N]): Natural
The order of the curve is the number of points used to define the curve, starting at 0. N = 1 is linear (2 points), N = 2 is quadratic (3 points), N = 3 is cubic (4 points)
proc project[T](lut: LUT[T]; point: Vec2): float
Finds the location on a curve closest to the given point. Returns a value between 0.0 and 1.0 that can be fed into the compute function
proc split(curve: DynBezier; t: float): (DynBezier, DynBezier) {....raises: [],
    tags: [].}
Splits the curve at the given location, where t is avalue between 0.0 and 1.0
proc split[N](curve: Bezier[N]; t: float): (Bezier[N], Bezier[N])
Splits the curve at the given location, where t is avalue between 0.0 and 1.0
proc tangent(curve: Bezier | DynBezier; t: float): Vec2
Returns the tangent vector at a given location, where t is a value between 0.0 and 1.0
proc tightBoundingBox(curve: Bezier | DynBezier): array[4, Vec2]
Returns the corners of a bounding box that is tightly aligned to a curve
proc xs(curve: DynBezier): seq[float] {....raises: [], tags: [].}
Returns all x values from the points in this curve
proc xs[N](curve: Bezier[N]): array[N + 1, float]
Returns all x values from the points in this curve
proc ys(curve: DynBezier): seq[float] {....raises: [], tags: [].}
Returns all y values from the points in this curve
proc ys[N](curve: Bezier[N]): array[N + 1, float]
Returns all y values from the points in this curve

Iterators

iterator extrema(curve: DynBezier): float {....raises: [], tags: [].}
Calculates all the extrema on a curve, expressed as a location between 0.0 and 1.0. You can feed these values into the compute method to get their coordinates
iterator extrema[N](curve: Bezier[N]): float
Calculates all the extrema on a curve, expressed as a location between 0.0 and 1.0. You can feed these values into the compute method to get their coordinates
iterator findY(curve: Bezier | DynBezier; x: float): Vec2
Produces the Y values for a given X. This can produce multiple values because a bezier curve may have multiple intersections with the same x value
iterator intersects(curve: Bezier | DynBezier; p1, p2: Vec2): Vec2
Yields the points where a curve intersects a line
iterator intervals[T](lut: LUT[T]; steps: Positive): Vec2
Produces points along the curve that are more geometrically evenly spaced. They aren't guaranteed to be exactly evenly spaced, but they will be better than using segment. If you need more accuracy, you can increase the sample size of the LUT. The argument steps is the number of intervals to produce. So this iterator will yield steps + 1 number of points.
iterator items(curve: DynBezier | Bezier): lent Vec2
Produces all the points in this curve
iterator pairs(curve: DynBezier | Bezier): (int, Vec2)
Produces all the points in this curve as well as their index
iterator points(curve: Bezier | DynBezier; steps: range[2 .. high(int)]): tuple[
    t: float, point: Vec2]
Produces a set of points along the curve at the given number of steps
iterator segments(curve: Bezier | DynBezier; steps: Positive): (Vec2, Vec2)
Breaks the curve into straight lines. Also known as flattening the curve. These lines are not guaranteed to be geometrically even.

Templates

template mapIt(curve: DynBezier; mapper: untyped): DynBezier
Applies a mapping function to the points in this curve. Within the mapping block, a variable named it will be injected with the current point
template mapIt[N](curve: Bezier[N]; mapper: untyped): Bezier[N]
Applies a mapping function to the points in this curve. Within the mapping block, a variable named it will be injected with the current point