> My application needs to draw a variety of arbitrary shapes using
> different pen styles.
I think the problem you are running into is that our implementation
currently only has two modes:
Draw thin undashed lines
Draw lines using full path widening/dashing geometry calculation
Most other graphics packages typically have a thin line (integer length)
dashing pipeline which could be used in the case you have identified,
but we haven't developed such a pipeline yet. If we are drawing directly
to an X11 screen then we attempt to translate the dash pattern into an
X11 line style, but for offscreen rendering, we can't use that method.
It also happens to be a very degenerate case for the dashing code
since you are creating so many pieces with your dashes. With much
larger dashes I think the performance will pick up some, but won't
be as fast as a dedicated integer-length thin line dasher.
Another way to do this would be to render the line with no dashing
but with a 50% off/on texture image. It will be slower than a
dedicated integer dasher, but faster than using a 1,1 dashed
BasicStroke. I've attached an example - run it with an integer
argument for the size of the texture cell (I didn't notice
much difference between 1 or 100 so the size doesn't seem to
matter much).
Hope that helps...
...jim
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.GeneralPath;
public class BasicStrokePerf extends JFrame {
public static void main(String[] args) {
if (args.length > 0) {
makeScreen(args[0]);
}
new BasicStrokePerf((args.length > 0));
}
public static void makeScreen(String arg) {
int size;
try {
size = Integer.parseInt(arg);
} catch (NumberFormatException e) {
return;
}
BufferedImage bimg = new BufferedImage( size * 2, size * 2,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = bimg.createGraphics();
g2d.setColor(Color.black);
g2d.fillRect(0, 0, size*2, size*2);
g2d.setColor(Color.yellow);
for (int i = 0; i < size*2; i++) {
for (int j = i&1; j < size*2; j += 2) {
g2d.fillRect(i, j, 1, 1);
}
}
HalfScreen = new TexturePaint(bimg, new Rectangle(0, 0, size*2, size*2));
}
public BasicStrokePerf(final boolean dotted) {
setTitle("BasicStroke Performance Tester");
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}}
);
polyline = new GeneralPath();
make_data();
JPanel canvas = new JPanel() {
private int coin = 0;
public void paintComponent(Graphics g) {
super.paintComponent(g);
Rectangle clip = g.getClipBounds();
Graphics2D g2 = (Graphics2D)g;
// UNCOMMENT TO HAVE THE CLIP REGION HILITED FOR EACH PAINT
// Color c = ((coin++ % 2) == 0) ? Color.gray : Color.darkGray;
// g.setColor(c);
// g.fillRect(clip.x, clip.y, clip.width, clip.height);
g.setColor(Color.yellow);
if (dotted) {
if (HalfScreen != null) {
g2.setPaint(HalfScreen);
} else {
g2.setStroke(DOTTED);
}
}
g2.draw(polyline);
}
};
canvas.setBackground(Color.black);
canvas.setPreferredSize(new Dimension(PTS, 400));
JScrollPane sp = new JScrollPane(canvas);
sp.getHorizontalScrollBar().setUnitIncrement(5);
getContentPane().add(sp);
pack();
setSize(800,500);
setVisible(true);
}
// Fill GeneralPath with a sine wave
private void make_data() {
double i, xval, yval;
i = 0;
int cnt = 0;
polyline.moveTo(0,0);
while (cnt < PTS) {
xval = (i * 10.0);
yval = Math.sin(i) * 100.0 + 200;
polyline.lineTo((float)xval, (float)yval);
cnt++;
i += 0.1;
}
}
private static final BasicStroke SOLID = new BasicStroke(1.0f);
private static final BasicStroke DOTTED =
new BasicStroke(
1.0f,
BasicStroke.CAP_BUTT,
BasicStroke.JOIN_MITER,
10.0f,
new float[]{1.0f, 1.0f},
0.0f
);
private static TexturePaint HalfScreen;
private final int PTS = 2000;
private double[] xpts = new double[PTS];
private double[] ypts = new double[PTS];
private GeneralPath polyline;
}