Click here to Skip to main content
15,882,017 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Can someone explain how GDI+ coordinates work?

I’m migrating a large MFC/C++ gdi-drawing program to use gdi+. The simplest way to get going was to create a Gdiplus::graphics object from a DC I’d already initialised, then move each element of drawing across in turn - taking care not to switch between DC & gdi++. Almost everything worked instantly.

So: mentally, I think in gdi. Migrating to gdi+ with minimal changes works, except for one thing...

In gdi+ line widths aren’t constant. Defining a pen, with a certain width results in a different number of pixels depending on where on the screen it’s drawn. With GDI, whatever units/scaling was declared, defining a pen always resulted in a constant pixel width. I’ve stripped out all mapping mode / DC initialisation code done prior to declaring the Gdiplus::graphics, but the basic issue is still there.

Clearly, I’m missing something.

Example code, stripping out all DC initialisation...
OnPaint >> DoDraw(CDC* pDC, CRect rPaint)

Graphics graphics(pDC->m_hDC);
Gdiplus::REAL sc = 1.0;

Gdiplus::REAL nPenWidth = sc * 5;
Gdiplus::Pen p(color, nPenWidth);
for (int r = 0; r < 20; r++)
{
Gdiplus::REAL y = 0.0 + (r *40);
g->DrawLine(&p, 20.0, y, 120.0, y);
}

This draws a column of 20 short horizontal lines, all using the same pen. On my 96dpi monitor some are 3 pixels wide, some are 4 pixels wide. Why aren’t these lines the same width?

What I have tried:

Replacing the initialization of “sc” prior to defining the pen improves the consistency, but doesn’t completely fix things (so maybe its a red herring).

// set Points as units -
graphics.SetPageUnit(Gdiplus::UnitPoint);
Gdiplus::REAL dpiX = graphics.GetDpiX();
Gdiplus::REAL sc = 72.0 / dpiX;
graphics.SetPageScale(sc);
Posted
Updated 23-Mar-18 7:31am
Comments
Richard MacCutchan 23-Mar-18 12:06pm    
I have just tried that code and every line appears exactly the same width, even under the magnifier.
SteveK2 23-Mar-18 13:25pm    
Thanks, Richard.

Your comment was enough for me to re-visit the simplifications I did for the code sample, where I discovered my mistake was in removing a couple of things which had no individual effect on the results, but if they were *both* removed then things work as you say.

1 solution

There is some interpolation like dithering of the bits which got set. When you want pixel precise output you must take the resolution into account and round all data like your y to an full integer. Often are special bitmaps used to avoid this mess.

When lines are in some angle the output must somehow decide to optimize and smooth the line. Normally it is done via some calculation of the surrounding pixels. So the background may also have some influence.

A good overview article of this art explains an article of the Cambrigde university.
 
Share this answer
 
Comments
SteveK2 23-Mar-18 13:39pm    
Karsten, that was the area where I thought the issue was, and had been banging my head against a desk for a couple of days.

The immediate issue (variable line widths) was down to me setting MM_ISOTROPIC mapping and a log/phys window size for scaling prior to switching to gdi+. If I remove that (& in the flicker-avoiding memory bitmap DC) my lines look consistent - and some elements of odd anti-aliasing disappear.

All I've got to do now is figure out how to correctly initialise the graphics object, and how to do scaling.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900