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 (66fcad84e3) 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>
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.
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).
- 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>
- 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>
- 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>
- 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>
- 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>
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>
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>
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>
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
The x-angle transformation for LAYER3 slabs assumed SweptArea
is always IfcArbitraryClosedProfileDef (which has OuterCurve),
but composite profiles use IfcCompositeProfileDef instead.
Apply the coord scaling to each sub-profile individually.
Generated with the assistance of an AI coding tool.
generate_section_reference_points had no handler for
MODEL_VIEW target view, causing it to silently return
None. Add MODEL_VIEW branch that clips the section line
to XY camera bounds while preserving the Z coordinate
for correct 3D placement.
Generated with the assistance of an AI coding tool.
Guard the int() cast on CardinalPoint in
BIM_OT_edit_assigned_material so a None value (no cardinal
point set) no longer raises a TypeError.
Generated with the assistance of an AI coding tool.
Extracted from the font file like so:
python3 -c "
from fontTools.ttLib import TTFont
tt = TTFont('src/bonsai/bonsai/bim/data/fonts/OpenGost Type B TT.ttf')
for record in tt['name'].names:
if record.nameID == 13:
print(record.toUnicode())
"
The https://github.com/IfcOpenShell/website repo already has bonsai-docs.yml workflow that does the same thing - builds Bonsai docs from the main repo and deploys to bonsaibim_org_docs, so this workflow is redundant and confusing.
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
Don't leave a broken repo if ifcmerge is misinstalled.
Fix bug where only local branches could be merged.
Fix gitch where merge commits were not considered relevant.
Add update callbacks to the relating_object and related_object
PointerProperties so that selecting an object via the eyedropper
in BIM_PT_aggregate immediately calls aggregate_assign_object
and closes the editing panel, removing the need to click the
checkmark button manually.
Generated with the assistance of an AI coding tool.
Adds `remove_coplanar_boundary_lines()` to operator.py (Bonsai uses this
path, not draw.py's main()). After `merge_linework_and_add_metadata()`
assigns material CSS classes, this post-processes the SVG to delete
projection line segments that appear in two or more adjacent, coplanar
elements with the same material and presentation style.
Key design decisions:
- Material identity: compared via sorted IFC material ID tuples from
`get_materials()`, not CSS class names — avoids false matches between
unrelated `material-null` elements.
- Presentation style identity: compared via IFC IfcPresentationStyle IDs
from `StyledByItem` on geometry representation items — handles elements
with no material but distinct visual styles.
- Physical adjacency: confirmed by a 3D shared-vertex test (tol=0.01 m)
after a quick AABB guard, rejecting elements whose 2D projections
overlap but sit at different depths.
- Coplanarity: determined by the dominant (largest-area) face normal of
each Blender mesh object — area-weighted averages are unreliable for
slabs whose equal top/bottom faces cancel out. Folded walls sharing an
edge but meeting at an angle are correctly rejected (normal dot ≪ 1.0).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add Anthropic prompt caching (cache_control on system prompt and
tools) to reduce repeated token costs by ~90%
- Truncate large tool results in conversation history (2000 char cap)
to prevent context bloat from ifc_tree/ifc_select responses
- Add sliding window (40 messages) on conversation history, trimming
at user message boundaries to avoid breaking tool-call sequences
- Default "New IFC" button to IFC4X3 schema instead of IFC4
- Constrain ifc_new schema parameter with enum to prevent invalid
schema strings like "IFC4X3ADD2"
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Parse ifcmerge JSON output and display a per-conflict breakdown in the
panel when merge fails. Ctrl+click on the Merge button previews
conflicts without committing. Add SelectConflictEntity operator to
select and frame the conflicting object in the 3D viewport.
Generated with the assistance of an AI coding tool.
A degenerate edge (zero-length segment) caused an early `return`
of a tuple instead of continuing the loop, resulting in a
TypeError when snap.py iterated the result and tried to assign
`point["group"]` on a float.
Generated with the assistance of an AI coding tool.
Add a provider selector (OpenAI / Anthropic) to the ifcchat web UI,
allowing users to use their Anthropic API key with Claude models
instead of only OpenAI.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a remote branch tip is checked out (resulting in detached HEAD),
the new-branch name field is now pre-filled with the local equivalent
of the remote branch name (generating a unique suffix if that name is
already taken), so the commit button is immediately usable.
See #7580
Generated with the assistance of an AI coding tool.
This version has some functional differences:
- Structured JSON error message instead of free text (on STDOUT not STDERR)
- New --prioritise-local flag to control which side wins in merge conflicts (not used by Bonsai yet)
- IfcLocalPlacement conflicts now auto-resolve instead of failing the merge (partial solution to #6885)
- Float values are normalised when comparing entities (workaround for #7696)
Include bonsai_git_branch in get_debug_info(). For dev environments
using the GitPython-based update_commit_data() path, the branch is
read from repo.active_branch.name. For built extensions, a 7777777
placeholder is replaced at build time via the Makefile, matching the
existing pattern for bonsai_commit_hash and bonsai_commit_date.
Generated with the assistance of an AI coding tool.
Move all business logic into bonsai core and tool. Performance fixes to
minimise file IO, various minor bug fixes and tests.
Generated with the assistance of an AI coding tool.
In order to fix error of the type:
| point, _ = cls.intersect_edge_region_border(
| ^^^^^^^^
| TypeError: cannot unpack non-iterable NoneType object
a tuple is expected.
Two bugs introduced in 31b571322:
- SnapObj assumed obj.data is always a Mesh; non-mesh
objects (empties, lights, etc.) have obj.data = None,
causing an AttributeError on obj.data.edges.
- view3d_utils was used but never imported.
Generated with the assistance of an AI coding tool.
Add --format ids to the ifcquery.rst format description and a new
"Scripting with ifcedit" section showing composition examples. Add
the foreach subcommand to ifcedit.rst with usage examples.
Add ifcquery, ifcedit and ifcmcp to the README contents table, the
Sphinx docs toctree and introduction utilities table. Add new .rst
pages for each package documenting subcommands, installation, usage,
and parameter types. Fix plot and render CLI examples in ifcquery
README to use -o/--out-format flags. Update ifcmcp README to use the
installed ifcmcp command rather than python3 -m ifcmcp.
Generated with the assistance of an AI coding tool.
These three packages were added to src/ but lacked the Makefile needed
by common.mk to build distribution wheels, and the GitHub Actions
workflow to publish them to PyPI.
Adds make dist / make test / make qa targets and ci-*-pypi.yaml
workflows matching the pattern used by ifcpatch, ifcclash, etc.
IfcRelConnectsPathElements has an optional ConnectionGeometry attribute for
recording the geometric cut-plane between adjacent elements, but there was
no way to set it via the API.
Generated with the assistance of an AI coding tool.
assign_product creates IfcRelAssignsToProduct linking a structural member to
a physical building element. assign_to_building creates IfcRelServicesBuildings
linking a structural analysis model to a building. add_topology_representation
creates IfcTopologyRepresentation for structural elements, inferring the
representation type from the item class.
Generated with the assistance of an AI coding tool.
Both attributes are required by the IFC schema but were not settable via
the API function. Add physical_or_virtual and internal_or_external parameters
with "NOTDEFINED" defaults for backward compatibility. Update Bonsai boundary
panel to expose both fields in the editor.
Generated with the assistance of an AI coding tool.
Add --format ids to ifcquery to output step IDs suitable for piping into
ifcedit parameters. Add ifcedit foreach to apply an operation to every
element in a query result. Extend clash and relations output so --format ids
extracts all involved element IDs, enabling one-liners like clash detection
piped directly into render.
Generated with the assistance of an AI coding tool.
Enhances the performance of mouse intersection checks for wireframe objects.
Details:
- Calculated the intersection with the mouse in 2D pixels first.
- Converted objects to a BVH Tree to reduce the number of edges checked against the mouse position.
mcp is an optional dependency so that the embedded API (embedded.py) can
be used from Pyodide without pulling in pydantic-core and the rest of the
MCP protocol stack, which may not be available in all WASM environments.
Fix#7034
bpy.ops.bim.extend_to_underside doesn't exist - the correct operator
name is bim.extend_walls_to_underside. The AttributeError killed the
entire panel draw, hiding mirror, align, aggregation, and QTO buttons.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
If a file had an IfcProjectedCRS without an IfcCoordinateOperation (or
vice versa), add_georeferencing would return early without creating the
missing entity. This caused edit_georeferencing to crash with IndexError.
Now detects the inconsistent state, cleans up, and recreates both.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ifcmcp is a new Model Context Protocol server that wraps ifcquery and ifcedit, holding an IFC model in memory across tool calls. It is the preferred way to interact with IFC models from AI assistants and MCP-compatible clients.
Setup:
claude mcp add --transport stdio ifc -- python3 -m ifcmcp
Session tools: ifc_load, ifc_save
Query tools: ifc_summary, ifc_tree, ifc_info, ifc_select, ifc_relations, ifc_clash, ifc_validate, ifc_schedule, ifc_cost, ifc_schema, ifc_contexts, ifc_materials, ifc_plot, ifc_render, ifc_shape, ifc_shape_list, ifc_shape_docs
Edit discovery: ifc_list, ifc_docs
Edit execution: ifc_edit, ifc_quantify
The model stays in memory between calls - ifc_edit does not auto-save; call ifc_save explicitly when done.
Depends on both ifcquery and ifcedit
Generated with the assistance of an AI coding tool.
ifcedit is a new command-line tool for executing ifcopenshell.api mutations from the shell. It wraps the entire API surface — any function callable via ifcopenshell.api can be invoked without writing Python.
Subcommands:
list [module] — list all API modules, or functions within a module
docs <module.function> — full documentation (params, types, descriptions)
run <file> <module.function> [--param value ...] — execute a mutation; overwrites input file by default, or use -o <output> to write elsewhere; --dry-run validates without executing
quantify list — list available QTO rules
quantify run <file> <rule> — run quantity take-off, writing IfcElementQuantity psets back to the file
Parameter coercion: entity references can be passed as step IDs (strings); lists, dicts, booleans, and None are handled automatically.
Usage:
python3 -m ifcedit run model.ifc root.remove_product --product 42
python3 -m ifcedit docs geometry.edit_object_placement
Generated with the assistance of an AI coding tool.
ifcquery is a new command-line tool for querying and inspecting IFC models. All output is JSON.
Subcommands:
summary — schema version, entity counts, project metadata
tree — full spatial hierarchy (Project → Site → Building → Storeys → Spaces → Elements)
info <id> — deep inspection of any entity by step ID (attributes, psets, placement matrix, type, material)
select <query> — filter elements using ifcopenshell selector syntax
relations <id> — relationships for an element; --traverse up walks to IfcProject
clash <id> — geometric intersection and clearance detection
validate — schema/constraint validation; --rules adds EXPRESS checks
schedule — work schedules with nested task trees
cost — cost schedules with nested cost item trees
schema <class> — IFC class documentation from the model's schema version
plot — SVG plan drawing
render — 3D geometry rendering
contexts — geometric representation contexts
materials — material assignments
Usage:
python3 -m ifcquery <file.ifc> <subcommand> [args]
Generated with the assistance of an AI coding tool.
* Add geometry.clip_solid API
* Add geometry.clip_solid_bounded API
* Add geometry.copy_representation API
Deep-copies the named representation from a source element to a target
element.
Generated with the assistance of an AI coding tool.
* Doc clarification for api.sequence.assign_process
* Doc clarification for api.geometry.edit_object_placement
* Doc clarification for api.feature.remove_feature
* Doc clarification for api.geometry.add_wall_representation clippings normal
* regenerate_wall_representation: document BBIM_Boolean preservation requirement
Generated with the assistance of an AI coding tool.
* shape_builder: complete docstrings and return type annotations
* shape_builder: warn about mixed item types in get_representation
* shape_builder: fix half_space_solid agreement_flag docstring
Generated with the assistance of an AI coding tool.
Add tests for all four covering generation operators: flooring/ceiling
from walls and flooring/ceiling from cursor. Previously only flooring
from walls was tested.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The covering tool used bmesh as an intermediate and relied on
type.assign_type post-listeners (removed in 44a52863a) to generate
the IfcExtrudedAreaSolid body. With those listeners gone, coverings
had no body representation and assign_swept_area_outer_curve crashed.
Build covering representations from scratch using ShapeBuilder, reading
the extrusion depth from the type's IfcMaterialLayerSet. Also replace
bpy.ops.bim.assign_class with bonsai.core.root.assign_class using
should_add_representation=False, consistent with the space fix.
Refactored shared coordinate-conversion and extrusion-building logic
into get_2d_vertices_from_polygon and set_extrusion_representation_from_polygon,
used by both space and covering code paths. Removed all bmesh-dependent
dead code from the spatial tool.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Space regeneration was only updating the Blender mesh and marking the
object as edited, but the IFC representation was never synced on save.
Replace the bmesh-based approach with ShapeBuilder to write geometry
directly to IFC as an IfcExtrudedAreaSolid, then reload via
switch_representation. This applies to both new space creation and
existing space regeneration.
Also changes assign_ifcspace_class_to_obj to call
bonsai.core.root.assign_class directly with
should_add_representation=False instead of bpy.ops.bim.assign_class.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The nest assign_object API now removes existing spatial containment and
aggregate relationships before creating the nest, matching the behavior
documented in its docstring and consistent with aggregate.assign_object.
Fix#7248
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Walk up the full hierarchy via get_parent() in can_nest() and
can_aggregate() to reject assignments that would create a cycle.
Also reject self-assignment.
Fix#7248
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
After assigning an IFC class and undoing, msgbus subscriptions registered
with the old Python object wrapper survived (PERSISTENT flag) but could
not be cleared because: (1) rollback_link_element looked up objects by
their post-link name which no longer exists after undo, and (2) the
per-object clear_by_owner calls in rebuild_element_maps used new Python
wrappers that didn't match the old subscription owners.
Fix by using a dedicated stable object (object_subscription_owner) as
the msgbus owner for all per-object subscriptions, allowing
rebuild_element_maps to clear all stale subscriptions in one call
regardless of Python wrapper identity changes during undo/redo.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The `is not ...` was being captured by the walrus assignment due to
missing parentheses, causing the condition to always evaluate incorrectly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
remove_representation_item now returns early if removing the item would
leave Items empty. edit_text_literals returns early on empty attributes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
add_boolean was removing second operands from ALL IfcShapeRepresentations
that referenced them, which could corrupt unrelated shapes and leave
representations with empty Items (bug #7803).
The API no longer modifies Items — callers manage this explicitly.
validate_type and Bonsai's AddBoolean operator now handle their own
item removal scoped to the correct representation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
remove_deep is deprecated and can silently delete elements still in use.
remove_deep2 requires zero inverses before removal, making it safer.
Also fixes a double-removal bug in remove_grid_axis and prevents
removing the last prop template from a pset template.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests using custom first/last tread runs were not setting
custom_tread_lock=False, so the custom values were silently ignored
since 8f7cf76d9 introduced the lock gate in the calculation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SyntaxWarning: invalid escape sequence '\/' at line 312.
`\/` in a plain string is treated as `/` by accident; replaced with raw string r"..." to be explicit.
- `function_item`, `tags` added in df7318973
- MakeVolume added in c385b93, ignore as all other conversion settings
- moved `SeparateZUpNode` ignore to the other geom serializer settings
Mentioned in https://github.com/IfcOpenShell/IfcOpenShell/issues/7667#issuecomment-4076645173
Traceback:
```
Traceback (most recent call last):
File "\bonsai\bim\module\patch\prop.py", line 55, in get_ifcpatch_recipes
docs = ifcpatch.extract_docs(f, "Patcher", "__init__", ("src", "file", "logger", "args"))
File "\ifcpatch\__init__.py", line 168, in extract_docs
spec.loader.exec_module(submodule)
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^
File "<frozen importlib._bootstrap_external>", line 1027, in exec_module
File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
File "\ifcpatch/recipes/FixRevit2025TINs.py", line 31, in <module>
class Patcher:
...<509 lines>...
return co / self.unit_scale
File "\ifcpatch/recipes/FixRevit2025TINs.py", line 168, in Patcher
def create_edges(self, obj: bpy.types.Object) -> None:
^^^
NameError: name 'bpy' is not defined
File "\bonsai\bim\module\patch\prop.py", line 43, in get_ifcpatch_recipes
```
To fix warnings below:
```
<python-input-1>:1: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).
```
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.
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.
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.
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.
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 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.
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.
Closes#7787: Previously bim.assign_selected_as_product required exactly
2 objects. With multiple annotations referencing the same
product, users had to repeat the operation once per
annotation. Now any number of IfcAnnotations can be selected
alongside a single product object and all are assigned in
one operation and one undo step.
Generated with the assistance of an AI coding tool.
* buildingSMART Data Dictionary module: added textfield to change data dictionary url
* moved change of bsdd baseurl change to addon settings
* Receiving Psets from other dictionary sources has been made available by dynamizing the identifier_url using the client baseurl
* Remove unnecessary blank lines in prop.py
* Remove unused import of bsdd module
* Fix#7712 - global alignment controls now affects all literals
* Fix#7760 - goodbye 3x3 box alignment
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previous logic always skipped the first point. Instead, it should only
skip when actually closing a loop (i.e. >= 3 points).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Since we added more data to debug info in fcf5614 Fatal Error itself started to fail and was never displayed due some props being inaccessible during load, should be fixed now.
Possible error that were fixed:
```
File "\Blender\5.1\extensions\raw_githubusercontent_com\bonsai\__init__.py", line 328, in <module>
print(format_debug_info(get_debug_info()))
~~~~~~~~~~~~~~^^
File "\Blender\5.1\extensions\raw_githubusercontent_com\bonsai\__init__.py", line 117, in get_debug_info
if bpy.data.is_saved:
^^^^^^^^^^^^^^^^^
AttributeError: '_RestrictData' object has no attribute 'is_saved'
Traceback (most recent call last):
File "\Blender\5.1\extensions\raw_githubusercontent_com\bonsai\__init__.py", line 366, in draw
info = get_debug_info()
File "\Blender\5.1\extensions\raw_githubusercontent_com\bonsai\__init__.py", line 152, in get_debug_info
bim_props = tool.Blender.get_bim_props()
^^^^
NameError: name 'tool' is not defined. Did you mean: 'bool'?
Traceback (most recent call last):
File "\Blender\5.1\extensions\raw_githubusercontent_com\bonsai\__init__.py", line 366, in draw
info = get_debug_info()
File "\Blender\5.1\extensions\raw_githubusercontent_com\bonsai\__init__.py", line 141, in get_debug_info
import bonsai.tool as tool
File "\Blender\5.1\extensions\.local\lib\python3.13\site-packages\bonsai\__init__.py", line 355, in <module>
print(format_debug_info(get_debug_info()))
~~~~~~~~~~~~~~^^
File "\Blender\5.1\extensions\.local\lib\python3.13\site-packages\bonsai\__init__.py", line 141, in get_debug_info
import bonsai.tool as tool
File "\Blender\5.1\extensions\.local\lib\python3.13\site-packages\bonsai\tool\__init__.py", line 23, in <module>
from bonsai.tool.attribute import Attribute
File "\Blender\5.1\extensions\.local\lib\python3.13\site-packages\bonsai\tool\attribute.py", line 31, in <module>
import bonsai.bim.helper as helper
File "\Blender\5.1\extensions\.local\lib\python3.13\site-packages\bonsai\bim\__init__.py", line 28, in <module>
from . import handler, operator, prop, ui
File "\Blender\5.1\extensions\.local\lib\python3.13\site-packages\bonsai\bim\handler.py", line 36, in <module>
from bonsai.bim.module.aggregate.decorator import AggregateDecorator
File "\Blender\5.1\extensions\.local\lib\python3.13\site-packages\bonsai\bim\module\aggregate\__init__.py", line 21, in <module>
from . import operator, prop, ui
File "\Blender\5.1\extensions\.local\lib\python3.13\site-packages\bonsai\bim\module\aggregate\operator.py", line 32, in <module>
class BIM_OT_aggregate_assign_object(bpy.types.Operator, tool.Ifc.Operator):
^^^^^^^^
AttributeError: partially initialized module 'bonsai.tool' from '\Blender\5.1\extensions\.local\lib\python3.13\site-packages\bonsai\tool\__init__.py' has no attribute 'Ifc' (most likely due to a circular import)
```
Blender doesn't have it's own quick favorites manager and working with them can be not very flexible - you can add them in context menu and remove them from Quick Favorites menu. But you can't reorder them, you can't rename them and you can't even add a new button to favorites if it's not added by some addon in the UI.
Have been stumbling upon this for awhile and decided to create an experimental manager UI for this. Things it can do:
- help user create a button with any operator in Blender and properties they prefer to then save it Quick Favorites. Which seems can be very useful in Bonsai, since you can create separate buttons for all kinds of selectors expressions, class assignment or other operators.
- it can import quick favorites from user's actual current quick favorites, so they can just modify them a bit, reorder, rename and then add them again.
- Since quick favorites are not exposed to Python API in Blender, we're using a very hacky way to retrieve them from Blender and don't provide our own buttons for adding and removing quick favorites, as it may be dangerous and even more hacky in implementation. So the workflow for user is to either generate some buttons and add them to quick favorites using Manager or to import it's own quick favorites, then change them how they like, then remove quick favorites using usual quick favorites menu and then add new button one by one.
Small demo - https://files.catbox.moe/vyffp6.mp4
Refactored methods for accessing objects in linked models and added a simple operator to select object in linked model by providing guid.
A quick demo - https://files.catbox.moe/sjjw37.mp4
* Fix#7718: Fix FallDecorator label calculation for all slope annotation types
- Fix wrong dict key type in decoration.py: DecoratorData.data["fall"] is
keyed by obj.name (str) but was looked up with obj (Object), causing
object_type to always be None
- Apply obj.matrix_world transform to spline points before computing rise/run
in both decoration.py and svgwriter.py; local coordinates have Z=0 for flat
annotations, world coordinates correctly reflect elevation change
- Use hypotenuse (segment_length) instead of run as the denominator for
SLOPE_FRACTION label display
Generated with the assistance of an AI coding tool.
* docs: add BonsaiPR bleeding edge installation section
Add new section to installation.rst documenting the BonsaiPR
community build, including why it exists, how the automated
PR-merging system works, installation steps with automated
updates, manual installation, and the PR workflow for
contributors.
Generated with the assistance of an AI coding tool.
* whoops
Linking flags were missing for `MODULE` type libraries, example warning: `IfcPythonPYTHON_wrap.obj : MSIL .netmodule or module compiled with /GL found; restarting link with /LTCG; add /LTCG to the link command line to improve linker performance`
Which is useful when debugging and calling tools.ps1 directly - less thing to modify to make it work.
Also replaced `exit 0` with `return`, so it would be possible to reuse functions inside `tools.ps1`
To avoid running in a situation when some builds are using one tag and some are using another and then unstable repo script fails to find builds for some platforms.
Objects with hide_select=True could not be selected during
isolation, causing hide_view_set to incorrectly hide them.
Objects with hide_viewport=True had their H-key hide state
modified as a side effect of hide_view_clear/hide_view_set.
Both are now left unaffected by bim.activate_drawing.
Generated with the assistance of an AI coding tool.
Use EPset_Parametric.LayerSetDirection exclusively to
determine horizontal vs vertical layer rendering in type
thumbnails, rather than hardcoding IfcSlabType checks.
Also fix line drawing to use the is_horizontal flag
consistently.
Generated with the assistance of an AI coding tool.
Fix Sphinx docs: replace csv-table with list-table for formatting functions
The documentation table of formatting/query functions was not rendering
because `.. csv-table::` requires strict RFC4180 CSV escaping. The table
contains nested quotes, inch marks (e.g. `3' - 0"`), backticks, and code
examples, which cause the CSV parser in docutils to treat rows as malformed
and drop the entire directive.
Replaced the directive with `.. list-table::`, which parses reStructuredText
instead of CSV and safely supports inline code, quotes, and multi-line cells.
Also moved the examples text outside the directive block and ensured a blank
line after the table so Sphinx does not interpret following paragraphs as
table rows.
No content changes — documentation now renders correctly.
Generated with the assistance of an AI coding tool.
* Enhance AddReferenceImage operator to use file browser instead of independent popup dialogue
* Fix dimensions assertion in TestAddReferenceImage
* Remove error in return in _execute (it is not execute)
* Add IFC2X3 support to AddReferenceImage
* Adde unit="LENGTH" to the x/y properties (every length dimension everywhere in the UI is in project length units. No need to say it explicitly)
* Manually create the texture always, not just for IFC2X3
* Add poll method to AddReferenceImage operator to check for loaded IFC project
* Refactor AddReferenceImage to add representation manually following pattern in root/operator.py's bim.add_element
* Improve File explorer options between new and select from existing project Ifc Reference Images
* Refactor get_existing_reference_images to use selector for filtering image annotations
* No extra args needed after should_add_representation is False
* Doing clean=True deletes everything
* Don't manually add geometry and materials, don't call bpy.ops. Only create IFC data, then use preexisting loading functions to create geometry.
* Black formatting, also now we can start to remove this operator as it becomes obsolete
* Consolidate duplicate UV generation into Loader.load_generated_uv_map
Replace 3 identical XY-UV baking blocks (create_object IMAGE,
bm_add_image_plane, ImageScalingTool) with a single reusable
classmethod in tool.Loader.
* Fix IFC4 texture display in Solid viewport Texture mode
IFC4 IfcTextureCoordinateGenerator Mode=COORD is used, load_texture_maps
falls back to load_generated_uv_map to bake XY-UV data onto the mesh.
* Fix IFC2X3 texture display
* This looks wrong
* Remove legacy override image feature, because we now have a proper styles and texture manager
* Remove legacy override existing image element, because we now have a dedicated styles texture manager
* Remove unnecessary roundtrip to bmesh and mesh
---------
Co-authored-by: Dion Moult <dion@thinkmoult.com>
Guidelines for external contributors using AI coding tools,
covering licensing, AI disclosure requirements, PR scope,
commit style, code formatting, and testing expectations.
Generated with the assistance of an AI coding tool.
Previously, there was a dance between invoke, execute, and draw. This
can probably be resolved, but is a high-risk for undo bugs. This
simplifies the logic flow to just a traditional _invoke -> _execute.
I add a new feature test to at least make sure it does something, and
this also fixes the segfault in tool tests as it no longer requires the
launching of the file browser.
In my previous commit, I mistakenly believed that there was an API change from
snap_angle_increment to snap_angle_increment_3d
But since the feature was introduced in blender 4.2 the setting is called
snap_angle_increment_3d.
Previously it was implemented inline. This now implements it as a
tool.Blender function with tests. Also the previous tests didn't
actually run and weren't actually testing any tools despite being in a
tool tests.
IfcSectionedSurface and IfcSectionedSolidHorizontal both of CrossSectionPositions attributes which are lists of IfcAxis2PlacementLinear. The implementation of each class used its own bespoke mapping of IfcAxis2PlacementLinear, which were identical to each other and slightly different than IfcAxis2PlacementLinear. Now the two sectioned classes use the one and only mapping for IfcAxis2PlacementLinear
* Linked IFC projects enhancement (multiple links to same project file)
- Implement link management system using UUIDs as identifiers to support multiple links to the same IFC file
- Add georeferencing compatibility detection and UI display (NONE, NOT_COMPATIBLE, PARTIAL_COMPATIBLE, FULL_COMPATIBLE)
- Support for duplicate link creation with Shift+D shortcut and automatic position offset
- Add false origin and project north calculation from 3D cursor for MANUAL mode
- Only store one cache per file, regardless of the amount of links
- Prevent duplicate links based on filepath and position comparison
- Improve error handling for missing files and loading failures
- Update tests
* Remove duplicate georef UI
I try to avoid duplicate UI (especially for one that can be as
sophisticated as georef - e.g. missing is WCS) as it means double the
code, double the tests, potential user confusion. BTW the note about
vertical datum isn't quite accurate as it may be included in the CRS
definition so vertical datum is optional.
* Remove depsgraph_update_post handler for update_link_ui_on_transform as per core developer feedback
* Move get_projected_crs to geolocation module
* Refactor get_projected_crs to simplify as per core developer feedback
* Remove unused import of bonsai.tool from project module
* Use IfcDocumentInformation per linked file and IfcDocumentReference for locaiton information
* Refactor SaveBlendMetadataFile operator to remove try-except blocks and remove linked projects collections since they are recreated by bonsai
* Cleanup removing empty collection instances for linked models in metadata.blend file and call determine_georeferencing_compatibility on link reload
* Add locking mechanism for linked models and update UI to reflect lock status
* Update logic that track IFC to execute_ifc_duplicate_operator instead of having it in execute() which does not track IFC undo/redo
* Refactor link handling to use get_link_empty_handle and set_link_empty_handle methods which in turn use the standard blender-ifc integrations patters (tool.Ifc.get_object(doc_reference) and tool.Ifc.link(doc_reference, empty_handle)
* remove operator.DuplicateLink and move it to tool.Project.duplicate_link()
* Refactor link handling to use sequential identifiers (no need for STEP ID DocRef)
* Refactor IFC linking logic to handle cases without a parent IFC file loaded. Firts link flase origin becomes parent origin
* Lock should not affect selection.
This makes it consistent with grid / spatial lock, and also toggle
selectability is already implemented.
* Remove unnecessary check for loaded library as Blender seems to do this internally already
* Rename util to get_crs because in IFC4X3 you can also have geographic CRS not just projected
* Remove unnecessary call to determine_georeferencing_compatibility
This function is already always called prior to calculate_link_position
so shouldn't be called here. It's also a very expensive function: as it
currently stands, just to link a single IFC, ifcopenshell.open() is
called 3 times. This reduces it to 2.
* Store CRS as metadata for linked models, and compare metadata when indicating georeferencing compatibility
Previously, to check georeferencing compatibility, ifcopenshell.open()
was used. When linking large models, this adds considerable time and
memory usage. This instead captures the georef as standard metadata in
our .cache.json. This now reduces the ifcopenshell.open() calls back
down to only 1 as necessary (see previous commit).
* Use link index instead of link name to fetch link collection item
Link name runs into issues with name uniqueness. This is why you created
a function for "get next link ID". After this refactoring, we can no
longer worry about uniqueness and that function may be removed.
* Simplify reloadlink into just unload and reload (with cache disabled)
This function should not be responsible for editing any data.
* Remove unnecessary get_next_link_id as names no longer need uniqueness
This now frees up the name variable to track a more meaningful, human
name like IfcDocumentInformation's Name attribute.
* Rewrite get / set link_empty_handle to just use the link directly
This prevents needless logic to fetch the link and also removes issues
related to duplicate names.
* Temporarily remove logic in prop callback
Right now, pretty much all the logic is done in a prop callback. In
general logic in prop callbacks should be minimised, since it's hard to
test and easily triggered as a domino effect of another change, and may
also impact undo/redo.
* Remove code that unnecessarily removes cache
This code removes cache, which means any project unlinking an IFC auto
clears the cache for any other project which doesn't make sense, and
also breaks the ability to readd it quickly.
* Rewrite link, unlink, load, and unload IFC
There were a few issues tackled here:
- Operators that change any IFC data must use tool.Ifc.Operator and
_execute, otherwise undo/redo will break. That's one of the risks of
using prop callbacks, as it is not explicit when an IFC edit happens.
- The usage of IfcDocumentReference was not correct. The Location
should store the URL, _not_ the position. The position should be in the
Identification attribute.
- The URL was stored in IfcDocumentInformation location, which does not
work in IFC2X3. There are a few changes here to make it IFC2X3
compatible.
- Generally move logic in operators, not prop callback.
* Remove restriction around manual mode.
Users should be able to use manual mode if they want.
* Restore AUTOMATIC mode to identical behaviour to file open
This is the first step to reusing cache files agnostic of the host.
* Revert tests for a fresh start for updating tests
* Revert "test_feature - clean up .ifc.cache. files after test was executed"
This reverts commit 99ae768ddf.
* Update tests and reimplement calculations for matrix of empty handle
Previously, the empty would always be placed at the origin, unless a
"position" offset was present. This is a problem, because the "position"
is simply a local offset relative to the Blender cache! If the cache was
regenerated, the offsets would be outdated. Also, the cache appeared in
different locations depending on the false origin mode, so the offset
would mean different things to different people.
Instead, a more robust method is:
1. When you link a file, a Blender cache is generated. The Blender
origin of this cache is arbitrary! It depends on the user's false origin
mode and is purely a Blender session specific thing.
2. When you load a link, a link is _always_ loaded into the correct
location with regards to IFC global coordinates. All math is done from
the perspective of IFC.
3. If you choose to transform (move / rotate / scale!?) this link from
its correct location, that gets recorded as a 4x4 transformation matrix.
Note: I haven't implemented this properly yet.
Tests all pass, with a minor modification to the new behaviour that
false origin mode now won't affect the location it ends up in, only the
generation of the cache.
* Remove arbitrary convention around display name
Not needed anymore now that A/M/D is a detail and not significant on
actual coordinates, and also that the UUID is no longer needed.
* Simplify implementation of loading linked models when opening an IFC
* Move link matrix calculation from operator to tool for reuse
* Implement editing link location and calculation of transformation matrix
I changed my mind on the is_locked thing, since it isn't clear to the
user that locking need to be done to save changes.
* Remove old is_locked, prop update callback no longer needed (dedicated operator instead), remove old calculation code
* Simplify code related to placed_as_per_georef
* For now, simple skip for duplicate / delete
IMO duplicate / delete / move a link are very rare and explicit
operations.
* Update tests
* Remove host_model coordinate data as cache is no longer host model dependent
* Move icons outside list because there are too many
* Minor tweaks
---------
Co-authored-by: Dion Moult <dionmoult@gmail.com>
Co-authored-by: Dion Moult <dion@thinkmoult.com>
IfcOpenshell read file, and write file without changes. This round trip introduces truncation noise. It should not hurt to increase the precision to keep this clean.
Replace hardcoded 5-degree angle snapping with Blender's
snap_angle_increment setting in create_wall_from_2_points()
and create_profile_from_2_points().
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace hardcoded 5-degree angle snapping with Blender's
snap_angle_increment setting in handle_lock_axis() for:
- Initial angle rounding when locking axis (A key)
- Angle rounding and increments on Shift+Wheel scroll
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace hardcoded 5-degree angle snapping with Blender's
snap_angle_increment setting in calculate_distance_and_angle().
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This function retrieves the angle snap increment from Blender's
tool_settings.snap_angle_increment property, which was added in
Blender 4.2. This allows users to configure the angle snap value
through Blender's native UI instead of using hardcoded values.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously, sort, reverse list, and join functionality was implemented
as special cases in Bonsai itself. Given that it has usecases
(especially in material lists, but any sort of list applies) I've moved
this function into the IOS formatting language.
The IOS formatting language previously wasn't capable of this, but the
awesome addition by @falken10vdl made the formatting language accept
queries inline, so that means it can handle lists. I also added tests
for all the new functions and expression syntax (+-*/ operators).
I simplified the code that gets the evaluated text literal - previously
it seems to call format() multiple times.
Previously, copy attribution was coupled with text editing. This meant
that you couldn't just do something like change the font or alignment
without also affecting literals. Now like most apps you can just select
bunch of text and change font size etc, using the same UI look and feel
that copying attribute has when editing attributes.
This refactor also removes the need for explicit props tracking each
possible attribute to copy, and the settings collection group. Bulk
applying is now done in core with no calls to UI.
Turned out `aud` module we had in our makefile had nothing to do with Blender built-in `uad` module 🫣
So no need to install anything from PyPI since this module is generally available in Blender
This isn't complete yet, but it hopefully demonstrates a preferred
implementation:
* Logic in core, not operator
* Loop done in core, without needing to call other core functions, so
the overhead of enabling and disabling editing per object is removed. No
more Blender logic, just straight editing in IFC.
* Reuse existing function to grab text attributes instead of
reimplementing it twice.
* Remove dead code, there seems to be a function
apply_to_selected_objects which was completely unused and duplicated
code twice.
Fix issue where selected text annotations remained in editing mode after
applying changes. Now properly restores original editing state for each
selected object.
Sync children was a bit odd because it's not actually an "array
parameter" per se, just a way to regenerate. It's now an operator.
There was a deeper issue I encountered where the way arrays work is that
they duplicate the parent element. (first encountered in e51d2d )
However, the duplication code has special array handling too. To avoid
issues with this cyclical coupling the previous solution was to
reimplement object duplication (with all sorts of pitfalls that has).
Now, I've tried to decouple it further by clearing all array psets prior
to any change, and readding the pset after everything has been
regenerated.
This can be improved upon but I don't feel confident until there is more
comprehensive test coverage for the duplicate operator.
This has a few advantages:
- The collection logic is centralised
- The collection logic is configurable based on the collection mode
- The name is not hardcoded
This reimplements @theoryshaw 's commit 9adbd4 but has a few upgrades:
- Considers all parent / child relationships, not just aggregates
- Puts business logic in core where it belongs and tool code in tool
- Uses existing utils where possible like get_decomposition
- Does not use name based collection checking which is fragile
- Reuses tool.Collector
- Makes container assignment handle the API's capability to do things
in bulk instead of one by one in a loop, so it's faster
- Tests
This is a cool idea, but users have all sorts of Blender collection
strategies and I think it's a good idea for Bonsai code to just touch
Bonsai's stuff and leave everything else. Separate functionality can be
built for non-Bonsai workflows and preferrably in a more discoverable
way than in individual Bonsai features.
When joining objects with mismatched representation types, deselect and
skip incompatible objects rather than canceling the entire operation.
This allows users to join compatible objects even when the selection
includes incompatible ones.
The previous fix by @theoryshaw had the correct conclusion but had some
issues:
1. Don't implement anything that fetches IFC data in the UI draw calls.
This historically has lead to race conditions and crashes. The data
classes are much preferred.
2. Rather than load the inapplicable attribute then selectively omit it
in the UI, it's preferred to just never load it in the first place.
Reuse tool.Geometry.duplicate_ifc_objects because that's where all
duplication logic should stay instead of half reimplementing it every
time which introduces subtle bugs.
I generally like to minimise knobs and dials, so this is now part of the
wizard but now defaults to a "NONE" unit. You also now have the option
to choose "NONE" for area / volume units which makes things consistent.
Enum names also match the IFC lowercase convention for conversion based
units. This also simplifies the core logic and treats all units the same
way instead of special cases for each unit type. (length is still
special and required in Bonsai as we are inherently graphical)
- is_skipped is calculated upstream instead of reimplementing logic
- the viewer now shows cardinality (not just in edit mode) to make it
clear what the requirements are
- prohibited specs are not allowed to have any requirements, so that
section is hidden
- failed prohibited specs now shows list of failed (applicable)
entities
The report_specification() method in the Json reporter class was raising
an UnboundLocalError when processing IDS specifications with certain
minOccurs/maxOccurs combinations that weren't explicitly handled.
Problem:
The cardinality variable was only assigned for three specific cases:
- minOccurs=1, maxOccurs="unbounded" → "required"
- minOccurs=0, maxOccurs="unbounded" → "optional"
- minOccurs=0, maxOccurs=0 → "prohibited"
However, the IDS schema allows other valid combinations such as:
- minOccurs=0, maxOccurs=1 (commonly used for optional specifications)
- minOccurs=1, maxOccurs=1 (exactly one occurrence required)
- Any other valid XML Schema cardinality values
When processing IDS files with these combinations, the cardinality
variable remained unassigned, causing an UnboundLocalError at line 382
when attempting to use it in ResultsSpecification().
Solution:
Added fallback logic to handle all valid IDS cardinality combinations:
- If minOccurs >= 1: cardinality = "required" (must occur at least once)
- Otherwise (minOccurs == 0): cardinality = "optional" (may occur)
This maintains semantic compatibility with the existing codebase, which
expects cardinality to be one of the semantic strings ("required",
"optional", "prohibited") rather than numeric ranges. This is critical
for:
- HTML template rendering (line 457: .capitalize())
- Conditional logic for skipped specs (line 454)
- UI rendering for prohibited specs (line 456)
Testing:
- Tested with IDS file containing minOccurs=0 without explicit maxOccurs
(defaults to 1 per XML Schema specification)
- Validation now completes successfully without UnboundLocalError
- HTML report generation works correctly with semantic cardinality labels
- Maintains backward compatibility with existing IDS files
Fixes: Validation failure when using valid IDS cardinality combinations
* black .
* add typing
* move function
* add get_class_relations
* add test for class relation
---------
Co-authored-by: Dion Moult <dionmoult@gmail.com>
Demo - https://files.catbox.moe/extsxf.mp4
But now it requires ifcsverchok graph to be nested inside a subgroup because we need a way to indicate which graph parameters are important, so user can modify them from Parametric Geometry tab without actually explicitly opening sverchok graph.
This reverts commit 96fe9b5398.
This commit contains a logical error where hide_viewport is checked in
the if statement but hide_set() is used as the effect. This causes a
regression in tests about project visibility. `hide_viewport` is the
correct hiding setting to use, because hide_set is more ephemeral and
affected by Shift-H, Alt-H etc.
Previously, when the add occurrence modal operator was executed, on
every modal loop (i.e. every mouse movement) it would fetch the mesh
geometry to be previewed, store the verts / edges / faces in mesh
collections, then the decorator would fetch that geometry, the clear the
collections, in a loop.
I've removed the Blender collections. Instead the same strategy is used
as in ItemDecorator i.e. the mesh and verts are fetched once during
decorator installation, then on each draw call only a single vertex loop
to multiply by the transformation matrix for snapping and mouse
position.
You can test with the LOD400 model in #7566. On my machine it would
cause lag on anything with >500 faces. Now it seems to work without lag
on a 26k polygon mesh.
Although it is a very cool trick, I feel this essentially duplicates the
UI in two spots, and is an outlier in UX. I'd prefer for all IFC data
and relationships to be in one location only (the panels). I think there
are a better unified solutions (e.g. favourite bookmark panels) for
quick access for things like this.
To be consistent with all other settings, I've moved the visibility
config UI from inline into the add-on settings. This restores the
previous tab layout and no longer needs the "settings" icons to be
there. This also removes the need for a "enable UI config" checkbox.
Most of the code previously had dedicated operators to toggle booleans.
This has been removed. This new approach also means helpers aren't
needed.
Previously calculation of visibility was done on every draw (3x 10tabs x
10 collection items). The data class is intended to calculate UI data
once only which is more efficient. This also removes all helper calls
from the UI.
When assigning a container to an aggregated element, automatically promote
the operation to the root aggregate and move all nested parts to the
container's collection in the Blender outliner.
Changes:
- AssignContainer now traverses the aggregate hierarchy to find the root
aggregate when a user selects any nested part
- All parts and sub-aggregates are moved to the container's collection in
the outliner while preserving IFC aggregate relationships
- Parts remain aggregated in IFC (not directly contained), only their
Blender collection membership changes
- RefreshLinkedAggregate now also moves all parts to the correct container
collection when restoring original data
This provides a more intuitive UX - users can select any part and the entire
assembly moves together, properly organized under the spatial container.
Fixes the previous behavior where:
- Aggregated elements were skipped with a warning
- Parts weren't organized under the container in the outliner
- Aggregate nesting was broken after container assignment
- Auto-include all parts when duplicating aggregates
- Preserve nested aggregate relationships during duplication
- Select all duplicated objects for immediate moving
- Add dual-rotation support for AXIS3 slabs (IFC angle + object rotation)
- Fix profile editing to display horizontal projection for tilted slabs
- Fix AXIS2 layer slicing to use local extrusion direction for walls
- Fix ChangeExtrusionDepth to refresh geometry after depth changes
- Remove rotation lock on slabs to allow free rotation
- Fix undefined variable bug in add_slab_representation.py
This commit introduces a new BBIM_MaterialLayer property set to persist custom
material layer offset settings in IFC files, along with significant UI improvements
for material editing.
Features Added:
- New BBIM_MaterialLayer pset with properties:
- UseCustomOffset (bool): Toggle for custom offset
- CustomOffset (float): Offset value in SI units
- CustomWallReference (str): Wall reference point (EXTERIOR/CENTER/INTERIOR)
- CustomSlabReference (str): Slab reference point (TOP/MIDDLE/BOTTOM)
Tool Updates (tool.py):
- Added save_custom_offset_to_pset(): Saves custom offset from UI props to pset
- Added load_custom_offset_from_pset(): Loads custom offset from pset to UI props
- Updated get_material_layer_custom_offset(): Reads from pset when props unavailable
Operator Updates (operator.py):
- EnableEditingAssignedMaterial: Loads custom offset from pset on edit start
- EditAssignedMaterial: Saves custom offset to pset on edit completion
- Fixed KeyError for CardinalPoint in material constituent sets
Data Layer (data.py):
- Added bbim_material_layer_pset() to ObjectMaterialData for caching pset data
- Improves performance by avoiding repeated IFC queries during UI drawing
UI Improvements (ui.py):
- Added custom offset display in both editable and read-only material UIs
- Added OffsetFromReferenceLine display in read-only UI
- Implemented dynamic headers based on material type (Layers/Profiles/Constituents)
- Improved visual hierarchy with consistent boxing and indentation
- Aligned editable and read-only UI layouts for consistency
- Fixed layer set boundary labels (Top/Bottom for slabs, Interior/Exterior for walls)
- Reorganized "Add Material" section into material layers box
Bug Fixes:
- Fixed format_distance() to correctly handle negative imperial values
(e.g., -0.5' now displays as "-0' - 6"" instead of "0' - -6"")
This allows users to set custom material layer offsets that persist in the IFC
file and remain available across sessions, with clear visual feedback in both
editing and viewing modes.
When appending a wall type and a slab type in turn, if their material
layer sets have the same name then the slab type would have a wall
construction. Now the material sets are compared before reusing an
existing material set.
Fixes typo introduced in b4740b6 where `element in MATERIAL_SETS` should
have been `element.is_a() in MATERIAL_SETS`. This resulted in
deduplication of layersets, but not of the layers themselves.
Enable multiple CSS files in stylesheet_path using comma separation.
Files are loaded in order with natural CSS cascading behavior.
Example: "base.css, overrides.css"
"In some versions of Python, instances of classes may have an
__annotations__ attribute. However, this is not supported functionality.
If you need the annotations of an instance, you can use type() to access
its class" https://docs.python.org/3/howto/annotations.html
When editing representation items for elements with IfcMaterialLayerSetUsage
(LAYER2/LAYER3), the depth attribute is now hidden from the UI as it should
not be modified at the item level for these parametric elements.
The check is performed by accessing the parent element through the
representation_obj property in geometry props and checking its material
usage type.
The copy_node_graph() method checks for a "window" key in the context
override, but get_shader_editor_context() wasn't providing it. This
caused the function to return early, preventing external styles from
loading.
Updated get_shader_editor_context() to include the window when the
screen differs from the current context, following the same pattern
used in get_viewport_context().
Changed tolerance from 1e-5 to 1e-4 to account for floating-point errors
introduced by matrix transformations. Fixes section annotations being
incorrectly excluded from drawings when they should be visible.
Moves IfcSpace hiding from collection assignment to after scene
addition, allowing hide_set() to work properly once objects are
in the view layer. Fixes RuntimeError during IFC import.
When duplicating elements, skip assign_body_styles if the element's
constituent materials already have style representations. This prevents
creating redundant IfcStyledItem entities on the geometry when styles
should be inherited from the material definition.
To speed up the process. Previously we were using `/m` which build different targets in parallel, but not .cpp files. So rocksdb could have been building for 30 mins because of this.
sync_references was syncing spatial element placements FROM Blender TO IFC,
corrupting their correct positions. Spatial elements (storeys, spaces,
buildings) often have Blender objects at Z=0 for modeling convenience, but
their IFC placements store absolute positions.
Solution: Skip syncing placements for IfcSpatialElement and IfcGrid types,
as their IFC placement is the source of truth.
Fixes storey elevation corruption during SECTION_LEVEL annotation generation.
- Removed interface.rst (was added in this PR)
- Removed all PNG documentation images that were added in this PR:
- bonsai_customization1.png
- bonsai_customization2.png
- bonsai_interface.png
- bonsai_interface2.png
- bookmarks.png
- gear_tabs.png
These files were not present in the upstream v0.8.0 branch and have been removed to restore the original documentation state.
Force UI redraw to flush pending Blender operations, as Blender was crashing during bulk printing. Not 100% this fixed everything, as there are a few crashes that spring up still, but is better.
Force viewport to use scene camera before rendering underlay. When
print_all was used, viewport remained locked to local camera from
previous drawing, causing OpenGL render to capture wrong view.
Enable importing multiple .svg reference files at once using
standard Blender multi-select (Shift/Ctrl+click).
Includes backward compatibility and test coverage.
After 5d56025 we were using `LibXml2::LibXml2` instead of `LIBXML2_LIBRARIES` for linking, but this target was missing debug variants leading to issues during linking.
Added more gizmos for multi-panel windows and for the door transom.
Support negative dimension values (lining offset for door and window)
Fix railing, stair, and roof being regenerated during UI panel draw instead of on property change
Various code quality changes and DRY improvements
Major changes:
- Relocate gizmo infrastructure from bim/gizmo.py to module/drawing/gizmos.py
- Replace arrow-based property gizmos with dimension line gizmos throughout
- Add view-dependent positioning: gizmos automatically reposition based on camera angle to stay visible and avoid overlapping geometry
- Add special icons for stair to deal with edge cases
Code quality:
- Add DRY helper methods for gizmo positioning across stair, door, and window
- Remove redundant visibility logic
- Extract integer input handling to dedicated module for reuse
- Add comprehensive documentation for gizmo architecture
Add dialog to DuplicateType operator allowing users to set name, description,
and optionally assign the active object to the duplicated type. Add duplicate
button to product UI in type panel with auto-assignment enabled by default.
- You can now input values using the keyboard once you clicked on a gizmo
- Gizmos now support click > move > click in addition to drag and drop (yay carpal tunnel !)
- Optimize snapping performance
- Consolidate door and window type in model.py
- You can now cycle through window and door types using the cycle gizmo
- Pen, validate, cancel, lock, and cycle gizmos are now billboards and follow view direction
- Draggable gizmos are now billboard 2D arrows instead of 3D cones
Implement visual parameter manipulation in 3D viewport with reusable
gizmo components. Features snap-to-mesh (Ctrl), precision mode (Shift),
and real-time feedback. Includes cone gizmos for dimensions,
arc gizmo for swing direction, and icon gizmos for edit controls. Gizmos are globally are individually toggleable in the addon preferences.
May be expanded upon later to add gizmos to other paramaterized elements (window, railing, roof, stairs, array, ...).
Unfortunately gizmos can't tap into the builtin snap system or bonsai snap system which is built for modal operators so gizmos implement yet another custom rather naive snap system.
When importing spatial decomposition, get_storey_elevation() returns values in the project's unit system (e.g., feet), but format_distance() expects values in meters. Added unit_scale conversion (elevation * unit_scale) before formatting to ensure elevations display correctly regardless of project units.
Level annotations were incorrectly converting feet to meters and back,
causing values like 3ft to display as 9'10". Updated format_value() to
accept in_unit_length parameter and pass it to format_distance(), since
Blender's Z coordinates are already in project units.
- Add in_unit_length parameter to BaseDecorator.format_value()
- Set in_unit_length=True in PlanLevelDecorator.draw_labels()
- Set in_unit_length=True in SectionLevelDecorator.draw_labels()
Replaced duplicate format_distance in unit.py with comprehensive MeasureIt-ARCH version from helper.py. Fixed critical floating point errors by changing inPerFoot from 11.9999 to 12.0, eliminating spurious fractions on whole numbers. Implemented auto-precision detection to simplify fractions (64/256 → 1/4) while preserving precise values like 3/256 when needed. Enhanced imperial parsing to support flexible input formats (optional symbols, mixed fractions, leading decimals) and fixed suppress_zero_inches functionality in dimension annotations.
Files saved in previous Blender versions stored position checksums as float64
(24 bytes for location, 72 bytes for rotation), but the current code only
expected float32 format. This caused a shape mismatch error (6,) vs (3,) when
comparing checksums during save operations.
Added byte size detection in is_moved() methods to automatically handle both
old float64 and new float32 checksum formats, ensuring backward compatibility
with files from previous versions.
Fixes ValueError when saving IFC files loaded from older Blender versions.
Unexpected consequence of #7365 - previously `OPENCASCADE_LIBRARIES` supposed to be a list of libraries filepaths, but after refactor `OpenCASCADE_LIBRARIES` end up being both list of library names and list of filepaths.
And since link directories for the names was not provided, it failed to find the libraries to link.
If using OpenCASCADEconfig it wouldn't fail as cmake would evaluate library names as imported target names.
To fix it and simplify it even further, in case of manually provided paths, it now creates `OpenCASCADE_INTERFACE` target and stores it in `OpenCASCADE_LIBRARIES` - target will automatically have all the includes, library names and library dirs.
Since this if-block happens in parentheses, then all `%VAR%` are expanded at the start and then `%ERRORLEVEL%` and `%RET%` values have no relation to the actual result of `git clone`. So if user were (un)lucky, then `%RET%` would be not yet set to "0" (by the previous function call), then it would skip checking out revision.
`GitCloneOrPullRepository` had similar issue, but it was never used anywhere.
`EIgen::Eigen` target used in #7340 for linking exists only if there's a cmake config, while there are cases when there's just include directory. Added same name interface target to mimic config.
It doesn't really matter in this case - it matters really only for FindLibXml2, because `PROJECT_SOURCE_DIR` point to svgfill, when it's config executed, instead of `CMAKE_SOURCE_DIR` - so `CMAKE_SOURCE_DIR ` is never removed from the path, leading to cyclic calls. Adding for HDF5 too just for consistency.
Not sure when it was introduced, but it was still using previous dependency path and leading to confusing error:
```
Boost 1.86.0 already downloaded. Skipping.
Extracting Boost 1.86.0 into L:\Projects\Github\IfcOpenShell\_deps from boost-1.86.0-b2-nodocs.7z
An error occurred
```
Note: rv3d.perspective_matrix should be avoided in these context. Use a numpy version of np.array(window_matrix) @ np.array(view_matrix). See https://github.com/IfcOpenShell/IfcOpenShell/issues/7046
Note2: region_2d_to_origin_3d_np clamp should be used for the snap to work in orthographic view.
Add target view detection to generate_section_reference_points() to create
appropriate geometry for each view type. Plan views get horizontal lines
(clip_segment), section/elevation views get vertical lines (elevate_segment).
Added steps to set 'is_visible' to TRUE and 'is_locked' to FALSE in the 'Spatial Decomposition' panel for the 'Override paste buffer - with active IFC data' scenario. This ensures the test covers visibility and lock state handling for IFC objects.
Example error:
```
TypeError: bpy_struct: item.attr = val: enum "Default" not found in ('city.exr', 'courtyard.exr', 'forest.exr', 'interior.exr', 'night.exr', 'studio.exr', 'sunrise.exr', 'sunset.exr')
```
There was a bug in shading_styles.json where we were using `Default` for `studio_light`, which is only available for `SOLID` shading type. Changed value to `forest.exr`, added code to handle old bugged value since users already copied and possibly modified shading_styles.json
The edit_assigned_product() function now removes the annotation from all
existing IfcRelAssignsToProduct relationships instead of just one, preventing
annotations from being incorrectly assigned to multiple products simultaneously.
This fixes issues where leader lines wouldn't update correctly because the
annotation retained old product assignments.
Previously, when multiple CSS selectors were comma-separated in a rule,
only the last selector received the unique drawing ID suffix. This caused
style conflicts when multiple drawings were placed on the same sheet.
Now all selectors in comma-separated lists receive the unique suffix,
ensuring proper style isolation between drawings.
Example:
Before: .cut.Status-DEMOLISH, .cut.Option-D.d2156 { ... }
After: .cut.Status-DEMOLISH.d2156, .cut.Option-D.d2156 { ... }
In Blender 5.0 some theme attributes were removed and moved to other places and code broke.
In the commit I've also switched the code to less dynamic approach, so static type checker could caught potential errors.
`get_active_stair_calculated_params` wasn't updated when zero tread runs support was added and it's still was relying on a convention that `0.0` custom tread run = no custom tread run.
`s0 = V_(custom_first_last_tread_run[0] or tread_run, tread_rise) + td_vector` was assuming `0` means "no custom first tread run", not it means actually "zero first tread run", so could should be adjusted
before - https://files.catbox.moe/5ovqnh.mp4
after - https://files.catbox.moe/srorl2.mp4
Before f52aafd default `(0,0)` meant that there are no custom tread runs, but after the change it actually means that runs for first and last treads are 0. So default value should be adjusted.
Added explicit `None` value for clarity.
Since it's not illegal in Blender and can be helpful - e.g. when you were assigning class to ifc space, you would lose selection completely and would need to reselect object to continue working on it.
After 3aa5ddb07 `select_products` adds to current selection, instead of resetting it.
So couple tests started to fail since they create new objects and `view_layer` is not yet updated (previously `bpy.ops.object.select_all(action="DESELECT")` was also implicitly updating view layer).
```
FAILED test/tool/test_spatial.py::TestSelectProducts::test_select_products - AssertionError: assert bpy.data.objects['Object'] in []
FAILED test/tool/test_system.py::TestSelectSystemProducts::test_run - AssertionError: assert bpy.data.objects['Object'] in []
```
Long story short - since 5.0 `np.array(Vector())` is now producing `np.float32` instead of `np.float64`. So we have to provide `dtype` explicitly to support both <5.0 and >= 5.0.
See https://projects.blender.org/blender/blender/issues/149283
It's probably will be very popular bug, when someone would try to migrate to Blender 5.0 using old Bonsai.
Example traceback:
```
File "Blender\5.0\extensions\.local\lib\python3.11\site-packages\bonsai\bim\prop.py", line 34, in <module>
import bonsai.bim.schema
File "Blender\5.0\extensions\.local\lib\python3.11\site-packages\bonsai\bim\schema.py", line 23, in <module>
import bpy_restrict_state
ModuleNotFoundError: No module named 'bpy_restrict_state'
```
Noticed testing command from #7277. I believe Serializers it not actually needed to build IfcGeomServer.
Example error:
```
/usr/bin/ld: cannot find -lSerializers: No such file or directory
```
`-Wl,-undefined,suppress` have no meaning in emscripten and they are just ignored. And emscripten is ignoring undefined symbols by default without any flags.
Next to `EXPORTED_FUNCTIONS` and avoid possible issues with pyodide in the future (pyodide is using `SIDE_MODULE=1`, but currently not providing it libraries of type `MODULE`, only for shared ones).
Adding extension, but avoiding adding sources as we're not actually building.
As a result build will have a correct suffix `pyodide_2025_0_wasm32.whl` that's pyodide is currently using and this is pyodide is plan to use when it's going to release to PyPI, see https://peps.python.org/pep-0783/
Documentation claimed that ODS/XLSX output was to a given filename, but
the code actually writes files with generated names in a folder.
(also create the folder if necessary for convenience)
This also deprecates one more instance of the add_representation API
call. As this is slowly cleaned up we can move towards "regenerating"
annotations, not just generating from scratch.
* first attempt to do annotation rotation when dong bulk tags
* Enhance annotation rotation handling based on camera orientation
* handle properly S_G
* black .
* reorder property in UI
* cleanup imports
Remove validate_sheet_files() check in regenerate_sheet() that prevented
regenerating missing LAYOUT files. The validation was blocking the
exact scenario that regeneration was designed to handle.
This allows users to open a bare IFC file with configured drawings and
sheets and have the SVG layouts automatically recreated with drawings
placed at default positions.
Note: now we are using hide_viewport not hide_set anymore. There might
be pending issues from this. Also, now because we use foreach_set, we
can quickly also apply hide_render, which saves time during underlay
generation.
The issue was with ci.yml - it was using system boost shared libraries (since Boost_USE_STATIC_LIBS by default is OFF), but CGALConfig was overriding leading to compilation issues.
Text annotations can now reverse the order of list values (e.g., materials) and use custom separators instead of the default comma-space. Two new properties have been added to EPset_Annotation: Reverse_List (boolean) and List_Separator (string). When text literals contain IFC list/tuple values, they are now detected during variable replacement and can be reversed and joined with the specified separator. The list separator supports escape sequences like \n for newlines, enabling multi-line list displays. These properties are exposed in the text editing UI and properly persist to the IFC file through the new update_text_annotation_properties method, which consolidates all annotation property updates into a single efficient operation.
Not sure why it occurred only now, maybe after recent changes with shared libraries this problem just got more apparent and previously it was masked by some other library after mappings also using IfcGeom.
But the issue was that mapping were not linked against IfcGeom, though it's symbols were used in them. E.g. IfcSectionedSurface.cpp was using `has_loft` from `infra_sweep_helper`.
Issue occurred only on Linux - msvc and clang are less strict and probably do multiple passes to fetch symbols.
Example errors:
```
libgeometry_mapping_ifc4x3.a(IfcSectionedSolidHorizontal.cpp.o): In function `ifcopenshell::geometry::mapping_Ifc4x3::map_impl(Ifc4x3::IfcSectionedSolidHorizontal const*)':
IfcSectionedSolidHorizontal.cpp:(.text._ZN12ifcopenshell8geometry14mapping_Ifc4x38map_implEPKN6Ifc4x327IfcSectionedSolidHorizontalE+0x19a4): undefined reference to `ifcopenshell::geometry::make_loft(ifcopenshell::geometry::Settings const&, IfcUtil::IfcBaseClass const*, std::shared_ptr<ifcopenshell::geometry::taxonomy::function_item> const&, std::vector<ifcopenshell::geometry::cross_section, std::allocator<ifcopenshell::geometry::cross_section> >&)'
libgeometry_mapping_ifc4x3.a(IfcSectionedSurface.cpp.o): In function `ifcopenshell::geometry::mapping_Ifc4x3::map_impl(Ifc4x3::IfcSectionedSurface const*)':
IfcSectionedSurface.cpp:(.text._ZN12ifcopenshell8geometry14mapping_Ifc4x38map_implEPKN6Ifc4x319IfcSectionedSurfaceE+0x19c4): undefined reference to `ifcopenshell::geometry::make_loft(ifcopenshell::geometry::Settings const&, IfcUtil::IfcBaseClass const*, std::shared_ptr<ifcopenshell::geometry::taxonomy::function_item> const&, std::vector<ifcopenshell::geometry::cross_section, std::allocator<ifcopenshell::geometry::cross_section> >&)'
libgeometry_mapping_ifc4x3_tc1.a(IfcSectionedSolidHorizontal.cpp.o): In function `ifcopenshell::geometry::mapping_Ifc4x3_tc1::map_impl(Ifc4x3_tc1::IfcSectionedSolidHorizontal const*)':
IfcSectionedSolidHorizontal.cpp:(.text._ZN12ifcopenshell8geometry18mapping_Ifc4x3_tc18map_implEPKN10Ifc4x3_tc127IfcSectionedSolidHorizontalE+0x19a4): undefined reference to `ifcopenshell::geometry::make_loft(ifcopenshell::geometry::Settings const&, IfcUtil::IfcBaseClass const*, std::shared_ptr<ifcopenshell::geometry::taxonomy::function_item> const&, std::vector<ifcopenshell::geometry::cross_section, std::allocator<ifcopenshell::geometry::cross_section> >&)'
libgeometry_mapping_ifc4x3_tc1.a(IfcSectionedSurface.cpp.o): In function `ifcopenshell::geometry::mapping_Ifc4x3_tc1::map_impl(Ifc4x3_tc1::IfcSectionedSurface const*)':
IfcSectionedSurface.cpp:(.text._ZN12ifcopenshell8geometry18mapping_Ifc4x3_tc18map_implEPKN10Ifc4x3_tc119IfcSectionedSurfaceE+0x19c4): undefined reference to `ifcopenshell::geometry::make_loft(ifcopenshell::geometry::Settings const&, IfcUtil::IfcBaseClass const*, std::shared_ptr<ifcopenshell::geometry::taxonomy::function_item> const&, std::vector<ifcopenshell::geometry::cross_section, std::allocator<ifcopenshell::geometry::cross_section> >&)'
libgeometry_mapping_ifc4x3_add1.a(IfcSectionedSolidHorizontal.cpp.o): In function `ifcopenshell::geometry::mapping_Ifc4x3_add1::map_impl(Ifc4x3_add1::IfcSectionedSolidHorizontal const*)':
IfcSectionedSolidHorizontal.cpp:(.text._ZN12ifcopenshell8geometry19mapping_Ifc4x3_add18map_implEPKN11Ifc4x3_add127IfcSectionedSolidHorizontalE+0x19a4): undefined reference to `ifcopenshell::geometry::make_loft(ifcopenshell::geometry::Settings const&, IfcUtil::IfcBaseClass const*, std::shared_ptr<ifcopenshell::geometry::taxonomy::function_item> const&, std::vector<ifcopenshell::geometry::cross_section, std::allocator<ifcopenshell::geometry::cross_section> >&)'
libgeometry_mapping_ifc4x3_add1.a(IfcSectionedSurface.cpp.o):IfcSectionedSurface.cpp:(.text._ZN12ifcopenshell8geometry19mapping_Ifc4x3_add18map_implEPKN11Ifc4x3_add119IfcSectionedSurfaceE+0x19c4): more undefined references to `ifcopenshell::geometry::make_loft(ifcopenshell::geometry::Settings const&, IfcUtil::IfcBaseClass const*, std::shared_ptr<ifcopenshell::geometry::taxonomy::function_item> const&, std::vector<ifcopenshell::geometry::cross_section, std::allocator<ifcopenshell::geometry::cross_section> >&)' follow
collect2: error: ld returned 1 exit status
```
Otherwise it can be overlooked if you build IfcOpenShell-Python or any other target specifically, it was only built if you run build-all.py without any target arguments.
This will give you additional styling granularity when working with material layers, allowing you to target elements not just by their material name but also by their material category in your SVG styling.
cmake configs seems to be provided with the default installation, so `find_package` should do the job that `find_path` and `find_library` did previously.
Previously we were setting `HDF5_LIBRARIES` explicitly, but I'm not sure if really worked, since we never set `HDF5_INCLUDE_DIR` and user would have to provide it manually either way.
`find_package(HDF5)` will search for default paths and will set `HDF5_LIBRARIES` and `HDF5_INCLUDE_DIR` automatically.
As it was needed for more recent swig version. Bumped swig in ae771cb without knowing this, so essentially building swig with build-all.py was broken for a bit.
After version 1.13.0 it seems hdf5 stopped publishing builds on the ftp and they also stopped publishing `CMake-hdf5-*` builds.
Switching to cmake, it will also make it consistent with build-deps.cmd
| bsdd | Library to query the bSDD API | LGPL-3.0-or-later | [](https://pypi.org/project/bsdd/) |
| ifc2ca | Utility to convert IFC structural analysis models to Code_Aster | LGPL-3.0-or-later |
| ifc4d | Convert to and from IFC and project management software | LGPL-3.0-or-later | [](https://pypi.org/project/ifc4d/) |
| ifc5d | Report and optimise cost information from IFC | LGPL-3.0-or-later | [](https://pypi.org/project/ifc5d/) |
| ifcbimtester | Wrapper for Gherkin based unit testing for IFC models | LGPL-3.0-or-later |
| [bcf](https://docs.ifcopenshell.org/bcf.html) | Library to read and write BCF-XML and query OpenCDE BCF-API modules | LGPL-3.0-or-later | [](https://pypi.org/project/bcf-client/) [](https://anaconda.org/conda-forge/bcf-client) |
| [bsdd](https://docs.ifcopenshell.org/bsdd.html) | Library to query the bSDD API | LGPL-3.0-or-later | [](https://pypi.org/project/bsdd/) |
| [ifc2ca](https://docs.ifcopenshell.org/ifc2ca.html) | Utility to convert IFC structural analysis models to Code_Aster | LGPL-3.0-or-later |
| [ifc4d](https://docs.ifcopenshell.org/ifc4d.html) | Convert to and from IFC and project management software | LGPL-3.0-or-later | [](https://pypi.org/project/ifc4d/) |
| [ifc5d](https://docs.ifcopenshell.org/ifc5d.html) | Report and optimise cost information from IFC | LGPL-3.0-or-later | [](https://pypi.org/project/ifc5d/) |
| [ifcbimtester](https://docs.ifcopenshell.org/bimtester.html) | Wrapper for Gherkin based unit testing for IFC models | LGPL-3.0-or-later |
| ifcconvert | CLI app to convert IFC to many other formats | LGPL-3.0-or-later\* | [](https://docs.ifcopenshell.org/ifcconvert/installation.html) [](https://github.com/IfcOpenShell/IfcOpenShell/releases?q=ifcconvert&expanded=true)
| ifccsv | Library and CLI app to export and import schedules from IFC | LGPL-3.0-or-later | [](https://pypi.org/project/ifccsv/) |
| ifcfm | Extract IFC data for FM handover requirements | LGPL-3.0-or-later | [](https://pypi.org/project/ifcfm/) |
| ifcmax | Historic extension for IFC support in 3DS Max | LGPL-3.0-or-later\* | [](https://docs.ifcopenshell.org/ifcmax.html)
| [ifcconvert](https://docs.ifcopenshell.org/ifcconvert.html) | CLI app to convert IFC to many other formats | LGPL-3.0-or-later\* | [](https://docs.ifcopenshell.org/ifcconvert/installation.html) [](https://github.com/IfcOpenShell/IfcOpenShell/releases?q=ifcconvert&expanded=true)
| [ifccsv](https://docs.ifcopenshell.org/ifccsv.html) | Library and CLI app to export and import schedules from IFC | LGPL-3.0-or-later | [](https://pypi.org/project/ifccsv/) |
| [ifcedit](https://docs.ifcopenshell.org/ifcedit.html) | CLI wrapper for ifcopenshell.api IFC model mutation functions | LGPL-3.0-or-later | [](https://pypi.org/project/ifcedit/) |
| [ifcfm](https://docs.ifcopenshell.org/ifcfm.html) | Extract IFC data for FM handover requirements | LGPL-3.0-or-later | [](https://pypi.org/project/ifcfm/) |
| [ifcmax](https://docs.ifcopenshell.org/ifcmax.html) | Historic extension for IFC support in 3DS Max | LGPL-3.0-or-later\* | [](https://docs.ifcopenshell.org/ifcmax.html)
| [ifcmcp](https://docs.ifcopenshell.org/ifcmcp.html) | MCP server for querying and editing IFC building models | LGPL-3.0-or-later | [](https://pypi.org/project/ifcopenshell-mcp/) |
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.