如何使用Java2D图形正确绘制具有紧密间隔点的粗线?

时间:2012-08-14 12:34:34

标签: java graphics java-2d shapes

我尝试使用Java2D绘制地图。当我的地图缩小时,我的道路上到处都是人工制品。在绘制完整的美国州时,这只是屏幕的一小部分:

Road section drawn at state scale showing drawing artefacts

当缩小距离时,这是道路的类似部分:

Road section drawn at sub-county scale with no drawing artefacts

使用的线条样式为纯蓝色线条,宽度缩放为相当于2个像素。 我尝试了各种渲染提示和连线规则,似乎没有任何帮助。

我在运行OS / X 10.8的Mac上使用Open JDK 1.7,这在带有Sun JDK 1.6的Linux机器上也是可重现的。

使用Java2D,所有形状和变换都是双精度。 线的几何形状有许多紧密间隔的点,我怀疑绘制假象的原因是渲染器被比单个像素更接近的连续点弄糊涂了。

有没有办法在不缩小点的情况下改善缩小形状的外观?

修改 绘图假象位于单独的线段相交的点处,因此缺失的像素与线帽(末端)不相交,即使端点相同也是如此。此图像显示两个线段之间的汇合点。我用7像素缩放的线条样式突出显示了每个线段(与白色的XOR-ed),但如果你仔细观察,你仍然可以看到原始蓝线的一部分(这是由于圆形帽重叠和XOR绘制模式) 。)在普通秤上,两端似乎重叠,但在普通油漆模式下缩小和缩回时会出现折线效应。

一种解决方法是在绘制它们之前将所有连续的线段连接在一起,但我仍然想知道绘制工件的真正原因。

Join between two road segments

2 个答案:

答案 0 :(得分:1)

请检查Xiaolin Wu's line algorithm它应该回答你的问题!

基本概念

function plot(x, y, c) is
plot the pixel at (x, y) with brightness c (where 0 ≤ c ≤ 1)

function ipart(x) is
return integer part of x

function round(x) is
return ipart(x + 0.5)

function fpart(x) is
return fractional part of x

function rfpart(x) is
return 1 - fpart(x)

function drawLine(x1,y1,x2,y2) is
dx = x2 - x1
dy = y2 - y1
if abs(dx) < abs(dy) then                 
  swap x1, y1
  swap x2, y2
  swap dx, dy
end if
if x2 < x1
  swap x1, x2
  swap y1, y2
end if
gradient = dy / dx

// handle first endpoint
xend = round(x1)
yend = y1 + gradient * (xend - x1)
xgap = rfpart(x1 + 0.5)
xpxl1 = xend  // this will be used in the main loop
ypxl1 = ipart(yend)
plot(xpxl1, ypxl1, rfpart(yend) * xgap)
plot(xpxl1, ypxl1 + 1, fpart(yend) * xgap)
intery = yend + gradient // first y-intersection for the main loop

// handle second endpoint
xend = round (x2)
yend = y2 + gradient * (xend - x2)
xgap = fpart(x2 + 0.5)
xpxl2 = xend  // this will be used in the main loop
ypxl2 = ipart (yend)
plot (xpxl2, ypxl2, rfpart (yend) * xgap)
plot (xpxl2, ypxl2 + 1, fpart (yend) * xgap)

// main loop
for x from xpxl1 + 1 to xpxl2 - 1 do
    plot (x, ipart (intery), rfpart (intery))
    plot (x, ipart (intery) + 1, fpart (intery))
    intery = intery + gradient
end function

答案 1 :(得分:1)

我无法重新创建使用OS X 1.6 JDK的情况,但我仍然有一些建议。

如果您只是使用它来概述状态,请考虑使用GeneralPath class。您可以使用lineTo(x,y)方法在线上建立每个点。同样,因为我无法使用Line2D.Double重新创建您的问题,我不知道这实际上是否会有所不同。

其次,可能更重要的是,你是如何放大和缩小的。我在setScaleTo(x,y)对象上使用AffineTransformGraphics2D),一切都在游泳。与通过缩放因子(或您可以做的任何其他事情)缩放数据中的点的替代方法相比,这相当容易。您还必须按因子调整线条的笔划,因为它会缩小所有内容。如果您愿意,我可以发布截图。