Skip to content

Instantly share code, notes, and snippets.

@rye
Created May 7, 2015 17:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rye/96f111f3416c3074e51c to your computer and use it in GitHub Desktop.
Save rye/96f111f3416c3074e51c to your computer and use it in GitHub Desktop.
A Ruby script to calculate Bézier curves.
require "matrix"
require "pry"
class Integer
# Method to compute binomial coefficient nCk (where n is this object,
# and k is some other integer.
def choose(k)
# n! / (n-k)!
top = (((self-k)+1)..(self)).inject(1, &:*)
# k!
bottom = (2..k).inject(1, &:*)
# n! / (n-k)!k!
top / bottom
end
end
class Bezier
attr_accessor :points
def initialize(points)
@points = points
validate_points!
end
def calculate(time)
validate_points!
@points.each_with_index.map do |point, index|
# Multiply the point (which should be a Vector)
# by a scalar, which corresponds to:
#
# (Where n is the maximum point index, t is the parametric time,
# from 0.0 to 1.0, and i is the index of the current point)
#
# nCi * ((1 - t)^(n - i)) * (t ^ i).
point *
((@points.count - 1).choose(index)) *
((1 - time) ** (@points.count - 1 - index)) *
(time ** index)
end.inject(:+)
end
protected
def validate_points(points)
point_counts = points.map do |point|
point.count
end
unique_point_counts = point_counts.uniq
raise RuntimeError, "Not all points are of the same length!" unless unique_point_counts.length == 1
end
def validate_points!
validate_points(@points)
end
end
bezier = Bezier.new([Vector[0, 0], Vector[0, 2], Vector[1, 2], Vector[1, 0], Vector[2, 0], Vector[2, 2]])
(0.00..1.00).step(0.01) do |t|
p bezier.calculate t
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment