Skip to content

Conversation

@fm3
Copy link
Member

@fm3 fm3 commented Dec 11, 2025

Ad-hoc meshing showed some open edges

  • with segment index: at layer topleft borders and layer bottomright borders
  • without segment index: only at layer topleft borders

The topleft problem was caused because the backend didn’t like negative requested coordinates, leading to crash fixes which shifted the toplefts into the layer bbox. This PR fixes this in the backend and undoes this change in the frontend, so negative coordinates are again sent, giving a clean upper edge.

The bottomright problem was caused because the segment index doesn’t indicate anything below the layer bbox. The neighbors case would add a cube outside of the layer, providing the outer edge, but the segment index case would skip that. Now the frontend embiggens the cubes to request if they align with the bottomright edges.

URL of deployed dev instance (used for testing):

Steps to test:

  • Request some ad-hoc meshes that touch the layer borders with and without segment index
  • test also with a dataset that starts at 0,0,0 so you can test that the backend now handles the negative-coordinate requests. l4_sample doesn’t test this.

Issues:


  • Added changelog entry (create a $PR_NUMBER.md file in unreleased_changes or use ./tools/create-changelog-entry.py)
  • Removed dev-only changes like prints and application.conf edits
  • Considered common edge cases
  • Needs datastore update after deployment

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 11, 2025

📝 Walkthrough

Walkthrough

Reworks ad-hoc mesh padding and cube-size handling across frontend sagas and the admin REST API, removes a bounding-box clipping helper, tightens backend cuboid/bucket intersection bounds to non-negative values, and adds a changelog entry for an edge-case mesh fix.

Changes

Cohort / File(s) Summary
Admin REST API
frontend/javascripts/admin/rest_api.ts
Removed V3 import and send cubeSize directly in computeAdHocMesh payload (removed previous V3.add/V3.toArray transformation).
Ad-hoc mesh saga & padding logic
frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts
Introduced paddedPosition and paddedCubeSize (new getPaddedCubeSizeInTargetMag), use paddedPosition for caching/map keys, send positionWithPadding: paddedPosition and cubeSize: paddedCubeSize in requests, added runtime error logging, and expanded inline documentation.
Bounding box utility
frontend/javascripts/viewer/model/bucket_data_handling/bounding_box.ts
Removed clipPositionIntoBoundingBox(position: Vector3) method.
Backend voxel extraction
webknossos-datastore/app/com/scalableminds/webknossos/datastore/services/BinaryDataService.scala
In cutOutCuboid, clamped cuboid–bucket intersection bounds to non-negative values by wrapping min/max calculations with max(0, ...) / min(..., ...) as appropriate.
Changelog
unreleased_changes/9143.md
Added entry noting ad-hoc meshes touching dataset layer edges now produce closing edges.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Review the new padded cube-size calculation (getPaddedCubeSizeInTargetMag) and its edge-condition increments.
  • Verify frontend request payload shape (plain cubeSize and positionWithPadding) matches backend API expectations.
  • Check for callers relying on the removed clipPositionIntoBoundingBox and ensure no regressions.
  • Inspect BinaryDataService.cutOutCuboid clamping to ensure valid voxels at zero-origin coordinates remain included.

Possibly related PRs

Suggested reviewers

  • MichaelBuessemeyer
  • philippotto

Poem

🐇 I nibbled at padding, I hopped at each seam,

I nudged cube sizes so edges could gleam.
Frontend sends plain arrays, the backend clamps tight,
Missing borders closed up, stitched day and night.
A little rabbit dance — the mesh is just right! 🎉

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: fixing ad-hoc mesh closing edges on layer borders, which aligns with the core changes throughout the changeset.
Description check ✅ Passed The description is well-related to the changeset, explaining the root causes of open edges in ad-hoc meshes and detailing the fixes applied in both backend and frontend.
Linked Issues check ✅ Passed The PR addresses issue #9069 by fixing half-open ad-hoc meshes at dataset bbox through backend coordinate handling and frontend cube enlargement logic.
Out of Scope Changes check ✅ Passed All changes are scoped to fixing ad-hoc mesh closing edges: backend coordinate clamping, frontend padding logic, helper functions, and error logging are all directly related to the issue.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch adhoc-mesh-edges

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@fm3 fm3 marked this pull request as ready for review December 11, 2025 14:15
@fm3 fm3 requested a review from philippotto December 11, 2025 14:25
Copy link
Member

@philippotto philippotto left a comment

Choose a reason for hiding this comment

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

thanks for digging into this and fixing the problem!! I left a couple of comments 😇

@fm3 fm3 requested a review from philippotto December 16, 2025 12:33
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (1)

195-195: Consider removing debug console.log statement.

The console.log in the error handler is not standard for production code. Since ErrorHandling.notify already captures the exception, the console logging is redundant. Consider removing it or using a proper logging framework if additional context is needed.

Apply this diff:

-    console.log("Exception when loading ad-hoc mesh for segment", action.segmentId, ":", exc);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b9b5bf1 and aba2f9d.

📒 Files selected for processing (1)
  • frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (5 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2024-11-22T17:18:04.217Z
Learnt from: dieknolle3333
Repo: scalableminds/webknossos PR: 8168
File: frontend/javascripts/oxalis/model/sagas/proofread_saga.ts:1039-1039
Timestamp: 2024-11-22T17:18:04.217Z
Learning: In `frontend/javascripts/oxalis/model/sagas/proofread_saga.ts`, when calling `getMagInfo`, the use of `volumeTracingLayer.resolutions` is intentional and should not be changed to `volumeTracingLayer.mags`.

Applied to files:

  • frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts
📚 Learning: 2024-11-22T17:17:39.914Z
Learnt from: dieknolle3333
Repo: scalableminds/webknossos PR: 8168
File: frontend/javascripts/oxalis/model/reducers/skeletontracing_reducer_helpers.ts:125-125
Timestamp: 2024-11-22T17:17:39.914Z
Learning: In the `createNode` function within `skeletontracing_reducer_helpers.ts`, the property `resolution` is intentionally kept even when the parameter is renamed to `mag`.

Applied to files:

  • frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts
📚 Learning: 2025-12-11T15:25:53.526Z
Learnt from: knollengewaechs
Repo: scalableminds/webknossos PR: 9117
File: frontend/javascripts/admin/statistic/time_tracking_overview.tsx:261-279
Timestamp: 2025-12-11T15:25:53.526Z
Learning: Ant Design v6 Select: when using the Select component, consider supplying a prefix prop to render an icon or element before the input for better visual context. Apply this guideline to TS and TSX files across the codebase where Ant Design Select is used; ensure prefix usage is accessible (e.g., provide meaningful aria-label if needed) and avoid unnecessary prefixes on simple inputs.

Applied to files:

  • frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts
🧬 Code graph analysis (1)
frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (2)
frontend/javascripts/libs/mjs.ts (1)
  • V3 (372-372)
frontend/javascripts/viewer/constants.ts (1)
  • Vector3 (15-15)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: backend-tests
  • GitHub Check: build-smoketest-push
🔇 Additional comments (2)
frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (2)

474-487: Excellent documentation and implementation of the padding logic.

The comment clearly explains both effects: (1) overlapping cubes to fill gaps and (2) extending beyond layer borders for closing surfaces. The implementation correctly:

  • Shifts position by subtracting mag to enable negative coordinates at top-left borders
  • Delegates size computation to the new helper function
  • Handles both segment-index and non-segment-index cases

565-586: Well-implemented helper function for computing padded cube size.

The function correctly:

  • Adds [1,1,1] to fill grid gaps between chunks
  • Detects when a cube aligns precisely with the layer's bottom-right border
  • Extends the cube by an additional voxel in those dimensions to provide closing surfaces

The logic is sound: cubeBottomRight is computed in mag1 coordinates (by scaling cubeSize by mag), making the comparison with layerBottomRight valid. The local mutation of cubeSize at line 582 is safe since it operates on the array created at line 573.

Copy link
Member

@philippotto philippotto left a comment

Choose a reason for hiding this comment

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

awesome! works well & looks good. thanks for fixing this bug!

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (1)

564-585: Helper function correctly implements bottom-right border detection and cube enlargement.

The logic is sound:

  1. Starts with base cube size + [1,1,1] for gap filling (line 572)
  2. Converts cube size to mag1 coordinates for comparison with layer bounds (line 577)
  3. Detects when a cube precisely touches the bottom-right layer border (line 580)
  4. Increases the cube size in that dimension to extend beyond the border (line 581)

For style consistency, consider using V3 operations for the dimension-specific increment as well:

  for (let dimension = 0; dimension < 3; dimension++) {
    if (cubeBottomRight[dimension] === layerBottomRight[dimension]) {
-     cubeSize[dimension] += 1;
+     cubeSize = V3.add(cubeSize, dimension === 0 ? [1, 0, 0] : dimension === 1 ? [0, 1, 0] : [0, 0, 1]);
    }
  }

However, the current imperative style is more readable for this use case, so this is purely a stylistic nitpick.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aba2f9d and 98981d6.

📒 Files selected for processing (1)
  • frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (5 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2024-11-22T17:18:04.217Z
Learnt from: dieknolle3333
Repo: scalableminds/webknossos PR: 8168
File: frontend/javascripts/oxalis/model/sagas/proofread_saga.ts:1039-1039
Timestamp: 2024-11-22T17:18:04.217Z
Learning: In `frontend/javascripts/oxalis/model/sagas/proofread_saga.ts`, when calling `getMagInfo`, the use of `volumeTracingLayer.resolutions` is intentional and should not be changed to `volumeTracingLayer.mags`.

Applied to files:

  • frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts
📚 Learning: 2024-11-22T17:17:39.914Z
Learnt from: dieknolle3333
Repo: scalableminds/webknossos PR: 8168
File: frontend/javascripts/oxalis/model/reducers/skeletontracing_reducer_helpers.ts:125-125
Timestamp: 2024-11-22T17:17:39.914Z
Learning: In the `createNode` function within `skeletontracing_reducer_helpers.ts`, the property `resolution` is intentionally kept even when the parameter is renamed to `mag`.

Applied to files:

  • frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts
📚 Learning: 2025-12-11T15:25:53.526Z
Learnt from: knollengewaechs
Repo: scalableminds/webknossos PR: 9117
File: frontend/javascripts/admin/statistic/time_tracking_overview.tsx:261-279
Timestamp: 2025-12-11T15:25:53.526Z
Learning: Ant Design v6 Select: when using the Select component, consider supplying a prefix prop to render an icon or element before the input for better visual context. Apply this guideline to TS and TSX files across the codebase where Ant Design Select is used; ensure prefix usage is accessible (e.g., provide meaningful aria-label if needed) and avoid unnecessary prefixes on simple inputs.

Applied to files:

  • frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: frontend-tests
  • GitHub Check: build-smoketest-push
  • GitHub Check: backend-tests
🔇 Additional comments (4)
frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (4)

195-195: Console logging provides useful debugging context.

The console.log adds the segmentId to the console output, which can be helpful when debugging mesh loading failures alongside the existing error notification.


489-498: Cache key updated consistently to use paddedPosition.

The cache lookup (line 489) and storage (line 498) both use paddedPosition, ensuring consistent cache behavior. Since the padding is deterministic based on clippedPosition and mag, the same logical cube will always map to the same cache key.


520-524: Request payload correctly uses padded values.

The API call now sends paddedPosition and paddedCubeSize, which aligns with the new padding strategy to generate closed mesh surfaces at layer borders.


474-487: Padding logic is well-documented and correctly implements the border-closing approach.

The comprehensive comment clearly explains the two-part padding strategy:

  1. Adding 1vx overlap between cubes to fill gaps
  2. Extending cubes beyond layer borders to enable marching cubes to generate closing surfaces

The implementation correctly shifts positions by -mag and delegates cube size calculation to the getPaddedCubeSizeInTargetMag helper function, which properly increases size by [1,1,1] for gaps and handles lower layer border extensions. The API correctly passes positionWithPadding to the backend, where the MarchingCubes implementation accepts negative offsets without validation and directly applies them in vertex calculations, confirming support for negative coordinates.

@fm3 fm3 merged commit df72b85 into master Dec 17, 2025
5 checks passed
@fm3 fm3 deleted the adhoc-mesh-edges branch December 17, 2025 08:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Ad-Hoc mesh is half-open at dataset bbox

3 participants