【问题标题】:Painting an arbitrary collection of points quickly快速绘制任意点集合
【发布时间】:2016-06-07 20:58:19
【问题描述】:

我正在编写一个飞镖应用程序,并且已经实现了一个被绘制为 BufferedImage 的 Dartboard。

在渲染飞镖板时,我首先遍历 BufferedImage 的坐标并计算它所在的“段”。我将其包装成一个 DartboardSegment,它基本上只是一个包含少量点的集合额外的结构(它对应的板上的数字等)。

目前,要实际渲染飞镖靶,我会单独绘制每个点,如下所示:

    for (Point pt : allPoints)
    {
        DartboardSegment segment = getSegmentForPoint(pt);
        Color colour = DartboardUtil.getColourForSegment(segment);

        int rgb = colour.getRGB();
        int x = (int)pt.getX();
        int y = (int)pt.getY();
        dartboardImage.setRGB(x, y, rgb);
    }

显然这需要一些时间。这不是一个无法忍受的数量(绘制 500x500 区域大约需要 2-3 秒),但如果可以的话,我想消除这种“滞后”。在我的应用程序的其他领域,我遇到了更快的替代方法(例如 Graphics.fillRect())。

我已经看到 Graphics 类上有一个 fillPolgyon() 方法,但是我认为我不能轻松地将我的线段转换为多边形,因为它们的形状各不相同(例如,三元组的形状,圆形靶心...)。 java中是否有更快的方法一次绘制任意点数组,而不是循环遍历并单独绘制?

想要写的代码是这样的:

    for (DartboardSegment segment : allSegments)
    {
        Color colour = DartboardUtil.getColourForSegment(segment);
        Polgyon poly = segment.toPolygon();

        Graphics gfx = dartboardImage.getGraphics();
        gfx.setColor(colour);
        gfx.fillPolygon(poly);
    }

【问题讨论】:

  • 一次绘制一个 500 x 500 像素的区域所需的时间应该比 2 秒少得多(在我的计算机上,用随机数据填充它大约需要 20 毫秒)。因此,我怀疑您的问题不在于dartboardImage.setRGB(x, y, rgb);,而在于getSegmentForPoint()DartboardUtil.getColourForSegment()。你能告诉我们这些方法的代码吗?
  • 它们本质上都是hashmap查找,除了在第一次迭代中hashmap将被构建。实施我描述的更改后,时间已经下降到 0.3 秒,这就是调用这两个相同的方法。不过,不确定为什么您没有看到相同的行为。

标签: java swing graphics polygon


【解决方案1】:

我认为我不能轻松地将我的线段转换为多边形,因为它们的形状各不相同(例如三元组的形状,靶心的圆形......)

这里有一些可能会给你一些想法。

您可以创建 Shape 对象来表示飞镖的每个区域:

import java.awt.*;
import java.util.*;
import javax.swing.*;
import java.awt.geom.*;

public class Dartboard extends JPanel
{
    private ArrayList<DartboardSegment> segments = new ArrayList<DartboardSegment>();
    private int size = 500;
    private int radius = size / 2;
    private int border = 25;
    private int doubleSize = size - (2 * border);
    private int tripleSize = size / 2;
    private int thickness = 10;

    public Dartboard()
    {
        createSegmentWedges();

        int innerRadius = size - (2 * border);
        Shape outer = new Ellipse2D.Double(0, 0, size, size);
        Shape inner = new Ellipse2D.Double(border, border, innerRadius, innerRadius);
        Area circle = new Area( outer );
        circle.subtract( new Area(inner) );
        segments.add( new DartboardSegment(circle, Color.BLACK) );

        createBullsEye();
    }

    private void createSegmentWedges()
    {
        int angle = -99;

        for (int i = 0; i < 20; i++)
        {
            //  Create the wedge shape

            GeneralPath path = new GeneralPath();
            path.moveTo(250, 250);

            double radians1 = Math.toRadians( angle );
            double x1 = Math.cos(radians1) * radius;
            double y1 = Math.sin(radians1) * radius;
            path.lineTo(x1 + 250, y1 + 250);

            angle += 18;
            double radians2 = Math.toRadians( angle );
            double x2 = Math.cos(radians2) * radius;
            double y2 = Math.sin(radians2) * radius;
            path.lineTo(x2 + 250, y2 + 250);

            path.closePath();

            Color wedgeColor = (i % 2 == 0) ? Color.BLACK : Color.WHITE;
            segments.add( new DartboardSegment(path, wedgeColor) );

            //  Create the double/triple shapes

            Color color = (i % 2 == 0) ? Color.RED : Color.GREEN;
            createShape(doubleSize, path, color);
            createShape(tripleSize, path, color);
        }
    }

    private void createShape(int outerSize, GeneralPath path, Color color)
    {
        int outerOffset = (size - outerSize) / 2;
        int innerSize = outerSize - (2 * thickness);
        int innerOffset = (size - innerSize) / 2;

        Shape outer = new Ellipse2D.Double(outerOffset, outerOffset, outerSize, outerSize);
        Shape inner = new Ellipse2D.Double(innerOffset, innerOffset, innerSize, innerSize);

        Area circle = new Area( outer );
        circle.subtract( new Area(inner) );
        circle.intersect( new Area(path) );

        segments.add( new DartboardSegment(circle, color) );
    }

    private void createBullsEye()
    {
            int radius1 = 40;
            int offset1 = (size - radius1) / 2;
            Ellipse2D.Double bullsEye1 = new Ellipse2D.Double(offset1, offset1, radius1, radius1);
            segments.add( new DartboardSegment(bullsEye1, Color.GREEN) );

            int radius2 = 20;
            int offset2 = (size - radius2) / 2;
            Ellipse2D.Double bullsEye2 = new Ellipse2D.Double(offset2, offset2, radius2, radius2);
            segments.add( new DartboardSegment(bullsEye2, Color.RED) );
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        Graphics2D g2d = (Graphics2D)g.create();

        for (DartboardSegment segment: segments)
        {
            g2d.setColor( segment.getColor() );
            g2d.fill( segment.getShape() );
        }

    }

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

    class DartboardSegment
    {
        private Shape shape;
        private Color color;

        public DartboardSegment(Shape shape, Color color)
        {
            this.shape = shape;
            this.color = color;
        }

        public Shape getShape()
        {
            return shape;
        }

        public Color getColor()
        {
            return color;
        }
    }


    private static void createAndShowGUI()
    {
        JFrame frame = new JFrame("DartBoard");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new Dartboard());
        frame.setLocationByPlatform( true );
        frame.pack();
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater( () -> createAndShowGUI() );
/*
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowGUI();
            }
        });
*/
    }
}

【讨论】:

  • 为您为此付出的努力而受到好评。我已经编写了所有的三角逻辑来首先创建片段,只是还没有从它们中创建完全成熟的形状。我不再有速度问题,所以我不会在这里使用代码,但对于其他想要做同样事情的人来说,它肯定是一个有用的参考!
【解决方案2】:

经过一番深入研究,我认为解决此问题的一种方法是执行以下操作。这不是最整洁的,但我认为它会起作用:

    int i = 0;
    for (int y=0; y<height; y++)
    {
        for (int x=0; x<width; x++)
        {
            Point pt = new Point(x, y);
            DartboardSegment segment = getSegmentForPoint(pt);
            Color colour = DartboardUtil.getColourForSegment(segment);

            pixels[i] = colorToUse.getRGB();
            i++;
        }
    }

    dartboardImage.setRGB(0, 0, width, height, pixels, 0, width);

不过,我愿意接受更好的建议!

【讨论】:

  • 您可以通过不在循环内创建新的Point 来加快速度:在循环外声明它,并在内部循环中使用pt.setLocation(x, y)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多