Curves
Introduction
Curves aims to be the best elixir framework for calculating bezier curves and splines.
curve = Curves.define_bezier(:ease_out)
|> Curves.Transform.set_scale(1.5)
|> Curves.Transform.inc_position({10, 10})
|> Curves.Transform.set_rotation(90)
# x and y are floats
{x, y} = Curves.solve!(curve, 0.25)
Installation
Add curves to your dependencies in mix.exs:
def deps do
[
{:curves, "~> 1.0.0-rc.1"}
]
end
Directory
- Upgrading from 0.2.x to 1.0
- Bezier Curves Livebook
- Splines Livebook
- Hex docs
- Hex package
- Github Repo
Hire me
Full stack developer seeking new challenges. You can reach me at hireme@aaronjprice.com
Visual Demo
Ease in-out Bezier
The simplest way to use Curves is with the predefined ones like :ease_in_out
curve = Curves.define_bezier(:ease_in_out)
# Find any point along the curve (t goes from 0.0 to 1.0)...
Curves.solve!(curve, 0.25)
# ...or draw the whole curve as an SVG image
Curves.Svg.save!(curve, "ease_in_out.svg")
Quadratic Bezier
Here we make an asymmetric quadratic curve
points = [
{0, 0},
{20, 50},
{100, 0}
]
curve = Curves.define_bezier(points)
Custom 4-point Bezier
points = [
{0, 0},
{0.8, 0.2},
{0.3, 2.2},
{1, 1}
]
curve = Curves.define_bezier(points)
Spline examples
The simplest spline is basically just a series of bezier curves connected to each other.
Notice we are no longer using define_bezier, but define_bezier_spline. Now it is a list of lists with 1, 2, or 3 tuples in each segment.
# points format for `define_bezier_spline/2`
[{knot_x, knot_y}]
[{knot_x, knot_y}, {cp0_x, cp0_y}]
[{knot_x, knot_y}, {cp0_x, cp0_y}, {cp1_x, cp1_y}]
Bezier Spline
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
]
curve = Curves.define_bezier_spline(points)
Cubic Hermite Spline
A smooth curve through every knot. At each knot you give a tangent: the direction (and speed) the curve leaves it with.
curve = Curves.define_hermite([
# [knot, tangent]
[{5, 10}, {5, -5}],
[{10, 5}, {5, 0}],
[{15, 10}, {5, 5}],
[{20, 10}, {5, -3}],
[{25, 5}, {5, 5}],
[{30, 15}, {5, 10}]
])
Catmull-Rom Spline
Similar to the Hermite spline, but now the derivative comes from the slope between the previous and next point.
curve = Curves.define_catmull_rom([
{0, 0},
{1, 0},
{1, 1},
{0, 1},
{0, 2},
{1, 2},
])
B-Spline
The smoothest of the splines featured here, but with the drawback that the line does not actually pass through the control points.
curve = Curves.define_b_spline([
{0, -2},
{3, 4},
{6, 5},
{7, -1},
{10, 3},
{5, 1},
{12, 9}
])
Benchmarks
Benchmarks live in bench/ and use Benchee. Run them all with:
mix bench
To check a change for slowdowns, save a run before the change, then run again afterwards. A run without a tag is compared against every saved run.
mix bench baseline # save this run under the tag "baseline"
mix run bench/solve.exs # later: run one script and compare it to the saved runs
Saved runs go in bench/results/, which is not committed. Only compare runs from the same machine.