# Why is built-in bezier function more smooth than my custom bezier function?

**URL:** https://discourse.processing.org/t/why-is-built-in-bezier-function-more-smooth-than-my-custom-bezier-function/31833
**Category:** Coding Questions
**Created:** [August 21, 2021, 9:02pm UTC](https://discourse.processing.org/t/why-is-built-in-bezier-function-more-smooth-than-my-custom-bezier-function/31833 "2021-08-21T21:02:46Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![ibrahimak](https://avatars.discourse-cdn.com/v4/letter/i/9fc348/32.png) [@ibrahimak](https://discourse.processing.org/u/ibrahimak)
#### Post date: [August 21, 2021, 9:02pm UTC](https://discourse.processing.org/t/why-is-built-in-bezier-function-more-smooth-than-my-custom-bezier-function/31833/1 "2021-08-21T21:02:46Z")

</div>

I’ve a linear interpolate function:

```auto
Vector2 linearInterpolate(Vector2 p1, Vector2 p2, float value)
{
  return p1.add(p2.sub(p1).mult(value));
}

```

I’ve quadratic bezier curve function:

```auto
Vector2 quadraticBezier(Vector2 p1, Vector2 p2, Vector2 p3, float value)
{
  Vector2 r1 = linearInterpolate(p1, p2, value);
  Vector2 r2 = linearInterpolate(p2, p3, value);
  Vector2 r3 = linearInterpolate(r1, r2, value);
  return r3;
}

```

This is my setup function:

```auto
void setup()
{
  size(900, 450);
  p1 = new Vector2(100, 100);
  p2 = new Vector2(350, 180);
  p3 = new Vector2(800, 100);
  //prevVec = linearInterpolation(p1, p2, .0f);
  prevVec = quadraticBezier(p1, p2, p3, .0f);
  strokeWeight(5);
  smooth();
  noFill();
}

```

Finally I wrote this to draw curve:

```auto
void draw()
{
  for (float i = 0; i < 1; i += 0.001f)
  {
     Vector2 tmp = prevVec;
     Vector2 p = quadraticBezier(p1, p2, p3, i);
     line(tmp.x, tmp.y, prevVec.x, prevVec.y);
     prevVec = p;
  }
}

```

I also draw bezier curve via built-in bezier function:

```auto
void draw()
{
  bezier(100, 260, 180, 340, 625, 340, 800, 260);
}

```

This is the screenshot of the curves:

 ![processing-beziers-smooth](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/5/5a180bca936fe2cd6b4aee4102916c9cc7f5926a.png)  
You can see that my custom bezier curve is not smooth but the built-in bezier function is more smooth. Why? How can I create smooth custom curve?

---

<div class="post-metadata">

### Author: ![quark](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/quark/32/26_2.png) [@quark](https://discourse.processing.org/u/quark)
#### Post date: [August 22, 2021, 7:40am UTC](https://discourse.processing.org/t/why-is-built-in-bezier-function-more-smooth-than-my-custom-bezier-function/31833/2 "2021-08-22T07:40:41Z")

</div>

I think you will find that the built in Bezier function uses a cubic Bezier curve (4 control points) whereas your implementation is a quadratic Bezier curve (3 control points).

Generally the higher the Bezier curve order (number of control points) the more ‘complex’ the curve can be. For instance a cubic curve can have a self-intersection , that is not possible with a quadratic curve. the curve

---

<div class="post-metadata">

### Author: ![ibrahimak](https://avatars.discourse-cdn.com/v4/letter/i/9fc348/32.png) [@ibrahimak](https://discourse.processing.org/u/ibrahimak)
#### Post date: [August 22, 2021, 3:39pm UTC](https://discourse.processing.org/t/why-is-built-in-bezier-function-more-smooth-than-my-custom-bezier-function/31833/3 "2021-08-22T15:39:49Z")

</div>

I wrote cubic bezier function:

```auto
Vector2 cubicBezier(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float value)
{
  Vector2 r1 = linearInterpolation(p1, p2, value);
  Vector2 r2 = linearInterpolation(p2, p3, value);
  Vector2 r3 = linearInterpolation(p3, p4, value);
  Vector2 r4 = linearInterpolation(r1, r2, value);
  Vector2 r5 = linearInterpolation(r2, r3, value);
  Vector2 r6 = linearInterpolation(r4, r5, value);
  return r6;
}

```

My draw function:

```auto
for (float i = 0; i < 1; i += 0.001f)
  {
    Vector2 tmp = prevVec;
    Vector2 p = cubicBezier(p1, p2, p3, p4, i);
    line(tmp.x, tmp.y, prevVec.x, prevVec.y);
    prevVec = p;
  }

```

But the result is same:

 ![bezier](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/c/c263cf2f5ce315a75e8f373b20b36e2525699d35.png)

---

<div class="post-metadata">

### Author: ![quark](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/quark/32/26_2.png) [@quark](https://discourse.processing.org/u/quark)
#### Post date: [August 22, 2021, 4:55pm UTC](https://discourse.processing.org/t/why-is-built-in-bezier-function-more-smooth-than-my-custom-bezier-function/31833/4 "2021-08-22T16:55:49Z")

</div>

I don’t know where you got the class `Vector2` or the implementation of the method `linearInterpolation`.

So, I have recreated the problem using the PVector class and the PVector.lerp(…) method from Processing and overlaid the two curves and got this result

 ![Screenshot 2021-08-22 at 17.46.21](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/f/f4073f8c71f1c69e522f0e9a2d4285c5a6f156ac.png)

The yellow curve is drawn using the `cubicBezier` method and the green using the `bezier` method as you can see there is no difference.

I suggest you make sure you are using the same control point coordinates for both methods.

Here is the code I used for this sketch

```auto
PVector pp1 = new PVector(100, 260), pp2 = new PVector(180, 340), 
  pp3 = new PVector(625, 340), pp4 = new PVector(800, 260);

void setup() {
  size(820, 400);
  background(200);
  noFill();
  stroke(255, 255, 130);
  strokeWeight(6);
  drawCubicCurve(pp1, pp2, pp3, pp4);
  stroke(90, 200, 90);
  strokeWeight(2);
  bezier(pp1.x, pp1.y, pp2.x, pp2.y, pp3.x, pp3.y, pp4.x, pp4.y);
}

void drawCubicCurve(PVector p1, PVector p2, PVector p3, PVector p4) {
  PVector prevP = cubicBezier(p1, p2, p3, p4, 0);
  float deltaT = 0.001;
  for (float i = deltaT; i <= 1; i += deltaT) {
    PVector nextP = cubicBezier(p1, p2, p3, p4, i);
    line(nextP.x, nextP.y, prevP.x, prevP.y);
    prevP = nextP;
  }
}

PVector cubicBezier(PVector p1, PVector p2, PVector p3, PVector p4, float value) {
  PVector r1 = PVector.lerp(p1, p2, value);
  PVector r2 = PVector.lerp(p2, p3, value);
  PVector r3 = PVector.lerp(p3, p4, value);
  PVector r4 = PVector.lerp(r1, r2, value);
  PVector r5 = PVector.lerp(r2, r3, value);
  PVector r6 = PVector.lerp(r4, r5, value);
  return r6;
}

```

---

<div class="post-metadata">

### Author: ![ibrahimak](https://avatars.discourse-cdn.com/v4/letter/i/9fc348/32.png) [@ibrahimak](https://discourse.processing.org/u/ibrahimak)
#### Post date: [August 25, 2021, 1:29am UTC](https://discourse.processing.org/t/why-is-built-in-bezier-function-more-smooth-than-my-custom-bezier-function/31833/5 "2021-08-25T01:29:22Z")

</div>

I tested your code. But the problem is not about cubic or quadratic bezier. You can see pixels of custom bezier on your picture. You also can see my picture here (Green bezier is built-in, black bezier is custom):

 ![bezier_](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/1/1d59dd2679ba0212eae68777237bb171983289de.png)  
I think built-in bezier uses a different algorithm instead of my custom bezier.

---

<div class="post-metadata">

### Author: ![quark](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/quark/32/26_2.png) [@quark](https://discourse.processing.org/u/quark)
#### Post date: [August 25, 2021, 7:05am UTC](https://discourse.processing.org/t/why-is-built-in-bezier-function-more-smooth-than-my-custom-bezier-function/31833/6 "2021-08-25T07:05:03Z")

</div>

> [@ibrahimak](#):
>
> But the problem is not about cubic or quadratic bezier.

It was in your first post. Although you can _exactly_ duplicate any quadratic curve with a cubic curve the reverse is not true.

Your original question is in the title of this post.

> Why is built-in bezier function more smooth than my custom bezier function?

The answer is -

“If there are no errors in your `Vector2` class and the `linearInterpolate` then they will produce the same curve.”

The tiny difference between the green and black lines are probably due to the number of lines used to draw the curve. In my custom method I am using 1000 lines (i.e. `1 / deltaT`). There is certainly no difference in smoothness between the 2 implementations.

---

<div class="post-metadata">

### Author: ![raron](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/raron/32/13651_2.png) [@raron](https://discourse.processing.org/u/raron)
#### Post date: [August 25, 2021, 10:39am UTC](https://discourse.processing.org/t/why-is-built-in-bezier-function-more-smooth-than-my-custom-bezier-function/31833/7 "2021-08-25T10:39:28Z")

</div>

In this case I think the answer is in the lack(?) of anti-aliasing for the renderer used (ref. [smooth()](https://processing.org/reference/smooth_.html)).  
(Provided quark’s assumtions above is correct, in that there’s no errors in your custom classes).

Still using Processing 3.5.4 btw. Maybe it’s different for the new version?

```auto
  size(820, 400, P2D);
  smooth(3); // try 2,3,4 or 8

```

Based on quarks code above I made this little test:

> **Click to (un) expand**
>
> ```auto
> /* Quadratic Bezier test 1
> 
> Based on quarks cubic Bezier
> https://discourse.processing.org/t/why-is-built-in-bezier-function-more-smooth-than-my-custom-bezier-function/31833/3
> 2021.08.25
> */
> 
> PVector pp1 = new PVector(100, 260), pp2 = new PVector(180, 340), 
> pp3 = new PVector(625, 340), pp4 = new PVector(800, 260);
> 
> PVector pc1 = new PVector(100, 100),
> pc2 = new PVector(350, 180), 
> pc3 = new PVector(800, 100);
> 
> void setup() {
> size(820, 400, P2D);
> smooth(3); // try 2,3,4 or 8
> //noSmooth();
> background(255);
> noFill();
> stroke(0);
> strokeWeight(6);
> drawQuadraticCurve(pc1, pc2, pc3);
> //stroke(90, 200, 90);
> //strokeWeight(2);
> //drawCubicCurve(pp1, pp2, pp3, pp4);
> bezier(pp1.x, pp1.y, pp2.x, pp2.y, pp3.x, pp3.y, pp4.x, pp4.y);
> }
> 
> void drawCubicCurve(PVector p1, PVector p2, PVector p3, PVector p4) {
> PVector prevP = cubicBezier(p1, p2, p3, p4, 0);
> float deltaT = 0.001;
> for (float i = deltaT; i <= 1; i += deltaT) {
> PVector nextP = cubicBezier(p1, p2, p3, p4, i);
> line(nextP.x, nextP.y, prevP.x, prevP.y);
> prevP = nextP;
> }
> }
> 
> PVector cubicBezier(PVector p1, PVector p2, PVector p3, PVector p4, float value) {
> PVector r1 = PVector.lerp(p1, p2, value);
> PVector r2 = PVector.lerp(p2, p3, value);
> PVector r3 = PVector.lerp(p3, p4, value);
> PVector r4 = PVector.lerp(r1, r2, value);
> PVector r5 = PVector.lerp(r2, r3, value);
> PVector r6 = PVector.lerp(r4, r5, value);
> return r6;
> }
> 
> void drawQuadraticCurve(PVector p1, PVector p2, PVector p3) {
> PVector prevP = quadraticBezier(p1, p2, p3, 0);
> float deltaT = 0.001;
> for (float i = deltaT; i <= 1; i += deltaT) {
> PVector nextP = quadraticBezier(p1, p2, p3, i);
> line(nextP.x, nextP.y, prevP.x, prevP.y);
> prevP = nextP;
> }
> }
> 
> PVector quadraticBezier(PVector p1, PVector p2, PVector p3, float value) {
> PVector r1 = PVector.lerp(p1, p2, value);
> PVector r2 = PVector.lerp(p2, p3, value);
> PVector r3 = PVector.lerp(r1, r2, value);
> return r3;
> }
> 
> ```

Btw what is the default renderer anyway?

I get different results from not specifying a renderer (= default), to specifying one. The default renderer doesn’t seem to have anti-aliasing at all? Yet the documentation states:

> The default renderer uses **smooth(3)** by default

FX2D doesn’t seem to care about different smooth() settings either, but it’s still a bit more smoothed than the default renderer.

P2D with smooth(4) or (8) is the best, I haven’t compared side-by-side but I don’t see much if any difference. I have a decent-ish GPU so I don’t think it’s the hardware (then again I use glasses… 😛 )

> **[size() / Reference](https://processing.org/reference/size_.html)**
>
> Defines the dimension of the display window width and height in units of pixels. In a program that has the setup() function, the size() function must be the first line of code inside …

EDIT: Slight correction: I switched up quadratic and cubic… Quark’s Bezier above is cubic, not quadratic. Reflected in code comments only, no change otherwise.  
Oh and also, I believe the default renderer is named Java2D?
