AbstractMacroPrimitive.java

package com.varnernet.gerb4j.macro;

import com.varnernet.gerb4j.Polarity;

/**
 * Base for all concrete macro primitive implementations. Provides the exposure flag,
 * polarity-inversion, and coordinate-rotation helpers used by every primitive type.
 */
abstract class AbstractMacroPrimitive implements MacroPrimitive {

    /**
     * {@code true} when the primitive's exposure field is 1 (add); {@code false} when 0 (subtract).
     */
    protected final boolean exposed;

    protected AbstractMacroPrimitive(final boolean exposed) {
        this.exposed = exposed;
    }

    /**
     * Return the effective polarity: if exposure=1 use {@code base} as-is; if exposure=0 invert it
     * (CLEAR cuts into DARK and vice-versa).
     *
     * @param base the base polarity
     * @return the effective polarity
     */
    protected Polarity effectivePolarity(final Polarity base) {
        if (exposed) {
            return base;
        }
        return base == Polarity.DARK ? Polarity.CLEAR : Polarity.DARK;
    }

    /**
     * Rotate point {@code (x, y)} counter-clockwise by {@code degrees} about the macro origin {@code
     * (0, 0)}. Positive angles are CCW per the Gerber spec.
     *
     * @param x       the x coordinate
     * @param y       the y coordinate
     * @param degrees the rotation angle in degrees
     * @return the rotated point as [x', y']
     */
    protected static double[] rotatePoint(final double x, final double y, final double degrees) {
        if (degrees == 0.0) {
            return new double[]{x, y};
        }
        double r = Math.toRadians(degrees);
        double c = Math.cos(r);
        double s = Math.sin(r);
        return new double[]{x * c - y * s, x * s + y * c};
    }
}