This commit is contained in:
Andrej730
2025-01-16 16:58:40 +05:00
parent 2859e9632e
commit 6fb0f5e63a
2 changed files with 36 additions and 22 deletions
+27 -15
View File
@@ -45,7 +45,7 @@ from bpy.types import SpaceView3D
from bpy.props import FloatProperty
from bpy_extras.object_utils import AddObjectHelper, object_data_add
from gpu_extras.batch import batch_for_shader
from typing import Union, Optional, Any, cast
from typing import Union, Optional, Any, cast, Sequence
class AddFilledOpening(bpy.types.Operator, tool.Ifc.Operator):
@@ -63,19 +63,21 @@ class AddFilledOpening(bpy.types.Operator, tool.Ifc.Operator):
class FilledOpeningGenerator:
def generate(
self,
filling_obj: Union[bpy.types.Object, None],
voided_obj: Union[bpy.types.Object, None],
filling_obj: bpy.types.Object,
voided_obj: bpy.types.Object,
target: Optional[Vector] = None,
) -> None:
) -> Union[None, str]:
"""
:param target: Target opening position. If ommited, cursor position is used.
:return: None if there was no errors, otherwise returns a string with error message.
"""
props = bpy.context.scene.BIMModelProperties
opening_thickness_si = 0.0
filling = tool.Ifc.get_entity(filling_obj)
element = tool.Ifc.get_entity(voided_obj)
if not voided_obj or not filling_obj:
return
assert filling and element
if filling.FillsVoids:
ifcopenshell.api.run(
"void.remove_opening", tool.Ifc.get(), opening=filling.FillsVoids[0].RelatingOpeningElement
@@ -94,7 +96,7 @@ class FilledOpeningGenerator:
target = filling_obj.matrix_world.translation.copy()
raycast = voided_obj.closest_point_on_mesh(voided_obj.matrix_world.inverted() @ target, distance=0.5)
if not raycast[0]:
return
return "TARGET is too far away from the voided object's mesh."
# In this prototype, we assume openings are only added to axis-based elements
layers = tool.Model.get_material_layer_parameters(element)
@@ -121,6 +123,8 @@ class FilledOpeningGenerator:
new_matrix.translation.xyz = voided_obj.matrix_world @ local_position_on_voided_obj
rotation_matrix = Matrix.Rotation(radians(-90), 4, "X")
new_matrix @= rotation_matrix
else:
assert False, f"Unexpected layer set direction: {layers['layer_set_direction']}"
filling_obj.matrix_world = new_matrix
bpy.context.view_layer.update()
@@ -149,6 +153,7 @@ class FilledOpeningGenerator:
representation = ifcopenshell.util.representation.get_representation(
existing_opening_occurrence, "Model", "Body", "MODEL_VIEW"
)
assert representation
representation = ifcopenshell.util.representation.resolve_representation(representation)
else:
representation = self.generate_opening_from_filling(
@@ -175,8 +180,10 @@ class FilledOpeningGenerator:
for voided_obj in voided_objs:
if voided_obj.data:
voided_element = tool.Ifc.get_entity(voided_obj)
assert voided_element
context = tool.Geometry.get_active_representation_context(voided_obj)
representation = tool.Geometry.get_representation_by_context(voided_element, context)
assert representation
bonsai.core.geometry.switch_representation(
tool.Ifc,
@@ -273,11 +280,12 @@ class FilledOpeningGenerator:
)
filling_obj = tool.Ifc.get_object(filling_type)
context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW")
assert context
if profile:
profile = ifcopenshell.util.representation.resolve_representation(profile)
def get_curve_2d_from_3d(profile):
def get_curve_2d_from_3d(profile: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance:
if len(profile.Items) == 1:
curve_3d = profile.Items[0]
if tool.Ifc.get_schema() == "IFC2X3":
@@ -944,7 +952,7 @@ class UpdateOpeningsFocus(Operator, tool.Ifc.Operator):
return {"FINISHED"}
def hide_openings(context, objects):
def hide_openings(context: bpy.types.Context, objects: Sequence[bpy.types.Object]) -> None:
objects_to_remove = set()
for opening_prop in context.scene.BIMModelProperties.openings:
opening_obj = opening_prop.obj
@@ -1008,10 +1016,12 @@ class EditOpenings(Operator, tool.Ifc.Operator):
bpy.ops.bim.update_openings_focus()
return {"FINISHED"}
def get_buildings_and_openings(self, context):
def get_buildings_and_openings(
self, context: bpy.types.Context
) -> tuple[set[bpy.types.Object], set[ifcopenshell.entity_instance]]:
props = context.scene.BIMModelProperties
building_objs = set()
opening_elements = set()
building_objs: set[bpy.types.Object] = set()
opening_elements: set[ifcopenshell.entity_instance] = set()
objects_to_remove = set()
if self.apply_all:
for opening_prop in props.openings:
@@ -1045,8 +1055,10 @@ class EditOpenings(Operator, tool.Ifc.Operator):
tool.Blender.remove_data_blocks(objects_to_remove, remove_unused_data=True)
return building_objs, opening_elements
def edit_openings(self, building_objs, opening_elements):
objects_to_remove = set()
def edit_openings(
self, building_objs: set[bpy.types.Object], opening_elements: set[ifcopenshell.entity_instance]
) -> None:
objects_to_remove: set[bpy.types.Object] = set()
for opening_element in opening_elements:
opening_obj = tool.Ifc.get_object(opening_element)
+9 -7
View File
@@ -662,26 +662,28 @@ class Model(bonsai.core.tool.Model):
return "PROFILE"
@classmethod
def get_wall_axis(cls, obj: bpy.types.Object, layers: Optional[dict[str, Any]] = None) -> dict[str, Any]:
def get_wall_axis(
cls, obj: bpy.types.Object, layers: Optional[dict[str, Any]] = None
) -> dict[str, tuple[Vector, Vector]]:
x_values = [v[0] for v in obj.bound_box]
min_x = min(x_values)
max_x = max(x_values)
axes = {}
if layers:
axes = {
"base": [
"base": (
(obj.matrix_world @ Vector((min_x, layers["offset"], 0.0))).to_2d(),
(obj.matrix_world @ Vector((max_x, layers["offset"], 0.0))).to_2d(),
],
"side": [
),
"side": (
(obj.matrix_world @ Vector((min_x, layers["offset"] + layers["thickness"], 0.0))).to_2d(),
(obj.matrix_world @ Vector((max_x, layers["offset"] + layers["thickness"], 0.0))).to_2d(),
],
),
}
axes["reference"] = [
axes["reference"] = (
(obj.matrix_world @ Vector((min_x, 0.0, 0.0))).to_2d(),
(obj.matrix_world @ Vector((max_x, 0.0, 0.0))).to_2d(),
]
)
return axes
@classmethod