diff --git a/rtdata/languages/default b/rtdata/languages/default index da79ec3ac..e53550a0d 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -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 diff --git a/rtengine/diagonalcurves.cc b/rtengine/diagonalcurves.cc index f478ba719..c81d48f16 100644 --- a/rtengine/diagonalcurves.cc +++ b/rtengine/diagonalcurves.cc @@ -48,7 +48,7 @@ DiagonalCurve::DiagonalCurve (const std::vector& 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& 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(); diff --git a/rtengine/histmatching.cc b/rtengine/histmatching.cc index da95946e7..1b6dd133f 100644 --- a/rtengine/histmatching.cc +++ b/rtengine/histmatching.cc @@ -97,55 +97,6 @@ int findMatch(int val, const std::vector &cdf, int j) } -class CubicSplineCurve: public DiagonalCurve { -public: - CubicSplineCurve(const std::vector &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 &mapping, std::vector &curve) { curve.clear(); @@ -259,10 +210,11 @@ void mappingToCurve(const std::vector &mapping, std::vector &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)); diff --git a/rtgui/curveeditor.cc b/rtgui/curveeditor.cc index 995dafa4e..3d1223bdf 100644 --- a/rtgui/curveeditor.cc +++ b/rtgui/curveeditor.cc @@ -25,6 +25,47 @@ #include +namespace { + +class CurveTypePopUpButton: public PopUpToggleButton { +public: + CurveTypePopUpButton(const Glib::ustring &label=""): + PopUpToggleButton(label) {} + + void setPosIndexMap(const std::vector &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 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(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(curveType)->setPosIndexMap({ 0, 1, 4, 2, 3 }); curveType->setSelected(DCT_Linear); + curveType->show(); rangeLabels[0] = M("CURVEEDITOR_SHADOWS"); @@ -65,6 +108,9 @@ std::vector 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")); diff --git a/rtgui/curveeditor.h b/rtgui/curveeditor.h index 14699b42a..4cf49a377 100644 --- a/rtgui/curveeditor.h +++ b/rtgui/curveeditor.h @@ -156,6 +156,8 @@ protected: std::vector paramResetCurve; std::vector NURBSCurveEd; std::vector NURBSResetCurve; + std::vector catmullRomCurveEd; + std::vector catmullRomResetCurve; Glib::ustring rangeLabels[4]; double rangeMilestones[3]; diff --git a/rtgui/diagonalcurveeditorsubgroup.cc b/rtgui/diagonalcurveeditorsubgroup.cc index 4cbde55cc..e8b92062a 100644 --- a/rtgui/diagonalcurveeditorsubgroup.cc +++ b/rtgui/diagonalcurveeditorsubgroup.cc @@ -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(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(ce))->NURBSCurveEd = p; break; + case (DCT_CatumullRom): + (static_cast(ce))->catmullRomCurveEd = p; + break; + default: break; } @@ -1126,6 +1153,14 @@ const std::vector 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 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(parent->displayedCurve); double mileStone[3]; diff --git a/rtgui/mydiagonalcurve.cc b/rtgui/mydiagonalcurve.cc index 5eacdcc46..f70f4af0f 100644 --- a/rtgui/mydiagonalcurve.cc +++ b/rtgui/mydiagonalcurve.cc @@ -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 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 &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.; diff --git a/rtgui/mydiagonalcurve.h b/rtgui/mydiagonalcurve.h index 9433c42b5..5b0f6f01e 100644 --- a/rtgui/mydiagonalcurve.h +++ b/rtgui/mydiagonalcurve.h @@ -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 }; diff --git a/rtgui/popupcommon.cc b/rtgui/popupcommon.cc index b7d08721e..c5a5a03e3 100644 --- a/rtgui/popupcommon.cc +++ b/rtgui/popupcommon.cc @@ -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 { diff --git a/rtgui/popupcommon.h b/rtgui/popupcommon.h index f4bdb581f..f939dbe96 100644 --- a/rtgui/popupcommon.h +++ b/rtgui/popupcommon.h @@ -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