简体   繁体   English

克服 32 位限制,使用由数百万单位转换的 System.Drawing.Graphics 表面

[英]Overcoming 32-bit limitations, when using a System.Drawing.Graphics surface translated by millions of units

Context:语境:

In .NET WinForms I built a map control so I can plot geometry and render satellite images.在 .NET WinForms 中,我构建了一个 map 控件,因此我可以 plot 几何图形和渲染卫星图像。 As in any 2D projection, the geographic coordinates are mapped to 2D surface.与任何 2D 投影一样,地理坐标映射到 2D 表面。 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.但是当您放大时,您会注意到随着您移动到更高的纬度和经度值,生成的 2D 坐标会达到数百万单位的数量级。


Problem:问题:

The way you can pan/zoom at large pictures such as in a map, is translating the drawing surface using a transformation matrix.您可以平移/缩放大型图片(例如 map)的方式是使用变换矩阵平移绘图表面。 The GDI+ uses float for internal calculations (as far you can tell by the .NET System.Drawing namespace). GDI+ 使用float进行内部计算(据您所知,.NET System.Drawing命名空间)。 The issue is that when your float grows to millions, you lose your decimal places precision, and things starts to get weird.问题是当你的float增长到数百万时,你会失去小数位的精度,事情就开始变得奇怪了。 Even though the screen works in a discrete integral type (multiples of 1 pixel) rendering operations and transformation still need to use float math.即使屏幕以离散整数类型(1 像素的倍数)工作,渲染操作和转换仍然需要使用float数学。


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.如下所示,map 显示了一个填充的多边形,后跟一个轮廓。 Notice that the weird result for the dashed outline, while the fill seems correct.请注意,虚线轮廓的奇怪结果,而填充似乎是正确的。 However both operation took the same Point[] as input.然而,这两个操作都采用相同的Point[]作为输入。

在 Windows 中使用 GDI+ 投影墨卡托地图

So the only sensible reasoning is that the GDI+ calculations with floating point will get rounding/truncation errors.所以唯一合理的推理是使用浮点的 GDI+ 计算会出现舍入/截断错误。

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.您已经可以看到这些值要么是.0 要么是.5,而当前值的大小约为几百万。 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.他们也有舍入错误,有时会从 alignment 跳出 1 或 2 个像素。 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?当图形表面被数百万单位平移时,如何解决 GDI+ 失去精度的限制?

I suppose that the main issue is the Matrix.Translate() call which offsets the visible region by millions of pixels.我想主要问题是Matrix.Translate()调用,它将可见区域偏移了数百万像素。 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 .尽管我可以轻松地重写 Matrix class 以使用double精度类型,但 GDI+ 仍然在 32 位float中运行。


Managing geodedic coordinates requires double-precision math, otherwise you'll loose precision with (projected) high coordinate magnitude values.管理大地坐标需要双精度数学,否则您会因(投影)高坐标幅度值而失去精度。

I wonder which map projection you use.我想知道您使用哪种 map 投影。 Normally, projection models requires a projection center, which it is the projection plane origin (0, 0).通常,投影模型需要一个投影中心,即投影平面原点 (0, 0)。 Setting the projection center to the coordinate of the current map view make projected coordinates values lower in their magnitude (since they are near to the projection center).将投影中心设置为当前 map 视图的坐标会使投影坐标值的大小降低(因为它们靠近投影中心)。

Change the projection center each time the map is recentered, and you'll need double precision only at lowest zoom levels.每次 map 重新居中时更改投影中心,并且仅在最低缩放级别下才需要双精度。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM