Java Swing BasicStroke“cap”不适用于零度角

时间:2013-03-23 01:06:08

标签: java swing graphics2d stroke

这个问题是我前一段时间提出的问题的后续问题: Drawing a bordered path with sharp corners in Java

经过实验,我发现了一些可能有意或可能是错误的行为,但我不希望这两种方式。 SSCCE:

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.GeneralPath;

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

public class CornerTest {
    private JFrame frame;

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    CornerTest window = new CornerTest();
                    window.frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public CornerTest() {
        initialize();
    }

    private void initialize() {
        frame = new JFrame();
        frame.setBounds(100, 100, 450, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel panel = new JPanel() {
            protected void paintComponent(Graphics g) {
                GeneralPath path;
                Graphics2D g2d = (Graphics2D) g;
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_ON);
                g2d.setStroke(new BasicStroke(15.5f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
                g2d.setColor(Color.BLACK);
                path = new GeneralPath();
                path.moveTo(100, 100);
                path.lineTo(200, 100);
                path.lineTo(100, 50);
                g2d.draw(path);
            }
        };
        frame.setBackground(Color.CYAN);
        frame.add(panel);
    }
}

通过取path.lineTo(100, 50);行并使用第二个参数,我们可以改变绘制路径的角度。有关各种示例,请参见下图。

enter image description here

基本上,我正在绘制GeneralPath,每个图像的角度略微减小。最终(在底部图像中)角度达到零。在这种情况下,圆形的“连接”不再被绘制。这种方式有道理,但有点不然。我不确定它是否有意。有趣的是,如果您将角度更改为略微大于0(即通过将上面引用的行更改为path.lineTo(100, 99.999);,则会再次绘制圆角。

在我的应用中,路径可以自身加倍(即创建零度角),并且在这种情况下,在这种情况下绘制连接轮在美学上更具吸引力。有什么方法可以破解Java源代码来实现这个目的吗?

2 个答案:

答案 0 :(得分:2)

不知道攻击源代码,但您可以通过绘制一行来自定义代码以解决此问题:

path = new GeneralPath();
path.moveTo(100, 100);
path.lineTo(200, 100);
path.lineTo(50, 100);

Rectangle bounds = path.getBounds();

if (bounds.height == 0)
{
    path = new GeneralPath();
    path.moveTo(bounds.x, bounds.y);
    path.lineTo(bounds.x + bounds.width, bounds.y);
}

if (bounds.width == 0)
{
    path = new GeneralPath();
    path.moveTo(bounds.x, bounds.y);
    path.lineTo(bounds.x, bounds.y + bounds.height);
}

g2d.draw(path);

答案 1 :(得分:2)

  

我正在用500+点绘制很长的路径,这会给我的绘制方法增加很多开销,以检查每个“子路径”

不要在paint方法中构建GeneralPath。您可以使用一个包装类,它将在添加时过滤每个点。这里的代码将比较每次要添加一个点时线的斜率。当斜率相同时,在添加moveTo之前的最后一个点生成lineTo。这将导致生成圆形笔划:

import java.awt.*;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.*;
import java.util.List;
import java.util.ArrayList;

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

public class CornerTest {
    private JFrame frame;

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    CornerTest window = new CornerTest();
                    window.frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public CornerTest() {
        initialize();
    }

    private void initialize() {
        frame = new JFrame();
        frame.setBounds(100, 100, 450, 450);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        final GeneralPath gp = new GeneralPath();
        MyGeneralPath path = new MyGeneralPath(gp);
        path.moveTo(100, 100);
        path.lineTo(200, 100);
        path.lineTo(100, 50);
//        path.lineTo(50, 100);
        path.flush();


        JPanel panel = new JPanel() {
            protected void paintComponent(Graphics g) {
                Graphics2D g2d = (Graphics2D) g;
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_ON);
                g2d.setStroke(new BasicStroke(15.5f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
                g2d.setColor(Color.BLACK);
                g2d.draw(gp);
            }
        };
        frame.setBackground(Color.CYAN);
        frame.add(panel);
    }

    static class MyGeneralPath
    {
        private GeneralPath path;
        private List<Point2D.Double> points = new ArrayList<Point2D.Double>();

        public MyGeneralPath(GeneralPath path)
        {
            this.path = path;
        }

        public void moveTo(double x, double y)
        {
            flush();
            points.add( new Point2D.Double(x, y) );
        }

        public void lineTo(double x, double y)
        {
            Point2D.Double point = new Point2D.Double(x, y);

            checkSlope(point);

            points.add( point );
        }

        private void checkSlope(Point2D.Double p3)
        {
            int size = points.size();

            if (size < 2 )
                return;

            Point2D.Double p2 = points.get(size - 1);
            Point2D.Double p1 = points.get(size - 2);

            double slope1 = (p2.getY() - p1.getY()) / (p2.getX() - p1.getX());
            double slope2 = (p3.getY() - p2.getY()) / (p3.getX() - p2.getX());

            if (slope1 == slope2)
                moveTo(p2.getX(), p2.getY());
        }

        public void flush()
        {
            int size = points.size();

            if (size == 0)
                return;

            Point2D.Double point = points.get(0);
            path.moveTo(point.getX(), point.getY());

            for (int i = 1; i < size; i++)
            {
                point = points.get(i);
                path.lineTo(point.getX(), point.getY());
            }

            points.clear();
        }
    }
}