Coffeehouse Thread

15 posts

Can someone check my math?

Back to Forum: Coffeehouse
  • User profile image
    Minh

    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?

    Generic Forum Image

    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;
    }
    

  • User profile image
    Maddus Mattus

    BRIAAAAAAAAAN!!! HELP!! Smiley

  • User profile image
    magicalclick

    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.
    Last modified
  • User profile image
    Tokter

            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);
            }

  • User profile image
    Minh

    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

  • User profile image
    Minh

    Tokter,

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

    Generic Forum Image

    Can you point me to how you worked that out?

  • User profile image
    magicalclick

    , 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.
    Last modified
  • User profile image
    Minh

    @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

  • User profile image
    magicalclick

    , 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.
    Last modified
  • User profile image
    Tokter

    , Minh wrote

    Tokter,

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

    Generic Forum Image

    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

  • User profile image
    Adam​Speight2008

    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");
      }
    }
    

     

  • User profile image
    Tokter

    @AdamSpeight2008:

     

    (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

  • User profile image
    Minh

    @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

  • User profile image
    Minh

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

  • User profile image
    magicalclick

    , 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.
    Last modified

Comments closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums, or Contact Us and let us know.