foumula: Define nice Bezier from 2 anchor points?

edited March 2015 in How To...

Hello all,

I am looking for a universal formula to draw a nice Bezier for any 2 given anchor points (a1 and a2).

How can I calculate the control points in a way, that my curve always looks cool and compact?

It should look good no matter if a1 is above or under a2 or next or right from it...

Here is my approach- thank you all!

Chrisir ;-)

void setup() {
  size(600, 500);
  background(0);
  stroke(255, 0, 0);
}

void draw() {

  background(0);

  // anchors 
  PVector a1=new PVector(mouseX, mouseY); 
  PVector a2=new PVector(200, 200);

  drawBezier (a1, a2);
}

void drawBezier( PVector a1, PVector a2 ) {

  // control points 
  PVector c1, c2; 

  int offSet = 160;  

  // detect the positon of both anchors to each other.
  if (abs(a1.x-a2.x) > abs(a1.y-a2.y)) {
    // they are more next to each other (left right - )
    // control points 
    c1=new PVector((a1.x+a2.x)/2, giveYValue(a1.y, a2.y, offSet) ) ;
    //  c2=new PVector(c1.x, c1.y);
  } else {
    // the are more above each other (more | )  
    // control points 
    c1=new PVector(  giveYValue(a1.x, a2.x, offSet), (a1.y+a2.y)/2);
    //  c2=new PVector(c1.x, c1.y);
  }  

  c2=new PVector( 0, 0 ); 
  // c2=new PVector( giveYValue(a2.x, a1.x, offSet), giveYValue(a2.y, a1.y, offSet) );

  if (true) {
    if (a1.x<a2.x) 
      c2.x = c1.x+120;
    else 
      c2.x = c1.x-120;

    if (a1.y<a2.y) 
      c2.y = c1.y+120;
    else 
      c2.y = c1.y-120;
  }

  if (false) {
    if (a1.x<a2.x) 
      c1.x = a1.x-30;
    else 
      c1.x = a2.x-30;

    if (a1.y<a2.y) 
      c1.y = a1.y-30;
    else 
      c1.y = a2.y-30;

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

    if (a1.x<a2.x) 
      c2.x = a1.x-30;
    else 
      c2.x = a2.x-30;

    if (a1.y<a2.y) 
      c2.y = a1.y-30;
    else 
      c2.y = a2.y-30;
  }

  noFill();
  bezier( 
  a1.x, a1.y, 
  c1.x, c1.y, 
  c2.x, c2.y, 
  a2.x, a2.y );
}
//
float giveYValue(float a1, float a2, float offSet) {
  // we want buffer **outside** the span of a1 and a2
  // and we want c1 be nearer to a1
  // so this function is for c1 only when you give the params as a1,a2.
  //                     for c2 give them as a2,a1. 
  float buffer;
  if (a1<a2)  
    buffer = a1-offSet;
  else
    buffer = a1+offSet;
  return buffer;
}

//

Zwischenablage02aaaaaaaaa

Tagged:

Answers

  • Compact: just a straight line... But it wouldn't be "cool".
    Of course, you can draw an infinity of Bézier lines between two points. But most of them wouldn't be cool nor compact... :-)

    More seriously, a quick idea is to compute the horizontal and vertical distances between the points / shapes. If one of them is zero, just draw a straight line. Otherwise, if width is bigger than height, compute two horizontal control vectors (ie. control points are just a move on x from the start point); otherwise, use vertical vectors.

  • OK, interesting challenge worth spending a quarter hour on it... :-)

    final float FACTOR = 0.5;
    
    void setup()
    {
      size(600, 500);
      background(255);
      stroke(255, 200, 120);
      strokeWeight(3);
      noFill();
    }
    
    void draw()
    {
      background(255);
    
      // anchors
      PVector a1 = new PVector(mouseX, mouseY);
      PVector a2 = new PVector(width / 2, height / 2);
    
      drawBezier (a1, a2);
    }
    
    void drawBezier(PVector a1, PVector a2)
    {
      float w = a2.x - a1.x;
      float h = a2.y - a1.y;
    
      if (abs(w) < 4 || abs(h) < 4)
      {
        line(a1.x, a1.y, a2.x, a2.y);
        return;
      }
    
      PVector c1 = new PVector();
      PVector c2 = new PVector();
      if (abs(w) > abs(h))
      {
        c1.x = a1.x + FACTOR * w;
        c1.y = a1.y;
        c2.x = a2.x - FACTOR * w;
        c2.y = a2.y;
      }
      else
      {
        c1.x = a1.x;
        c1.y = a1.y + FACTOR * h;
        c2.x = a2.x;
        c2.y = a2.y - FACTOR * h;
      }
    
      bezier(
        a1.x, a1.y,
        c1.x, c1.y,
        c2.x, c2.y,
        a2.x, a2.y 
      );
    }
    

    As said, it is only a few possibilities, you can adjust the formulae and algorithm to fit your tastes.

  • edited March 2015 Answer ✓

    Rewritten properly using PVector operations... Compacter, cleaner code.

    final float FACTOR = 0.5;
    
    void setup()
    {
      size(600, 500);
      background(255);
      stroke(255, 200, 120);
      strokeWeight(3);
      noFill();
    }
    
    void draw()
    {
      background(255);
    
      // anchors
      PVector a1 = new PVector(mouseX, mouseY);
      PVector a2 = new PVector(width / 2, height / 2);
    
      drawBezier (a1, a2);
    }
    
    void drawBezier(PVector a1, PVector a2)
    {
      PVector delta = PVector.sub(a2, a1);
      float w = delta.x;
      float h = delta.y;
    
      PVector c1 = a1.copy();
      PVector c2 = a2.copy();
      if (abs(w) > abs(h))
      {
        c1.add(FACTOR * w, 0, 0);
        c2.add(-FACTOR * w, 0, 0);
      }
      else
      {
    
        c1.add(0, FACTOR * h, 0);
        c2.add(0, -FACTOR * h, 0);
      }
    
      bezier(
        a1.x, a1.y,
        c1.x, c1.y,
        c2.x, c2.y,
        a2.x, a2.y 
      );
    }
    
  • Thank you so much!

    The curve looks great!

    Hope this helps others too....

  • edited March 2015

    And here's your tweaked version: :-bd

    // forum.Processing.org/two/discussion/9638/
    // foumula-define-nice-bezier-from-2-anchor-points
    
    // 2015/Mar/01 by PhiLho
    
    static final float FACTOR = .5;
    
    final PVector p1 = new PVector(), p2 = new PVector();
    final PVector q1 = new PVector(), q2 = new PVector();
    
    void setup() {
      size(600, 500, JAVA2D);
      frameRate(60);
      smooth(4);
      noFill();
      stroke(255, 200, 120);
      strokeWeight(3);
    }
    
    void draw() {
      background(-1);
      p1.set(mouseX, mouseY);
      p2.set(width>>1, height>>1);
      drawBezier(p1, p2, q1, q2);
    }
    
    void drawBezier(PVector a1, PVector a2, PVector b1, PVector b2) {
      float w = a2.x - a1.x, ww = abs(w);
      float h = a2.y - a1.y, hh = abs(h);
    
      if (ww < 4 | hh < 4) {
        line(a1.x, a1.y, a2.x, a2.y);
        return;
      }
    
      b1.set(a1);
      b2.set(a2);
    
      if (ww > hh) {
        b1.x += FACTOR * w;
        b2.x -= FACTOR * w;
      } else {
        b1.y += FACTOR * h;
        b2.y -= FACTOR * h;
      }
    
      bezier(
      a1.x, a1.y, 
      b1.x, b1.y, 
      b2.x, b2.y, 
      a2.x, a2.y);
    }
    
  • thanks a lot...

    nice...

Sign In or Register to comment.