smoothcontract / mediate

Automatically exported from code.google.com/p/mediate
0 stars 0 forks source link

Spline path support #181

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
Would be good to add support for spline paths - useful for animation effects

Original issue reported on code.google.com by aretman...@gmail.com on 4 Feb 2009 at 11:06

GoogleCodeExporter commented 9 years ago
HOWTO: Using Splines to compute animation paths:

(should be easy enough to extrapolate this into 3 dimensions. Alternatively
we could use Cartmull Rom splines which are supported in DirectX:
http://www.mvps.org/directx/articles/catmull/index.htm
Cartmull Rom splines may take any no. of control points (min 4), but we
cannot calculate end positions)

The code provided uses Qubic Bezier-splines which takes four control points and
generates the curve using four blending functions:

    * f1(u) = (1 - u)³
    * f2(u) = 3u(1 - u)²
    * f3(u) = 3u²(1 - u)
    * f4(u) = u³

where 0 <= u <= 1

Below, the function that computes points in the curve is shown. fPoint is just a
struct that contains two floats x and y. The blending functions multiplied with 
the
control points are added to the pDstPoint.

void BezierComputePoint(float fU, fPoint* pDstPoint, CPoint* pSrcPoints)
{
    //

    //    Add up all the blending functions multiplied with the control points
    //
    float fBlend;
    float f1subu = 1.0f - fU;

    //

    //    First blending function (1-u)^3
    //
    fBlend = f1subu * f1subu * f1subu;
    pDstPoint->x = fBlend * pSrcPoints[0].x;
    pDstPoint->y = fBlend * pSrcPoints[0].y;

    //
    //    Second blending function 3u(1-u)^2

    //
    fBlend = 3 * fU * f1subu * f1subu;
    pDstPoint->x += fBlend * pSrcPoints[1].x;
    pDstPoint->y += fBlend * pSrcPoints[1].y;

    //
    //    Third blending function 3u^2 * (1-u)

    //
    fBlend = 3 * fU * fU * f1subu;
    pDstPoint->x += fBlend * pSrcPoints[2].x;
    pDstPoint->y += fBlend * pSrcPoints[2].y;

    //
    //    Fourth blending function u^3

    //
    fBlend = fU * fU * fU;
    pDstPoint->x += fBlend * pSrcPoints[3].x;
    pDstPoint->y += fBlend * pSrcPoints[3].y;
}

The next code snippet shows the DrawBezier function. It takes a CDC pointer as 
input,
four control points and how many segments the spline should be divided in. The 
more
segments you use, the better the result but this will take more time. So it's 
best to
experiment for the best results.

Iterate over all the segments and generate a point on the curve. Draw a line 
between
the previous point and the one computed. And at last, draw a line to the ending 
point.

void DrawBezier(CDC *pDC, CPoint *pPoints, int nSegments)
{
    pDC->MoveTo(pPoints[0]);
    fPoint fPointBezier;
    for(int i = 0; i < nSegments; i++)
    {
        BezierComputePoint(i / (float)nSegments, &fPointBezier, pPoints);
        pDC->LineTo(ROUND(fPointBezier.x), ROUND(fPointBezier.y));
    }
    pDC->LineTo(pPoints[3]);
}

Original comment by aretman...@gmail.com on 4 Feb 2009 at 11:07