FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Bonsai: snap to the nearest solid, not the nearest object origin by carlopav · Pull Request #9004 · IfcOpenShell/IfcOpenShell · GitHub

Bonsai: snap to the nearest solid, not the nearest object origin - #9004

Closed
carlopav wants to merge 1 commit into
IfcOpenShell:v0.8.0from
carlopav:bonsai-snap-nearest-solid
Closed

Bonsai: snap to the nearest solid, not the nearest object origin#9004
carlopav wants to merge 1 commit into
IfcOpenShell:v0.8.0from
carlopav:bonsai-snap-nearest-solid

Conversation

carlopav commented Jul 26, 2026
edited
Loading

Copy link
Copy Markdown
Contributor

Problem

Object snapping cannot snap to an IfcCovering (or any solid) that is coincident with another solid such as a wall or slab. Its vertices/edges are never offered as snap points where it overlaps the other element; the same covering snaps fine where it overhangs into empty space. IfcBuildingElementPart with a tessellated body has the same symptom.

In Raycast.ray_cast_and_get_closest_to_camera_snaps (non-xray path), candidate solids are sorted by object-origin distance to the ray and the loop breaks at the first face hit. Only that object is flagged is_closest_to_camera, and detect_snapping_points then generates vertex/edge snaps for it alone. The object origin is a poor proxy for what is under the cursor (it can sit far from the geometry), so when two solids overlap the wrong one is picked and the front-most surface — the covering — is skipped. Separated elements (plain walls) are unaffected because the heuristic only misbehaves when solids overlap.

Fix

Ray cast every candidate solid under the cursor and keep the one with the nearest actual hit distance — which is what the xray branch and Raycast.cast_rays_and_get_best_object already do — instead of the origin-sort + first-hit heuristic. The extra ray casts are limited to the few solids whose 2D bounding box is under the cursor, and obj.ray_cast is cheap.

Performance trade-off

This replaces the single early-exit ray cast with one ray cast per candidate solid under the cursor. filter_objects_to_raycast already narrows candidates to objects whose 2D bounding box overlaps the mouse, so in the common case that is the 2-3 solids meeting at a wall/slab/covering junction, and obj.ray_cast uses Blender's cached per-object BVH. For very heavy linked scenes, where 2D bounding boxes can be large/imprecise, this does remove the early-exit that previously bounded the non-xray path to a single ray cast — the broader cost of snapping against heavy linked geometry is already tracked in #8187 (Problem 2) and #8008, and would be better addressed by narrowing the candidate set there rather than by keeping the origin-sort heuristic here.

Verify

Logic change in Blender-bound modal code. Tested on a real IFC4 project: a covering coincident with a slab, and a tessellated IfcBuildingElementPart, both went from "not snappable where they overlap" to snapping correctly; plain walls unchanged. Syntax-checked.

A modal regression test in test/modal/test_modal.py (which drives object snapping over snap.ifc) is the right place for a fixture reproducing this, and is planned as a follow-up once a minimal coincident-solid fixture that reliably reproduces the pre-fix behaviour is prepared. Happy to add it here first if preferred.

Related

Test file in issue comments.

🤖 Generated with Claude Code

Object snapping could not snap to an IfcCovering (or any solid) that is
coincident with another solid such as a wall or slab. In the non-xray path,
ray_cast_and_get_closest_to_camera_snaps sorted candidate solids by their
object-origin distance to the ray and stopped at the first face hit. The
object origin is a poor proxy for what is actually under the cursor, so a
covering sitting on a slab was skipped whenever the slab's origin sorted
first - its vertex/edge snaps were never generated.

Ray cast every solid under the cursor and keep the one with the nearest
actual hit (as the xray path and cast_rays_and_get_best_object already do).
The extra ray casts are limited to the few solids whose 2D bounding box is
under the cursor, and obj.ray_cast is cheap.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copy link
Copy Markdown
Contributor Author

ping @brunoperdigao

brunoperdigao self-assigned this Jul 29, 2026

Copy link
Copy Markdown
Contributor

In fact, the origin is not the best parameter. However, this doesn't solve the issue for when we have a wireframe object in front of a mesh, because raycast doesn't detect objects without faces. We need to prioritize the wireframe in those cases. I'll have to think about an alternative approach.

Copy link
Copy Markdown
Contributor

I'm trying a general different approach for the snapping system, that uses the GPU Module from the Blender API. If it works it might solve a lot of current issues.

Copy link
Copy Markdown
Contributor Author

I'm trying a general different approach for the snapping system, that uses the GPU Module from the Blender API. If it works it might solve a lot of current issues.

Thanks for the feedback, I saw that mentioned in another issue, but I thought to open this pr anyway to have a little improvement in the meantime, expecially because it was just two lines of code.
Let me know if you prefer to close the PR, no problem from my side, and good luck with the different approach!

Copy link
Copy Markdown
Contributor Author

fixed with recent changes by @brunoperdigao

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bonsai: object snapping skips a covering/solid coincident with a wall or slab

2 participants


Back | FazBrowse Home | New Git URL