Skip to content

Fix #7799: Fix elements hidden when activating plan drawings#7807

Open
theoryshaw wants to merge 2 commits intov0.8.0from
fix/drawing-activation-stale-bbox
Open

Fix #7799: Fix elements hidden when activating plan drawings#7807
theoryshaw wants to merge 2 commits intov0.8.0from
fix/drawing-activation-stale-bbox

Conversation

@theoryshaw
Copy link
Copy Markdown
Member

Problem

When activating a plan view drawing (bim.activate_drawing) after previously
activating a reflected ceiling plan (RCP) drawing — or vice versa — certain
elements would be hidden from the scene even though they belong to that storey
level. In the reported case, an IfcLightFixture with both PLAN_VIEW and
REFLECTED_PLAN_VIEW representations was invisible after switching between the
two drawing types.

Root Cause

activate_drawing calls get_drawing_elements, which calls
get_elements_in_camera_view to determine which objects fall within the
camera's frustum. The frustum test in is_in_camera_view used obj.bound_box
— the bounding box of the currently active Blender mesh — to determine
whether an element intersects the camera.

The problem is that activate_drawing switches each element's active
representation to match the target view after the camera frustum test. So
when switching from an RCP drawing to a plan view drawing:

  1. The element's active mesh is the REFLECTED_PLAN_VIEW geometry (ceiling
    level, e.g. local z ≈ +1.2 m above the element origin).
  2. The plan view camera looks downward from z = 1.6 m world. The camera frustum
    in camera-local space spans z ∈ [−10, −0.002].
  3. The ceiling-level mesh transforms to positive z in camera-local space
    (above the camera), falling entirely outside the frustum.
  4. is_in_camera_view returns False, the element is excluded from
    filtered_elements, and it is hidden — regardless of the fact that a
    PLAN_VIEW representation exists that would be within the frustum.

The same failure occurs in reverse: activating an RCP drawing when the
element's active mesh is the PLAN_VIEW geometry (floor level, below the
upward-looking RCP camera).

Fix

tool/drawing.py — representation-independent bbox

A new helper _get_bbox_corners(obj, element) replaces the direct use of
obj.bound_box in is_in_camera_view. It unions three bbox sources to produce
a spatial envelope that is independent of which representation is currently
active:

  1. IfcBoundingBox — if the element has a Box representation context,
    the IfcBoundingBox item is read and converted to metres. This provides the
    canonical floor-plan footprint defined in the IFC file, which is always
    present regardless of which Blender mesh is active.

  2. Accumulated custom properties (obj["ifc_bbox_min"] /
    obj["ifc_bbox_max"]) — a growing union of every representation bbox that
    has been loaded for this object, populated by update_bbox_accumulation (see
    below). After the first round-trip between drawing types, this covers all
    previously seen geometry extents.

  3. obj.bound_box — the existing fallback for objects without IFC metadata
    or on first load.

The union of these three sources ensures the bounding envelope spans both the
floor-level footprint (for plan cameras) and the ceiling-level geometry (for
RCP cameras), so the frustum test returns True for both view types regardless
of which mesh is currently active.

is_in_camera_view gains an optional element parameter passed through from
get_elements_in_camera_view, which now iterates objects explicitly rather than
using a list comprehension so the entity lookup is available for both the test
and the result set.

tool/geometry.py — bbox accumulation

New method update_bbox_accumulation(obj) unions the current obj.bound_box
into obj["ifc_bbox_min"] / obj["ifc_bbox_max"] Blender custom properties.
The union grows monotonically as representations are loaded, so after any two
representation switches the accumulated bbox covers all seen extents.

core/geometry.py — hook into representation switching

switch_representation calls geometry.update_bbox_accumulation(obj) after
reimport_element_representations completes. This means every time a drawing
activation switches an element's mesh, the new geometry is harvested into the
accumulation automatically.

Notes

  • No changes to IFC reading, writing, or any operator logic outside of the
    three files listed above.
  • The IfcBoundingBox path only activates when the element has a Box
    representation context; elements without one fall through to the accumulated
    props and obj.bound_box unchanged.
  • On a cold Blender session (no prior representation switches), the
    IfcBoundingBox alone is sufficient to fix the plan-view case for elements
    that carry a Box context. For elements without a Box context, the
    accumulated props will build up after the first switch.

Testing

Tested with an IFC file containing an IfcLightFixture with
Model/Body/PLAN_VIEW, Model/Body/REFLECTED_PLAN_VIEW, and
Model/Box/MODEL_VIEW representations:

  • Activating the plan view drawing from a cold session (RCP mesh active):
    fixture is now included and switches to PLAN_VIEW representation. ✓
  • Activating the RCP drawing after the plan view: fixture is included and
    switches to REFLECTED_PLAN_VIEW representation. ✓
  • Toggling between the two drawings repeatedly: both continue to work. ✓

Generated with the assistance of an AI coding tool.

Elements with multiple IFC representations (plan, RCP, body)
were incorrectly excluded from drawings because the camera
frustum test used obj.bound_box, which reflects only the
currently active Blender mesh. After switching from an RCP
drawing, the plan-view mesh was no longer active, placing the
element's bbox outside the plan camera's frustum.

Fix by unioning three bbox sources in is_in_camera_view:
the IfcBoundingBox (representation-independent footprint),
accumulated custom properties built up across representation
switches, and the current obj.bound_box. This ensures the
spatial test covers the element's full extent regardless of
which representation is active.

Generated with the assistance of an AI coding tool.
Guard against objects that have already been removed from
Blender's data (StructRNA removed) before the function runs.
This occurs when switch_representation is called on temporary
annotation objects that are freed before returning.

Generated with the assistance of an AI coding tool.
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.

1 participant