Various enhancement of the curves (see issue 968) :

- less memory required (512 KB less)
- isIdentity() method has to be used by developers to let the user preselect a curve type without processing overhead
- faster NURBS getVal(float t) method, by using a hash table
This commit is contained in:
Hombre
2011-09-04 18:16:21 +02:00
parent 247cebbb2e
commit ee5b7c3a88
6 changed files with 485 additions and 339 deletions

View File

@@ -38,6 +38,13 @@ namespace rtengine {
x = 0;
y = 0;
ypp = 0;
hash = NULL;
hashSize = 1000; // has to be initiallised to the maximum value
}
Curve::~Curve () {
if (hash)
delete [] hash;
}
void Curve::AddPolygons ()
@@ -62,12 +69,71 @@ namespace rtengine {
poly_y.push_back(y3);
}
void Curve::fillHash() {
hash = new unsigned short int[hashSize+2];
unsigned int polyIter = 0;
double const increment = 1./hashSize;
double milestone = 0.;
for (unsigned int i=0; i<(hashSize+1); i++) {
while(poly_x[polyIter] <= milestone) ++polyIter;
hash[i] = polyIter-1;
milestone += increment;
}
hash[hashSize+1] = poly_x.size()-1;
/*
// Debug output to file
FILE* f = fopen ("hash.txt", "wt");
for (int i=0; i<(hashSize+2); i++)
fprintf (f, "%d: %d > %.6f, %.6f\n", i, hash[i], poly_x[hash[i]], poly_y[hash[i]]);
fprintf (f, "\nppn: %d\npoly_x: %d\n", ppn, poly_x.size());
fclose (f);
*/
}
// Wikipedia sRGB: Unlike most other RGB color spaces, the sRGB gamma cannot be expressed as a single numerical value.
// The overall gamma is approximately 2.2, consisting of a linear (gamma 1.0) section near black, and a non-linear section elsewhere involving a 2.4 exponent
// and a gamma (slope of log output versus log input) changing from 1.0 through about 2.3.
const double CurveFactory::sRGBGamma = 2.2;
const double CurveFactory::sRGBGammaCurve = 2.4;
void fillCurveArray(DiagonalCurve* diagCurve, LUTf &outCurve, int skip, bool needed) {
if (needed) {
LUTf lutCurve (65536);
for (int i=0; i<=0xffff; i+= i<0xffff-skip ? skip : 1 ) {
// change to [0,1] range
double val = (double)i / 65535.0;
// apply custom/parametric/NURBS curve, if any
val = diagCurve->getVal (val);
// store result in a temporary array
lutCurve[i] = (val);
}
// if skip>1, let apply linear interpolation in the skipped points of the curve
if (skip > 1) {
int prev = 0;
for (int i=1; i<=0xffff-skip; i++) {
if (i%skip==0) {
prev+=skip;
continue;
}
lutCurve[i] = ( lutCurve[prev] * (skip - i%skip) + lutCurve[prev+skip] * (i%skip) ) / skip;
}
}
for (int i=0; i<=0xffff; i++) {
outCurve[i] = (65535.0 * lutCurve[i]);
}
}
else {
for (int i=0; i<=0xffff; i++) {
outCurve[i] = (float)i;
}
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void CurveFactory::complexsgnCurve (double saturation, bool satlimit, double satlimthresh, \
@@ -76,16 +142,18 @@ namespace rtengine {
//colormult = chroma_scale for Lab manipulations
//-----------------------------------------------------
bool needed;
DiagonalCurve* dCurve = NULL;
// check if contrast curve is needed
bool needsaturation = (saturation<-0.0001 || saturation>0.0001);
needed = (saturation<-0.0001 || saturation>0.0001);
// curve without contrast
LUTf dacurve (65536);
LUTf dbcurve (65536);
// Filling the curve if needed
if (needed) {
LUTf dscurve (65536);
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%% Saturation curve's control points %%%%%%%%%%%%%%%%%
std::vector<double> satcurvePoints;
satcurvePoints.push_back((double)DCT_NURBS);
if (saturation>0) {
@@ -125,69 +193,48 @@ namespace rtengine {
satcurvePoints.push_back(1);
satcurvePoints.push_back(1+saturation/200.0);
}
DiagonalCurve* satcurve = new DiagonalCurve (satcurvePoints, CURVES_MIN_POLY_POINTS/skip); // Actually, CURVES_MIN_POLY_POINTS = 1000,
dCurve = new DiagonalCurve (satcurvePoints, CURVES_MIN_POLY_POINTS/skip);
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
fillCurveArray(dCurve, satCurve, skip, needed);
delete dCurve;
dCurve = NULL;
}
else {
fillCurveArray(NULL, satCurve, skip, needed);
}
//-----------------------------------------------------
needed = false;
// create a curve if needed
DiagonalCurve* tacurve = NULL;
if (acurvePoints.size()>0 && acurvePoints[0]!=0)
tacurve = new DiagonalCurve (acurvePoints, CURVES_MIN_POLY_POINTS/skip);
DiagonalCurve* tbcurve = NULL;
if (bcurvePoints.size()>0 && bcurvePoints[0]!=0)
tbcurve = new DiagonalCurve (bcurvePoints, CURVES_MIN_POLY_POINTS/skip);
for (int i=0; i<=0xffff; i+= i<0xffff-skip ? skip : 1 ) {
// change to [0,1] range
double aval = (double)i / 65535.0;
double bval = (double)i / 65535.0;
double sval = (double)i / 65535.0;
// apply saturation curve
if (needsaturation)
sval = satcurve->getVal (sval);
// apply custom/parametric/NURBS curve, if any
if (tacurve) {
aval = tacurve->getVal (aval);
if (acurvePoints.size()>0 && acurvePoints[0]!=0) {
dCurve = new DiagonalCurve (acurvePoints, CURVES_MIN_POLY_POINTS/skip);
if (dCurve && !dCurve->isIdentity())
needed = true;
}
// apply custom/parametric/NURBS curve, if any
if (tbcurve) {
bval = tbcurve->getVal (bval);
fillCurveArray(dCurve, aoutCurve, skip, needed);
if (dCurve) {
delete dCurve;
dCurve = NULL;
}
// store result in a temporary array
dacurve[i] = (aval);
dbcurve[i] = (bval);
dscurve[i] = (sval);
}
//-----------------------------------------------------
delete tacurve;
delete tbcurve;
// if skip>1, let apply linear interpolation in the skipped points of the curve
int prev = 0;
for (int i=1; i<=0xffff-skip; i++) {
if (i%skip==0) {
prev+=skip;
continue;
needed = false;
if (bcurvePoints.size()>0 && bcurvePoints[0]!=0) {
dCurve = new DiagonalCurve (bcurvePoints, CURVES_MIN_POLY_POINTS/skip);
if (dCurve && !dCurve->isIdentity())
needed = true;
}
dacurve[i] = ( dacurve[prev] * (skip - i%skip) + dacurve[prev+skip] * (i%skip) ) / skip;
dbcurve[i] = ( dbcurve[prev] * (skip - i%skip) + dbcurve[prev+skip] * (i%skip) ) / skip;
dscurve[i] = ( dscurve[prev] * (skip - i%skip) + dscurve[prev+skip] * (i%skip) ) / skip;
fillCurveArray(dCurve, boutCurve, skip, needed);
if (dCurve) {
delete dCurve;
dCurve = NULL;
}
for (int i=0; i<=0xffff; i++) {
aoutCurve[i] = (65535.0 * dacurve[i]);
boutCurve[i] = (65535.0 * dbcurve[i]);
satCurve[i] = (65535.0 * dscurve[i]);
}
delete satcurve;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -223,17 +270,9 @@ namespace rtengine {
// curve without contrast
LUTf dcurve(0x10000);
// check if contrast curve is needed
bool needcontrast = contr>0.00001 || contr<-0.00001;
// check if inverse gamma is needed at the end
bool needigamma = igamma_ && gamma_>0;
// create a curve if needed
DiagonalCurve* tcurve = NULL;
if (curvePoints.size()>0 && curvePoints[0]!=0)
tcurve = new DiagonalCurve (curvePoints, CURVES_MIN_POLY_POINTS/skip);
// clear array that stores histogram valid before applying the custom curve
outBeforeCCurveHistogram.clear();
@@ -241,11 +280,16 @@ namespace rtengine {
// tone curve base. a: slope (from exp.comp.), b: black, def_mul: max. x value (can be>1), hr,sr: highlight,shadow recovery
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DiagonalCurve* brightcurve = NULL;
// check if brightness curve is needed
if (br>0.00001 || br<-0.00001) {
std::vector<double> brightcurvePoints;
brightcurvePoints.push_back((double)DCT_NURBS);
brightcurvePoints.push_back(0); //black point. Value in [0 ; 1] range
brightcurvePoints.push_back(0); //black point. Value in [0 ; 1] range
brightcurvePoints.push_back(0.); //black point. Value in [0 ; 1] range
brightcurvePoints.push_back(0.); //black point. Value in [0 ; 1] range
if(br>0) {
brightcurvePoints.push_back(0.1); //toe point
@@ -260,10 +304,11 @@ namespace rtengine {
brightcurvePoints.push_back(MIN(1.0,0.7-br/300.0)); //shoulder point
brightcurvePoints.push_back(0.7); //value at shoulder point
}
brightcurvePoints.push_back(1); // white point
brightcurvePoints.push_back(1); // value at white point
brightcurvePoints.push_back(1.); // white point
brightcurvePoints.push_back(1.); // value at white point
DiagonalCurve* brightcurve = new DiagonalCurve (brightcurvePoints, CURVES_MIN_POLY_POINTS/skip); // Actually, CURVES_MIN_POLY_POINTS = 1000,
brightcurve = new DiagonalCurve (brightcurvePoints, CURVES_MIN_POLY_POINTS/skip);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
float exp_scale = a;
@@ -311,17 +356,23 @@ namespace rtengine {
val = gamma (val, gamma_, start, slope, mul, add);
// apply brightness curve
val = brightcurve->getVal (val);
if (brightcurve)
val = brightcurve->getVal (val); // TODO: getVal(double) is very slow! Optimize with a LUTf
// store result in a temporary array
dcurve[i] = CLIPD(val);
}
if (brightcurve)
delete brightcurve;
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if (needcontrast) {
// check if contrast curve is needed
if (contr>0.00001 || contr<-0.00001) {
// compute mean luminance of the image with the curve applied
int sum = 0;
float avg = 0;
@@ -352,23 +403,36 @@ namespace rtengine {
contrastcurvePoints.push_back(1); // white point
contrastcurvePoints.push_back(1); // value at white point
DiagonalCurve* contrastcurve = new DiagonalCurve (contrastcurvePoints, CURVES_MIN_POLY_POINTS/skip); // Actually, CURVES_MIN_POLY_POINTS = 1000,
DiagonalCurve* contrastcurve = new DiagonalCurve (contrastcurvePoints, CURVES_MIN_POLY_POINTS/skip);
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// apply contrast enhancement
for (int i=0; i<=0xffff; i++) {
dcurve[i] = contrastcurve->getVal (dcurve[i]);
}
delete contrastcurve;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// create a curve if needed
bool histNeeded = false;
DiagonalCurve* tcurve = NULL;
if (curvePoints.size()>0 && curvePoints[0]!=0) {
tcurve = new DiagonalCurve (curvePoints, CURVES_MIN_POLY_POINTS/skip);
if (outBeforeCCurveHistogram && histogramCropped)
histNeeded = true;
}
if (tcurve && tcurve->isIdentity()) {
delete tcurve;
tcurve = NULL;
}
for (int i=0; i<=0xffff; i++) {
float val;
// apply custom/parametric/NURBS curve, if any
if (tcurve) {
if (outBeforeCCurveHistogram && histogramCropped) {
if (histNeeded) {
float fi=i;
float hval = dcurve[shCurve[hlCurve[i]*fi]*fi];
//if (needigamma)
@@ -376,7 +440,10 @@ namespace rtengine {
int hi = (int)(255.0*(hval));
outBeforeCCurveHistogram[hi] += histogramCropped[i] ;
}
val = tcurve->getVal (dcurve[i]);
// apply custom/parametric/NURBS curve, if any
if (tcurve) {
val = tcurve->getVal (dcurve[i]); // TODO: getVal(double) is very slow! Optimize with a LUTf
} else {
val = (dcurve[i]);
}
@@ -388,13 +455,12 @@ namespace rtengine {
outCurve[i] = (65535.0 * val);
}
if (tcurve)
delete tcurve;
delete brightcurve;
/*if (outBeforeCCurveHistogram) {
for (int i=0; i<256; i++) printf("i= %d bchist= %d \n",i,outBeforeCCurveHistogram[i]);
}*/
}
@@ -409,15 +475,6 @@ namespace rtengine {
// curve without contrast
LUTf dcurve(65536,0);
// check if contrast curve is needed
bool needcontrast = contr>0.00001 || contr<-0.00001;
// create a curve if needed
DiagonalCurve* tcurve = NULL;
if (curvePoints.size()>0 && curvePoints[0]!=0)
tcurve = new DiagonalCurve (curvePoints, CURVES_MIN_POLY_POINTS/skip);
// clear array that stores histogram valid before applying the custom curve
if (outBeforeCCurveHistogram)
outBeforeCCurveHistogram.clear();
@@ -426,11 +483,14 @@ namespace rtengine {
// tone curve base. a: slope (from exp.comp.), b: black, def_mul: max. x value (can be>1), hr,sr: highlight,shadow recovery
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// check if brightness curve is needed
if (br>0.00001 || br<-0.00001) {
std::vector<double> brightcurvePoints;
brightcurvePoints.push_back((double)((CurveType)DCT_NURBS));
brightcurvePoints.push_back(0); // black point. Value in [0 ; 1] range
brightcurvePoints.push_back(0); // black point. Value in [0 ; 1] range
brightcurvePoints.push_back(0.); // black point. Value in [0 ; 1] range
brightcurvePoints.push_back(0.); // black point. Value in [0 ; 1] range
if (br>0) {
brightcurvePoints.push_back(0.1); // toe point
@@ -445,12 +505,13 @@ namespace rtengine {
brightcurvePoints.push_back(MIN(1.0,0.7-br/300.0)); // shoulder point
brightcurvePoints.push_back(0.7); // value at shoulder point
}
brightcurvePoints.push_back(1); // white point
brightcurvePoints.push_back(1); // value at white point
brightcurvePoints.push_back(1.); // white point
brightcurvePoints.push_back(1.); // value at white point
DiagonalCurve* brightcurve = new DiagonalCurve (brightcurvePoints, CURVES_MIN_POLY_POINTS/skip); // Actually, CURVES_MIN_POLY_POINTS = 1000,
DiagonalCurve* brightcurve = new DiagonalCurve (brightcurvePoints, CURVES_MIN_POLY_POINTS/skip);
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Applying brightness curve
for (int i=0; i<32768; i++) { // L values range up to 32767, higher values are for highlight overflow
// change to [0,1] range
@@ -462,12 +523,22 @@ namespace rtengine {
// store result in a temporary array
dcurve[i] = CLIPD(val);
}
delete brightcurve;
}
else {
for (int i=0; i<32768; i++) { // L values range up to 32767, higher values are for highlight overflow
// set the identity curve in the temporary array
dcurve[i] = (float)i / 32767.0;
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if (needcontrast) {
// check if contrast curve is needed
if (contr>0.00001 || contr<-0.00001) {
// compute mean luminance of the image with the curve applied
int sum = 0;
float avg = 0;
@@ -485,8 +556,8 @@ namespace rtengine {
std::vector<double> contrastcurvePoints;
contrastcurvePoints.push_back((double)((CurveType)DCT_NURBS));
contrastcurvePoints.push_back(0); // black point. Value in [0 ; 1] range
contrastcurvePoints.push_back(0); // black point. Value in [0 ; 1] range
contrastcurvePoints.push_back(0.); // black point. Value in [0 ; 1] range
contrastcurvePoints.push_back(0.); // black point. Value in [0 ; 1] range
contrastcurvePoints.push_back(avg-avg*(0.6-contr/250.0)); // toe point
contrastcurvePoints.push_back(avg-avg*(0.6+contr/250.0)); // value at toe point
@@ -494,10 +565,10 @@ namespace rtengine {
contrastcurvePoints.push_back(avg+(1-avg)*(0.6-contr/250.0)); // shoulder point
contrastcurvePoints.push_back(avg+(1-avg)*(0.6+contr/250.0)); // value at shoulder point
contrastcurvePoints.push_back(1); // white point
contrastcurvePoints.push_back(1); // value at white point
contrastcurvePoints.push_back(1.); // white point
contrastcurvePoints.push_back(1.); // value at white point
DiagonalCurve* contrastcurve = new DiagonalCurve (contrastcurvePoints, CURVES_MIN_POLY_POINTS/skip); // Actually, CURVES_MIN_POLY_POINTS = 1000,
DiagonalCurve* contrastcurve = new DiagonalCurve (contrastcurvePoints, CURVES_MIN_POLY_POINTS/skip);
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// apply contrast enhancement
@@ -509,32 +580,57 @@ namespace rtengine {
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for (int i=0; i<32768; i++) { // L values go up to 32767, last stop is for highlight overflow
// create a curve if needed
DiagonalCurve* tcurve = NULL;
bool histNeeded = false;
if (curvePoints.size()>0 && curvePoints[0]!=0) {
tcurve = new DiagonalCurve (curvePoints, CURVES_MIN_POLY_POINTS/skip);
if (outBeforeCCurveHistogram && histogramCropped)
histNeeded = true;
}
if (tcurve && tcurve->isIdentity()) {
delete tcurve;
tcurve = NULL;
}
if (tcurve) {
// L values go up to 32767, last stop is for highlight overflow
for (int i=0; i<32768; i++) {
float val;
// apply custom/parametric/NURBS curve, if any
if (tcurve) {
if (outBeforeCCurveHistogram) {
if (histNeeded) {
float hval = dcurve[i];
int hi = (int)(255.0*CLIPD(hval));
outBeforeCCurveHistogram[hi]+=histogramCropped[i] ;
}
// apply custom/parametric/NURBS curve, if any
val = tcurve->getVal (dcurve[i]);
} else {
val = (dcurve[i]);
}
outCurve[i] = (32767.0 * val);
}
for (int i=32768; i<65536; i++) outCurve[i]=i;
}
else {
// Skip the slow getval method if no curve is used (or an identity curve)
// L values go up to 32767, last stop is for highlight overflow
for (int i=0; i<32768; i++) {
if (histNeeded) {
float hval = dcurve[i];
int hi = (int)(255.0*CLIPD(hval));
outBeforeCCurveHistogram[hi]+=histogramCropped[i] ;
}
outCurve[i] = 32767.0*dcurve[i];
}
}
for (int i=32768; i<65536; i++) outCurve[i]=(float)i;
if (tcurve)
delete tcurve;
delete brightcurve;
/*if (outBeforeCCurveHistogram) {
for (int i=0; i<256; i++) printf("i= %d bchist= %d \n",i,outBeforeCCurveHistogram[i]);
}*/
}

View File

@@ -35,7 +35,6 @@
#define CLIPI(a) ((a)>0?((a)<65534?(a):65534):0)
namespace rtengine {
class CurveFactory {
@@ -211,6 +210,9 @@ class Curve {
double* y;
std::vector<double> poly_x; // X points of the faceted curve
std::vector<double> poly_y; // Y points of the faceted curve
unsigned short int* hash;
unsigned int hashSize; // hash table's size, between [10, 100, 1000]
double* ypp;
// Fields for the elementary curve polygonisation
@@ -225,12 +227,16 @@ class Curve {
static inline double p10 (double x, double prot) { return x<=0.5 ? CurveFactory::cupper (x*2, 2.0, prot)/2.0 : 0.5 + CurveFactory::clower ((x-0.5)*2, 2.0, prot)/2.0; }
static inline double pfull (double x, double prot, double sh, double hl) { return (1-sh)*(1-hl)*p00(x,prot) + sh*hl*p11(x,prot) + (1-sh)*hl*p01(x,prot) + sh*(1-hl)*p10(x,prot); }
void fillHash();
public:
Curve ();
~Curve ();
void AddPolygons ();
virtual double getVal (double t) = 0;
virtual void getVal (const std::vector<double>& t, std::vector<double>& res) = 0;
virtual bool isIdentity () = 0;
};
class DiagonalCurve : public Curve {
@@ -238,6 +244,10 @@ class DiagonalCurve : public Curve {
protected:
DiagonalCurveType kind;
unsigned int minSearch; // a effacer!!!
unsigned int maxSearch; // a effacer!!!
unsigned int searchArray[21]; // a effacer!!!
void spline_cubic_set ();
void NURBS_set ();
@@ -247,6 +257,7 @@ class DiagonalCurve : public Curve {
double getVal (double t);
void getVal (const std::vector<double>& t, std::vector<double>& res);
bool isIdentity () { return kind==DCT_Empty; };
};
class FlatCurve : public Curve {
@@ -266,6 +277,7 @@ class FlatCurve : public Curve {
double getVal (double t);
void getVal (const std::vector<double>& t, std::vector<double>& res);
bool isIdentity () { return kind==FCT_Empty; };
};
}

View File

@@ -31,6 +31,10 @@ namespace rtengine {
DiagonalCurve::DiagonalCurve (const std::vector<double>& p, int poly_pn) {
ppn = poly_pn;
bool identity = true;
if (ppn < 500) hashSize = 100; // Arbitrary cut-off value
if (ppn < 50) hashSize = 10; // Arbitrary cut-off value
if (p.size()<3) {
kind = DCT_Empty;
@@ -45,17 +49,28 @@ DiagonalCurve::DiagonalCurve (const std::vector<double>& p, int poly_pn) {
for (int i=0; i<N; i++) {
x[i] = p[ix++];
y[i] = p[ix++];
if (x[i] != y[i])
identity = false;
}
if (kind==DCT_Spline)
if (x[0] != 0.0f || x[N-1] != 1.0f)
// Special (and very rare) case where all points are on the identity line but
// not reaching the limits
identity = false;
if (!identity) {
if (kind==DCT_Spline && N > 2)
spline_cubic_set ();
else if (kind==DCT_NURBS && N > 2)
else if (kind==DCT_NURBS && N > 2) {
NURBS_set ();
fillHash();
}
else kind=DCT_Linear;
}
}
else if (kind==DCT_Parametric) {
if (p.size()!=8 && p.size()!=9)
kind = DCT_Empty;
else {
if ((p.size()==8 || p.size()==9) && (p.at(4)!=0.0f || p.at(5)!=0.0f || p.at(6)!=0.0f || p.at(7)!=0.0f)) {
identity = false;
x = new double[9];
for (int i=0; i<4; i++)
x[i] = p[i];
@@ -67,6 +82,9 @@ DiagonalCurve::DiagonalCurve (const std::vector<double>& p, int poly_pn) {
x[8] = p[8]/100.0;
}
}
if (identity) {
kind = DCT_Empty;
}
}
}
@@ -82,7 +100,7 @@ DiagonalCurve::~DiagonalCurve () {
void DiagonalCurve::spline_cubic_set () {
double* u = new double[N-1];
delete [] ypp;
delete [] ypp; // TODO: why do we delete ypp here since it should not be allocated yet?
ypp = new double [N];
ypp[0] = u[0] = 0.0; /* set lower boundary condition to "natural" */
@@ -113,7 +131,7 @@ void DiagonalCurve::NURBS_set () {
double total_length=0.;
// Create the list of Bezier sub-curves
// NURBS_set is called if N > 2 only
// NURBS_set is called if N > 2 and non identity only
int j = 0;
int k = 0;
@@ -165,13 +183,21 @@ void DiagonalCurve::NURBS_set () {
poly_y.clear();
unsigned int sc_xsize=j-1;
j = 0;
// adding the initial horizontal segment, if any
if (x[0] > 0.) {
poly_x.push_back(0.);
poly_y.push_back(y[0]);
}
// adding the initial horizontal segment, if any
// create the polyline with the number of points adapted to the X range of the sub-curve
for (unsigned int i=0; i < sc_xsize /*sc_x.size()*/; i+=3) {
// TODO: Speeding-up the interface by caching the polyline, instead of rebuilding it at each action on sliders !!!
nbr_points = (int)(((double)(ppn+N-2) * sc_length[i/3] )/ total_length);
if (nbr_points<0){
for(int it=0;it < sc_x.size(); it+=3) printf("sc_length[%d/3]=%f \n",it,sc_length[it/3]);
printf("NURBS: error detected!\n i=%d nbr_points=%d ppn=%d N=%d sc_length[i/3]=%f total_length=%f",i,nbr_points,ppn,N,sc_length[i/3],total_length);
printf("NURBS diagonal curve: error detected!\n i=%d nbr_points=%d ppn=%d N=%d sc_length[i/3]=%f total_length=%f",i,nbr_points,ppn,N,sc_length[i/3],total_length);
exit(0);
}
// increment along the curve, not along the X axis
@@ -182,16 +208,16 @@ void DiagonalCurve::NURBS_set () {
firstPointIncluded = !i;
AddPolygons ();
}
// adding the final horizontal segment, always (see under)
poly_x.push_back(1.1); // 1.1 is a hack for optimization purpose of the getVal method (the last value has to be beyond the normal range)
poly_y.push_back(y[N-1]);
}
double DiagonalCurve::getVal (double t) {
switch (kind) {
case DCT_Empty :
return t;
break;
case DCT_Parametric : {
if (t<=1e-14)
return 0.0;
@@ -252,28 +278,38 @@ double DiagonalCurve::getVal (double t) {
break;
}
case DCT_NURBS : {
// values under and over the first and last point
if (t>x[N-1])
return y[N-1];
else if (t<x[0])
return y[0];
else if (N == 2)
return y[0] + (t - x[0]) * ( y[1] - y[0] ) / (x[1] - x[0]);
// get the hash table entry by rounding the value (previously multiplied by "hashSize")
unsigned short int i = (unsigned short int)(t*hashSize);
// do a binary search for the right interval:
int k_lo = 0, k_hi = poly_x.size() - 1;
if (i > (hashSize+1)) {
//printf("\nOVERFLOW: hash #%d is used while seeking for value %.8f, corresponding polygon's point #%d (out of %d point) x value: %.8f\n\n", i, t, hash[i], poly_x.size(), poly_x[hash[i]]);
printf("\nOVERFLOW: hash #%d is used while seeking for value %.8f\n\n", i, t);
return t;
}
unsigned int k_lo = 0;
unsigned int k_hi = 0;
k_lo = hash[i];
k_hi = hash[i+1];
// do a binary search for the right interval :
while (k_hi - k_lo > 1){
int k = (k_hi + k_lo) / 2;
unsigned int k = (k_hi + k_lo) / 2;
if (poly_x[k] > t)
k_hi = k;
else
k_lo = k;
}
if (k_lo == k_hi)
k_hi = k_lo+1;
double h = poly_x[k_hi] - poly_x[k_lo];
return poly_y[k_lo] + (t - poly_x[k_lo]) * ( poly_y[k_hi] - poly_y[k_lo] ) / h;
double dx = poly_x[k_hi] - poly_x[k_lo];
double dy = poly_y[k_hi] - poly_y[k_lo];
return poly_y[k_lo] + (t - poly_x[k_lo]) * ( dy ) / dx;
break;
}
case DCT_Empty :
default:
// all other (unknown) kind
return t;
@@ -282,8 +318,6 @@ double DiagonalCurve::getVal (double t) {
void DiagonalCurve::getVal (const std::vector<double>& t, std::vector<double>& res) {
// TODO!!!! can be made much faster!!! Binary search of getVal(double) at each point can be avoided
res.resize (t.size());
for (unsigned int i=0; i<t.size(); i++)
res[i] = getVal(t[i]);

View File

@@ -38,6 +38,8 @@ FlatCurve::FlatCurve (const std::vector<double>& p, bool isPeriodic, int poly_pn
kind = FCT_Empty;
periodic = isPeriodic;
bool identity = true;
if (p.size()>4) {
kind = (FlatCurveType)p[0];
if (kind==FCT_MinMaxCPoints) {
@@ -53,6 +55,8 @@ FlatCurve::FlatCurve (const std::vector<double>& p, bool isPeriodic, int poly_pn
y[i] = p[ix++];
leftTangent[i] = p[ix++];
rightTangent[i] = p[ix++];
if (y[i] != 0.5f)
identity = false;
}
// The first point is copied to the end of the point list, to handle the curve periodicity
if (periodic) {
@@ -64,11 +68,15 @@ FlatCurve::FlatCurve (const std::vector<double>& p, bool isPeriodic, int poly_pn
else {
N--;
}
if (N > 0+(periodic?1:0) )
if (!identity && N > 0+(periodic?1:0) ) {
CtrlPoints_set ();
fillHash();
}
}
/*else if (kind==FCT_Parametric) {
}*/
if (identity)
kind = FCT_Empty;
}
}
@@ -312,8 +320,6 @@ double FlatCurve::getVal (double t) {
return y[N-1];
else if (t<x[0])
return y[0];
else if (N == 2)
return y[0] + (t - x[0]) * ( y[1] - y[0] ) / (x[1] - x[0]);
*/
// magic to handle curve periodicity : we look above the 1.0 bound for the value
@@ -337,16 +343,14 @@ double FlatCurve::getVal (double t) {
break;
}*/
case FCT_Empty :
case FCT_Linear :
case FCT_Linear : // Linear doesn't exist yet and is then considered as identity
default:
return t;
return 0.5;
}
}
void FlatCurve::getVal (const std::vector<double>& t, std::vector<double>& res) {
// TODO!!!! can be made much faster!!! Binary search of getVal(double) at each point can be avoided
res.resize (t.size());
for (unsigned int i=0; i<t.size(); i++)
res[i] = getVal(t[i]);

View File

@@ -29,7 +29,7 @@
// For compatibility and simplicity reason, order shouldn't change, and must be identical to the order specified in the curveType widget
enum DiagonalCurveType {
DCT_Empty = -1,
DCT_Empty = -1, // Also used for identity curves
DCT_Linear, // 0
DCT_Spline, // 1
DCT_Parametric, // 2

View File

@@ -27,7 +27,7 @@
// For compatibility and simplicity reason, order shouldn't change, and must be identical to the order specified in the curveType widget
enum FlatCurveType {
FCT_Empty = -1,
FCT_Empty = -1, // Also used for identity curves
FCT_Linear, // 0
FCT_MinMaxCPoints, // 1
//FCT_Parametric, // 2