MeasureTool

class controllers.MeasureTool

Bases: handle

MEASURETOOL - Controller for the interactive Measurement Tool panel.

Owns all UX for measurement creation and management: interactive ROI drawing (via images.roi.* objects), routing to core.Measurements static helpers for math, measurement table refresh, edit/recalculate flow, kymograph generation, and load/save.

The companion view is views.MeasureToolGUI.mlapp (created by the user with widget tags matching those listed in the plan).

Architecture:

  • core.Measurements - data-only class on the dataset; this controller drives it.

  • controllers.MibController - parent; provides cImageDoc and model.

  • All interactive drawing lives here, never in core.Measurements.

Launch via utils.startController:

obj.startController('controllers.MeasureTool', obj)

The second argument is the calling MibController handle, which utils.startController forwards as varargin{1} to the constructor.

Constructor Summary
MeasureTool(mibModel, varargin)

MEASURETOOL - Constructor for the MeasureTool controller.

Syntax:
cTool = controllers.MeasureTool(mibModel, mibController)

Follows the utils.startController contract: first argument is always mibModel; the parent MibController handle is passed as varargin{1} by the caller.

Input Arguments:
Output Arguments:
Usage:

Example 1 - launched via ribbon button callback

obj.startController('controllers.MeasureTool', obj);
Property Summary
indices

{1×N cell} listener handles - deleted on close

listener

handle to views.MeasureToolGUI (set by core.ChildView in constructor)

mibController
mibModel

handle to controllers.MibController (passed as varargin{1} by startController)

view

handle to models.MibModel

Method Summary
static ViewListner_Callback2(~, event)

VIEWLISTNER_CALLBACK2 - Static model-event relay.

Syntax:
controllers.MeasureTool.ViewListner_Callback2(obj, src, evt)

Discards the listener and returns silently when the controller or its view has been deleted.

Input Arguments:
addCallbacks()

ADDCALLBACKS - Wire widget callbacks and build context menu.

Syntax:
obj.addCallbacks()

Called once from the constructor after the view is created. All widget callbacks route through gui_Callbacks (dispatched by src.Tag). The context menu is created here and attached to measureTable.

Input Arguments:
addMeasurement()

ADDMEASUREMENT - Handle the Add button: backup, draw, compute, store.

Syntax:
obj.addMeasurement()

Reads measurement type and options from the view, calls the appropriate measureXxx method, then restores disableSegmentation and refreshes the table and image regardless of success or cancellation.

Input Arguments:
closeWindow()

CLOSEWINDOW - Close the MeasureTool window and clean up.

Syntax:
obj.closeWindow()

Restores disableSegmentation, deletes listeners, deletes the view, and fires CloseEvent so utils.purgeChildController removes this entry from the parent’s childControllers array.

contextMenu(parameter)

CONTEXTMENU - Handle right-click context menu actions on the measurements table.

Syntax:
obj.contextMenu(parameter)
Input Arguments:
  • obj - controllers.MeasureTool

  • parameter - [char] action key:

    • 'ModifyInfo' - edit the .info annotation text

    • 'Jump' - navigate to the measurement’s Z/T slice

    • 'Modify' - re-draw measurement on current slice

    • 'Recalculate' - re-draw on the stored slice (preserves Z/T)

    • 'Duplicate' - append a copy of the selected measurement

    • 'Kymograph' - generate kymograph from this measurement

    • 'Plot' - plot intensity profile in a standalone figure

    • 'Delete' - remove this measurement

drawROI(roiType, finetuneCheck, maxVertices, initialDataPos)

DRAWROI - Interactively draw a ROI on the image axes and return pixel coords.

Syntax:
[pixelX, pixelY, wasCancelled] = obj.drawROI(roiType)
[pixelX, pixelY, wasCancelled] = obj.drawROI(roiType, finetuneCheck)
[pixelX, pixelY, wasCancelled] = obj.drawROI(roiType, finetuneCheck, maxVertices)

Creates an images.roi.* object on the current image axes using the MATLAB R2022b+ drawing functions, waits for the user to finalise the placement (double-click), then converts the result from axes space to data pixel coordinates. Pressing Escape cancels and returns empty arrays with wasCancelled = true.

Input Arguments:
  • roiType - [char] one of:

    • 'line' - two-endpoint line (drawline)

    • 'polyline' - open N-point polygon (drawpolygon)

    • 'ellipse' - ellipse; returns boundary vertices (drawellipse)

    • 'point' - single point (drawpoint)

    • 'freehand' - open freehand path (drawfreehand)

  • finetuneCheck - (optional) [logical] when false the ROI is auto-accepted as soon as drawing finishes (no double-click required). Default: true.

  • maxVertices - (optional) [double] maximum number of vertices for 'polyline' drawings; drawing ends automatically when this count is reached. Default: Inf (unlimited, finish with a double-click). drawpolyline has no vertex limit, so with a finite count the drawing is ended from a WindowMouseRelease listener once that many vertices are placed, and an images.roi.Polyline is rebuilt from them; with finetuneCheck = true that polyline is then adjustable until a double-click, otherwise it is accepted at once.

Output Arguments:
  • pixelX - [double column] X coordinates in data pixel space.

  • pixelY - [double column] Y coordinates in data pixel space.

  • wasCancelled - [logical] true when the user pressed Escape.

Usage:

Example 1

[X, Y, cancelled] = obj.drawROI('line');
if cancelled; return; end
editMeasurement(datasetId, measurementIndex, colCh, integrationWidth, finetuneCheck, calcIntensity, useFixedZT)

EDITMEASUREMENT - Re-edit an existing measurement at a given index.

Syntax:
obj.editMeasurement(datasetId, measurementIndex, colCh, integrationWidth, finetuneCheck, calcIntensity, useFixedZT)

Backs up, re-runs the interactive drawing for the same measurement type, and replaces the old entry at measurementIndex with the new result. When useFixedZT is true the new record keeps the original Z/T values (Recalculate mode); when false the current slice/time is used (Modify mode).

The replace-at-index pattern is: removeMeasurement(idx) then storeMeasurement(newData, idx). Each measureXxx method accepts an insertIndex argument that implements this automatically.

Input Arguments:
  • datasetId - [double] index into mibModel.I

  • measurementIndex - [double] 1-based row in hMeasure.Data

  • colCh - [double] colour channel

  • integrationWidth - [double] integration width for linear distance

  • finetuneCheck - [logical] allow interactive ROI adjustment

  • calcIntensity - [logical] recalculate intensity profile

  • useFixedZT - [logical] preserve original Z/T (true = Recalculate)

generateKymograph(datasetId, measurementIndex)

GENERATEKYMOGRAPH - Generate a kymograph from a linear or polyline measurement.

Syntax:
obj.generateKymograph(datasetId, measurementIndex)

Asks the user for output format and whether to add a scale bar, calls core.Measurements.computeKymograph() with the 4-D image stack, then saves or previews the result. A .txt description file with physical step sizes is written alongside every TIF save.

Input Arguments:
  • obj - controllers.MeasureTool

  • datasetId - [double] index into mibModel.I

  • measurementIndex - [double] 1-based index in hMeasure.Data

gui_Callbacks(source, event)

GUI_CALLBACKS - Dispatcher for all MeasureTool widget callbacks.

Syntax:
obj.gui_Callbacks(source, event)

Routes by source.Tag to the appropriate action.

Input Arguments:
  • obj - controllers.MeasureTool

  • source - widget handle that fired the event

  • event - event data (ignored for most widgets; used for table selection)

loadMeasurements()

LOADMEASUREMENTS - Load measurements from a .measure file.

Syntax:
obj.loadMeasurements()

Opens a file dialog, deserialises the Data struct array from the selected MAT-file, and replaces the current measurements.

Input Arguments:
measureAngle(datasetId, colCh, finetuneCheck, calcIntensity, showInfoDlg, insertIndex)

MEASUREANGLE - Interactive angle measurement (3 points, vertex = point 2).

Syntax:
obj.measureAngle(datasetId, colCh, finetuneCheck, calcIntensity, showInfoDlg)
obj.measureAngle(datasetId, colCh, finetuneCheck, calcIntensity, showInfoDlg, insertIndex)

Draws a 3-vertex polyline on the image axes, computes the angle at the second vertex, optionally computes an intensity profile, then stores the result via core.Measurements.storeMeasurement().

Input Arguments:
  • datasetId - [double] index into mibModel.I

  • colCh - [double] colour channel (0 = all, 1+ = specific)

  • finetuneCheck - [logical] when false accept the ROI immediately after placement (no double-click required)

  • calcIntensity - [logical] compute intensity profile along path

  • showInfoDlg - [logical] show annotation text dialog after drawing

  • insertIndex - (optional) [double] replace-at-position (0 = append)

Output Arguments:
  • annotationText - [char] annotation label entered by the user; empty string '' when the dialog was skipped or cancelled

measureCaliper(datasetId, colCh, finetuneCheck, calcIntensity, showInfoDlg, insertIndex)

MEASURECALIPER - Interactive caliper (perpendicular-width) measurement.

Syntax:
obj.measureCaliper(datasetId, colCh, finetuneCheck, calcIntensity, showInfoDlg)
obj.measureCaliper(datasetId, colCh, finetuneCheck, calcIntensity, showInfoDlg, insertIndex)

Draws a 2-point line (P1, P2) then a single point (P3) perpendicular to it. Computes the shortest distance from P3 to the line P1-P2, scaled by pixel size. P4 (foot of perpendicular) is stored for overlay rendering.

Input Arguments:
  • datasetId - [double] index into mibModel.I

  • colCh - [double] colour channel (0 = all, 1+ = specific)

  • finetuneCheck - [logical] when false accept each ROI immediately after placement (no double-click required)

  • calcIntensity - [logical] compute intensity profile along perpendicular

  • showInfoDlg - [logical] show annotation text dialog

  • insertIndex - (optional) [double] replace-at-position (0 = append)

Output Arguments:
  • annotationText - [char] annotation label entered by the user; empty string '' when the dialog was skipped or cancelled

measureCircle(datasetId, colCh, finetuneCheck, calcIntensity, showInfoDlg, insertIndex)

MEASURECIRCLE - Interactive circle-fit measurement via an ellipse ROI.

Syntax:
obj.measureCircle(datasetId, colCh, finetuneCheck, calcIntensity, showInfoDlg)
obj.measureCircle(datasetId, colCh, finetuneCheck, calcIntensity, showInfoDlg, insertIndex)

The user draws an ellipse ROI. The boundary vertices are passed to core.Measurements.computeCircleFit() for a least-squares circle fit. Stores a 60-point circle arc as X/Y for overlay rendering.

Input Arguments:
  • datasetId - [double] index into mibModel.I

  • colCh - [double] colour channel (0 = all, 1+ = specific)

  • finetuneCheck - [logical] when false accept the ellipse immediately after placement (no double-click required)

  • calcIntensity - [logical] compute radial intensity profile

  • showInfoDlg - [logical] show annotation text dialog

  • insertIndex - (optional) [double] replace-at-position (0 = append)

measureDistance(datasetId, colCh, finetuneCheck, integrationWidth, calcIntensity, showInfoDlg, insertIndex)

MEASUREDISTANCE - Interactive linear distance measurement (2-point line).

Syntax:
obj.measureDistance(datasetId, colCh, finetuneCheck, integrationWidth, calcIntensity, showInfoDlg)
obj.measureDistance(datasetId, colCh, finetuneCheck, integrationWidth, calcIntensity, showInfoDlg, insertIndex)

The user draws a two-endpoint line. Physical distance is computed via core.Measurements.computeDistance(). When integrationWidth > 0 the intensity profile is integrated laterally across that width.

Input Arguments:
  • datasetId - [double] index into mibModel.I

  • colCh - [double] colour channel (0 = all, 1+ = specific)

  • finetuneCheck - [logical] when true enable fine-tuning of the drawn measurement, when false, it is automatically accepted upon finishing of drawing

  • integrationWidth - [double] lateral integration half-width in pixels (0 = off)

  • calcIntensity - [logical] compute intensity profile along the line

  • showInfoDlg - [logical] show annotation text dialog after drawing

  • insertIndex - (optional) [double] replace-at-position (0 = append)

Output Arguments:
  • annotationText - [char] annotation label entered by the user; empty string '' when the dialog was skipped or cancelled

measureDistanceFree(datasetId, colCh, finetuneCheck, calcIntensity, showInfoDlg, insertIndex)

MEASUREDISTANCEFREE - Interactive freehand distance measurement.

Syntax:
obj.measureDistanceFree(datasetId, colCh, finetuneCheck, calcIntensity, showInfoDlg)
obj.measureDistanceFree(datasetId, colCh, finetuneCheck, calcIntensity, showInfoDlg, insertIndex)

The user draws a freehand path. The resulting dense vertex array is downsampled using an evenly-spaced parameterisation, then the result is handed to measureDistancePoly() which computes the cumulative arc-length and stores the measurement.

Input Arguments:
  • datasetId - [double] index into mibModel.I

  • colCh - [double] colour channel (0 = all, 1+ = specific)

  • finetuneCheck - [logical] when false accept the freehand path immediately after drawing (no double-click required)

  • calcIntensity - [logical] compute intensity profile along path

  • showInfoDlg - [logical] show annotation text dialog after drawing

  • insertIndex - (optional) [double] replace-at-position (0 = append)

Output Arguments:
  • annotationText - [char] annotation label entered by the user; empty string '' when the dialog was skipped or cancelled

measureDistancePoly(datasetId, colCh, finetuneCheck, calcIntensity, showInfoDlg, insertIndex)

MEASUREDISTANCEPOLY - Interactive polyline distance measurement.

Syntax:
obj.measureDistancePoly(datasetId, colCh, finetuneCheck, calcIntensity, showInfoDlg)
obj.measureDistancePoly(datasetId, colCh, finetuneCheck, calcIntensity, showInfoDlg, insertIndex)

The user draws an open polygon. The vertices are interpolated with the spline method selected in interpolationModePopup and the cumulative arc-length is computed in physical units. The original knot coordinates are stored in .spline for overlay rendering; the interpolated path is stored in X/Y.

Input Arguments:
  • datasetId - [double] index into mibModel.I

  • colCh - [double] colour channel (0 = all, 1+ = specific)

  • finetuneCheck - [logical] when false accept the polyline immediately after placement (no double-click required)

  • calcIntensity - [logical] compute intensity profile along path

  • showInfoDlg - [logical] show annotation text dialog after drawing

  • insertIndex - (optional) [double] replace-at-position (0 = append)

Output Arguments:
  • annotationText - [char] annotation label entered by the user; empty string '' when the dialog was skipped or cancelled

measurePoint(datasetId, colCh, finetuneCheck, calcIntensity, showInfoDlg, insertIndex)

MEASUREPOINT - Interactive single-point measurement.

Syntax:
obj.measurePoint(datasetId, colCh, finetuneCheck, calcIntensity, showInfoDlg)
obj.measurePoint(datasetId, colCh, finetuneCheck, calcIntensity, showInfoDlg, insertIndex)

The user places a single point. Pixel intensity at that location is read from the 2-D image slice for all channels.

Input Arguments:
  • datasetId - [double] index into mibModel.I

  • colCh - [double] colour channel (0 = all, 1+ = specific)

  • finetuneCheck - [logical] when false accept the point immediately after placement (no double-click required)

  • calcIntensity - [logical] read pixel intensity at the point

  • showInfoDlg - [logical] show annotation text dialog

  • insertIndex - (optional) [double] replace-at-position (0 = append)

Output Arguments:
  • annotationText - [char] annotation label entered by the user; empty string '' when the dialog was skipped or cancelled

plotIntensityProfile(dataIndex)

PLOTINTENSITYPROFILE - Plot the intensity profile in a standalone figure.

Syntax:
obj.plotIntensityProfile(dataIndex)

Opens (or reuses) figure 1952 and plots the intensity profile for the measurement at dataIndex.

Input Arguments:
previewIntensityProfile()

PREVIEWINTENSITYPROFILE - Update profileAxes on table row selection.

Syntax:
obj.previewIntensityProfile()

Called when the user selects a row in measureTable and previewIntensityCheck is on. Plots the stored intensity profile in the profileAxes widget. If autoJumpCheck is on, also navigates to the measurement’s Z/T slice.

Input Arguments:
saveMeasurements()

SAVEMEASUREMENTS - Save current measurements to a .measure or .xls file.

Syntax:
obj.saveMeasurements()

Opens a save-file dialog. Depending on the chosen extension:

  • *.measure - serialises hMeasure.Data to a MAT-file (variable Data).

  • *.xls - writes two sheets: Sheet1 (summary table) and Sheet2 (intensity profiles).

Input Arguments:
updatePlotSettings()

UPDATEPLOTSETTINGS - Sync marker/line/text checkboxes to Options and repaint.

Syntax:
obj.updatePlotSettings()
Input Arguments:
updateTable()

UPDATETABLE - Rebuild the measurements table from the current dataset.

Syntax:
obj.updateTable()

Reads hMeasure.Data for the active dataset, applies the type filter selected in filterPopup, and writes a 6-column cell array into measureTable.Data (columns: n, type, value, info, Z, T).

Input Arguments:
updateWidgets()

UPDATEWIDGETS - Refresh all GUI widget state from the current dataset.

Syntax:
obj.updateWidgets()

Called on construction and whenever UpdateGuiWidgets or NewDataset fires. Rebuilds the colour-channel dropdown, updates the pixel-size label, syncs the interpolation method and marker/line/text checkboxes, and refreshes the measurements table.

Input Arguments: