Monday, June 27, 2005

Lines with Endcaps in Windows CE (3 of 3)

(We now return to our regularly scheduled programming. I believe we were still in February discovering lines with endcaps...)

Previously: Hatched brushes worked great...every 8th pixel

After flailing about for a while I discovered polygons. That isn't to say I'd never heard of Archimedes and triangles before, I just hadn't thought about his work in terms of my problem.

And the problem was easy, too. In any line that had a fixed width, the shape of the line was merely a Polygon() with its end vertices shaped to look like semi-circles.

Pixel-level polygon
Above: a 5-pixel high polygon on your monitor under an electron microscope

To break it down even farther (at a pixel-level) a "rounded glue line" was just a Polyline() where the lines in the middle extended a pixel or two past the lines at the top and bottom, like a snaking connect-the-dots viewed from across the room.

Pixel-level polyline
Above: Refocusing our massive scanning electron microscope on a 5-pixel high polyline instead

Having two equally promising prospects meant putting both to the test. I set up a simple test of my idea, the meat of which is listed below:


DrawGlueLine(...) {

if (m_polygon)

polyPts[0].x = rect.left+1; polyPts[0].y =;
polyPts[1].x = rect.right-1; polyPts[1].y =;
polyPts[2].x = rect.right; polyPts[2].y =;
polyPts[3].x = rect.right; polyPts[3].y =;
polyPts[4].x = rect.right-1; polyPts[4].y =;
polyPts[5].x = rect.left+1; polyPts[5].y =;
polyPts[6].x = rect.left; polyPts[6].y =;
polyPts[7].x = rect.left; polyPts[7].y =;

pDC->Polygon(polyPts, nCount);
polyPts[0].x = rect.left+1; polyPts[0].y =;
polyPts[1].x = rect.right-1; polyPts[1].y =;
polyPts[2].x = rect.right; polyPts[2].y =;
polyPts[3].x = rect.left; polyPts[3].y =;
polyPts[4].x = rect.left; polyPts[4].y =;
polyPts[5].x = rect.right; polyPts[5].y =;
polyPts[6].x = rect.right; polyPts[6].y =;
polyPts[7].x = rect.left; polyPts[7].y =;
polyPts[8].x = rect.left+1; polyPts[8].y =;
// Polyline draws up to the last x-pixel - 1, so
// draw 1 pixel farther
polyPts[9].x = rect.right; polyPts[9].y =;

pDC->Polyline(polyPts, nCount);

Under the emulator, both polylines and polygons drew equally well (and equally fast). But when I ran the demo on the physical device the polylines blew the polygons away. I suspect it was for two reasons: the polygon fill was slow, and the polyline optimized itself to draw five lines instead of the nine I plotted. (Four of the nine lines are just "steps" to the next level. They have an effective length of zero.)

Also, the lines were extremely fast. On the actual device I drew 480 polylines every redraw no slower than drawing as many normal lines. Flexible these lines were not. But flexibility wasn't one of the original requirements. I needed lines that would look like a line of glue and draw extremely fast. On both those counts this solution fit the bill.

Moral of the story: I knew that I would have to go outside my toolbox to solve the problem, but I didn't know that my screwdriver would make an excellent wrench, so to speak. It turned out that it wasn't noticeably slower to draw nine (or five) lines that appeared to look like a line with circle endcaps than to draw one plain line.

I also benefited from simplifying the problem. I didn't need to draw a line at an arbirtrary width with circles of an arbirtrary radius on each end. I just needed to draw a specific-sized line. And for my specific problem I found a specific solution. (eVC 4.0 project compiled for 4.2 standard SDK)

Sunday, June 26, 2005


When I started writing here I told myself that this would be a work-only blog. If I wanted to write anything personal, I thought, I would do it in another blog, and not under a pseudonym. In that regard, I've been about as successful as the Chicago Cubs at the World Series. But some things are as important in the history of this project as any technical detail, and this record would be less of one for not having included them.

So fast-forwarding for a moment to the present, today in real life marks the sixth anniversary of my marriage to Antonia, a beautiful woman that I don't deserve to have. Five other anniversaries have come and gone, and I wonder what compels me to write this on our sixth.

What compels me is that I love her.

When I was a child, I would ask my parents how they knew that they had found "the right one." I'm not sure why I wondered about those things, but I did. The unsatisfactory answer that I always received was that "they just knew." Unhappy with their response, I would usually ponder it for a few seconds, then go play with my Legos.

It wasn't until I met Antonia I understood what they meant. I didn't understand it right away, but when the time came that I was free of any logical or emotional reasons why I should choose to spend the rest of my life with her—and there were many—I came to the place where I just knew. She was pretty, she was a lady, she was smart and she was the cutest thing in the world. But apart from that, I knew that I needed to spend the rest of my life with this woman.

Of all the choices that I've made, very few have been choices that set my life's course. It's comforting to know that the important decisions have been accompanied by the calm confidence of knowing that it they were the right decisions.

Antonia, you are not only the best thing that has ever happened in my life, you are the best thing that will ever happen in my life. I sometimes think that if you hadn't come across me, you would've been just fine. But if I hadn't found you, I would still be lost—a ship without a course, or a rudder to steer by even if it had one.

I'm glad to have found you, glad to see where we're headed, glad that our anchors are weighed and our course is set. There's no one I'd rather sail this voyage with but you, and nowhere I'd rather go than where you are.

Forever your love,

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:

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;

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

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

// Restore the original brush

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

Keeping the Home Fires Burning

I'd be remiss not to mention the support system that kept me going till this point in the Oswald Project. Some might say that I'm doing too much "mentioning" of things non-technical, but I'll return to the esoteric details of CE development soon enough. There will always be more software projects; these are the things that are important.

When I was unmarried and my only bills worth mentioning were car insurance and gas, I was happy to work long hours for the sake of working. The reward of a good job to me was to have done it well. Sometimes I even pulled all-nighters at work for no apparent reason other than that the work was there to do, and I liked to do it. (Dick Buckzan, a machinist who starts his day at an ungodly hour, still laughs at me about coming in one morning and finding me slumped over my keyboard at my desk.)

A decade later my “lifescape” has widened from a narrow slice of the spectrum to a panorama of responsibilities. I'm blessed and fortunate to have wooed a wonderful wife, found a nice home and fathered a beautiful son (his brother is on the way). But these blessings are also responsibilities, and in the workplace that translates into less hours in order to lead a more balanced life.

With the Oswald Project, that changed. I was thrust into a schedule that would've been unsustainable by myself.

My savior was Antonia. Despite working part-time as an accountant in tax season, she made the time to bring me lunches and dinners. She kept the household running and did the job of two parents. I don't know how she found the time to do it all.

She became a den mother to my team, well known around the office for arriving bundled with dinner, drinks and a child in tow. George and Ted enjoyed her company, and her presence always lowered our stress level a notch or two. Later, when we discovered the joy of working on our laptops in my living room with a crackling fire and wireless internet access1, she made sure that the area was always clean and work-ready.

It's rare to see the man who receives a lifetime award who doesn't think his wife, family and those around him who made his accomplishments possible. Without support systems like those it's infinitely harder to accomplish much at all. I'm not winning any awards or recognition, but even in my small corner of the world, my small achievements are due in no small part to those that I rely on.

Thanks, Antonia. There's no one I'd rather rely on than you.

[1] The CE emulator using the TCP/IP transport requires an IP address to communicate with eVC/Platform Manager. This means either being online or installing a loopback adapter.

Thursday, June 09, 2005

To De-Feature or Not

Worked continued at a frenetic pace through February, although it became more apparent at the end of each day there were less days remaining than the amount of work. Still, we pushed forward with our double-shift days.

I found some solace, oddly, in winning trinkets on eBay auctions. At least it took my mind off of other things for a few minutes. The actual thrill was probably more in bidding at the last second than in buying anything. I sniped in with two seconds left and won a weather station (thermometer, barometer, hydrometer). It arrived with the dials permanenty set to 74° F, 30.5 inches and 30% humidity. But it looked nice so I hung it on the wall anyway. My auctioneering activities won me a reminder from Antonia that such pursuits had a very low wife acceptance factor.

Around mid-month even the most optimistic of the project backers could see the writing on the wall, so a meeting was called to de-feature the program for a workable, but not as comprehensive, demo. Victor asked the most senior engineer, a 20-year employee, to sit in on the meeting and help make the difficult decisions.

I made up a list of about 65 major features that we were working on and asked everyone which ones we should pull out for the demo. We went over nearly every one, and each time someone voiced a reason why that particular feature should stay in.

Me: Okay, how about Shuttle Test on the Microwave sensor screen
Someone 1: Oh, no. We need that if we're going to have Microwave.
Someone 2: If we pull that out we'd have to pull out Activate Shuttle as well.
Someone 1: Yeah, we can't do that.
Me: Okay, we'll leave it in. How about Tolerance on the Pattern screens?
Someone 3: Wait, we can't pull that out!
Et cetera.

About an hour and a half later, we ended the meeting. We had pulled out exactly two and a half features.

Still, timelines and features aside, I thought the project was looking up. Some major pieces were starting to fit together and we were making very good progress. We still weren't going to be anywhere close to our deadline, but we were making progress.

Lines with Endcaps in Windows CE (1 of 3)

I believe that two things are important in any craft: having good tools, and knowing how to use your tools. Having good tools means that you won't spend needless amounts of time doing things the hard way. And knowing your tools means that you know which tool is the right tool for which job. It also means that when none of the tools in your toolbox is the right one, it's time to improvise.

Microsoft Windows CE .NET: Windows CE does not support user-specified endcap styles, such as PS_ENDCAP_ROUND.

Messages like this are a pretty good indicator that it's time to go outside of the toolbox. (For some reason it's also a great motivator for me; nothing gets my creative juices going like someone telling me they don't think I can do it.)

So I set about coming up with alternative. We were looking for a way to show glue lines. They needed to look like glue lines, and they needed to draw very quickly. In a worst-case scenario, we were drawing 24 patterns x 20 events per pattern = 480 lines, several times per second.

We could've showed a glue pattern with a simple thick line Plain line, but a line with an endcap Line with round endcaps looks much closer to what a bead of glue actually looks like. It shouldn't be very hard, I thought. A round endcap is simply a half-circle at the end of each line. Breakdown of line with round endcaps Even simpler, since CE doesn't support drawing arcs, a round endcap was simply a full-circle at the end of each line.

I wrote up a DrawGlueLine() function for our main dialog class to include two circles at the each end of a filled rectangle as the dimensions for a line.

Unfortunately, drawing circles is computationally expensive, and the performance was nowhere close to being fast enough. I considered other algorithms. The Abrash/Hardenbergh integer-only circle algorithm draws circles much more quickly, but implementing an x86 assembly (which I'm not very good at) routine just to draw endcaps seemed like overkill.

So, it was back to the drawing board. At least we knew what didn't work. As Thomas Edison told a reporter in 1879, "I have not failed 5,000 times. I have successfully discovered 5,000 ways that do not work and I do not need to try them again."

We had found way #1 that did not work.

Next time: Simplyfing the problem and trying again

Monday, June 06, 2005

Meetings on Meetings

The next day Victor held an early meeting about the project. He wanted to know what our day's plans were and if we had any obstacles. Then we talked about other parts of the program. And then we talked about future features, and things that we might do sometime in the future. Two hours later we were ready to get started on the day.

The next day we had another meeting, and the day after that. Over the course of the next few weeks we spent 100 or so man-hours having meetings about how the project more productive.

I'm not a big fan of meetings for the sake of having a meeting. I realize that on any large project, meetings tie the principal participants together and keep everyone appraised of its status. And having many great minds in the same room brainstorming is a thing of wonder. But I prefer a meeting with a set topic and duration. Unfortunately, my preferences weren't the driving force behind our meetings. I haven't worked at a company yet where someone told the president that his meeting was wasting time and he was talking about irrelevant things. So we kept having meetings.

One day, Rutherford called me into his office. He had a strange habit: he would walk through the engineering department without saying anything. A few moments later, Stasi style, one of us would get a call from his office asking to stop by.

His sentences were steeped in bureaucratic style and usually began with steepled fingers, pursed lips, and an opening of "as you know..." or "moving forward..."

"As you know, we've all been working very hard on this project," he started, predictably. "We've also made an international commitment to a major vendor that this project is very, um, important to."

He paused awkwardly. I said nothing, wondering where he was going. And since the awkward pause was his own, I left him on the hook. He looked around, then continued, "Moving forward, if you can, uh, get this project finished by our deadline, we'd like to pay for you and, um, Antonia to have a nice meal downtown, and maybe spend the night."

He smiled, as if he had just offered to double my salary. I tried to decide whether I should be amused, offended or even grateful. I think I ended up offused.

"Well, thanks," I said lamely. Then my jaw steeled, "We're working very hard on this project and we'll do the best we can." I stood up and walked back to my desk.

Later, I calld Antonia with the "great" news. She was mad. "For working 70 hour weeks they're offering you dinner and a hotel room? How about a $10,000 bonus!" I couldn't have agreed more.