4

The code below draws rectangle and 2 ellipses.

enter image description here

While should draw 3 ellipses.

My OS is Windows 7 prof 64 bit

My Java is 1.6 x86 also 1.7 x64 tested.

Why?

package tests;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import net.miginfocom.swing.MigLayout;

public class AntialiacingScaleTester {

    public static void main(String[] args) {

        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {

                JPanel circlePanel = new JPanel() {
                    @Override
                    public void paintComponent(Graphics g) {

                        super.paintComponent(g);

                        Graphics2D g2d = (Graphics2D)g;
                        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

                        g2d.setColor(Color.RED);
                        g2d.setStroke(new BasicStroke(1));
                        //g2d.drawOval(0, 0, 200, 200);
                        g2d.draw(new Ellipse2D.Double(0, 0, 200, 200));

                        AffineTransform old = g2d.getTransform();

                        g2d.setColor(Color.GREEN);
                        g2d.scale(1000, 1000);
                        g2d.setStroke(new BasicStroke(0.001f));
                        g2d.draw(new Ellipse2D.Double(0, 0, 0.225, 0.225));

                        g2d.setColor(Color.BLUE);
                        g2d.scale(10, 10);
                        g2d.setStroke(new BasicStroke(0.001f));
                        g2d.draw(new Ellipse2D.Double(0, 0, 0.025, 0.025));

                        g2d.setTransform(old);

                    }
                };

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);


                //frame.setLayout(new MigLayout("fill"));
                //frame.add(circlePanel, "w 300, h 300, grow");

                //frame.add(circlePanel);

                frame.setLayout(null);
                circlePanel.setBounds(new Rectangle(0, 0, 300, 300));
                frame.add(circlePanel);

                frame.setBounds(0, 0, 350, 300);

                //frame.pack();
                frame.setVisible(true);

            }
        });

    }

}
Dims
  • 47,675
  • 117
  • 331
  • 600
  • 1
    For better help sooner, post an [SSCCE](http://sscce.org/). – Andrew Thompson Dec 24 '12 at 01:45
  • 1) `g2d.scale(10000, 10000);` Why the huge scaling? 2) `new JPanel() { @Override public void paint(Graphics g)` should be `new JPanel() { @Override public void paintComponent(Graphics g)` 3) The first line of that method should typically call `super` e.g. `super.paintComponent(g)`. – Andrew Thompson Dec 24 '12 at 01:46
  • @Andrew (1) for test (2,3) didn't help – Dims Dec 24 '12 at 09:08

2 Answers2

2

I copy/pasted your code and it drew the 2 ellipses you wrote about, the only change I made was to replace your MigLayout by null, set the frame and panel dimensions by hand and remove the frame.pack() invocation:

import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Test {
    /**
     * @param args
     */
    public static void main(String[] args) {
        JPanel circlePanel = new JPanel() {
            @Override
            public void paint(Graphics g) {

                Graphics2D g2d = (Graphics2D) g;
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

                g2d.setStroke(new BasicStroke(1));
                //g2d.drawOval(0, 0, 200, 200);
                g2d.draw(new Ellipse2D.Double(0, 0, 200, 200));

                AffineTransform old = g2d.getTransform();

                g2d.scale(10000, 10000);
                g2d.setStroke(new BasicStroke(0.001f));
                g2d.draw(new Ellipse2D.Double(0, 0, 0.025, 0.025));

                g2d.setTransform(old);

            }
        };

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.setLayout(null);
        circlePanel.setBounds(new Rectangle(0, 0, 300, 300));
        frame.add(circlePanel);

        frame.setBounds(0, 0, 350, 300);

        //frame.pack();
        frame.setVisible(true);
    }
}

enter image description here

Update: Could reproduce the problem using the Oracle JDK (java version "1.8.0-ea") instead of the OpenJDK. Got the diamond shape, as pointed out in another answers, the scale factor is the root cause of the shape degenaration, don't know if that should be the appropiate behaviour though, so, there must be a bug in one these JRE's. The following test program works fine for both JRE's:

import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Test {
    /**
     * @param args
     */
    public static void main(String[] args) {
        JPanel circlePanel = new JPanel() {
            @Override
            public void paint(Graphics g) {

                Graphics2D g2d = (Graphics2D) g;
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

                g2d.setStroke(new BasicStroke(1));
                //g2d.drawOval(0, 0, 200, 200);
                g2d.draw(new Ellipse2D.Double(0, 0, 200, 200));

                AffineTransform old = g2d.getTransform();

                g2d.scale(10, 10);
                g2d.setStroke(new BasicStroke(1.0f));
                g2d.draw(new Ellipse2D.Double(0, 0, 25.0, 25.0));

                g2d.setTransform(old);

            }
        };

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.setLayout(null);
        circlePanel.setBounds(new Rectangle(0, 0, 300, 300));
        frame.add(circlePanel);

        frame.setBounds(0, 0, 350, 300);

        //frame.pack();
        frame.setVisible(true);
    }
}
higuaro
  • 15,730
  • 4
  • 36
  • 43
  • *"replace your `MigLayout` by a `NullLayout`"* 1) There is no `NullLayout` class as that string suggests. 2) The panel should return a preferred size, for the layout manager to have a dimension to work with. – Andrew Thompson Dec 24 '12 at 01:59
  • Sorry, my bad, indeed, I dit mean to replace the `MigLayout` by just `null`, corrected in the answer – higuaro Dec 24 '12 at 02:06
  • @h3nr1x what OS&Java do you have – Dims Dec 24 '12 at 09:11
  • I'm getting the same results using both codes in 1.6.0 (once the other compiled) & 1.7.0_09 (using just your code), a square instead of an ellipse. – Andrew Thompson Dec 24 '12 at 10:09
  • I'm using linux with the OpenJDK version 1.7.0_09 – higuaro Dec 25 '12 at 02:41
1

Replicated on Java 7, Windows 7 in Eclipse, removing the Layout Manager.

My feeling is that it's due to the combination of the high scaling and inaccuracies at small floating point values, reducing the number of points generated.

If you substitute values you find between 0.0363 and 0.0362 the rendering API breaks. It no longer generates an Arc, but instead a square.

The work-around is to stop combining the huge scaling with tiny sized objects. Scale down and increase the size.

Philip Whitehouse
  • 4,293
  • 3
  • 23
  • 36