CenterLineMacroPrimitive.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 21 — Center Line (filled rectangle). Format: {@code
 * 21,exposure,width,height,centerX,centerY,rotation}
 */
final class CenterLineMacroPrimitive extends AbstractMacroPrimitive {

    private final double width;
    private final double height;
    private final double centerX;
    private final double centerY;
    private final double rotation;

    CenterLineMacroPrimitive(
            final boolean exposed,
            final double width,
            final double height,
            final double centerX,
            final double centerY,
            final double rotation) {
        super(exposed);
        this.width = width;
        this.height = height;
        this.centerX = centerX;
        this.centerY = centerY;
        this.rotation = rotation;
    }

    @Override
    public Rectangle2D getBounds() {
        // Conservative axis-aligned bounds; for rotated rects this over-estimates slightly.
        double hw = width / 2.0;
        double hh = height / 2.0;
        double[][] corners = {
                {centerX - hw, centerY - hh},
                {centerX + hw, centerY - hh},
                {centerX + hw, centerY + hh},
                {centerX - hw, centerY + hh}
        };
        double minX = Double.MAX_VALUE;
        double maxX = -Double.MAX_VALUE;
        double minY = Double.MAX_VALUE;
        double maxY = -Double.MAX_VALUE;
        for (double[] c : corners) {
            double[] r = rotatePoint(c[0], c[1], rotation);
            minX = Math.min(minX, r[0]);
            maxX = Math.max(maxX, r[0]);
            minY = Math.min(minY, r[1]);
            maxY = Math.max(maxY, r[1]);
        }
        return new Rectangle2D.Double(minX, minY, maxX - minX, maxY - minY);
    }

    @Override
    public void render(final Point2D flashPoint, final GerberOutputTarget target, final Polarity polarity) {
        double hw = width / 2.0;
        double hh = height / 2.0;
        double[][] local = {
                {centerX - hw, centerY - hh},
                {centerX + hw, centerY - hh},
                {centerX + hw, centerY + hh},
                {centerX - hw, centerY + hh}
        };
        Path2D.Double path = new Path2D.Double();
        for (int i = 0; i < 4; i++) {
            double[] rot = rotatePoint(local[i][0], local[i][1], 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));
    }
}