HexMacroCellParameters.java
package org.fresnel.optics;
/**
* Parameters for a hexagonal macro cell composed of many small sub-zone-plates,
* all converging on a common image plane.
*
* <p>The macro cell is a regular hexagon with flat-top orientation and circumscribed
* radius {@code macroRadiusMm} (so the flat-to-flat distance is {@code √3 · macroRadiusMm}).
* Sub-elements are circular zone plates of diameter {@code subDiameterMm} packed on a
* triangular (hex) lattice with center-to-center pitch {@code subPitchMm}
* (must be ≥ {@code subDiameterMm}). Sub-elements whose centre lies inside the hex
* are kept; their support is clipped to both the sub-circle and the outer hex.
*
* <p>All sub-plates focus on a common target {@code (targetX, targetY, focal)} measured
* from the macro-cell centre. For each sub-plate centred at {@code (cx, cy)} the local
* off-axis offset is {@code (targetX - cx, targetY - cy)} so they constructively project
* the same point on the image plane.
*
* @param macroRadiusMm circumscribed radius of the outer hex (centre → vertex), mm
* @param subDiameterMm diameter of each sub-zone-plate, mm
* @param subPitchMm centre-to-centre spacing on the hex lattice, mm (≥ subDiameterMm)
* @param focalLengthMm z-distance from macro plane to common image plane, mm
* @param targetOffsetXmm in-plane X target offset from macro centre, mm
* @param targetOffsetYmm in-plane Y target offset from macro centre, mm
* @param wavelengthNm design wavelength, nm
* @param dpi printer resolution
* @param maskType binary amplitude or greyscale phase
* @param polarity mask polarity
*/
public record HexMacroCellParameters(
double macroRadiusMm,
double subDiameterMm,
double subPitchMm,
double focalLengthMm,
double targetOffsetXmm,
double targetOffsetYmm,
double wavelengthNm,
double dpi,
MaskType maskType,
Polarity polarity
) {
public HexMacroCellParameters {
if (macroRadiusMm <= 0) throw new IllegalArgumentException("macroRadiusMm must be > 0");
if (subDiameterMm <= 0) throw new IllegalArgumentException("subDiameterMm must be > 0");
if (subPitchMm < subDiameterMm)
throw new IllegalArgumentException("subPitchMm must be ≥ subDiameterMm");
if (subDiameterMm > 2.0 * macroRadiusMm)
throw new IllegalArgumentException("subDiameterMm must be ≤ 2·macroRadiusMm");
if (focalLengthMm <= 0) throw new IllegalArgumentException("focalLengthMm must be > 0");
if (wavelengthNm <= 0) throw new IllegalArgumentException("wavelengthNm must be > 0");
if (dpi <= 0) throw new IllegalArgumentException("dpi must be > 0");
if (maskType == null) throw new IllegalArgumentException("maskType must not be null");
if (polarity == null) throw new IllegalArgumentException("polarity must not be null");
}
/** Convenience constructor with on-axis target and binary positive mask. */
public static HexMacroCellParameters onAxis(
double macroRadiusMm,
double subDiameterMm,
double subPitchMm,
double focalLengthMm,
double wavelengthNm,
double dpi) {
return new HexMacroCellParameters(
macroRadiusMm, subDiameterMm, subPitchMm,
focalLengthMm, 0.0, 0.0,
wavelengthNm, dpi,
MaskType.BINARY_AMPLITUDE, Polarity.POSITIVE);
}
}