Files
IfcOpenShell/src/blenderbim/blenderbim/bim/module/model/slab.py
T
2023-03-29 14:30:35 +05:00

758 lines
30 KiB
Python

# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BlenderBIM Add-on is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy
import json
import bmesh
import ifcopenshell
import ifcopenshell.util.type
import ifcopenshell.util.unit
import ifcopenshell.util.element
import blenderbim.bim.handler
import blenderbim.core.type
import blenderbim.core.geometry
import blenderbim.tool as tool
from math import radians
from mathutils import Vector, Matrix
from blenderbim.bim.module.geometry.helper import Helper
from blenderbim.bim.module.model.decorator import ProfileDecorator
def calculate_quantities(usecase_path, ifc_file, settings):
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file)
obj = settings["blender_object"]
product = ifc_file.by_id(obj.BIMObjectProperties.ifc_definition_id)
parametric = ifcopenshell.util.element.get_psets(product).get("EPset_Parametric")
if not parametric or "Engine" not in parametric or parametric["Engine"] != "BlenderBIM.DumbLayer3":
return
qto = ifcopenshell.api.run(
"pset.add_qto", ifc_file, should_run_listeners=False, product=product, name="Qto_SlabBaseQuantities"
)
length = obj.dimensions[0] / unit_scale
width = obj.dimensions[1] / unit_scale
depth = obj.dimensions[2] / unit_scale
perimeter = 0
helper = Helper(ifc_file)
indices = helper.auto_detect_arbitrary_profile_with_voids_extruded_area_solid(settings["geometry"])
bm = bmesh.new()
bm.from_mesh(settings["geometry"])
bm.verts.ensure_lookup_table()
def calculate_profile_length(indices):
indices.append(indices[0]) # Close the loop
edge_vert_pairs = list(zip(indices, indices[1:]))
return sum([(bm.verts[p[1]].co - bm.verts[p[0]].co).length for p in edge_vert_pairs])
perimeter += calculate_profile_length(indices["profile"])
for inner_indices in indices["inner_curves"]:
perimeter += calculate_profile_length(inner_indices)
bm.free()
if product.HasOpenings:
# TODO: calculate gross / net
gross_area = 0
net_area = 0
gross_volume = 0
net_volume = 0
else:
bm = bmesh.new()
bm.from_object(obj, bpy.context.evaluated_depsgraph_get())
bm.faces.ensure_lookup_table()
gross_area = sum([f.calc_area() for f in bm.faces if f.normal.z > 0.9])
net_area = gross_area
gross_volume = bm.calc_volume()
net_volume = gross_volume
bm.free()
properties = {
"Depth": round(depth, 2),
"Perimeter": round(perimeter, 2),
"GrossArea": round(gross_area, 2),
"NetArea": round(net_area, 2),
"GrossVolume": round(gross_volume, 2),
"NetVolume": round(net_volume, 2),
}
if round(obj.dimensions[0] * obj.dimensions[1] * obj.dimensions[2], 2) == round(gross_volume, 2):
properties.update(
{
"Length": round(length, 2),
"Width": round(width, 2),
}
)
else:
properties.update(
{
"Length": None,
"Width": None,
}
)
ifcopenshell.api.run("pset.edit_qto", ifc_file, should_run_listeners=False, qto=qto, properties=properties)
class DumbSlabGenerator:
def __init__(self, relating_type):
self.relating_type = relating_type
def generate(self):
self.file = tool.Ifc.get()
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
thicknesses = []
for rel in self.relating_type.HasAssociations:
if rel.is_a("IfcRelAssociatesMaterial"):
material = rel.RelatingMaterial
if material.is_a("IfcMaterialLayerSet"):
thicknesses = [l.LayerThickness for l in material.MaterialLayers]
break
if not sum(thicknesses):
return
self.body_context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW")
self.footprint_context = ifcopenshell.util.representation.get_context(
tool.Ifc.get(), "Plan", "FootPrint", "SKETCH_VIEW"
)
props = bpy.context.scene.BIMModelProperties
self.collection = bpy.context.view_layer.active_layer_collection.collection
self.collection_obj = bpy.data.objects.get(self.collection.name)
self.depth = sum(thicknesses) * unit_scale
self.width = 3
self.length = 3
self.rotation = 0
self.location = Vector((0, 0, 0))
self.x_angle = 0 if tool.Cad.is_x(props.x_angle, 0, tolerance=0.001) else radians(props.x_angle)
return self.derive_from_cursor()
def derive_from_cursor(self):
self.location = bpy.context.scene.cursor.location
return self.create_slab()
def create_slab(self):
ifc_classes = ifcopenshell.util.type.get_applicable_entities(self.relating_type.is_a(), self.file.schema)
# Standard cases are deprecated, so let's cull them
ifc_class = [c for c in ifc_classes if "StandardCase" not in c][0]
mesh = bpy.data.meshes.new("Dummy")
obj = bpy.data.objects.new(tool.Model.generate_occurrence_name(self.relating_type, ifc_class), mesh)
matrix_world = Matrix()
matrix_world.col[3] = self.location.to_4d()
if self.collection_obj and self.collection_obj.BIMObjectProperties.ifc_definition_id:
matrix_world[2][3] = self.collection_obj.location[2] - self.depth
else:
matrix_world[2][3] -= self.depth
obj.matrix_world = Matrix.Rotation(self.x_angle, 4, "X") @ matrix_world
bpy.context.view_layer.update()
self.collection.objects.link(obj)
element = blenderbim.core.root.assign_class(
tool.Ifc,
tool.Collector,
tool.Root,
obj=obj,
ifc_class=ifc_class,
should_add_representation=False,
context=self.body_context,
)
ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=self.relating_type)
blenderbim.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=obj)
representation = ifcopenshell.api.run(
"geometry.add_slab_representation",
tool.Ifc.get(),
context=self.body_context,
depth=self.depth,
x_angle=self.x_angle,
)
ifcopenshell.api.run(
"geometry.assign_representation", tool.Ifc.get(), product=element, representation=representation
)
blenderbim.core.geometry.switch_representation(
tool.Ifc,
tool.Geometry,
obj=obj,
representation=representation,
should_reload=True,
is_global=True,
should_sync_changes_first=False,
)
if self.footprint_context:
extrusion = tool.Model.get_extrusion(representation)
if extrusion.SweptArea.is_a("IfcArbitraryClosedProfileDef"):
curves = [extrusion.SweptArea.OuterCurve]
if extrusion.SweptArea.is_a("IfcArbitraryProfileDefWithVoids"):
curves.extend(extrusion.SweptArea.InnerCurves)
representation = ifcopenshell.api.run(
"geometry.add_footprint_representation",
tool.Ifc.get(),
context=self.footprint_context,
curves=curves,
)
ifcopenshell.api.run(
"geometry.assign_representation", tool.Ifc.get(), product=element, representation=representation
)
pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="EPset_Parametric")
ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Engine": "BlenderBIM.DumbLayer3"})
obj.select_set(True)
return obj
class DumbSlabPlaner:
def regenerate_from_layer(self, usecase_path, ifc_file, settings):
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file)
layer = settings["layer"]
thickness = settings["attributes"].get("LayerThickness")
if thickness is None:
return
for layer_set in layer.ToMaterialLayerSet:
total_thickness = sum([l.LayerThickness for l in layer_set.MaterialLayers])
if not total_thickness:
continue
for inverse in ifc_file.get_inverse(layer_set):
if not inverse.is_a("IfcMaterialLayerSetUsage") or inverse.LayerSetDirection != "AXIS3":
continue
if ifc_file.schema == "IFC2X3":
for rel in ifc_file.get_inverse(inverse):
if not rel.is_a("IfcRelAssociatesMaterial"):
continue
for element in rel.RelatedObjects:
self.change_thickness(element, thickness)
else:
for rel in inverse.AssociatedTo:
for element in rel.RelatedObjects:
self.change_thickness(element, thickness)
def regenerate_from_type(self, usecase_path, ifc_file, settings):
obj = tool.Ifc.get_object(settings["related_object"])
if not obj or not obj.data or not obj.data.BIMMeshProperties.ifc_definition_id:
return
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file)
new_material = ifcopenshell.util.element.get_material(settings["relating_type"])
if not new_material or not new_material.is_a("IfcMaterialLayerSet"):
return
new_thickness = sum([l.LayerThickness for l in new_material.MaterialLayers])
material = ifcopenshell.util.element.get_material(settings["related_object"])
if material and material.is_a("IfcMaterialLayerSetUsage") and material.LayerSetDirection == "AXIS3":
self.change_thickness(settings["related_object"], new_thickness)
def change_thickness(self, element, thickness):
body_context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW")
obj = tool.Ifc.get_object(element)
if not obj:
return
delta_thickness = (thickness * self.unit_scale) - obj.dimensions.z
if round(delta_thickness, 2) == 0:
return
representation = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
if representation:
extrusion = tool.Model.get_extrusion(representation)
if extrusion:
extrusion.Depth = thickness
else:
props = bpy.context.scene.BIMModelProperties
x_angle = 0 if tool.Cad.is_x(props.x_angle, 0, tolerance=0.001) else radians(props.x_angle)
new_rep = ifcopenshell.api.run(
"geometry.add_slab_representation",
tool.Ifc.get(),
context=body_context,
depth=thickness,
x_angle=x_angle,
)
for inverse in tool.Ifc.get().get_inverse(representation):
ifcopenshell.util.element.replace_attribute(inverse, representation, new_rep)
blenderbim.core.geometry.switch_representation(
tool.Ifc,
tool.Geometry,
obj=obj,
representation=new_rep,
should_reload=True,
is_global=True,
should_sync_changes_first=False,
)
blenderbim.core.geometry.remove_representation(
tool.Ifc, tool.Geometry, obj=obj, representation=representation
)
return
else:
props = bpy.context.scene.BIMModelProperties
x_angle = 0 if tool.Cad.is_x(props.x_angle, 0, tolerance=0.001) else radians(props.x_angle)
representation = ifcopenshell.api.run(
"geometry.add_slab_representation",
tool.Ifc.get(),
context=body_context,
depth=thickness,
x_angle=x_angle,
)
ifcopenshell.api.run(
"geometry.assign_representation", tool.Ifc.get(), product=element, representation=representation
)
blenderbim.core.geometry.switch_representation(
tool.Ifc,
tool.Geometry,
obj=obj,
representation=representation,
should_reload=True,
is_global=True,
should_sync_changes_first=False,
)
obj.location[2] -= delta_thickness
class EnableEditingSketchExtrusionProfile(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.enable_editing_sketch_extrusion_profile"
bl_label = "Enable Editing Sketch Extrusion Profile"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return context.selected_objects
def _execute(self, context):
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
obj = context.active_object
element = tool.Ifc.get_entity(obj)
pset = ifcopenshell.util.element.get_psets(element).get("EPset_Parametric", None)
if pset and pset["Engine"] == "CADSketcher" and pset["Entities"]:
context.scene["sketcher"].update(json.loads(pset["Entities"]))
bpy.context.view_layer.update()
bpy.ops.wm.tool_set_by_id(name="sketcher.slvs_select")
bpy.ops.view3d.slvs_set_all_constraints_visibility(visibility="SHOW")
return {"FINISHED"}
body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
extrusion = tool.Model.get_extrusion(body)
profile = extrusion.SweptArea
if extrusion.Position:
position = Matrix(ifcopenshell.util.placement.get_axis2placement(extrusion.Position).tolist())
position[0][3] *= self.unit_scale
position[1][3] *= self.unit_scale
position[2][3] *= self.unit_scale
else:
position = Matrix()
z_values = [v[2] for v in obj.bound_box]
element = tool.Ifc.get_entity(obj)
entities = context.scene.sketcher.entities
entities.ensure_origin_elements(context)
origin = entities.add_point_3d(obj.matrix_world @ Vector((0, 0, max(z_values))))
origin.fixed = True
origin.origin = True
normal = entities.add_normal_3d(obj.matrix_world.to_quaternion())
normal.fixed = True
normal.origin = True
wp = entities.add_workplane(origin, normal)
sketch = entities.add_sketch(wp)
self.vertices = []
self.edges = []
self.arcs = []
self.circles = []
profile = extrusion.SweptArea
if profile.is_a("IfcArbitraryClosedProfileDef"):
self.process_curve(obj, position, profile.OuterCurve)
if profile.is_a("IfcArbitraryProfileDefWithVoids"):
for inner_curve in profile.InnerCurves:
self.process_curve(obj, position, inner_curve)
points = []
for vertex in self.vertices:
points.append(context.scene.sketcher.entities.add_point_2d(vertex.to_2d(), sketch))
for edge in self.edges:
context.scene.sketcher.entities.add_line_2d(points[edge[0]], points[edge[1]], sketch)
bpy.ops.view3d.slvs_set_active_sketch(index=sketch.slvs_index)
return {"FINISHED"}
def process_curve(self, obj, position, curve):
offset = len(self.vertices)
if curve.is_a("IfcPolyline"):
total_points = len(curve.Points)
last_index = len(curve.Points) - 1
for i, point in enumerate(curve.Points):
if i == last_index:
continue
global_point = position @ Vector(self.convert_unit_to_si(point.Coordinates)).to_3d()
self.vertices.append(global_point)
self.edges.extend([(i, i + 1) for i in range(offset, len(self.vertices))])
self.edges[-1] = (len(self.vertices) - 1, offset) # Close the loop
elif curve.is_a("IfcIndexedPolyCurve"):
is_arc = False
if curve.Segments:
for segment in curve.Segments:
if len(segment[0]) == 3: # IfcArcIndex
is_arc = True
local_point = self.convert_unit_to_si(curve.Points.CoordList[segment[0][0] - 1])
global_point = position @ Vector(local_point).to_3d()
self.vertices.append(global_point)
local_point = self.convert_unit_to_si(curve.Points.CoordList[segment[0][1] - 1])
global_point = position @ Vector(local_point).to_3d()
self.vertices.append(global_point)
self.arcs.append([len(self.vertices) - 2, len(self.vertices) - 1])
else:
local_point = self.convert_unit_to_si(curve.Points.CoordList[segment[0][0] - 1])
global_point = position @ Vector(local_point).to_3d()
self.vertices.append(global_point)
if is_arc:
self.arcs[-1].append(len(self.vertices) - 1)
is_arc = False
else:
for local_point in curve.Points.CoordList:
global_point = position @ Vector(self.convert_unit_to_si(local_point)).to_3d()
self.vertices.append(global_point)
# Curves without segments are self closing
del self.vertices[-1]
self.edges.extend([(i, i + 1) for i in range(offset, len(self.vertices))])
self.edges[-1] = (len(self.vertices) - 1, offset) # Close the loop
elif curve.is_a("IfcCircle"):
center = self.convert_unit_to_si(
Matrix(ifcopenshell.util.placement.get_axis2placement(curve.Position).tolist()).col[3].to_3d()
)
radius = self.convert_unit_to_si(curve.Radius)
self.vertices.extend(
[
position @ Vector((center[0], center[1] - curve.Radius, 0.0)),
position @ Vector((center[0], center[1] + curve.Radius, 0.0)),
]
)
self.circles.append([offset, offset + 1])
self.edges.append((offset, offset + 1))
def convert_unit_to_si(self, value):
if isinstance(value, (tuple, list)):
return [v * self.unit_scale for v in value]
return value * self.unit_scale
class EditSketchExtrusionProfile(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.edit_sketch_extrusion_profile"
bl_label = "Edit Sketch Extrusion Profile"
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
obj = context.active_object
element = tool.Ifc.get_entity(obj)
representation = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
extrusion = tool.Model.get_extrusion(representation)
if extrusion.Position:
position = Matrix(ifcopenshell.util.placement.get_axis2placement(extrusion.Position).tolist())
else:
position = Matrix()
position_i = position.inverted()
cad_sketcher = __import__("CAD_Sketcher-main")
sketch = context.scene.sketcher.active_sketch
converter = cad_sketcher.convertors.BezierConverter(context.scene, sketch)
converter.run()
profile = tool.Ifc.get().createIfcArbitraryClosedProfileDef("AREA")
for path in converter.paths:
points = []
lines = path[0]
last_index = len(lines) - 1
for i, line in enumerate(lines):
local_point = (position_i @ Vector(line.p1.co).to_3d()).to_2d()
points.append(tool.Ifc.get().createIfcCartesianPoint(local_point))
points.append(points[0])
curve = tool.Ifc.get().createIfcPolyline(points)
profile.OuterCurve = curve
old_profile = extrusion.SweptArea
extrusion.SweptArea = profile
ifcopenshell.util.element.remove_deep2(tool.Ifc.get(), old_profile)
pset = ifcopenshell.util.element.get_psets(element).get("EPset_Parametric", None)
if pset:
pset = tool.Ifc.get().by_id(pset["id"])
else:
pset = ifcopenshell.api.run("pset.add_pset", tool.Ifc.get(), product=element, name="EPset_Parametric")
ifcopenshell.api.run(
"pset.edit_pset",
tool.Ifc.get(),
pset=pset,
properties={"Engine": "CADSketcher", "Entities": json.dumps(context.scene["sketcher"].to_dict())},
)
bpy.ops.view3d.slvs_set_active_sketch(index=-1)
workplane = sketch.wp
p1 = workplane.p1
p1.origin = False
nm = workplane.nm
nm.origin = False
bpy.ops.view3d.slvs_delete_entity(index=sketch["slvs_index"])
bpy.ops.view3d.slvs_delete_entity(index=workplane["slvs_index"])
bpy.ops.view3d.slvs_delete_entity(index=p1["slvs_index"])
bpy.ops.view3d.slvs_delete_entity(index=nm["slvs_index"])
blenderbim.core.geometry.switch_representation(
tool.Ifc,
tool.Geometry,
obj=obj,
representation=representation,
should_reload=True,
is_global=True,
should_sync_changes_first=False,
)
return {"FINISHED"}
class DisableEditingSketchExtrusionProfile(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.disable_editing_sketch_extrusion_profile"
bl_label = "Disable Editing Sketch Extrusion Profile"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return context.selected_objects
def _execute(self, context):
sketch = context.scene.sketcher.active_sketch
bpy.ops.view3d.slvs_set_active_sketch(index=-1)
workplane = sketch.wp
p1 = workplane.p1
p1.origin = False
nm = workplane.nm
nm.origin = False
bpy.ops.view3d.slvs_delete_entity(index=sketch["slvs_index"])
bpy.ops.view3d.slvs_delete_entity(index=workplane["slvs_index"])
bpy.ops.view3d.slvs_delete_entity(index=p1["slvs_index"])
bpy.ops.view3d.slvs_delete_entity(index=nm["slvs_index"])
return {"FINISHED"}
def disable_editing_extrusion_profile(context):
ProfileDecorator.uninstall()
bpy.ops.object.mode_set(mode="OBJECT")
obj = context.active_object
element = tool.Ifc.get_entity(obj)
body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
blenderbim.core.geometry.switch_representation(
tool.Ifc,
tool.Geometry,
obj=obj,
representation=body,
should_reload=True,
is_global=True,
should_sync_changes_first=False,
)
return {"FINISHED"}
class DisableEditingExtrusionProfile(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.disable_editing_extrusion_profile"
bl_label = "Disable Editing Extrusion Profile"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return context.selected_objects
def _execute(self, context):
return disable_editing_extrusion_profile(context)
class EnableEditingExtrusionProfile(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.enable_editing_extrusion_profile"
bl_label = "Enable Editing Extrusion Profile"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return context.selected_objects
def _execute(self, context):
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
obj = context.active_object
element = tool.Ifc.get_entity(obj)
body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
extrusion = tool.Model.get_extrusion(body)
if extrusion.Position:
position = Matrix(ifcopenshell.util.placement.get_axis2placement(extrusion.Position).tolist())
position[0][3] *= self.unit_scale
position[1][3] *= self.unit_scale
position[2][3] *= self.unit_scale
else:
position = Matrix()
tool.Model.import_profile(extrusion.SweptArea, obj=obj, position=position)
bpy.ops.object.mode_set(mode="EDIT")
ProfileDecorator.install(context, exit_edit_mode_callback=lambda: disable_editing_extrusion_profile(context))
if not bpy.app.background:
bpy.ops.wm.tool_set_by_id(tool.Blender.get_viewport_context(), name="bim.cad_tool")
return {"FINISHED"}
class EditExtrusionProfile(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.edit_extrusion_profile"
bl_label = "Edit Extrusion Profile"
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
ProfileDecorator.uninstall()
bpy.ops.object.mode_set(mode="OBJECT")
obj = context.active_object
element = tool.Ifc.get_entity(obj)
representation = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
extrusion = tool.Model.get_extrusion(representation)
if extrusion.Position:
position = Matrix(ifcopenshell.util.placement.get_axis2placement(extrusion.Position).tolist())
position[0][3] *= self.unit_scale
position[1][3] *= self.unit_scale
position[2][3] *= self.unit_scale
else:
position = Matrix()
profile = tool.Model.export_profile(obj, position=position)
if not profile:
def msg(self, context):
self.layout.label(text="INVALID PROFILE")
bpy.context.window_manager.popup_menu(msg, title="Error", icon="ERROR")
ProfileDecorator.install(
context, exit_edit_mode_callback=lambda: disable_editing_extrusion_profile(context)
)
bpy.ops.object.mode_set(mode="EDIT")
return
old_profile = extrusion.SweptArea
for inverse in tool.Ifc.get().get_inverse(old_profile):
ifcopenshell.util.element.replace_attribute(inverse, old_profile, profile)
ifcopenshell.util.element.remove_deep2(tool.Ifc.get(), old_profile)
blenderbim.core.geometry.switch_representation(
tool.Ifc,
tool.Geometry,
obj=obj,
representation=representation,
should_reload=True,
is_global=True,
should_sync_changes_first=False,
)
footprint_context = ifcopenshell.util.representation.get_context(
tool.Ifc.get(), "Plan", "FootPrint", "SKETCH_VIEW"
)
if footprint_context:
curves = [profile.OuterCurve]
if profile.is_a("IfcArbitraryProfileDefWithVoids"):
curves.extend(profile.InnerCurves)
new_footprint = ifcopenshell.api.run(
"geometry.add_footprint_representation", tool.Ifc.get(), context=footprint_context, curves=curves
)
old_footprint = ifcopenshell.util.representation.get_representation(
element, "Plan", "FootPrint", "SKETCH_VIEW"
)
if old_footprint:
for inverse in tool.Ifc.get().get_inverse(old_footprint):
ifcopenshell.util.element.replace_attribute(inverse, old_footprint, new_footprint)
blenderbim.core.geometry.remove_representation(
tool.Ifc, tool.Geometry, obj=obj, representation=old_footprint
)
else:
ifcopenshell.api.run(
"geometry.assign_representation", tool.Ifc.get(), product=element, representation=new_footprint
)
return {"FINISHED"}
class ResetVertex(bpy.types.Operator):
bl_idname = "bim.reset_vertex"
bl_label = "Reset Vertex"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
obj = context.active_object
return bool(obj) and obj.type == "MESH"
def cancel_message(self, msg):
self.report({"WARNING"}, msg)
return {"CANCELLED"}
def execute(self, context):
obj = context.active_object
bpy.ops.object.mode_set(mode="OBJECT")
selected_vertices = [v.index for v in obj.data.vertices if v.select]
for group in obj.vertex_groups:
group.remove(selected_vertices)
bpy.ops.object.mode_set(mode="EDIT")
return {"FINISHED"}
class SetArcIndex(bpy.types.Operator):
bl_idname = "bim.set_arc_index"
bl_label = "Set Arc Index"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
obj = context.active_object
return bool(obj) and obj.type == "MESH"
def cancel_message(self, msg):
self.report({"ERROR"}, msg)
return {"CANCELLED"}
def execute(self, context):
# NOTE: undo won't remove new verex group
# because of jumping between modes
obj = context.active_object
bm = tool.Blender.get_bmesh_for_mesh(obj.data)
selected_vertices = [v.index for v in bm.verts if v.select]
if len(selected_vertices) != 3:
return self.cancel_message("Select 3 vertices.")
bpy.ops.object.mode_set(mode="OBJECT")
in_group = any([bool(obj.data.vertices[v].groups) for v in selected_vertices])
for group in obj.vertex_groups:
group.remove(selected_vertices)
group = obj.vertex_groups.new(name="IFCARCINDEX")
group.add(selected_vertices, 1, "REPLACE")
bpy.ops.object.mode_set(mode="EDIT")
return {"FINISHED"}