"SnapTo" feature enabled in the curve editor + non periodic handling of the flat curve editor.

Here is the new modifiew key behaviour :

    * CONTROL while dragging a point :
      slow down 20x the point move (i.e. 1pixel of cursor move move the control point by 0.05px)

    * SHIFT while dragging a point :
      snap the point to the following elements, on a "use nearest solution" method :
          o Diagonal curve editor :
                + top bound,
                + bottom bound,
                + identity (diagonal) line,
                + same Y than previous point,
                + same Y than next point,
                + line made by the previous and next point ; this will help to create linear parts in the curve more easilly
          o Flat curve editor (when moving a point) :
                + top bound,
                + bottom bound,
                + identity (horizontal) line,
                + same Y than previous point (or last point if you move the first point),
                + same Y than next point (or first point if you move the last point
          o Flat curve editor (when moving a tangential handle) :
                + 0.0, 0.35, 0.5, 1.0 values
                  0.35 is the default handles value and does create an smooth "diagonal" transition between points.
This commit is contained in:
Hombre
2011-04-18 15:40:22 +02:00
parent a6370306f7
commit 3de100ae5e
13 changed files with 258 additions and 80 deletions

View File

@@ -264,12 +264,13 @@ class FlatCurve : public Curve {
FlatCurveType kind; FlatCurveType kind;
double* leftTangent; double* leftTangent;
double* rightTangent; double* rightTangent;
bool periodic;
void CtrlPoints_set (); void CtrlPoints_set ();
public: public:
FlatCurve (const std::vector<double>& points, int ppn=CURVES_MIN_POLY_POINTS); FlatCurve (const std::vector<double>& points, bool isPeriodic = true, int ppn=CURVES_MIN_POLY_POINTS);
~FlatCurve (); ~FlatCurve ();
double getVal (double t); double getVal (double t);

View File

@@ -29,21 +29,24 @@
namespace rtengine { namespace rtengine {
FlatCurve::FlatCurve (const std::vector<double>& p, int poly_pn) : leftTangent(NULL), rightTangent(NULL) { FlatCurve::FlatCurve (const std::vector<double>& p, bool isPeriodic, int poly_pn) : leftTangent(NULL), rightTangent(NULL) {
ppn = poly_pn; ppn = poly_pn;
poly_x.clear();
poly_y.clear();
if (p.size()<5) { kind = FCT_Empty;
kind = FCT_Empty; periodic = isPeriodic;
}
else { if (p.size()>4) {
kind = (FlatCurveType)p[0]; kind = (FlatCurveType)p[0];
if (kind==FCT_MinMaxCPoints) { if (kind==FCT_MinMaxCPoints) {
int oneMorePoint = periodic ? 1:0;
N = (p.size()-1)/4; N = (p.size()-1)/4;
x = new double[N+1]; x = new double[N+oneMorePoint];
y = new double[N+1]; y = new double[N+oneMorePoint];
leftTangent = new double[N+1]; leftTangent = new double[N+oneMorePoint];
rightTangent = new double[N+1]; rightTangent = new double[N+oneMorePoint];
int ix = 1; int ix = 1;
for (int i=0; i<N; i++) { for (int i=0; i<N; i++) {
x[i] = p[ix++]; x[i] = p[ix++];
@@ -52,11 +55,16 @@ FlatCurve::FlatCurve (const std::vector<double>& p, int poly_pn) : leftTangent(N
rightTangent[i] = p[ix++]; rightTangent[i] = p[ix++];
} }
// The first point is copied to the end of the point list, to handle the curve periodicity // The first point is copied to the end of the point list, to handle the curve periodicity
x[N] = p[1]+1.0; if (periodic) {
y[N] = p[2]; x[N] = p[1]+1.0;
leftTangent[N] = p[3]; y[N] = p[2];
rightTangent[N] = p[4]; leftTangent[N] = p[3];
if (N > 1) rightTangent[N] = p[4];
}
else {
N--;
}
if (N > 0+(periodic?1:0) )
CtrlPoints_set (); CtrlPoints_set ();
} }
/*else if (kind==FCT_Parametric) { /*else if (kind==FCT_Parametric) {
@@ -239,24 +247,30 @@ void FlatCurve::CtrlPoints_set () {
poly_y.clear(); poly_y.clear();
j = 0; j = 0;
// very first point of the curve // 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_x.push_back(sc_x[j]);
poly_y.push_back(sc_y[j]); poly_y.push_back(sc_y[j]);
firstPointIncluded = false; firstPointIncluded = false;
// create the polyline with the number of points adapted to the X range of the sub-curve // 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++) { for (unsigned int i=0; i < k; i++) {
if (sc_isLinear[i]) { if (sc_isLinear[i]) {
j++; // skip the first point j++; // skip the first point
poly_x.push_back(sc_x[j]); poly_x.push_back(sc_x[j]);
poly_y.push_back(sc_y[j++]); poly_y.push_back(sc_y[j++]);
} }
else { else {
nbr_points = (int)(((double)(ppn) * sc_length[i] )/ total_length); nbr_points = (int)(((double)(ppn) * sc_length[i] )/ total_length);
if (nbr_points<0){ if (nbr_points<0){
for(unsigned int it=0;it < sc_x.size(); it+=3) printf("sc_length[%d/3]=%f \n",it,sc_length[it/3]); for(unsigned int it=0;it < sc_x.size(); it+=3) printf("sc_length[%d/3]=%f \n",it,sc_length[it/3]);
printf("Flat 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); 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); exit(0);
} }
// increment along the curve, not along the X axis // increment along the curve, not along the X axis
@@ -268,6 +282,12 @@ void FlatCurve::CtrlPoints_set () {
} }
} }
// adding an final horizontal line if necessary
if (!periodic && sc_x[--j] != 1.) {
poly_x.push_back(1.);
poly_y.push_back(sc_y[j]);
}
/* /*
// Checking the values // Checking the values
Glib::ustring fname = "Curve.xyz"; // TopSolid'Design "plot" file format Glib::ustring fname = "Curve.xyz"; // TopSolid'Design "plot" file format

View File

@@ -56,7 +56,9 @@ std::vector<double> DiagonalCurveEditor::getCurve () {
} }
} }
FlatCurveEditor::FlatCurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEditorSubGroup* ceSubGroup) : CurveEditor::CurveEditor(text, (CurveEditorGroup*) ceGroup, ceSubGroup) { FlatCurveEditor::FlatCurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEditorSubGroup* ceSubGroup, bool isPeriodic) : CurveEditor::CurveEditor(text, (CurveEditorGroup*) ceGroup, ceSubGroup) {
periodic = isPeriodic;
// Order set in the same order than "enum FlatCurveType". Shouldn't change, for compatibility reason // Order set in the same order than "enum FlatCurveType". Shouldn't change, for compatibility reason
curveType->addEntry(argv0+"/images/curveType-flatLinear.png", M("CURVEEDITOR_LINEAR")); // 0 Linear curveType->addEntry(argv0+"/images/curveType-flatLinear.png", M("CURVEEDITOR_LINEAR")); // 0 Linear

View File

@@ -110,9 +110,10 @@ class FlatCurveEditor : public CurveEditor {
protected: protected:
// reflects the buttonType active selection ; used as a pre-'selectionChange' reminder value // reflects the buttonType active selection ; used as a pre-'selectionChange' reminder value
std::vector<double> controlPointsCurveEd; std::vector<double> controlPointsCurveEd;
bool periodic;
public: public:
FlatCurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEditorSubGroup* ceSubGroup); FlatCurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEditorSubGroup* ceSubGroup, bool isPeriodic = true);
std::vector<double> getCurve (); std::vector<double> getCurve ();
}; };

View File

@@ -56,8 +56,10 @@ void CurveEditorGroup::hideCurrentCurve() {
/* /*
* Add a new curve to the curves list * Add a new curve to the curves list
*
* The "periodic" parameter is only used by flat curve editors
*/ */
CurveEditor* CurveEditorGroup::addCurve(CurveType cType, Glib::ustring curveLabel) { CurveEditor* CurveEditorGroup::addCurve(CurveType cType, Glib::ustring curveLabel, bool periodic) {
switch (cType) { switch (cType) {
case (CT_Diagonal): case (CT_Diagonal):
if (!diagonalSubGroup) { if (!diagonalSubGroup) {
@@ -68,7 +70,7 @@ CurveEditor* CurveEditorGroup::addCurve(CurveType cType, Glib::ustring curveLabe
if (!flatSubGroup) { if (!flatSubGroup) {
flatSubGroup = new FlatCurveEditorSubGroup(this); flatSubGroup = new FlatCurveEditorSubGroup(this);
} }
return (CurveEditor*)flatSubGroup->addCurve(curveLabel); return (CurveEditor*)flatSubGroup->addCurve(curveLabel, periodic);
default: default:
return (CurveEditor*)NULL; return (CurveEditor*)NULL;
break; break;

View File

@@ -70,7 +70,7 @@ public:
void setColorProvider (ColorProvider* p) { cp = p; } void setColorProvider (ColorProvider* p) { cp = p; }
CurveEditor* getDisplayedCurve () { return displayedCurve; } CurveEditor* getDisplayedCurve () { return displayedCurve; }
//void on_realize (); //void on_realize ();
CurveEditor* addCurve(CurveType cType, Glib::ustring curveLabel); CurveEditor* addCurve(CurveType cType, Glib::ustring curveLabel, bool periodic = true);
protected: protected:
//void curveTypeToggled (); //void curveTypeToggled ();

View File

@@ -72,8 +72,8 @@ FlatCurveEditorSubGroup::~FlatCurveEditorSubGroup() {
/* /*
* Add a new curve to the curves list * Add a new curve to the curves list
*/ */
FlatCurveEditor* FlatCurveEditorSubGroup::addCurve(Glib::ustring curveLabel) { FlatCurveEditor* FlatCurveEditorSubGroup::addCurve(Glib::ustring curveLabel, bool isPeriodic) {
FlatCurveEditor* newCE = new FlatCurveEditor(curveLabel, parent, this); FlatCurveEditor* newCE = new FlatCurveEditor(curveLabel, parent, this, isPeriodic);
// Initialization of the new curve // Initialization of the new curve
storeCurveValues(newCE, getCurveFromGUI(FCT_MinMaxCPoints)); storeCurveValues(newCE, getCurveFromGUI(FCT_MinMaxCPoints));
@@ -99,6 +99,7 @@ void FlatCurveEditorSubGroup::switchGUI() {
switch((FlatCurveType)(dCurve->curveType->getSelected())) { switch((FlatCurveType)(dCurve->curveType->getSelected())) {
case (FCT_MinMaxCPoints): case (FCT_MinMaxCPoints):
CPointsCurve->setPeriodicity(dCurve->periodic); // Setting Periodicity before setting points
CPointsCurve->setPoints (dCurve->controlPointsCurveEd); CPointsCurve->setPoints (dCurve->controlPointsCurveEd);
parent->pack_start (*CPointsCurveBox); parent->pack_start (*CPointsCurveBox);
CPointsCurveBox->check_resize(); CPointsCurveBox->check_resize();
@@ -196,7 +197,7 @@ void FlatCurveEditorSubGroup::restoreDisplayedHistogram() {
//paramCurve->updateBackgroundHistogram (parent->displayedCurve->histogram); //paramCurve->updateBackgroundHistogram (parent->displayedCurve->histogram);
CPointsCurve->updateBackgroundHistogram (parent->displayedCurve->histogram); CPointsCurve->updateBackgroundHistogram (parent->displayedCurve->histogram);
} }
} }
void FlatCurveEditorSubGroup::storeCurveValues (CurveEditor* ce, const std::vector<double>& p) { void FlatCurveEditorSubGroup::storeCurveValues (CurveEditor* ce, const std::vector<double>& p) {

View File

@@ -40,7 +40,7 @@ public:
FlatCurveEditorSubGroup(CurveEditorGroup* prt); FlatCurveEditorSubGroup(CurveEditorGroup* prt);
~FlatCurveEditorSubGroup(); ~FlatCurveEditorSubGroup();
FlatCurveEditor* addCurve(Glib::ustring curveLabel = ""); FlatCurveEditor* addCurve(Glib::ustring curveLabel = "", bool periodic = true);
//virtual void updateBackgroundHistogram (CurveEditor* ce); //virtual void updateBackgroundHistogram (CurveEditor* ce);
virtual void setColorProvider (ColorProvider* p); virtual void setColorProvider (ColorProvider* p);

View File

@@ -31,6 +31,7 @@ MyCurve::MyCurve () : listener(NULL) {
snapTo = ST_None; snapTo = ST_None;
colorProvider = NULL; colorProvider = NULL;
sized = RS_Pending; sized = RS_Pending;
snapToElmt = -100;
set_extension_events(Gdk::EXTENSION_EVENTS_ALL); set_extension_events(Gdk::EXTENSION_EVENTS_ALL);
add_events(Gdk::EXPOSURE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::POINTER_MOTION_HINT_MASK | Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::BUTTON1_MOTION_MASK); add_events(Gdk::EXPOSURE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::POINTER_MOTION_HINT_MASK | Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::BUTTON1_MOTION_MASK);
@@ -54,3 +55,16 @@ void MyCurve::notifyListener () {
if (listener) if (listener)
listener->curveChanged (); listener->curveChanged ();
} }
bool MyCurve::snapCoordinate(double testedVal, double realVal) {
double distY = realVal - testedVal;
if (distY < 0.) distY = -distY;
if (distY < snapToMinDist) {
snapToMinDist = distY;
snapToVal = testedVal;
return true;
}
return false;
}

View File

@@ -70,12 +70,25 @@ class MyCurve : public Gtk::DrawingArea {
std::vector<Gdk::Point> upoint; std::vector<Gdk::Point> upoint;
std::vector<Gdk::Point> lpoint; std::vector<Gdk::Point> lpoint;
bool buttonPressed; bool buttonPressed;
enum SnapToType snapTo; /*
* snapToElmt must be interpreted like this:
* -100 : no element (default)
* -3 : maximum value
* -2 : identity value
* -1 : minimum value
* [0;1000[ : control point that it's snapped to
* >=1000 : moved control point which is snapped to to the line made by it neighbors
*/
int snapToElmt;
bool snapTo;
double snapToMinDist;
double snapToVal;
MyCurveIdleHelper* mcih; MyCurveIdleHelper* mcih;
enum ResizeState sized; enum ResizeState sized;
virtual std::vector<double> get_vector (int veclen) = 0; virtual std::vector<double> get_vector (int veclen) = 0;
int getGraphMinSize() { return GRAPH_SIZE + RADIUS + 1; } int getGraphMinSize() { return GRAPH_SIZE + RADIUS + 1; }
bool snapCoordinate(double testedVal, double realVal);
public: public:
MyCurve (); MyCurve ();

View File

@@ -178,7 +178,10 @@ void MyDiagonalCurve::draw (int handle) {
cr->stroke (); cr->stroke ();
// draw f(x)=x line // draw f(x)=x line
cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p()); if (snapToElmt == -2)
cr->set_source_rgb (1.0, 0.0, 0.0);
else
cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p());
std::valarray<double> ds (1); std::valarray<double> ds (1);
ds[0] = 4; ds[0] = 4;
cr->set_dash (ds, 0); cr->set_dash (ds, 0);
@@ -205,20 +208,30 @@ void MyDiagonalCurve::draw (int handle) {
// draw the cage of the NURBS curve // draw the cage of the NURBS curve
if (curve.type==DCT_NURBS) { if (curve.type==DCT_NURBS) {
unsigned int nbPoints;
std::valarray<double> ch_ds (1); std::valarray<double> ch_ds (1);
ch_ds[0] = 2; ch_ds[0] = 2;
cr->set_dash (ch_ds, 0); cr->set_dash (ch_ds, 0);
cr->set_source_rgb (0.0, 0.0, 0.0); cr->set_source_rgb (0.0, 0.0, 0.0);
std::vector<double> points = getPoints(); std::vector<double> points = getPoints();
for (int i = 1; i < (int)points.size(); ) { nbPoints = ((int)points.size()-1)/2;
double x = ((innerWidth-1) * points[i++] + 0.5)+RADIUS; // project (curve.x[i], 0, 1, innerWidth); for (unsigned int i = 1; i < nbPoints; i++) {
double y = innerHeight - ((innerHeight-1) * points[i++] + 0.5)+RADIUS; // project (curve.y[i], 0, 1, innerHeight); int pos = i*2+1;
if (i==3)
cr->move_to (x, y); double x1 = ((innerWidth-1) * points[pos-2] + 0.5)+RADIUS; // project (curve.x[i], 0, 1, innerWidth);
double y1 = innerHeight - ((innerHeight-1) * points[pos-1] + 0.5)+RADIUS; // project (curve.y[i], 0, 1, innerHeight);
double x2 = ((innerWidth-1) * points[pos] + 0.5)+RADIUS; // project (curve.x[i], 0, 1, innerWidth);
double y2 = innerHeight - ((innerHeight-1) * points[pos+1] + 0.5)+RADIUS; // project (curve.y[i], 0, 1, innerHeight);
// set the color of the line when the point is snapped to the cage
if (curve.x.size() == nbPoints && snapToElmt >= 1000 && ((i == (snapToElmt-1000)) || (i == (snapToElmt-999))))
cr->set_source_rgb (1.0, 0.0, 0.0);
else else
cr->line_to (x, y); cr->set_source_rgb (0.0, 0.0, 0.0);
cr->move_to (x1, y1);
cr->line_to (x2, y2);
cr->stroke ();
} }
cr->stroke ();
cr->unset_dash (); cr->unset_dash ();
} }
@@ -232,7 +245,17 @@ void MyDiagonalCurve::draw (int handle) {
// draw bullets // draw bullets
if (curve.type!=DCT_Parametric) if (curve.type!=DCT_Parametric)
for (int i = 0; i < (int)curve.x.size(); ++i) { for (int i = 0; i < (int)curve.x.size(); ++i) {
cr->set_source_rgb ((i == handle ? 1.0 : 0.0), 0.0, 0.0); if (curve.x[i] == -1) continue;
if (snapToElmt >= 1000) {
int pt = snapToElmt-1000;
if (i >= (pt-1) && i <= (pt+1))
cr->set_source_rgb(1.0, 0.0, 0.0);
else
cr->set_source_rgb(0.0, 0.0, 0.0);
}
else
cr->set_source_rgb ((i == handle || i == snapToElmt ? 1.0 : 0.0), 0.0, 0.0);
double x = ((innerWidth-1) * curve.x[i] + 0.5)+RADIUS; // project (curve.x[i], 0, 1, innerWidth); double x = ((innerWidth-1) * curve.x[i] + 0.5)+RADIUS; // project (curve.x[i], 0, 1, innerWidth);
double y = innerHeight - ((innerHeight-1) * curve.y[i] + 0.5)+RADIUS; // project (curve.y[i], 0, 1, innerHeight); double y = innerHeight - ((innerHeight-1) * curve.y[i] + 0.5)+RADIUS; // project (curve.y[i], 0, 1, innerHeight);
@@ -297,6 +320,7 @@ bool MyDiagonalCurve::handleEvents (GdkEvent* event) {
break; break;
case Gdk::BUTTON_PRESS: case Gdk::BUTTON_PRESS:
snapToElmt = -100;
if (curve.type!=DCT_Parametric) { if (curve.type!=DCT_Parametric) {
if (event->button.button == 1) { if (event->button.button == 1) {
buttonPressed = true; buttonPressed = true;
@@ -338,6 +362,7 @@ bool MyDiagonalCurve::handleEvents (GdkEvent* event) {
break; break;
case Gdk::BUTTON_RELEASE: case Gdk::BUTTON_RELEASE:
snapToElmt = -100;
if (curve.type!=DCT_Parametric) { if (curve.type!=DCT_Parametric) {
if (buttonPressed && event->button.button == 1) { if (buttonPressed && event->button.button == 1) {
buttonPressed = false; buttonPressed = false;
@@ -398,7 +423,13 @@ bool MyDiagonalCurve::handleEvents (GdkEvent* event) {
break; break;
case Gdk::MOTION_NOTIFY: 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) {
snapToMinDist = 10.;
snapToVal = 0.;
snapToElmt = -100;
// get the pointer position // get the pointer position
getCursorPosition(event); getCursorPosition(event);
@@ -439,6 +470,9 @@ bool MyDiagonalCurve::handleEvents (GdkEvent* event) {
ugpX += deltaX; ugpX += deltaX;
ugpY += deltaY; ugpY += deltaY;
// the unclamped grabbed point is brought back in the range when snapTo is active
if (snapTo) ugpY = CLAMP(ugpY, 0.0, 1.0);
// handling limitations along X axis // handling limitations along X axis
if (ugpX >= rightDeletionBound && (grab_point > 0 && grab_point < (num-1))) { if (ugpX >= rightDeletionBound && (grab_point > 0 && grab_point < (num-1))) {
curve.x[grab_point] = -1.; curve.x[grab_point] = -1.;
@@ -457,9 +491,39 @@ bool MyDiagonalCurve::handleEvents (GdkEvent* event) {
else if (ugpY <= bottomDeletionBound && grab_point != 0 && grab_point != num-1) { else if (ugpY <= bottomDeletionBound && grab_point != 0 && grab_point != num-1) {
curve.x[grab_point] = -1.; curve.x[grab_point] = -1.;
} }
else else {
// nextPosY is in the bounds // snapping point to specific values
curve.y[grab_point] = CLAMP(ugpY, 0.0, 1.0); if (snapTo && curve.x[grab_point] != -1.) {
if (grab_point > 0 && grab_point < (curve.y.size()-1)) {
double prevX = curve.x[grab_point-1];
double prevY = curve.y[grab_point-1];
double nextX = curve.x[grab_point+1];
double nextY = curve.y[grab_point+1];
double ratio = (curve.x[grab_point]-prevX)/(nextX-prevX);
double y = (nextY-prevY) * ratio + prevY;
if (snapCoordinate(y, ugpY)) snapToElmt = 1000+grab_point;
}
if (grab_point > 0) {
int prevP = grab_point-1;
if (snapCoordinate(curve.y[prevP], ugpY)) snapToElmt = prevP;
}
if (grab_point < (curve.y.size()-1)) {
int nextP = grab_point+1;
if (snapCoordinate(curve.y[nextP], ugpY)) snapToElmt = nextP;
}
if (snapCoordinate(1.0, ugpY)) snapToElmt = -3;
if (snapCoordinate(curve.x[grab_point], ugpY)) snapToElmt = -2;
if (snapCoordinate(0.0, ugpY)) snapToElmt = -1;
curve.y[grab_point] = snapToVal;
}
else {
// nextPosY is in the bounds
curve.y[grab_point] = CLAMP(ugpY, 0.0, 1.0);
}
}
if (curve.x[grab_point] != prevPosX || curve.y[grab_point] != prevPosY) { if (curve.x[grab_point] != prevPosX || curve.y[grab_point] != prevPosY) {
// we recalculate the curve only if we have to // we recalculate the curve only if we have to
@@ -529,9 +593,8 @@ void MyDiagonalCurve::getCursorPosition(GdkEvent* event) {
int shift_key = mod_type & GDK_SHIFT_MASK; int shift_key = mod_type & GDK_SHIFT_MASK;
// the increment get smaller if modifier key are used, and "snap to" may be enabled // the increment get smaller if modifier key are used, and "snap to" may be enabled
if (control_key && shift_key) { snapTo = ST_Neighbors; } if (control_key) { incrementX *= 0.05; incrementY *= 0.05; }
else if (control_key) { snapTo = ST_Identity; } if (shift_key) { snapTo = true; }
else if (shift_key) { incrementX *= 0.04; incrementY *= 0.04; }
deltaX = (double)(cursorX - prevCursorX) * incrementX; deltaX = (double)(cursorX - prevCursorX) * incrementX;
deltaY = (double)(cursorY - prevCursorY) * incrementY; deltaY = (double)(cursorY - prevCursorY) * incrementY;
@@ -660,16 +723,16 @@ void MyDiagonalCurve::updateBackgroundHistogram (LUTu & hist) {
if (hist!=NULL) { if (hist!=NULL) {
//memcpy (bghist, hist, 256*sizeof(unsigned int)); //memcpy (bghist, hist, 256*sizeof(unsigned int));
for (int i=0; i<256; i++) bghist[i]=hist[i]; for (int i=0; i<256; i++) bghist[i]=hist[i];
//hist = bghist; //hist = bghist;
bghistvalid = true; bghistvalid = true;
} }
else else
bghistvalid = false; bghistvalid = false;
mcih->pending++; mcih->pending++;
g_idle_add (diagonalmchistupdate, mcih); g_idle_add (diagonalmchistupdate, mcih);
} }
void MyDiagonalCurve::reset() { void MyDiagonalCurve::reset() {

View File

@@ -54,7 +54,7 @@ std::vector<double> MyFlatCurve::get_vector (int veclen) {
// Get the curve control points // Get the curve control points
std::vector<double> curveDescr = getPoints (); std::vector<double> curveDescr = getPoints ();
rtengine::FlatCurve* rtcurve = new rtengine::FlatCurve (curveDescr, veclen*1.5 > 5000 ? 5000 : veclen*1.5); rtengine::FlatCurve* rtcurve = new rtengine::FlatCurve (curveDescr, periodic, veclen*1.5 > 5000 ? 5000 : veclen*1.5);
// Create the sample values that will be converted // Create the sample values that will be converted
std::vector<double> samples; std::vector<double> samples;
@@ -157,13 +157,20 @@ void MyFlatCurve::draw () {
double y0 = (double)RADIUS-0.5; double y0 = (double)RADIUS-0.5;
double y1 = (double)RADIUS-0.5 + (double)innerHeight + 2.; double y1 = (double)RADIUS-0.5 + (double)innerHeight + 2.;
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
double currX = (double)RADIUS-0.5 + (double)i*((double)innerWidth + 2.)/4.; cr->move_to (x0, y0);
double currY = (double)RADIUS-0.5 + (double)i*((double)innerHeight + 2.)/4.; cr->line_to (x0, y1);
cr->line_to (x1, y1);
cr->line_to (x1, y0);
cr->line_to (x0, y0);
}
/*for (int i = 0; i < 5; i++) {
double currX = (double)RADIUS-0.5 + (double)i*((double)innerWidth + 2.)/4.;
double currY = (double)RADIUS-0.5 + (double)i*((double)innerHeight + 2.)/4.;
cr->move_to (x0, currY); cr->move_to (x0, currY);
cr->line_to (x1, currY); cr->line_to (x1, currY);
cr->move_to (currX, y0); cr->move_to (currX, y0);
cr->line_to (currX, y1); cr->line_to (currX, y1);
} }*/
cr->stroke (); cr->stroke ();
// draw f(x)=0.5 line // draw f(x)=0.5 line
@@ -171,13 +178,14 @@ void MyFlatCurve::draw () {
std::valarray<double> ds (1); std::valarray<double> ds (1);
ds[0] = 4; ds[0] = 4;
cr->set_dash (ds, 0); cr->set_dash (ds, 0);
cr->move_to ((double)RADIUS+0.5 , (double)RADIUS+0.5 + (double)innerHeight/2.); cr->move_to (x0, (double)RADIUS+0.5 + (double)innerHeight/2.);
cr->line_to ((double)RADIUS+0.5 + (double)innerWidth/2., (double)RADIUS+0.5 + (double)innerHeight/2.); cr->line_to (x1, (double)RADIUS+0.5 + (double)innerHeight/2.);
cr->stroke (); cr->stroke ();
cr->unset_dash ();
cr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL); cr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL);
cr->unset_dash ();
cr->set_line_width (1.0); cr->set_line_width (1.0);
// draw the color feedback of the control points // draw the color feedback of the control points
@@ -347,6 +355,9 @@ void MyFlatCurve::draw () {
else else
cr->set_source_rgb (1.0, 0.0, 0.0); cr->set_source_rgb (1.0, 0.0, 0.0);
} }
else if (i == snapToElmt) {
cr->set_source_rgb (1.0, 0.0, 0.0);
}
else if (curve.y[i] == 0.5) else if (curve.y[i] == 0.5)
cr->set_source_rgb (0.0, 0.5, 0.0); cr->set_source_rgb (0.0, 0.5, 0.0);
else else
@@ -473,6 +484,7 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
int src, dst; int src, dst;
std::vector<double>::iterator itx, ity, itlt, itrt; std::vector<double>::iterator itx, ity, itlt, itrt;
snapToElmt = -100;
bool retval = false; bool retval = false;
int num = (int)curve.x.size(); int num = (int)curve.x.size();
@@ -548,7 +560,7 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
curve.rightTangent.insert (itrt, 0); curve.rightTangent.insert (itrt, 0);
num++; num++;
// the graph is refreshed only if a new point is created (snaped to a pixel) // the graph is refreshed only if a new point is created
curve.x[closest_point] = clampedX; curve.x[closest_point] = clampedX;
curve.y[closest_point] = clampedY; curve.y[closest_point] = clampedY;
curve.leftTangent[closest_point] = 0.35; curve.leftTangent[closest_point] = 0.35;
@@ -695,14 +707,13 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
case Gdk::MOTION_NOTIFY: case Gdk::MOTION_NOTIFY:
if (curve.type == FCT_Linear || curve.type == FCT_MinMaxCPoints) { if (curve.type == FCT_Linear || curve.type == FCT_MinMaxCPoints) {
int leftNeigborPoint = -1;
int rightNeigborPoint = -1;
double leftNeigborY = -1.;
double rightNeigborY = -1.;
int previous_lit_point = lit_point; int previous_lit_point = lit_point;
enum MouseOverAreas prevArea = area; enum MouseOverAreas prevArea = area;
snapToMinDist = 10.;
snapToVal = 0.;
snapToElmt = -100;
// get the pointer position // get the pointer position
getCursorPosition(event); getCursorPosition(event);
getMouseOverArea(); getMouseOverArea();
@@ -826,13 +837,22 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
break; break;
case (FCT_EditedHandle_LeftTan): { case (FCT_EditedHandle_LeftTan): {
double prevValue = ugpX; double prevValue = curve.leftTangent[lit_point];
ugpX -= deltaX*3; ugpX -= deltaX*3;
ugpX = CLAMP(ugpX, 0., 1.); ugpX = CLAMP(ugpX, 0., 1.);
curve.leftTangent[lit_point] = ugpX; if (snapTo) {
snapCoordinate(0.0, ugpX);
snapCoordinate(0.35, ugpX);
snapCoordinate(0.5, ugpX);
snapCoordinate(1.0, ugpX);
curve.leftTangent[lit_point] = snapToVal;
}
else {
curve.leftTangent[lit_point] = ugpX;
}
if (ugpX != prevValue) { if (curve.leftTangent[lit_point] != prevValue) {
interpolate (); interpolate ();
draw (); draw ();
notifyListener (); notifyListener ();
@@ -841,13 +861,22 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
} }
case (FCT_EditedHandle_RightTan): { case (FCT_EditedHandle_RightTan): {
double prevValue = ugpX; double prevValue = curve.rightTangent[lit_point];
ugpX += deltaX*3; ugpX += deltaX*3;
ugpX = CLAMP(ugpX, 0., 1.); ugpX = CLAMP(ugpX, 0., 1.);
curve.rightTangent[lit_point] = ugpX; if (snapTo) {
snapCoordinate(0.0, ugpX);
snapCoordinate(0.35, ugpX);
snapCoordinate(0.5, ugpX);
snapCoordinate(1.0, ugpX);
curve.rightTangent[lit_point] = snapToVal;
}
else {
curve.rightTangent[lit_point] = ugpX;
}
if (ugpX != prevValue) { if (curve.rightTangent[lit_point] != prevValue) {
interpolate (); interpolate ();
draw (); draw ();
notifyListener (); notifyListener ();
@@ -855,7 +884,7 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
break; break;
} }
// already process before the "switch" instruction // already processed before the "switch" instruction
//case (FCT_EditedHandle_CPointUD): //case (FCT_EditedHandle_CPointUD):
default: default:
@@ -995,9 +1024,41 @@ void MyFlatCurve::movePoint(bool moveX, bool moveY) {
} }
if (moveY) { if (moveY) {
// we memorize the previous position of the point, for optimization purpose // we memorize the previous position of the point, for optimization purpose
ugpY += deltaY; ugpY += deltaY;
// snapping point to specific values
if (snapTo && curve.x[lit_point] != -1) {
// the unclamped grabbed point is brought back in the range
ugpY = CLAMP(ugpY, 0.0, 1.0);
if (lit_point == 0) {
int prevP = curve.y.size()-1;
if (snapCoordinate(curve.y[prevP], ugpY)) snapToElmt = prevP;
}
else {
int prevP = lit_point-1;
if (snapCoordinate(curve.y[prevP], ugpY)) snapToElmt = prevP;
}
if (curve.y.size() > 2) {
if (lit_point == (curve.y.size()-1)) {
if (snapCoordinate(curve.y[0], ugpY)) snapToElmt = 0;
}
else {
int nextP = lit_point+1;
if (snapCoordinate(curve.y[nextP], ugpY)) snapToElmt = nextP;
}
}
if (snapCoordinate(1.0, ugpY)) snapToElmt = -3;
if (snapCoordinate(0.5, ugpY)) snapToElmt = -2;
if (snapCoordinate(0.0, ugpY)) snapToElmt = -1;
curve.y[lit_point] = snapToVal;
}
// Handling limitations along Y axis // Handling limitations along Y axis
if (ugpY >= topDeletionBound && nbPoints>2) { if (ugpY >= topDeletionBound && nbPoints>2) {
if (curve.x[lit_point] != -1.) { if (curve.x[lit_point] != -1.) {
@@ -1015,7 +1076,7 @@ void MyFlatCurve::movePoint(bool moveX, bool moveY) {
} }
else { else {
// nextPosY is in the bounds // nextPosY is in the bounds
curve.y[lit_point] = CLAMP(ugpY, 0.0, 1.0); if (!snapTo) curve.y[lit_point] = CLAMP(ugpY, 0.0, 1.0);
if (!moveX && curve.x[lit_point] == -1.) { if (!moveX && curve.x[lit_point] == -1.) {
// bring back the X value of the point if it reappear // bring back the X value of the point if it reappear
curve.x[lit_point] = deletedPointX; curve.x[lit_point] = deletedPointX;
@@ -1024,7 +1085,7 @@ void MyFlatCurve::movePoint(bool moveX, bool moveY) {
} }
if (curve.x[lit_point] != prevPosX || curve.y[lit_point] != prevPosY) { if (curve.x[lit_point] != prevPosX || curve.y[lit_point] != prevPosY) {
// we recalculate the curve only if we have to // we recompute the curve only if we have to
interpolate (); interpolate ();
draw (); draw ();
notifyListener (); notifyListener ();
@@ -1071,7 +1132,7 @@ void MyFlatCurve::getCursorPosition(GdkEvent* event) {
preciseCursorX = cursorX * incrementX; preciseCursorX = cursorX * incrementX;
preciseCursorY = cursorY * incrementY; preciseCursorY = cursorY * incrementY;
snapTo = ST_None; snapTo = false;
// update deltaX/Y if the user drags a point // update deltaX/Y if the user drags a point
if (editedHandle != FCT_EditedHandle_None) { if (editedHandle != FCT_EditedHandle_None) {
@@ -1080,9 +1141,8 @@ void MyFlatCurve::getCursorPosition(GdkEvent* event) {
int shift_key = mod_type & GDK_SHIFT_MASK; int shift_key = mod_type & GDK_SHIFT_MASK;
// the increment get smaller if modifier key are used, and "snap to" may be enabled // the increment get smaller if modifier key are used, and "snap to" may be enabled
if (control_key && shift_key) { snapTo = ST_Neighbors; } if (control_key) { incrementX *= 0.05; incrementY *= 0.05; }
else if (control_key) { snapTo = ST_Identity; } if (shift_key) { snapTo = true; }
else if (shift_key) { incrementX *= 0.04; incrementY *= 0.04; }
deltaX = (double)(cursorX - prevCursorX) * incrementX; deltaX = (double)(cursorX - prevCursorX) * incrementX;
deltaY = (double)(cursorY - prevCursorY) * incrementY; deltaY = (double)(cursorY - prevCursorY) * incrementY;

View File

@@ -93,7 +93,7 @@ class MyFlatCurve : public MyCurve {
double minDistanceX; // X minimal distance before point suppression double minDistanceX; // X minimal distance before point suppression
double minDistanceY; // Y minimal distance before point suppression double minDistanceY; // Y minimal distance before point suppression
double deletedPointX; // Backup of the X value of the edited point, when deleted while being dragged double deletedPointX; // Backup of the X value of the edited point, when deleted while being dragged
HandlePosition leftTanHandle; // XY coordinate if the upper left and bottom right corner of the left tangent handle HandlePosition leftTanHandle; // XY coordinate if the upper left and bottom right corner of the left tangent handle
HandlePosition rightTanHandle; // XY coordinate if the upper left and bottom right corner of the right tangent handle HandlePosition rightTanHandle; // XY coordinate if the upper left and bottom right corner of the right tangent handle
bool tanHandlesDisplayed; // True if the tangent handles are displayed bool tanHandlesDisplayed; // True if the tangent handles are displayed
bool periodic; // Flat curves are periodic by default bool periodic; // Flat curves are periodic by default
@@ -114,6 +114,7 @@ class MyFlatCurve : public MyCurve {
MyFlatCurve (); MyFlatCurve ();
//~MyFlatCurve (); //~MyFlatCurve ();
std::vector<double> getPoints (); std::vector<double> getPoints ();
void setPeriodicity (bool isPeriodic) { periodic = isPeriodic; };
void setPoints (const std::vector<double>& p); void setPoints (const std::vector<double>& p);
void setType (FlatCurveType t); void setType (FlatCurveType t);
bool handleEvents (GdkEvent* event); bool handleEvents (GdkEvent* event);