快速绘制任意集合的点



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

在渲染飞镖板时,我首先迭代BufferedImage的坐标,并计算它所在的"段"。我将其封装成一个飞镖板段,它基本上只是一个具有少量额外结构的点的集合(它对应于板上的数字等)。

目前,为了实际渲染飞镖板,我单独绘制每个点,如下所示:

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);
}

我不认为我可以很容易地将线段转换为多边形,因为它们的形状各不相同(例如,三元组的形状,牛眼的圆形…)

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

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

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();
}
});
*/
}
}

经过进一步的挖掘,我认为解决这个问题的一个方法是执行以下操作。这不是最整洁的,但我认为它会起作用:

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);

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

最新更新