OutlineMacroPrimitive.java
package com.varnernet.gerb4j.macro;
import com.varnernet.gerb4j.Polarity;
import com.varnernet.gerb4j.render.GerberOutputTarget;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
/**
* Gerber macro primitive type 4 — Outline (filled polygon with arbitrary vertices). Format: {@code
* 4,exposure,n,x1,y1,x2,y2,...,xn+1,yn+1,rotation}
*
* <p>The {@code n+1} coordinate pair closes the outline back to the first vertex. All vertices are
* expressed in aperture-local coordinates before rotation.
*/
final class OutlineMacroPrimitive extends AbstractMacroPrimitive {
/**
* Vertex X coordinates in aperture-local space (before rotation).
*/
private final double[] xs;
/**
* Vertex Y coordinates in aperture-local space (before rotation).
*/
private final double[] ys;
private final double rotation;
OutlineMacroPrimitive(final boolean exposed, final double[] xs, final double[] ys, final double rotation) {
super(exposed);
this.xs = xs.clone();
this.ys = ys.clone();
this.rotation = rotation;
}
@Override
public Rectangle2D getBounds() {
double minX = Double.MAX_VALUE;
double maxX = -Double.MAX_VALUE;
double minY = Double.MAX_VALUE;
double maxY = -Double.MAX_VALUE;
for (int i = 0; i < xs.length; i++) {
double[] rot = rotatePoint(xs[i], ys[i], rotation);
minX = Math.min(minX, rot[0]);
maxX = Math.max(maxX, rot[0]);
minY = Math.min(minY, rot[1]);
maxY = Math.max(maxY, rot[1]);
}
if (minX > maxX) {
return null;
}
return new Rectangle2D.Double(minX, minY, maxX - minX, maxY - minY);
}
@Override
public void render(final Point2D flashPoint, final GerberOutputTarget target, final Polarity polarity) {
Path2D.Double path = new Path2D.Double();
for (int i = 0; i < xs.length; i++) {
double[] rot = rotatePoint(xs[i], ys[i], rotation);
if (i == 0) {
path.moveTo(flashPoint.getX() + rot[0], flashPoint.getY() + rot[1]);
} else {
path.lineTo(flashPoint.getX() + rot[0], flashPoint.getY() + rot[1]);
}
}
path.closePath();
target.drawRegion(path, effectivePolarity(polarity));
}
}