Usage
# Create a bezier curve
curve = Curves.define_bezier(:ease_in)
# Find the {x, y} coordinate at 24% from the start
{x, y} = Curves.solve!(curve, 0.24)For a list of all predefined bezier_types, use Curves.Bezier.Predefined.list/0
Custom curves
You can also create a custom bezier curve by passing in a list of {x, y} tuples. They can be any combination of floats and integers.
curve = Curves.define_bezier([
# {x, y}
{0, 0}, # Knot 0. AKA the start point
{0, 0.5}, # Control Point 0
{0.8, 0.4}, # Control Point 1
{1, 1} # Knot 1. AKA the stop point
])
t = 0.1234
{x, y} = Curves.solve!(curve, t)Interactive tutorial
Be sure to check out the livebooks to see these points turn into graphs.
Options
All define_*, solve*, and take* functions can receive the following opts.
key | default | description |
|---|---|---|
:origin | {0, 0} | Provides an offset. every point in the curve will automatically be increased by this {x, y} coordinate |
:float_dtype | 16 | One of 8, 16, 32, 64. Passed into Nx tensors as {:f, dtype}. |
:force_percent | false | If true, all results from take and solve are normalized as percentages of the max y coordinate defined |
Summary
Functions
Define a spline struct of type: Curves.Spline.Type.BSpline.
Build a new Curves.Bezier.Curve
Return a Curves.Spline.Curve struct representing a Curves.Spline.Type.BezierSpline.
Can later be passed into solve/2.
Define a new Curves.Spline.Type.CatmullRom. Only the joins need to be defined, the control points are calculated automatically.
Define a new Curves.Spline.Type.Hermite spline.
Control points are calculated automatically based on the first derivative of each knot.
Given a Curves.Bezier.Curve or Curves.Spline.Curve struct, and t, find the point along the curve.
The raising version of solve/3
Take n samples, evenly spaced, from the curve.
The raising version of take/3
Functions
@spec define_b_spline( Curves.Utils.Types.point_list(), Curves.Utils.Types.define_opts() ) :: Curves.Spline.Curve.t()
Define a spline struct of type: Curves.Spline.Type.BSpline.
Only the knots need to be defined, the control points are calculated automatically.
Options
See available opts
curve = Curves.define_b_spline([
{0, 0},
{1, 0},
{1, 1},
{0, 1},
{0, 2},
{1, 2},
])
{x, y} = Curves.solve!(curve, 0.15)
@spec define_bezier( points :: Curves.Utils.Types.point_list() | Curves.Bezier.Predefined.curve_key(), Curves.Utils.Types.define_opts() ) :: Curves.Bezier.Curve.t()
Build a new Curves.Bezier.Curve
Options
See available opts
Examples
iex> c = Curves.define_bezier([{0.1, 0.9}, {0.5, 0.9}, {0.5, 0.1}, {0.75, 0.1}])
iex> is_struct(c, Curves.Bezier.Curve)
true
@spec define_bezier_spline( points :: [Curves.Utils.Types.point_list()], opts :: Curves.Utils.Types.define_opts() ) :: Curves.Spline.Curve.t()
Return a Curves.Spline.Curve struct representing a Curves.Spline.Type.BezierSpline.
Can later be passed into solve/2.
Options
See available opts
points = [
# P0
[{5.0, 10.0}, # Knot
{10.0, 10.0}], # control point 0
# P1
[{10.0, 5.0}, # Knot
{5.0, 5.0}, # control point 0
{15.0, 5.0}],# control point 1
# P2
[{15.0, 10.0}, # Knot
{15.0, 6.0}, # control point 0
{15.0, 14.0} # control point 1
],
# P3
[{20.0, 15.0}, # Knot
{18.0, 15.0}, # control point 0
{23.0, 15.0}],# control point 1
# P4
[{30.0, 10.0}, # Knot
{32.0, 5.0}] # control point 0
]
curves = Curves.define_bezier_spline(points)
{x, y} = Curves.solve!(curves, 0.518)
@spec define_catmull_rom( Curves.Utils.Types.point_list(), Curves.Utils.Types.define_opts() ) :: Curves.Spline.Curve.t()
Define a new Curves.Spline.Type.CatmullRom. Only the joins need to be defined, the control points are calculated automatically.
Options
See available opts
curve = Curves.define_catmull_rom([
{0, 0},
{1, 0},
{1, 1},
{0, 1},
{0, 2},
{1, 2},
])
{x, y} = Curves.solve!(curves, 0.5)
@spec define_hermite( Curves.Utils.Types.point_list(), Curves.Utils.Types.define_opts() ) :: Curves.Spline.Curve.t()
Define a new Curves.Spline.Type.Hermite spline.
Control points are calculated automatically based on the first derivative of each knot.
Options
See available opts
Example
curve = Curves.define_hermite([
{5, 10},
{10, 5},
{15, 10},
{20, 10},
{25, 5},
{30, 15},
])
{x, y} = Curves.solve!(curve, 0.85)
@spec solve( Curves.Bezier.Curve.t() | Curves.Spline.Curve.t(), Curves.Utils.Types.t(), Curves.Utils.Types.opts() ) :: {:ok, Curves.Utils.Types.point_tuple()} | {:error, term()}
Given a Curves.Bezier.Curve or Curves.Spline.Curve struct, and t, find the point along the curve.
For a bezier curve, t must be between 0.0 and 1.0.
e.g. t = 0.5 means the coordinate at 50% through the bezier curve.
For splines, the range of t depends on the number of segments (number of knots - 1).
e.g. t = 0.5 means the coordinate at 50% through the first segment. But t = 1.5 is 50% through the next segment.
Examples
iex> c = Curves.define_bezier([{0.1, 0.9}, {0.5, 0.9}, {0.5, 0.1}, {0.75, 0.1}])
iex> Curves.solve(c, 0.3)
{:ok, {0.3695499897003174, 0.727199912071228}}Options
:float_dtype(default: nil) | If set to an integer, passes results to Float.round(_, precision)
@spec solve!( Curves.Bezier.Curve.t() | Curves.Spline.Curve.t(), Curves.Utils.Types.t(), Curves.Utils.Types.opts() ) :: Curves.Utils.Types.point_tuple()
The raising version of solve/3
@spec take( Curves.Bezier.Curve.t() | Curves.Spline.Curve.t(), n :: pos_integer(), Curves.Utils.Types.opts() ) :: {:ok, Curves.Utils.Types.point_list()} | {:error, term()}
Take n samples, evenly spaced, from the curve.
@spec take!( Curves.Bezier.Curve.t() | Curves.Spline.Curve.t(), n :: pos_integer(), Curves.Utils.Types.opts() ) :: Curves.Utils.Types.point_list()
The raising version of take/3