Wednesday, June 22, 2005

Lines with Endcaps in Windows CE (2 of 3)

Previously: Circles are expensive

It occurred to me that we might try using CreatePatternBrush() to draw the semi-circles on each end of the line. Normally a pattern brush uses a (small) bitmap to repeat a pattern, but its original use was to create a hatched bit-pattern brush.

These are like tessellations, and are the same repeating patterns that you can play with in Display Properties, Background (none), Pattern. If you've ever worked with a bit-pattern brush before you know how difficult it is drawing on a flat canvas and trying to predict how it will look like, in effect, stretched over a globe. Fortunately, preview windows usually take the guesswork out of things.

With a few lines of test code I had a sample up and running:

c_test.UpdateWindow();
CDC* pDC = c_test.GetDC();

// Create a hatched bit pattern
WORD hatchBits[8] =
   { 0x87, 0x03, 0x03, 0x03,
     0x87, 0xff, 0xff, 0xff };

// Use the bit pattern to create a bitmap
CBitmap bmp;
bmp.CreateBitmap(8, 8, 1, 1, hatchBits);

// Create a pattern brush from the bitmap
CBrush brush;
brush.CreatePatternBrush(&bmp);

// Select the brush into a device context and draw
CBrush* pOldBrush =
   (CBrush *)pDC->SelectObject(&brush);

CRect rect;
c_test.GetClientRect(&rect);
pDC->FillRect(&rect, &brush);

// Restore the original brush
pDC->SelectObject(pOldBrush);


It worked great! All I needed to do was separate the brushes into a right half and a left half and draw my line ends. I started experimenting with some more brushed lines all over the screen.

Hatched brush test
Above: the hatched brush test with the endcaps conveniently located on 8-byte boundaries

Uh oh. When I moved the start point to a physical (x,y) location that wasn't a multiple of 8 the brush drew a deformed circle. Since the glue lines could occur at any point in a carton, only drawing them in predefined spots that were multiples of 8 wasn't going to work.

I had a few more ideas, including dynamically modifying the brush depending on where it was going to be drawn. But it was too complicated a solution for this kind of problem. I tried a few more things until I was pretty convinced that I was at a dead end.

Note: At the time I didn't know there was a SetBrushOrgEx() (WinCE), which can be used to keep a pattern aligned. My ignorance serendipitously led to finding a better solution.

Next time: An unexpected solution