Commit Graph

70 Commits

Author SHA1 Message Date
Petru Conduraru bc1fb2a88d Bonsai: add one click copy of annotations to another drawing (#8719)
* Bonsai: move annotations between drawings when reassigning their group

Assigning an IfcAnnotation to a group that represents another drawing
previously left the annotation in both drawings at once: it stayed in
its old drawing group, its Blender object stayed in the old drawing
collection, and it kept the old camera depth, so the reassignment
appeared to do nothing useful. Issue #2966 documents the seven step
manual workaround users needed instead.

The assign group operator now detects when the target group represents
a drawing (via the new tool.Drawing.get_group_drawing, the inverse of
get_drawing_group), unassigns the annotation from its previous drawing
group, moves its object into the new drawing collection, and places it
on the new drawing camera plane. The target camera is imported on
demand when it has not been loaded yet, matching the pattern used by
the activate drawing operator.

Generated with the assistance of an AI coding tool.

* Bonsai: add one click copy of annotations to another drawing (#2966)

Duplicating an annotation into a different drawing used to require a
seven step manual process: loading groups in scene properties, copying
the object, fixing its group assignment by hand, and repositioning it
onto the target camera plane. A plain Blender duplicate is not enough
because the copy keeps pointing at the same IFC entity, and the Shift D
override, while it does create a genuine new entity through
root.copy_class, leaves the duplicate in the source drawing group,
collection, and camera depth.

The new copy annotation to drawing operator packages the proven recipe
already used by duplicate drawing into one action: duplicate through
tool.Geometry.duplicate_ifc_objects, unassign the copy from the source
drawing group, assign it to the chosen target group, place it on the
target camera plane at the same world XY, and file it into the target
drawing collection. The originals are left untouched and the user's
selection is restored. The target camera is imported on demand when it
has not been loaded yet.

The operator shows a target drawing dropdown and is reachable from the
annotation tool sidebar when an annotation is selected, and from the
drawings panel. Annotations already in the target drawing are skipped
and reported.

The orchestration lives in core.drawing.copy_annotations_to_drawing
with prophecy tests covering the copy, the skip, and the camera import
branches. Verified live in headless Blender 5.1: the copy is a new
IfcAnnotation with its own GlobalId and IfcTextLiteral, both texts are
editable independently, and everything survives save and reload with
each annotation loading in its own drawing.

Generated with the assistance of an AI coding tool.
2026-07-20 09:50:14 +10:00
Andrej730 3a8619726b core.drawing: deduplicate code, fix test
Core test was trying to access actual ifc data (`ifc.get().by_type("IfcGroup")` and was failing.
2026-07-14 19:57:31 +05:00
Bruno Postle b549e65ad9 bonsai: restore descriptive name for test_copy_with_new_geometry_copied_from_the_old
The underlying bug (has_material_styles bypassing the tool layer) was
already fixed by e76455913, which added the required mock expectation
here, but left the test under its quarantine placeholder name
test_AAAAAAAAAAAA. Restore the real name now that it genuinely passes.
2026-07-04 17:38:13 +01:00
Gorgious56 006a24ef32 Refactor: rename rel -> subject in disconnect_rel dispatch
The "mep-pair-fitting" kind added in the previous commit carries an
IfcFlowFitting (the entity whose deletion disconnects the pair), not a
relationship entity, in the dispatch slot — but the slot was named ``rel``
across the function signature and every call site. Rename to ``subject``
so the parameter name reflects the uniform intent: "the entity whose
teardown effects the disconnect", regardless of whether that's a rel or
a fitting.

Sweep covers:

- core.connection.disconnect_rel signature + body
- tool.Connection.find_rels / find_rels_for_element / find_rel docstrings
- The cascade-on-delete call site in tool.Geometry.delete_ifc_object
- DisconnectElements operator in bim.module.model.wall
- All affected test kwargs and AST forward-compat docstring
- Error message: "Unknown rel kind" -> "Unknown kind"

No behaviour change.

Generated with the assistance of an AI coding tool.
2026-06-23 14:39:53 +02:00
Gorgious56 6fa984ce2b Fix MEP pair-disconnect crash and bend re-edit pen icon
Three user-facing fixes for the MEP-system gizmo surface:

1. MEP pair-disconnect no longer crashes Blender. The
   MEPSystemPathDecorator cached entity_instance references in
   _cached_walk; deleting a bridging fitting via the gizmo left a freed
   SWIG handle in the list, and the next _build_geometry pass segfaulted
   on .is_a. The cache now stores STEP integer ids and re-resolves via
   ifc_file.by_id on each draw, plus folds tool.Parametric.get_geom_generation
   into the cache key — ifcopenshell.api mutations invalidate before the
   next frame regardless of how the deletion was routed.

2. Bend re-edit pen icon stays reachable. The bend creation path
   tessellates the swept-disk body (upstream geometry-kernel workaround),
   so tool.System.has_parametric_body correctly returns False for a
   freshly-committed bend. _active_is_bend_fitting and
   GizmoMEPActions.is_eligible_object now fall back to the type's
   BBIM_Fitting pset — the same source bim.enable_bend_preview_from_bend
   reads parameters from — keeping the pen icon eligible.

3. MEP pair / per-port unjoin icons unified through bim.disconnect_elements.
   The MEP gizmo group's three unjoin icons (pair, start, end) now share
   the wall-disconnect surface: same VIEW3D_GT_wall_link_toggle icon, same
   bim.disconnect_elements operator. tool.Connection.find_rels learned a
   new "mep-pair-fitting" kind that returns the bridging fitting as the
   disconnect target; core.connection.disconnect_rel grew the matching
   dispatch arm. The old MEPUnjoinAtPort and MEPUnjoinPair operators are
   removed.

Also registered wall.GizmoPairDisconnect (previously declared but never
in the classes tuple, so dead code) for the wall+slab pair-disconnect
surface, and extracted MEP port-topology helpers (find_bridging_fitting,
is_disconnectable_fitting, neighbours_at_ports) onto tool.System so the
canonical walk has a single home.

Generated with the assistance of an AI coding tool.
2026-06-23 14:39:53 +02:00
Gorgious56 bb8681a954 Cascade connection cleanup on element delete
Deleting a slab that was connected to a wall via IfcRelConnectsElements(TOP)
left the wall holding orphan IfcBooleanResult items + a stale BBIM_Boolean
pset. The disconnect operator already runs the right cleanup; element delete
just never invoked it.

Extract the per-kind cleanup into core.connection.disconnect_rel so the
operator (bim.disconnect_elements) and a new cascade in
tool.Geometry.delete_ifc_object share one dispatch table. Adding a future
rel kind to tool.Connection.find_rels now flows into both call sites
automatically; an AST forward-compat guard enforces coverage.

Other adjustments:
- regenerate_wall_to_underside zero-slab branch now removes stale clip
  booleans instead of silently skipping, so disconnecting the last TOP
  slab also reverts the wall correctly.
- duplicate_ifc_objects (Shift+D) calls strip_underside_booleans on copied
  walls so the duplicate doesn't carry over the source's slab trim, then
  reloads the body representation when something was stripped so the
  viewport reflects the change without waiting on Shift+G.
- batch_being_deleted_ids threads through OverrideDelete so the cascade
  can suppress partner-side regenerate when both endpoints are queued for
  deletion in the same batch.

This file was generated with the assistance of an AI coding tool.
2026-06-12 11:11:07 +02:00
Gorgious56 5b79cefee2 Fix #8138: door/window container assignment no-op
Spatial.get_root_element walks aggregate / nest / filled-void /
voided-element chains and core.assign_container assigns the container
to whatever the walk returns. For an IfcDoor the filled-void hop
redirects to the IfcOpeningElement, then voided-element to the host
wall, so a user who selects a door and runs bim.assign_container ends
up targeting the wall — and silently no-ops on the door if the wall is
already in the target storey.

Per IFC4 / IFC4.3 (IfcDoor, IfcWindow): the spatial containment of a
filling is defined independently of the filling relationship. Major
exporters (Revit, ArchiCAD, Tekla, Allplan) emit independent
ContainedInStructure on doors / windows accordingly. Drop the
filled-void / voided-element hops from the walk; aggregate and nest
remain — those are true sub-part relationships where the parent
legitimately owns the container.

New TestGetRootElement in test/tool pins the new contract (filling
resolves to itself) plus the retained aggregate / nest / loose-element
paths so a future PR that re-adds either hop is caught. Two new
TestAssignContainer cases in test/core pin filling-to-self through the
core layer and per-element can_contain filtering.

Generated with the assistance of an AI coding tool.
2026-06-08 18:53:50 +02:00
Gorgious56 e764559133 Route _has_material_styles through tool.Root.has_material_styles
Pre-existing architectural smell on v0.8.0: core/root.py.copy_class
called a module-level _has_material_styles helper that did
ifcopenshell.util.element.get_materials() directly, bypassing the
Prophecy mock seam that every other branch in copy_class flowed
through. Symptom: test/core/test_root.py::TestCopyClass::
test_AAAAAAAAAAAA passed mock strings into copy_class, the helper
called .is_a() on the string, AttributeError.

Move the check to tool.Root.has_material_styles (paired with
assign_body_styles — they're called in sequence as "is there a
material style? if not, assign body style"). core/root.py now
calls root.has_material_styles(new) like every other dependency,
fixing the test failure and dropping the ifcopenshell.util.element
import that was the only consumer of the ifcopenshell import at
module load in core/root.py.

* core/tool.py: add abstract has_material_styles to Root interface.
* tool/root.py: add concrete classmethod near assign_body_styles.
* core/root.py: replace _has_material_styles helper call site with
  root.has_material_styles; drop the local helper and its import.
* test/core/test_root.py: add the new mock expectation
  root.has_material_styles("element").will_return(False) before the
  existing assign_body_styles expectation.

Generated with the assistance of an AI coding tool.
2026-06-01 10:47:57 +02:00
Gorgious56 26eef20eb5 Add wall parametric editing and gizmos
Walls gain in-viewport parametric editing matching the door/window/stair
UX: drag handles for length, height, slope (x-angle), layer baseline
cycle, plus cursor-anchored quality-of-life operators (split at cursor,
extend to cursor, extend height, rotate 90, toggle openings) and
two-object state-machine gizmos (unjoin / merge / join-corner /
extend-to-wall / extend-vertically / add-opening).

Wall enters tool.Parametric.EDIT_TYPES, so save-time auto-commit,
GizmoPreferencesWall registration, and the in-progress-edit predicates
all light up automatically through the registry plumbing landed two
commits back.

The three-layer commit model (drag -> BIMWallProperties -> bmesh
preview -> Finish -> single ifc.run) means dragging a handle through
hundreds of intermediate values produces zero extra IFC entities. A
no-op enable->finish round-trip is byte-identical. The snapshot diff
in FinishEditingWall skips unchanged params.
_commit_active_wall_edit_if_any ensures cursor-anchored operators see
committed geometry, not the draft preview box.

Also lands the `prompt_auto_commit_parametric_edits` BoolProperty on
BIM_ADDON_preferences (consumed by the auto-commit dialog landed in
the framework commit) and refactors
`draw_{door,window,stair}_gizmo_parameters` into a shared
`_draw_parametric_gizmo_parameters` helper that the new
`draw_wall_gizmo_parameters` reuses. This commit and the framework
commit are stacked - the framework commit references the BoolProperty
defined here, so they must land together.

Tests cover pure math (core/test_model.py), DimensionGizmoConfig text
formatter, GizmoWallExtendVertically.poll() preconditions, and the
refresh_post_commit cache-invalidation regression. BDD scenarios in
model.feature cover the edit triad, auto-commit on save, and the
two-object gizmos. Documentation added to creating_walls.rst.

Generated with the assistance of an AI coding tool.
2026-05-20 16:58:39 +02:00
Bruno Postle b4558f7f75 Fix ruff import ordering complaints 2026-04-09 01:04:14 +01:00
Bruno Postle ca6e950496 ifcgit: conflict report panel and dry-run merge preview
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.
2026-04-03 13:28:14 +01:00
Bruno Postle 5e784e4175 Refactor ifcgit, fix UI bugs and performance
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.
2026-04-02 00:03:03 +01:00
Andrej730 ec6c268cdb Fix type assign_type core test (44a52863a) 2026-03-18 13:15:39 +05:00
Andrej730 64003fd5ef Fix drawing update_drawing_name core test (19534e225) 2026-03-18 13:15:38 +05:00
Andrej730 58d07bace4 Fix drawing edit_text core test and tool interface (5e9f97a0c) 2026-03-18 13:15:38 +05:00
Andrej730 3b718bc58d Fix georeference core tests (b246998f6) 2026-03-18 13:15:38 +05:00
Andrej730 47ac909a81 ruff - sort imports 2026-01-30 16:05:26 +05:00
Dion Moult 53e5f84730 Fix failing core unit tests 2026-01-28 21:49:25 +11:00
Dion Moult ff35666ad9 Reimplement feature to reassign inherited containers if you select a child element
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
2026-01-28 18:00:04 +11:00
Dion Moult 35ae1e927d Fix missing model prophet in core test bootstrap 2026-01-28 17:49:15 +11:00
Dion Moult 44a52863a2 Fix #3764. WARNING: Preserve material usage attributes when switching types and refactor type regeneration API listeners
This is a dangerous commit because the effect of refactoring of the listeners is hard to know.
2026-01-26 23:30:39 +11:00
Andrej730 953c5fddc6 bonsai - sort imports 2026-01-26 17:13:18 +05:00
Andrej730 6d4eb06d89 black . 2026-01-26 17:10:03 +05:00
falken10vdl bbda8d2aff Merge pull request #7543 from falken10vdl/MEP-ports
Simplified handling of Ports in MEP
Addresses https://community.osarch.org/discussion/comment/27740#Comment_27740
2026-01-22 09:34:52 +01:00
falken10vdl 96a0e9f72d Adapt tests for create_port_at_cursor method 2026-01-13 10:07:10 +01:00
falken10vdl 81fdf63bd0 adapted to get pytest -p no:pytest-blender test/core/test_document.py working. Black formating 2026-01-10 10:44:51 +01:00
falken10 5ea66730d4 Implemented tree like structure for documents 2026-01-10 10:44:51 +01:00
Andrej730 2581c36a5f black . 2025-12-18 18:47:13 +05:00
falken10vdl f902c7a50a ui change to add or not add mass and time units 2025-12-15 13:27:20 +01:00
falken10vdl 93579b8f66 Cleanup based on core developer's feedback 2025-12-15 13:27:20 +01:00
falken10vdl 169ca806c0 Updated with core developer feedback 2025-12-15 13:27:20 +01:00
falken10vdl a4e76ed6ee Updated with core developer feedback: fixed for Tonne and added tests 2025-12-15 13:27:20 +01:00
Andrej730 a7c8c908fe Fix left out invalid mesh data blocks and fix failing geom core test (after fcee54c) 2025-11-17 16:30:28 +05:00
Andrej730 e879dac4bd Remove obsolete tests after e662308 2025-11-17 16:30:26 +05:00
Andrej730 145c629d92 Fix core geometry tests after e662308 c4d54f7 2025-11-17 16:30:26 +05:00
Andrej730 339a0606c0 Fix failing product assignment test after 5a511ee
Moved code from `core`, added a warning so we could possibly narrow down #4014 in the future.
2025-11-13 19:13:27 +05:00
Andrej730 b6f1119eaa Fix failing product assignment test after 555621c 2025-11-13 19:13:27 +05:00
Andrej730 7f7aef0e6e Fix duplicate drawing core test (8ffa6fc) 2025-11-11 19:56:56 +05:00
Andrej730 1599bc14b3 Fix core/test_system.py (5de96c9) 2025-11-03 18:33:34 +05:00
Dion Moult b68ce08811 Deprecate should_reload and is_global in switch representation as they don't do anything now.
Superseded by item editing mode, so always reload, and always global.
2025-10-06 16:57:54 +11:00
Dion Moult e662308665 Deprecate should_sync_changes_first for switching representation, since it is no longer relevant in item editing. 2025-10-06 16:19:39 +11:00
Ryan Schultz ec2d0bfa4a Add support for reversing and customizing separators in text annotation lists
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.
2025-10-01 22:44:34 -05:00
Andrej730 679fa6d876 Option to change text symbol from general text editing UI
Example - https://files.catbox.moe/kxyepa.mp4
2025-09-09 15:42:31 +05:00
Andrej730 555621ceae Avoid storing transient ui values in BIMTextProperties #4699
To avoid crashes and either way we stored the same data twice - once bim text props (and they were updated on each data refresh) and then again in data.py. Now it's going to use just data.py
2025-09-02 18:27:57 +05:00
Andrej730 3f0e30245b Fix TestSelectSimilarContainer after 553003e 2025-07-14 18:53:11 +05:00
Andrej730 b3778facda Fix core drawing tests after be65774 2025-06-24 19:08:41 +05:00
Andrej730 a968cad4cc core/tool tests for application methods 2025-06-19 19:28:34 +05:00
Andrej 02d359d0e6 Fix Ruff UP035 (also deprecated annotation symbols) 2025-06-09 18:03:19 +05:00
Andrej 7d4176d105 Fix Ruff UP006 (deprecated annotation symbols) 2025-06-09 18:03:18 +05:00
Andrej 7259dd625f Fix Ruff UP013 (convert-typed-dict-functional-to-class)
https://docs.astral.sh/ruff/rules/convert-typed-dict-functional-to-class/
2025-05-28 18:24:12 +05:00