Add Export Fused ROI CSV export
Lets a user export the current ROI as one CSV with a column per selected angle's value (RF peak freq, Bias A, Bias B, or velocity), once angles share a common (x, y) grid -- either via a live Fusion alignment result or because the open file is itself a previous Alignment Wizard export whose angles already share one grid on disk. Never triggers a background compute; angles without cached/stored data for the chosen value type are simply unavailable in the picker. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
"""SrasFile.angles_share_raw_grid(): the no-alignment-needed gating path for
|
||||
Export Fused ROI.
|
||||
|
||||
A plain multi-angle scan gives each angle its own bounding box and stage
|
||||
x_start (scan_format.md's whole reason v6 geometry is per-angle), so it must
|
||||
read as "not shareable" without a live alignment. A file the viewer's own
|
||||
Alignment Wizard exported repeats one Per-Angle Geometry record and one Row
|
||||
Table span for every angle (scan_format.md, "Files written by the viewer's
|
||||
Alignment Wizard"), so it must read as "shareable" with no alignment needed
|
||||
at all.
|
||||
|
||||
No Qt: this exercises sras_format/sras_compute/sras_align_export directly,
|
||||
mirroring tests/test_align_export.py.
|
||||
"""
|
||||
|
||||
import sras_align_export as export
|
||||
import sras_compute as compute
|
||||
from sras_format import SrasFile
|
||||
import tools.make_test_sras as gen
|
||||
|
||||
_THRESHOLD_MV = 80.0
|
||||
|
||||
|
||||
def test_single_angle_file_always_shares_its_grid(tmp_path):
|
||||
path = tmp_path / "one_angle.sras"
|
||||
gen.write(path, n_angles=1)
|
||||
sras = SrasFile(str(path))
|
||||
assert sras.angles_share_raw_grid()
|
||||
|
||||
|
||||
def test_plain_multi_angle_file_does_not_share_its_grid(tmp_path):
|
||||
"""tools.make_test_sras.write gives every angle its own geometry and
|
||||
stage x_start (build()'s `x_start = -0.5 + 0.1 * a`), matching how real
|
||||
v6 scans vary per angle — so this must read as "not shareable"."""
|
||||
path = tmp_path / "plain.sras"
|
||||
gen.write(path, n_angles=3)
|
||||
sras = SrasFile(str(path))
|
||||
assert not sras.angles_share_raw_grid()
|
||||
|
||||
|
||||
def test_wizard_exported_file_shares_its_grid(tmp_path):
|
||||
src_path = tmp_path / "rotating.sras"
|
||||
meta = gen.write_rotating(src_path, n_angles=4)
|
||||
sras = SrasFile(str(src_path))
|
||||
params = {a: compute.ManualAngleParams(rot, shift)
|
||||
for a, (rot, shift) in meta["truth"].items()}
|
||||
result = compute.build_manual_alignment(sras, 0, _THRESHOLD_MV, params)
|
||||
|
||||
out_path = tmp_path / "rotating_aligned.sras"
|
||||
export.write_aligned_sras(sras, result, out_path)
|
||||
out = SrasFile(str(out_path))
|
||||
|
||||
assert not sras.angles_share_raw_grid(), (
|
||||
"sanity check: the *source* rotating scan must NOT already share a "
|
||||
"grid, or this test would not actually exercise the wizard export")
|
||||
assert out.angles_share_raw_grid()
|
||||
|
||||
|
||||
def test_mutated_angle_breaks_the_shared_grid(tmp_path):
|
||||
"""A loaded SrasFile's x_start_mm is a public per-angle array (as
|
||||
tests/test_gui.py::test_alignment_geometry_is_stage_independent also
|
||||
relies on) -- mutating one angle's start must be visible here too."""
|
||||
src_path = tmp_path / "rotating.sras"
|
||||
meta = gen.write_rotating(src_path, n_angles=3)
|
||||
sras = SrasFile(str(src_path))
|
||||
params = {a: compute.ManualAngleParams(rot, shift)
|
||||
for a, (rot, shift) in meta["truth"].items()}
|
||||
result = compute.build_manual_alignment(sras, 0, _THRESHOLD_MV, params)
|
||||
out_path = tmp_path / "rotating_aligned.sras"
|
||||
export.write_aligned_sras(sras, result, out_path)
|
||||
out = SrasFile(str(out_path))
|
||||
assert out.angles_share_raw_grid()
|
||||
|
||||
out.x_start_mm[1] += 1.0
|
||||
assert not out.angles_share_raw_grid()
|
||||
Reference in New Issue
Block a user