Closes #6321: Auto-snap SECTION endpoints to drawing border#7965
Closes #6321: Auto-snap SECTION endpoints to drawing border#7965theoryshaw wants to merge 9 commits intov0.8.0from
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
When a SECTION annotation is created or a drawing is activated, endpoint vertices are automatically placed at a configurable BorderOffset (paper-space mm, default 8) inside the camera border, scaled by the drawing scale. BorderOffset is stored in the BBIM_Section pset and visible in the Property Sets panel. An "UpdateSectionEndpoints" operator (bim.update_section_endpoints) resets endpoints back to the border offset on demand. Endpoints are also recomputed when the diagram scale is changed. Generated with the assistance of an AI coding tool.
504d0b1 to
c1d4494
Compare
BonsaiPR Conflict Resolution: PR #7798 vs PR #7965Date: 2026-04-19 ProblemPR #7798 (Manual drawing reference) (
The goal was to resolve the conflict without modifying PR #7798, which needs to stay clean for upstream submission. Step 1: Identifying the Conflicting PRPR #7798 touches the following files:
After testing PR #7798 against the Checking which build PRs touched Confirmation: PR #7798 was successfully included in the previous build Step 2: Testing Other Skipped PRsThe following open PRs were also not in the build branch and were tested against it:
PRs #7886 and #7924 have separate conflicts (not with PR #7798), left for another time per user request. Step 3: Nature of the ConflictBoth PRs add a new operator class registration to the same location in PR #7798 adds: operator.AddAnnotationType,
+ operator.AssignManualDrawingReference, # ← PR #7798
operator.AddDrawing,PR #7965 adds: operator.AddAnnotationType,
+ operator.UpdateSectionEndpoints, # ← PR #7965
operator.AddDrawing,This is a classic adjacent-line insertion conflict. The two features are independent and additive — neither is a subset of the other. Both operators need to be registered. Step 4: Rebase DirectionDecision: Rebase PR #7965 onto PR #7798.
PR #7798 is the more mature, upstream-bound PR and must not be modified. PR #7965 is a brand-new PR that should accommodate the established one. The build processes PRs in descending PR-number order (newest first). Since
Step 5: Rebase ExecutionUsed git checkout -b pr-7965-rebased origin/inset_section_endpoints
git rebase --onto origin/ManualDrawingReference origin/v0.8.0Conflict in operator.AddAnnotationType,
operator.AssignManualDrawingReference, # from PR #7798
operator.UpdateSectionEndpoints, # from PR #7965
operator.AddDrawing,Rebase completed cleanly. All other files (data.py, operator.py, prop.py, core/drawing.py, tool/drawing.py) auto-merged without conflicts. Step 6: Pushgit push origin pr-7965-rebased:inset_section_endpoints --force-with-leaseResult: Summary
|
Closes #6321
Summary
Prior to this change,
SECTIONannotation endpoints had no relationship to the drawing camera border. Their positions were entirely manual — a user had to place them by hand each time, and they would not update if the drawing scale changed.This PR introduces automatic placement of
SECTIONannotation endpoints: when a section annotation is created, when a drawing is activated, or when the diagram scale is changed, the two mesh vertices that form the section line are automatically positioned at a configurable inset distance (BorderOffset) from the drawing camera's orthographic border. The offset is defined in paper-space millimetres and is converted to model-space units using the drawing scale, so the same 8 mm inset looks correct at 1:50, 1:100, or any other scale.If a user manually moves one endpoint in Edit Mode, that vertex is fingerprinted and its custom position is preserved. Only endpoints that still sit at their last auto-computed position are updated on the next activation or scale change. A dedicated operator lets the user force-reset both endpoints back to the border offset at any time.
What Changed
tool/drawing.py— new geometry helpers and core update logicget_camera_dimensions(camera)— derives the camera's model-space width and height fromortho_scaleand the render resolution aspect ratio._section_ray_rect_intersections(origin, direction, half_w, half_h)— finds the twotvalues where an infinite ray through the section line's midpoint intersects the camera border rectangle.get_section_border_positions(camera, v0_world, v1_world, border_offset_mm)— uses the above two helpers to compute the two world-space positions that sitborder_offset_mm(paper mm, converted by scale) inside the camera border along the section line direction.update_section_endpoints(obj, camera)— the main entry point. ReadsBorderOffset,AutoStartPosition, andAutoEndPositionfrom theBBIM_Sectionpset. Compares each current world-space vertex position against its stored auto-position; if they match (or no auto-position is stored yet) the vertex is auto-updated. Writes the new auto-positions andBorderOffsetback to the pset, then callsbpy.ops.bim.update_representationto persist the moved vertices to the IFC geometry._parse_vector3/_format_vector3— small static helpers to serialise and deserialise aVectorto/from a comma-separated string for IFC pset storage.data.py— pset defaultsget_section_markers_display_data()now addsBorderOffset: 8.0,AutoStartPosition: "", andAutoEndPosition: ""to theBBIM_Sectionpset defaults so the values are always present and visible in the Property Sets panel even before the user changes anything.operator.py— new operator + activation hookUpdateSectionEndpoints— a newbim.update_section_endpointsoperator (label: "Reset Section to Border"). It clearsAutoStartPositionandAutoEndPositionin the pset so thatupdate_section_endpointstreats both vertices as unmodified, then callsupdate_section_endpointsto recompute. Only enabled when the active object is aSECTIONannotation and a scene camera is set.ActivateDrawingBase._execute— aftersync_referencesreloads the IFC geometry, iterates over allIfcAnnotationmembers of the drawing group withObjectType == "SECTION"and callsupdate_section_endpointsfor each one.prop.py— scale-change hookupdate_diagram_scale()(the callback for the diagram scale dropdown) now iterates the same drawing group and callsupdate_section_endpointsfor everySECTIONannotation in it, so endpoints are repositioned immediately when the scale is changed.core/drawing.py— creation hookadd_annotation()now callsupdate_section_endpointsimmediately after the new annotation is assigned to the drawing group, so a freshly created section annotation starts at the correct inset positions.__init__.pyUpdateSectionEndpointsis added to theclassestuple so it is registered with Blender.Notes
print("[SECTION] …")statements are present throughout and should be removed before final merge.AutoStartPosition/AutoEndPositionare stored in world space in this version. An object-level translate (moving the annotation object without editing vertices) will change world-space vertex positions while leaving local-spacev.counchanged, which can cause false "manually moved" detection. This is a known limitation of the current approach.BorderOffsetis intentionally exposed in the Property Sets panel rather than a custom UI panel, so users can inspect and override it without any additional UI work.Generated with the assistance of an AI coding tool.