# Shift-mouse not placing on surface of segment

**URL:** https://discourse.slicer.org/t/shift-mouse-not-placing-on-surface-of-segment/48240
**Category:** Development
**Created:** [September 23, 2026, 12:42pm UTC](https://discourse.slicer.org/t/shift-mouse-not-placing-on-surface-of-segment/48240 "2026-09-23T12:42:44Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![hherhold](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/hherhold/32/12199_2.png) [@hherhold](https://discourse.slicer.org/u/hherhold)
#### Post date: [September 23, 2026, 12:42pm UTC](https://discourse.slicer.org/t/shift-mouse-not-placing-on-surface-of-segment/48240/1 "2026-09-23T12:42:44Z")

</div>

This is on main, built yesterday on MacBook Pro M5. When I hold down shift in the 3D view to place a crosshair, the crosshair is placed slightly above the segment (see attached image). This does not happen on my Windows machine running 5.12.1. Any ideas? This makes placing markups on 3D models inconsistent across platforms. Do I have some incorrect setting in the latest build? Many thanks!!

 ![image](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/7/2/72c4cc6d0e3d5bc0d67351c6ed55e1656dee59de.jpeg)

---

<div class="post-metadata">

### Author: ![hherhold](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/hherhold/32/12199_2.png) [@hherhold](https://discourse.slicer.org/u/hherhold)
#### Post date: [September 23, 2026, 12:49pm UTC](https://discourse.slicer.org/t/shift-mouse-not-placing-on-surface-of-segment/48240/2 "2026-09-23T12:49:24Z")

</div>

This also occurs on 5.12.4 amd64 (running under rosetta).

---

<div class="post-metadata">

### Author: ![hherhold](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/hherhold/32/12199_2.png) [@hherhold](https://discourse.slicer.org/u/hherhold)
#### Post date: [September 23, 2026, 1:33pm UTC](https://discourse.slicer.org/t/shift-mouse-not-placing-on-surface-of-segment/48240/3 "2026-09-23T13:33:14Z")

</div>

And also on Windows running 5.12.4.

I actually have a fix for this, with Claude’s help: it looks like it’s associated with “BUG: Keep 3D picking fast when a large surface is shown” (commit 20a81474c0, Aug 2).

Salient points from Claude:

1. **The cause:** the 5.12.4 change adds a lookup structure (a cell locator) to large surfaces. With it, VTK’s picker takes the first triangle that comes within the pick tolerance of the ray, not the one the ray actually hits.
2. **The fix:** it doesn’t touch the locator. It first searches for a triangle the ray actually hits, then falls back to the normal tolerance search.
3. **Performance:** a pick still takes microseconds, versus milliseconds before 5.12.4. Rays that miss the surface can take a second search, but even the slowest pick in the benchmark was under 0.1 ms.

I’m happy to submit a PR, let me know.

---

<div class="post-metadata">

### Author: ![hherhold](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/hherhold/32/12199_2.png) [@hherhold](https://discourse.slicer.org/u/hherhold)
#### Post date: [September 23, 2026, 2:36pm UTC](https://discourse.slicer.org/t/shift-mouse-not-placing-on-surface-of-segment/48240/4 "2026-09-23T14:36:04Z")

</div>

The thread associated with this change can be found here:

> <https://github.com/Slicer/Slicer/pull/9329>
>
> \### Symptom
> Picking in a 3D view is janky whenever a large surface is shown — mo…st commonly
> a segmentation closed surface. Markup control-point dragging (default snap mode
> "to visible surface") and hover read-out both pick on every mouse move; hiding
> the surface makes interaction smooth again. A plain \`forceRender()\` of the same
> scene is fast (~12 ms), so the cost is in picking, not rendering.
> 
> \### Cause
> \`vtkCellPicker\` tests \*\*every cell of every pickable surface\*\* unless a spatial
> locator is registered for that surface's data. Over a segmentation closed
> surface with millions of cells each pick costs tens to hundreds of milliseconds
> (measured ~184 ms over a 2.4 M-cell surface; a warmed pick is as slow as the
> first, confirming it is brute force, not a one-time build).
> 
> \### Fix
> Add \*\*\`vtkMRMLAccuratePicker\`\*\* (a \`vtkCellPicker\` subclass) that registers and
> caches a \`vtkStaticCellLocator\` for each large, pickable surface in the renderer
> before every pick — rebuilding a locator only when its surface changes and
> dropping it when the surface is hidden. Picks become indexed queries; tolerance,
> picked position, and returned normal are unchanged.
> 
> Following review feedback, this is \*\*shared per view rather than per widget\*\*:
> \`vtkMRMLThreeDViewInteractorStyle\` now creates a \`vtkMRMLAccuratePicker\` as the
> picker it already hands to \`vtkMRMLInteractionEventData\`, so every widget — and
> anything that needs quick localization in world coordinates — reuses one picker
> and one set of locators. This also accelerates the interaction-context / hover
> pick (\`ComputeAccurateWorldPosition\`), not just markups. The markups widget
> passes the shared picker to its representation for each interaction event, so
> control-point dragging uses it too.
> 
> | | before | after |
> |---|---|---|
> | pick over a 2.4 M-cell surface | ~184 ms | ~0.03 ms |
> | scripted control-point drag over the surface | ~184 ms/move | ~0.4 ms/move |
> 
> The only residual cost is a one-time locator build (~50 ms for a multi-million
> cell surface) on the first pick after such a surface appears — a single frame,
> then sub-millisecond. Helps any large surface, not only segmentations.
> 
> \### Test
> \`vtkMRMLAccuratePickerTest\` picks repeatedly over a 1.6 M-cell surface and
> asserts the picks stay fast (\< 30 ms/pick). It fails (~78 ms/pick) without the
> locator and passes (~0.2 ms/pick) with it; the wide gap keeps it insensitive to
> hardware speed.

---

<div class="post-metadata">

### Author: ![pieper](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/pieper/32/8_2.png) [@pieper](https://discourse.slicer.org/u/pieper)
#### Post date: [September 23, 2026, 2:38pm UTC](https://discourse.slicer.org/t/shift-mouse-not-placing-on-surface-of-segment/48240/5 "2026-09-23T14:38:52Z")

</div>

Thanks for catching this and sorry about the regression.

Yes, a PR ideally with a confirmed test to prevent a future regression would be great.

---

<div class="post-metadata">

### Author: ![hherhold](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/hherhold/32/12199_2.png) [@hherhold](https://discourse.slicer.org/u/hherhold)
#### Post date: [September 23, 2026, 3:02pm UTC](https://discourse.slicer.org/t/shift-mouse-not-placing-on-surface-of-segment/48240/6 "2026-09-23T15:02:26Z")

</div>

Okie dokie, I usually do PRs by hand but I’m going to try Claude this time, apologies in advance if it goes wonky.

Edit - spelling error.

---

<div class="post-metadata">

### Author: ![hherhold](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/hherhold/32/12199_2.png) [@hherhold](https://discourse.slicer.org/u/hherhold)
#### Post date: [September 23, 2026, 3:27pm UTC](https://discourse.slicer.org/t/shift-mouse-not-placing-on-surface-of-segment/48240/7 "2026-09-23T15:27:25Z")

</div>

OK, submitted.

> <https://github.com/Slicer/Slicer/pull/9404>
>
> Since #9329, positions picked in 3D views on large surfaces can land in front of… the surface instead of on it. This is easy to see with the crosshair: Shift + mouse-move over a segmentation closed surface puts the crosshair slightly above the surface. Slicer 5.12.1 puts it on the surface; 5.12.4 does not, on both macOS and Windows.
> 
> \## Cause
> 
> \#9329 makes \`vtkMRMLAccuratePicker\` register a \`vtkStaticCellLocator\` for each surface with 10,000 or more cells. With a locator, \`vtkCellPicker::IntersectDataSetWithLine()\` takes the first cell along the ray that intersects the ray within the pick tolerance. \`vtkTriangle::IntersectWithLine()\` accepts a ray that crosses the plane of the triangle within the tolerance of the triangle, and returns that crossing point. Over a curved surface, that is often a neighboring triangle in front of the one that the ray hits, so the picked position is in front of the surface. Without a locator, \`vtkCellPicker\` prefers the cell with the smallest parametric distance, which is the cell that the ray passes through.
> 
> \## Fix
> 
> \`vtkMRMLAccuratePicker\` overrides \`IntersectDataSetWithLine()\`. For a surface indexed with a locator, it first searches for a cell that the ray hits, and uses the pick tolerance only if the ray does not hit the surface (for example, just outside its silhouette). The first search uses 1e-6 times the pick tolerance rather than zero: with zero tolerance, a ray that passes exactly through a shared edge can miss both triangles due to rounding. Picking stays locator-accelerated.
> 
> \## Testing
> 
> \- \`vtkMRMLAccuratePickerTest\` now also picks a 15 × 15 grid of positions on a bumpy surface (80,000 triangles, about 1 unit wide) and checks that they are on the surface. Without the fix, 197 of 225 positions are off the surface, by up to 9e-4. With the fix, none are (largest distance 2e-16). The existing speed check still passes.
> \- MRMLDisplayableManager and Markups tests pass.
> \- Checked interactively on macOS with a segmentation closed surface: the crosshair is on the surface.
> 
> Pick times with the VTK of Slicer 5.12.4 (Apple M5 Max), for a grid of picks over a whole 2000 × 550 view:
> 
> | Surface | Without locator (up to 5.12.3) | With locator (5.12.4) | This PR |
> |---|---|---|---|
> | 124k triangles | 1.7 ms | 8 µs (16 µs on the surface) | 14 µs (15 µs on the surface) |
> | 588k triangles | 7.6 ms | 9 µs (26 µs on the surface) | 15 µs (19 µs on the surface) |
> 
> Rays that miss the surface can take a second locator search. These times were measured in Python by running a second pick for those rays, which overstates their cost; the slowest pick was under 0.1 ms.
> 
> \## Backport
> 
> Please add the \`backport:5.x\` label (I can't set labels): #9329 was backported to 5.12, so 5.12.4 has this issue.
> 
> 🤖 Generated with \[Claude Code\](https://claude.com/claude-code)

---

<div class="post-metadata">

### Author: ![hherhold](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/hherhold/32/12199_2.png) [@hherhold](https://discourse.slicer.org/u/hherhold)
#### Post date: [September 23, 2026, 4:56pm UTC](https://discourse.slicer.org/t/shift-mouse-not-placing-on-surface-of-segment/48240/8 "2026-09-23T16:56:54Z")

</div>

@pieper I have to say, the speedup in placing markups is a game changer for me.
