Introduction
When I started coding a CAD-application program for Pocket PC, I soon found out that GDI on the Pocket PC was limited compared to ordinary Windows GDI. I was in need of drawing splines. So I tried to find a simple, easy to use algorithm on the net, but did not find anything useful.
I looked around for information on Bezier-splines since that is what GDI on Windows uses and I wanted a replacement function for that. And after reading in the book Computer Graphics by Donald Hern and M. Pauline baker, I got an understanding how Bezier-splines worked.
So how does it work?
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 float
s x
and y
. The blending functions multiplied with the control points are added to the pDstPoint
.
void BezierComputePoint(float fU, fPoint* pDstPoint, CPoint* pSrcPoints)
{
float fBlend;
float f1subu = 1.0f - fU;
fBlend = f1subu * f1subu * f1subu;
pDstPoint->x = fBlend * pSrcPoints[0].x;
pDstPoint->y = fBlend * pSrcPoints[0].y;
fBlend = 3 * fU * f1subu * f1subu;
pDstPoint->x += fBlend * pSrcPoints[1].x;
pDstPoint->y += fBlend * pSrcPoints[1].y;
fBlend = 3 * fU * fU * f1subu;
pDstPoint->x += fBlend * pSrcPoints[2].x;
pDstPoint->y += fBlend * pSrcPoints[2].y;
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]);
}
Using the code
Include the Bezier.h in your project and call the functions. Look into the example project for tips. I used PPC 2003 when testing this example but it should not be a problem with older PPC SDKs.
And that's it! Hope you find it useful. Comments and constructive criticism appreciated.
History
2005-03-15 - First release.