curves: restored the old DCT_Spline implementation (cubic splines), and added new DCT_CatumullRom curve type

This commit is contained in:
Alberto Griggio 2018-12-06 14:11:49 +01:00
parent 1bf837d5b1
commit fd48b34cd5
10 changed files with 138 additions and 80 deletions

View File

@ -17,9 +17,10 @@ CURVEEDITOR_AXIS_IN;I:
CURVEEDITOR_AXIS_LEFT_TAN;LT:
CURVEEDITOR_AXIS_OUT;O:
CURVEEDITOR_AXIS_RIGHT_TAN;RT:
CURVEEDITOR_CATMULLROM;Flexible
CURVEEDITOR_CURVE;Curve
CURVEEDITOR_CURVES;Curves
CURVEEDITOR_CUSTOM;Custom
CURVEEDITOR_CUSTOM;Standard
CURVEEDITOR_DARKS;Darks
CURVEEDITOR_EDITPOINT_HINT;Enable edition of node in/out values.\n\nRight-click on a node to select it.\nRight-click on empty space to de-select the node.
CURVEEDITOR_HIGHLIGHTS;Highlights

View File

@ -48,7 +48,7 @@ DiagonalCurve::DiagonalCurve (const std::vector<double>& p, int poly_pn)
bool identity = true;
kind = (DiagonalCurveType)p[0];
if (kind == DCT_Linear || kind == DCT_Spline || kind == DCT_NURBS) {
if (kind == DCT_Linear || kind == DCT_Spline || kind == DCT_NURBS || kind == DCT_CatumullRom) {
N = (p.size() - 1) / 2;
x = new double[N];
y = new double[N];
@ -86,11 +86,12 @@ DiagonalCurve::DiagonalCurve (const std::vector<double>& p, int poly_pn)
if (!identity) {
if (kind == DCT_Spline && N > 2) {
//spline_cubic_set ();
catmull_rom_set();
spline_cubic_set ();
} else if (kind == DCT_NURBS && N > 2) {
NURBS_set ();
fillHash();
} else if (kind == DCT_CatumullRom && N > 2) {
catmull_rom_set();
} else {
kind = DCT_Linear;
}
@ -459,7 +460,7 @@ double DiagonalCurve::getVal (double t) const
}
case DCT_Linear :
// case DCT_Spline :
case DCT_Spline :
{
// values under and over the first and last point
if (t > x[N - 1]) {
@ -484,21 +485,21 @@ double DiagonalCurve::getVal (double t) const
double h = x[k_hi] - x[k_lo];
// linear
// if (kind == DCT_Linear) {
if (kind == DCT_Linear) {
return y[k_lo] + (t - x[k_lo]) * ( y[k_hi] - y[k_lo] ) / h;
// }
// // spline curve
// else { // if (kind==Spline) {
// double a = (x[k_hi] - t) / h;
// double b = (t - x[k_lo]) / h;
// double r = a * y[k_lo] + b * y[k_hi] + ((a * a * a - a) * ypp[k_lo] + (b * b * b - b) * ypp[k_hi]) * (h * h) * 0.1666666666666666666666666666666;
// return CLIPD(r);
// }
}
// spline curve
else { // if (kind==Spline) {
double a = (x[k_hi] - t) / h;
double b = (t - x[k_lo]) / h;
double r = a * y[k_lo] + b * y[k_hi] + ((a * a * a - a) * ypp[k_lo] + (b * b * b - b) * ypp[k_hi]) * (h * h) * 0.1666666666666666666666666666666;
return CLIPD(r);
}
break;
}
case DCT_Spline: {
case DCT_CatumullRom: {
auto it = std::lower_bound(poly_x.begin(), poly_x.end(), t);
if (it == poly_x.end()) {
return poly_y.back();

View File

@ -97,55 +97,6 @@ int findMatch(int val, const std::vector<int> &cdf, int j)
}
class CubicSplineCurve: public DiagonalCurve {
public:
CubicSplineCurve(const std::vector<double> &points):
DiagonalCurve({DCT_Linear})
{
N = points.size() / 2;
x = new double[N];
y = new double[N];
for (int i = 0; i < N; ++i) {
x[i] = points[2*i];
y[i] = points[2*i+1];
}
kind = DCT_Spline;
spline_cubic_set();
}
double getVal(double t) const override
{
// 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];
}
// do a binary search for the right interval:
unsigned int k_lo = 0, k_hi = N - 1;
while (k_hi > 1 + k_lo) {
unsigned int k = (k_hi + k_lo) / 2;
if (x[k] > t) {
k_hi = k;
} else {
k_lo = k;
}
}
double h = x[k_hi] - x[k_lo];
double a = (x[k_hi] - t) / h;
double b = (t - x[k_lo]) / h;
double r = a * y[k_lo] + b * y[k_hi] + ((a * a * a - a) * ypp[k_lo] + (b * b * b - b) * ypp[k_hi]) * (h * h) * 0.1666666666666666666666666666666;
return LIM01(r);
}
};
void mappingToCurve(const std::vector<int> &mapping, std::vector<double> &curve)
{
curve.clear();
@ -259,10 +210,11 @@ void mappingToCurve(const std::vector<int> &mapping, std::vector<double> &curve)
if (curve.size() < 4) {
curve = { DCT_Linear }; // not enough points, fall back to linear
} else {
CubicSplineCurve c(curve);
curve.insert(curve.begin(), DCT_Spline);
DiagonalCurve c(curve);
double gap = 0.05;
double x = 0.0;
curve = { DCT_Spline };
curve = { DCT_CatumullRom };
while (x < 1.0) {
curve.push_back(x);
curve.push_back(c.getVal(x));

View File

@ -25,6 +25,47 @@
#include <cstring>
namespace {
class CurveTypePopUpButton: public PopUpToggleButton {
public:
CurveTypePopUpButton(const Glib::ustring &label=""):
PopUpToggleButton(label) {}
void setPosIndexMap(const std::vector<int> &pmap)
{
posidxmap_ = pmap;
}
protected:
int posToIndex(int pos) const override
{
if (pos < 0 || size_t(pos) >= posidxmap_.size()) {
return pos;
}
return posidxmap_[pos];
}
int indexToPos(int index) const override
{
if (index < 0 || size_t(index) >= posidxmap_.size()) {
return index;
}
for (int i = 0, n = int(posidxmap_.size()); i < n; ++i) {
if (posidxmap_[i] == index) {
return i;
}
}
return -1;
}
private:
std::vector<int> posidxmap_;
};
} // namespace
bool CurveEditor::reset()
{
return subGroup->curveReset(this);
@ -33,12 +74,14 @@ bool CurveEditor::reset()
DiagonalCurveEditor::DiagonalCurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEditorSubGroup* ceSubGroup) : CurveEditor::CurveEditor(text, static_cast<CurveEditorGroup*>(ceGroup), ceSubGroup)
{
// Order set in the same order than "enum DiagonalCurveType". Shouldn't change, for compatibility reason
curveType->addEntry("curve-linear-small.png", M("CURVEEDITOR_LINEAR")); // 0 Linear
curveType->addEntry("curve-spline-small.png", M("CURVEEDITOR_CUSTOM")); // 1 Spline
curveType->addEntry("curve-catmullrom-small.png", M("CURVEEDITOR_CATMULLROM")); // 4 CatmullRom
curveType->addEntry("curve-parametric-small.png", M("CURVEEDITOR_PARAMETRIC")); // 2 Parametric
curveType->addEntry("curve-nurbs-small.png", M("CURVEEDITOR_NURBS")); // 3 NURBS
static_cast<CurveTypePopUpButton *>(curveType)->setPosIndexMap({ 0, 1, 4, 2, 3 });
curveType->setSelected(DCT_Linear);
curveType->show();
rangeLabels[0] = M("CURVEEDITOR_SHADOWS");
@ -65,6 +108,9 @@ std::vector<double> DiagonalCurveEditor::getCurve ()
case (DCT_NURBS):
return curve = NURBSCurveEd;
case (DCT_CatumullRom):
return curve = catmullRomCurveEd;
default:
// returning Linear or Unchanged
curve.push_back((double)(selected));
@ -96,6 +142,13 @@ void DiagonalCurveEditor::setResetCurve(DiagonalCurveType cType, const std::vect
break;
case (DCT_CatumullRom):
if (resetCurve.size() && DiagonalCurveType(resetCurve.at(0)) == cType) {
catmullRomResetCurve = resetCurve;
}
break;
default:
break;
}
@ -209,9 +262,9 @@ CurveEditor::CurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEd
subGroup = ceSubGroup;
if (group && text.size()) {
curveType = new PopUpToggleButton(text + ":");
curveType = new CurveTypePopUpButton(text + ":");
} else {
curveType = new PopUpToggleButton();
curveType = new CurveTypePopUpButton();
}
curveType->set_tooltip_text(M("CURVEEDITOR_TYPE"));

View File

@ -156,6 +156,8 @@ protected:
std::vector<double> paramResetCurve;
std::vector<double> NURBSCurveEd;
std::vector<double> NURBSResetCurve;
std::vector<double> catmullRomCurveEd;
std::vector<double> catmullRomResetCurve;
Glib::ustring rangeLabels[4];
double rangeMilestones[3];

View File

@ -393,6 +393,7 @@ DiagonalCurveEditor* DiagonalCurveEditorSubGroup::addCurve(Glib::ustring curveLa
storeCurveValues(newCE, getCurveFromGUI(DCT_Spline));
storeCurveValues(newCE, getCurveFromGUI(DCT_Parametric));
storeCurveValues(newCE, getCurveFromGUI(DCT_NURBS));
storeCurveValues(newCE, getCurveFromGUI(DCT_CatumullRom));
return newCE;
}
@ -437,6 +438,7 @@ void DiagonalCurveEditorSubGroup::pipetteMouseOver(EditDataProvider *provider, i
switch((DiagonalCurveType)(curveEditor->curveType->getSelected())) {
case (DCT_Spline):
case (DCT_CatumullRom):
customCurve->pipetteMouseOver(curveEditor, provider, modifierKey);
customCurve->setDirty(true);
break;
@ -511,6 +513,7 @@ bool DiagonalCurveEditorSubGroup::pipetteButton1Pressed(EditDataProvider *provid
switch((DiagonalCurveType)(curveEditor->curveType->getSelected())) {
case (DCT_Spline):
case (DCT_CatumullRom):
isDragging = customCurve->pipetteButton1Pressed(provider, modifierKey);
break;
@ -539,6 +542,7 @@ void DiagonalCurveEditorSubGroup::pipetteButton1Released(EditDataProvider *provi
switch((DiagonalCurveType)(curveEditor->curveType->getSelected())) {
case (DCT_Spline):
case (DCT_CatumullRom):
customCurve->pipetteButton1Released(provider);
break;
@ -562,6 +566,7 @@ void DiagonalCurveEditorSubGroup::pipetteDrag(EditDataProvider *provider, int mo
switch((DiagonalCurveType)(curveEditor->curveType->getSelected())) {
case (DCT_Spline):
case (DCT_CatumullRom):
customCurve->pipetteDrag(provider, modifierKey);
break;
@ -615,6 +620,7 @@ void DiagonalCurveEditorSubGroup::refresh(CurveEditor *curveToRefresh)
if (curveToRefresh != nullptr && curveToRefresh == static_cast<DiagonalCurveEditor*>(parent->displayedCurve)) {
switch((DiagonalCurveType)(curveToRefresh->curveType->getSelected())) {
case (DCT_Spline):
case (DCT_CatumullRom):
customCurve->refresh();
break;
@ -703,9 +709,10 @@ void DiagonalCurveEditorSubGroup::switchGUI()
}
}
switch((DiagonalCurveType)(dCurve->curveType->getSelected())) {
switch(auto tp = (DiagonalCurveType)(dCurve->curveType->getSelected())) {
case (DCT_Spline):
customCurve->setPoints (dCurve->customCurveEd);
case (DCT_CatumullRom):
customCurve->setPoints(tp == DCT_Spline ? dCurve->customCurveEd : dCurve->catmullRomCurveEd);
customCurve->setColorProvider(dCurve->getCurveColorProvider(), dCurve->getCurveCallerId());
customCurve->setColoredBar(leftBar, bottomBar);
customCurve->queue_resize_no_redraw();
@ -776,6 +783,7 @@ void DiagonalCurveEditorSubGroup::savePressed ()
switch (parent->displayedCurve->selected) {
case DCT_Spline: // custom
case DCT_CatumullRom:
p = customCurve->getPoints ();
break;
@ -797,6 +805,8 @@ void DiagonalCurveEditorSubGroup::savePressed ()
f << "Linear" << std::endl;
} else if (p[ix] == (double)(DCT_Spline)) {
f << "Spline" << std::endl;
} else if (p[ix] == (double)(DCT_CatumullRom)) {
f << "CatmullRom" << std::endl;
} else if (p[ix] == (double)(DCT_NURBS)) {
f << "NURBS" << std::endl;
} else if (p[ix] == (double)(DCT_Parametric)) {
@ -838,6 +848,8 @@ void DiagonalCurveEditorSubGroup::loadPressed ()
p.push_back ((double)(DCT_Linear));
} else if (s == "Spline") {
p.push_back ((double)(DCT_Spline));
} else if (s == "CatmullRom") {
p.push_back ((double)(DCT_CatumullRom));
} else if (s == "NURBS") {
p.push_back ((double)(DCT_NURBS));
} else if (s == "Parametric") {
@ -858,7 +870,7 @@ void DiagonalCurveEditorSubGroup::loadPressed ()
rtengine::sanitizeCurve(p);
if (p[0] == (double)(DCT_Spline)) {
if (p[0] == (double)(DCT_Spline) || p[0] == (double)(DCT_CatumullRom)) {
customCurve->setPoints (p);
customCurve->queue_draw ();
customCurve->notifyListener ();
@ -903,6 +915,12 @@ void DiagonalCurveEditorSubGroup::copyPressed ()
clipboard.setDiagonalCurveData (curve, DCT_NURBS);
break;
case DCT_CatumullRom:
curve = customCurve->getPoints ();
curve[0] = DCT_CatumullRom;
clipboard.setDiagonalCurveData (curve, DCT_CatumullRom);
break;
default: // (DCT_Linear, DCT_Unchanged)
// ... do nothing
break;
@ -923,6 +941,7 @@ void DiagonalCurveEditorSubGroup::pastePressed ()
switch (type) {
case DCT_Spline: // custom
case DCT_CatumullRom:
customCurve->setPoints (curve);
customCurve->queue_draw ();
customCurve->notifyListener ();
@ -1060,6 +1079,10 @@ void DiagonalCurveEditorSubGroup::storeDisplayedCurve()
storeCurveValues(parent->displayedCurve, getCurveFromGUI(DCT_NURBS));
break;
case (DCT_CatumullRom):
storeCurveValues(parent->displayedCurve, getCurveFromGUI(DCT_CatumullRom));
break;
default:
break;
}
@ -1097,6 +1120,10 @@ void DiagonalCurveEditorSubGroup::storeCurveValues (CurveEditor* ce, const std::
(static_cast<DiagonalCurveEditor*>(ce))->NURBSCurveEd = p;
break;
case (DCT_CatumullRom):
(static_cast<DiagonalCurveEditor*>(ce))->catmullRomCurveEd = p;
break;
default:
break;
}
@ -1126,6 +1153,14 @@ const std::vector<double> DiagonalCurveEditorSubGroup::getCurveFromGUI (int type
case (DCT_NURBS):
return NURBSCurve->getPoints ();
case (DCT_CatumullRom): {
auto ret = customCurve->getPoints();
if (!ret.empty()) {
ret[0] = DCT_CatumullRom;
}
return ret;
}
default: {
// linear and other solutions
std::vector<double> lcurve (1);
@ -1162,6 +1197,10 @@ bool DiagonalCurveEditorSubGroup::curveReset(CurveEditor *ce)
customCurve->reset (dce->customResetCurve, dce->getIdentityValue());
return true;
case (DCT_CatumullRom) :
customCurve->reset (dce->catmullRomResetCurve, dce->getIdentityValue());
return true;
case (DCT_Parametric) : {
DiagonalCurveEditor* dCurve = static_cast<DiagonalCurveEditor*>(parent->displayedCurve);
double mileStone[3];

View File

@ -775,7 +775,7 @@ bool MyDiagonalCurve::handleEvents (GdkEvent* event)
case GDK_MOTION_NOTIFY:
snapToElmt = -100;
if (curve.type == DCT_Linear || curve.type == DCT_Spline || curve.type == DCT_NURBS) {
if (curve.type == DCT_Linear || curve.type == DCT_Spline || curve.type == DCT_NURBS || curve.type == DCT_CatumullRom) {
snapToMinDistY = snapToMinDistX = 10.;
snapToValY = snapToValX = 0.;
@ -1026,7 +1026,7 @@ void MyDiagonalCurve::pipetteMouseOver (CurveEditor *ce, EditDataProvider *provi
double minDistanceX = double(MIN_DISTANCE) / double(graphW - 1);
if (curve.type == DCT_Linear || curve.type == DCT_Spline || curve.type == DCT_NURBS) {
if (curve.type == DCT_Linear || curve.type == DCT_Spline || curve.type == DCT_NURBS || curve.type == DCT_CatumullRom) {
// get the pointer position
getCursorPositionFromCurve(pipetteVal);
@ -1415,6 +1415,8 @@ std::vector<double> MyDiagonalCurve::getPoints ()
result.push_back (double(DCT_Spline));
} else if (curve.type == DCT_NURBS) {
result.push_back (double(DCT_NURBS));
} else if (curve.type == DCT_CatumullRom) {
result.push_back (double(DCT_CatumullRom));
}
// then we push all the points coordinate
@ -1552,6 +1554,7 @@ void MyDiagonalCurve::reset(const std::vector<double> &resetCurve, double identi
switch (curve.type) {
case DCT_Spline :
case DCT_NURBS :
case DCT_CatumullRom:
curve.x.resize(2);
curve.y.resize(2);
curve.x.at(0) = 0.;

View File

@ -34,6 +34,7 @@ enum DiagonalCurveType {
DCT_Spline, // 1
DCT_Parametric, // 2
DCT_NURBS, // 3
DCT_CatumullRom, // 4
// Insert new curve type above this line
DCT_Unchanged // Must remain the last of the enum
};

View File

@ -103,17 +103,18 @@ bool PopUpCommon::addEntry (const Glib::ustring& fileName, const Glib::ustring&
void PopUpCommon::entrySelected (int i)
{
// Emit a signal if the selected item has changed
if (setSelected (i))
messageChanged (selected);
if (setSelected (posToIndex(i)))
messageChanged (posToIndex(selected));
// Emit a signal in all case (i.e. propagate the signal_activate event)
messageItemSelected (selected);
messageItemSelected (posToIndex(selected));
}
void PopUpCommon::setItemSensitivity (int index, bool isSensitive) {
const auto items = menu->get_children ();
if (size_t(index) < items.size ()) {
items[size_t(index)]->set_sensitive (isSensitive);
size_t pos = indexToPos(index);
if (pos < items.size ()) {
items[pos]->set_sensitive (isSensitive);
}
}
@ -123,6 +124,8 @@ void PopUpCommon::setItemSensitivity (int index, bool isSensitive) {
*/
bool PopUpCommon::setSelected (int entryNum)
{
entryNum = indexToPos(entryNum);
if (entryNum < 0 || entryNum > ((int)images.size() - 1) || (int)entryNum == selected) {
return false;
} else {

View File

@ -75,6 +75,9 @@ private:
void showMenu(GdkEventButton* event);
protected:
virtual int posToIndex(int p) const { return p; }
virtual int indexToPos(int i) const { return i; }
void entrySelected (int i);
};
@ -96,7 +99,7 @@ inline int PopUpCommon::getEntryCount () const
inline int PopUpCommon::getSelected () const
{
return selected;
return posToIndex(selected);
}
#endif