15 posts

## Can someone check my math?

Back to Forum: Coffeehouse
• Edit: Added Translate function, fixed parameters

Hey, I'm trying to implement the cubic bezier curve for an animation, I found the definition below from wikipedia, can someone validate this for me?

```public float CubicBezier(float t, PointF p0, PointF p1, PointF p2, PointF p3)
{
if (t < 0 || t > 1) throw new ArgumentException();
PointF b =
Translate(
Scale(Power(1 - t, 3), p0),
Scale(3 * Power(1 - t, 2) * t, p1),
Scale(3 * (1 - t) * Power(t, 2), p2),
Scale(Power(t, 3), p3)
);
return b.Y;
}

public float Power(float n, float p)
{
double v = Math.Pow((double) n, (double) p);
return Convert.ToSingle(v);
}

public PointF Scale(float f, PointF p)
{
PointF ps = new PointF();
ps.X = p.X * f;
ps.Y = p.Y * f;
return ps;
}

public PointF Translate(params PointF[] ps)
{
PointF pt = new PointF();
foreach (PointF p in ps)
{
pt.X = pt.X + p.X;
pt.Y = pt.Y + p.Y;
}
return pt;
}
```

• BRIAAAAAAAAAN!!! HELP!!

• Shouldn't your return value a point? like return b?

Also I would think it is better doing it recursively? I mean, this way you can support higher order curves and the calculation is much more straight forward.

Leaving WM on 5/2018 if no apps, no dedicated billboards where I drive, no Store name.
• ```        public PointF CubicBezier(float t, PointF p0, PointF p1, PointF p2, PointF p3)
{
float cx = 3 * (p1.X - p0.X);
float bx = 3 * (p2.X - p1.X) - cx;
float ax = p3.X - p0.X - cx - bx;
float cy = 3 * (p1.Y - p0.Y);
float by = 3 * (p2.Y - p1.Y) - cy;
float ay = p3.Y - p0.Y - cy - by;
float tCubed = t * t * t;
float tSquared = t * t;
float resultX = (ax * tCubed) + (bx * tSquared) + (cx * t) + p0.X;
float resultY = (ay * tCubed) + (by * tSquared) + (cy * t) + p0.Y;
return new PointF(resultX, resultY);
}```

• I like Tokter's solution. The reason I only return the Y value is that I assume X = t. Maybe that won't be the case. I'll have to play around to check.

Thanks everybody

• Tokter,

Looking more into it, your routine isn't a direct reflection of this formula:

Can you point me to how you worked that out?

• , Minh wrote

I like Tokter's solution. The reason I only return the Y value is that I assume X = t. Maybe that won't be the case. I'll have to play around to check.

Thanks everybody

Nope, t is from 0 to 1, not X.

The easy solution is,

private Point InBetweenAB(double t, Point A, Point B)
{
return new Point((1 - t) * A.X + t * B.X, (1 - t) * A.Y + t * B.Y);
}
private Point[] OneLessOrder(double t, Point[] points)
{
Point[] result = new Point[points.Length - 1];

for (int i = 0; i < result.Length; i++)
result[i] = InBetweenAB(t, points[i], points[i + 1]);

return result;
}
public Point MultiCurve(double t, Point[] points)
{
if (points==null || points.Length <= 0)
return null;
Point[] result = points;
while (result.Length > 1)
result = OneLessOrder(t, result);
return result[0];
}

Ok, this is strange, the insert code block doesn't work. I am using your own code block and pasted my code. So, the line number maybe off. (that also doesn't work). So, I am just having the text here.

this should do it.

obviously slower, but, it works for any number of control points. And the code is quite brainless.

Leaving WM on 5/2018 if no apps, no dedicated billboards where I drive, no Store name.
• @magicalclick, Ah, I see. I'm framing the points inside (0,0) and (1,1) anyways, so I could use t as X, but I can see how that's confusing.

I'm not sure your code displayed in its entirity

• , Minh wrote

@magicalclick, Ah, I see. I'm framing the points inside (0,0) and (1,1) anyways, so I could use t as X, but I can see how that's confusing.

I'm not sure your code displayed in its entirity

In your case, x = t IFF the points for X direction are monotonically increasing at exact same speed. Meaning your points needs to be,

Point1 X = 0

Point2 X = 0.3333333

Point3 X = 0.6666666

Point4 X = 1

otherwise the speed of the animation along X axis will be whacky. Also if you have Point 3 X = 1 and Point4 X = 0.66666, then, your path will be wrong.

..........

You meaning you didn't see my code? I can see it on my PC. Didn't test out my code, but, should work.

Leaving WM on 5/2018 if no apps, no dedicated billboards where I drive, no Store name.
• , Minh wrote

Tokter,

Looking more into it, your routine isn't a direct reflection of this formula:

Can you point me to how you worked that out?

First you get the extended form of your formula http://www.wolframalpha.com/input/?i=%281-t%29%5E3*P0%2B3*%281-t%29%5E2*t*P1%2B3*%281-t%29*t%5E2*P2%2Bt%5E3*P3:

-P0*t^3 + 3*P0*t^2 - 3*P0*t + P0 + 3*P1*t^3 - 6*P1*t^2 + 3*P1*t - 3*P2*t^3 + 3*P2*t^2 + P3*t^3

Then you factorize for t^3, t^2 and t

t^3(-P0 + 3*P1 - 3*P2 + P3) + t^2(3*P0 - 6*P1 + 3*P2) + t(3*P1 - 3* P0) + P0

then you substitute:

c = 3*(P1 - P0)
b = 3*(P2 - P1) - c
a = P3 - P0 - c -b

And you get:

`B(t) = (a * t^3) + (b * t^2) + (c * t) + P0`

• Isn't it something like the following C#

```PointF B(double t,PointF P0, PointF P1, PointF P2, PointF P3)
{
return New PointF(B(t, P0.X, P1.X, P2.X, P3.X),B(t, P0.Y, P1.Y, P2.Y, P3.Y))
}

double B(double t,double P0, double P1,double P2, double P2)
{
if( 0 <= t && t <= 1)
{
double a = (1 - t);
double b = 3 * a;
return (a^3 * P0) + (b^2 * t * P1) + (b * t^2 * P2) + (t^3 * P3);
} else
{
throw new ArgumentOutOfRangeException("t");
}
}
```

•

(b^2 * t * P1):

b^2 = (3*(1-t))^2 = 9(1-t)^2 instead of 3(1-t)^2

so it should be (3 * a^2 * t * P1) imho

• @magicalclick:You meaning you didn't see my code? I can see it on my PC. Didn't test out my code, but, should work.

Oh I see the code now... I was confused about how OneLessOrder and MultiCurve relate to the Bezier

• @Tokter, I'll take your word for it lol Wolfram Alpha couldn't figure it out without a pro account

• , Minh wrote

@magicalclick:You meaning you didn't see my code? I can see it on my PC. Didn't test out my code, but, should work.

Oh I see the code now... I was confused about how OneLessOrder and MultiCurve relate to the Bezier

Oh that, as you can see, you can have K level of control points, OneLessOrder just reduce the level by 1. You keep doing it until the level is 1. That's how Bezier Curve works at its most basic form.

Leaving WM on 5/2018 if no apps, no dedicated billboards where I drive, no Store name.