{{ message }}
Manual drawing reference#7798
Open
theoryshaw wants to merge 25 commits into
Open
Conversation
Introduces a boolean pset property that marks an ELEVATION or SECTION annotation as manually placed, exempting it from automatic deletion or regeneration during drawing sync. Generated with the assistance of an AI coding tool.
Adds operator to place manual elevation/section drawing reference tags that survive drawing regeneration. Includes core function, tool methods, type-selection dialog, default horizontal rotation for elevation tags, and SVG null guard for unassigned references. Generated with the assistance of an AI coding tool.
Adds operator to link a manual drawing reference tag to a target drawing via IfcRelAssignsToProduct, with a pre-populated dialog and immediate Properties panel refresh on confirm. Generated with the assistance of an AI coding tool.
Adds MANUAL_DRAWING_REFERENCE to the annotation type dropdown. Selecting it shows a dialog to choose elevation or section and optionally assign a target drawing before placement. Tags are protected from regeneration via EPset_Annotation.IsManualDrawingReference. Generated with the assistance of an AI coding tool.
The elevation tag's local -Z axis is intentionally parallel to its drawing camera's view direction, making screen-space projection of that axis always degenerate (zero XY delta). Fall through to the tag's local +X axis, which lies in the camera plane and rotates correctly as the user adjusts the tag's orientation. Also fix a zero-length vector crash in svgwriter when the same degenerate case occurs during SVG export.
Use get_default_annotation_matrix() for manual SECTION annotations so the object is placed in the camera's annotation plane with the correct rotation, matching how auto-generated section annotations are created. Without this, annotations placed in elevation or section camera views had identity rotation, causing the IFC representation to be in the wrong coordinate system and failing to tessellate. Also guard draw_edit_object_interface against non-IFC active objects to prevent AssertionError during toolbar redraws, and skip IFC item edit mode for ELEVATION/SECTION annotation types on placement.
Replace plain enum dropdowns with prop_with_search in the AddAnnotation and AssignManualDrawingReference operator dialogs, making it easier to locate a target drawing when many drawings exist in the project. Generated with the assistance of an AI coding tool.
Extends manual drawing reference annotations (elevation and section) to also support external SVG references imported via bim.add_reference. - Add "Is a Reference" checkbox to the annotation tool sidebar, shown when Elevation or Section is the active type; checking it and pressing Add opens a dialog to optionally link the tag to a Bonsai drawing or an external SVG reference - The MANUAL_DRAWING_REFERENCE dropdown type is retained for backwards compatibility; selecting it shows a style picker (Elevation/Section) and the same linking dialog - External-reference annotations are flagged with IsDocumentReference in EPset_Annotation and linked to their IfcDocumentInformation via IfcRelAssociatesDocument; drawing-reference annotations continue to use IfcRelAssignsToProduct as before - SVG export resolves the correct reference/sheet IDs for both link types via get_reference_and_sheet_id_from_annotation - Add IsDocumentReference to the EPset_Annotation pset template
Member
Author
…uld not show `0`.
…BBIM_Dimension.SuppressZeroInches Generated with the assistance of an AI coding tool.
Generated with the assistance of an AI coding tool.
…eometry New modal operator (bim.set_dimension_anchor) anchors dimension vertices to IFC element faces. Anchors are stored as JSON in a BBIM_DimensionTarget pset on the IfcAnnotation and resolved via tessellation at regeneration time. - resolve_anchor.py / regenerate_dimension.py: new ifcopenshell API modules - bim.set_dimension_anchor: 2-phase Object Mode modal (pick vertex → pick face) - bim.regenerate_dimensions: recomputes all parametric dimensions - Auto-regeneration via depsgraph_update_post when referenced elements move - placement_override reads Blender matrix_world for G-moved elements - Plan-view annotations flattened to annotation plane (Z=0 in local space) - IfcIndexedPolyCurve.Segments rebuilt to handle n-point chains correctly
…imensions Extends parametric dimension support with a modal polyline operator that uses Bonsai's existing snap infrastructure (same as walls/slabs) for placing anchor points. Shift+A in the Annotation tool now routes dimension types through this operator instead of the generic add_annotation path. - DrawParametricDimension: PolylineOperator subclass; each confirmed snap point is converted to a BBIM_DimensionTarget anchor via _snap_to_anchor, which reads face_index from the snap dict for face hits and falls back to closest_point_on_mesh for vertex/edge hits - handle_inserting_polyline override tracks anchor list in sync with polyline points (insert on count increase, pop on BACKSPACE) - hotkey_S_A dispatches to bim.draw_parametric_dimension for DIMENSION/RADIUS/ DIAMETER/ANGLE/PLAN_LEVEL/SECTION_LEVEL types; all other types keep existing path - depsgraph_update_post_handler extended to also watch is_updated_geometry so dimensions auto-regenerate when a referenced mesh is edited in Edit Mode; the affected element's tessellation is evicted from _dim_shape_cache so resolve_anchor re-tessellates from the updated IFC representation on the next pass Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
SetDimensionAnchor — hover-select-then-confirm: - Cursor highlights candidate IFC elements (orange Blender selection outline) before committing; Tab cycles through overlapping/coplanar candidates - _compute_candidates: ray-cast all IFC mesh objects; falls back to 2D bounding-box proximity (5 cm tolerance) for plan-view picks where the ray misses the mesh by sub-mm amounts - _write_anchor: after anchoring a face, immediately calls regenerate_dimension with placement_override (Blender matrix_world) and _update_blender_curve so the curve vertex moves to the resolved point DrawParametricDimension — ForcePerpendicularToFace live snap constraint: - Reads force_perpendicular_to_face toggle from annotation props on invoke - After anchor[0] is placed on a FACE, _update_perp_constraint extracts the face normal and stores it as the constraint axis - _apply_perp_constraint runs every modal tick after handle_snap_selection, projecting the current snap point onto pt[0] + t*normal - On finalize, _create_dimension_from_polyline writes ForcePerpendicularToFace to the BBIM_Dimension pset and calls regenerate_dimension to snap the stored curve to the constraint before the operator exits regenerate_dimension.py: - ForcePerpendicularToFace block: after resolving all anchors, projects vertices 1…n onto the line through pt[0] along anchor[0]'s face normal - _get_anchor_face_normal_world: reads normal_local from anchor fingerprint, calls _rotate_local_to_world with placement_override; falls back to stored world-space normal resolve_anchor.py: - _rotate_local_to_world: transforms an element-local direction vector to world space using the element's placement or placement_override matrix pset/operator.py: - EditPset._execute: after editing a BBIM_Dimension pset on an IfcAnnotation, auto-calls regenerate_dimension + _update_blender_curve so changes to anchors/ForcePerpendicularToFace are reflected immediately in the viewport prop.py / workspace.py: - Added force_perpendicular_to_face BoolProperty to BIMAnnotationProperties - UI toggle shown in annotation tool header for DIMENSION/RADIUS/DIAMETER/ ANGLE/PLAN_LEVEL/SECTION_LEVEL types Psets_BBIM_Annotation.ifc: - Added ForcePerpendicularToFace property template (#39) to BBIM_Dimension - Extended BBIM_Dimension applicability to ANGLE, PLAN_LEVEL, SECTION_LEVEL Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…cularToFace toggle updates selection workspace.py: - Move "Set Dimension Anchor" and "Regenerate" buttons from the properties panel (ui.py) into draw_edit_object_interface in the annotation tool, visible whenever a selected object is a dimension-type IfcAnnotation - Change force_perpendicular_to_face from a push-button (toggle=True) to a standard checkbox for clearer on/off state ui.py: - Remove the "Parametric Dimension" section (now lives in the tool header) prop.py: - Add _update_force_perpendicular update callback: when the checkbox is toggled, iterates all selected dimension annotations, writes the new ForcePerpendicularToFace value to each BBIM_Dimension pset, and calls regenerate_dimension so the constraint is applied immediately Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…pendicularToFace - BBIM_Dimension.LinePosition (IfcLengthMeasure): holds the dimension line at a fixed global coordinate along cross(world_Z, dim_direction), independent of geometry movement - regenerate_dimension applies LinePosition only when ForcePerpendicularToFace is also set (the two are semantically coupled); anchor["pt"] always stores the true surface hit so the measured length is unaffected - BIMAnnotationProperties.line_position uses get/set callbacks instead of an update callback to avoid the 'Writing to ID classes in this context is not allowed' error that fires when Blender draws the tool header - DimensionLinePositionWidget (BIM_GGT_dimension_line_position): gizmo group with two opposing GizmoCone handles at the curve midpoint; poll requires ForcePerpendicularToFace so the handles only appear when the feature is active - UI: line_position field and gizmo are hidden when ForcePerpendicularToFace is off - Psets_BBIM_Annotation.ifc: #40 LinePosition template added to BBIM_Dimension Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tric dimensions - GizmoAnchorHandle + DimensionAnchorWidget: colored dot gizmos at each dimension curve vertex (green=anchored, orange=free); color changes to blue while SetDimensionAnchor is in PICK_FACE mode for that vertex - ClickNearestDimensionAnchor (LMB keymap): Python proximity operator that fires SetDimensionAnchor pre-targeted at the nearest anchor dot within 120px, returning PASS_THROUGH for misses so normal viewport clicks are unaffected - SetDimensionAnchor: added anchor_index prop to enter PICK_FACE directly; set_active_anchor called at all phase transitions (invoke, vertex-pick, face-pick, alt-click free, ESC/RMB) so gizmo color tracks state correctly - handler._sync_dimension_anchors_to_curve: proximity-based anchor sync when curve vertex count changes in Edit Mode (subdivide / delete) - depsgraph_update_post_handler: regenerates dimensions when referenced elements move; also handles annotation curve edits directly - Remove standalone Set Anchor button from annotation tool UI (replaced by clicking a gizmo dot) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… layer anchors - ClickNearestDimensionAnchor: scan all selected objects instead of active object so clicking a green dot doesn't lose to the underlying IFC geometry - GizmoAnchorHandle: remove draw_select entirely (any entry in the select buffer causes Blender's gizmo system to consume clicks); keep purely visual - Scale anchor dots to scale_basis = 0.2 - Fix ReferenceError in decoration.py draw loop after undo by catching ReferenceError and resetting DecoratorData.is_loaded - SetDimensionAnchor: inherit tool.Ifc.Operator so IFC pset writes are tracked for undo; finish the modal after each face write so each anchor gets its own undo step - Fix ReferenceError in _modal after undo when annotation RNA is freed - handler.py: add regenerate_dims_for_layer; call it from EditMaterialSetItem._execute so dimensions update when layer thickness changes - regenerate_dimension.py: fix ForcePerpendicularToFace for LAYER_BOUNDARY anchors by deriving the thickness-axis normal from LayerSetDirection (AXIS2→Y, AXIS1→X, AXIS3→Z) instead of requiring a stored normal_local Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…for DrawParametricDimension - DrawParametricDimension: TAB cycles snap mode FACE→LAYER→EDGE→VERTEX during placement; consumes both PRESS and RELEASE when not in input mode to avoid conflict with polyline Cycle Input - DrawParametricDimension: IFC-native snap candidate overrides polyline cursor position in LAYER/EDGE/VERTEX modes; FACE mode shows polygon outline; reuses _snap_draw_data / _draw_snap_indicator_global infrastructure from SetDimensionAnchor - DrawParametricDimension: LAYER_BOUNDARY support in _update_perp_constraint, deriving normal from LayerSetDirection (AXIS1/2/3) - ClickNearestDimensionAnchor: scan all visible annotations instead of only selected ones — view3d.select deselects the dimension before this operator runs, so pre-selection check caused dots to never activate - AnnotationTool keymap: bim.click_nearest_dimension_anchor placed before view3d.select so it fires first when the annotation tool is active Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove clear_snap_objs() from PolylineOperator.invoke — BVH cache now persists across invocations; per-entry staleness is checked in create_snap_obj via matrix_world equality + vertex count, eliminating the ~11 s full rebuild on every Shift+A press. - Add _init_snapping_points() hook to PolylineOperator; DrawParametricDimension overrides it with a cheap plane-intersection placeholder, deferring full BVH detection to the first MOUSEMOVE. - Cache matrix_world in SnapObj and replace O(N_vertices) validation loop with O(1) matrix equality + single sample vertex check, cutting per-call create_snap_obj cost from 22-600 ms to <0.2 ms on cache hits. - Use scene-level BVH pierce-through in SetDimensionAnchor._compute_candidates instead of per-object ray_cast loop (O(log N) vs O(N_objects)). - Guard PolylineDecorator snap_mouse_point access against empty collection to prevent IndexError before first MOUSEMOVE populates the property. - Wrap closest_point_on_mesh in try/except RuntimeError in _update_snap_draw_data for annotation objects with no internal mesh data. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nsion Vertical faces perpendicular to the camera cannot be hit by raycast, so the dimension snap tool missed them entirely. Fix by checking nearby objects whose 3D bbox contains the floor hit point and running mode-appropriate candidate lookup on each: - FACE mode: _snap_on_coplanar_faces finds vertical mesh faces with a bottom edge at the hovered Z, projects the cursor onto the face plane, and returns a FACE candidate (blue outline + face snap point). - LAYER mode: get_layer_snap_candidates now runs on nearby bbox objects the same way VERTEX/EDGE mode already did, using the shared _snap_cand_multi_cache (cleared on TAB mode switch).
Both PR #7798 (ManualDrawingReference) and PR #8083 (parametric_dimensions) independently added properties after entry #33 in Psets_BBIM_Annotation.ifc and new BoolProperty declarations after `type_name` in prop.py and workspace.py UI rows at the same locations. Resolution: keep #8083's IDs (#34-#40) unchanged, renumber #7798's IsManualDrawingReference and IsDocumentReference entries to #41 and #42, update EPset_Annotation reference list accordingly, keep both UI rows, and combine hotkey_S_A to use #8083's parametric-dimension routing with #7798's "INVOKE_DEFAULT" argument for add_annotation.
Member
Author
…bility Move is_manual_reference UI block to before _DIMENSION_TYPES to match the position established by PR #7965's conflict resolution already present in the build. The prior merge fix (66fcad8) placed it after _DIMENSION_TYPES, causing a 3-way merge conflict when the build's #7965 has it before. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Member
Author
theoryshaw
added a commit
that referenced
this pull request
Jun 8, 2026
The build (BonsaiPR v0.8.6-alpha260608-c65433c) already contains old parametric_dimensions commits (pre-rebase, different hashes) followed by PR #7798 (ManualDrawingReference) and other PRs merged on top. After the rebase of parametric_dimensions onto v0.8.0, git's LCA between the build state and this branch reverted to v0.8.0. This caused false conflicts in DrawParametricDimension (operator.py) where both sides "added" it from empty, and real conflicts in prop.py/workspace.py/pset from PR #7798 additions that now appeared as build-only changes. Fix: merge old-pd tip 913c9c4 with -s ours (no content change) to make it a git ancestor of this branch. This shifts the LCA to 913c9c4, so: - operator.py: only new pd changed DrawParametricDimension from that LCA -> clean - prop.py / workspace.py / pset: new pd = LCA; build added #7798 content -> clean Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Addresses #7790:
Manual Drawing Reference Tags
What & Why
Elevation and section reference tags are normally generated automatically by Bonsai. But there are cases where a manually placed, persistent reference is needed — one that survives drawing regeneration without being moved or deleted. This PR adds a Manual Drawing Reference annotation type for exactly that.
Changes
AssignManualDrawingReferenceoperator — reassign an existing manual tag to a different drawing via the Properties panel, using a searchable dropdown.IsManualDrawingReferencepset flag — marks a tag as manually placed;is_auto_annotationnow respects this flag so manual tags are never touched during regeneration.-Zis parallel to the camera view; no crash when no drawing is assigned.Bug Fixes
ElevationDecoratorarrow — triangle failed to render in non-plan views because the tag's local-Zalways projects to near-zero XY in camera space. Now cascades through local axes to find a non-degenerate screen projection.get_default_annotation_matrix(camera), matching how auto annotations are created.get_text_datawas called without checking for an IFC entity on the active object; guarded withtool.Ifc.get_entity(obj).20260315_1533.mp4