I\'m working with Areas in Java.
My test program draws three random triangles and combines them to form one or more polygons. After the Areas
I've re-factored your example to make testing easier, adding features of both answers. Restoring triangle.reset() seemed to eliminate the artifatcts for me. In addition,
Build the GUI on the event dispatch thread.
For rendering, extend a JComponent, e.g. JPanel, and override paintComponent().
Absent subcomponents having a preferred size, override getPreferredSize().
Use RenderingHints.
SSCCE:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.awt.geom.PathIterator;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/** @see http://stackoverflow.com/q/9526835/230513 */
public class AreaTest extends JPanel {
private static final int SIZE = 500;
private static final int INSET = SIZE / 10;
private static final int BOUND = SIZE - 2 * INSET;
private static final int N = 5;
private static final AffineTransform I = new AffineTransform();
private static final double FLATNESS = 1;
private static final Random random = new Random();
private Area area = new Area();
private List areaSegments = new ArrayList();
private int count = N;
AreaTest() {
setLayout(new BorderLayout());
create();
add(new JPanel() {
@Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.lightGray);
g2d.fill(area);
g.setColor(Color.black);
for (Line2D.Double line : areaSegments) {
g2d.draw(line);
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(SIZE, SIZE);
}
});
JPanel control = new JPanel();
control.add(new JButton(new AbstractAction("Update") {
@Override
public void actionPerformed(ActionEvent e) {
create();
repaint();
}
}));
JSpinner countSpinner = new JSpinner();
countSpinner.setModel(new SpinnerNumberModel(N, 3, 42, 1));
countSpinner.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
JSpinner s = (JSpinner) e.getSource();
count = ((Integer) s.getValue()).intValue();
}
});
control.add(countSpinner);
add(control, BorderLayout.SOUTH);
}
private int randomPoint() {
return random.nextInt(BOUND) + INSET;
}
private void create() {
area.reset();
areaSegments.clear();
Path2D.Double triangle = new Path2D.Double();
// Draw three random triangles
for (int i = 0; i < count; i++) {
triangle.moveTo(randomPoint(), randomPoint());
triangle.lineTo(randomPoint(), randomPoint());
triangle.lineTo(randomPoint(), randomPoint());
triangle.closePath();
area.add(new Area(triangle));
triangle.reset();
}
// Note: we're storing double[] and not Point2D.Double
List areaPoints = new ArrayList();
double[] coords = new double[6];
for (PathIterator pi = area.getPathIterator(I, FLATNESS);
!pi.isDone(); pi.next()) {
// Because the Area is composed of straight lines
int type = pi.currentSegment(coords);
// We record a double array of {segment type, x coord, y coord}
double[] pathIteratorCoords = {type, coords[0], coords[1]};
areaPoints.add(pathIteratorCoords);
}
// To record where each polygon starts
double[] start = new double[3];
for (int i = 0; i < areaPoints.size(); i++) {
// If we're not on the last point, return a line from this point to the next
double[] currentElement = areaPoints.get(i);
// We need a default value in case we've reached the end of the List
double[] nextElement = {-1, -1, -1};
if (i < areaPoints.size() - 1) {
nextElement = areaPoints.get(i + 1);
}
// Make the lines
if (currentElement[0] == PathIterator.SEG_MOVETO) {
// Record where the polygon started to close it later
start = currentElement;
}
if (nextElement[0] == PathIterator.SEG_LINETO) {
areaSegments.add(
new Line2D.Double(
currentElement[1], currentElement[2],
nextElement[1], nextElement[2]));
} else if (nextElement[0] == PathIterator.SEG_CLOSE) {
areaSegments.add(
new Line2D.Double(
currentElement[1], currentElement[2],
start[1], start[2]));
}
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame f = new JFrame();
f.add(new AreaTest());
f.pack();
f.setLocationRelativeTo(null);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setResizable(false);
f.setVisible(true);
}
});
}
}