Given two points (vectors), plot a 3rd so all three can be bisected by a straight line

Hi,

I have small issue with creating linked beziers in that the link between each bezier is not that smooth. I'm using bezierVertex to draw the connected beziers.

What I'm trying to do is smooth out this join, and from what I understand I need to do the following "In order to make two curves A and B smoothly continuous, the last control point of A, the last point of A, and the first control point of B have to be on a straight line."

So, given two vectors like so;

function setup() {
    createCanvas(windowWidth, windowHeight);
    background(255);
    noLoop();

    rectMode(CENTER);


    var v1 = createVector(random(200, 300), random(200, 300));
    var v2 = createVector(random(100, 400), random(300, 400));

    ellipse(v1.x, v1.y, 20, 20);
    ellipse(v2.x, v2.y, 20, 20);


    var angle = p5.Vector.angleBetween(v1, v2);

    console.log(angle, radians(angle));

    ellipse( 200 * sin(angle) , 200 * cos(angle), 30, 30);
}

I want to be able to plot the 3rd, so that I can set the control point of the next bezier in my in a straight line, and smooth the bezier connection point.

Thanks in advance.

First time using p5. I'm converting an old Director project as a learning exercise. The Director version looks like this; https://goo.gl/photos/K6zmabEyPUgTsmYMA

Answers

  • It would help if your example draw a curve. And then you want that curve to continue to another point? I'm confused about which points you want as endpoints and which you want as control points.

    Here is a bezier curve with dragaballs to play with in the meantime.

    class DragaBall {
      int x, y, r;
      color c;
      boolean grabbed;
      DragaBall(int _x, int _y, color _c) {
        x=_x;
        y=_y;
        c=_c;
        r = 10;
        grabbed = false;
      }
      boolean isOver() {
        return( dist( mouseX, mouseY, x, y) < r );
      }
      void draw() {
        // Grabbed but nothing is held, release it.
        if ( grabbed && !mousePressed ) {
          grabbed = false;
        }
        // Otherwise it's where the mouse is.
        if ( grabbed ) {
          x = mouseX;
          y = mouseY;
        }
        // Keep it on the grid too.
        x = constrain(x, r, width-r);
        y = constrain(y, r, height-r);
        // Actually draw it.
        fill(c);
        noStroke();
        ellipseMode(CENTER);
        ellipse(x, y, 2*r, 2*r);
      }
      void mouseDown() {
        if ( isOver() ) {
          //// Clone balls instead by uncommenting.
          //if( !grabbed ){
          //   dragaballs.add( new DragaBall( x, y, c ) );
          //}
          grabbed = true;
        }
      }
    } 
    
    DragaBall e0 = new DragaBall(200, 200, color(255, 0, 0));
    DragaBall e1 = new DragaBall(400, 200, color(255, 0, 0));
    DragaBall c0 = new DragaBall(300, 100, color(0, 255, 0));
    DragaBall c1 = new DragaBall(300, 300, color(0, 0, 255));
    
    void setup() {
      size(600, 400);
      strokeWeight(2);
    }
    
    void draw() {
      background(0);
      stroke(0,128,0);
      line(e0.x, e0.y, c0.x, c0.y);
      stroke(0,0,128);
      line(e1.x, e1.y, c1.x, c1.y);
      stroke(255);
      noFill();
      bezier(e0.x, e0.y, c0.x, c0.y, c1.x, c1.y, e1.x, e1.y);
      e0.draw();
      e1.draw();
      c0.draw();
      c1.draw();
    }
    
    void mousePressed() {
      e0.mouseDown();
      e1.mouseDown();
      c0.mouseDown();
      c1.mouseDown();
    }
    

    (Uses Processing, not P5.js!)

  • edited March 2017

    Hi,

    Sorry, I took out the curve drawing, as I thought that would complicate things.

    Basically I'm trying to do what is mentioned here;

    https://processing.org/tutorials/curves/

    At the bottom of the page, an example is given for drawing two joined beziers, and then again, with a solution for an uneven join where the first bezier connects to the next in the sequence.

    I have the bezier line drawing all complete, its just getting a solution to make the connection between the beziers smooth. Which is basically finding the angle between 2 points, and being able to plot a 3rd point further along that same line. As illustrated below;

  • edited March 2017

    Seems that lerp() with a number larger than 1 does basically what I'm after.

    function setup() {
        createCanvas(windowWidth, windowHeight);
        background(255);
        frameRate(30);
    
        rectMode(CENTER);
    
    
        var v1 = createVector(random(200, 300), random(200, 300));
        var v2 = createVector(random(100, 400), random(300, 400));
    
        ellipse(v1.x, v1.y, 20, 20);
        ellipse(v2.x, v2.y, 20, 20);
    
        var v3 = p5.Vector.lerp(v1, v2, 1.5);
    
        ellipse( v3.x , v3.y, 30, 30);
    }
    
  • edited March 2017

    @ noponies , very interesting
    When I read your title I immediately thought lerp(),
    Then I read your question and thought it only worked between points, so you taught me something new.
    Can you also test what happens with negative values?
    It seems to also lerp the other way for negative number which I hoped it would.

  • Yeah, I was surprised it worked with numbers great that 1. Not in the docs.

  • @noponies -- glad that PVector.lerp() solved your problem.

    For clarity reading the code or for a tutorial on the concept, it would also be intuitive to me to implement that PVector.lerp() as a series of vector operations -- for example, subtract, multiply, then add:

    1. vScale = PVector.sub(v1,v2) (to create a relative vector between the two points) https://processing.org/reference/PVector_sub_.html
    2. vScale.mult() (to scale that relative vector any arbitrary distance)
    3. PVector.add() (to add the scaled relative vector to point v1

    ...thus finding any new point(s) along the line v1-v2 (with mult 0-1) or beyond the line (with mult 1+).

    In other words, given a line v1-v2, find a new point v3 at a scaling factor m along that line by: v3 = v1 + m*(v2-v1)

Sign In or Register to comment.