Dedup format layer; public accessors replace private reach-throughs
- SrasFile: _parse_v6 now retains per-angle x_delta and the verbatim preamble/background byte spans, and gains public data_offset, y_pos_per_angle, and iter_angle_blocks() (which now owns the ragged block-offset walk used three separate places before). - sras_edit_scans: the 70-line re-parse of the v6 header sections (_read_v6_sections/_reread_span/_v6_angle_offsets) collapses into a _write_v6 that consumes SrasFile directly — verified byte-identical round-trip on v6 int8/int16 and legacy files. Eight print-and-exit pairs become _die(). - tools/make_test_sras imports the struct layouts from sras_format and the rotation matrix from sras_compute instead of re-declaring them (byte assembly stays independent of the reader). - sras_compute: block_mean_2d, pixel_pitch_mm, nominal_delta_deg made public (they were GUI-facing); registration_workers() and default_max_workers() wrap the remaining private reach-throughs from sras_workers. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -40,7 +40,7 @@ def mm_transform(sras: SrasFile, result, angle_idx: int) -> np.ndarray:
|
||||
per-angle pixel pitches; undoing both must leave something orthonormal, or
|
||||
the transform is smuggling in a scale or a shear.
|
||||
"""
|
||||
dx_a, dy_a = compute._pixel_pitch_mm(sras, angle_idx)
|
||||
dx_a, dy_a = compute.pixel_pitch_mm(sras, angle_idx)
|
||||
A_out = np.array([[0.0, result.canvas_dx_mm], [result.canvas_dy_mm, 0.0]])
|
||||
D = np.array([[0.0, 1.0 / dy_a], [1.0 / dx_a, 0.0]])
|
||||
return np.linalg.inv(D) @ result.per_angle[angle_idx].matrix @ np.linalg.inv(A_out)
|
||||
@@ -99,7 +99,7 @@ def test_stage_coordinates_are_not_consulted(rig):
|
||||
moved = SrasFile(str(rig.path))
|
||||
for a in range(1, moved.n_angles):
|
||||
moved.x_start_mm[a] += 13.5 * a
|
||||
moved._y_pos_per_angle[a] = moved._y_pos_per_angle[a] - 9.25 * a
|
||||
moved.y_pos_per_angle[a] = moved.y_pos_per_angle[a] - 9.25 * a
|
||||
moved_dc4 = dc4_images(moved)
|
||||
moved_fits = {a: compute.register_angle_to_reference(
|
||||
moved, a, 0, moved_dc4, dc_threshold_mv=_THRESHOLD_MV)
|
||||
@@ -118,7 +118,7 @@ def test_canvas_is_reference_grid_extended(rig):
|
||||
assert np.allclose(t0.offset, np.round(t0.offset)), \
|
||||
f"angle 0 does not land on whole canvas pixels: {t0.offset}"
|
||||
assert ((result.canvas_dx_mm, result.canvas_dy_mm)
|
||||
== compute._pixel_pitch_mm(sras, 0)), \
|
||||
== compute.pixel_pitch_mm(sras, 0)), \
|
||||
"canvas pitch is angle 0's own pitch"
|
||||
|
||||
n_rows, n_cols = result.canvas_shape
|
||||
@@ -169,7 +169,7 @@ def test_downsampled_preview_lands_with_full_res(rig):
|
||||
result.canvas_origin_mm, result.canvas_shape)
|
||||
fy, fx = 4, 16
|
||||
small = compute.reproject_mask(
|
||||
sras, a, 0, compute._block_mean_2d(full_mask, fy, fx),
|
||||
sras, a, 0, compute.block_mean_2d(full_mask, fy, fx),
|
||||
p.rotation_deg, p.shift_mm, (pitch[0] * fx, pitch[1] * fy),
|
||||
result.canvas_origin_mm,
|
||||
(result.canvas_shape[0] // fy, result.canvas_shape[1] // fx),
|
||||
|
||||
+3
-3
@@ -261,7 +261,7 @@ def test_manual_alignment_geometry(ctx):
|
||||
assert np.allclose(compute._center_idx(s, 0),
|
||||
[(n_rows - 1) / 2, (n_frames - 1) / 2]), \
|
||||
"array center is the geometric center of the pixel grid"
|
||||
dx0, dy0 = compute._pixel_pitch_mm(s, 0)
|
||||
dx0, dy0 = compute.pixel_pitch_mm(s, 0)
|
||||
assert np.allclose(compute._local_half_extent_mm(s, 0),
|
||||
[(n_frames - 1) / 2 * abs(dx0), (n_rows - 1) / 2 * abs(dy0)]), \
|
||||
"local half-extent is derived from shape and pitch alone"
|
||||
@@ -270,7 +270,7 @@ def test_manual_alignment_geometry(ctx):
|
||||
moved = SrasFile(str(ctx.path))
|
||||
for a in range(1, moved.n_angles):
|
||||
moved.x_start_mm[a] += 7.5
|
||||
moved._y_pos_per_angle[a] = moved._y_pos_per_angle[a] + 3.25
|
||||
moved.y_pos_per_angle[a] = moved.y_pos_per_angle[a] + 3.25
|
||||
origin_b, shape_b = compute.canvas_for_params(moved, 0, (dx0, dy0), identity)
|
||||
assert shape_a == shape_b and np.allclose(origin_a, origin_b), \
|
||||
("moving every non-reference angle's scan window must leave the canvas "
|
||||
@@ -356,7 +356,7 @@ def test_auto_derotate(ctx):
|
||||
dlg, s, active = ctx.dlg, ctx.s, ctx.active
|
||||
shift_before_derotate = dlg._angle_params[active].shift_mm
|
||||
dlg._on_auto_derotate()
|
||||
nominal = compute._nominal_delta_deg(s, active, dlg._ref_angle_idx)
|
||||
nominal = compute.nominal_delta_deg(s, active, dlg._ref_angle_idx)
|
||||
assert abs(dlg._angle_params[active].rotation_deg - nominal) < 1e-6, \
|
||||
"auto de-rotate seeded rotation from the stage's reported angle"
|
||||
assert dlg._angle_params[active].shift_mm == shift_before_derotate, \
|
||||
|
||||
Reference in New Issue
Block a user