ported the University CGI demo from WINDOWS + GLUT + GLEW + GLU + OpenGL 4 to LINUX WAYLAND + EGL + GLES 2 with minimal cuts

This commit is contained in:
beno
2025-07-03 01:26:25 +02:00
commit 6c125fb35e
85 changed files with 91688 additions and 0 deletions

View File

@@ -0,0 +1,80 @@
#include "../../HEADERS/CURVES/Bezier.hpp"
#include "iostream"
#define LERP(t,a,b) (1 - t) * a + t * b;
Bezier::Bezier(unsigned int order, vector<glm::vec3> *points, vector<float> *intervals) : Curve{ points, intervals } {
this->order = order;
}
/*might be useless (using lerp based evaluation)*/
float Bezier::evaluateBasisFunction(float at, int number, int order, float intervalLeft, float intervalRight) {
if (number < 0 || number > order) {
return 0;
}
else if (number == 0 && order == 0) {
return 1;
}
else {
return ((at - intervalLeft)/(intervalRight - intervalLeft)) * evaluateBasisFunction(at, number - 1, order - 1, intervalLeft, intervalRight) + ((intervalRight - at) / (intervalRight - intervalLeft)) * evaluateBasisFunction(at, number, order - 1, intervalLeft, intervalRight);
}
}
glm::vec3 Bezier::evaluate(float at) {
vector<glm::vec3>partials = vector<glm::vec3>();
for (const glm::vec3 point : *controlPoints)
partials.push_back(point);
int iter = partials.size() - 1;
while (iter > 0) {
for (int i = 0; i < iter; i++) {
partials[i] = LERP(at, partials[i], partials[i + 1]);
}
iter--;
}
return partials[0];
}
glm::vec3 Bezier::derivate(float at) {
return glm::vec3();
}
/*
* takes as input a sequence of points
* to be interpreted as conjoined bezier segments of order 3
*/
Bezier3Segments::Bezier3Segments( vector<glm::vec3>* points, vector<float>* intervals) : Bezier { ((unsigned int) points->size() - 1 ) , points , intervals } {
int nPoints = points->size();
assert((nPoints % 4) == 0);
}
glm::vec3 Bezier3Segments::evaluate(float at) {
for (int interval = 0; interval < intervalBoundaries->size() - 1; interval++) {
if ((intervalBoundaries->operator[](interval) <= at) && (intervalBoundaries->operator[](interval + 1) >= at)) {
float normalizedAt = (at - intervalBoundaries->operator[](interval)) / (intervalBoundaries->operator[](interval + 1) - intervalBoundaries->operator[](interval));
vector<glm::vec3> partials;
for (int j = 0; j <= 3; j++) {
partials.push_back(controlPoints->operator[](4 * interval + j));
}
int count = 3;
while (count > 0) {
for (int j = 0; j < count; j++) {
partials[j] = LERP(normalizedAt, partials[j], partials[j + 1]);
}
count--;
}
return partials[0];
}
}
throw "Bezier3Segment evaluation out of range";
}
glm::vec3 Bezier3Segments::derivate(float at) {
return glm::vec3();
}
float Bezier3Segments::getLeftBound() {
return intervalBoundaries->front();
}
float Bezier3Segments::getRightBound() {
return intervalBoundaries->back();
}

View File

@@ -0,0 +1,34 @@
#include "../../HEADERS/CURVES/Curve.hpp"
#include <iostream>
Curve::Curve(vector<glm::vec3> *points, vector<float> *boundaries) {
setControlPoints(points);
setIntervalBoundaries(boundaries);
}
vector<glm::vec3>* Curve::getControlPoints() {
return controlPoints;
}
vector<float>* Curve::getIntervalBoundaries() {
return intervalBoundaries;
}
void Curve::setControlPoints(vector<glm::vec3>* points) {
controlPoints = points;
}
void Curve::setIntervalBoundaries(vector<float> *boundaries) {
intervalBoundaries = boundaries;
}
float Curve::getLeftBound() {
return intervalBoundaries->front();
}
float Curve::getRightBound() {
return intervalBoundaries->back();
}

View File

@@ -0,0 +1,110 @@
#include "../../HEADERS/CURVES/CurveIterator.hpp"
#include <iostream>
#include <sstream>
CurveIterator::CurveIterator(Curve *curve, unsigned int steps, CurveIterationMode basicOrLength) {
this->curve = curve;
this->steps = steps;
this->iterationMode = basicOrLength;
leftBound = curve->getLeftBound();
rightBound = curve->getRightBound();
estimatedLength = 0;
resetIterator();
if (iterationMode == CurveIterationMode::LENGTH) {
computeLength();
}
}
void CurveIterator::resetIterator() {
basicStepCounter = 0;
lengthStepCounter = leftBound;
lastIncrement = (rightBound - leftBound) / steps;
//std::cout << "lastIncrement after reset is " << lastIncrement << std::endl;
}
void CurveIterator::computeLength() {
for (int i = 0; i < steps; i++) {
glm::vec3 startPoint = curve->evaluate(leftBound + (rightBound - leftBound) * i / steps);
glm::vec3 endPoint = curve->evaluate(leftBound + (rightBound - leftBound) * (i + 1) / steps);
estimatedLength += glm::length(endPoint - startPoint);
//std::cout << "segment length " << estimatedLength << std::endl;
}
}
float CurveIterator::getStep() {
if (iterationMode == CurveIterationMode::LENGTH) {
return lengthStepCounter;
}
else {
return leftBound + (rightBound - leftBound) * basicStepCounter / steps;
}
}
void CurveIterator::nextStep() {
if (iterationMode == CurveIterationMode::LENGTH) {
float increment = lastIncrement;
//std::cout << "lastInc is " << lastIncrement << std::endl;
//std::cout << "lstepCount is " << lengthStepCounter << std::endl;
if ((lengthStepCounter + increment) <= rightBound) {
glm::vec3 point1 = curve->evaluate(lengthStepCounter);
glm::vec3 point2 = curve->evaluate(lengthStepCounter + increment);
increment *= ((estimatedLength / steps) / glm::length(point2 - point1));
//std::cout << "segment length " << glm::length(curve->evaluate(lengthStepCounter + increment) - curve->evaluate(lengthStepCounter)) << std::endl;
lengthStepCounter += increment;
lastIncrement = increment;
}
else { //cycle
resetIterator();
}
}
else {
if(basicStepCounter < steps){
basicStepCounter++;
}
else {
resetIterator();
}
}
}
void CurveIterator::setProgress(float at) {
if (at < 0 || at > 1) {
std::stringstream err;
err << "CurveIterator : required progress (" << at << ") is out of range [ 0 , 1 ]";
throw std::invalid_argument(err.str());
}
else {
resetIterator();
int nSteps = at * steps;
for (int i = 0; i < nSteps; i++)
nextStep();
}
}
glm::vec3 CurveIterator::evaluation() {
float at;
if (iterationMode == CurveIterationMode::LENGTH) {
at = lengthStepCounter;
}
else {
at = leftBound + (rightBound - leftBound) * basicStepCounter / steps;
}
//std::cout << "iterator at is " << at << std::endl;
return curve->evaluate(at);
}
glm::vec3 CurveIterator::derivation() {
float at;
if (iterationMode == CurveIterationMode::LENGTH) {
at = lengthStepCounter;
}
else {
at = leftBound + (rightBound - leftBound) * basicStepCounter / steps;
}
return curve->derivate(at);
}
Curve* CurveIterator::getCurve() {
return curve;
}

View File

@@ -0,0 +1,203 @@
#include "../../HEADERS/CURVES/CurvesLoader.hpp"
string CurvesLoader::currentCurveType;
vector<glm::vec3>* CurvesLoader::pointsBuffer;
vector<NURBS*> CurvesLoader::NURBSes;
vector<Bezier3Segments*> CurvesLoader::beziers;
unsigned int CurvesLoader::NURBSOrder;
NURBSType CurvesLoader::NURBS_TYPE;
vector<float>* CurvesLoader::NURBSWeights;
char CurvesLoader::lineHeader[128];
char* CurvesLoader::res;
FILE* CurvesLoader::file;
std::smatch CurvesLoader::pieces;
void CurvesLoader::beginCurve(string str, std::smatch pieces, std::regex regex) {
pointsBuffer = new vector<glm::vec3>();
NURBSWeights = new vector<float>();
NURBS_TYPE = NURBSType::BASIC;
//si inizia una patch di BEZIER
if (pieces[1].str() == "BEZIER") {
//std::cout << "next is BEZIER" << std::endl;
currentCurveType = "BEZIER";
}
//si inizia una NURBS
else if (pieces[1].str() == "NURBS") {
//std::cout << "next is NURBS" << std::endl;
currentCurveType = "NURBS";
res = fgets(lineHeader, 128, file); // read curve multiplicity
str = lineHeader;
std::regex regex("\\s*order (\\d)\\s*(clamped|cyclic)?\\s*(\\n)?");
if (res == NULL || !std::regex_match(str, pieces, regex)) {
throw "expected NURBS order";
}
else {
NURBSOrder = stoi(pieces[1]);
if (pieces.length() > 2) {
if (pieces[2].str() == "clamped") {
NURBS_TYPE = NURBSType::CLAMPED;
}
else if (pieces[2].str() == "cyclic") {
NURBS_TYPE = NURBSType::CYCLIC;
}
}
else {
NURBS_TYPE = NURBSType::BASIC;
}
std::cout << res << std::endl;
}
//std::cout << "parsed order : " << NURBSOrder << std::endl;
}
}
NURBS* CurvesLoader::BasicNURBS() {
unsigned int nFunctions = pointsBuffer->size();
unsigned int totalElements = NURBSOrder + nFunctions;
vector<float>* intervals = new vector<float>();
for (int i = 0; i <= totalElements; i++)
intervals->push_back((float) i / totalElements);
vector<unsigned int>* multiplicities = new vector<unsigned int>;
for (int i = 0; i < pointsBuffer->size(); i++)
multiplicities->push_back(1);
return new NURBS(NURBSOrder, pointsBuffer, NURBSWeights, intervals, multiplicities);
}
NURBS* CurvesLoader::ClampedNURBS() {
unsigned int nFunctions = pointsBuffer->size();
vector<float>* intervals = new vector<float>();
for (int i = 0; i <= NURBSOrder; i++)
intervals->push_back(0);
for (int i = 1; i <= nFunctions - NURBSOrder; i++)
intervals->push_back((float)i / (nFunctions - NURBSOrder));
for (int i = 0; i < NURBSOrder; i++)
intervals->push_back(1);
vector<unsigned int>* multiplicities = new vector<unsigned int>;
for (int i = 0; i < pointsBuffer->size(); i++)
multiplicities->push_back(1);
return new NURBS(NURBSOrder, pointsBuffer, NURBSWeights, intervals, multiplicities);
}
NURBS* CurvesLoader::CyclicNURBS() {
for (int i = 0; i < NURBSOrder; i++) {
pointsBuffer->push_back(pointsBuffer->at(i));
NURBSWeights->push_back(NURBSWeights->at(i));
}
unsigned int nFunctions = pointsBuffer->size();
unsigned int totalElements = NURBSOrder + nFunctions;
vector<float>* intervals = new vector<float>();
for (int i = 0; i <= totalElements; i++)
intervals->push_back((float) i/ totalElements);
vector<unsigned int>* multiplicities = new vector<unsigned int>;
for (int i = 0; i < pointsBuffer->size(); i++)
multiplicities->push_back(1);
return new NURBS(NURBSOrder, pointsBuffer, NURBSWeights, intervals, multiplicities);
}
void CurvesLoader::closeNURBS(){
try {
switch (NURBS_TYPE) {
case NURBSType::BASIC :
std::cout << "NURBS was BASIC" << std::endl;
NURBSes.push_back(BasicNURBS());
break;
case NURBSType::CLAMPED :
std::cout << "NURBS was CLAMPED" << std::endl;
NURBSes.push_back(ClampedNURBS());
break;
case NURBSType::CYCLIC :
std::cout << "NURBS was CYCLIC" << std::endl;
NURBSes.push_back(CyclicNURBS());
break;
}
}
catch (std::invalid_argument e) {
std::cout << e.what() << std::endl;
}
}
void CurvesLoader::closeBezier() {
vector<float>* intervals = new vector<float>();
int nIntervals = pointsBuffer->size() / 4;
intervals->push_back(0);
for (int i = 1; i <= nIntervals; i++)
intervals->push_back((float)i / nIntervals);
beziers.push_back(new Bezier3Segments(pointsBuffer, intervals));
}
void CurvesLoader::closePendingCurve() {
if (currentCurveType == "BEZIER") {
closeBezier();
}
else if (currentCurveType == "NURBS") {
closeNURBS();
}
}
void CurvesLoader::parseVertexData(string str) {
vector<float> vecComponents = vector<float>();
std::regex regex("-?\\d+.\\d+");
while (std::regex_search(str, pieces, regex)) {
float entry = stof(pieces[0], NULL); //potevi evitare la regex
vecComponents.push_back(entry);
str = pieces.suffix().str();
}
glm::vec3 vec(vecComponents[0], vecComponents[1], vecComponents[2]);
pointsBuffer->push_back(vec);
if (currentCurveType == "NURBS") {
NURBSWeights->push_back(vecComponents[3]);
}
}
bool CurvesLoader::loadCurves(std::string path, vector<Curve*>& curves) {
currentCurveType = "NONE";
pointsBuffer = new vector<glm::vec3>();
NURBSWeights = new vector<float>();
file = fopen(&path[0], "r");
if (file == NULL) {
printf("Impossible to open the curve file ! Are you in the right path ?\n");
getchar();
return false;
}
while (1) {
res = fgets(lineHeader, 128, file); // read the first word of the line
// EOF = End Of File. Store pending curve and quit the loop.
if (res == NULL) {
closePendingCurve(); //what if there was no pending curve? (aka return false)
break;
}
string str = lineHeader;
std::regex regex("\\s*curve \\d+ : (BEZIER|NURBS)\\n");
//inizia una curva (la prima o una nuova)
if (std::regex_match(str, pieces, regex)) {
closePendingCurve();
beginCurve(str, pieces, regex);
}
//deve essere materiale inerente la curva in costruzione
else {
std::regex regex("\\s*(-?\\d+.\\d+)(( , -?\\d+.\\d+)+)\\s*(\\n)?");
//sono dati di un vertice
if (std::regex_match(str, pieces, regex)){
parseVertexData(str);
}
else {
std::cout << "unrecognized line : " << str << std::endl;
}
}
}
std::cout << "trovate " << beziers.size() << " curve di bezier" << std::endl << "e " << NURBSes.size() << " NURBS" << std::endl;
for (Bezier3Segments* el : beziers)
curves.push_back(el);
for (NURBS* el : NURBSes)
curves.push_back(el);
/* !!! only the file existence gets checked */
return true;
}

View File

@@ -0,0 +1,124 @@
#include "../../HEADERS/CURVES/Hermite.hpp"
#define PHI0(t) (2.0f*t*t*t - 3.0f*t*t + 1)
#define PHI1(t) (t*t*t - 2.0f*t*t + t)
#define PSI0(t) (-2.0f*t*t*t + 3.0f*t*t)
#define PSI1(t) (t*t*t - t*t)
Hermite::Hermite(vector<glm::vec3> *points, vector<float> *intervalBoundaries)
: Curve{ points, intervalBoundaries } {
}
void Hermite::computeDerivatives(HermiteModes mode, vector<glm::vec3> auxData) {
derivatives.clear();
int length = (*controlPoints).size();
switch (mode) {
case HermiteModes::Direct:
assert(controlPoints->size() == auxData.size());
derivatives.push_back(auxData[0]);
for (int i = 0; i < auxData.size() - 1; i++) {
derivatives.push_back(auxData[i]);
derivatives.push_back(auxData[i]);
}
derivatives.push_back(auxData[auxData.size() - 1]);
break;
case HermiteModes::Basic:
{
glm::vec3 result;
result = 0.5f * ((*controlPoints)[1] - (*controlPoints)[0]) / ((*intervalBoundaries)[1] - (*intervalBoundaries)[0]);
derivatives.push_back(result);
for (int i = 1; i < length - 1; i++) {
result = 0.5f *
(
(((*controlPoints)[i + 1] - (*controlPoints)[i])
/ ((*intervalBoundaries)[i + 1] - (*intervalBoundaries)[i]))
+ (((*controlPoints)[i] - (*controlPoints)[i - 1])
/ ((*intervalBoundaries)[i] - (*intervalBoundaries)[i - 1]))
);
derivatives.push_back(result);
derivatives.push_back(result);
}
result = 0.5f * ((*controlPoints)[length - 1] - (*controlPoints)[length - 2]) / ((*intervalBoundaries)[length - 1] - (*intervalBoundaries)[length - 2]);
derivatives.push_back(result);
}
break;
case HermiteModes::Cardinal:
{
assert(controlPoints->size() == auxData.size());
int last = controlPoints->size() - 1;
glm::vec3 delta1;
glm::vec3 delta2;
delta1 = (*controlPoints)[1] - (*controlPoints)[0];
float interval1;
float interval2;
interval1 = (*intervalBoundaries)[1] - (*intervalBoundaries)[0];
glm::vec3 result;
result = 0.5f * (1 - auxData[0].x) * delta1 / interval1;
derivatives.push_back(result);
for (int i = 1; i < last; i++) {
delta1 = (*controlPoints)[i + 1] - (*controlPoints)[i];
delta2 = (*controlPoints)[i] - (*controlPoints)[i - 1];
interval1 = (*intervalBoundaries)[i + 1] - (*intervalBoundaries)[i];
interval2 = (*intervalBoundaries)[i] - (*intervalBoundaries)[i - 1];
result = 0.5f * (1 - auxData[i].x) * (delta1 / interval1 + delta2 / interval2);
derivatives.push_back(result);
derivatives.push_back(result);
}
delta1 = (*controlPoints)[last] - (*controlPoints)[last - 1];
interval1 = (*intervalBoundaries)[last] - (*intervalBoundaries)[last - 1];
result = 0.5f * (1 - auxData[last].x) * (delta1 / interval1);
derivatives.push_back(result);
}
break;
case HermiteModes::TBC:
{
assert(controlPoints->size() == auxData.size());
int last = controlPoints->size() - 1;
glm::vec3 delta1;
glm::vec3 delta2;
delta1 = (*controlPoints)[1] - (*controlPoints)[0];
float interval1;
float interval2;
interval1 = (*intervalBoundaries)[1] - (*intervalBoundaries)[0];
glm::vec3 result;
//first
result = 0.5f * (1 - auxData[0].x) * (1 + auxData[0].y) * (1 + auxData[0].z) * delta1 / interval1;
derivatives.push_back(result);
for (int i = 1; i < last; i++) {
delta1 = (*controlPoints)[i + 1] - (*controlPoints)[i];
delta2 = (*controlPoints)[i] - (*controlPoints)[i - 1];
interval1 = (*intervalBoundaries)[i + 1] - (*intervalBoundaries)[i];
interval2 = (*intervalBoundaries)[i] - (*intervalBoundaries)[i - 1];
//last
result = 0.5f * ((1 - auxData[i].x) * (1 + auxData[i].y) * (1 - auxData[i].z) * (delta1 / interval1) + (1 - auxData[i].x) * (1 - auxData[i].y) * (1 - auxData[i].z) * (delta2 / interval2));
derivatives.push_back(result);
//first
result = 0.5f * ((1 - auxData[i].x) * (1 + auxData[i].y) * (1 + auxData[i].z) * (delta1 / interval1) + (1 - auxData[i].x) * (1 - auxData[i].y) * (1 - auxData[i].z) * (delta2 / interval2));
derivatives.push_back(result);
}
delta1 = (*controlPoints)[last] - (*controlPoints)[last - 1];
interval1 = (*intervalBoundaries)[last] - (*intervalBoundaries)[last - 1];
//last
result = 0.5f * ((1 - auxData[last].x) * (1 + auxData[last].y) * (1 - auxData[last].z) * (delta1 / interval1));
derivatives.push_back(result);
}
break;
}
}
glm::vec3 Hermite::evaluateCubic(float t, float t1, float t2, glm::vec3 y1, glm::vec3 y2, glm::vec3 dy1, glm::vec3 dy2) {
float interval = t2 - t1;
float newX = (t - t1) / interval;
return y1 * PHI0(newX) + dy1 * interval * PHI1(newX) + y2 * PSI0(newX) + dy2 * interval * PSI1(newX);
}
glm::vec3 Hermite::evaluate(float at) {
for (int i = 0; i < intervalBoundaries->size() - 1; i++)
if ((*intervalBoundaries)[i] <= at && at <= (*intervalBoundaries)[i + 1])
return evaluateCubic(at, (*intervalBoundaries)[i], (*intervalBoundaries)[i + 1], (*controlPoints)[i], (*controlPoints)[i + 1], derivatives[2 * i], derivatives[2 * i + 1]);
return glm::vec3();
}
glm::vec3 Hermite::derivate(float at) {
return glm::vec3();
}

128
GL_STUFF/SOURCES/CURVES/NURBS.cpp Executable file
View File

@@ -0,0 +1,128 @@
#include "../../HEADERS/CURVES/NURBS.hpp"
#include <stdexcept>
#include <sstream>
#include <iostream>
void NURBS::preliminaryChecks() {
int nPoints = controlPoints->size();
int nWeights = weights->size();
int nBoundaries = intervalBoundaries->size();
int nMultiplicities = multiplicities->size();
int requiredBoundaries = order + 1;
for (int i = 0; i < nMultiplicities; i++)
requiredBoundaries += multiplicities->operator[](i);
std::cout << "nPoints : " << nPoints << std::endl;
std::cout << "nWeights : " << nWeights << std::endl;
std::cout << "nBoundaries : " << nBoundaries << std::endl;
std::cout << "nMultiplicities : " << nMultiplicities << std::endl;
std::cout << "requiredBoundaries : " << requiredBoundaries << std::endl;
if (nWeights != nPoints)
throw std::invalid_argument("NURBS : nPoints <> nWeights");
if (nMultiplicities != (nPoints)) {
std::stringstream err;
err << "NURBS : nPoints (" << nPoints << ") <> nMultiplicities (" << nMultiplicities << ")";
throw std::invalid_argument(err.str());
}
if (nBoundaries != requiredBoundaries) {
std::stringstream err;
err << "NURBS : nBoundaries (" << nBoundaries << ") <> should be equal to Order + sum (multiplicities) (" << requiredBoundaries << ")";
throw std::invalid_argument(err.str());
}
}
NURBS::NURBS( unsigned int order, vector<glm::vec3>* points, vector<float>* weights, vector<float>* boundaries, vector<unsigned int>* multiplicities) : Curve{ points , boundaries} {
this->order = order;
this->weights = weights;
this->intervalBoundaries = boundaries;
this->multiplicities = multiplicities;
preliminaryChecks();
derivativePoints = new vector<glm::vec3>();
derivativeWeghts = new vector<float>();
derivativeBoundaries = new vector<float>();
for (int i = 0; i < controlPoints->size() - 1; i++) {
glm::vec3 point = ((float)order) * ((*controlPoints)[i + 1] - (*controlPoints)[i])
/ ((*intervalBoundaries)[i + order + 1] - (*intervalBoundaries)[i + 1]);
derivativePoints->push_back(point);
//not so sure about this
derivativeWeghts->push_back(weights->at(i));
}
for (int i = 1; i < intervalBoundaries->size() - 1; i++)
derivativeBoundaries->push_back(intervalBoundaries->operator[](i));
}
glm::vec3 NURBS::deBoor(float at, int index) {
if (order < 0) {
throw std::invalid_argument("NURBS : evaluateBasis order underflow");
}
else {
vector<glm::vec3> points = vector<glm::vec3>();
vector<float> wei = vector<float>(); //
int firstPointIndex = index - order;
for (int i = index - order; i <= index; i++) {
float w = weights->operator[](i);
points.push_back(controlPoints->operator[](i) * w);
wei.push_back(w); //
}
for (int j = 0; j < order; j++) {
for (int i = index - order + j + 1; i <= index; i++) {
int pointIndex = i - index + order;
float denominator = ((*intervalBoundaries)[i + order - j] - (*intervalBoundaries)[i]);
if (denominator != 0.0f){
points[pointIndex] = (points[pointIndex] * (at - (*intervalBoundaries)[i]) + ((*intervalBoundaries)[i + order - j] - at) * points[pointIndex - 1])
/ denominator;
wei[pointIndex] = (wei[pointIndex] * (at - (*intervalBoundaries)[i]) + ((*intervalBoundaries)[i + order - j] - at) * wei[pointIndex - 1])
/ denominator;
}
}
}
return points[order] / wei[order];
}
}
glm::vec3 NURBS::evaluate(float at) {
//std::cout << "eval at " << at << std::endl;
for(int i = order; i < intervalBoundaries->size() - order - 1; i++)
if ((intervalBoundaries->operator[](i) <= at) && (at < intervalBoundaries->operator[](i + 1))) {
return deBoor(at, i);
}
if (pow(at - getRightBound(), 2) < 1e-8)
return deBoor(at, intervalBoundaries->size() - order - 2);
throw std::invalid_argument("NURBS : evaluation out of range");
}
glm::vec3 NURBS::derivate(float at) {
vector<glm::vec3>* swapPoints = controlPoints;
vector<float>* swapWeights = weights;
vector<float>* swapBoundaries = intervalBoundaries;
controlPoints = derivativePoints;
weights = derivativeWeghts;
intervalBoundaries = derivativeBoundaries;
order--;
glm::vec3 result = evaluate(at);
order++;
controlPoints = swapPoints;
weights = swapWeights;
intervalBoundaries = swapBoundaries;
return result;
}
float NURBS::getLeftBound() {
return intervalBoundaries->at(order);
}
float NURBS::getRightBound() {
return intervalBoundaries->at(intervalBoundaries->size() - order - 1);
}