Bezier curve strength weight points

Hi everyone,

I have a simple bezier code here and would like to know if it is possible to give the weight point that shapes the line into a curve more weight? Let the curve be pulled closer to the point. Is there a way to get a weight value? Like I tried to mockup in this image:

Here is the simple code:

function setup() {
  createCanvas(600, 600);
  p0 = createVector(0, 300);
  p1 = createVector(300, 0);
  p2 = createVector(600, 300);
}

function draw() {
  background(0);
  strokeWeight(20);
  point(mouseX, mouseY);
  stroke(255);
  noFill();
  strokeWeight(1);
  p1.x = mouseX;
  p1.y = mouseY;

  beginShape();
  for (let t = 0; t <= 1; t += 0.01) {
    let x1 = lerp(p0.x, p1.x, t);
    let y1 = lerp(p0.y, p1.y, t);
    let x2 = lerp(p1.x, p2.x, t);
    let y2 = lerp(p1.y, p2.y, t);
    //line(x1,y1,x2, y2);
    let x = lerp(x1, x2, t);
    let y = lerp(y1, y2, t);
    vertex(x, y);
  }
  endShape();
}

1 Like

Hi @Tilman,

if you want to get the curve through your points you can use curveVertex…

Example:

ArrayList<PVector> points;

void setup() {
  size(600,300);
  
  // some points for the curve 
  points=new ArrayList<PVector>();
  points.add(new PVector(width*.5,height)); // start-Point
  points.add(new PVector(width*.5,height)); // full curve visible
  
  points.add(new PVector(width*.5,height*.75));    
  points.add(new PVector(width*.75,height*.75));
  points.add(new PVector(width*.75,height*.5));
  points.add(new PVector(width*.5,height*.5));
  points.add(new PVector(width*.25,height*.5));
  points.add(new PVector(width*.25,height*.25));
  points.add(new PVector(width*.5,height*.25));
  
  points.add(new PVector(width*.5,0)); // full curve visible
  points.add(new PVector(width*.5,0)); // end-Point
}

void draw() {
  background(0);
  
  // draw curve
  stroke(255);
  strokeWeight(2);
  noFill();
  beginShape();
  for (int i = 0; i < points.size(); i++) {
      PVector p = points.get(i);
      curveVertex(p.x, p.y);
  }
  endShape();
  
  // draw dots
  noStroke();
  fill(255,0,0);
  for (int i = 0; i < points.size(); i++) {
      PVector p = points.get(i);
      ellipse(p.x, p.y, 10, 10);
  }
}

dummy

Cheers
— mnse

1 Like

Hi @Tilman,

Sorry! just noticed, that we are in p5js here :woozy_face: :joy:

Here’s the same for p5js …

let points = [];

function setup() {
  createCanvas(600,300);
  
  // some points for the curve   
  points = [new p5.Vector(width*.5,height) // start-Point
           ,new p5.Vector(width*.5,height) // full curve visible  

           ,new p5.Vector(width*.5,height*.75)    
           ,new p5.Vector(width*.75,height*.75)
           ,new p5.Vector(width*.75,height*.5)
           ,new p5.Vector(width*.5,height*.5)
           ,new p5.Vector(width*.25,height*.5)
           ,new p5.Vector(width*.25,height*.25)
           ,new p5.Vector(width*.5,height*.25)
  
           ,new p5.Vector(width*.5,0) // full curve visible
           ,new p5.Vector(width*.5,0) // end-Point
           ];
}

function draw() {
  background(0);
  
  // draw curve
  stroke(255);
  strokeWeight(2);
  noFill();
  beginShape();
  points.forEach(p => curveVertex(p.x , p.y));
  endShape();
  
  // draw dots
  noStroke();
  fill(255,0,0);
  points.forEach(p => ellipse(p.x , p.y, 10, 10));
}

Cheers
— mnse

Thank you! @mnse
but I am seeking a way to increase the amount of curvature. Pull the curve closer to the dot. I have a specific application where I try to match a specific behavior. This is a screenshot from that app:
Bildschirmfoto 2022-11-10 um 14.42.16
and this is how it looks with my code in comparison
Bildschirmfoto 2022-11-10 um 14.54.58

I try to find out how to match the curvature from the example… It seems to be more attracted and the curve is a bit steaper towards the weight point.

Anyone an idea? Thank you!

Yes it’s possible, and the P5.Vector class offers many helpful methods to enhance the capabilities of vectors. In your original post you use vectors to save x- & y-coordinates, but you could do much more with it such as calculating its angle and magnitude. Combined with P5’s build-in bezier methods you can achieve your goal.

From the midpoint of the anchor points —which are the begin and end vectors— you can calculate the angle between the midpoint and your mouse coordinates. Your new, ‘weighted’ control point is an amplification of the magnitude between those two.

The code below is done with Processing, so you’ll have to convert it to P5 yourself.

PVector ap1; // anchor point 1
PVector ap2; // anchor point 2
PVector mid; // midpoint of anchors

void setup() {
  size(600, 600);
  ap1 = new PVector(0, height/2);
  ap2 = new PVector(width, height/2);
  mid = PVector.lerp(ap1, ap2, 0.5);
  noLoop();
  strokeWeight(2);
  noFill();
}

void draw() {
  background(0);
  stroke(#00FF00);
  point(mid.x, mid.y);
  drawBezier(#FFFFFF, calcControlPoint(1.0));
  drawBezier(#FF0000, calcControlPoint(1.4));
}

PVector calcControlPoint(float weight) {
  PVector base = new PVector(mouseX, mouseY);
  PVector diff = PVector.sub(base, mid);
  float magnitude = diff.mag() * weight;
  float angle = diff.heading();
  println("'cp' is now at an angle of", degrees(angle), "degrees towards 'mid'");  
  return PVector.fromAngle(angle).setMag(magnitude).add(mid);
}

void drawBezier(color c, PVector cp) {  
  stroke(c);
  beginShape();
  vertex(ap1.x, ap1.y);
  quadraticVertex(cp.x, cp.y, ap2.x, ap2.y);
  endShape();
}

void mouseMoved() {
  redraw();
}
3 Likes

Thank you @Tiemen! this does help me explore further!