Using LineDDA to produce complex line styles

Introduction:

A Very old method for generating complex line styles is the use of the Win32
API call "LineDDA". LineDDA can be used to create dashed or dotted lines, as
well as more complex graphics such as wavy lines or "Railroad Tracks".

This method was first made available with Windows NT 3.1 and is currently
supported by Windows 95/98. (Not Supported by Windows CE)

LineDDA is a GDI32 library call that takes a set of line coordinates, an
address to a callback function and a pointer to some user data with the
following signature: (Taken from the GDI: Platform SDK)

Concept:

Basic use requires that LineDDA be called with the coordinates of the line
segment, the address of the LineDDAProc and some User defined data and GDI
will call the LineDDAProc for every calculated point on the line. (Excluding
the Endpoint)

LineDDA is not a Graphics routine in that it does not draw anything, but
rather is a support routine used to set up the callback stream. (DDA stands
for Digital Differential Analyzer) Because of this, the line will always be
calculated using default transformations and mapping modes applied to the
current display resolution. Manual Transformation of the X and Y values
passed to the LineDDAProc if other than the defaults are used.

Implementation:

A basic implementation would have a call to LinDDA in the "OnDraw" method
passing in a static or global pointer to a function that would draw whatever
interesting lines styles that the solution required:

void CSimpleView::OnDraw(CDC* pDC)
{
//Implementation Note: it is safe to pass our local reference
//of the pDC object because all of the callbacks will complete
//before the pDC goes out of scope.
CSimpleDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
//Draw a Line
pDC->MoveTo(10,10);
pDC->LineTo(300,300);
//Use LineDDA to Draw 0's at intervals along the line.
::LineDDA(10,10,300,300,(LINEDDAPROC)DrawZero,(long)pDC);
}
VOID CALLBACK DrawZero(int X,int Y,LPARAM lpData)
{
//This Callback routine will be called for every calculated
//point in the line.
//Implementation Note: Use lpData to pass a reference to a
//CDC object for drawing.
CDC* pDC;
pDC = (CDC*)lpData;
if( X % 20 ==0)
{
pDC->TextOut(X,Y,_T("0"));
}
}

This treatment would have acceptable performance in very simple situations
but under more rigorous application, would not be sufficient.

A better approach would be to use this method to precalculate points for
later use in the OnDraw method. If the points are static, this would only be
performed once.

Conclusion:

LineDDA can provide a solution to problems requiring more complex line
styles. This is a Win32 solution and is currently not supported directly by
MFC. (Probably because it is not used very much) As a general solution it
may not prove to be very useful but it will solve some very unique problems
for which no other direct solution exists.

Further Reading:

The Win32 SDK contains an average amount of documentation on this method.
MSDN Knowledge Base contains several examples of how to use LineDDA to
create some interesting affects. One sample actually used LineDDA to draw
the cell lines for a simple spreadsheet program. (Article ID: Q68301)

Comments

Why aren't we using CPen to create textured lines?

For all the searching that I have done I don't find anyone using CPen to Create textured lines. I have to ask why? Is it really that difficult to use? Are there no clear cut examples? For all my looking THERE AREN'T. Could someone shed some light on my Microsoft frustrations. How about you Bill Gates? Naw I didn't think so.

LineDDA is too restrictive

1) LineDDA works only with straight lines
2) LineDDA works in logical coordinate space, not device
coordinate space
3) LineDDA callback routine does not give you sense of
line direction, so you can't draw something like
a dash, although dots or any symmetric shapes are OK.

SetPixel is slow!

The problem with LineDDA isn't that the function itself is slow. It (probably) uses the bresenham-algorithm, which is considerably fast. (3 or 4 addition per pixel)
The two reasons why this usage has poor performance is, that (1) a function call to the callback takes some time and (2) SetPixel does a multiplication (per pixel). (mapping modes, etc not included)
So, saving the pixels in an array or something will not help.

Top White Papers and Webcasts

Live Event Date: March 19, 2015 @ 1:00 p.m. ET / 10:00 a.m. PT
The 2015 Enterprise Mobile Application Survey asked 250 mobility professionals what their biggest mobile challenges are, how many employees they are equipping with mobile apps, and their methods for driving value with mobility.
Join Dan Woods, Editor and CTO of CITO Research, and Alan Murray, SVP of Products at Apperian, as they break down the results of this survey and discuss how enterprises are using mobile application management and private …

On-demand Event
Event Date: February 12, 2015
The evolution of systems engineering with the SysML modeling language has resulted in improved requirements specification, better architectural definition, and better hand-off to downstream engineering. Agile methods have proven successful in the software domain, but how can these methods be applied to systems engineering? Check out this webcast and join Bruce Powel Douglass, author of Real-Time Agility, as he discusses how agile methods have had a tremendous …