Fix dead duplicates and misleading import comments

Three small post-landing cleanups against the parametric framework commit:

* core/model.py had `are_axes_collinear` and `closest_endpoint_midpoint`
  each defined twice — Python silently kept the second copy, the first
  was dead code. Removed the dead copies; runtime behavior unchanged
  (the live versions were already the kept ones).
* bim/__init__.py's `_parametric_gizmo_preference_classes` docstring
  named the wrong link in the import chain (`tool.blender → bim.ifc`).
  The real chain is `tool/ifc.py` (and ~6 other tool/* modules) which
  import `from bonsai.bim.ifc import IfcStore` at module load. Updated
  docstring to cite that root cause and the architectural fix (move
  `IfcStore` out of `bim/`).
* tool/blender.py's `from bonsai.bim.ifc import IFC_CONNECTED_TYPE`
  carried a 5-line comment claiming it was "lazy" to avoid a circular
  load. The import sits inside an `if TYPE_CHECKING:` block with
  `from __future__ import annotations` — it never runs at runtime
  regardless. Comment removed; the TYPE_CHECKING guard is
  self-explanatory.

Generated with the assistance of an AI coding tool.
This commit is contained in:
Gorgious56
2026-05-20 16:25:49 +02:00
committed by Thomas Krijnen
parent fb70c64138
commit b36bdf4130
3 changed files with 12 additions and 59 deletions
+12 -5
View File
@@ -31,11 +31,18 @@ from . import handler, operator, prop, ui
def _parametric_gizmo_preference_classes() -> list[type]:
"""Deferred lookup. Importing ``bonsai.tool`` at module top would cold-start
``tool.blender`` → ``bim.ifc`` before the ``from . import handler, …`` above
has primed the ``bim.ifc`` ↔ ``bim.handler`` partial-import dance, crashing
addon registration. Resolved at classes-tuple build time below — by then the
relative imports have settled."""
"""Lazy resolution. ``bonsai.tool/__init__.py`` transitively loads
``tool/ifc.py`` (and several siblings) which import ``from bonsai.bim.ifc
import IfcStore`` at module top — that ``tool → bim`` cycle means
``bonsai.tool`` cannot be imported here before ``from . import handler, …``
above has primed the bim partial-import dance through ``handler``'s own
``import bonsai.tool``. By the time this function runs (during the
classes-tuple build below), ``handler`` has fully loaded and ``bonsai.tool``
is safely importable.
The architectural root cause is ``IfcStore`` living in ``bim/ifc.py``;
moving it to ``tool/ifc.py`` would let ``tool/`` stop reaching into ``bim/``
and eliminate the need for this indirection. Tracked separately."""
import bonsai.tool as tool
return tool.Parametric.iter_gizmo_preference_classes(ui)
-48
View File
@@ -260,54 +260,6 @@ def vertical_height_from_extrusion_depth(extrusion_depth: float, x_angle: float)
return extrusion_depth * abs(math.cos(x_angle))
def are_axes_collinear(
seg_a: tuple[tuple[float, float, float], tuple[float, float, float]],
seg_b: tuple[tuple[float, float, float], tuple[float, float, float]],
parallel_threshold: float = 0.9994,
line_tolerance: float = 0.05,
) -> bool:
"""True if both segments lie on the same infinite line in plan (X,Y).
Two conditions: their directions must be (anti-)parallel within
``parallel_threshold`` (cos ~2°), AND any endpoint of B must lie on A's
infinite line within ``line_tolerance`` (~5cm). Z is ignored — two parallel
walls at different elevations are still considered collinear."""
p1, p2 = seg_a
q1, q2 = seg_b
d1x, d1y = p2[0] - p1[0], p2[1] - p1[1]
d2x, d2y = q2[0] - q1[0], q2[1] - q1[1]
d1_len = (d1x * d1x + d1y * d1y) ** 0.5
d2_len = (d2x * d2x + d2y * d2y) ** 0.5
if d1_len < 1e-9 or d2_len < 1e-9:
return False
dot = (d1x * d2x + d1y * d2y) / (d1_len * d2_len)
if abs(dot) < parallel_threshold:
return False
# Project q1 onto the infinite line through seg_a; perpendicular distance
# from q1 to its projection tells us how far off the line B sits.
ux, uy = d1x / d1_len, d1y / d1_len
rx, ry = q1[0] - p1[0], q1[1] - p1[1]
t = rx * ux + ry * uy
proj_x = p1[0] + t * ux
proj_y = p1[1] + t * uy
perp_dist = ((q1[0] - proj_x) ** 2 + (q1[1] - proj_y) ** 2) ** 0.5
return perp_dist < line_tolerance
def closest_endpoint_midpoint(
seg_a: tuple[tuple[float, float, float], tuple[float, float, float]],
seg_b: tuple[tuple[float, float, float], tuple[float, float, float]],
) -> tuple[float, float, float]:
"""Midpoint of the closest pair of endpoints between two segments.
For walls that meet end-to-end this is the shared corner; for walls with a
small gap it is the midpoint of the gap. Either way it is the user-meaningful
"boundary" where a merge would graft the two segments together."""
pairs = ((a, b) for a in seg_a for b in seg_b)
pa, pb = min(pairs, key=lambda pair: sum((pair[0][i] - pair[1][i]) ** 2 for i in range(3)))
return ((pa[0] + pb[0]) / 2, (pa[1] + pb[1]) / 2, (pa[2] + pb[2]) / 2)
def are_axes_collinear(
seg_a: tuple[tuple[float, float, float], tuple[float, float, float]],
seg_b: tuple[tuple[float, float, float], tuple[float, float, float]],
-6
View File
@@ -62,12 +62,6 @@ if TYPE_CHECKING:
import bpy.stub_internal.rna_enums as rna_enums
from sun_position.properties import SunPosProperties
# Type-only — imported lazily to avoid a circular load when ``bim/__init__.py``
# imports ``bonsai.tool`` before ``bim.ifc`` has reached its line-43 definition
# of ``IFC_CONNECTED_TYPE`` (the chain re-enters ``bim.ifc`` through
# ``bim.handler`` and trips on a still-undefined ``IfcStore``). The file has
# ``from __future__ import annotations``, so the type hint at line 1884 is a
# deferred string and needs no runtime binding.
from bonsai.bim.ifc import IFC_CONNECTED_TYPE
from bonsai.bim.module.attribute.prop import BIMAttributeProperties
from bonsai.bim.module.constraint.prop import (