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