Commit cbd029fa authored by Lars Krecklau's avatar Lars Krecklau

Added first classes for NURBS support. Not finished yet but already working for simple cases.

parent 9074a852
////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2011, Computer Graphics Group RWTH Aachen University //
// All rights reserved. //
////////////////////////////////////////////////////////////////////////////////
#ifndef ACGL_SCENE_NURBSCONTROLPOINT_HH
#define ACGL_SCENE_NURBSCONTROLPOINT_HH
#include <ACGL/ACGL.hh>
#include <ACGL/Scene/NURBSDataVector.hh>
namespace ACGL{
namespace Scene{
template<uint_t DATA_DIMENSION>
class NURBSControlPoint
{
public:
typedef NURBSDataVector<DATA_DIMENSION> NURBSDataVectorType;
NURBSControlPoint(void)
: data(),
weight(1.0f)
{}
NURBSControlPoint(
const NURBSDataVectorType& _data,
float _weight = 1.0f)
: data(_data),
weight(_weight)
{}
virtual ~NURBSControlPoint(void) {}
NURBSControlPoint operator+(const NURBSControlPoint<DATA_DIMENSION>& _c) const
{
NURBSControlPoint c;
c.data = data + _c.data;
c.weight = weight + _c.weight;
return c;
}
const NURBSControlPoint& operator+=(const NURBSControlPoint<DATA_DIMENSION>& _c)
{
data += _c.data;
weight += _c.weight;
return *this;
}
NURBSControlPoint operator-(const NURBSControlPoint<DATA_DIMENSION>& _c) const
{
NURBSControlPoint c;
c.data = data - _c.data;
c.weight = weight - _c.weight;
return c;
}
const NURBSControlPoint& operator-=(const NURBSControlPoint<DATA_DIMENSION>& _c)
{
data -= _c.data;
weight -= _c.weight;
return *this;
}
NURBSControlPoint operator/(float _value) const
{
NURBSControlPoint c;
c.data = data / _value;
c.weight = weight / _value;
return c;
}
const NURBSControlPoint& operator/=(float _value)
{
data /= _value;
weight /= _value;
return *this;
}
NURBSControlPoint operator*(float _value) const
{
NURBSControlPoint c;
c.data = data * _value;
c.weight = weight * _value;
return c;
}
const NURBSControlPoint& operator*=(float _value)
{
data *= _value;
weight *= _value;
return *this;
}
NURBSDataVectorType data;
float weight;
};
template<uint_t DATA_DIMENSION>
std::ostream& operator<<(std::ostream& _os, const NURBSControlPoint<DATA_DIMENSION>& _controlPoint)
{
_os << "(Data: " << _controlPoint.data << ", Weight: " << _controlPoint.weight << ")";
return _os;
}
} // Scene
} // ACGL
#endif // ACGL_SCENE_NURBSCONTROLPOINT_HH
////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2011, Computer Graphics Group RWTH Aachen University //
// All rights reserved. //
////////////////////////////////////////////////////////////////////////////////
#ifndef ACGL_SCENE_NURBSCURVE_HH
#define ACGL_SCENE_NURBSCURVE_HH
#include <ACGL/ACGL.hh>
#include <ACGL/Scene/NURBSControlPoint.hh>
#include <vector>
namespace ACGL{
namespace Scene{
template<uint_t DATA_DIMENSION>
class NURBSCurve
{
public:
typedef NURBSControlPoint<DATA_DIMENSION> NURBSControlPointType;
NURBSCurve(
const std::vector<NURBSControlPointType>& _controlPoints,
uint_t _degree = 3)
: mDegree(_degree),
mOrder(_degree + 1),
mControlPoints(_controlPoints),
mKnots()
{
//First knot with #order multiplicity
mKnots.resize(mControlPoints.size() + mOrder, 0.0f);
//Inner knots
float fCurrentKnot = 1.0f;
for(uint_t i = mOrder; i < mKnots.size()-mOrder; ++i)
{
mKnots[i] = fCurrentKnot;
fCurrentKnot += 1.0f;
}
//Last knot with #order multiplicity
for(uint_t i = mKnots.size() - mOrder; i < mKnots.size(); ++i)
mKnots[i] = fCurrentKnot;
normalizeKnotVector();
}
NURBSCurve(
const std::vector<NURBSControlPointType>& _controlPoints,
const std::vector<float>& _knots,
uint_t _degree = 3)
: mDegree(_degree),
mOrder(_degree + 1),
mControlPoints(_controlPoints),
mKnots(_knots)
{}
virtual ~NURBSCurve(void){}
uint_t getDegree (void) const { return mDegree; }
uint_t getOrder (void) const { return mOrder; }
const std::vector<NURBSControlPointType>& getControlPoints (void) const { return mControlPoints; }
const std::vector<float>& getKnots (void) const { return mKnots; }
// http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/NURBS/NURBS-knot-insert.html
void insertKnot(float _t)
{
//Find the interval that _t lies in
uint_t interval = mDegree;
uint_t start = mOrder;
uint_t end = mKnots.size() - mOrder;
for(uint_t i = start; i < end; ++i)
{
if(mKnots[i] <= _t)
interval++;
else
break;
}
//Apply the weight of all NURBS control points and
//reverse the order in the span for easier indices
//in the next step.
std::vector<NURBSControlPointType> controlPointsInSpan(mOrder);
for(uint_t i = 0; i < mOrder; ++i)
{
controlPointsInSpan[i] = mControlPoints[interval - i];
controlPointsInSpan[i].data *= controlPointsInSpan[i].weight;
}
std::vector<NURBSControlPointType> newControlPoints(mDegree);
for(uint_t i = 0; i < mDegree; ++i)
{
float fRatio = (_t - mKnots[interval - i]) / (mKnots[interval + mDegree - i] - mKnots[interval - i]);
newControlPoints[i] = controlPointsInSpan[i + 1] * (1.0f - fRatio) + controlPointsInSpan[i] * fRatio;
newControlPoints[i].data /= newControlPoints[i].weight;
}
mKnots.insert(mKnots.begin() + (interval + 1), _t);
mControlPoints.insert(mControlPoints.begin() + interval, newControlPoints[0]);
for(uint_t i = 1; i < mDegree; ++i)
mControlPoints[interval - i] = newControlPoints[i];
}
//This function takes a knot vector and normalizes
//it to [0,1] within the region that can be evaluated,
//namely between the knots (degree) and (#knots - degree - 1)
void normalizeKnotVector(void)
{
float fSpan = mKnots[mKnots.size() - mOrder] - mKnots[mDegree];
for(std::vector<float>::size_type i = 0; i < mKnots.size(); ++i)
{
mKnots[i] -= mKnots[mDegree];
mKnots[i] /= fSpan;
}
}
private:
uint_t mDegree;
uint_t mOrder;
std::vector<NURBSControlPointType> mControlPoints;
std::vector<float> mKnots;
};
template<uint_t DATA_DIMENSION>
std::ostream& operator<<(std::ostream& _os, const NURBSCurve<DATA_DIMENSION>& _curve)
{
_os << "(Degree: " << _curve.getDegree() << ", Order: " << _curve.getOrder() << ", ";
_os << "ControlPoints: (";
for(typename std::vector<typename NURBSCurve<DATA_DIMENSION>::NURBSControlPointType>::size_type i = 0; i < _curve.getControlPoints().size(); ++i)
{
_os << _curve.getControlPoints()[i];
if(i + 1 < _curve.getControlPoints().size())
_os << ", ";
}
_os << "), ";
_os << "Knots: (";
for(std::vector<float>::size_type i = 0; i < _curve.getKnots().size(); ++i)
{
_os << _curve.getKnots()[i];
if(i + 1 < _curve.getKnots().size())
_os << ", ";
}
_os << ")";
return _os;
}
} // Scene
} // ACGL
#endif // ACGL_SCENE_NURBSCURVE_HH
////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2011, Computer Graphics Group RWTH Aachen University //
// All rights reserved. //
////////////////////////////////////////////////////////////////////////////////
#ifndef ACGL_SCENE_NURBSDATAVECTOR_HH
#define ACGL_SCENE_NURBSDATAVECTOR_HH
#include <ACGL/ACGL.hh>
#include <ACGL/Math/Math.hh>
#include <ACGL/Utils/Log.hh>
namespace ACGL{
namespace Scene{
template<uint_t DATA_DIMENSION>
class NURBSDataVector
{
public:
NURBSDataVector(void) {}
NURBSDataVector(const float* _data)
{
for(uint_t i = 0; i < DATA_DIMENSION; ++i)
data[i] = _data[i];
}
virtual ~NURBSDataVector(void) {}
static const uint_t sDataDimension;
uint_t getDataDimension (void) const { return sDataDimension;}
NURBSDataVector operator+(const NURBSDataVector<DATA_DIMENSION>& _v) const
{
NURBSDataVector v;
for(uint_t i = 0; i < DATA_DIMENSION; ++i)
v.data[i] = data[i] + _v.data[i];
return v;
}
const NURBSDataVector& operator+=(const NURBSDataVector<DATA_DIMENSION>& _v)
{
for(uint_t i = 0; i < DATA_DIMENSION; ++i)
data[i] += _v.data[i];
return *this;
}
NURBSDataVector operator-(const NURBSDataVector<DATA_DIMENSION>& _v) const
{
NURBSDataVector v;
for(uint_t i = 0; i < DATA_DIMENSION; ++i)
v.data[i] = data[i] - _v.data[i];
return v;
}
const NURBSDataVector& operator-=(const NURBSDataVector<DATA_DIMENSION>& _v)
{
for(uint_t i = 0; i < DATA_DIMENSION; ++i)
data[i] -= _v.data[i];
return *this;
}
NURBSDataVector operator/(float _value) const
{
NURBSDataVector v;
for(uint_t i = 0; i < DATA_DIMENSION; ++i)
v.data[i] = data[i] / _value;
return v;
}
const NURBSDataVector& operator/=(float _value)
{
for(uint_t i = 0; i < DATA_DIMENSION; ++i)
data[i] /= _value;
return *this;
}
NURBSDataVector operator*(float _value) const
{
NURBSDataVector v;
for(uint_t i = 0; i < DATA_DIMENSION; ++i)
v.data[i] = data[i] * _value;
return v;
}
const NURBSDataVector& operator*=(float _value)
{
for(uint_t i = 0; i < DATA_DIMENSION; ++i)
data[i] *= _value;
return *this;
}
float getLength (void) const
{
double sum = 0.0;
for(uint_t i = 0; i < DATA_DIMENSION; ++i)
sum += data[i] * data[i];
return ACGL::Math::Functions::sqrt(sum);
}
float operator[](int_t _id) const
{
return data[_id];
}
float data[DATA_DIMENSION];
};
template<uint_t DATA_DIMENSION>
const uint_t NURBSDataVector<DATA_DIMENSION>::sDataDimension = DATA_DIMENSION;
template<uint_t DATA_DIMENSION>
std::ostream& operator<<(std::ostream& _os, const NURBSDataVector<DATA_DIMENSION>& _v)
{
_os << "(";
for(uint_t i = 0; i < DATA_DIMENSION; ++i)
{
_os << _v.data[i];
if(i + 1 < DATA_DIMENSION)
_os << ", ";
}
_os << ")";
return _os;
}
} // Scene
} // ACGL
#endif // ACGL_SCENE_NURBSDATAVECTOR_HH
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment