mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 18:16:40 +00:00
Bonsai: fix clash pin drifting away when a false origin is active
ifcclash computes p1/p2 directly from the IFC file's true (SI metre) coordinates. Every other imported object gets Bonsai's false origin / georeferencing offset applied to its matrix_world on import, but the clash pin in SelectClash assigned the raw ifcclash points straight to the viewport, with no such conversion. Whenever a false origin was active, the pin landed off by the entire offset (translation and project-north rotation), which can be very large for real georeferenced projects, matching the "shows up a very long ways away" symptom in #7178. Live reproduction (synthetic IFC models, real ifcclash + real Bonsai import pipeline in headless Blender) showed the raw unit-scale hypothesis from our earlier comment on the issue does not hold: ifcclash already returns proper SI metres regardless of project unit system (feet vs mm projects gave identical, correct clash points for identical real-world geometry). The false origin/georeferencing offset was the actual cause: forcing a 50m offset moved the pin ~70m from the true intersection, and adding a 30 degree project-north rotation on top moved it ~88m away. Fix: convert ifcclash points through the same false-origin/project-north transform already used for every other displayed object (tool.Loader.apply_blender_offset_to_matrix_world), via a new tool.Clash.convert_clash_point_to_blender() helper used by SelectClash. Verified the fix brings the pin back to within the existing measurement/approximation noise floor (~0.1-0.3m) of the true intersection in both the translation-only and translation+rotation cases, and leaves the false-origin-disabled case byte-for-byte unchanged. Generated with the assistance of an AI coding tool.
This commit is contained in:
@@ -428,10 +428,10 @@ class SelectClash(bpy.types.Operator):
|
||||
|
||||
tool.Spatial.select_products(products, unhide=True)
|
||||
ClashDecorator.install(bpy.context)
|
||||
target = Vector(clash["p1"])
|
||||
target = tool.Clash.convert_clash_point_to_blender(clash["p1"])
|
||||
tool.Clash.look_at(target, target + Vector((5, 5, 5)))
|
||||
self.props.p1 = clash["p1"]
|
||||
self.props.p2 = clash["p2"]
|
||||
self.props.p1 = target
|
||||
self.props.p2 = tool.Clash.convert_clash_point_to_blender(clash["p2"])
|
||||
self.props.active_clash_text = clash["type"].title() + " " + str(round(clash["distance"] * 1000)) + "mm"
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -22,6 +22,9 @@ import json
|
||||
from typing import TYPE_CHECKING, Literal, Union
|
||||
|
||||
import bpy
|
||||
import ifcopenshell.util.geolocation
|
||||
import ifcopenshell.util.unit
|
||||
import numpy as np
|
||||
from ifcclash import ifcclash
|
||||
from ifcclash.ifcclash import ClashSource
|
||||
from mathutils import Vector
|
||||
@@ -129,6 +132,25 @@ class Clash(bonsai.core.tool.Clash):
|
||||
with open(fn) as f:
|
||||
ClashStore.clash_sets = json.load(f)
|
||||
|
||||
@classmethod
|
||||
def convert_clash_point_to_blender(cls, point: Union[list[float], tuple[float, float, float]]) -> Vector:
|
||||
"""Convert a raw ifcclash point into Bonsai's displayed viewport coordinates."""
|
||||
props = tool.Georeference.get_georeference_props()
|
||||
if not props.has_blender_offset:
|
||||
return Vector(point)
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
matrix = np.eye(4)
|
||||
matrix[:3, 3] = point
|
||||
matrix = ifcopenshell.util.geolocation.global2local(
|
||||
matrix,
|
||||
float(props.blender_offset_x) * unit_scale,
|
||||
float(props.blender_offset_y) * unit_scale,
|
||||
float(props.blender_offset_z) * unit_scale,
|
||||
float(props.blender_x_axis_abscissa),
|
||||
float(props.blender_x_axis_ordinate),
|
||||
)
|
||||
return Vector(matrix[:3, 3])
|
||||
|
||||
@classmethod
|
||||
def look_at(cls, target: Vector, location: Vector) -> None:
|
||||
camera_location = location
|
||||
|
||||
Reference in New Issue
Block a user