mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-09 13:52:23 +00:00
Basic adding of filled openings reimplemented with new opening system
This commit is contained in:
@@ -47,65 +47,70 @@ class AddElementOpening(bpy.types.Operator):
|
|||||||
return IfcStore.execute_ifc_operator(self, context)
|
return IfcStore.execute_ifc_operator(self, context)
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
voided_obj = self.get_voided_building_element(context)
|
voided_obj = bpy.data.objects.get(self.voided_building_element)
|
||||||
filling_obj = self.get_filling_building_element(context)
|
filling_obj = bpy.data.objects.get(self.filling_building_element)
|
||||||
|
filling = tool.Ifc.get_entity(filling_obj)
|
||||||
|
|
||||||
if not voided_obj:
|
if not voided_obj or not filling_obj:
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
element = IfcStore.get_file().by_id(voided_obj.BIMObjectProperties.ifc_definition_id)
|
element = tool.Ifc.get_entity(voided_obj)
|
||||||
local_location = voided_obj.matrix_world.inverted() @ context.scene.cursor.location
|
local_location = voided_obj.matrix_world.inverted() @ context.scene.cursor.location
|
||||||
raycast = voided_obj.closest_point_on_mesh(local_location, distance=0.01)
|
raycast = voided_obj.closest_point_on_mesh(local_location, distance=0.01)
|
||||||
if not raycast[0]:
|
if not raycast[0]:
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
if filling_obj:
|
# In this prototype, we assume openings are only added to axis-based elements
|
||||||
opening = self.generate_opening_from_filling(filling_obj, voided_obj)
|
axis = [voided_obj.matrix_world @ Vector((0,0,0)), voided_obj.matrix_world @ Vector((1,0,0))]
|
||||||
else:
|
new_matrix = voided_obj.matrix_world.copy()
|
||||||
# The opening shall be based on the smallest bounding dimension of the element
|
new_matrix.col[3] = tool.Cad.point_on_edge(context.scene.cursor.location, axis).to_4d()
|
||||||
dimension = min(voided_obj.dimensions)
|
if filling.is_a("IfcWindow"):
|
||||||
bpy.ops.mesh.primitive_cube_add(size=dimension * 2)
|
new_matrix[2][3] = context.scene.cursor.location[2]
|
||||||
opening = context.selected_objects[0]
|
filling_obj.matrix_world = new_matrix
|
||||||
|
bpy.context.view_layer.update()
|
||||||
|
|
||||||
# Place the opening in the middle of the element
|
opening_obj = self.generate_opening_from_filling(filling_obj, voided_obj)
|
||||||
global_location = voided_obj.matrix_world @ raycast[1]
|
|
||||||
normal = raycast[2]
|
|
||||||
normal.negate()
|
|
||||||
global_normal = voided_obj.matrix_world.to_quaternion() @ normal
|
|
||||||
opening.location = global_location + (global_normal * (dimension / 2))
|
|
||||||
opening.rotation_euler = voided_obj.rotation_euler
|
|
||||||
opening.name = "Opening"
|
|
||||||
|
|
||||||
bpy.ops.bim.add_opening(opening=opening.name, obj=voided_obj.name)
|
# Still prototyping, for now duplicating code from bpy.ops.bim.add_opening
|
||||||
if filling_obj:
|
if tool.Ifc.is_moved(voided_obj):
|
||||||
bpy.ops.bim.add_filling(opening=opening.name, obj=filling_obj.name)
|
blenderbim.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=voided_obj)
|
||||||
|
|
||||||
|
has_visible_openings = False
|
||||||
|
for opening in [r.RelatedOpeningElement for r in element.HasOpenings]:
|
||||||
|
if tool.Ifc.get_object(opening):
|
||||||
|
has_visible_openings = True
|
||||||
|
break
|
||||||
|
|
||||||
|
body_context = ifcopenshell.util.representation.get_context(IfcStore.get_file(), "Model", "Body")
|
||||||
|
opening = blenderbim.core.root.assign_class(
|
||||||
|
tool.Ifc,
|
||||||
|
tool.Collector,
|
||||||
|
tool.Root,
|
||||||
|
obj=opening_obj,
|
||||||
|
ifc_class="IfcOpeningElement",
|
||||||
|
should_add_representation=True,
|
||||||
|
context=body_context,
|
||||||
|
)
|
||||||
|
ifcopenshell.api.run("void.add_opening", tool.Ifc.get(), opening=opening, element=element)
|
||||||
|
|
||||||
|
representation = tool.Ifc.get().by_id(voided_obj.data.BIMMeshProperties.ifc_definition_id)
|
||||||
|
blenderbim.core.geometry.switch_representation(
|
||||||
|
tool.Geometry,
|
||||||
|
obj=voided_obj,
|
||||||
|
representation=representation,
|
||||||
|
should_reload=True,
|
||||||
|
enable_dynamic_voids=False,
|
||||||
|
is_global=True,
|
||||||
|
should_sync_changes_first=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
bpy.ops.bim.add_filling(opening=opening_obj.name, obj=filling_obj.name)
|
||||||
|
|
||||||
|
if not has_visible_openings:
|
||||||
|
tool.Ifc.unlink(obj=opening_obj)
|
||||||
|
bpy.data.objects.remove(opening_obj)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def get_voided_building_element(self, context):
|
|
||||||
obj = None
|
|
||||||
if self.voided_building_element:
|
|
||||||
obj = bpy.data.objects.get(self.voided_building_element)
|
|
||||||
else:
|
|
||||||
total_selected = len(context.selected_objects)
|
|
||||||
if total_selected == 1 or total_selected == 2:
|
|
||||||
obj = context.active_object
|
|
||||||
if obj and obj.BIMObjectProperties.ifc_definition_id:
|
|
||||||
return obj
|
|
||||||
|
|
||||||
def get_filling_building_element(self, context):
|
|
||||||
obj = None
|
|
||||||
if self.filling_building_element:
|
|
||||||
obj = bpy.data.objects.get(self.filling_building_element)
|
|
||||||
else:
|
|
||||||
total_selected = len(context.selected_objects)
|
|
||||||
if total_selected == 2:
|
|
||||||
if context.selected_objects[0] == context.active_object:
|
|
||||||
obj = context.selected_objects[1]
|
|
||||||
else:
|
|
||||||
obj = context.selected_objects[0]
|
|
||||||
if obj and obj.BIMObjectProperties.ifc_definition_id:
|
|
||||||
return obj
|
|
||||||
|
|
||||||
def generate_opening_from_filling(self, filling_obj, voided_obj):
|
def generate_opening_from_filling(self, filling_obj, voided_obj):
|
||||||
x, y, z = filling_obj.dimensions
|
x, y, z = filling_obj.dimensions
|
||||||
dimension = min(voided_obj.dimensions)
|
dimension = min(voided_obj.dimensions)
|
||||||
@@ -155,10 +160,6 @@ class AddElementOpening(bpy.types.Operator):
|
|||||||
mesh.from_pydata(verts, edges, faces)
|
mesh.from_pydata(verts, edges, faces)
|
||||||
obj = bpy.data.objects.new("Opening", mesh)
|
obj = bpy.data.objects.new("Opening", mesh)
|
||||||
obj.matrix_world = filling_obj.matrix_world
|
obj.matrix_world = filling_obj.matrix_world
|
||||||
|
|
||||||
filling_obj.rotation_euler = voided_obj.rotation_euler
|
|
||||||
obj.parent = filling_obj
|
|
||||||
obj.matrix_parent_inverse = filling_obj.matrix_world.inverted()
|
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
||||||
@@ -184,7 +185,7 @@ class AddPotentialOpening(Operator, AddObjectHelper):
|
|||||||
new_matrix = None
|
new_matrix = None
|
||||||
if context.selected_objects and context.active_object:
|
if context.selected_objects and context.active_object:
|
||||||
new_matrix = context.active_object.matrix_world.copy()
|
new_matrix = context.active_object.matrix_world.copy()
|
||||||
new_matrix.col[3] = context.scene.cursor.location.to_4d().to_4d()
|
new_matrix.col[3] = context.scene.cursor.location.to_4d()
|
||||||
|
|
||||||
x = self.x / 2
|
x = self.x / 2
|
||||||
y = self.y / 2
|
y = self.y / 2
|
||||||
|
|||||||
@@ -150,8 +150,6 @@ class AddConstrTypeInstance(bpy.types.Operator):
|
|||||||
bpy.ops.bim.add_element_opening(
|
bpy.ops.bim.add_element_opening(
|
||||||
voided_building_element=building_obj.name, filling_building_element=obj.name
|
voided_building_element=building_obj.name, filling_building_element=obj.name
|
||||||
)
|
)
|
||||||
if instance_class == "IfcDoor" and self.link_to_scene:
|
|
||||||
obj.location[2] = building_obj.location[2] - min([v[2] for v in obj.bound_box])
|
|
||||||
elif self.link_to_scene:
|
elif self.link_to_scene:
|
||||||
if collection_obj and collection_obj.BIMObjectProperties.ifc_definition_id:
|
if collection_obj and collection_obj.BIMObjectProperties.ifc_definition_id:
|
||||||
obj.location[2] = collection_obj.location[2] - min([v[2] for v in obj.bound_box])
|
obj.location[2] = collection_obj.location[2] - min([v[2] for v in obj.bound_box])
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ class FacetDocGenerator:
|
|||||||
# Create an IDS with the applicability selecting exactly
|
# Create an IDS with the applicability selecting exactly
|
||||||
# the entity type passed to us in `inst`.
|
# the entity type passed to us in `inst`.
|
||||||
specs = ids.Ids(title=name)
|
specs = ids.Ids(title=name)
|
||||||
spec = ids.Specification(name=name)
|
spec = ids.Specification(name=name, minOccurs=1)
|
||||||
spec.applicability.append(ids.Entity(name=inst.is_a().upper()))
|
spec.applicability.append(ids.Entity(name=inst.is_a().upper()))
|
||||||
spec.requirements.append(facet)
|
spec.requirements.append(facet)
|
||||||
specs.specifications.append(spec)
|
specs.specifications.append(spec)
|
||||||
|
|||||||
Reference in New Issue
Block a user