PolyBezierCurve.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. /*
  2. * PolyBezierCurve.cpp
  3. * Poly
  4. *
  5. * Created by Ivan Safrin on 9/5/08.
  6. * Copyright 2008 __MyCompanyName__. All rights reserved.
  7. *
  8. */
  9. #include "PolyBezierCurve.h"
  10. using namespace Polycode;
  11. BezierPoint::BezierPoint(Number p1x, Number p1y, Number p1z, Number p2x, Number p2y, Number p2z, Number p3x, Number p3y, Number p3z) {
  12. p1.x = p1x;
  13. p1.y = p1y;
  14. p1.z = p1z;
  15. p2.x = p2x;
  16. p2.y = p2y;
  17. p2.z = p2z;
  18. p3.x = p3x;
  19. p3.y = p3y;
  20. p3.z = p3z;
  21. }
  22. BezierCurve::BezierCurve(){
  23. for(int i=0; i < BUFFER_CACHE_PRECISION; i++) {
  24. heightBuffer[i] = 0;
  25. }
  26. buffersDirty = false;
  27. }
  28. BezierCurve::~BezierCurve() {
  29. }
  30. void BezierCurve::addControlPoint(Number p1x, Number p1y, Number p1z, Number p2x, Number p2y, Number p2z, Number p3x, Number p3y, Number p3z) {
  31. BezierPoint* newPoint = new BezierPoint(p1x, p1y, p1z, p2x, p2y, p2z, p3x, p3y, p3z);
  32. controlPoints.push_back(newPoint);
  33. distances.push_back(0);
  34. recalculateDistances();
  35. buffersDirty = true;
  36. }
  37. void BezierCurve::addControlPoint3dWithHandles(Number p1x, Number p1y, Number p1z, Number p2x, Number p2y, Number p2z, Number p3x, Number p3y, Number p3z) {
  38. addControlPoint(p1x, p1y, p1z, p2x, p2y, p2z, p3x, p3y, p3z);
  39. }
  40. void BezierCurve::addControlPoint3d(Number x, Number y, Number z) {
  41. addControlPoint(x, y, z, x, y, z, x, y, z);
  42. }
  43. void BezierCurve::addControlPoint2dWithHandles(Number p1x, Number p1y, Number p2x, Number p2y, Number p3x, Number p3y) {
  44. addControlPoint(p1x, p1y, 0, p2x, p2y, 0, p3x, p3y, 0);
  45. }
  46. void BezierCurve::addControlPoint2d(Number x, Number y) {
  47. addControlPoint(x, y, 0, x, y, 0, x, y, 0);
  48. }
  49. void BezierCurve::recalculateDistances() {
  50. if(controlPoints.size() < 2)
  51. return;
  52. Number dist, lastDist = 0;
  53. distances[0] = 0;
  54. Number totalDistance = 0;
  55. Vector3 point, lastPoint;
  56. for(int i=0; i < controlPoints.size()-1; i++) {
  57. lastPoint = getPointBetween(0, controlPoints[i], controlPoints[i+1]);
  58. dist = 0;
  59. for(Number a=0.0f; a < 1.0f; a += 0.01) {
  60. point = getPointBetween(a, controlPoints[i], controlPoints[i+1]);
  61. dist += point.distance(lastPoint);
  62. lastPoint = point;
  63. }
  64. lastDist += dist;
  65. distances[i+1] = lastDist;
  66. totalDistance += dist;
  67. }
  68. // normalize distances to total distance
  69. for(int i=0; i < controlPoints.size(); i++) {
  70. distances[i] = distances[i]/totalDistance;
  71. }
  72. }
  73. Vector3 BezierCurve::getPointBetween(Number a, BezierPoint *bp1, BezierPoint *bp2) {
  74. Vector3 retVector;
  75. Number b = 1.0f - a;
  76. retVector.x = bp1->p2.x*a*a*a + bp1->p3.x*3*a*a*b + bp2->p1.x*3*a*b*b + bp2->p2.x*b*b*b;
  77. retVector.y = bp1->p2.y*a*a*a + bp1->p3.y*3*a*a*b + bp2->p1.y*3*a*b*b + bp2->p2.y*b*b*b;
  78. retVector.z = bp1->p2.z*a*a*a + bp1->p3.z*3*a*a*b + bp2->p1.z*3*a*b*b + bp2->p2.z*b*b*b;
  79. return retVector;
  80. }
  81. BezierPoint *BezierCurve::getControlPoint(unsigned int index) {
  82. return controlPoints[index];
  83. }
  84. unsigned int BezierCurve::getNumControlPoints() {
  85. return controlPoints.size();
  86. }
  87. Number BezierCurve::getHeightAt(Number a) {
  88. if( a< 0) a = 0;
  89. if(a > 1) a = 1;
  90. if (buffersDirty)
  91. rebuildBuffers();
  92. int index = ((Number)(BUFFER_CACHE_PRECISION)) * a;
  93. return heightBuffer[index];
  94. // return getPointAt(a).y;
  95. }
  96. void BezierCurve::rebuildBuffers() {
  97. for(int i=0; i < BUFFER_CACHE_PRECISION; i++) {
  98. heightBuffer[i] = getPointAt(((Number)i)/((Number)BUFFER_CACHE_PRECISION)).y;
  99. }
  100. buffersDirty = false;
  101. }
  102. Vector3 BezierCurve::getPointAt(Number a) {
  103. if(a < 0)
  104. a = 0;
  105. if(a > 1)
  106. a = 1;
  107. if(controlPoints.size() < 2)
  108. return Vector3(0,0,0);
  109. Vector3 retVector;
  110. for(int i=0; i < controlPoints.size()-1; i++) {
  111. if(a >= distances[i] && a <= distances[i+1]) {
  112. retVector = getPointBetween(1.0f-((a-distances[i])/(distances[i+1]-distances[i])), controlPoints[i], controlPoints[i+1]);
  113. }
  114. }
  115. return retVector;
  116. }