"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;
double* leftTangent;
double* rightTangent;
bool periodic;
void CtrlPoints_set ();
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 ();
double getVal (double t);

View File

@@ -29,21 +29,24 @@
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;
poly_x.clear();
poly_y.clear();
if (p.size()<5) {
kind = FCT_Empty;
}
else {
kind = FCT_Empty;
periodic = isPeriodic;
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+1];
y = new double[N+1];
leftTangent = new double[N+1];
rightTangent = new double[N+1];
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++];
@@ -52,11 +55,16 @@ FlatCurve::FlatCurve (const std::vector<double>& p, int poly_pn) : leftTangent(N
rightTangent[i] = p[ix++];
}
// The first point is copied to the end of the point list, to handle the curve periodicity
x[N] = p[1]+1.0;
y[N] = p[2];
leftTangent[N] = p[3];
rightTangent[N] = p[4];
if (N > 1)
if (periodic) {
x[N] = p[1]+1.0;
y[N] = p[2];
leftTangent[N] = p[3];
rightTangent[N] = p[4];
}
else {
N--;
}
if (N > 0+(periodic?1:0) )
CtrlPoints_set ();
}
/*else if (kind==FCT_Parametric) {
@@ -239,24 +247,30 @@ void FlatCurve::CtrlPoints_set () {
poly_y.clear();
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_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 {
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(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);
}
// 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
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
curveType->addEntry(argv0+"/images/curveType-flatLinear.png", M("CURVEEDITOR_LINEAR")); // 0 Linear

View File

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

View File

@@ -56,8 +56,10 @@ void CurveEditorGroup::hideCurrentCurve() {
/*
* 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) {
case (CT_Diagonal):
if (!diagonalSubGroup) {
@@ -68,7 +70,7 @@ CurveEditor* CurveEditorGroup::addCurve(CurveType cType, Glib::ustring curveLabe
if (!flatSubGroup) {
flatSubGroup = new FlatCurveEditorSubGroup(this);
}
return (CurveEditor*)flatSubGroup->addCurve(curveLabel);
return (CurveEditor*)flatSubGroup->addCurve(curveLabel, periodic);
default:
return (CurveEditor*)NULL;
break;

View File

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

View File

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

View File

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

View File

@@ -31,6 +31,7 @@ MyCurve::MyCurve () : listener(NULL) {
snapTo = ST_None;
colorProvider = NULL;
sized = RS_Pending;
snapToElmt = -100;
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);
@@ -54,3 +55,16 @@ void MyCurve::notifyListener () {
if (listener)
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> lpoint;
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;
enum ResizeState sized;
virtual std::vector<double> get_vector (int veclen) = 0;
int getGraphMinSize() { return GRAPH_SIZE + RADIUS + 1; }
bool snapCoordinate(double testedVal, double realVal);
public:
MyCurve ();

View File

@@ -178,7 +178,10 @@ void MyDiagonalCurve::draw (int handle) {
cr->stroke ();
// 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);
ds[0] = 4;
cr->set_dash (ds, 0);
@@ -205,20 +208,30 @@ void MyDiagonalCurve::draw (int handle) {
// draw the cage of the NURBS curve
if (curve.type==DCT_NURBS) {
unsigned int nbPoints;
std::valarray<double> ch_ds (1);
ch_ds[0] = 2;
cr->set_dash (ch_ds, 0);
cr->set_source_rgb (0.0, 0.0, 0.0);
std::vector<double> points = getPoints();
for (int i = 1; i < (int)points.size(); ) {
double x = ((innerWidth-1) * points[i++] + 0.5)+RADIUS; // project (curve.x[i], 0, 1, innerWidth);
double y = innerHeight - ((innerHeight-1) * points[i++] + 0.5)+RADIUS; // project (curve.y[i], 0, 1, innerHeight);
if (i==3)
cr->move_to (x, y);
nbPoints = ((int)points.size()-1)/2;
for (unsigned int i = 1; i < nbPoints; i++) {
int pos = i*2+1;
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
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 ();
}
@@ -232,7 +245,17 @@ void MyDiagonalCurve::draw (int handle) {
// draw bullets
if (curve.type!=DCT_Parametric)
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 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;
case Gdk::BUTTON_PRESS:
snapToElmt = -100;
if (curve.type!=DCT_Parametric) {
if (event->button.button == 1) {
buttonPressed = true;
@@ -338,6 +362,7 @@ bool MyDiagonalCurve::handleEvents (GdkEvent* event) {
break;
case Gdk::BUTTON_RELEASE:
snapToElmt = -100;
if (curve.type!=DCT_Parametric) {
if (buttonPressed && event->button.button == 1) {
buttonPressed = false;
@@ -398,7 +423,13 @@ bool MyDiagonalCurve::handleEvents (GdkEvent* event) {
break;
case Gdk::MOTION_NOTIFY:
snapToElmt = -100;
if (curve.type == DCT_Linear || curve.type == DCT_Spline || curve.type == DCT_NURBS) {
snapToMinDist = 10.;
snapToVal = 0.;
snapToElmt = -100;
// get the pointer position
getCursorPosition(event);
@@ -439,6 +470,9 @@ bool MyDiagonalCurve::handleEvents (GdkEvent* event) {
ugpX += deltaX;
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
if (ugpX >= rightDeletionBound && (grab_point > 0 && grab_point < (num-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) {
curve.x[grab_point] = -1.;
}
else
// nextPosY is in the bounds
curve.y[grab_point] = CLAMP(ugpY, 0.0, 1.0);
else {
// snapping point to specific values
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) {
// 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;
// the increment get smaller if modifier key are used, and "snap to" may be enabled
if (control_key && shift_key) { snapTo = ST_Neighbors; }
else if (control_key) { snapTo = ST_Identity; }
else if (shift_key) { incrementX *= 0.04; incrementY *= 0.04; }
if (control_key) { incrementX *= 0.05; incrementY *= 0.05; }
if (shift_key) { snapTo = true; }
deltaX = (double)(cursorX - prevCursorX) * incrementX;
deltaY = (double)(cursorY - prevCursorY) * incrementY;
@@ -660,16 +723,16 @@ void MyDiagonalCurve::updateBackgroundHistogram (LUTu & hist) {
if (hist!=NULL) {
//memcpy (bghist, hist, 256*sizeof(unsigned int));
for (int i=0; i<256; i++) bghist[i]=hist[i];
//hist = bghist;
for (int i=0; i<256; i++) bghist[i]=hist[i];
//hist = bghist;
bghistvalid = true;
}
else
bghistvalid = false;
mcih->pending++;
g_idle_add (diagonalmchistupdate, mcih);
}
void MyDiagonalCurve::reset() {

View File

@@ -54,7 +54,7 @@ std::vector<double> MyFlatCurve::get_vector (int veclen) {
// Get the curve control points
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
std::vector<double> samples;
@@ -157,13 +157,20 @@ void MyFlatCurve::draw () {
double y0 = (double)RADIUS-0.5;
double y1 = (double)RADIUS-0.5 + (double)innerHeight + 2.;
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, y0);
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->line_to (x1, currY);
cr->move_to (currX, y0);
cr->line_to (currX, y1);
}
}*/
cr->stroke ();
// draw f(x)=0.5 line
@@ -171,13 +178,14 @@ void MyFlatCurve::draw () {
std::valarray<double> ds (1);
ds[0] = 4;
cr->set_dash (ds, 0);
cr->move_to ((double)RADIUS+0.5 , (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->move_to (x0, (double)RADIUS+0.5 + (double)innerHeight/2.);
cr->line_to (x1, (double)RADIUS+0.5 + (double)innerHeight/2.);
cr->stroke ();
cr->unset_dash ();
cr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL);
cr->unset_dash ();
cr->set_line_width (1.0);
// draw the color feedback of the control points
@@ -347,6 +355,9 @@ void MyFlatCurve::draw () {
else
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)
cr->set_source_rgb (0.0, 0.5, 0.0);
else
@@ -473,6 +484,7 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
int src, dst;
std::vector<double>::iterator itx, ity, itlt, itrt;
snapToElmt = -100;
bool retval = false;
int num = (int)curve.x.size();
@@ -548,7 +560,7 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
curve.rightTangent.insert (itrt, 0);
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.y[closest_point] = clampedY;
curve.leftTangent[closest_point] = 0.35;
@@ -695,14 +707,13 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
case Gdk::MOTION_NOTIFY:
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;
enum MouseOverAreas prevArea = area;
snapToMinDist = 10.;
snapToVal = 0.;
snapToElmt = -100;
// get the pointer position
getCursorPosition(event);
getMouseOverArea();
@@ -826,13 +837,22 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
break;
case (FCT_EditedHandle_LeftTan): {
double prevValue = ugpX;
double prevValue = curve.leftTangent[lit_point];
ugpX -= deltaX*3;
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 ();
draw ();
notifyListener ();
@@ -841,13 +861,22 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
}
case (FCT_EditedHandle_RightTan): {
double prevValue = ugpX;
double prevValue = curve.rightTangent[lit_point];
ugpX += deltaX*3;
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 ();
draw ();
notifyListener ();
@@ -855,7 +884,7 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
break;
}
// already process before the "switch" instruction
// already processed before the "switch" instruction
//case (FCT_EditedHandle_CPointUD):
default:
@@ -995,9 +1024,41 @@ void MyFlatCurve::movePoint(bool moveX, bool moveY) {
}
if (moveY) {
// we memorize the previous position of the point, for optimization purpose
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
if (ugpY >= topDeletionBound && nbPoints>2) {
if (curve.x[lit_point] != -1.) {
@@ -1015,7 +1076,7 @@ void MyFlatCurve::movePoint(bool moveX, bool moveY) {
}
else {
// 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.) {
// bring back the X value of the point if it reappear
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) {
// we recalculate the curve only if we have to
// we recompute the curve only if we have to
interpolate ();
draw ();
notifyListener ();
@@ -1071,7 +1132,7 @@ void MyFlatCurve::getCursorPosition(GdkEvent* event) {
preciseCursorX = cursorX * incrementX;
preciseCursorY = cursorY * incrementY;
snapTo = ST_None;
snapTo = false;
// update deltaX/Y if the user drags a point
if (editedHandle != FCT_EditedHandle_None) {
@@ -1080,9 +1141,8 @@ void MyFlatCurve::getCursorPosition(GdkEvent* event) {
int shift_key = mod_type & GDK_SHIFT_MASK;
// the increment get smaller if modifier key are used, and "snap to" may be enabled
if (control_key && shift_key) { snapTo = ST_Neighbors; }
else if (control_key) { snapTo = ST_Identity; }
else if (shift_key) { incrementX *= 0.04; incrementY *= 0.04; }
if (control_key) { incrementX *= 0.05; incrementY *= 0.05; }
if (shift_key) { snapTo = true; }
deltaX = (double)(cursorX - prevCursorX) * incrementX;
deltaY = (double)(cursorY - prevCursorY) * incrementY;

View File

@@ -93,7 +93,7 @@ class MyFlatCurve : public MyCurve {
double minDistanceX; // X 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
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
bool tanHandlesDisplayed; // True if the tangent handles are displayed
bool periodic; // Flat curves are periodic by default
@@ -114,6 +114,7 @@ class MyFlatCurve : public MyCurve {
MyFlatCurve ();
//~MyFlatCurve ();
std::vector<double> getPoints ();
void setPeriodicity (bool isPeriodic) { periodic = isPeriodic; };
void setPoints (const std::vector<double>& p);
void setType (FlatCurveType t);
bool handleEvents (GdkEvent* event);