mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 17:58:20 +00:00
black .
This commit is contained in:
+163
-128
@@ -52,6 +52,7 @@ ARC_LINE_WIDTH = 0.015
|
||||
|
||||
PRECISION_MODE_MULTIPLIER = 0.1
|
||||
|
||||
|
||||
class SnapManager:
|
||||
"""Manages snap point visualization and mesh snapping."""
|
||||
|
||||
@@ -64,16 +65,14 @@ class SnapManager:
|
||||
"""Set snap point and register draw handler if needed."""
|
||||
self._snap_point = point
|
||||
if self._draw_handler is None and point is not None:
|
||||
self._draw_handler = bpy.types.SpaceView3D.draw_handler_add(
|
||||
self._draw, (), 'WINDOW', 'POST_VIEW'
|
||||
)
|
||||
self._draw_handler = bpy.types.SpaceView3D.draw_handler_add(self._draw, (), "WINDOW", "POST_VIEW")
|
||||
self._redraw_viewport()
|
||||
|
||||
def clear(self) -> None:
|
||||
"""Clear snap point and unregister handler."""
|
||||
self._snap_point = None
|
||||
if self._draw_handler is not None:
|
||||
bpy.types.SpaceView3D.draw_handler_remove(self._draw_handler, 'WINDOW')
|
||||
bpy.types.SpaceView3D.draw_handler_remove(self._draw_handler, "WINDOW")
|
||||
self._draw_handler = None
|
||||
self._redraw_viewport()
|
||||
|
||||
@@ -83,17 +82,15 @@ class SnapManager:
|
||||
return
|
||||
|
||||
if self._shader is None:
|
||||
self._shader = gpu.shader.from_builtin('UNIFORM_COLOR')
|
||||
self._shader = gpu.shader.from_builtin("UNIFORM_COLOR")
|
||||
|
||||
self._shader.bind()
|
||||
self._shader.uniform_float("color", SNAP_CIRCLE_COLOR)
|
||||
gpu.state.line_width_set(SNAP_LINE_WIDTH)
|
||||
|
||||
for plane in ('XY', 'XZ', 'YZ'):
|
||||
vertices = generate_circle_vertices(
|
||||
self._snap_point, SNAP_CIRCLE_RADIUS, SNAP_CIRCLE_SEGMENTS, plane
|
||||
)
|
||||
batch = batch_for_shader(self._shader, 'LINE_STRIP', {"pos": vertices})
|
||||
for plane in ("XY", "XZ", "YZ"):
|
||||
vertices = generate_circle_vertices(self._snap_point, SNAP_CIRCLE_RADIUS, SNAP_CIRCLE_SEGMENTS, plane)
|
||||
batch = batch_for_shader(self._shader, "LINE_STRIP", {"pos": vertices})
|
||||
batch.draw(self._shader)
|
||||
|
||||
gpu.state.line_width_set(1.0)
|
||||
@@ -102,15 +99,12 @@ class SnapManager:
|
||||
def _redraw_viewport() -> None:
|
||||
"""Force 3D viewport redraw."""
|
||||
for area in bpy.context.screen.areas:
|
||||
if area.type == 'VIEW_3D':
|
||||
if area.type == "VIEW_3D":
|
||||
area.tag_redraw()
|
||||
|
||||
@staticmethod
|
||||
def snap_to_mesh(
|
||||
location: Vector,
|
||||
context: bpy.types.Context,
|
||||
axis_vector: Vector,
|
||||
active_obj: bpy.types.Object
|
||||
location: Vector, context: bpy.types.Context, axis_vector: Vector, active_obj: bpy.types.Object
|
||||
) -> Vector:
|
||||
"""Snap a location to the nearest mesh element if snapping is enabled.
|
||||
|
||||
@@ -131,9 +125,7 @@ class SnapManager:
|
||||
snap_elements = tool_settings.snap_elements_base
|
||||
|
||||
mesh_objects = [
|
||||
obj
|
||||
for obj in context.visible_objects
|
||||
if obj.type == "MESH" and obj != active_obj and obj.visible_get()
|
||||
obj for obj in context.visible_objects if obj.type == "MESH" and obj != active_obj and obj.visible_get()
|
||||
]
|
||||
|
||||
if not mesh_objects:
|
||||
@@ -168,14 +160,14 @@ class SnapManager:
|
||||
|
||||
world_vertices = [obj.matrix_world @ v.co for v in mesh.vertices]
|
||||
|
||||
if 'VERTEX' in snap_elements:
|
||||
if "VERTEX" in snap_elements:
|
||||
for v_co in world_vertices:
|
||||
dist = (v_co - location).length
|
||||
if dist < closest_distance:
|
||||
closest_distance = dist
|
||||
closest_point = v_co
|
||||
|
||||
if 'EDGE' in snap_elements:
|
||||
if "EDGE" in snap_elements:
|
||||
for edge in mesh.edges:
|
||||
v1 = world_vertices[edge.vertices[0]]
|
||||
v2 = world_vertices[edge.vertices[1]]
|
||||
@@ -192,10 +184,8 @@ class SnapManager:
|
||||
closest_distance = dist
|
||||
closest_point = closest_on_edge
|
||||
|
||||
if 'FACE' in snap_elements:
|
||||
bvh = BVHTree.FromPolygons(
|
||||
world_vertices, [p.vertices for p in mesh.polygons]
|
||||
)
|
||||
if "FACE" in snap_elements:
|
||||
bvh = BVHTree.FromPolygons(world_vertices, [p.vertices for p in mesh.polygons])
|
||||
|
||||
nearest_loc, normal, index, dist = bvh.find_nearest(location)
|
||||
|
||||
@@ -223,19 +213,13 @@ def clear_snap_point() -> None:
|
||||
|
||||
|
||||
def snap_to_mesh(
|
||||
location: Vector,
|
||||
context: bpy.types.Context,
|
||||
axis_vector: Vector,
|
||||
active_obj: bpy.types.Object
|
||||
location: Vector, context: bpy.types.Context, axis_vector: Vector, active_obj: bpy.types.Object
|
||||
) -> Vector:
|
||||
return _snap_manager.snap_to_mesh(location, context, axis_vector, active_obj)
|
||||
|
||||
|
||||
def generate_circle_vertices(
|
||||
center: Tuple[float, float, float],
|
||||
radius: float,
|
||||
segments: int,
|
||||
plane: str = 'XY'
|
||||
center: Tuple[float, float, float], radius: float, segments: int, plane: str = "XY"
|
||||
) -> List[Tuple[float, float, float]]:
|
||||
"""Generate circle vertices in specified plane.
|
||||
|
||||
@@ -254,9 +238,9 @@ def generate_circle_vertices(
|
||||
cos_a = radius * math.cos(angle)
|
||||
sin_a = radius * math.sin(angle)
|
||||
|
||||
if plane == 'XY':
|
||||
if plane == "XY":
|
||||
vertices.append((center[0] + cos_a, center[1] + sin_a, center[2]))
|
||||
elif plane == 'XZ':
|
||||
elif plane == "XZ":
|
||||
vertices.append((center[0] + cos_a, center[1], center[2] + sin_a))
|
||||
else:
|
||||
vertices.append((center[0], center[1] + cos_a, center[2] + sin_a))
|
||||
@@ -265,10 +249,7 @@ def generate_circle_vertices(
|
||||
|
||||
|
||||
def create_quarter_circle_arc(
|
||||
radius: float = 1.0,
|
||||
segments: int = ARC_SEGMENTS,
|
||||
direction: str = "LEFT",
|
||||
line_width: float = ARC_LINE_WIDTH
|
||||
radius: float = 1.0, segments: int = ARC_SEGMENTS, direction: str = "LEFT", line_width: float = ARC_LINE_WIDTH
|
||||
) -> Tuple[Tuple[float, float, float], ...]:
|
||||
"""Create a quarter circle arc with cross-section thickness for visibility from all angles.
|
||||
|
||||
@@ -307,27 +288,35 @@ def create_quarter_circle_arc(
|
||||
if length > 0:
|
||||
px, py = -dy / length * half_width, dx / length * half_width
|
||||
|
||||
arc_triangles.extend([
|
||||
(x1 + px, y1 + py, 0.0),
|
||||
(x1 - px, y1 - py, 0.0),
|
||||
(x2 + px, y2 + py, 0.0),
|
||||
])
|
||||
arc_triangles.extend([
|
||||
(x2 + px, y2 + py, 0.0),
|
||||
(x1 - px, y1 - py, 0.0),
|
||||
(x2 - px, y2 - py, 0.0),
|
||||
])
|
||||
arc_triangles.extend(
|
||||
[
|
||||
(x1 + px, y1 + py, 0.0),
|
||||
(x1 - px, y1 - py, 0.0),
|
||||
(x2 + px, y2 + py, 0.0),
|
||||
]
|
||||
)
|
||||
arc_triangles.extend(
|
||||
[
|
||||
(x2 + px, y2 + py, 0.0),
|
||||
(x1 - px, y1 - py, 0.0),
|
||||
(x2 - px, y2 - py, 0.0),
|
||||
]
|
||||
)
|
||||
|
||||
arc_triangles.extend([
|
||||
(x1, y1, -half_width),
|
||||
(x2, y2, -half_width),
|
||||
(x1, y1, +half_width),
|
||||
])
|
||||
arc_triangles.extend([
|
||||
(x1, y1, +half_width),
|
||||
(x2, y2, -half_width),
|
||||
(x2, y2, +half_width),
|
||||
])
|
||||
arc_triangles.extend(
|
||||
[
|
||||
(x1, y1, -half_width),
|
||||
(x2, y2, -half_width),
|
||||
(x1, y1, +half_width),
|
||||
]
|
||||
)
|
||||
arc_triangles.extend(
|
||||
[
|
||||
(x1, y1, +half_width),
|
||||
(x2, y2, -half_width),
|
||||
(x2, y2, +half_width),
|
||||
]
|
||||
)
|
||||
|
||||
return tuple(arc_triangles)
|
||||
|
||||
@@ -387,8 +376,10 @@ class GizmoMovable(bpy.types.Gizmo):
|
||||
axis_direction = self.get_axis_direction()
|
||||
|
||||
result = intersect_line_line(
|
||||
view_origin, view_origin + view_direction * 1000,
|
||||
self.start_location, self.start_location + axis_direction * 1000
|
||||
view_origin,
|
||||
view_origin + view_direction * 1000,
|
||||
self.start_location,
|
||||
self.start_location + axis_direction * 1000,
|
||||
)
|
||||
current_3d = result[1] if result else self.start_location
|
||||
|
||||
@@ -414,13 +405,7 @@ class GizmoMovable(bpy.types.Gizmo):
|
||||
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
def _update_header(
|
||||
self,
|
||||
context: bpy.types.Context,
|
||||
value: float,
|
||||
is_snapping: bool,
|
||||
is_precision: bool
|
||||
) -> None:
|
||||
def _update_header(self, context: bpy.types.Context, value: float, is_snapping: bool, is_precision: bool) -> None:
|
||||
header_text = f"Value: {value:.3f}m"
|
||||
hints = []
|
||||
if is_snapping:
|
||||
@@ -446,25 +431,57 @@ class GizmoLock(bpy.types.Gizmo):
|
||||
)
|
||||
|
||||
tris_closed = (
|
||||
(0.16803650558, 0.18791499734, 0.0), (-0.07805634290, 0.18791499734, 0.0), (0.16803650558, 0.44701099396, 0.0),
|
||||
(0.16803650558, 0.44701099396, 0.0), (-0.07805634290, 0.18791499734, 0.0), (-0.07805634290, 0.44701099396, 0.0),
|
||||
(0.20165449381, 0.13603900373, 0.0), (-0.11167433113, 0.13603900373, 0.0), (0.20165449381, -0.44701099396, 0.0),
|
||||
(0.20165449381, -0.44701099396, 0.0), (-0.11167433113, 0.13603900373, 0.0), (-0.11167433113, -0.44701099396, 0.0),
|
||||
(-0.07805634290, 0.18791499734, 0.0), (-0.39353451133, 0.18791499734, 0.0), (-0.07805634290, 0.44701099396, 0.0),
|
||||
(-0.07805634290, 0.44701099396, 0.0), (-0.39353451133, 0.18791499734, 0.0), (-0.39353451133, 0.30746498704, 0.0),
|
||||
(-0.44701099396, 0.18791499734, 0.0), (-0.44701099396, -0.04477182776, 0.0), (-0.39353451133, 0.18791499734, 0.0),
|
||||
(-0.39353451133, 0.18791499734, 0.0), (-0.44701099396, -0.04477182776, 0.0), (-0.39353451133, -0.04477182776, 0.0),
|
||||
(0.16803650558, 0.18791499734, 0.0),
|
||||
(-0.07805634290, 0.18791499734, 0.0),
|
||||
(0.16803650558, 0.44701099396, 0.0),
|
||||
(0.16803650558, 0.44701099396, 0.0),
|
||||
(-0.07805634290, 0.18791499734, 0.0),
|
||||
(-0.07805634290, 0.44701099396, 0.0),
|
||||
(0.20165449381, 0.13603900373, 0.0),
|
||||
(-0.11167433113, 0.13603900373, 0.0),
|
||||
(0.20165449381, -0.44701099396, 0.0),
|
||||
(0.20165449381, -0.44701099396, 0.0),
|
||||
(-0.11167433113, 0.13603900373, 0.0),
|
||||
(-0.11167433113, -0.44701099396, 0.0),
|
||||
(-0.07805634290, 0.18791499734, 0.0),
|
||||
(-0.39353451133, 0.18791499734, 0.0),
|
||||
(-0.07805634290, 0.44701099396, 0.0),
|
||||
(-0.07805634290, 0.44701099396, 0.0),
|
||||
(-0.39353451133, 0.18791499734, 0.0),
|
||||
(-0.39353451133, 0.30746498704, 0.0),
|
||||
(-0.44701099396, 0.18791499734, 0.0),
|
||||
(-0.44701099396, -0.04477182776, 0.0),
|
||||
(-0.39353451133, 0.18791499734, 0.0),
|
||||
(-0.39353451133, 0.18791499734, 0.0),
|
||||
(-0.44701099396, -0.04477182776, 0.0),
|
||||
(-0.39353451133, -0.04477182776, 0.0),
|
||||
)
|
||||
|
||||
tris_open = (
|
||||
(0.16803650558, 0.18791499734, 0.0), (-0.07805634290, 0.18791499734, 0.0), (0.16803650558, 0.44701099396, 0.0),
|
||||
(0.16803650558, 0.44701099396, 0.0), (-0.07805634290, 0.18791499734, 0.0), (-0.07805634290, 0.44701099396, 0.0),
|
||||
(0.20165449381, 0.13603900373, 0.0), (-0.11167433113, 0.13603900373, 0.0), (0.20165449381, -0.44701099396, 0.0),
|
||||
(0.20165449381, -0.44701099396, 0.0), (-0.11167433113, 0.13603900373, 0.0), (-0.11167433113, -0.44701099396, 0.0),
|
||||
(0.16803650558, 0.44701099396, 0.0), (-0.07805634290, 0.44701099396, 0.0), (0.16803650558, 0.70610702038, 0.0),
|
||||
(0.16803650558, 0.70610702038, 0.0), (-0.07805634290, 0.44701099396, 0.0), (-0.07805634290, 0.58656096458, 0.0),
|
||||
(-0.11167433113, 0.44701099396, 0.0), (-0.11167433113, 0.73432201147, 0.0), (-0.07805634290, 0.44701099396, 0.0),
|
||||
(-0.07805634290, 0.44701099396, 0.0), (-0.11167433113, 0.73432201147, 0.0), (-0.07805634290, 0.73432201147, 0.0),
|
||||
(0.16803650558, 0.18791499734, 0.0),
|
||||
(-0.07805634290, 0.18791499734, 0.0),
|
||||
(0.16803650558, 0.44701099396, 0.0),
|
||||
(0.16803650558, 0.44701099396, 0.0),
|
||||
(-0.07805634290, 0.18791499734, 0.0),
|
||||
(-0.07805634290, 0.44701099396, 0.0),
|
||||
(0.20165449381, 0.13603900373, 0.0),
|
||||
(-0.11167433113, 0.13603900373, 0.0),
|
||||
(0.20165449381, -0.44701099396, 0.0),
|
||||
(0.20165449381, -0.44701099396, 0.0),
|
||||
(-0.11167433113, 0.13603900373, 0.0),
|
||||
(-0.11167433113, -0.44701099396, 0.0),
|
||||
(0.16803650558, 0.44701099396, 0.0),
|
||||
(-0.07805634290, 0.44701099396, 0.0),
|
||||
(0.16803650558, 0.70610702038, 0.0),
|
||||
(0.16803650558, 0.70610702038, 0.0),
|
||||
(-0.07805634290, 0.44701099396, 0.0),
|
||||
(-0.07805634290, 0.58656096458, 0.0),
|
||||
(-0.11167433113, 0.44701099396, 0.0),
|
||||
(-0.11167433113, 0.73432201147, 0.0),
|
||||
(-0.07805634290, 0.44701099396, 0.0),
|
||||
(-0.07805634290, 0.44701099396, 0.0),
|
||||
(-0.11167433113, 0.73432201147, 0.0),
|
||||
(-0.07805634290, 0.73432201147, 0.0),
|
||||
)
|
||||
|
||||
def get_custom_shape(self, context: bpy.types.Context):
|
||||
@@ -656,40 +673,52 @@ class GizmoArrow(GizmoMovable):
|
||||
"""Generate arrow geometry along +X axis."""
|
||||
triangles = []
|
||||
|
||||
triangles.extend([
|
||||
(0, -ARROW_WIDTH, 0),
|
||||
(ARROW_SHAFT_LENGTH, -ARROW_WIDTH, 0),
|
||||
(0, +ARROW_WIDTH, 0),
|
||||
])
|
||||
triangles.extend([
|
||||
(0, +ARROW_WIDTH, 0),
|
||||
(ARROW_SHAFT_LENGTH, -ARROW_WIDTH, 0),
|
||||
(ARROW_SHAFT_LENGTH, +ARROW_WIDTH, 0),
|
||||
])
|
||||
triangles.extend(
|
||||
[
|
||||
(0, -ARROW_WIDTH, 0),
|
||||
(ARROW_SHAFT_LENGTH, -ARROW_WIDTH, 0),
|
||||
(0, +ARROW_WIDTH, 0),
|
||||
]
|
||||
)
|
||||
triangles.extend(
|
||||
[
|
||||
(0, +ARROW_WIDTH, 0),
|
||||
(ARROW_SHAFT_LENGTH, -ARROW_WIDTH, 0),
|
||||
(ARROW_SHAFT_LENGTH, +ARROW_WIDTH, 0),
|
||||
]
|
||||
)
|
||||
|
||||
triangles.extend([
|
||||
(0, 0, -ARROW_WIDTH),
|
||||
(ARROW_SHAFT_LENGTH, 0, -ARROW_WIDTH),
|
||||
(0, 0, +ARROW_WIDTH),
|
||||
])
|
||||
triangles.extend([
|
||||
(0, 0, +ARROW_WIDTH),
|
||||
(ARROW_SHAFT_LENGTH, 0, -ARROW_WIDTH),
|
||||
(ARROW_SHAFT_LENGTH, 0, +ARROW_WIDTH),
|
||||
])
|
||||
triangles.extend(
|
||||
[
|
||||
(0, 0, -ARROW_WIDTH),
|
||||
(ARROW_SHAFT_LENGTH, 0, -ARROW_WIDTH),
|
||||
(0, 0, +ARROW_WIDTH),
|
||||
]
|
||||
)
|
||||
triangles.extend(
|
||||
[
|
||||
(0, 0, +ARROW_WIDTH),
|
||||
(ARROW_SHAFT_LENGTH, 0, -ARROW_WIDTH),
|
||||
(ARROW_SHAFT_LENGTH, 0, +ARROW_WIDTH),
|
||||
]
|
||||
)
|
||||
|
||||
head_width = ARROW_WIDTH * ARROW_HEAD_WIDTH_MULTIPLIER
|
||||
triangles.extend([
|
||||
(ARROW_SHAFT_LENGTH, -head_width, 0),
|
||||
(ARROW_SHAFT_LENGTH + ARROW_HEAD_LENGTH, 0, 0),
|
||||
(ARROW_SHAFT_LENGTH, +head_width, 0),
|
||||
])
|
||||
triangles.extend(
|
||||
[
|
||||
(ARROW_SHAFT_LENGTH, -head_width, 0),
|
||||
(ARROW_SHAFT_LENGTH + ARROW_HEAD_LENGTH, 0, 0),
|
||||
(ARROW_SHAFT_LENGTH, +head_width, 0),
|
||||
]
|
||||
)
|
||||
|
||||
triangles.extend([
|
||||
(ARROW_SHAFT_LENGTH, 0, -head_width),
|
||||
(ARROW_SHAFT_LENGTH + ARROW_HEAD_LENGTH, 0, 0),
|
||||
(ARROW_SHAFT_LENGTH, 0, +head_width),
|
||||
])
|
||||
triangles.extend(
|
||||
[
|
||||
(ARROW_SHAFT_LENGTH, 0, -head_width),
|
||||
(ARROW_SHAFT_LENGTH + ARROW_HEAD_LENGTH, 0, 0),
|
||||
(ARROW_SHAFT_LENGTH, 0, +head_width),
|
||||
]
|
||||
)
|
||||
|
||||
for i in range(ARROW_CIRCLE_SEGMENTS):
|
||||
angle1 = (2 * math.pi * i) / ARROW_CIRCLE_SEGMENTS
|
||||
@@ -700,11 +729,13 @@ class GizmoArrow(GizmoMovable):
|
||||
y2 = head_width * math.cos(angle2)
|
||||
z2 = head_width * math.sin(angle2)
|
||||
|
||||
triangles.extend([
|
||||
(ARROW_SHAFT_LENGTH, 0, 0),
|
||||
(ARROW_SHAFT_LENGTH, y1, z1),
|
||||
(ARROW_SHAFT_LENGTH, y2, z2),
|
||||
])
|
||||
triangles.extend(
|
||||
[
|
||||
(ARROW_SHAFT_LENGTH, 0, 0),
|
||||
(ARROW_SHAFT_LENGTH, y1, z1),
|
||||
(ARROW_SHAFT_LENGTH, y2, z2),
|
||||
]
|
||||
)
|
||||
|
||||
return tuple(triangles)
|
||||
|
||||
@@ -746,17 +777,21 @@ class GizmoCone(GizmoMovable):
|
||||
y2 = CONE_RADIUS * math.cos(angle2)
|
||||
z2 = CONE_RADIUS * math.sin(angle2)
|
||||
|
||||
triangles.extend([
|
||||
(cone_tip_x, 0, 0),
|
||||
(0, y1, z1),
|
||||
(0, y2, z2),
|
||||
])
|
||||
triangles.extend(
|
||||
[
|
||||
(cone_tip_x, 0, 0),
|
||||
(0, y1, z1),
|
||||
(0, y2, z2),
|
||||
]
|
||||
)
|
||||
|
||||
triangles.extend([
|
||||
(0, 0, 0),
|
||||
(0, y2, z2),
|
||||
(0, y1, z1),
|
||||
])
|
||||
triangles.extend(
|
||||
[
|
||||
(0, 0, 0),
|
||||
(0, y2, z2),
|
||||
(0, y1, z1),
|
||||
]
|
||||
)
|
||||
|
||||
return tuple(triangles)
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ class BIM_OT_aggregate_unassign_object(bpy.types.Operator, tool.Ifc.Operator):
|
||||
# Skip spatial elements - they should not be deleted even if empty
|
||||
if aggregate.is_a("IfcSpatialElement"):
|
||||
continue
|
||||
|
||||
|
||||
related_objects = ifcopenshell.util.element.get_parts(aggregate)
|
||||
if len(related_objects) == 0:
|
||||
aggregate_name = aggregate.Name or f"{aggregate.is_a()} #{aggregate.id()}"
|
||||
|
||||
@@ -745,10 +745,10 @@ class DimensionDecorator(BaseDecorator):
|
||||
if not show_description_only:
|
||||
length = (v1 - v0).length
|
||||
text = self.format_value(
|
||||
context,
|
||||
length,
|
||||
context,
|
||||
length,
|
||||
suppress_zero_inches=dimension_data["suppress_zero_inches"],
|
||||
custom_unit=dimension_data["custom_unit"]
|
||||
custom_unit=dimension_data["custom_unit"],
|
||||
)
|
||||
if isinstance(self, DiameterDecorator):
|
||||
text = "D" + text
|
||||
@@ -1203,11 +1203,11 @@ class PlanLevelDecorator(BaseDecorator):
|
||||
def get_text():
|
||||
abs_z = verts[0].z
|
||||
z = helper.get_relative_z(obj, element, abs_z)
|
||||
|
||||
|
||||
# Z is in meters (Blender world space), convert to project units (feet)
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
z = z / unit_scale # Convert meters to feet
|
||||
|
||||
|
||||
rl = self.format_value(context, z, in_unit_length=True)
|
||||
text = "{}{}".format("" if z < 0 else "+", rl)
|
||||
return text
|
||||
@@ -1284,7 +1284,7 @@ class SectionLevelDecorator(BaseDecorator):
|
||||
# Z is in meters (Blender world space), convert to project units (feet)
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
z = z / unit_scale # Convert meters to feet
|
||||
|
||||
|
||||
rl = self.format_value(context, z, in_unit_length=True)
|
||||
text = "RL {}{}".format("" if z < 0 else "+", rl)
|
||||
return text
|
||||
@@ -1300,6 +1300,7 @@ class SectionLevelDecorator(BaseDecorator):
|
||||
)
|
||||
break # support only 1 label
|
||||
|
||||
|
||||
class BreakDecorator(BaseDecorator):
|
||||
"""Decorator for breakline objects
|
||||
- first edge of a mesh with zigzag thingy in the middle
|
||||
|
||||
@@ -121,11 +121,12 @@ class BoundingBox:
|
||||
retVal = True
|
||||
return retVal
|
||||
|
||||
|
||||
def find_best_precision(fractional_inches, max_precision=256, base_tolerance=0.0001):
|
||||
"""
|
||||
Find the simplest fraction denominator that accurately represents the value.
|
||||
Uses a sliding tolerance - smaller denominators get more tolerance.
|
||||
|
||||
|
||||
:param fractional_inches: The fractional part of inches (0.0 to 1.0)
|
||||
:param max_precision: Maximum denominator to try (256 for imperial)
|
||||
:param base_tolerance: Base tolerance in inches (very strict)
|
||||
@@ -133,29 +134,29 @@ def find_best_precision(fractional_inches, max_precision=256, base_tolerance=0.0
|
||||
"""
|
||||
if abs(fractional_inches) < 0.00001:
|
||||
return 1 # No fraction needed
|
||||
|
||||
|
||||
# Try denominators from coarsest to finest: 2, 4, 8, 16, 32, 64, 128, 256
|
||||
for exp in range(1, 9): # 2^1 to 2^8
|
||||
denom = 2 ** exp
|
||||
denom = 2**exp
|
||||
if denom > max_precision:
|
||||
break
|
||||
|
||||
|
||||
# Find nearest numerator for this denominator
|
||||
numer = round(fractional_inches * denom)
|
||||
|
||||
|
||||
# Skip if numerator is 0
|
||||
if numer == 0:
|
||||
continue
|
||||
|
||||
|
||||
# Check if this fraction is close enough
|
||||
fraction_value = numer / denom
|
||||
error = abs(fraction_value - fractional_inches)
|
||||
|
||||
|
||||
# Very strict tolerance - only simplify if it's a near-perfect match
|
||||
# This keeps 3/256 as 3/256, but allows floating point errors to be cleaned up
|
||||
if error < base_tolerance:
|
||||
return denom
|
||||
|
||||
|
||||
# If no simpler fraction works, use max precision
|
||||
return max_precision
|
||||
|
||||
@@ -233,11 +234,10 @@ def format_distance(
|
||||
if isArea:
|
||||
toInches = 1550
|
||||
inPerFoot = 144
|
||||
|
||||
|
||||
decInches = value * toInches
|
||||
decFeet = decInches / 12
|
||||
|
||||
|
||||
if not precision:
|
||||
precision = 256
|
||||
elif precision == "1":
|
||||
@@ -258,10 +258,10 @@ def format_distance(
|
||||
else:
|
||||
feet = 0
|
||||
|
||||
# Separate Fractional Inches
|
||||
# Separate Fractional Inches
|
||||
decInches = abs(decInches) # ignore the sign for inches
|
||||
inches = math.floor(decInches) # remove decimal
|
||||
|
||||
|
||||
# Clean up floating point errors
|
||||
fractional_inches = decInches - inches
|
||||
tolerance = 0.01 # About 1/100 of an inch
|
||||
@@ -280,11 +280,11 @@ def format_distance(
|
||||
else:
|
||||
frac = round(base * fractional_inches)
|
||||
|
||||
|
||||
# Set proper numerator and denominator
|
||||
if frac != base:
|
||||
# Simplify using GCD
|
||||
from math import gcd
|
||||
|
||||
divisor = gcd(int(frac), int(base))
|
||||
frac = int(frac / divisor)
|
||||
base = int(base / divisor)
|
||||
@@ -312,14 +312,14 @@ def format_distance(
|
||||
tx_dist += str(feet) + "'"
|
||||
if not feet and not add_inches:
|
||||
tx_dist += str(feet) + "'"
|
||||
|
||||
|
||||
# Add "0' - " when we have inches but no feet
|
||||
# But only add " - " separator if we actually have inches to show
|
||||
if not feet and add_inches:
|
||||
tx_dist += "0' - "
|
||||
elif feet and add_inches:
|
||||
tx_dist += " - "
|
||||
|
||||
|
||||
if not feet and value < 0:
|
||||
tx_dist += "-"
|
||||
if add_inches:
|
||||
@@ -341,13 +341,11 @@ def format_distance(
|
||||
# Only add inch symbol if we actually added inch content
|
||||
if inches > 0 or frac > 0 or feet == 0:
|
||||
tx_dist += '"'
|
||||
|
||||
|
||||
|
||||
if precision == "12" and unit_system == "IMPERIAL":
|
||||
tx_dist = str(round(decFeet)) + "'"
|
||||
if tx_dist == '"':
|
||||
tx_dist = "0' - 0\""
|
||||
tx_dist = "0' - 0\""
|
||||
else:
|
||||
fmt = "%1.3f"
|
||||
sq_feet = round(value * toInches / inPerFoot, 4)
|
||||
|
||||
@@ -731,6 +731,7 @@ class GizmoDoorEdition(bpy.types.GizmoGroup):
|
||||
return cls.COLOR_GREEN
|
||||
else:
|
||||
return cls.COLOR_BLUE
|
||||
|
||||
gizmo_props = [
|
||||
{"attr_name": "overall_height", "axis": (0, 0, 1)},
|
||||
{"attr_name": "overall_width", "axis": (1, 0, 0)},
|
||||
|
||||
@@ -777,9 +777,7 @@ def draw_stair_properties(layout: bpy.types.UILayout, props: bpy.types.PropertyG
|
||||
if prop_name == "custom_first_last_tread_run":
|
||||
# Draw the lock toggle
|
||||
row_lock = layout.row(align=True)
|
||||
lock_text = (
|
||||
"Lock First/Last Treads" if not props.custom_tread_lock else "Unlock First/Last Treads"
|
||||
)
|
||||
lock_text = "Lock First/Last Treads" if not props.custom_tread_lock else "Unlock First/Last Treads"
|
||||
row_lock.prop(
|
||||
props,
|
||||
"custom_tread_lock",
|
||||
|
||||
@@ -1625,11 +1625,11 @@ class Drawing(bonsai.core.tool.Drawing):
|
||||
|
||||
xmin, xmax, ymin, ymax = helper.ortho_view_frame(camera.data)[:4]
|
||||
rl = ifcopenshell.util.placement.get_local_placement(storey.ObjectPlacement)[2][3]
|
||||
|
||||
|
||||
# Convert RL from project units (feet) to meters for Blender world space
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
rl_meters = rl * unit_scale
|
||||
|
||||
|
||||
y = (camera.matrix_world.inverted() @ Vector((0.0, 0.0, rl_meters))).y
|
||||
if y < ymin or y > ymax:
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user