6

私はJavaグラフィックスを使用していますが、「醜い」サークルを取得し続けています。

これが私のJavaプログラムが作るものです ここに画像の説明を入力してください

そして、これはMatlabで行われているのと同じものですここに画像の説明を入力してください

特に円の端では、JavaのものがMatlabのものほど「見栄えが良くない」ことは明らかだと思います。これは解像度とは関係がないことに注意してください...これらの画像は実質的に同じサイズです。また、レンダリングのヒントをすでに設定していることにも注意してください。

これは、これをテストするために実行できるMain関数を備えたスタンドアロンです。

package test;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;

public class SimplePaint02 {

    private static final int LINE_THICKNESS = 4;
    private static final int LINE_GAP = 10;
    private Color lineColor = Color.red;

    public static void main(String[] args) {
        new SimplePaint02();
    }

    public SimplePaint02() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception ex) {
                }

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(100, 100);
        }

        @Override
        public void paintComponent(Graphics g) {

            int radius = 50;
            BufferedImage buffer = new BufferedImage(radius, radius, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2d = buffer.createGraphics();
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);

            Ellipse2D circle = new Ellipse2D.Float(0, 0, radius,radius);
            Shape clip = g2d.getClip();
            g2d.setClip(circle);
            AffineTransform at = g2d.getTransform();

            g2d.setTransform(AffineTransform.getRotateInstance(Math.toRadians(45),radius / 2, radius / 2));

            int gap = LINE_GAP;

            g2d.setColor(Color.WHITE);
            g2d.fill(circle);

            g2d.setColor(lineColor);
            //g2d.setStroke(new BasicStroke(LINE_THICKNESS));
            for (int index = 0; index < 10; index++) {
                int x1 = index*gap-(LINE_THICKNESS/2);
                int y1 = 0;
                int x2 = index*gap+(LINE_THICKNESS/2);
                int y2 = radius;
                int width = x2 - x1;
                int height = y2 - y1;

                g2d.fillRect(x1, y1, width, height);
                //g2d.drawLine(index * gap, 0, index * gap, getRadius());
            }

            g2d.setTransform(at);
            g2d.setClip(clip);
            g2d.dispose();
            g.drawImage(buffer, 0, 0, this);
        }

    }

}
4

5 に答える 5

6

編集:解決策については、以下のCodeGuyの回答を参照してください。最初にそれを理解したのはJoeyRohanだったので、これは正しいとマークされています!


同じことを試してみると、滑らかなエッジが得られました。

  g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,    RenderingHints.VALUE_ANTIALIAS_ON);

ここに画像の説明を入力してください

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;

public class DrawSmoothCircle {
    public static void main(String[] argv) throws Exception {
        BufferedImage bufferedImage = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = bufferedImage.createGraphics();

        g2d.setRenderingHint (RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setPaint(Color.green);
        g2d.fillOval(10, 10, 50, 50);
        g2d.dispose();

        ImageIO.write(bufferedImage, "png", new File("e:\\newimage.png"));
    }
}

アップデート:

たくさん検索した後:

コードに問題はありませんが、

残念ながら、Java 2D(または少なくともSunの現在の実装)は「ソフトクリッピング」をサポートしていません。

しかし、クリップのトリックもあります。このリンクをたどると、求めていることを達成できます。

(また、上の画像では、クリップを使用していないため、滑らかなエッジが得られました)

于 2013-01-20T08:28:24.867 に答える
4

これが答えでした。私はこのサイトからのコードの大部分を適応させました。見てください:

ここに画像の説明を入力してください

コードは次のとおりです。

public void paintComponent(Graphics g) {

        // Create a translucent intermediate image in which we can perform
        // the soft clipping
        GraphicsConfiguration gc = ((Graphics2D) g).getDeviceConfiguration();
        BufferedImage img = gc.createCompatibleImage(getWidth(), getHeight(), Transparency.TRANSLUCENT);
        Graphics2D g2 = img.createGraphics();

        // Clear the image so all pixels have zero alpha
        g2.setComposite(AlphaComposite.Clear);
        g2.fillRect(0, 0, getWidth(), getHeight());

        // Render our clip shape into the image.  Note that we enable
        // antialiasing to achieve the soft clipping effect.  Try
        // commenting out the line that enables antialiasing, and
        // you will see that you end up with the usual hard clipping.
        g2.setComposite(AlphaComposite.Src);
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setColor(Color.WHITE);
        g2.fillOval(0, 0, getRadius(), getRadius());

        // Here's the trick... We use SrcAtop, which effectively uses the
        // alpha value as a coverage value for each pixel stored in the
        // destination.  For the areas outside our clip shape, the destination
        // alpha will be zero, so nothing is rendered in those areas.  For
        // the areas inside our clip shape, the destination alpha will be fully
        // opaque, so the full color is rendered.  At the edges, the original
        // antialiasing is carried over to give us the desired soft clipping
        // effect.
        g2.setComposite(AlphaComposite.SrcAtop);
        g2.setColor(lineColor);
        int gap = LINE_GAP;
        AffineTransform at = g2.getTransform();

        g2.setTransform(AffineTransform.getRotateInstance(Math.toRadians(45),getRadius() / 2, getRadius() / 2));

        for (int index = 0; index < 10; index++) {
            int x1 = index*gap-(LINE_THICKNESS/2);
            int y1 = 0;
            int x2 = index*gap+(LINE_THICKNESS/2);
            int y2 = getRadius();
            int width = x2 - x1;
            int height = y2 - y1;

            g2.fillRect(x1, y1, width, height);
        }

        g2.setTransform(at);
        g2.dispose();

        // Copy our intermediate image to the screen
        g.drawImage(img, 0, 0, null);
    }
于 2013-01-20T09:49:29.610 に答える
2

アップデート

わかった。次に、クリッピングまったく使用せず、代わりに、互いに面積を差し引いてクリップされた形状を作成するというアイデアがあります。

面積を差し引いてクリッピング

import java.awt.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import javax.swing.*;

public class SimplePaint02 {

    private static final int LINE_THICKNESS = 4;
    private static final int LINE_GAP = 10;
    private Color lineColor = Color.red;

    public static void main(String[] args) {
        new SimplePaint02();
    }

    public SimplePaint02() {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception ex) {
                }

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        int radius = 75;

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(radius, radius);
        }

        @Override
        public void paintComponent(Graphics g) {


            Ellipse2D circle = new Ellipse2D.Float(0, 0, radius, radius);
            Area lines = new Area();

            int gap = LINE_GAP;

            for (int index = 0; index < 10; index++) {
                int x1 = index * gap - (LINE_THICKNESS / 2);
                int y1 = 0;
                int x2 = index * gap + (LINE_THICKNESS / 2);
                int y2 = radius;
                int width = x2 - x1;
                int height = y2 - y1;

                Shape lineShape = new Rectangle2D.Double(x1, y1, width, height);
                lines.add(new Area(lineShape));

                //g3d.fillRect(x1, y1, width, height);
                //g2d.drawLine(index * gap, 0, index * gap, getRadius());
            }
            //g2d.setClip(circle);

            Area circleNoLines = new Area(circle);
            circleNoLines.subtract(lines);

            Area linesCutToCircle = new Area(circle);
            linesCutToCircle.subtract(circleNoLines);

            //g2d.setTransform(at);
            BufferedImage buffer = new BufferedImage(radius * 2, radius * 2, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2d = buffer.createGraphics();

            RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setTransform(AffineTransform.getRotateInstance(Math.toRadians(45), radius / 2, radius / 2));
            g2d.setRenderingHints(rh);
            g2d.setColor(Color.ORANGE);
            g2d.fill(linesCutToCircle);
            g2d.setColor(Color.RED);
            g2d.fill(circleNoLines);

            g2d.dispose();
            g.drawImage(buffer, 0, 0, this);
        }
    }
}

古いコード

問題の一部は、レンダリング操作が通常はに適用されないことですが、描画時にClip適用さShapeれます。私は通常、(最後に)Shape自分自身をペイントすることでそれを解決します。例えば

SimplePaint02

ここでは、赤い円に1.5ピクセルBasicStrokeが使用されています。これにより、によって生成される粗いエッジが滑らかになりClipます。

import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;

public class SimplePaint02 {

    private static final int LINE_THICKNESS = 4;
    private static final int LINE_GAP = 10;
    private Color lineColor = Color.red;

    public static void main(String[] args) {
        new SimplePaint02();
    }

    public SimplePaint02() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception ex) {
                }

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        int radius = 75;
        
        @Override
        public Dimension getPreferredSize() {
            return new Dimension((int)(1.1*radius), (int)(1.1*radius));
        }

        @Override
        public void paintComponent(Graphics g) {

            BufferedImage buffer = new BufferedImage(radius*2, radius*2, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2d = buffer.createGraphics();
            
            RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            rh.put(RenderingHints.KEY_DITHERING,RenderingHints.VALUE_DITHER_ENABLE);
            rh.put(RenderingHints.KEY_COLOR_RENDERING,RenderingHints.VALUE_COLOR_RENDER_QUALITY);
            g2d.setRenderingHints(rh);

            Ellipse2D circle = new Ellipse2D.Float(0, 0, radius,radius);
            Shape clip = g2d.getClip();
            g2d.setClip(circle);
            AffineTransform at = g2d.getTransform();

            g2d.setTransform(AffineTransform.getRotateInstance(Math.toRadians(45),radius / 2, radius / 2));

            int gap = LINE_GAP;

            g2d.setColor(Color.WHITE);
            g2d.fill(circle);

            g2d.setColor(lineColor);
            //g2d.setStroke(new BasicStroke(LINE_THICKNESS));
            for (int index = 0; index < 10; index++) {
                int x1 = index*gap-(LINE_THICKNESS/2);
                int y1 = 0;
                int x2 = index*gap+(LINE_THICKNESS/2);
                int y2 = radius;
                int width = x2 - x1;
                int height = y2 - y1;

                g2d.fillRect(x1, y1, width, height);
                //g2d.drawLine(index * gap, 0, index * gap, getRadius());
            }

            g2d.setTransform(at);
            g2d.setClip(clip);
            g2d.setClip(null);
            g2d.setStroke(new BasicStroke(1.5f));
            g2d.draw(circle);
            g2d.dispose();
            g.drawImage(buffer, 0, 0, this);
        }
    }
}
于 2013-01-20T08:32:56.020 に答える
1

drawPolygonメソッドを使用して、提案された半径を持つ円の円周上のほとんどの点の配列を生成することにより、円を描画しました。コード:

           import java.awt.*;
           import java.applet.*;

            /*<applet code="OnlyCircle" width=500 height=500>
                 </applet>*/

          public class OnlyCircle extends Applet{

            public void paint(Graphics g){


              int r=200;//radius
              int x1=250;//center x coordinate
              int y1=250;//center y coordinate
              double x2,y2;
              double a=0;
              double pi=3.14159;
              int count=0; 
              int i=0;
              int f=0;
              int[] x22=new int[628319];
              int[] y22=new int[628319];

             while(a<=2*pi&&i<628319&&f<628319)
                  {
                   double k=Math.cos(a);
                   double l=Math.sin(a);
                     x2=x1+r*k;
                     y2=y1+r*l;
                  x22[i]=(int)x2;
                  y22[f]=(int)y2;
                   i++;
                   f++;
                   a+=0.00001;
                  }
               int length=x22.length;
               g.drawPolygon(x22,y22,length);
                 }
               }
于 2013-05-29T19:17:08.297 に答える
0

アンチエイリアシングを有効にできます。

Graphics2D g2 = (Graphics2D) g;
Map<RenderingHints.Key, Object> hints = new HashMap<RenderingHints.Key, Object>();
hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
g2.setRenderingHints(hints);

paintComponentまた、中間を作成するのではなく、メソッドから取得したGraphicsオブジェクトに描画することをお勧めしますBufferedImage

于 2013-01-20T08:24:42.500 に答える