raygeo.ops.raster
ScanLine
A single scan line with its pixel coverage and mm-space endpoints.
Produced by generate_scan_lines. Each line has a unique index, start/end positions in mm, and the set of pixels it intersects in the image.
end_mm
end_mm: tuple[float, float]
End position of the scan line in mm space.
index
index: int
The index of this scan line (used to determine alternating direction).
line_interval_mm
line_interval_mm: float
Spacing between scan lines in mm.
pixels
pixels: list[tuple[int, int]]
Pixel coordinates covered by this scan line.
start_mm
start_mm: tuple[float, float]
Start position of the scan line in mm space.
direction()
direction() -> tuple[float, float]
Normalised direction vector from start to end in mm space.
| Parameter | Type | Description |
|---|---|---|
| Returns | tuple[float, float] | (dx, dy) unit vector. |
| Complexity | O(1) |
length_mm()
length_mm() -> float
Compute the length of this scan line in mm.
| Parameter | Type | Description |
|---|---|---|
| Returns | float | Total path length in mm. |
| Complexity | O(1) |
pixel_to_mm()
pixel_to_mm(
px: int,
py: int,
pixels_per_mm: tuple[float, float],
) -> tuple[float, float]
Convert pixel coordinates to mm space, projected onto this scan line.
| Parameter | Type | Description |
|---|---|---|
px | int | X pixel coordinate. |
py | int | Y pixel coordinate. |
pixels_per_mm | tuple[float, float] | (x, y) pixel density in px/mm. |
| Returns | tuple[float, float] | (x, y) position in mm, projected onto the scan line. |
| Complexity | O(1) |
ScanMode
Scan mode for raster operations.
SEGMENTED skips zero-power gaps within a scan line. FULL_SWEEP emits the full line with power
values (zeros included).
Functions
downsample_power_values()
downsample_power_values(
power_values: numpy.ndarray,
start_mm: tuple[float, float],
end_mm: tuple[float, float],
sample_interval_mm: float,
) -> tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray]
Downsample power values along a scan segment.
If the sample interval is larger than the native pixel spacing, the power values are resampled by nearest-neighbour at the target spacing. Otherwise the original values are returned with their corresponding positions.
| Parameter | Type | Description |
|---|---|---|
power_values | numpy.ndarray | 1-D array of byte power values. |
start_mm | tuple[float, float] | (x, y) start position of the segment in mm. |
end_mm | tuple[float, float] | (x, y) end position of the segment in mm. |
sample_interval_mm | float | Desired sample spacing in mm. |
| Returns | tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray] | (power, x_mm, y_mm) of downsampled values. |
| Complexity | O(n) where n = number of power values |
extract_zero_power_segments()
extract_zero_power_segments(
start: tuple[float, float, float],
end: tuple[float, float, float],
power_values: bytes,
) -> list[float]
Extract zero-power segment endpoints from scanline power data.
Finds contiguous runs of zero values in power_values and computes their 3D start/end points via linear interpolation along the scanline segment from start to end.
| Parameter | Type | Description |
|---|---|---|
start | tuple[float, float, float] | (x, y, z) start position of the scanline in mm. |
end | tuple[float, float, float] | (x, y, z) end position of the scanline in mm. |
power_values | bytes | Per-step power bytes. |
| Returns | list[float] | Flat list of [sx, sy, sz, ex, ey, ez, ...] segments. |
| Complexity | O(n) where n = number of steps |
find_mask_bounding_box()
find_mask_bounding_box(mask: numpy.ndarray) -> tuple[int, int, int, int] | None
Find the bounding box of non-zero pixels in a binary mask.
Scans the mask and returns the (y_min, y_max, x_min, x_max) of the smallest axis-aligned rectangle covering all non-zero pixels.
| Parameter | Type | Description |
|---|---|---|
mask | numpy.ndarray | 2-D binary mask array. |
| Returns | tuple[int, int, int, int] | None | (y_min, y_max, x_min, x_max) pixel coordinates, or None if the mask is entirely zero. |
| Complexity | O(h*w) |
find_segments()
find_segments(values: numpy.ndarray) -> list[tuple[int, int]]
Find contiguous non-zero segments in a 1-D array.
Returns a list of (start, end) index pairs covering every run of consecutive non-zero values.
| Parameter | Type | Description |
|---|---|---|
values | numpy.ndarray | 1-D array of byte values. |
| Returns | list[tuple[int, int]] | List of (start, end) index pairs. |
| Complexity | O(n) |
generate_horizontal_scan_positions()
generate_horizontal_scan_positions(
y_min_px: int,
y_max_px: int,
height_px: int,
pixels_per_mm: tuple[float, float],
line_interval_mm: float,
offset_y_mm: float,
) -> tuple[list[float], list[float]]
Compute Y positions for horizontal scan lines.
Given a vertical pixel range, computes the mm and pixel Y coordinates of evenly-spaced scan lines (aligned to a global grid defined by line_interval_mm and offset_y_mm).
| Parameter | Type | Description |
|---|---|---|
y_min_px | int | Minimum Y pixel coordinate. |
y_max_px | int | Maximum Y pixel coordinate. |
height_px | int | Image height in pixels. |
pixels_per_mm | tuple[float, float] | (x, y) pixel density in px/mm. |
line_interval_mm | float | Spacing between scan lines in mm. |
offset_y_mm | float | Global Y offset in mm. |
| Returns | tuple[list[float], list[float]] | (y_coords_mm, y_coords_px) tuple of Y positions. |
| Complexity | O(n) where n = number of scan lines |
generate_scan_lines()
generate_scan_lines(
bbox: tuple[int, int, int, int],
image_size: tuple[int, int],
pixels_per_mm: tuple[float, float],
line_interval_mm: float,
direction_degrees: float = 0,
offset_x_mm: float = 0,
offset_y_mm: float = 0,
global_center_mm: tuple[float, float] | None = None,
) -> list[ScanLine]
Generate scan lines covering a bounding box.
Creates a set of parallel scan lines at a given angle and spacing that cover the bounding box region. Each line is rasterised to pixels and stored as a ScanLine.
| Parameter | Type | Description |
|---|---|---|
bbox | tuple[int, int, int, int] | (y_min, y_max, x_min, x_max) of the region. |
image_size | tuple[int, int] | (width, height) of the image in pixels. |
pixels_per_mm | tuple[float, float] | (x, y) pixel density in px/mm. |
line_interval_mm | float | Spacing between scan lines in mm. |
direction_degrees | float = 0 | Scan direction angle in degrees. |
offset_x_mm | float = 0 | Global X offset in mm. |
offset_y_mm | float = 0 | Global Y offset in mm. |
global_center_mm | tuple[float, float] | None = None | Optional rotation centre in mm; defaults to the bbox centre + offset. |
| Returns | list[ScanLine] | List of ScanLine objects. |
| Complexity | O(n * p) where n = number of lines, p = pixels per line |
line_pixels()
line_pixels(
start: tuple[float, float],
end: tuple[float, float],
width: int,
height: int,
) -> list[tuple[int, int]]
Rasterise a line segment into pixel coordinates.
Uses Bresenham's line algorithm to enumerate all integer pixel positions intersecting the line from
start to end, clipped to the image dimensions (width, height).
| Parameter | Type | Description |
|---|---|---|
start | tuple[float, float] | (x, y) start position in pixel coordinates. |
end | tuple[float, float] | (x, y) end position in pixel coordinates. |
width | int | Image width in pixels. |
height | int | Image height in pixels. |
| Returns | list[tuple[int, int]] | List of (x, y) pixel coordinates on the line. |
| Complexity | O(n) where n = number of pixels on the line |
rasterize_mask_lines()
rasterize_mask_lines(
mask: numpy.NDArray[numpy.uint8],
pixels_per_mm: tuple[float, float],
offset_x_mm: float,
offset_y_mm: float,
line_interval_mm: float,
z: float = 0,
angle: float = 0,
scan_mode: ScanMode = ScanMode.SEGMENTED,
) -> ops.Ops
Rasterise a binary mask into line-to commands (no power).
Similar to rasterize_mask_scan but emits move-to/line-to commands with a Z offset instead of scan-to with power values. Useful for simple contour or hatch patterns.
| Parameter | Type | Description |
|---|---|---|
mask | numpy.NDArray[numpy.uint8] | 2-D binary mask array. |
pixels_per_mm | tuple[float, float] | (x, y) pixel density in px/mm. |
offset_x_mm | float | Global X offset in mm. |
offset_y_mm | float | Global Y offset in mm. |
line_interval_mm | float | Spacing between scan lines in mm. |
z | float = 0 | Z offset for the lines in mm. |
angle | float = 0 | Scan angle in degrees. |
scan_mode | ScanMode = ScanMode.SEGMENTED | ScanMode.SEGMENTED or ScanMode.FULL_SWEEP. |
| Returns | ops.Ops | An ~raygeo.ops.Ops container. |
| Complexity | O(h * w + n * p) where h, w = image dimensions, n = scan lines, p = pixels per line |
rasterize_mask_scan()
rasterize_mask_scan(
mask: numpy.NDArray[numpy.uint8],
pixels_per_mm: tuple[float, float],
offset_x_mm: float,
offset_y_mm: float,
line_interval_mm: float,
step_power: float = 1,
angle: float = 0,
scan_mode: ScanMode = ScanMode.SEGMENTED,
) -> ops.Ops
Rasterise a binary mask into scan-to commands.
Generates scan lines covering the mask's bounding box, samples the mask along each line, and emits move-to/scan-to commands for each non-zero segment (or the full sweep).
| Parameter | Type | Description |
|---|---|---|
mask | numpy.NDArray[numpy.uint8] | 2-D binary mask array. |
pixels_per_mm | tuple[float, float] | (x, y) pixel density in px/mm. |
offset_x_mm | float | Global X offset in mm. |
offset_y_mm | float | Global Y offset in mm. |
line_interval_mm | float | Spacing between scan lines in mm. |
step_power | float = 1 | Power value (0-1) for exposed pixels. |
angle | float = 0 | Scan angle in degrees. |
scan_mode | ScanMode = ScanMode.SEGMENTED | ScanMode.SEGMENTED or ScanMode.FULL_SWEEP. |
| Returns | ops.Ops | An ~raygeo.ops.Ops container. |
| Complexity | O(h * w + n * p) where h, w = image dimensions, n = scan lines, p = pixels per line |
rasterize_multi_pass()
rasterize_multi_pass(
gray_image: numpy.NDArray[numpy.uint8],
pixels_per_mm: tuple[float, float],
offset_x_mm: float,
offset_y_mm: float,
line_interval_mm: float,
num_depth_levels: int,
z_step_down: float,
angle: float = 0,
angle_increment: float = 0,
scan_mode: ScanMode = ScanMode.SEGMENTED,
) -> ops.Ops
Rasterise a grayscale image as multiple Z-depth passes.
Decomposes the grayscale image into num_depth_levels layers by depth-slicing, then rasterises each layer with a progressive Z offset and optional per-pass angle increment.
| Parameter | Type | Description |
|---|---|---|
gray_image | numpy.NDArray[numpy.uint8] | 2-D grayscale image (0 = black, 255 = white). |
pixels_per_mm | tuple[float, float] | (x, y) pixel density in px/mm. |
offset_x_mm | float | Global X offset in mm. |
offset_y_mm | float | Global Y offset in mm. |
line_interval_mm | float | Spacing between scan lines in mm. |
num_depth_levels | int | Number of depth layers to produce. |
z_step_down | float | Z decrement per depth layer in mm. |
angle | float = 0 | Initial scan angle in degrees. |
angle_increment | float = 0 | Angle added per depth layer in degrees. |
scan_mode | ScanMode = ScanMode.SEGMENTED | ScanMode.SEGMENTED or ScanMode.FULL_SWEEP. |
| Returns | ops.Ops | An ~raygeo.ops.Ops container. |
| Complexity | O(d * (h * w + n * p)) where d = depth levels, h, w = image dims, n = scan lines, p = pixels per line |
rasterize_power_modulation()
rasterize_power_modulation(
gray_image: numpy.NDArray[numpy.uint8],
alpha: numpy.NDArray[numpy.uint8],
pixels_per_mm: tuple[float, float],
offset_x_mm: float,
offset_y_mm: float,
line_interval_mm: float,
sample_interval_mm: float,
min_power: float = 0,
max_power: float = 1,
step_power: float = 1,
num_power_levels: int = 256,
angle: float = 0,
scan_mode: ScanMode = ScanMode.SEGMENTED,
) -> ops.Ops
Rasterise a grayscale image with power-modulated scans.
Samples the image along scan lines and computes per-pixel power values from the grayscale intensity and alpha channel, then emits move-to/scan-to commands with the modulated power.
| Parameter | Type | Description |
|---|---|---|
gray_image | numpy.NDArray[numpy.uint8] | 2-D grayscale image (0 = black, 255 = white). |
alpha | numpy.NDArray[numpy.uint8] | 2-D alpha mask (0 = transparent/no emission). |
pixels_per_mm | tuple[float, float] | (x, y) pixel density in px/mm. |
offset_x_mm | float | Global X offset in mm. |
offset_y_mm | float | Global Y offset in mm. |
line_interval_mm | float | Spacing between scan lines in mm. |
sample_interval_mm | float | Output sample spacing in mm. |
min_power | float = 0 | Minimum power fraction (for white pixels). |
max_power | float = 1 | Maximum power fraction (for black pixels). |
step_power | float = 1 | Global power multiplier. |
num_power_levels | int = 256 | Number of quantised power levels. |
angle | float = 0 | Scan angle in degrees. |
scan_mode | ScanMode = ScanMode.SEGMENTED | ScanMode.SEGMENTED or ScanMode.FULL_SWEEP. |
| Returns | ops.Ops | An ~raygeo.ops.Ops container. |
| Complexity | O(h * w + n * p) where h, w = image dimensions, n = scan lines, p = pixels per line |
resample_rows()
resample_rows(
image: numpy.NDArray[numpy.uint8],
y_coords_px: numpy.ndarray,
) -> numpy.NDArray[numpy.uint8]
Resample image rows at arbitrary Y coordinates.
Performs linear interpolation between adjacent rows to sample the image at the given (potentially fractional) Y positions.
| Parameter | Type | Description |
|---|---|---|
image | numpy.NDArray[numpy.uint8] | 2-D input image array. |
y_coords_px | numpy.ndarray | 1-D array of Y pixel coordinates. |
| Returns | numpy.NDArray[numpy.uint8] | 2-D array with shape (len(y_coords_px), width). |
| Complexity | O(m * w) where m = output rows, w = image width |