Context:
In .NET WinForms I built a map control so I can plot geometry and render satellite images. As in any 2D projection, the geographic coordinates are mapped to 2D surface. But as you zoom IN, you notice that the resulting 2D coordinates get to the order of Millions of Units as you move to higher latitude and longitude values.
Problem:
The way you can pan/zoom at large pictures such as in a map, is translating the drawing surface using a transformation matrix. The GDI+ uses float for internal calculations (as far you can tell by the .NET System.Drawing namespace). The issue is that when your float grows to millions, you lose your decimal places precision, and things starts to get weird. Even though the screen works in a discrete integral type (multiples of 1 pixel) rendering operations and transformation still need to use float math.
Code:
public void Render(Graphics gfx, ICamera camera, Polygon polygon) {
var points = polygon.Points();
if (!(FillBrush is null)) {
gfx.FillPolygon(FillBrush, points);
}
if (!(OutlinePen is null)) {
gfx.DrawPolygon(OutlinePen, points);
}
}
As seen below, the map show a filled polygon followed by an outline. Notice that the weird result for the dashed outline, while the fill seems correct. However both operation took the same Point[] as input.
So the only sensible reasoning is that the GDI+ calculations with floating point will get rounding/truncation errors.
This is evident when I look closer into the values of each coordinate just before they are converted to integers to feed the drawing methods:
You can already see that the values are either .0 or .5 with the current magnitude of values in the order of few millions. And as you zoom IN even more, the errors will probably get worse.
I had a similar issue when rendering the tiles into place. They also got rounding errors and they would jump 1 or 2 pixels out of alignment sometimes. The way I solved that was to overlap them a little bit.
Question and ideas:
How can I workaround that GDI+ limitation of losing precision when the graphical surface is translated by millions of units?
I suppose that the main issue is the Matrix.Translate() call which offsets the visible region by millions of pixels. If I could somehow avoid to translate the surface by that much... but doesn't seem possible to avoid that.
Even though I could easily re-write the Matrix class to work with double types, the GDI+ still operates in 32-bit float.

