radioviz.tools.measurement_tool

Measurement tool module for radioviz application.

This module implements a built-in tool to measure segment lengths and angle amplitudes on image windows. It provides a dock widget with two tables (segments and angles), interactive selection sessions, overlays, and workspace serialization for both JSON and HDF5 formats.

Functions

draw_angle_overlay(overlay, axes)

Draw angle overlays.

draw_segment_overlay(overlay, axes)

Draw segment overlays.

Classes

AngleMeasurementData(name, color[, p1, p2, ...])

Data class representing an angle measurement.

AngleMeasurementWorkspaceSpec(id, name[, ...])

Workspace specification for an angle measurement.

AngleTableModel(store[, parent])

Table model for displaying angle measurements.

MeasurementDataProtocol(*args, **kwargs)

Protocol defining the common interface for measurement data types.

MeasurementFilterProxyModel([parent])

Proxy model for filtering measurements by active image.

MeasurementSelectionDialog(measurement_type)

Dialog for selecting measurement parameters.

MeasurementTool()

Tool for measuring segment lengths and angle amplitudes.

MeasurementToolController(tool_ctx, tool)

Controller for the measurement tool.

MeasurementToolDock(parent, controller)

Dock widget for the measurement tool.

MeasurementToolSession(tool_controller, ...)

Session for measurement creation.

MeasurementType(*values)

Measurement types supported by the measurement tool.

SegmentMeasurementData(name, color[, p1, ...])

Data class representing a segment measurement.

SegmentMeasurementWorkspaceSpec(id, name[, ...])

Workspace specification for a segment measurement.

SegmentTableModel(store[, parent])

Table model for displaying segment measurements.

class radioviz.tools.measurement_tool.AngleMeasurementData(name: str, color: Color, p1: tuple[float, float] | None = None, p2: tuple[float, float] | None = None, p3: tuple[float, float] | None = None, image_controller: ImageWindowController | None = None, session_id: UUID | None = None, measurement_id: UUID | None = None, show_overlay: bool | None = True, show_label: bool | None = False, show_measure: bool | None = True, angle_deg: float | None = None)[source]

Bases: object

Data class representing an angle measurement.

Initialize an AngleMeasurementData instance.

Parameters:
  • name (str) – Measurement name

  • color (Color) – Measurement color

  • p1 (tuple[float, float], optional) – First point (x, y)

  • p2 (tuple[float, float], optional) – Vertex point (x, y)

  • p3 (tuple[float, float], optional) – Third point (x, y)

  • image_controller (Optional[ImageWindowController]) – Image controller owning the measurement

  • session_id (Optional[UUID]) – Session identifier

  • measurement_id (Optional[UUID]) – Unique identifier for the measurement

  • show_overlay (Optional[bool]) – Whether the overlay is visible

  • show_label (Optional[bool]) – Whether the label text is visible

  • show_measure (Optional[bool]) – Whether the measurement value is visible

  • angle_deg (Optional[float]) – Precomputed angle in degrees

calculate_properties() None[source]

Compute angle measurement from current geometry.

to_workspace_spec(include_data: bool) AngleMeasurementWorkspaceSpec[source]

Convert this measurement to a workspace specification.

Parameters:

include_data (bool) – Whether to include computed data

Returns:

Workspace specification

Return type:

AngleMeasurementWorkspaceSpec

Raises:

RuntimeError – when attempting to serialize incomplete geometry

class radioviz.tools.measurement_tool.AngleMeasurementWorkspaceSpec(id: UUID, name: str, image_controller_id: UUID | None = None, color: tuple[float, float, float] = (0.0, 0.0, 0.0), p1: tuple[float, float] = (0.0, 0.0), p2: tuple[float, float] = (0.0, 0.0), p3: tuple[float, float] = (0.0, 0.0), show_overlay: bool = True, show_label: bool = False, show_measure: bool = True, angle_deg: float = 0.0)[source]

Bases: object

Workspace specification for an angle measurement.

class radioviz.tools.measurement_tool.AngleTableModel(store: ItemStore[AngleMeasurementData], parent: QObject | None = None)[source]

Bases: ItemModel

Table model for displaying angle measurements.

Initialize the angle table model.

Parameters:
  • store (AngleStore) – Store containing angle data

  • parent (QObject, optional) – Parent object

data_for(item: AngleMeasurementData, column: int, role: int = ItemDataRole.DisplayRole) Any[source]

Return data for an angle cell.

Parameters:
  • item (AngleMeasurementData) – Angle data item

  • column (int) – Column index

  • role (Qt.ItemDataRole) – Item data role

Returns:

Cell data

Return type:

Any

flags(index: QModelIndex | QPersistentModelIndex, /) ItemFlag[source]

Return item flags for an angle cell.

Parameters:

index (QModelIndex) – Index of the item

Returns:

Item flags

Return type:

Qt.ItemFlag

set_data_for(item: AngleMeasurementData, column: int, value: Any, role: int = ItemDataRole.DisplayRole) bool[source]

Set data for a specific angle cell.

Parameters:
  • item (AngleMeasurementData) – Angle data item

  • column (int) – Column index

  • value (Any) – Value to set

  • role (Qt.ItemDataRole) – Item data role

Returns:

True if successful

Return type:

bool

class radioviz.tools.measurement_tool.MeasurementDataProtocol(*args, **kwargs)[source]

Bases: Protocol

Protocol defining the common interface for measurement data types.

class radioviz.tools.measurement_tool.MeasurementFilterProxyModel(parent: QObject | None = None)[source]

Bases: QSortFilterProxyModel

Proxy model for filtering measurements by active image.

Initialize the proxy model.

Parameters:

parent (QObject, optional) – Parent object

filterAcceptsRow(source_row: int, source_parent: QModelIndex | QPersistentModelIndex) bool[source]

Decide whether a row should be accepted.

Parameters:
  • source_row (int) – Row in the source model

  • source_parent (QModelIndex) – Source parent index

Returns:

True if accepted

Return type:

bool

set_active_image(image_controller: ImageWindowController | None) None[source]

Set the active image controller for filtering.

Parameters:

image_controller (Optional[ImageWindowController]) – Active image controller

set_filter_enabled(enabled: bool) None[source]

Enable or disable filtering.

Parameters:

enabled (bool) – Whether filtering is enabled

class radioviz.tools.measurement_tool.MeasurementSelectionDialog(measurement_type: MeasurementType, parent: QWidget | None = None)[source]

Bases: QDialog

Dialog for selecting measurement parameters.

Initialize the measurement selection dialog.

Parameters:
  • measurement_type (MeasurementType) – Initial measurement type

  • parent (QWidget, optional) – Parent widget

_on_measurement_changed(measurement_type: MeasurementType) None[source]

Handle measurement type changes.

Parameters:

measurement_type (MeasurementType) – New measurement type

_update_instructions() None[source]

Update instruction text based on measurement type.

measurement_type_changed

Signal emitted when measurement type is changed.

class radioviz.tools.measurement_tool.MeasurementTool[source]

Bases: Tool[MeasurementToolController]

Tool for measuring segment lengths and angle amplitudes.

static _normalize_workspace_id(value: object) str | None[source]

Normalize a workspace id that may be stored as bytes or None.

Parameters:

value (object) – Raw id value

Returns:

Normalized string id or None

Return type:

Optional[str]

_on_item_restore_completed() None[source]

Handle completion of item restoration.

_reorder_store() None[source]

Reorder stores based on workspace order.

static _require_image_controller(item: SegmentMeasurementData | AngleMeasurementData) ImageWindowController[source]

Return the image controller for a measurement item or raise if missing.

Parameters:

item (SegmentMeasurementData | AngleMeasurementData) – Segment or angle measurement data

Returns:

Image window controller for the measurement

Return type:

ImageWindowController

Raises:

RuntimeError – If the measurement has no associated image controller

_restore_completed() None[source]

Signal completion of workspace restore.

_restore_selected_items() None[source]

Restore selected items from workspace state.

create_controller(ctx: ToolContext) MeasurementToolController[source]

Create a controller for this tool.

Parameters:

ctx (ToolContext) – Tool context

Returns:

Tool controller

Return type:

MeasurementToolController

from_workspace(spec: ToolWorkspace, context: WorkspaceReferenceManager) None[source]

Restore the tool from workspace specification.

Parameters:
Raises:

RuntimeError – when no controller is available

restore_phase() int[source]

Return the restore phase for workspace restore.

Returns:

Restore phase

Return type:

int

to_workspace(include_data: bool) ToolWorkspace[source]

Generate a workspace specification for the measurement tool.

Parameters:

include_data (bool) – Whether to include computed data

Returns:

Workspace specification

Return type:

ToolWorkspace

description: str = 'A tool to measure segment lengths and angle amplitudes'

Tooltip or description

name: str = 'Measurement Tool'

Human-readable name

overlays_to_be_registered: list[OverlaySpec] = [OverlaySpec(overlay_type='measure_segment', overlay_role=<OverlayRole.Permanent: 'permanent'>, renderer=<function draw_segment_overlay>), OverlaySpec(overlay_type='measure_segment', overlay_role=<OverlayRole.Highlight: 'highlight'>, renderer=<function draw_segment_overlay>), OverlaySpec(overlay_type='measure_angle', overlay_role=<OverlayRole.Permanent: 'permanent'>, renderer=<function draw_angle_overlay>), OverlaySpec(overlay_type='measure_angle', overlay_role=<OverlayRole.Highlight: 'highlight'>, renderer=<function draw_angle_overlay>)]

List of overlay specifications to register

tool_id: str = 'measure'

Unique identifier of the tool

class radioviz.tools.measurement_tool.MeasurementToolController(tool_ctx: ToolContext, tool: Tool[MeasurementToolController])[source]

Bases: ToolController[ImageWindowController, MeasurementToolSession]

Controller for the measurement tool.

Initialize the measurement tool controller.

Parameters:
_handle_selection_changed(selected: MeasurementDataProtocol | None, deselected: MeasurementDataProtocol | None) None[source]

Handle selection changes for measurement data.

Parameters:
_on_active_image_changed(new_window_controller: SubWindowController[Any] | None) None[source]

Handle active image changes.

Parameters:

new_window_controller (SubWindowController[Any]) – New active window controller

_on_image_about_to_close(image_controller: ImageWindowController) None[source]

Remove measurements associated with the closing image.

Parameters:

image_controller (ImageWindowController) – Image controller that is closing

_remove_measurement(item: MeasurementDataType | None, store: ItemStore[MeasurementDataType]) None[source]

Remove a measurement from the store.

Parameters:
  • item (Optional[MeasurementDataProtocol]) – Measurement to remove

  • store (SegmentStore | AngleStore) – Store to remove from

_sync_angle(angle: AngleMeasurementData) None[source]

Synchronize angle overlays and metadata.

Parameters:

angle (AngleMeasurementData) – Angle measurement

_sync_segment(segment: SegmentMeasurementData) None[source]

Synchronize segment overlays and metadata.

Parameters:

segment (SegmentMeasurementData) – Segment measurement

count_dependencies_for_image(window_controller: SubWindowController[Any]) int[source]

Count measurement items attached to window_controller.

create_dock(parent_window: QWidget) MeasurementToolDock[source]

Create and configure the measurement tool dock.

Parameters:

parent_window (QWidget) – Parent window for the dock widget

Returns:

Configured dock widget

Return type:

MeasurementToolDock

create_session(window_controller: ImageWindowController, measurement_type: MeasurementType | None = None, input_data: SegmentMeasurementData | AngleMeasurementData | None = None) MeasurementToolSession[source]

Create a new measurement tool session.

Parameters:
Returns:

New tool session

Return type:

MeasurementToolSession

export_angles_csv(path: Path) None[source]

Export all angle measurements to CSV.

Parameters:

path (pathlib.Path) – Output file path

export_segments_csv(path: Path) None[source]

Export all segment measurements to CSV.

Parameters:

path (pathlib.Path) – Output file path

finalize_measurement(session_result: ToolSessionResult) None[source]

Finalize a measurement creation.

Parameters:

session_result (ToolSessionResult) – Tool session result

invalidate_dependencies_for_image(window_controller: SubWindowController[Any]) int[source]

Remove measurement items attached to window_controller.

menu_specs() list[ToolMenuSpec][source]

Get the menu specifications for the measurement tool.

Returns:

Menu specifications

Return type:

list[ToolMenuSpec]

on_angle_selection_changed(selected: AngleMeasurementData | None, deselected: AngleMeasurementData | None) None[source]

Handle changes to angle selection.

Parameters:
on_cancelled_measurement_definition() None[source]

Handle cancellation of measurement definition.

on_confirmed_measurement_definition() None[source]

Handle confirmation of measurement definition.

on_delete_angle_clicked() None[source]

Handle delete angle button click.

on_delete_segment_clicked() None[source]

Handle delete segment button click.

on_measurement_type_change(new_type: MeasurementType) None[source]

Handle measurement type changes during selection.

Parameters:

new_type (MeasurementType) – New measurement type

on_segment_selection_changed(selected: SegmentMeasurementData | None, deselected: SegmentMeasurementData | None) None[source]

Handle changes to segment selection.

Parameters:
remove_angle(item: AngleMeasurementData | None) None[source]

Remove an angle measurement.

Parameters:

item (Optional[AngleMeasurementData]) – Angle measurement to remove

remove_segment(item: SegmentMeasurementData | None) None[source]

Remove a segment measurement.

Parameters:

item (Optional[SegmentMeasurementData]) – Segment measurement to remove

start_add_angle() None[source]

Start adding a new angle measurement.

start_add_segment() None[source]

Start adding a new segment measurement.

update_angle_fields(event: StoreEvent, data: AngleMeasurementData | None = None, index: int = 0) None[source]

Sync angle overlays after store updates.

update_segment_fields(event: StoreEvent, data: SegmentMeasurementData | None = None, index: int = 0) None[source]

Sync segment overlays after store updates.

class radioviz.tools.measurement_tool.MeasurementToolDock(parent: QWidget, controller: MeasurementToolController)[source]

Bases: ToolDockWidget[MeasurementToolController]

Dock widget for the measurement tool.

Initialize the measurement tool dock.

Parameters:
_on_add_action_triggered() None[source]

Handle add action triggers.

_on_angle_count_changed(count: int) None[source]

Handle angle count changes.

_on_delete_clicked() None[source]

Delete the currently selected measurement from the active tab.

_on_export_clicked() None[source]

Export current tab data to CSV.

_on_filter_toggled(enabled: bool) None[source]

Toggle filtering for the current tab.

_on_segment_count_changed(count: int) None[source]

Handle segment count changes.

_on_tab_changed(index: int) None[source]

Update labels and states when switching tabs.

_set_default_action(measurement_type: MeasurementType) None[source]

Set the default action for the add button.

Parameters:

measurement_type (MeasurementType) – Measurement type to set as default

_update_delete_enabled() None[source]

Update delete button enabled state for the active tab.

_update_export_enabled() None[source]

Update export button enabled state for the active tab.

create_selection_dialog() None[source]

Create and show the selection dialog.

handle_event(event: ToolEvent) None[source]

Handle tool events.

on_angle_selected(selected: QItemSelection, deselected: QItemSelection) None[source]

Handle angle selection changes.

on_request_to_change_angle_selection(index: QModelIndex, flags: SelectionFlag) None[source]

Update angle selection from controller.

on_request_to_change_segment_selection(index: QModelIndex, flags: SelectionFlag) None[source]

Update segment selection from controller.

on_segment_selected(selected: QItemSelection, deselected: QItemSelection) None[source]

Handle segment selection changes.

on_window_controller_changed(window_controller: SubWindowController[Any] | None) None[source]

Handle window controller changes.

Parameters:

window_controller (Optional[SubWindowController[Any]]) – Active window controller

set_can_remove_angle(enable: bool) None[source]

Set whether angle deletion is enabled.

set_can_remove_segment(enable: bool) None[source]

Set whether segment deletion is enabled.

class radioviz.tools.measurement_tool.MeasurementToolSession(tool_controller: MeasurementToolController, window_controller: ImageWindowController, measurement_type: MeasurementType, input_data: SegmentMeasurementData | AngleMeasurementData | None = None)[source]

Bases: BaseToolSession[MeasurementToolController, ImageWindowController]

Session for measurement creation.

Initialize the measurement tool session.

Parameters:
_angle_overlay_from_data() OverlayModel[source]

Build angle overlay from current angle data.

Returns:

Overlay model

Return type:

OverlayModel

_define_initial_condition() None[source]

Define parameters from pre-existing data.

_finalize_from_restore() None[source]

Finalize the session for restored measurements.

_on_interactive_definition() None[source]

Initialize interactive measurement definition.

_segment_overlay_from_data() OverlayModel[source]

Build segment overlay from current segment data.

Returns:

Overlay model

Return type:

OverlayModel

_setup_interactive(measurement_type: MeasurementType) None[source]

Initialize selector and data for the requested measurement type.

Parameters:

measurement_type (MeasurementType) – Measurement type to initialize

_teardown_selectors() None[source]

Tear down selectors without closing the dialog.

cleanup() None[source]

Clean up selection resources.

finalize_measurement() None[source]

Finalize measurement creation after dialog confirmation.

on_cancel(reason: str) None[source]

Cancel the session.

Parameters:

reason (str) – Reason for cancellation

on_finish() None[source]

Finish the session.

on_selector_accepted() None[source]

Handle selector acceptance.

on_selector_canceled() None[source]

Handle selector cancellation.

on_selector_created() None[source]

Handle selector creation.

on_start() None[source]

Start the measurement session.

switch_measurement_type(new_type: MeasurementType) None[source]

Switch the active measurement type during an interactive session.

Parameters:

new_type (MeasurementType) – New measurement type

class radioviz.tools.measurement_tool.MeasurementType(*values)[source]

Bases: StrEnum

Measurement types supported by the measurement tool.

static _generate_next_value_(name, start, count, last_values)

Return the lower-cased version of the member name.

class radioviz.tools.measurement_tool.SegmentMeasurementData(name: str, color: Color, p1: tuple[float, float] | None = None, p2: tuple[float, float] | None = None, image_controller: ImageWindowController | None = None, session_id: UUID | None = None, measurement_id: UUID | None = None, show_overlay: bool | None = True, show_label: bool | None = False, show_measure: bool | None = True, pixel_size_m: tuple[float, float] | None = None, length_px: float | None = None, length_m: float | None = None, unit_name: str | None = None)[source]

Bases: object

Data class representing a segment measurement.

Initialize a SegmentMeasurementData instance.

Parameters:
  • name (str) – Measurement name

  • color (Color) – Measurement color

  • p1 (tuple[float, float], optional) – Start point (x, y)

  • p2 (tuple[float, float], optional) – End point (x, y)

  • image_controller (Optional[ImageWindowController]) – Image controller owning the measurement

  • session_id (Optional[UUID]) – Session identifier

  • measurement_id (Optional[UUID]) – Unique identifier for the measurement

  • show_overlay (Optional[bool]) – Whether the overlay is visible

  • show_label (Optional[bool]) – Whether the label text is visible

  • show_measure (Optional[bool]) – Whether the measurement value is visible

  • pixel_size_m (Optional[tuple[float, float]]) – Pixel size in meters (x, y)

  • length_px (Optional[float]) – Precomputed length in pixels

  • length_m (Optional[float]) – Precomputed length in meters

  • unit_name (Optional[str]) – Display unit name for calibrated length

calculate_properties() None[source]

Compute measurement properties from current geometry.

length_display() str[source]

Format the calibrated length for display.

Returns:

Formatted length string or ‘n/a’

Return type:

str

measurement_display() str[source]

Format the preferred measurement value for display.

Returns:

Measurement display string

Return type:

str

to_workspace_spec(include_data: bool) SegmentMeasurementWorkspaceSpec[source]

Convert this measurement to a workspace specification.

Parameters:

include_data (bool) – Whether to include computed data

Returns:

Workspace specification

Return type:

SegmentMeasurementWorkspaceSpec

Raises:

RuntimeError – when attempting to serialize incomplete geometry

class radioviz.tools.measurement_tool.SegmentMeasurementWorkspaceSpec(id: UUID, name: str, image_controller_id: UUID | None = None, color: tuple[float, float, float] = (0.0, 0.0, 0.0), p1: tuple[float, float] = (0.0, 0.0), p2: tuple[float, float] = (0.0, 0.0), show_overlay: bool = True, show_label: bool = False, show_measure: bool = True, length_px: float = 0.0, length_m: float | None = None, unit_name: str | None = None, pixel_size_m: tuple[float, float] | None = None)[source]

Bases: object

Workspace specification for a segment measurement.

class radioviz.tools.measurement_tool.SegmentTableModel(store: ItemStore[SegmentMeasurementData], parent: QObject | None = None)[source]

Bases: ItemModel

Table model for displaying segment measurements.

Initialize the segment table model.

Parameters:
  • store (SegmentStore) – Store containing segment data

  • parent (QObject, optional) – Parent object

data_for(item: SegmentMeasurementData, column: int, role: int = ItemDataRole.DisplayRole) Any[source]

Return data for a segment cell.

Parameters:
  • item (SegmentMeasurementData) – Segment data item

  • column (int) – Column index

  • role (Qt.ItemDataRole) – Item data role

Returns:

Cell data

Return type:

Any

flags(index: QModelIndex | QPersistentModelIndex, /) ItemFlag[source]

Return item flags for a segment cell.

Parameters:

index (QModelIndex) – Index of the item

Returns:

Item flags

Return type:

Qt.ItemFlag

set_data_for(item: SegmentMeasurementData, column: int, value: Any, role: int = ItemDataRole.DisplayRole) bool[source]

Set data for a specific segment cell.

Parameters:
  • item (SegmentMeasurementData) – Segment data item

  • column (int) – Column index

  • value (Any) – Value to set

  • role (Qt.ItemDataRole) – Item data role

Returns:

True if successful

Return type:

bool

radioviz.tools.measurement_tool._segment_caps(p1: tuple[float, float], p2: tuple[float, float], cap_length: float) list[Line2D][source]

Create cap lines for a segment.

Parameters:
  • p1 (tuple[float, float]) – Segment start point

  • p2 (tuple[float, float]) – Segment end point

  • cap_length (float) – Cap length in data units

Returns:

List of Line2D cap artists

Return type:

list[Line2D]

radioviz.tools.measurement_tool.draw_angle_overlay(overlay: OverlayModel, axes: Axes) list[Artist][source]

Draw angle overlays.

Parameters:
  • overlay (OverlayModel) – Overlay model

  • axes (matplotlib.axes.Axes) – Matplotlib axes

Returns:

List of artists

Return type:

list

radioviz.tools.measurement_tool.draw_segment_overlay(overlay: OverlayModel, axes: Axes) list[Artist][source]

Draw segment overlays.

Parameters:
  • overlay (OverlayModel) – Overlay model

  • axes (matplotlib.axes.Axes) – Matplotlib axes

Returns:

List of artists

Return type:

list