如何在 Java 中绘制一个体面的圆圈
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1094539/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to draw a decent looking Circle in Java
提问by soldier.moth
I have tried using the method drawOval with equal height and width but as the diameter increases the circle becomes worse looking. What can I do to have a decent looking circle no matter the size. How would I implement anti-aliasing in java or some other method.
我曾尝试使用具有相等高度和宽度的 drawOval 方法,但随着直径的增加,圆看起来更糟。无论大小如何,我都可以做些什么才能拥有一个体面的圆圈。我将如何在 java 或其他一些方法中实现抗锯齿。
采纳答案by Brandon Yarbrough
As it turns out, Java2D (which I'm assuming is what you're using) is already pretty good at this! There's a decent tutorial here: http://www.javaworld.com/javaworld/jw-08-1998/jw-08-media.html
事实证明,Java2D(我假设您正在使用它)已经非常擅长这个!这里有一个不错的教程:http: //www.javaworld.com/javaworld/jw-08-1998/jw-08-media.html
The important line is:
重要的一行是:
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
回答by Josef Pfleger
you can set rendering hints:
您可以设置渲染提示:
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
回答by finnw
Two things that may help:
两件事可能有帮助:
- Use
Graphics2D.draw(Shape)
with an instance ofjava.awt.geom.Ellipse2D
instead ofGraphics.drawOval
- If the result is still not satisfactory, try using
Graphics2D.setRenderingHint
to enable antialiasing
Graphics2D.draw(Shape)
与java.awt.geom.Ellipse2D
代替的实例一起使用Graphics.drawOval
- 如果结果仍然不满意,请尝试使用
Graphics2D.setRenderingHint
启用抗锯齿
Example
例子
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);
}
See Josef's answer for an example of setRenderingHint
有关示例,请参阅约瑟夫的回答 setRenderingHint
回答by Clint
Of course you set your radius to what ever you need:
当然,您可以将半径设置为您需要的任何值:
@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);
}
回答by Oleg Estekhin
Inability to draw a "decent looking circle" is related to the very old bug 6431487.
无法绘制“体面的圆圈”与非常古老的错误6431487 相关。
Turning antialiasing on does not help a lot - just check the kind of "circle" produced by the drawOval() or drawShape(Eclipse) when the required circle size is 16 pixels (still pretty common for icon size) and antialiasing is on. Bigger antialiased circles will look better but they are still asymmetric, if somebody will care to look at them closely.
打开抗锯齿并没有多大帮助 - 当所需的圆形大小为 16 像素(对于图标大小仍然很常见)并且抗锯齿功能打开时,只需检查 drawOval() 或 drawShape(Eclipse) 生成的“圆形”类型。更大的抗锯齿圆圈看起来会更好,但它们仍然是不对称的,如果有人愿意仔细观察它们。
It seems that to draw a "decent looking circle" one has to manually draw one. Without antialiasing it will be midpoint circle algorithm (this questionhas an answer with a pretty java code for it).
似乎要绘制一个“体面的圆圈”,必须手动绘制一个。如果没有抗锯齿,它将是中点圆算法(这个问题有一个带有漂亮的 java 代码的答案)。
回答by Marco Ottina
EDITED: 06 September 2017
编辑:2017 年 9 月 6 日
That's an algorithm invented by me to draw a circle over a integer matrix. The same idea could be used to write a circle inside a BufferedImage. If you are trying to draw that circle using the class Graphics this is not the answare you are looking for (unless you wish to modify each color-assignement with g.drawLine(x, y, x+1, y), but it could be very slow).
这是我发明的在整数矩阵上画圆的算法。可以使用相同的想法在 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;
}
I tried it so many times, verifying manually it correctness, so I think it will work. I haven't made any range-check just to simplify the code. I hope it will help you and everyone wish to draw a circle over a matrix (for example, those programmer who tries to create their own videogames on pure code and need to manage a matrix-oriented game-map to store the objects lying on the game-map [if you need help on this, email me]).
我尝试了很多次,手动验证它的正确性,所以我认为它会起作用。我没有进行任何范围检查只是为了简化代码。我希望它能帮助你和每个想在矩阵上画圆的人(例如,那些试图用纯代码创建自己的视频游戏并需要管理面向矩阵的游戏地图来存储躺在矩阵上的对象的程序员游戏地图 [如果您需要这方面的帮助,请给我发电子邮件])。
回答by Evgeni Sergeev
Thanks to Oleg Estekhin for pointing out the bug report, because it explains how to do it.
感谢 Oleg Estekhin 指出错误报告,因为它解释了如何去做。
Here are some small circles before and after. Magnified a few times to see the pixel grid.
这里有一些之前和之后的小圆圈。放大几倍以查看像素网格。
Going down a row, they're moving slightly by subpixel amounts.
向下一行,它们以亚像素数量轻微移动。
The first column is without rendering hints. The second is with antialias only. The third is with antialias and pure mode.
第一列没有渲染提示。第二种是仅使用抗锯齿。第三种是抗锯齿和纯模式。
Note how with antialias hints only, the first three circles are the same, and the last two are also the same. There seems to be some discrete transition happening. Probably rounding at some point.
请注意仅使用抗锯齿提示如何,前三个圆圈相同,后两个圆圈也相同。似乎发生了一些离散的转变。可能在某个时候四舍五入。
Here's the code. It's in Jython for readability, but it drives the Java runtime library underneath and can be losslessly ported to equivalent Java source, with exactly the same effect.
这是代码。它位于 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"))
Summary: you need both VALUE_ANTIALIAS_ON
and VALUE_STROKE_PURE
to get proper looking circles drawn with subpixel accuracy.
总结:您需要VALUE_ANTIALIAS_ON
和VALUE_STROKE_PURE
才能获得以亚像素精度绘制的正确外观的圆圈。