Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions src/odemis/gui/cont/multi_point_correlation.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,10 @@ def __init__(self, frame):

# Reset targets and current target and populate it based on the current feature
self._subscribed_target = None
# Just before the 3DCT correlation dialog is opened,
# ensure FM fiducial indices are contiguous (1..N) when there are no FIB fiducials.
# This fixes cases like FM indices being 1,2,3,6 when no FIB fiducials are present on startup.
self._renumber_fm_fiducials_on_start()
self._tab_data_model.main.targets.subscribe(self._on_target_changes, init=True)
self._tab_data_model.main.currentTarget.subscribe(self._on_current_target_changes, init=True)

Expand Down Expand Up @@ -839,3 +843,48 @@ def _reorder_grid(self) -> None:
for row, row_data in enumerate(data):
for col, value in enumerate(row_data):
self.grid.SetCellValue(row, col, str(value))

def _renumber_fm_fiducials_on_start(self) -> None:
"""
If there are no FIB fiducials at GUI start, renumber FM fiducials so their indices are contiguous
starting from 1. This handles cases where FM fiducials may have gaps (e.g. 1,2,3,6).

This method updates both the `index` and `name` fields of the FM targets in-place and
persists the feature file via `update_feature_correlation_target` so the rest of the GUI
sees the corrected ordering when it initializes.
"""
try:
targets = self._tab_data_model.main.targets.value
except Exception:
# If targets are not available for any reason, skip renumbering
return
Comment on lines +856 to +860
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Prefer catching a specific exception over bare Exception.

The static analysis tool flagged this catch-all. Since targets.value access typically raises AttributeError if targets is None or lacks the value attribute, catch that specifically. This avoids silently swallowing unexpected errors.

Proposed fix
         try:
             targets = self._tab_data_model.main.targets.value
-        except Exception:
+        except AttributeError:
             # If targets are not available for any reason, skip renumbering
             return
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try:
targets = self._tab_data_model.main.targets.value
except Exception:
# If targets are not available for any reason, skip renumbering
return
try:
targets = self._tab_data_model.main.targets.value
except AttributeError:
# If targets are not available for any reason, skip renumbering
return
🧰 Tools
🪛 Ruff (0.15.2)

[warning] 857-857: Do not catch blind exception: Exception

(BLE001)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/odemis/gui/cont/multi_point_correlation.py` around lines 855 - 859, The
try/except is catching all Exceptions when reading
self._tab_data_model.main.targets.value; change this to catch the specific
AttributeError (or NoneType access) instead of bare Exception so unrelated
errors aren't swallowed—update the block around the targets =
self._tab_data_model.main.targets.value access to except AttributeError: (and
return) and keep the comment about skipping renumbering if targets are not
available.


# Check if any FIB fiducials exist; if so, we don't renumber on startup
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm missing why numbering isn't problematic when there are fib fiducials.

Copy link
Copy Markdown
Contributor Author

@K4rishma K4rishma Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can be deleted in pairs , if certain FIB-FM pair is not of interest to the user. Although the numbering of the indices are not continuous but the pairs would be in sync,

pairs of FM-FIB, 1-1, 2-2, 3-3, 6-6 (after deleting pair 4 and 5). The pair indices should be same.

Earlier, when there are 20 FM indices, user decides to delete 4 indices (3,4,5,6).

FM 1,2,.....7 upto 20. Then in FIB the user has to either make fake 4 FIBs between 2 and 7 and delete it afterwards, which is a bit of annoyance.

This is how renumbering helps.

has_fib = any(t.type.value == TargetType.FibFiducial for t in targets)
if has_fib:
return

# Collect FM fiducials (TargetType.Fiducial) and sort by current index
fm_fiducials = [t for t in targets if t.type.value == TargetType.Fiducial]
if not fm_fiducials:
return

fm_fiducials.sort(key=lambda t: t.index.value)

# If indices are already contiguous starting from 1, nothing to do
# The fiducials are sorted when saved, so we just need to check the last index
expected_last_index = len(fm_fiducials)
actual_last_index = fm_fiducials[-1].index.value
if expected_last_index == actual_last_index:
Comment on lines +874 to +878
return

# Renumber sequentially and update names preserving the prefix (if present)
for new_idx, target in enumerate(fm_fiducials, start=1):
old_name = target.name.value
old_name_type = re.search(FIDUCIAL_PATTERN, old_name).group()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we make our lives a bit hard with this. Why didn't we introduce a name and (computed) display_name (where we prepend prefix and append suffix on a callback) for instance.

Copy link
Copy Markdown
Contributor

@tmoerkerken tmoerkerken Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is something for the technical debt board:
https://delmic.atlassian.net/jira/software/projects/SWM/boards/33?selectedIssue=SWM-222

target.index.value = new_idx
target.name.value = old_name_type + str(target.index.value)
Comment on lines +882 to +886
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Guard against regex match returning None.

If a target's name doesn't contain the expected prefix pattern (no dash), re.search() returns None and .group() raises AttributeError. Although FM fiducials should consistently have this format, defensive coding prevents unexpected crashes if data is malformed.

Proposed fix
         for new_idx, target in enumerate(fm_fiducials, start=1):
             old_name = target.name.value
-            old_name_type = re.search(FIDUCIAL_PATTERN, old_name).group()
+            match = re.search(FIDUCIAL_PATTERN, old_name)
+            if not match:
+                logging.warning(f"FM fiducial name '{old_name}' does not match expected pattern, skipping renumber")
+                continue
+            old_name_type = match.group()
             target.index.value = new_idx
             target.name.value = old_name_type + str(target.index.value)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/odemis/gui/cont/multi_point_correlation.py` around lines 881 - 885, In
the renumbering loop in multi_point_correlation.py (fm_fiducials, old_name,
old_name_type, FIDUCIAL_PATTERN, target.name.value), guard the call to
re.search(...) so it cannot return None before calling .group(); replace the
direct re.search(...).group() with code that first does match =
re.search(FIDUCIAL_PATTERN, old_name) and then uses old_name_type =
match.group() if match else a safe fallback (for example '' or a default
prefix), then continue setting target.index.value and target.name.value;
optionally emit a warning/log when match is None to aid debugging.

Comment on lines +884 to +886

# Update the correlation_target and persist features
logging.debug(f"Renumbered FM fiducials on GUI start to contiguous indices 1..{len(fm_fiducials)}")
self.correlation_target = update_feature_correlation_target(self.correlation_target, self._tab_data_model)
Loading