BezierCurve.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /**
  2. * Copyright (c) 2006-2014 LOVE Development Team
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. *
  8. * Permission is granted to anyone to use this software for any purpose,
  9. * including commercial applications, and to alter it and redistribute it
  10. * freely, subject to the following restrictions:
  11. *
  12. * 1. The origin of this software must not be misrepresented; you must not
  13. * claim that you wrote the original software. If you use this software
  14. * in a product, an acknowledgment in the product documentation would be
  15. * appreciated but is not required.
  16. * 2. Altered source versions must be plainly marked as such, and must not be
  17. * misrepresented as being the original software.
  18. * 3. This notice may not be removed or altered from any source distribution.
  19. **/
  20. // LOVE
  21. #include "BezierCurve.h"
  22. #include "common/Exception.h"
  23. #include <cmath>
  24. using namespace std;
  25. namespace
  26. {
  27. /**
  28. * Subdivide Bezier polygon.
  29. **/
  30. void subdivide(vector<love::Vector> &points, int k)
  31. {
  32. if (k <= 0)
  33. return;
  34. // subdivision using de casteljau - subdivided control polygons are
  35. // on the 'edges' of the computation scheme, e.g:
  36. //
  37. // ------LEFT------->
  38. // b00 b10 b20 b30
  39. // b01 b11 b21 .---
  40. // b02 b12 .---'
  41. // b03 .---'RIGHT
  42. // <--'
  43. //
  44. // the subdivided control polygon is:
  45. // b00, b10, b20, b30, b21, b12, b03
  46. vector<love::Vector> left, right;
  47. left.reserve(points.size());
  48. right.reserve(points.size());
  49. for (size_t step = 1; step < points.size(); ++step)
  50. {
  51. left.push_back(points[0]);
  52. right.push_back(points[points.size() - step]);
  53. for (size_t i = 0; i < points.size() - step; ++i)
  54. points[i] = (points[i] + points[i+1]) * .5;
  55. }
  56. left.push_back(points[0]);
  57. right.push_back(points[0]);
  58. // recurse
  59. subdivide(left, k-1);
  60. subdivide(right, k-1);
  61. // merge (right is in reversed order)
  62. points.resize(left.size() + right.size() - 1);
  63. for (size_t i = 0; i < left.size(); ++i)
  64. points[i] = left[i];
  65. for (size_t i = 1; i < right.size(); ++i)
  66. points[i-1 + left.size()] = right[right.size() - i - 1];
  67. }
  68. }
  69. namespace love
  70. {
  71. namespace math
  72. {
  73. BezierCurve::BezierCurve(const vector<Vector> &pts)
  74. : controlPoints(pts)
  75. {
  76. }
  77. BezierCurve BezierCurve::getDerivative() const
  78. {
  79. if (getDegree() < 1)
  80. throw Exception("Cannot derive a curve of degree < 1.");
  81. // actually we can, it just doesn't make any sense.
  82. vector<Vector> forward_differences(controlPoints.size()-1);
  83. float degree = float(getDegree());
  84. for (size_t i = 0; i < forward_differences.size(); ++i)
  85. forward_differences[i] = (controlPoints[i+1] - controlPoints[i]) * degree;
  86. return BezierCurve(forward_differences);
  87. }
  88. const Vector &BezierCurve::getControlPoint(int i) const
  89. {
  90. if (i < 0)
  91. i += controlPoints.size();
  92. if (i < 0 || (size_t) i >= controlPoints.size())
  93. throw Exception("Invalid control point index");
  94. return controlPoints[i];
  95. }
  96. void BezierCurve::setControlPoint(int i, const Vector &point)
  97. {
  98. if (i < 0)
  99. i += controlPoints.size();
  100. if (i < 0 || (size_t) i >= controlPoints.size())
  101. throw Exception("Invalid control point index");
  102. controlPoints[i] = point;
  103. }
  104. void BezierCurve::insertControlPoint(const Vector &point, int pos)
  105. {
  106. if (pos < 0)
  107. pos += controlPoints.size() + 1;
  108. if (pos < 0 ||(size_t) pos > controlPoints.size())
  109. throw Exception("Invalid control point index");
  110. controlPoints.insert(controlPoints.begin() + pos, point);
  111. }
  112. void BezierCurve::translate(const Vector &t)
  113. {
  114. for (size_t i = 0; i < controlPoints.size(); ++i)
  115. controlPoints[i] += t;
  116. }
  117. void BezierCurve::rotate(double phi, const Vector &center)
  118. {
  119. float c = cos(phi), s = sin(phi);
  120. for (size_t i = 0; i < controlPoints.size(); ++i)
  121. {
  122. Vector v = controlPoints[i] - center;
  123. controlPoints[i].x = c * v.x - s * v.y + center.x;
  124. controlPoints[i].y = s * v.x + c * v.y + center.y;
  125. }
  126. }
  127. void BezierCurve::scale(double s, const Vector &center)
  128. {
  129. for (size_t i = 0; i < controlPoints.size(); ++i)
  130. controlPoints[i] = (controlPoints[i] - center) * s + center;
  131. }
  132. Vector BezierCurve::evaluate(double t) const
  133. {
  134. if (t < 0 || t > 1)
  135. throw Exception("Invalid evaluation parameter: must be between 0 and 1");
  136. if (controlPoints.size() < 2)
  137. throw Exception("Invalid Bezier curve: Not enough control points.");
  138. // de casteljau
  139. vector<Vector> points(controlPoints);
  140. for (size_t step = 1; step < controlPoints.size(); ++step)
  141. for (size_t i = 0; i < controlPoints.size() - step; ++i)
  142. points[i] = points[i] * (1-t) + points[i+1] * t;
  143. return points[0];
  144. }
  145. vector<Vector> BezierCurve::render(size_t accuracy) const
  146. {
  147. if (controlPoints.size() < 2)
  148. throw Exception("Invalid Bezier curve: Not enough control points.");
  149. vector<Vector> vertices(controlPoints);
  150. subdivide(vertices, accuracy);
  151. return vertices;
  152. }
  153. vector<Vector> BezierCurve::renderSegment(double start, double end, size_t accuracy) const
  154. {
  155. if (controlPoints.size() < 2)
  156. throw Exception("Invalid Bezier curve: Not enough control points.");
  157. vector<Vector> vertices(controlPoints);
  158. subdivide(vertices, accuracy);
  159. if (start > 0)
  160. {
  161. Vector startPoint = evaluate(start);
  162. for (size_t i = 0; i < vertices.size(); ++i)
  163. {
  164. if ((double)i / vertices.size() > start)
  165. {
  166. vertices.erase(vertices.begin(), vertices.begin() + i - 1);
  167. break;
  168. }
  169. }
  170. vertices.insert(vertices.begin(), startPoint);
  171. }
  172. if (end < 1)
  173. {
  174. Vector endPoint = evaluate(end);
  175. for (size_t i = vertices.size(); i > 0; --i)
  176. {
  177. if ((double)(i - 1) / vertices.size() < end)
  178. {
  179. vertices.erase(vertices.begin() + i, vertices.end());
  180. break;
  181. }
  182. }
  183. vertices.insert(vertices.end(), endPoint);
  184. }
  185. return vertices;
  186. }
  187. } // namespace math
  188. } // namespace love