Motive Animation System
An open source project by FPL.
 All Classes Functions Variables Typedefs Friends Pages
curve.h
1 // Copyright 2014 Google Inc. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef MOTIVE_MATH_CURVE_H_
16 #define MOTIVE_MATH_CURVE_H_
17 
18 #include <string>
19 #include <cstring> // Required for memset, memcpy on Linux
20 #include "motive/common.h"
21 #include "motive/math/range.h"
22 
23 namespace motive {
24 
25 enum CurveValueType {
26  kCurveValue,
27  kCurveDerivative,
28  kCurveSecondDerivative,
29  kCurveThirdDerivative,
30 };
31 
32 static const int kDefaultGraphWidth = 80;
33 static const int kDefaultGraphHeight = 30;
34 static const mathfu::vec2i kDefaultGraphSize(kDefaultGraphWidth,
35  kDefaultGraphHeight);
36 
37 /// 2^22 = the max precision of significand.
38 static const float kEpsilonPrecision = static_cast<float>(1 << 22);
39 static const float kEpsilonScale = 1.0f / kEpsilonPrecision;
40 
41 /// @class QuadraticInitWithStartDerivative
42 /// @brief Initialization parameters to create a quaternion with
43 /// start and end values, and start derivative.
44 /// Start is x = 0. End is x = 1.
46  QuadraticInitWithStartDerivative(const float start_y,
47  const float start_derivative,
48  const float end_y)
49  : start_y(start_y), start_derivative(start_derivative), end_y(end_y) {}
50 
51  float start_y;
52  float start_derivative;
53  float end_y;
54 };
55 
56 /// @class QuadraticInitWithOrigin
57 /// @brief Initialization parameters to create a quaternion with
58 /// values and derivatives at x=0.
60  QuadraticInitWithOrigin(const float y, const float derivative,
61  const float second_derivative)
62  : y(y), derivative(derivative), second_derivative(second_derivative) {}
63 
64  float y;
65  float derivative;
66  float second_derivative;
67 };
68 
69 /// @class QuadraticInitWithPoint
70 /// @brief Initialization parameters to create a quaternion with
71 /// values and derivatives at a specified x.
73  QuadraticInitWithPoint(const float x, const float y_at_x,
74  const float derivative_at_x,
75  const float second_derivative)
76  : x(x),
77  y_at_x(y_at_x),
78  derivative_at_x(derivative_at_x),
79  second_derivative(second_derivative) {}
80 
81  float x;
82  float y_at_x;
83  float derivative_at_x;
84  float second_derivative;
85 };
86 
87 /// @class QuadraticCurve
88 /// @brief Represent a quadratic polynomial in the form
89 /// c_[2] * x^2 + c_[1] * x + c_[0]
91  public:
92  static const int kNumCoeff = 3;
95 
96  QuadraticCurve() { memset(c_, 0, sizeof(c_)); }
97  QuadraticCurve(const float c2, const float c1, const float c0) {
98  c_[2] = c2;
99  c_[1] = c1;
100  c_[0] = c0;
101  }
102  QuadraticCurve(const float* c) { memcpy(c_, c, sizeof(c_)); }
103  QuadraticCurve(const QuadraticCurve& q, const float y_scale) {
104  for (int i = 0; i < kNumCoeff; ++i) {
105  c_[i] = y_scale * q.c_[i];
106  }
107  }
108  QuadraticCurve(const QuadraticInitWithStartDerivative& init) { Init(init); }
109  QuadraticCurve(const QuadraticInitWithOrigin& init) { Init(init); }
110  QuadraticCurve(const QuadraticInitWithPoint& init) { Init(init); }
111  void Init(const QuadraticInitWithStartDerivative& init);
112  void Init(const QuadraticInitWithOrigin& init);
113  void Init(const QuadraticInitWithPoint& init);
114 
115  /// Add the coefficients of another quadratic curve to this one.
117  for (int i = 0; i < kNumCoeff; ++i) {
118  c_[i] += rhs.c_[i];
119  }
120  return *this;
121  }
122 
123  /// Subtract the coefficients of another quadratic curve from this one.
125  for (int i = 0; i < kNumCoeff; ++i) {
126  c_[i] -= rhs.c_[i];
127  }
128  return *this;
129  }
130 
131  /// Shift the curve along the x-axis: x_shift to the left.
132  /// That is x_shift becomes the curve's x=0.
133  void ShiftLeft(const float x_shift);
134 
135  /// Shift the curve along the x-axis: x_shift to the right.
136  void ShiftRight(const float x_shift) { ShiftLeft(-x_shift); }
137 
138  /// Shift the curve along the y-axis by y_offset: y_offset up the y-axis.
139  void ShiftUp(const float y_offset) { c_[0] += y_offset; }
140 
141  /// Scale the curve along the y-axis by a factor of y_scale.
142  void ScaleUp(const float y_scale) {
143  for (int i = 0; i < kNumCoeff; ++i) {
144  c_[i] *= y_scale;
145  }
146  }
147 
148  /// Return the quadratic function's value at `x`.
149  /// f(x) = c2*x^2 + c1*x + c0
150  float Evaluate(const float x) const {
151  return (c_[2] * x + c_[1]) * x + c_[0];
152  }
153 
154  /// Return the quadratic function's slope at `x`.
155  /// f'(x) = 2*c2*x + c1
156  float Derivative(const float x) const { return 2.0f * c_[2] * x + c_[1]; }
157 
158  /// Return the quadratic function's constant second derivative.
159  /// f''(x) = 2*c2
160  float SecondDerivative() const { return 2.0f * c_[2]; }
161 
162  /// Return the quadratic function's constant second derivative.
163  /// Even though `x` is unused, we pass it in for consistency with other
164  /// curve classes.
165  float SecondDerivative(const float /*x*/) const { return SecondDerivative(); }
166 
167  /// Return the quadratic function's constant third derivative: 0.
168  /// Even though `x` is unused, we pass it in for consistency with other
169  /// curve classes.
170  /// f'''(x) = 0
171  float ThirdDerivative(const float x) const {
172  (void)x;
173  return 0.0f;
174  }
175 
176  /// Returns a value below which floating point precision is unreliable.
177  /// If we're testing for zero, for instance, we should test against this
178  /// value. Pass in the x-range as well, in case that coefficient dominates
179  /// the others.
180  float EpsilonInRange(const float max_x) const {
181  return Epsilon(std::max(std::fabs(max_x), MaxCoeff()));
182  }
183 
184  /// Returns a value below which floating point precision is unreliable.
185  /// If we're testing for zero, for instance, we should test against this
186  /// value. We don't consider the x-range here, so this value is useful only
187  /// when dealing with the equation itself.
188  float EpsilonOfCoefficients() const { return Epsilon(MaxCoeff()); }
189 
190  /// Given values in the range of `x`, returns a value below which should be
191  /// considered zero.
192  float Epsilon(const float x) const {
193  return x * kEpsilonScale;
194  }
195 
196  /// Returns the largest absolute value of the coefficients. Gives a sense
197  /// of the scale of the quaternion. If all the coefficients are tiny or
198  /// huge, we'll need to renormalize around 1, since we take reciprocals of
199  /// the coefficients, and floating point precision is poor for floats.
200  float MaxCoeff() const {
201  using std::max;
202  const QuadraticCurve abs = AbsCoeff();
203  return max(max(abs.c_[2], abs.c_[1]), abs.c_[0]);
204  }
205 
206  /// Used for finding roots, and more.
207  /// See http://en.wikipedia.org/wiki/Discriminant
208  float Discriminant() const { return c_[1] * c_[1] - 4.0f * c_[2] * c_[0]; }
209 
210  /// When Discriminant() is close to zero, set to zero.
211  /// Often floating point precision problems can make the discriminant
212  /// very slightly non-zero, even though mathematically it should be zero.
213  float ReliableDiscriminant(const float epsilon) const;
214 
215  /// Return the x at which the derivative is zero.
216  float CriticalPoint() const {
217  assert(std::fabs(c_[2]) >= EpsilonOfCoefficients());
218 
219  /// 0 = f'(x) = 2*c2*x + c1 ==> x = -c1 / 2c2
220  return -(c_[1] / c_[2]) * 0.5f;
221  }
222 
223  /// Calculate the x-coordinates where this quadratic is zero,
224  /// and put them into `roots`, in ascending order.
225  /// Returns the 0, 1, or 2, the number of unique values put into `roots`.
226  void Roots(RootsArray* roots) const { roots->len = Roots(roots->arr); }
227 
228  /// Same as Roots() but do not normalize the quadratic for precision.
229  /// This function is not recommended, in general. Normalizing does not take
230  /// much time, and floating point precision is something that we only like to
231  /// think we can ignore. It may be safe to call this function if you are
232  /// certain that your x^2 coefficient is near 1.
233  void RootsWithoutNormalizing(RootsArray* roots) const {
234  roots->len = RootsWithoutNormalizing(roots->arr);
235  }
236 
237  /// Calculate the x-coordinates within the range [start_x, end_x] where the
238  /// quadratic is zero. Put them into `roots`. Return the number of unique
239  /// values put into `roots`.
240  void RootsInRange(const Range& x_limits, RootsArray* roots) const {
241  roots->len = RootsInRange(x_limits, roots->arr);
242  }
243 
244  /// Calculate the x-coordinates at the value.
245  void XsForValue(float value, RootsArray* roots) const {
246  const QuadraticCurve shifted_down(c_[2], c_[1], c_[0] - value);
247  shifted_down.Roots(roots);
248  }
249 
250  /// Get ranges above or below zero. Since a quadratic can cross zero at most
251  /// twice, there can be at most two ranges. Ranges are clamped to `x_limits`.
252  /// `sign` is used to determine above or below zero only--actual value is
253  /// ignored.
254  void RangesMatchingSign(const Range& x_limits, const float sign,
255  RangeArray* matching) const {
256  matching->len = RangesMatchingSign(x_limits, sign, matching->arr);
257  }
258 
259  /// Return the ranges on which the quadratic is above zero.
260  void RangesAboveZero(const Range& x_limits, RangeArray* matching) const {
261  RangesMatchingSign(x_limits, 1.0f, matching);
262  }
263 
264  /// Return the ranges on which the quadratic is below zero.
265  void RangesBelowZero(const Range& x_limits, RangeArray* matching) const {
266  RangesMatchingSign(x_limits, -1.0f, matching);
267  }
268 
269  /// Returns the coefficient for x-to-the-ith -power.
270  float Coeff(int i) const { return c_[i]; }
271 
272  /// Returns the number of coefficients in this curve.
273  int NumCoeff() const { return kNumCoeff; }
274 
275  /// Returns the curve f(x / x_scale), where f is the current quadratic.
276  /// This stretches the curve along the x-axis by x_scale.
277  QuadraticCurve ScaleInX(const float x_scale) const {
278  return ScaleInXByReciprocal(1.0f / x_scale);
279  }
280 
281  /// Returns the curve f(x * x_scale_reciprocal), where f is the current
282  /// quadratic.
283  /// This stretches the curve along the x-axis by 1/x_scale_reciprocal
284  QuadraticCurve ScaleInXByReciprocal(const float x_scale_reciprocal) const {
285  return QuadraticCurve(c_[2] * x_scale_reciprocal * x_scale_reciprocal,
286  c_[1] * x_scale_reciprocal, c_[0]);
287  }
288 
289  /// Returns the curve y_scale * f(x).
290  QuadraticCurve ScaleInY(const float y_scale) const {
291  return QuadraticCurve(*this, y_scale);
292  }
293 
294  /// Returns the same curve but with all coefficients in absolute value.
295  /// Useful for numerical precision work.
297  using std::fabs;
298  return QuadraticCurve(fabs(c_[2]), fabs(c_[1]), fabs(c_[0]));
299  }
300 
301  /// Equality. Checks for exact match. Useful for testing.
302  bool operator==(const QuadraticCurve& rhs) const;
303  bool operator!=(const QuadraticCurve& rhs) const { return !operator==(rhs); }
304 
305  /// A string with the equation for this quadratic. Useful for debugging.
306  std::string Text() const;
307 
308  private:
309  // Feel free to expose these versions in the external API if they're useful.
310  size_t Roots(float roots[2]) const;
311  size_t RootsWithoutNormalizing(float roots[2]) const;
312  size_t RootsInRange(const Range& x_limits, float roots[2]) const;
313  size_t RangesMatchingSign(const Range& x_limits, const float sign,
314  Range matching[2]) const;
315 
316  float c_[kNumCoeff]; /// c_[2] * x^2 + c_[1] * x + c_[0]
317 };
318 
319 inline QuadraticCurve operator+(const QuadraticCurve& a,
320  const QuadraticCurve& b) {
321  return QuadraticCurve(a.Coeff(2) + b.Coeff(2), a.Coeff(1) + b.Coeff(1),
322  a.Coeff(0) + b.Coeff(0));
323 }
324 
325 inline QuadraticCurve operator-(const QuadraticCurve& a,
326  const QuadraticCurve& b) {
327  return QuadraticCurve(a.Coeff(2) - b.Coeff(2), a.Coeff(1) - b.Coeff(1),
328  a.Coeff(0) - b.Coeff(0));
329 }
330 
331 /// @class CubicInit
332 /// @brief Initialization parameters to create a cubic curve with start and
333 /// end y-values and derivatives.
334 /// Start is x = 0. End is x = width_x.
335 struct CubicInit {
336  CubicInit(const float start_y, const float start_derivative,
337  const float end_y, const float end_derivative, const float width_x)
338  : start_y(start_y),
339  start_derivative(start_derivative),
340  end_y(end_y),
341  end_derivative(end_derivative),
342  width_x(width_x) {}
343 
344  // Short-form in comments:
345  float start_y; // y0
346  float start_derivative; // s0
347  float end_y; // y1
348  float end_derivative; // s1
349  float width_x; // w
350 };
351 
352 /// @class CubicCurve
353 /// @brief Represent a cubic polynomial of the form,
354 /// c_[3] * x^3 + c_[2] * x^2 + c_[1] * x + c_[0]
355 class CubicCurve {
356  public:
357  static const int kNumCoeff = 4;
358  CubicCurve() { memset(c_, 0, sizeof(c_)); }
359  CubicCurve(const float c3, const float c2, const float c1, const float c0) {
360  c_[3] = c3;
361  c_[2] = c2;
362  c_[1] = c1;
363  c_[0] = c0;
364  }
365  CubicCurve(const float* c) { memcpy(c_, c, sizeof(c_)); }
366  CubicCurve(const CubicInit& init) { Init(init); }
367  void Init(const CubicInit& init);
368 
369  /// Shift the curve along the x-axis: x_shift to the left.
370  /// That is x_shift becomes the curve's x=0.
371  void ShiftLeft(const float x_shift);
372 
373  /// Shift the curve along the x-axis: x_shift to the right.
374  void ShiftRight(const float x_shift) { ShiftLeft(-x_shift); }
375 
376  /// Shift the curve along the y-axis by y_offset: y_offset up the y-axis.
377  void ShiftUp(float y_offset) { c_[0] += y_offset; }
378 
379  /// Scale the curve along the y-axis by a factor of y_scale.
380  void ScaleUp(float y_scale) {
381  for (int i = 0; i < kNumCoeff; ++i) {
382  c_[i] *= y_scale;
383  }
384  }
385 
386  /// Return the cubic function's value at `x`.
387  /// f(x) = c3*x^3 + c2*x^2 + c1*x + c0
388  float Evaluate(const float x) const {
389  /// Take advantage of multiply-and-add instructions that are common on FPUs.
390  return ((c_[3] * x + c_[2]) * x + c_[1]) * x + c_[0];
391  }
392 
393  /// Return the cubic function's slope at `x`.
394  /// f'(x) = 3*c3*x^2 + 2*c2*x + c1
395  float Derivative(const float x) const {
396  return (3.0f * c_[3] * x + 2.0f * c_[2]) * x + c_[1];
397  }
398 
399  /// Return the cubic function's second derivative at `x`.
400  /// f''(x) = 6*c3*x + 2*c2
401  float SecondDerivative(const float x) const {
402  return 6.0f * c_[3] * x + 2.0f * c_[2];
403  }
404 
405  /// Return the cubic function's constant third derivative.
406  /// Even though `x` is unused, we pass it in for consistency with other
407  /// curve classes.
408  /// f'''(x) = 6*c3
409  float ThirdDerivative(const float x) const {
410  (void)x;
411  return 6.0f * c_[3];
412  }
413 
414  /// Returns true if always curving upward or always curving downward on the
415  /// specified x_limits.
416  /// That is, returns true if the second derivative has the same sign over
417  /// all of x_limits.
418  bool UniformCurvature(const Range& x_limits) const;
419 
420  /// Return a value below which floating point precision is unreliable.
421  /// If we're testing for zero, for instance, we should test against this
422  /// Epsilon().
423  float Epsilon() const {
424  using std::max;
425  using std::fabs;
426  const float max_c =
427  max(max(max(fabs(c_[3]), fabs(c_[2])), fabs(c_[1])), fabs(c_[0]));
428  return max_c * kEpsilonScale;
429  }
430 
431  /// Returns the coefficient for x to the ith power.
432  float Coeff(int i) const { return c_[i]; }
433 
434  /// Overrides the coefficent for x to the ith power.
435  void SetCoeff(int i, float coeff) { c_[i] = coeff; }
436 
437  /// Returns the number of coefficients in this curve.
438  int NumCoeff() const { return kNumCoeff; }
439 
440  /// Equality. Checks for exact match. Useful for testing.
441  bool operator==(const CubicCurve& rhs) const;
442  bool operator!=(const CubicCurve& rhs) const { return !operator==(rhs); }
443 
444  /// A string with the cubic equation. Useful for debugging.
445  std::string Text() const;
446 
447  private:
448  float c_[kNumCoeff]; /// c_[3] * x^3 + c_[2] * x^2 + c_[1] * x + c_[0]
449 };
450 
451 /// Draw an ASCII-art graph of the array of (x,y) 'points'.
452 /// The size of the graph in (horizontal characters, vertical lines) is given
453 /// by 'size'.
454 std::string Graph2DPoints(const mathfu::vec2* points, const int num_points,
455  const mathfu::vec2i& size = kDefaultGraphSize);
456 
457 /// Slow function that returns one of the possible values that this curve
458 /// can evaluate. Useful for debugging.
459 template <class T>
460 float CurveValue(const T& curve, const float x,
461  const CurveValueType value_type) {
462  switch (value_type) {
463  case kCurveValue:
464  return curve.Evaluate(x);
465  case kCurveDerivative:
466  return curve.Derivative(x);
467  case kCurveSecondDerivative:
468  return curve.SecondDerivative(x);
469  case kCurveThirdDerivative:
470  return curve.ThirdDerivative(x);
471  default:
472  assert(false);
473  }
474  return 0.0f;
475 }
476 
477 /// Returns an ASCII-art graph for x in 'x_range' for type T.
478 template <class T>
479 std::string GraphCurveOnXRange(const T& curve, const CurveValueType value_type,
480  const Range& x_range,
481  const mathfu::vec2i& size = kDefaultGraphSize) {
482  // Gather a collection of (x,y) points to graph.
483  const int num_points = size.x;
484  std::vector<mathfu::vec2> points(num_points);
485  const float inc_x = x_range.Length() / (num_points - 1);
486  float x = x_range.start();
487  for (int i = 0; i < num_points; ++i) {
488  points[i] = mathfu::vec2(x, CurveValue(curve, x, value_type));
489  x += inc_x;
490  }
491 
492  // Output the points in an ASCII-art graph.
493  return Graph2DPoints(&points[0], num_points, size);
494 }
495 
496 /// Returns an ASCII-art graph from StartX() to EndX() for the requested type.
497 template <class T>
498 std::string GraphCurve(const T& curve, const CurveValueType value_type,
499  const mathfu::vec2i& size = kDefaultGraphSize) {
500  return curve.Text() + "\n" +
501  GraphCurveOnXRange(curve, value_type,
502  Range(curve.StartX(), curve.EndX()), size);
503 }
504 
505 } // namespace motive
506 
507 #endif // MOTIVE_MATH_CURVE_H_
float Derivative(const float x) const
Definition: curve.h:156
void ScaleUp(const float y_scale)
Scale the curve along the y-axis by a factor of y_scale.
Definition: curve.h:142
float ThirdDerivative(const float x) const
Definition: curve.h:171
Initialization parameters to create a cubic curve with start and end y-values and derivatives...
Definition: curve.h:335
float Coeff(int i) const
Returns the coefficient for x to the ith power.
Definition: curve.h:432
std::string Text() const
A string with the cubic equation. Useful for debugging.
Definition: range.h:46
QuadraticCurve ScaleInY(const float y_scale) const
Returns the curve y_scale * f(x).
Definition: curve.h:290
Initialization parameters to create a quaternion with start and end values, and start derivative...
Definition: curve.h:45
float Derivative(const float x) const
Definition: curve.h:395
void Roots(RootsArray *roots) const
Definition: curve.h:226
bool operator==(const CubicCurve &rhs) const
Equality. Checks for exact match. Useful for testing.
float SecondDerivative(const float x) const
Definition: curve.h:401
QuadraticCurve ScaleInX(const float x_scale) const
Definition: curve.h:277
Definition: range.h:40
float Epsilon() const
Definition: curve.h:423
void RootsWithoutNormalizing(RootsArray *roots) const
Definition: curve.h:233
float CriticalPoint() const
Return the x at which the derivative is zero.
Definition: curve.h:216
Represent a quadratic polynomial in the form c_[2] * x^2 + c_[1] * x + c_[0].
Definition: curve.h:90
float ReliableDiscriminant(const float epsilon) const
int NumCoeff() const
Returns the number of coefficients in this curve.
Definition: curve.h:273
Represent a cubic polynomial of the form, c_[3] * x^3 + c_[2] * x^2 + c_[1] * x + c_[0]...
Definition: curve.h:355
Initialization parameters to create a quaternion with values and derivatives at x=0.
Definition: curve.h:59
QuadraticCurve ScaleInXByReciprocal(const float x_scale_reciprocal) const
Definition: curve.h:284
float Evaluate(const float x) const
Definition: curve.h:150
void ShiftLeft(const float x_shift)
int NumCoeff() const
Returns the number of coefficients in this curve.
Definition: curve.h:438
void ScaleUp(float y_scale)
Scale the curve along the y-axis by a factor of y_scale.
Definition: curve.h:380
QuadraticCurve AbsCoeff() const
Definition: curve.h:296
QuadraticCurve & operator-=(const QuadraticCurve &rhs)
Subtract the coefficients of another quadratic curve from this one.
Definition: curve.h:124
void RootsInRange(const Range &x_limits, RootsArray *roots) const
Definition: curve.h:240
float ThirdDerivative(const float x) const
Definition: curve.h:409
float Coeff(int i) const
Returns the coefficient for x-to-the-ith -power.
Definition: curve.h:270
Initialization parameters to create a quaternion with values and derivatives at a specified x...
Definition: curve.h:72
void ShiftUp(const float y_offset)
Shift the curve along the y-axis by y_offset: y_offset up the y-axis.
Definition: curve.h:139
void XsForValue(float value, RootsArray *roots) const
Calculate the x-coordinates at the value.
Definition: curve.h:245
float SecondDerivative(const float) const
Definition: curve.h:165
void SetCoeff(int i, float coeff)
Overrides the coefficent for x to the ith power.
Definition: curve.h:435
void RangesBelowZero(const Range &x_limits, RangeArray *matching) const
Return the ranges on which the quadratic is below zero.
Definition: curve.h:265
QuadraticCurve & operator+=(const QuadraticCurve &rhs)
Add the coefficients of another quadratic curve to this one.
Definition: curve.h:116
float Evaluate(const float x) const
Definition: curve.h:388
bool UniformCurvature(const Range &x_limits) const
float Discriminant() const
Definition: curve.h:208
float MaxCoeff() const
Definition: curve.h:200
float SecondDerivative() const
Definition: curve.h:160
void ShiftUp(float y_offset)
Shift the curve along the y-axis by y_offset: y_offset up the y-axis.
Definition: curve.h:377
void RangesMatchingSign(const Range &x_limits, const float sign, RangeArray *matching) const
Definition: curve.h:254
float EpsilonInRange(const float max_x) const
Definition: curve.h:180
void ShiftLeft(const float x_shift)
void RangesAboveZero(const Range &x_limits, RangeArray *matching) const
Return the ranges on which the quadratic is above zero.
Definition: curve.h:260
bool operator==(const QuadraticCurve &rhs) const
Equality. Checks for exact match. Useful for testing.
float Epsilon(const float x) const
Definition: curve.h:192
void ShiftRight(const float x_shift)
Shift the curve along the x-axis: x_shift to the right.
Definition: curve.h:374
std::string Text() const
A string with the equation for this quadratic. Useful for debugging.
void ShiftRight(const float x_shift)
Shift the curve along the x-axis: x_shift to the right.
Definition: curve.h:136
float EpsilonOfCoefficients() const
Definition: curve.h:188
Represent an interval on a number line.
Definition: range.h:37