Could somebody proof-read my curve Class?

Hello all!

I just wrote a class for curve.

Could somebody check / proofread my code?

I am surprised why the curve goes UP when my the control point goes down.

my understanding of https://www.processing.org/reference/curve_.html is that the 8
parameters are :

  • controlpoint1 x,y
  • anchor 1 x,y
  • anchor 2 x,y
  • controlpoint2 x,y

Thank you!

Warm regards,

Chrisir



// Test for a new Curve Class that can do curve and curvepoint (2D)

CurveClass myCurve; 

// ---------------------------------------------------------------------------------------------

void setup() {

  size(1500, 900);

  final int STANDARD_DISTANCE=100;

  myCurve = new  CurveClass (
    width/2-31, height/2+310, //  beginning control point (cp1)
    width/2-STANDARD_DISTANCE, height/2+STANDARD_DISTANCE, // coordinates for the first point
    width/2+STANDARD_DISTANCE, height/2+STANDARD_DISTANCE, // coordinates for the second point
    width/2+31, height/2+310  // ending control point
    );
}

void draw() {
  background(#24B41D);

  fill(0); 
  text("You can drag the two red control points with the mouse. \nMove the mouse to move the white ball on the curve (mouseX->amt)", 
    14, 14);

  testCurve();
}

//-------------------------------------------------------------------------------------------------------

void testCurve () {
  myCurve.displayCurve(); 
  myCurve.testCurveData();
  myCurve.moveOnCurveWithMouseX(); // OR moveOnCurve() 
  myCurve.drag();
}

//-------------------------------------------------------------------------------------------------------

void mousePressed() {
  myCurve.mousePressedClass();
}

void mouseReleased() {
  myCurve.mouseReleasedClass();
}

// ===============================================================================================

class CurveClass {

  PVector cp1, anchor1, anchor2, cp2; 
  float x, y; 
  float amt;

  int drag = -1; 

  // constr - you call the constr as you would curve command (2D version) 
  CurveClass ( float f0, float f1, 
    float f2, float f3, 
    float f4, float f5, 
    float f6, float f7 ) {
    // constr 
    cp1     = new PVector (f0, f1);  
    anchor1 = new PVector (f2, f3);
    anchor2 = new PVector (f4, f5);
    cp2     = new PVector (f6, f7);
  } // constr 

  // ---

  void displayCurve() {
    stroke(255, 0, 0); //RED 
    strokeWeight(1);
    noFill();
    curve (
      cp1.x, cp1.y, 
      anchor1.x, anchor1.y, 
      anchor2.x, anchor2.y, 
      cp2.x, cp2.y);
  }

  // ---

  void moveOnCurve() {
    // AUTO move 
    x = curvePoint(cp1.x, anchor1.x, anchor2.x, cp2.x, amt); 
    y = curvePoint(cp1.y, anchor1.y, anchor2.y, cp2.y, amt);
    fill(255); // WHITE
    noStroke(); 
    ellipse(x, y, 5, 5);
    amt+=0.01;
    if (amt>=1) 
      amt=0.0;
  }

  void moveOnCurveWithMouseX() {
    // mouseX move
    amt=map(mouseX, 0, width, 
      0, 1); 
    x = curvePoint(cp1.x, anchor1.x, anchor2.x, cp2.x, amt); 
    y = curvePoint(cp1.y, anchor1.y, anchor2.y, cp2.y, amt);
    fill(255); // WHITE
    noStroke(); 
    ellipse(x, y, 5, 5);
    //amt+=0.01;
    //if (amt>=1) 
    //  amt=0.0;
  }

  // ---

  void testCurveData() {
    noStroke(); 
    fill(255, 0, 0); 
    ellipse (cp1.x, cp1.y, 28, 18);
    text("cp1", 
      cp1.x+15, cp1.y-8);

    noStroke(); 
    fill(255, 0, 0); 
    ellipse (cp2.x, cp2.y, 28, 18);
    text("cp2", 
      cp2.x+15, cp2.y-8);

    //-------

    noStroke(); 
    fill( 0, 0, 255); 
    ellipse (anchor1.x, anchor1.y, 28, 18);

    noStroke(); 
    fill( 0, 0, 255); 
    ellipse (anchor2.x, anchor2.y, 28, 18);
  }//method

  // ---

  void mousePressedClass() {
    if (dist(mouseX, mouseY, cp1.x, cp1.y) < 33) 
      drag=0; 
    else if (dist(mouseX, mouseY, cp2.x, cp2.y) < 33) 
      drag=1;
  }//method 

  void mouseReleasedClass() {
    drag=-1; // reset
  }

  // ---

  void drag() {
    switch (drag) {
    case 0:
      cp1.x=mouseX; 
      cp1.y=mouseY;
      break; 

    case 1:
      cp2.x=mouseX; 
      cp2.y=mouseY;
      break;

    case -1:
      //ignore
      break;
    }//switch
  }//method
  //
}//class
//

1 Like

As I’m not very screenRealState wealthy, at at first I couldn’t even find the control points on my small screen… :smiley:

UPDATE: I had a quick look. I think I know what is going on:
It is a naming & interpretation problem. The curve() interface is funny!
Do not interpret those points as control points, in the Bezier sense. They are more like “pre-anchor” and “post-anchor” control points and allow for curve continuity with a previous or next curve (if placed over the other curve’s anchor points, not outside the curve like “traditional” control points).

1 Like

Oh boy!

WTH

I was thinking bezier…

and now, the order of parameters is even different, it’s

  • anchor control control anchor…

:wink:

Thanks a ton!

1 Like

NEW bezier version

// Test for a new bezier Class that can do bezier and bezierpoint (2D) to set a color from bezierPoint y-value 

BezierClass mybezier; 

// ---------------------------------------------------------------------------------------------

void setup() {

  size(1500, 900);

  final int STANDARD_DISTANCE=100;

  mybezier = new  BezierClass (
    width/2-31, 33, // coordinates for the first point / anchor
    width/2-STANDARD_DISTANCE, height/2+STANDARD_DISTANCE, //  control point (cp1)
    width/2+STANDARD_DISTANCE, height/2+STANDARD_DISTANCE, //  control point 
    width/2+31, 33  // coordinates for the second point / anchor 
    );
}

void draw() {
  background(#24B41D);

  fill(0); 
  text("Bezier\n"
    +"Demo for Bezier y value to color\n"
    +"You can drag the two red control points (and the anchor points) with the mouse. \n"
    +"Move the mouse to move the white ball and the color on the bezier (mouseX->amt)", 
    14, 14);

  testbezier();
}

//-------------------------------------------------------------------------------------------------------

void testbezier () {
  mybezier.displaybezier();    // show entire bezier  
  mybezier.testbezierData();   // show circles with texts
  mybezier.moveOnbezierWithMouseX(); // OR moveOnbezier()
  mybezier.testlerpColor();   // lerpColor
  mybezier.drag();            // for dragging with the mouse
}

//-------------------------------------------------------------------------------------------------------

void mousePressed() {
  mybezier.mousePressedClass();
}

void mouseReleased() {
  mybezier.mouseReleasedClass();
}

// ===============================================================================================

class BezierClass {

  final int UNKNOWN = -1; 

  // bezier data 
  PVector anchor1, cp1, cp2, anchor2;

  // the amt for lerp 
  float amt=0;

  // indicates which point we drag (cp1, cp2 or anchor1 or anchor2)
  int drag = -1; 

  // the min and max y for the current bezier
  float minY, maxY; 

  // how strong the cp influences !!! Doesn't work good........
  float factorCP = 1; 

  // constr - Parameters: you call the constr as you would bezier command (2D version) - see reference
  BezierClass ( float f0, float f1, 
    float f2, float f3, 
    float f4, float f5, 
    float f6, float f7 ) {
    // constr 
    anchor1 = new PVector (f0, f1);  
    cp1     = new PVector (f2, f3);
    cp2     = new PVector (f4, f5);
    anchor2 = new PVector (f6, f7);

    setMinYAndMaxY();
  } // constr 

  // ---

  void setMinYAndMaxY () {
    // init 
    minY = 1000000; 
    maxY = -100000;
    // simulate bezier 
    for (int i = 0; i <= 100; i++) {
      float y = bezierPoint(anchor1.y, factorCP * cp1.y, factorCP * cp2.y, anchor2.y, 
        i/100.0);
      if (y<minY) 
        minY = y; 
      if (y>maxY) 
        maxY = y;
    }//for
  }

  // ---

  void displaybezier() {
    stroke(255, 0, 0); //RED 
    strokeWeight(1);
    noFill();
    bezier (
      anchor1.x, anchor1.y, 
      factorCP * cp1.x, factorCP * cp1.y, 
      factorCP * cp2.x, factorCP * cp2.y, 
      anchor2.x, anchor2.y
      );
  }

  // ---

  void moveOnbezier() {
    // AUTO move 
    // resulting point 
    float x, y; 
    x = bezierPoint(anchor1.x, factorCP * cp1.x, factorCP * cp2.x, anchor2.x, amt); 
    y = bezierPoint( anchor1.y, factorCP * cp1.y, factorCP * cp2.y, anchor2.y, amt);
    fill(255); // WHITE
    noStroke(); 
    ellipse(x, y, 5, 5);
    amt+=0.01;
    if (amt>=1) 
      amt=0.0;
  }

  void moveOnbezierWithMouseX() {
    // mouseX move
    float x, y; 
    // mouseX -> amt :
    amt=map(mouseX, 0, width, 
      0, 1); 
    // amt ->bezier point
    x = bezierPoint(anchor1.x, factorCP * cp1.x, factorCP * cp2.x, anchor2.x, amt); 
    y = bezierPoint( anchor1.y, factorCP * cp1.y, factorCP * cp2.y, anchor2.y, amt);

    //x = bezierPoint(factorCP * cp1.x, anchor1.x, anchor2.x, factorCP * cp2.x, amt); 
    //y = bezierPoint(factorCP * cp1.y, anchor1.y, anchor2.y, factorCP * cp2.y, amt);
    fill(255); // WHITE
    noStroke(); 
    ellipse(x, y, 5, 5);
  }

  // ---

  void testlerpColor() {
    // now it gets interesting 
    // mouseX to lerpColor 
    // mouseX -> amt : 
    float amt=map(mouseX, 0, width, 
      0, 1); 
    // amt -> bezierPoint Y 
    float y = bezierPoint( anchor1.y, factorCP * cp1.y, factorCP * cp2.y, anchor2.y, amt);  
    // y-value -> lerp color colorAmt
    float colorAmt = map ( y, minY, maxY, 
      0, 1  );
    // lerp color colorAmt -> color 
    fill( lerpColor(  color(255, 0, 0), color(0, 0, 255), colorAmt ) ); 
    rect (100, 100, 66, 66);

    fill(255);
    text ("min and max: " + minY+"  "+maxY 
      + " -> " +y 
      + " \ncolor amt = "+colorAmt, 100, 180);
  }

  // ---

  void testbezierData() {
    makeCircleWithText("cp1", cp1, color (255, 0, 0)) ;  
    makeCircleWithText("cp2", cp2, color (255, 0, 0)) ;  
    makeCircleWithText("anchor1", anchor1, color (0, 0, 255)) ;  
    makeCircleWithText("anchor2", anchor2, color (0, 0, 255)) ;
  }//method

  void makeCircleWithText(String txt, PVector pv, color col) {
    noStroke(); 
    fill(col);
    ellipse (pv.x, pv.y, 18, 18);

    fill(255);
    text(txt, 
      pv.x+15, pv.y-8);
  }

  // ---

  void mousePressedClass() {
    if (dist(mouseX, mouseY, cp1.x, cp1.y) < 33) 
      drag=0; 
    else if (dist(mouseX, mouseY, cp2.x, cp2.y) < 33) 
      drag=1;
    else if (dist(mouseX, mouseY, anchor1.x, anchor1.y) < 33) 
      drag=2;
    else if (dist(mouseX, mouseY, anchor2.x, anchor2.y) < 33) 
      drag=3;
  }//method 

  void mouseReleasedClass() {
    drag=UNKNOWN; // reset
    setMinYAndMaxY();
  }

  // ---

  void drag() {
    if (drag==UNKNOWN) 
      return; 

    switch (drag) {
    case 0:
      cp1.x=mouseX; 
      cp1.y=mouseY;
      break; 

    case 1:
      cp2.x=mouseX; 
      cp2.y=mouseY;
      break;

    case 2:
      anchor1.x=mouseX; 
      anchor1.y=mouseY;
      break;

    case 3:
      anchor2.x=mouseX; 
      anchor2.y=mouseY;
      break;

    case UNKNOWN:
      //ignore
      break;

    default:
      // Error
      break;
    }//switch

    setMinYAndMaxY();
  }//method
  //
}//class
//

1 Like

Why not a have a bezierVertex version?


// unfinished work 

// Test for a new bezierVertex (!) Class that can do bezierVertex (2D)

// [later: to set a color from bezierPoint y-value] 

// https://discourse.processing.org/t/how-do-i-lerp-colors-on-a-curve-not-linear-interpolation/24815

// this holds the entire curve consisting of multiple bezierVertex
EntireCurveContainer myCurveContainer; 

// ---------------------------------------------------------------------------------------------

void setup() {
  size(1500, 900);
  myCurveContainer = new  EntireCurveContainer();
}

void draw() {
  background(#24B41D);

  fill(0); 
  text("bezierVertex\n"
    +"Demo for bezierVertex\n"
    +"You can drag the control points (and the anchor points) with the mouse. \n"
    +"", 
    14, 14);

  testContainer();
}

//-------------------------------------------------------------------------------------------------------

void testContainer() {
  myCurveContainer.displayContainer();    // show entire bezier  
  //myCurveContainer.testbezierData();   // show circles with texts
  //myCurveContainer.moveOnbezierWithMouseX(); // OR moveOnbezier()
  //myCurveContainer.testlerpColor();   // lerpColor
  myCurveContainer.drag();            // for dragging with the mouse
}

//-------------------------------------------------------------------------------------------------------

void mousePressed() {
  myCurveContainer.mousePressedClass();
}

void mouseReleased() {
  myCurveContainer.mouseReleasedClass();
}

// ===============================================================================================

class EntireCurveContainer {
  PVector startPV = new PVector (50, 120); 
  boolean dragFlag=false;
  ArrayList<BezierVertexClass> listVertex = new ArrayList(); 

  // constr - Parameters: you call the constr as you would bezier command (2D version) - see reference
  EntireCurveContainer () {
    // constr 
    for (int i=0; i < 8; i++) {
      listVertex.add (
        new BezierVertexClass ( 
        84+110*i, 211, //  control point (cp1)
        84+110*i, 240, //  control point 
        84+113*i, 233+30  // coordinates for the second point / anchor

        ));
    }//for
  } // constr 

  void displayContainer() {
    stroke(255, 0, 0); //RED 
    strokeWeight(1);
    noFill();

    // show also the start point 
    makeCircleWithText("Start", startPV, color(255));

    beginShape();
    // this is mandatory - it's also draggable
    vertex(startPV.x, startPV.y);// 

    for (BezierVertexClass bvc : listVertex) {
      bvc.displayVertex();
      bvc.testbezierData();
    } 
    endShape();
  }

  void mousePressedClass() {

    if (dist(mouseX, mouseY, startPV.x, startPV.y) < 17) {
      dragFlag = true;    
      return;
    }

    for (BezierVertexClass bvc : listVertex) {
      if (bvc. mousePressedClass()) 
        return;
    }//for
  }//method 

  void mouseReleasedClass() {
    dragFlag=false; 

    for (BezierVertexClass bvc : listVertex) {
      bvc.mouseReleasedClass(); // reset
    }
  }//method

  void drag() {
    if (dragFlag) {
      startPV.set(mouseX, mouseY); 
      return;
    } 

    for (BezierVertexClass bvc : listVertex) {
      bvc. drag();
    }
  }

  void makeCircleWithText(String txt, PVector pv, color col) {
    noStroke(); 
    fill(col); 
    ellipse (pv.x, pv.y, 18, 18); 

    fill(255); 
    text(txt, 
      pv.x+15, pv.y-8);
    noFill();
    stroke(255, 0, 0);
  }
  //
}//class

//===============================================================================================================

class BezierVertexClass {

  final int UNKNOWN = -1; 

  color BezierVertexClassColor = color(random(256), random(256), random(256) ); 
  PVector  cp1, cp2, anchor1; 
  int drag=UNKNOWN; 

  // constr - Parameters: you call the constr as you would bezierVertex command (2D version) - see reference
  BezierVertexClass ( 
    float f0, float f1, 
    float f2, float f3, 
    float f4, float f5 
    ) {
    // constr 
    cp1     = new PVector (f0, f1); 
    cp2     = new PVector (f2, f3); 
    anchor1 = new PVector (f4, f5);
  } // constr

  void displayVertex() {
    bezierVertex (
      cp1.x, cp1.y, 
      cp2.x, cp2.y, 
      anchor1.x, anchor1.y );
  }//func

  void testbezierData() {
    makeCircleWithText("cp1", cp1, BezierVertexClassColor); 
    makeCircleWithText("cp2", cp2, BezierVertexClassColor); 
    makeCircleWithText("anchor1", anchor1, BezierVertexClassColor);
  }//method

  void makeCircleWithText(String txt, PVector pv, color col) {
    noStroke(); 
    fill(col); 
    ellipse (pv.x, pv.y, 18, 18); 

    fill(255); 
    text(txt, 
      pv.x+15, pv.y-8);
    noFill();
    stroke(255, 0, 0);
  }

  boolean mousePressedClass() {
    drag=-1; 
    if (dist(mouseX, mouseY, cp1.x, cp1.y) < 15) 
      drag=0; 
    else if (dist(mouseX, mouseY, cp2.x, cp2.y) < 15) 
      drag=1; 
    else if (dist(mouseX, mouseY, anchor1.x, anchor1.y) < 15) 
      drag=2;
    else return false; // no point was met, we signal false 

    // point was met, we signal success
    return true;
  }//method 

  void mouseReleasedClass() {
    drag=UNKNOWN;
  }

  void drag() {
    if (drag==UNKNOWN) 
      return; 

    switch (drag) {
    case 0 : 
      cp1.x=mouseX; 
      cp1.y=mouseY; 
      break; 

    case 1 : 
      cp2.x=mouseX; 
      cp2.y=mouseY; 
      break; 

    case 2 : 
      anchor1.x=mouseX; 
      anchor1.y=mouseY; 
      break; 

    case UNKNOWN : 
      //ignore
      break; 

    default : 
      // Error
      break;
    }//switch
  }//method
  //
}//class
// 

1 Like