在Java中绘制虚线时的性能问题 [英] Performance's issue when drawing dashed line in Java

查看:75
本文介绍了在Java中绘制虚线时的性能问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用以下代码,我能够画一条虚线:

Using the following code, I am able to draw a dashed line:

public void foo(Graphics2D g2d, Shape shape)
{
    Stroke stroke = BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 10, new float[]{10}, 0);

    g2d.setStroke(stroke);

    g2d.draw(shape);
}

创建形状后,我希望能够放大该形状(最多2万次)。我的问题是,当我对形状进行过多缩放时,应用程序开始滞后,如果继续缩放,最终将崩溃。

Once a shape is created, I want to be able to zoom on that shape (up to 20 000 time). The issue I have is that, when I zoom too much on the shape, the application start to lag and will eventually, if I continue to zoom, crash.

因此,我的问题是:有没有办法绘制很大的形状(例如:一个20万像素的矩形30万像素)并带有虚线?

Therefore, my question is the following: Is there a way to draw very big shape (e.g: A rectangle of 200 000 pixels by 300 000 pixels) with a dash line ?

谢谢。

编辑:

这是我能够重现问题的简短示例:

Here is an short example where I was able to reproduce my issue:

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

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

class Scale
{
    private static int _scale = 1;

    public static int getScale()
    {
        return _scale;
    }

    public static void setScale(int scale)
    {
        _scale = scale;
    }
}

class Surface extends JPanel implements ActionListener
{
    private static Surface _surface;

    boolean isBlue = false;

    private Surface()
    {
    }

    public static Surface getInstance()
    {
        if (_surface == null)
        {
            _surface = new Surface();
        }

        return _surface;
    }

    private void doDrawing(Graphics g)
    {
        Shape rectangle = new Rectangle(0, 0, 600 * Scale.getScale(), 400 * Scale.getScale());
        Graphics2D g2d = (Graphics2D) g.create();

        g2d.setColor(Color.blue);

        Stroke stroke = new BasicStroke(10, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 10.0f, new float[]{10.0f}, 0);
        g2d.setStroke(stroke);

        // Adding a clip don't seem to do the trick :(
        g2d.clip(new Rectangle(0, 0, 100, 100));

        long startTime = System.nanoTime();
        g2d.draw(rectangle);
        long elapseTime = System.nanoTime() - startTime;

        // Printing the time it took each time I render my shape. As the size increase, the time increase. If the shape decrease, the time decrease as well.
        System.out.println(elapseTime);

        g2d.dispose();
    }

    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        doDrawing(g);
    }

    @Override
    public void actionPerformed(ActionEvent e)
    {
        repaint();
    }
}

public class MainFrame extends JFrame implements KeyListener
{
    public MainFrame()
    {
        initUI();

        setFocusable(true);
        addKeyListener(this);
    }

    public static void main(String[] args)
    {

        EventQueue.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                MainFrame ex = new MainFrame();
                ex.setVisible(true);
            }
        });
    }

    private void initUI()
    {
        final Surface surface = Surface.getInstance();
        add(surface);

        setTitle("My boggus apps");
        setSize(600, 400);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }


    @Override
    public void keyTyped(final KeyEvent e)
    {

    }

    @Override
    public void keyPressed(final KeyEvent e)
    {
        int key = e.getKeyCode();

        if (key == KeyEvent.VK_UP)
        {
            Scale.setScale(Scale.getScale() * 2);

            if (Scale.getScale() > 200000)
            {
                Scale.setScale(200000);
            }

            Surface.getInstance().repaint();
        }
        else if (key == KeyEvent.VK_DOWN)
        {
            Scale.setScale(Scale.getScale() / 2);

            if (Scale.getScale() < 1)
            {
                Scale.setScale(1);
            }

            Surface.getInstance().repaint();
        }
        else
        {
            System.out.println(key);
        }
    }

    @Override
    public void keyReleased(final KeyEvent e)
    {

    }
}


推荐答案

带有虚线笔划的长线的不良渲染性能是AWT Graphics2D和JavaFX 2中一个很长的已知且仍未解决的问题:

Bad rendering performance for long lines with dashed strokes is a very long known and still unresolved issue in AWT Graphics2D and also JavaFX 2:

  • AWT: https://bugs.openjdk.java.net/browse/JDK-6620013
  • JavaFX 2: https://bugs.openjdk.java.net/browse/JDK-8160600

在Java 8u152和9.0.1中仍未解决。但是,在9.0.1中的性能要好一些(在我的一项测试9.0.1与8u152中,大约是1.5s对4.0s)。

It is still unresolved in Java 8u152 and 9.0.1. However, performance in 9.0.1 is slightly better (about 1.5s vs. 4.0s in one of my tests 9.0.1 vs. 8u152).

背景:
长虚线被解析为它们包含的每个短破折号,即使这些破折号甚至都没有碰到剪切区域。

Background: Long dashed lines are resolved to each individual short dash they contain, even if none of these dashes even touches the clipping area.

已知但大多不令人满意的解决方法:

Known but mostly unsatisfying workarounds:


  1. 使用实线。 (并不能真正解决问题)

  2. 手动计算线段与剪辑rect的交点。仅将剪辑中的可见短部分绘制为新的Line2D。放下甚至不碰剪辑的线。 (复杂,仅限于Rectangle2D或Line2D等简单情况,不适用于一般形状)

  3. 使用带有纹理涂料的实线,例如棋盘格或网格。 (容易,非常依赖于角度,没有精确的破折号,莫尔条纹)

  1. Use solid lines. (does not really solve the problem)
  2. Manually calculate the lines' intersection points with the clip rect. Draw only the short visible parts within the clip as new Line2Ds. Drop lines that do not even touch the clip. (complicated, restricted to easy cases like Rectangle2D or Line2D, not applicable to general shapes)
  3. Use solid lines with textured paints like e.g. checkerboards or grids. (easy, very angle dependent, no precise dashes, moiré effects)

这篇关于在Java中绘制虚线时的性能问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆