mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
typing
This commit is contained in:
@@ -45,7 +45,7 @@ from bpy.types import SpaceView3D
|
|||||||
from bpy.props import FloatProperty
|
from bpy.props import FloatProperty
|
||||||
from bpy_extras.object_utils import AddObjectHelper, object_data_add
|
from bpy_extras.object_utils import AddObjectHelper, object_data_add
|
||||||
from gpu_extras.batch import batch_for_shader
|
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):
|
class AddFilledOpening(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
@@ -63,19 +63,21 @@ class AddFilledOpening(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
class FilledOpeningGenerator:
|
class FilledOpeningGenerator:
|
||||||
def generate(
|
def generate(
|
||||||
self,
|
self,
|
||||||
filling_obj: Union[bpy.types.Object, None],
|
filling_obj: bpy.types.Object,
|
||||||
voided_obj: Union[bpy.types.Object, None],
|
voided_obj: bpy.types.Object,
|
||||||
target: Optional[Vector] = None,
|
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
|
props = bpy.context.scene.BIMModelProperties
|
||||||
opening_thickness_si = 0.0
|
opening_thickness_si = 0.0
|
||||||
|
|
||||||
filling = tool.Ifc.get_entity(filling_obj)
|
filling = tool.Ifc.get_entity(filling_obj)
|
||||||
element = tool.Ifc.get_entity(voided_obj)
|
element = tool.Ifc.get_entity(voided_obj)
|
||||||
|
|
||||||
if not voided_obj or not filling_obj:
|
assert filling and element
|
||||||
return
|
|
||||||
|
|
||||||
if filling.FillsVoids:
|
if filling.FillsVoids:
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"void.remove_opening", tool.Ifc.get(), opening=filling.FillsVoids[0].RelatingOpeningElement
|
"void.remove_opening", tool.Ifc.get(), opening=filling.FillsVoids[0].RelatingOpeningElement
|
||||||
@@ -94,7 +96,7 @@ class FilledOpeningGenerator:
|
|||||||
target = filling_obj.matrix_world.translation.copy()
|
target = filling_obj.matrix_world.translation.copy()
|
||||||
raycast = voided_obj.closest_point_on_mesh(voided_obj.matrix_world.inverted() @ target, distance=0.5)
|
raycast = voided_obj.closest_point_on_mesh(voided_obj.matrix_world.inverted() @ target, distance=0.5)
|
||||||
if not raycast[0]:
|
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
|
# In this prototype, we assume openings are only added to axis-based elements
|
||||||
layers = tool.Model.get_material_layer_parameters(element)
|
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
|
new_matrix.translation.xyz = voided_obj.matrix_world @ local_position_on_voided_obj
|
||||||
rotation_matrix = Matrix.Rotation(radians(-90), 4, "X")
|
rotation_matrix = Matrix.Rotation(radians(-90), 4, "X")
|
||||||
new_matrix @= rotation_matrix
|
new_matrix @= rotation_matrix
|
||||||
|
else:
|
||||||
|
assert False, f"Unexpected layer set direction: {layers['layer_set_direction']}"
|
||||||
|
|
||||||
filling_obj.matrix_world = new_matrix
|
filling_obj.matrix_world = new_matrix
|
||||||
bpy.context.view_layer.update()
|
bpy.context.view_layer.update()
|
||||||
@@ -149,6 +153,7 @@ class FilledOpeningGenerator:
|
|||||||
representation = ifcopenshell.util.representation.get_representation(
|
representation = ifcopenshell.util.representation.get_representation(
|
||||||
existing_opening_occurrence, "Model", "Body", "MODEL_VIEW"
|
existing_opening_occurrence, "Model", "Body", "MODEL_VIEW"
|
||||||
)
|
)
|
||||||
|
assert representation
|
||||||
representation = ifcopenshell.util.representation.resolve_representation(representation)
|
representation = ifcopenshell.util.representation.resolve_representation(representation)
|
||||||
else:
|
else:
|
||||||
representation = self.generate_opening_from_filling(
|
representation = self.generate_opening_from_filling(
|
||||||
@@ -175,8 +180,10 @@ class FilledOpeningGenerator:
|
|||||||
for voided_obj in voided_objs:
|
for voided_obj in voided_objs:
|
||||||
if voided_obj.data:
|
if voided_obj.data:
|
||||||
voided_element = tool.Ifc.get_entity(voided_obj)
|
voided_element = tool.Ifc.get_entity(voided_obj)
|
||||||
|
assert voided_element
|
||||||
context = tool.Geometry.get_active_representation_context(voided_obj)
|
context = tool.Geometry.get_active_representation_context(voided_obj)
|
||||||
representation = tool.Geometry.get_representation_by_context(voided_element, context)
|
representation = tool.Geometry.get_representation_by_context(voided_element, context)
|
||||||
|
assert representation
|
||||||
|
|
||||||
bonsai.core.geometry.switch_representation(
|
bonsai.core.geometry.switch_representation(
|
||||||
tool.Ifc,
|
tool.Ifc,
|
||||||
@@ -273,11 +280,12 @@ class FilledOpeningGenerator:
|
|||||||
)
|
)
|
||||||
filling_obj = tool.Ifc.get_object(filling_type)
|
filling_obj = tool.Ifc.get_object(filling_type)
|
||||||
context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW")
|
context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW")
|
||||||
|
assert context
|
||||||
|
|
||||||
if profile:
|
if profile:
|
||||||
profile = ifcopenshell.util.representation.resolve_representation(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:
|
if len(profile.Items) == 1:
|
||||||
curve_3d = profile.Items[0]
|
curve_3d = profile.Items[0]
|
||||||
if tool.Ifc.get_schema() == "IFC2X3":
|
if tool.Ifc.get_schema() == "IFC2X3":
|
||||||
@@ -944,7 +952,7 @@ class UpdateOpeningsFocus(Operator, tool.Ifc.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
def hide_openings(context, objects):
|
def hide_openings(context: bpy.types.Context, objects: Sequence[bpy.types.Object]) -> None:
|
||||||
objects_to_remove = set()
|
objects_to_remove = set()
|
||||||
for opening_prop in context.scene.BIMModelProperties.openings:
|
for opening_prop in context.scene.BIMModelProperties.openings:
|
||||||
opening_obj = opening_prop.obj
|
opening_obj = opening_prop.obj
|
||||||
@@ -1008,10 +1016,12 @@ class EditOpenings(Operator, tool.Ifc.Operator):
|
|||||||
bpy.ops.bim.update_openings_focus()
|
bpy.ops.bim.update_openings_focus()
|
||||||
return {"FINISHED"}
|
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
|
props = context.scene.BIMModelProperties
|
||||||
building_objs = set()
|
building_objs: set[bpy.types.Object] = set()
|
||||||
opening_elements = set()
|
opening_elements: set[ifcopenshell.entity_instance] = set()
|
||||||
objects_to_remove = set()
|
objects_to_remove = set()
|
||||||
if self.apply_all:
|
if self.apply_all:
|
||||||
for opening_prop in props.openings:
|
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)
|
tool.Blender.remove_data_blocks(objects_to_remove, remove_unused_data=True)
|
||||||
return building_objs, opening_elements
|
return building_objs, opening_elements
|
||||||
|
|
||||||
def edit_openings(self, building_objs, opening_elements):
|
def edit_openings(
|
||||||
objects_to_remove = set()
|
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:
|
for opening_element in opening_elements:
|
||||||
opening_obj = tool.Ifc.get_object(opening_element)
|
opening_obj = tool.Ifc.get_object(opening_element)
|
||||||
|
|
||||||
|
|||||||
@@ -662,26 +662,28 @@ class Model(bonsai.core.tool.Model):
|
|||||||
return "PROFILE"
|
return "PROFILE"
|
||||||
|
|
||||||
@classmethod
|
@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]
|
x_values = [v[0] for v in obj.bound_box]
|
||||||
min_x = min(x_values)
|
min_x = min(x_values)
|
||||||
max_x = max(x_values)
|
max_x = max(x_values)
|
||||||
axes = {}
|
axes = {}
|
||||||
if layers:
|
if layers:
|
||||||
axes = {
|
axes = {
|
||||||
"base": [
|
"base": (
|
||||||
(obj.matrix_world @ Vector((min_x, layers["offset"], 0.0))).to_2d(),
|
(obj.matrix_world @ Vector((min_x, layers["offset"], 0.0))).to_2d(),
|
||||||
(obj.matrix_world @ Vector((max_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((min_x, layers["offset"] + layers["thickness"], 0.0))).to_2d(),
|
||||||
(obj.matrix_world @ Vector((max_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((min_x, 0.0, 0.0))).to_2d(),
|
||||||
(obj.matrix_world @ Vector((max_x, 0.0, 0.0))).to_2d(),
|
(obj.matrix_world @ Vector((max_x, 0.0, 0.0))).to_2d(),
|
||||||
]
|
)
|
||||||
return axes
|
return axes
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
Reference in New Issue
Block a user