Draw a curve line using random points on the sketch.

edited January 2014 in How To...

Ok, this is kinda difficult to explain with words so I decided to come up with some graphics to explain what I'm trying to achieve:

01.- Randomly divide the sketch horizontally in uneven parts (red lines). I will use hem as x coordinates.

graphic001

02.- Randomly divide the sketch vertically in uneven parts (cyan lines). I will use them as y coordinates.

graphic002

03.- Connect the x and y coordinates using lines

graphic003

04.- This is my goal, instead of lines, I want to create a continuous curve.

graphic004

It that possible or am I daydreaming? Is there a better way to do what I want? Thanks in advance for taking your time to review this thing.

Answers

  • This is what I have at the moment:

    int numberOfSegments = 6;
    int numberOfPoints = numberOfSegments+1;
    
    PVector[] pointsArray;
    
    void setup() {
      size(800, 300);
      frameRate(30);
      smooth();
    
      pointsArray = new PVector[numberOfPoints];
      float segmentWidth = width/numberOfSegments;
      float segmentOffset = segmentWidth/4;
    
      //Set the segment position
      for (int i=0; i< numberOfPoints; i++) {
        float pointPos=segmentWidth*i;  
    
        float xPos;
        if (i==0) {
          xPos = 0;
        }
        else if (i==numberOfPoints-1) {
          xPos = width;
        }
        else {
          xPos = random(pointPos-segmentOffset, pointPos+segmentOffset);
        }
        pointsArray[i] = new PVector(xPos, int(random(0, height)));
      }
    }
    
    void draw() {
      background(100);
      noFill();
      println(pointsArray);
    
      //Draw the lines
      for (int i=0; i< numberOfPoints-1; i++) {
        line(pointsArray[i].x, pointsArray[i].y, pointsArray[i+1].x, pointsArray[i+1].y);
      }
    }
    
  • You can use the Shapes3D library (get using Sketch > Import Library > Add Library menu) to create a 2D Bezier spline from a set of points. The code below created this image.

    curve

    import shapes3d.utils.*;
    import shapes3d.animation.*;
    import shapes3d.*;
    
    P_BezierSpline curve;
    PVector[] points;
    
    int[] x = {  
      0, 110, 270, 350, 390, 530, 600
    };
    int[] y = { 
      70, 370, 40, 380, 250, 340, 230
    };
    
    public void setup() {
      size(600, 400);
      makeCurveFromPoints();
    
      background(255, 255, 240);
      stroke(0);
      strokeWeight(1.2);
    
      drawCurve(curve, 1000);
      save("curve.png");
    }
    
    public void drawCurve(P_BezierSpline c, int nbrSegs) {
      float t = 0, dt = 1.0 / nbrSegs;
      PVector curr, last = c.point(t);
      while (t < 1.0) {
        t += dt;
        curr = c.point(t);
        line(last.x, last.y, curr.x, curr.y);
        last = curr;
      }
    }
    
    public void makeCurveFromPoints() {
      points = new PVector[x.length];
      for (int i = 0; i < x.length; i ++) {
        points[i] = new PVector(x[i], y[i]);
      }
      curve = new P_BezierSpline(points);
    }
    
  • edited January 2014

    Alternatively, add the following function:

    final int delta = 25;
    void drawBezier(float x1, float y1, float x2, float y2)
    {
      bezier(x1, y1,
          x1 + delta, y1,
          x2 - delta, y2, 
          x2, y2);
    }
    

    and in your code, replace line() with drawBezier(). Not perfect (°), but a step forward.

    ° for simple inflexion points, ie. two successive descending or ascending lines.
    For these, the control points should be aligned on a line average of the two lines.

  • Wow, that was fantastic! Thanks you all for your help. I'll be expanding the script and I'll come back if I have more questions.

  • OK, here's the deal. A friend helped me to modify the sketch and use a function to create a line so the other parallel lines could be created easily. I am wondering if it's possible to shift the x position of the new lines to create a more interesting effect. This is the code at the moment:

    int numberOfSegments = 5;
    int numberOfPoints = numberOfSegments+1;
    
    PVector[] pointsArray;
    
    void setup() {
      size(800, 600);
      frameRate(30);
      smooth();
    
      pointsArray = new PVector[numberOfPoints];
      float segmentWidth = width/numberOfSegments;
      float segmentOffset = segmentWidth/4;
    
      //Set the segment position
      for (int i=0; i<numberOfPoints; i++) {
        float pointPos=segmentWidth*i;  
        float xPos;
        //Condition to indicate that the first x must be "0", and the last "width"
        if (i==0) {
          xPos = 0;
        }
        else if (i==numberOfPoints-1) {
          xPos = width;
        }
        else {
          xPos = random(pointPos-segmentOffset, pointPos+segmentOffset);
        }
        pointsArray[i] = new PVector(xPos, int(random(0, height/2)));
      }
    }
    
    void draw() {
      background(100);
      noFill();
    
      float lineDistance = 40;
      float parallelLines = 3;
    
      for (float i=0; i<parallelLines; i++) {
        createLine(i*lineDistance);
      }
    }
    
    //Function to create a line using a loop
    void createLine(float parallelOffsetY) {
      for (int i=0; i< numberOfPoints-1; i++) {
        drawBesize(pointsArray[i].x, pointsArray[i].y+parallelOffsetY, pointsArray[i+1].x, pointsArray[i+1].y+parallelOffsetY);
      }
    }
    
    //Function to draw a bezier line
    final int delta = 25;
    void drawBesize(float x1, float y1, float x2, float y2)
    {
      bezier(x1, y1, 
      x1 + delta, y1, 
      x2 - delta, y2, 
      x2, y2);
    }
    
  • Yes, call drawBezier() (there was a typo in my function definition, sorry) with an offset on x1 and x2. The offset can be an additional parameter to createLine(), for example.

  • Sorry, I didn't get that. What I want it the parallel lines to have different x position, or at least shifted a bit forward or backward. Is there any way to introduce that variant in that sketch?

  • I would make an array of offsets of same size than pointsArray. In createLine(), I would fill the array with random numbers, eg. between -3 and 3. Then, in the loop, call drawBezier() by adding pointsArray[i].x (or i+1) with the offset of same index.

  • Hmmm, I think I'm doing something wrong:

    int numberOfSegments = 5;
    int numberOfPoints = numberOfSegments+1;
    
    PVector[] pointsArray;
    PVector[] offsetArray;
    
    void setup() {
      size(800, 600);
      frameRate(30);
      smooth();
    
      pointsArray = new PVector[numberOfPoints];
      offsetArray = new PVector[numberOfPoints];
    
      float segmentWidth = width/numberOfSegments;
      float segmentOffset = segmentWidth/4;
    
      //Set the segment position
      for (int i=0; i<numberOfPoints; i++) {
        float pointPos=segmentWidth*i;  
        float xPos;
        //Condition to indicate that the first x must be "0", and the last "width"
        if (i==0) {
          xPos = 0;
        }
        else if (i==numberOfPoints-1) {
          xPos = width;
        }
        else {
          xPos = random(pointPos-segmentOffset, pointPos+segmentOffset);
        }
        pointsArray[i] = new PVector(xPos, int(random(0, height/2)));
      }
    
      //Set the offset position
      for (int i=0; i<numberOfPoints; i++) {
        float offsetPointPos=segmentWidth*i;  
        float offsetXPos;
        //Condition to indicate that the first x must be "0", and the last "width"
        if (i==0) {
          offsetXPos = 0;
        }
        else if (i==numberOfPoints-1) {
          offsetXPos = width;
        }
        else {
          offsetXPos = random(-3,3);
        }
        offsetArray[i] = new PVector(offsetXPos, int(random(0, height/2)));
      }
    }
    
    void draw() {
      background(100);
      noFill();
    
      float lineDistance = 40;
      float parallelLines = 3;
    
      for (float i=0; i<parallelLines; i++) {
        createLine(i*lineDistance);
      }
    }
    
    //Function to create a line using a loop
    void createLine(float parallelOffsetY) {
      for (int i=0; i< numberOfPoints-1; i++) {
        drawBesize(pointsArray[i].x+offsetArray[i].x, pointsArray[i].y+parallelOffsetY,
        pointsArray[i+1].x+offsetArray[i].x, pointsArray[i+1].y+parallelOffsetY);
      }
    }
    
    //Function to draw a bezier line
    final int delta = 25;
    void drawBesize(float x1, float y1, float x2, float y2)
    {
      bezier(x1, y1, 
      x1 + delta, y1, 
      x2 - delta, y2, 
      x2, y2);
    }
    
  • int numberOfSegments = 5;
    int numberOfPoints = numberOfSegments+1;
    
    PVector[] pointsArray;
    float[] offsetArray;
    
    void setup() {
      size(800, 600);
      frameRate(30);
      noLoop();
      smooth();
    
      pointsArray = new PVector[numberOfPoints];
      offsetArray = new float[numberOfPoints];
    
      float segmentWidth = width/numberOfSegments;
      float segmentOffset = segmentWidth/4;
    
      //Set the segment position
      for (int i=0; i<numberOfPoints; i++) {
        float pointPos=segmentWidth*i; 
        float xPos;
        //Condition to indicate that the first x must be "0", and the last "width"
        if (i==0) {
          xPos = 0;
        }
        else if (i==numberOfPoints-1) {
          xPos = width;
        }
        else {
          xPos = random(pointPos-segmentOffset, pointPos+segmentOffset);
        }
        pointsArray[i] = new PVector(xPos, int(random(0, height/2)));
      }
    }
    
    void draw() {
      background(100);
      noFill();
    
      float lineDistance = 40;
      float parallelLines = 3;
    
      for (float i=0; i<parallelLines; i++) {
        createLine(i*lineDistance);
      }
    }
    
    //Function to create a line using a loop
    void createLine(float parallelOffsetY) {
       //Set the offset position
      for (int i=0; i<numberOfPoints; i++) {
        offsetArray[i] = random(-5,5);
      }
    
      for (int i=0; i< numberOfPoints-1; i++) {
        drawBesize(pointsArray[i].x+offsetArray[i], pointsArray[i].y+parallelOffsetY,
        pointsArray[i+1].x+offsetArray[i+1], pointsArray[i+1].y+parallelOffsetY);
      }
    }
    
    //Function to draw a bezier line
    final int delta = 25;
    void drawBesize(float x1, float y1, float x2, float y2)
    {
      bezier(x1, y1,
      x1 + delta, y1,
      x2 - delta, y2,
      x2, y2);
    }
    
Sign In or Register to comment.