绘制多个圆的问题(drawOval / Java)

Posted

技术标签:

【中文标题】绘制多个圆的问题(drawOval / Java)【英文标题】:Issues with drawing multiple circles (drawOval / Java) 【发布时间】:2015-03-10 06:24:02 【问题描述】:

我的问题如下:我的实际项目(下面的代码是其简化版本)涉及许多同心圆(每个都有不同的颜色)和使用计时器的动画。圆圈是使用 drawOval 方法绘制的。

我的问题是,当绘制这些同心圆时,这些圆的轮廓中似乎有很多间隙,我猜这与圆由像素和线条组成的事实有关是任何形状,所以圆形的外观是一种错觉。我这样说是因为当我将 drawOval 方法换成 drawRect 时,绘画看起来就像你所期望的那样。

在弄乱其他人的代码时,我发现使用 RenderingHints 以某种方式解决了这个问题,但是将动画减慢到了我认为可以接受的程度。

下面是绘制的截图。我们看到的是:

这是我的简化代码:

Test10

import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
public class Test10 extends JPanel 
Circle[] circles;
    public static void main(String[] args) 
        new Test10().go();
    
    void go() 
        JFrame frame = new JFrame("Circle Test");
        frame.getContentPane().add(this);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        circles = new Circle[200];
        for (int i = 0; i < 200; i++) 
            circles[i] = new Circle(i, ((2 * ( 200 - i) + 1)));
        
        repaint();
        frame.setPreferredSize(new Dimension(500,500));
        frame.pack();
        frame.setVisible(true);
    
    public void paintComponent(Graphics g) 
        for (Circle circle : circles ) 
            circle.draw(g);
        
    

圈子

import java.awt.Graphics;    
public class Circle 
int topLeft;
int diameter;
    public Circle(int topLeft, int diameter) 
        this.topLeft = topLeft;
        this.diameter = diameter;
    
    void draw(Graphics g) 
        g.drawOval(topLeft, topLeft, diameter, diameter);

    

谁能向我解释a)为什么会发生这种情况,b)如何克服这个问题。更新 尝试了各种方法,包括从最外圈开始并使用 fillOval 而不是 drawOval,以及使用更高的 stroke 值,我仍然发现我有某些人工制品出现的问题与 Pavel 发布的屏幕截图相似。这是我运行动画的完整应用程序的屏幕截图,如果您仔细观察,您会发现大多数给定圆圈的颜色不一致,从而导致这些奇怪的结果。它们的分布实际上遵循与上面发布的屏幕截图相同的模式,因此这些选项显然没有解决一些基本问题。这是我的屏幕截图:

【问题讨论】:

画一个实心圆或两个同心圆不就行了吗? 查看我的帖子顶部,在完整的应用程序中,每个圆圈都有不同的颜色,创建了一系列漂亮的同心圆。这就是我不使用fillOval的原因,无论如何谢谢:P 您是否正在实施 Futurama 的催眠蟾蜍? ;-) 【参考方案1】:

画完美的圆是不可能的。

试试下面的方法

public void paintComponent(Graphics g) 
        Graphics2D g2d = (Graphics2D)g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setStroke(new BasicStroke(2));
        int i = 0;
        for (Circle circle : circles ) 
            Shape circle2 = new Ellipse2D.Double(i++, i, circle.diameter, circle.diameter);
            g2d.draw(circle2);
        
    

您说您尝试使用RenderingHints,它会减慢您的动画速度,但您没有给我们任何动画代码,所以也许试试我的代码(很高兴看到动画实现)。它看起来更好,但仍然不是你想要的。将 stroke 设置为另一个值将解决此问题(至少设置为 2)。另一种是使用.fill() 而不是.draw()。我知道它并不完美,但你可以试试。

另一个想法

我想,也许你可以给你的图像添加一些模糊,这样那些伪影就看不见了? 我以前没有做过,但我发现了这个(found HERE):

private class BlurGlass extends JComponent 
        private JFrame f;

        public BlurGlass(JFrame f) 
            this.f = f;
            setOpaque(false);
            setFocusable(false);
        

        public void paintComponent(Graphics g) 
            int w = f.getWidth();
            int h = f.getHeight();
            setLocation(0, 0);
            setSize(w, h);
            g.setColor(new Color(0, 0, 0, 0.3f));
            g.fillRect(0, 0, w, h);
        
    

现在在 go() 方法中的某处:

frame.setGlassPane(new BlurGlass(frame));
frame.getGlassPane().setVisible(true);

对我来说看起来好多了。玩一下这个 GlassPane 颜色(尝试将 .3f 更改为其他值)。

【讨论】:

感谢您的所有建议,我已经尝试了所有建议,但我仍然得到奇怪的人工制品,因为在个别圈子中不能始终保持其确切的颜色,特别是在 NE NW SW 和 SE 方向。如果您有任何其他想法,请告诉我。 新信息看起来不错,稍后再试,谢谢!【参考方案2】:

您可能想让Stroke 更大。在与您类似的情况下,我很幸运

【讨论】:

谢谢 稍后会玩这个,看起来很有希望。 试一试,对我的原始帖子进行了更新,以显示由于它们不理想而产生的结果。这种方法当然有帮助,但它仍然存在问题。感谢您的帮助,如果您能查看更新将不胜感激:)【参考方案3】:

您可以尝试在绘图函数中的 Circle 类中添加此行:

Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
//and draw the Oval on g2

另一种解决方案可能是填充圆圈:

Ellipse2D.Double circle = new Ellipse2D.Double(x, y, diameter, diameter);
g2.fill(circle);

【讨论】:

感谢您的帮助,有关问题仍然存在的原因的详细信息,请参阅更新。非常好的建议,尽管我需要熟悉渲染提示。更多帮助将不胜感激。 另一种方法是使用一些预定义的同心圆图像并逐渐显示图像。太糟糕了,它不是一个程序化解决方案,它可能会为您提供更好的图形。 嗯,完整的应用程序是一个动画,其中每一帧都包含一系列同心圆,RGB 分量以指定的增量上升。随着每一帧的进行,圆圈将它们的颜色传递到它们外部的圆圈上,从而产生虫洞的效果。有点需要编程对吗? 我有一个最终的想法。尝试应用模糊滤镜,看看它是否看起来更好一些。 java2s.com/Code/Java/2D-Graphics-GUI/ImageEffectSharpenblur.htm【参考方案4】:

这是因为计算机无法画出完美的圆。

计算机使用方形像素来近似真实的圆形,但它不可能达到完美,导致某些像素不显示

画一个实心圆会帮助你

a detailed explanation

【讨论】:

正如我所怀疑的,非常感谢。我的问题尚未解决,如果您仍然有兴趣提供帮助,我已在我的问题中添加了详细信息,非常感谢该链接,稍后会好好阅读!【参考方案5】:

请您尝试使用 fillOval 方法而不是 drawOval。

g.fillOval(topLeft, topLeft, diameter, diameter);

【讨论】:

在我的身上比在你的身上效果更好。我在你的丝网印刷品上看到的那些对称的人工制品是不可取的。感谢您的回答,尽管到目前为止似乎是最有用的。 是的,我也得到了那些文物,有什么线索可以摆脱它们吗?【参考方案6】:

扭转你的想法。从最外圈开始,然后画内圈,以此类推,以最小的圆圈结束。你应该在这个过程中使用fillOval

【讨论】:

嗨,谢谢,我实际上已经尝试过这种方法,虽然它在涉及多种颜色时适用于小规模,但它会产生有趣的人工制品。我编辑了我的问题,将此信息与另一个屏幕截图一起包含在内。再次感谢 这是因为填充椭圆填充了圆圈,并且圆圈的半径之间存在很大差异。如果您想绘制一个带有粗边框的空圆(以获得一个完美的圆),那么您可以在您的 fillOval 内绘制具有几乎相同半径的 drawOval。 感谢您的回复。圆的半径之间的差异很大?相邻圆的半径相差 1,所以我不太确定我明白你的意思...... 哦,我错过了。不过,试试我改进后的想法,它可能会有所帮助。【参考方案7】:

另一个通常对圆形/椭圆有用的渲染提示是

g.setRenderingHint( RenderingHints.  KEY_STROKE_CONTROL,
                    RenderingHints.VALUE_STROKE_PURE);

见我的other answer with more details and example。

【讨论】:

以上是关于绘制多个圆的问题(drawOval / Java)的主要内容,如果未能解决你的问题,请参考以下文章

绘制几何图形

绘制具有给定厚度、位置和半径的环。 (Java2D)

画一个圆的半径和点周围的边缘

OpenGL / GLU:是不是有用于绘制圆的内置函数?

canvas-圆的绘制

为多边形轮廓绘制圆的最有效方法