/* * PolyBezierCurve.cpp * Poly * * Created by Ivan Safrin on 9/5/08. * Copyright 2008 __MyCompanyName__. All rights reserved. * */ #include "PolyBezierCurve.h" using namespace Polycode; BezierPoint::BezierPoint(float p1x, float p1y, float p1z, float p2x, float p2y, float p2z, float p3x, float p3y, float p3z) { p1.x = p1x; p1.y = p1y; p1.z = p1z; p2.x = p2x; p2.y = p2y; p2.z = p2z; p3.x = p3x; p3.y = p3y; p3.z = p3z; } BezierCurve::BezierCurve(){ for(int i=0; i < BUFFER_CACHE_PRECISION; i++) { heightBuffer[i] = 0; } buffersDirty = false; } BezierCurve::~BezierCurve() { } void BezierCurve::addControlPoint(float p1x, float p1y, float p1z, float p2x, float p2y, float p2z, float p3x, float p3y, float p3z) { BezierPoint* newPoint = new BezierPoint(p1x, p1y, p1z, p2x, p2y, p2z, p3x, p3y, p3z); controlPoints.push_back(newPoint); distances.push_back(0); recalculateDistances(); buffersDirty = true; } void BezierCurve::addControlPoint3dWithHandles(float p1x, float p1y, float p1z, float p2x, float p2y, float p2z, float p3x, float p3y, float p3z) { addControlPoint(p1x, p1y, p1z, p2x, p2y, p2z, p3x, p3y, p3z); } void BezierCurve::addControlPoint3d(float x, float y, float z) { addControlPoint(x, y, z, x, y, z, x, y, z); } void BezierCurve::addControlPoint2dWithHandles(float p1x, float p1y, float p2x, float p2y, float p3x, float p3y) { addControlPoint(p1x, p1y, 0, p2x, p2y, 0, p3x, p3y, 0); } void BezierCurve::addControlPoint2d(float x, float y) { addControlPoint(x, y, 0, x, y, 0, x, y, 0); } void BezierCurve::recalculateDistances() { if(controlPoints.size() < 2) return; float dist, lastDist = 0; distances[0] = 0; float totalDistance = 0; Vector3 point, lastPoint; for(int i=0; i < controlPoints.size()-1; i++) { lastPoint = getPointBetween(0, controlPoints[i], controlPoints[i+1]); dist = 0; for(float a=0.0f; a < 1.0f; a += 0.01) { point = getPointBetween(a, controlPoints[i], controlPoints[i+1]); dist += point.distance(lastPoint); lastPoint = point; } lastDist += dist; distances[i+1] = lastDist; totalDistance += dist; } // normalize distances to total distance for(int i=0; i < controlPoints.size(); i++) { distances[i] = distances[i]/totalDistance; } } Vector3 BezierCurve::getPointBetween(float a, BezierPoint *bp1, BezierPoint *bp2) { Vector3 retVector; float b = 1.0f - a; 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; 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; 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; return retVector; } BezierPoint *BezierCurve::getControlPoint(unsigned int index) { return controlPoints[index]; } unsigned int BezierCurve::getNumControlPoints() { return controlPoints.size(); } float BezierCurve::getHeightAt(float a) { if( a< 0) a = 0; if(a > 1) a = 1; if (buffersDirty) rebuildBuffers(); int index = ((float)(BUFFER_CACHE_PRECISION)) * a; return heightBuffer[index]; // return getPointAt(a).y; } void BezierCurve::rebuildBuffers() { for(int i=0; i < BUFFER_CACHE_PRECISION; i++) { heightBuffer[i] = getPointAt(((float)i)/((float)BUFFER_CACHE_PRECISION)).y; } buffersDirty = false; } Vector3 BezierCurve::getPointAt(float a) { if(a < 0) a = 0; if(a > 1) a = 1; if(controlPoints.size() < 2) return Vector3(0,0,0); Vector3 retVector; for(int i=0; i < controlPoints.size()-1; i++) { if(a >= distances[i] && a <= distances[i+1]) { retVector = getPointBetween(1.0f-((a-distances[i])/(distances[i+1]-distances[i])), controlPoints[i], controlPoints[i+1]); } } return retVector; }