Class: BezierCurve
- Inherits:
-
Object
- Object
- BezierCurve
- Defined in:
- lib/bezier_curve.rb,
lib/bezier_curve/version.rb
Overview
bezier_curve/version.rb Just the version information for this library
Defined Under Namespace
Classes: DifferingDimensionError, InsufficientPointsError, ZeroDimensionError
Constant Summary collapse
- VERSION =
"0.9.2"
- RELEASE_DATE =
"2015-06-22"
Instance Attribute Summary collapse
-
#controls ⇒ Object
readonly
Returns the value of attribute controls.
Instance Method Summary collapse
-
#degree ⇒ Object
(also: #order)
the degree of the curve.
-
#dimensions ⇒ Object
the number of dimensions given.
-
#divergence ⇒ Object
How much this curve diverges from straight, measuring from ‘t=0.5`.
-
#first ⇒ Object
(also: #start)
the first control point.
-
#index(t) ⇒ Object
(also: #[])
find the point for a given value of ‘t`.
-
#initialize(*controls) ⇒ BezierCurve
constructor
create a new curve, from a list of points.
-
#is_straight?(tolerance) ⇒ Boolean
test this curve to see of it can be considered straight, optionally within the given angular tolerance, in radians.
-
#last ⇒ Object
(also: #end)
the last control point.
-
#points(count: nil, tolerance: Math::PI/64) ⇒ Object
Returns a list of points on this curve.
-
#split_at(t) ⇒ Object
divide this bezier curve into two curves, at the given ‘t`.
-
#subdivide(tolerance) ⇒ Object
recursively subdivides the curve until each is straight within the given tolerance value, in radians.
Constructor Details
#initialize(*controls) ⇒ BezierCurve
create a new curve, from a list of points.
19 20 21 22 23 24 25 26 |
# File 'lib/bezier_curve.rb', line 19 def initialize(*controls) # check for argument errors ZeroDimensionError.check! controls DifferingDimensionError.check! controls InsufficientPointsError.check! controls @controls = controls.map(&:to_np) end |
Instance Attribute Details
#controls ⇒ Object (readonly)
Returns the value of attribute controls.
28 29 30 |
# File 'lib/bezier_curve.rb', line 28 def controls @controls end |
Instance Method Details
#degree ⇒ Object Also known as: order
the degree of the curve
38 39 40 |
# File 'lib/bezier_curve.rb', line 38 def degree controls.size - 1 end |
#dimensions ⇒ Object
the number of dimensions given
43 44 45 |
# File 'lib/bezier_curve.rb', line 43 def dimensions controls[0].size end |
#divergence ⇒ Object
How much this curve diverges from straight, measuring from ‘t=0.5`
127 128 129 |
# File 'lib/bezier_curve.rb', line 127 def divergence first.angle_to(self[0.5],last) end |
#first ⇒ Object Also known as: start
the first control point
31 |
# File 'lib/bezier_curve.rb', line 31 def first() controls.first; end |
#index(t) ⇒ Object Also known as: []
find the point for a given value of ‘t`.
48 49 50 51 52 53 54 55 56 |
# File 'lib/bezier_curve.rb', line 48 def index(t) pts = controls while pts.size > 1 pts = (0..pts.size-2).map do |i| pts[i].zip(pts[i+1]).map{|a,b| t*(b-a)+a} end end pts[0].to_np end |
#is_straight?(tolerance) ⇒ Boolean
test this curve to see of it can be considered straight, optionally within the given angular tolerance, in radians
111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/bezier_curve.rb', line 111 def is_straight?(tolerance) # normal check for tolerance if divergence <= tolerance # maximum wavyness is `degree` - 1; split at `degree` points pts = points(count:degree) # size-3, because we ignore the last 2 points as starting points; # check all angles against `tolerance` (0..pts.size-3).all? do |i| pts[i].angle_to(pts[i+1], pts[i+2]) < tolerance end else false end end |
#last ⇒ Object Also known as: end
the last control point
34 |
# File 'lib/bezier_curve.rb', line 34 def last() controls.last; end |
#points(count: nil, tolerance: Math::PI/64) ⇒ Object
Returns a list of points on this curve. If you specify ‘count`, returns that many points, evenly spread over values of `t`. If you specify `tolerance`, no adjoining line segments will deviate from 180 by an angle of more than the value given (in radians). If unspecified, defaults to `tolerance: 1/64pi` (~3 deg)
79 80 81 82 83 84 85 86 |
# File 'lib/bezier_curve.rb', line 79 def points(count:nil, tolerance:Math::PI/64) if count (0...count).map{|i| index i/(count-1.0)} else lines = subdivide(tolerance) lines.map{|seg|seg.first} + [lines.last.last] end end |
#split_at(t) ⇒ Object
divide this bezier curve into two curves, at the given ‘t`
60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/bezier_curve.rb', line 60 def split_at(t) pts = controls a,b = [pts.first],[pts.last] while pts.size > 1 pts = (0..pts.size-2).map do |i| pts[i].zip(pts[i+1]).map{|a,b| t*(b-a)+a} end a<<pts.first b<<pts.last end [BezierCurve.new(*a), BezierCurve.new(*b.reverse)] end |
#subdivide(tolerance) ⇒ Object
recursively subdivides the curve until each is straight within the given tolerance value, in radians. Then, subdivides further as needed to remove remaining corners.
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/bezier_curve.rb', line 91 def subdivide(tolerance) if is_straight? tolerance [self] else a,b = split_at(0.5).map{|c| c.subdivide(tolerance)} # now make sure the angle from a to b is good while a.last.first.angle_to(a.last.last,b.first.last) > tolerance if a.last.divergence > b.first.divergence a[-1,1] = a[-1].split_at(0.5) else b[0,1] = b[0].split_at(0.5) end end a+b end end |