如何在Java中绘制一个像样的圆圈
我尝试使用drawOval方法具有相同的高度和宽度,但随着直径的增加,圆圈变得更糟。 无论大小如何,我能做些什么才能拥有体面的圆圈。 我将如何在java或其他方法中实现抗锯齿。
事实certificate,Java2D(我假设你正在使用的)已经相当不错了! 这里有一个不错的教程: http : //www.javaworld.com/javaworld/jw-08-1998/jw-08-media.html
重要的是:
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
您可以设置渲染提示:
Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
两件事可能会有所帮助:
- 使用
Graphics2D.draw(Shape)
和java.awt.geom.Ellipse2D
实例代替Graphics.drawOval
- 如果结果仍不理想,请尝试使用
Graphics2D.setRenderingHint
启用抗锯齿
例
public void paint(Graphics g) { Graphics2D g2d = (Graphics2D) g; Shape theCircle = new Ellipse2D.Double(centerX - radius, centerY - radius, 2.0 * radius, 2.0 * radius); g2d.draw(theCircle); }
有关setRenderingHint
的示例,请参阅Josef的答案
当然,您可以根据需要设置半径:
@Override public void paint(Graphics g) { Graphics2D g2d = (Graphics2D) g; g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); Ellipse2D.Double hole = new Ellipse2D.Double(); hole.width = 28; hole.height = 28; hole.x = 14; hole.y = 14; g2d.draw(hole); }
感谢Oleg Estekhin指出错误报告,因为它解释了如何做到这一点。
以下是前后的一些小圈子。 放大几次以查看像素网格。
连续下去,它们按子像素数量略微移动。
第一列没有渲染提示。 第二种是仅使用抗锯齿。 第三种是抗锯齿和纯模式。
注意仅使用抗锯齿提示,前三个圆圈是相同的,后两个圆圈也是相同的。 似乎发生了一些离散的转变。 在某些时候可能会四舍五入。
这是代码。 它在Jython中是为了提高可读性,但它驱动下面的Java运行时库,可以无损地移植到等效的Java源代码,效果完全相同。
from java.lang import * from java.io import * from java.awt import * from java.awt.geom import * from java.awt.image import * from javax.imageio import * bim = BufferedImage(30, 42, BufferedImage.TYPE_INT_ARGB) g = bim.createGraphics() g.fillRect(0, 0, 100, 100) g.setColor(Color.BLACK) for i in range(5): g.draw(Ellipse2D.Double(2+0.2*i, 2+8.2*i, 5, 5)) g.setRenderingHint( RenderingHints. KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON) for i in range(5): g.draw(Ellipse2D.Double(12+0.2*i, 2+8.2*i, 5, 5)) g.setRenderingHint( RenderingHints. KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE) for i in range(5): g.draw(Ellipse2D.Double(22+0.2*i, 2+8.2*i, 5, 5)) #You'll probably want this too later on: #g.setRenderingHint( RenderingHints. KEY_INTERPOLATION, # RenderingHints.VALUE_INTERPOLATION_BICUBIC) #g.setRenderingHint( RenderingHints. KEY_RENDERING, # RenderingHints.VALUE_RENDER_QUALITY) ImageIO.write(bim, "PNG", File("test.png"))
简介:您需要VALUE_ANTIALIAS_ON
和VALUE_STROKE_PURE
才能获得以亚像素精度绘制的正确圆形。
无法绘制“体面的圆圈”与非常老的错误6431487有关 。
打开抗锯齿并没有多大帮助 – 只需检查drawOval()或drawShape(Eclipse)产生的“圆圈”类型,当所需的圆形大小为16像素(图标大小仍然很常见)并打开抗锯齿function时。 较大的抗锯齿圈看起来会更好,但如果有人愿意密切关注它们,它们仍然是不对称的。
似乎要绘制一个“体面的圆圈”,必须手动绘制一个。 如果没有抗锯齿,它将是中点圆算法(这个问题有一个漂亮的java代码的答案)。
编辑:2017年9月6日
这是我发明的算法,用于在整数矩阵上绘制一个圆。 可以使用相同的想法在BufferedImage中写一个圆圈。 如果你试图使用类Graphics绘制那个圆圈,这不是你正在寻找的answare(除非你希望用g.drawLine(x,y,x + 1,y)修改每个颜色分配,但它可以很慢)。
protected boolean runOnCircumference(int[][] matrix, int x, int y, int ray, int color) { boolean ret; int[] rowUpper = null, rowInferior = null, rowCenterUpper = null, rowCenterInferior = null; if (ret = ray > 0) { if (ray == 1) { matrix[y][x + 1] = color; rowUpper = matrix[++y]; rowUpper[x] = color; rowUpper[x + 2] = color; matrix[y][x] = color; } else { double rRay = ray + 0.5; int r = 0, c = 0, ray2 = ray << 1, ray_1 = ray - 1, halfRay = (ray >> 1) + ray % 2, rInf, ray1 = ray + 1, horizontalSymmetricOldC; // draw cardinal points rowUpper = matrix[ray + y]; rowUpper[x] = color; rowUpper[x + ray2] = color; matrix[y][x + ray] = color; matrix[ray2 + y][x + ray] = color; horizontalSymmetricOldC = ray1; rInf = ray2; c = ray_1; for (r = 0; r < halfRay; r++, rInf--) { rowUpper = matrix[r + y]; rowInferior = matrix[rInf + y]; while (c > 0 && (Math.hypot(ray - c, (ray - r)) < rRay)) { rowUpper[x + c] = color; rowUpper[x + horizontalSymmetricOldC] = color; rowInferior[x + c] = color; rowInferior[x + horizontalSymmetricOldC] = color; // get the row pointer to optimize rowCenterUpper = matrix[c + y]; rowCenterInferior = matrix[horizontalSymmetricOldC + y]; // draw rowCenterUpper[x + r] = color; rowCenterUpper[x + rInf] = color; rowCenterInferior[x + r] = color; rowCenterInferior[x + rInf] = color; horizontalSymmetricOldC++; c--; } } // end r circle } } return ret; }
我试了很多次,手动validation它的正确性,所以我认为它会起作用。 我没有进行任何范围检查只是为了简化代码。 我希望它会帮助你,每个人都希望在矩阵上绘制一个圆圈(例如,那些试图在纯代码上创建自己的video游戏并需要管理面向矩阵的游戏地图以存储位于矩阵上的对象的程序员游戏地图[如果你需要帮助,请给我发电子邮件])。