Pipette and "On Preview Widgets" branch. See issue 227
The pipette part is already working quite nice but need to be finished. The widgets part needs more work...
This commit is contained in:
380
rtengine/flatcurves.cc
Normal file
380
rtengine/flatcurves.cc
Normal file
@@ -0,0 +1,380 @@
|
||||
/*
|
||||
* This file is part of RawTherapee.
|
||||
*
|
||||
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
|
||||
*
|
||||
* RawTherapee is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* RawTherapee is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <glib.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include "curves.h"
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
#include "mytime.h"
|
||||
#include <cstring>
|
||||
|
||||
#include <gtkmm.h>
|
||||
#include <fstream>
|
||||
|
||||
namespace rtengine {
|
||||
|
||||
FlatCurve::FlatCurve (const std::vector<double>& p, bool isPeriodic, int poly_pn) : kind(FCT_Empty), leftTangent(NULL), rightTangent(NULL), identityValue(0.5), periodic(isPeriodic) {
|
||||
|
||||
ppn = poly_pn > 65500 ? 65500 : poly_pn;
|
||||
poly_x.clear();
|
||||
poly_y.clear();
|
||||
|
||||
bool identity = true;
|
||||
|
||||
if (p.size()>4) {
|
||||
kind = (FlatCurveType)p[0];
|
||||
if (kind==FCT_MinMaxCPoints) {
|
||||
int oneMorePoint = periodic ? 1:0;
|
||||
N = (p.size()-1)/4;
|
||||
x = new double[N+oneMorePoint];
|
||||
y = new double[N+oneMorePoint];
|
||||
leftTangent = new double[N+oneMorePoint];
|
||||
rightTangent = new double[N+oneMorePoint];
|
||||
int ix = 1;
|
||||
for (int i=0; i<N; i++) {
|
||||
x[i] = p[ix++];
|
||||
y[i] = p[ix++];
|
||||
leftTangent[i] = p[ix++];
|
||||
rightTangent[i] = p[ix++];
|
||||
if (y[i] >= identityValue+1.e-7 || y[i] <= identityValue-1.e-7)
|
||||
identity = false;
|
||||
}
|
||||
// The first point is copied to the end of the point list, to handle the curve periodicity
|
||||
if (periodic) {
|
||||
x[N] = p[1]+1.0;
|
||||
y[N] = p[2];
|
||||
leftTangent[N] = p[3];
|
||||
rightTangent[N] = p[4];
|
||||
}
|
||||
else {
|
||||
N--;
|
||||
}
|
||||
if (!identity && N > 0+(periodic?1:0) ) {
|
||||
CtrlPoints_set ();
|
||||
fillHash();
|
||||
}
|
||||
}
|
||||
/*else if (kind==FCT_Parametric) {
|
||||
}*/
|
||||
if (identity)
|
||||
kind = FCT_Empty;
|
||||
}
|
||||
}
|
||||
|
||||
FlatCurve::~FlatCurve () {
|
||||
|
||||
delete [] x;
|
||||
delete [] y;
|
||||
delete [] leftTangent;
|
||||
delete [] rightTangent;
|
||||
delete [] ypp;
|
||||
poly_x.clear();
|
||||
poly_y.clear();
|
||||
}
|
||||
|
||||
/*
|
||||
* The nominal (identity) curve may not be 0.5, use this method to set it to whatever value in the 0.-1. range you want
|
||||
* Return true if the curve is nominal
|
||||
*/
|
||||
bool FlatCurve::setIdentityValue (double iVal) {
|
||||
|
||||
if (identityValue == iVal)
|
||||
return kind==FCT_Empty;
|
||||
|
||||
identityValue = iVal;
|
||||
bool identity = true;
|
||||
for (int i=0; i<N; i++) {
|
||||
if (y[i] >= identityValue+1.e-7 || y[i] <= identityValue-1.e-7) {
|
||||
identity = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (identity)
|
||||
kind = FCT_Empty;
|
||||
else
|
||||
kind = FCT_MinMaxCPoints;
|
||||
|
||||
return kind==FCT_Empty;
|
||||
}
|
||||
|
||||
void FlatCurve::CtrlPoints_set () {
|
||||
|
||||
int nbSubCurvesPoints = N*6;
|
||||
|
||||
std::vector<double> sc_x(nbSubCurvesPoints); // X sub-curve points ( XP0,XP1,XP2, XP2,XP3,XP4, ...)
|
||||
std::vector<double> sc_y(nbSubCurvesPoints); // Y sub-curve points ( YP0,YP1,YP2, YP2,YP3,YP4, ...)
|
||||
std::vector<double> sc_length(N*2); // Length of the subcurves
|
||||
std::vector<bool> sc_isLinear(N*2); // true if the subcurve is linear
|
||||
double total_length=0.;
|
||||
|
||||
// Create the list of Bezier sub-curves
|
||||
// CtrlPoints_set is called if N > 1
|
||||
|
||||
unsigned int j = 0;
|
||||
unsigned int k = 0;
|
||||
|
||||
for (int i = 0; i < N;) {
|
||||
double length;
|
||||
double dx;
|
||||
double dy;
|
||||
double xp1, xp2, yp2, xp3;
|
||||
bool startLinear, endLinear;
|
||||
|
||||
startLinear = (rightTangent[i] == 0.) || (y[i] == y[i+1]);
|
||||
endLinear = (leftTangent [i+1] == 0.) || (y[i] == y[i+1]);
|
||||
|
||||
if (startLinear && endLinear) {
|
||||
// line shape
|
||||
sc_x[j] = x[i];
|
||||
sc_y[j++] = y[i];
|
||||
sc_x[j] = x[i+1];
|
||||
sc_y[j] = y[i+1];
|
||||
sc_isLinear[k] = true;
|
||||
i++;
|
||||
|
||||
dx = sc_x[j] - sc_x[j-1];
|
||||
dy = sc_y[j] - sc_y[j-1];
|
||||
length = sqrt(dx*dx + dy*dy);
|
||||
j++;
|
||||
|
||||
// Storing the length of all sub-curves and the total length (to have a better distribution
|
||||
// of the points along the curve)
|
||||
sc_length[k++] = length;
|
||||
total_length += length;
|
||||
}
|
||||
else {
|
||||
if (startLinear) {
|
||||
xp1 = x[i];
|
||||
}
|
||||
else {
|
||||
//xp1 = (xp4 - xp0) * rightTangent0 + xp0;
|
||||
xp1 = (x[i+1] - x[i]) * rightTangent[i] + x[i];
|
||||
}
|
||||
if (endLinear) {
|
||||
xp3 = x[i+1];
|
||||
}
|
||||
else {
|
||||
//xp3 = (xp0 - xp4]) * leftTangent4 + xp4;
|
||||
xp3 = (x[i] - x[i+1]) * leftTangent[i+1] + x[i+1];
|
||||
}
|
||||
|
||||
xp2 = (xp1 + xp3) / 2.0;
|
||||
yp2 = (y[i] + y[i+1]) / 2.0;
|
||||
|
||||
if (rightTangent[i]+leftTangent[i+1] > 1.0) { // also means that start and end are not linear
|
||||
xp1 = xp3 = xp2;
|
||||
}
|
||||
|
||||
if (startLinear) {
|
||||
// Point 0, 2
|
||||
sc_x[j] = x[i];
|
||||
sc_y[j++] = y[i];
|
||||
sc_x[j] = xp2;
|
||||
sc_y[j] = yp2;
|
||||
sc_isLinear[k] = true;
|
||||
|
||||
dx = sc_x[j] - sc_x[j-1];
|
||||
dy = sc_y[j] - sc_y[j-1];
|
||||
length = sqrt(dx*dx + dy*dy);
|
||||
j++;
|
||||
|
||||
// Storing the length of all sub-curves and the total length (to have a better distribution
|
||||
// of the points along the curve)
|
||||
sc_length[k++] = length;
|
||||
total_length += length;
|
||||
}
|
||||
else {
|
||||
// Point 0, 1, 2
|
||||
sc_x[j] = x[i];
|
||||
sc_y[j++] = y[i];
|
||||
sc_x[j] = xp1;
|
||||
sc_y[j] = y[i];
|
||||
|
||||
dx = sc_x[j] - sc_x[j-1];
|
||||
dy = sc_y[j] - sc_y[j-1];
|
||||
length = sqrt(dx*dx + dy*dy);
|
||||
j++;
|
||||
|
||||
sc_x[j] = xp2;
|
||||
sc_y[j] = yp2;
|
||||
sc_isLinear[k] = false;
|
||||
|
||||
dx = sc_x[j] - sc_x[j-1];
|
||||
dy = sc_y[j] - sc_y[j-1];
|
||||
length += sqrt(dx*dx + dy*dy);
|
||||
j++;
|
||||
|
||||
// Storing the length of all sub-curves and the total length (to have a better distribution
|
||||
// of the points along the curve)
|
||||
sc_length[k++] = length;
|
||||
total_length += length;
|
||||
}
|
||||
if (endLinear) {
|
||||
// Point 2, 4
|
||||
sc_x[j] = xp2;
|
||||
sc_y[j++] = yp2;
|
||||
sc_x[j] = x[i+1];
|
||||
sc_y[j] = y[i+1];
|
||||
sc_isLinear[k] = true;
|
||||
|
||||
dx = sc_x[j] - sc_x[j-1];
|
||||
dy = sc_y[j] - sc_y[j-1];
|
||||
length = sqrt(dx*dx + dy*dy);
|
||||
j++;
|
||||
|
||||
// Storing the length of all sub-curves and the total length (to have a better distribution
|
||||
// of the points along the curve)
|
||||
sc_length[k++] = length;
|
||||
total_length += length;
|
||||
}
|
||||
else {
|
||||
// Point 2, 3, 4
|
||||
sc_x[j] = xp2;
|
||||
sc_y[j++] = yp2;
|
||||
sc_x[j] = xp3;
|
||||
sc_y[j] = y[i+1];
|
||||
|
||||
dx = sc_x[j] - sc_x[j-1];
|
||||
dy = sc_y[j] - sc_y[j-1];
|
||||
length = sqrt(dx*dx + dy*dy);
|
||||
j++;
|
||||
|
||||
sc_x[j] = x[i+1];
|
||||
sc_y[j] = y[i+1];
|
||||
sc_isLinear[k] = false;
|
||||
|
||||
dx = sc_x[j] - sc_x[j-1];
|
||||
dy = sc_y[j] - sc_y[j-1];
|
||||
length += sqrt(dx*dx + dy*dy);
|
||||
j++;
|
||||
|
||||
// Storing the length of all sub-curves and the total length (to have a better distribution
|
||||
// of the points along the curve)
|
||||
sc_length[k++] = length;
|
||||
total_length += length;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
poly_x.clear();
|
||||
poly_y.clear();
|
||||
j = 0;
|
||||
|
||||
// adding an initial horizontal line if necessary
|
||||
if (!periodic && sc_x[j] != 0.) {
|
||||
poly_x.push_back(0.);
|
||||
poly_y.push_back(sc_y[j]);
|
||||
}
|
||||
|
||||
// the first point of the curves
|
||||
poly_x.push_back(sc_x[j]);
|
||||
poly_y.push_back(sc_y[j]);
|
||||
|
||||
firstPointIncluded = false;
|
||||
|
||||
// create the polyline with the number of points adapted to the X range of the sub-curve
|
||||
for (unsigned int i=0; i < k; i++) {
|
||||
if (sc_isLinear[i]) {
|
||||
j++; // skip the first point
|
||||
poly_x.push_back(sc_x[j]);
|
||||
poly_y.push_back(sc_y[j++]);
|
||||
}
|
||||
else {
|
||||
nbr_points = (int)(((double)(ppn) * sc_length[i] )/ total_length);
|
||||
if (nbr_points<0){
|
||||
for(size_t it=0;it < sc_x.size(); it+=3) printf("sc_length[%zd/3]=%f \n",it,sc_length[it/3]);
|
||||
printf("Flat curve: error detected!\n i=%d periodic=%d nbr_points=%d ppn=%d N=%d sc_length[i/3]=%f total_length=%f",i,periodic,nbr_points,ppn,N,sc_length[i/3],total_length);
|
||||
exit(0);
|
||||
}
|
||||
// increment along the curve, not along the X axis
|
||||
increment = 1.0 / (double)(nbr_points-1);
|
||||
x1 = sc_x[j]; y1 = sc_y[j++];
|
||||
x2 = sc_x[j]; y2 = sc_y[j++];
|
||||
x3 = sc_x[j]; y3 = sc_y[j++];
|
||||
AddPolygons ();
|
||||
}
|
||||
}
|
||||
|
||||
// adding the final horizontal segment, always (see under)
|
||||
poly_x.push_back(3.0); // 3.0 is a hack for optimization purpose of the getVal method (the last value has to be beyond the normal range)
|
||||
poly_y.push_back(sc_y[j-1]);
|
||||
|
||||
/*
|
||||
// Checking the values
|
||||
Glib::ustring fname = "Curve.xyz"; // TopSolid'Design "plot" file format
|
||||
std::ofstream f (fname.c_str());
|
||||
f << "$" << std::endl;;
|
||||
for (unsigned int iter = 0; iter < poly_x.size(); iter++) {
|
||||
f << poly_x[iter] << ", " << poly_y[iter] << ", 0." << std::endl;;
|
||||
}
|
||||
f << "$" << std::endl;;
|
||||
f.close ();
|
||||
*/
|
||||
}
|
||||
|
||||
double FlatCurve::getVal (double t) const {
|
||||
|
||||
switch (kind) {
|
||||
|
||||
case FCT_MinMaxCPoints : {
|
||||
/* To be updated if we have to handle non periodic flat curves
|
||||
// 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];
|
||||
*/
|
||||
|
||||
// magic to handle curve periodicity : we look above the 1.0 bound for the value
|
||||
if (t < poly_x[0]) t += 1.0;
|
||||
|
||||
// do a binary search for the right interval:
|
||||
int k_lo = 0, k_hi = poly_x.size() - 1;
|
||||
while (k_hi - k_lo > 1){
|
||||
int k = (k_hi + k_lo) / 2;
|
||||
if (poly_x[k] > t)
|
||||
k_hi = k;
|
||||
else
|
||||
k_lo = k;
|
||||
}
|
||||
|
||||
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 Parametric : {
|
||||
break;
|
||||
}*/
|
||||
case FCT_Empty :
|
||||
case FCT_Linear : // Linear doesn't exist yet and is then considered as identity
|
||||
default:
|
||||
return identityValue;
|
||||
}
|
||||
}
|
||||
|
||||
void FlatCurve::getVal (const std::vector<double>& t, std::vector<double>& res) const {
|
||||
|
||||
res.resize (t.size());
|
||||
for (unsigned int i=0; i<t.size(); i++)
|
||||
res[i] = getVal(t[i]);
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user