9

私はこれまでJavaの描画方法を使用したことがないので、PoCとしてアナログ時計を作成することにしました。手に加えて、分/時間の目盛りが付いた文字盤を描きます。単純なsin/cos計算を使用して、円の周りの線の位置を決定します。

しかし、細かい目盛りが非常に短いため、線の角度が間違っていることに気づきました。これは、Graphics2D.drawLine()Line2D.double()メソッドの両方がサブピクセルの精度で描画できないためだと確信しています。

中心から始まり、円でマスクして(より長く、より正確な線を作成するために)線を引くことができることは知っていますが、それはそのようなエレガントでコストのかかる解決策のようです。私はこれを行う方法についていくつかの調査を行いましたが、私が遭遇した最良の答えはを使用することAffineTransformです。AffineTransformスーパーサンプリングを実行する必要があるのではなく、回転ありのみを使用できると思います。

これは、サブピクセル精度で描画する唯一の/最良の方法ですか?または、潜在的に高速なソリューションはありますか?

編集:私はすでにオブジェクトにを設定しRenderingHintていGraphics2Dます。

要求に応じて、ここにコードの一部を示します(これは単なるPoCであったため、完全には最適化されていません)。

diameter = Math.max(Math.min(pnlOuter.getSize().getWidth(),
                             pnlOuter.getSize().getHeight()) - 2, MIN_DIAMETER);

for (double radTick = 0d; radTick < 360d; radTick += 6d) {
   g2d.draw(new Line2D.Double(
      (diameter / 2) + (Math.cos(Math.toRadians(radTick))) * diameter / 2.1d,
      (diameter / 2) + (Math.sin(Math.toRadians(radTick))) * diameter / 2.1d,
      (diameter / 2) + (Math.cos(Math.toRadians(radTick))) * diameter / 2.05d,
      (diameter / 2) + (Math.sin(Math.toRadians(radTick))) * diameter / 2.05d));
} // End for(radTick)

これが図面のスクリーンショットです。少し見づらいかもしれませんが、59分間目盛りを見てください。それは完全に垂直です。

サンプル画像

4

1 に答える 1

8

Line2D.double()メソッドは、サブピクセルの精度で描画できません。

間違ってRenderingHints.VALUE_STROKE_PURE、Graphics2Dオブジェクトを使用すると、形状で「サブピクセル」の精度を描画できますLine2D


スーパーサンプリングを実行する必要はなく、回転のみでAffineTransformを使用できると思います。これは、サブピクセル精度で描画する唯一の/最良の方法ですか?または、潜在的に高速なソリューションはありますか?

ここで何かが足りないと思います。Graphics2Dオブジェクトはすでにを保持しており、すべての描画アクションとその安価なパフォーマンスAffineTransformに使用しています。


しかし、あなたのコードに欠けているものをあなたに返すために-これは欠けています:

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

以下は、この画像を生成する自己完結型の例です。

スクリーンショット

public static void main(String[] args) throws Exception {

    final JFrame frame = new JFrame("Test");

    frame.add(new JComponent() {
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            Graphics2D g2d = (Graphics2D) g;

            System.out.println(g2d.getTransform());
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                                 RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
                                 RenderingHints.VALUE_STROKE_PURE);

            double dia = Math.min(getWidth(), getHeight()) - 2;

            for (int i = 0; i < 60 ; i++) {
                double angle = 2 * Math.PI * i / 60;
                g2d.draw(new Line2D.Double(
                        (dia / 2) + Math.cos(angle) * dia / 2.1d,
                        (dia / 2) + Math.sin(angle) * dia / 2.1d,
                        (dia / 2) + Math.cos(angle) * dia / 2.05d,
                        (dia / 2) + Math.sin(angle) * dia / 2.05d));
            }

            g2d.draw(new Ellipse2D.Double(1, 1, dia - 1, dia - 1));
        }
    });

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(400, 400);
    frame.setVisible(true);
}
于 2011-02-16T16:38:10.453 に答える