Files
IfcOpenShell/src/blenderbim/blenderbim/bim/module/qto/helper.py
T
2023-10-30 15:14:34 +05:00

125 lines
4.2 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 bmesh
def calculate_height(obj):
return obj.dimensions[2]
def calculate_edges_lengths(objs, context):
return calculate_mesh_quantity(objs, context, lambda bm: sum((e.calc_length() for e in bm.edges if e.select)))
def calculate_faces_areas(objs, context):
return calculate_mesh_quantity(objs, context, lambda bm: sum((f.calc_area() for f in bm.faces if f.select)))
def calculate_volumes(objs, context):
return calculate_mesh_quantity(objs, context, lambda bm: bm.calc_volume())
def calculate_mesh_quantity(objs: bpy.types.Object, context, operation):
"""Get the sum of the target quantity on all passed mesh objects
:param objs: iterable of mesh object
:param context: current execution context
:param operation: function which takes a single bmesh as an argument, returns a float value
:returns float:
"""
result = 0
edit_mode = context.active_object.mode == "EDIT"
for obj in objs:
if edit_mode:
bm = bmesh.from_edit_mesh(obj.data)
result += operation(bm)
else:
bm = bmesh.new()
bm.from_mesh(obj.data)
result += operation(bm)
bm.free()
return result
def calculate_formwork_area(objs, context):
"""
Formwork is defined as the surface area required to cover all exposed
surfaces of one or more objects, excluding top surfaces (i.e. that have a
face normal with a significant +Z component).
"""
copied_objs = []
result = 0
copied_obj = objs[0].copy()
copied_obj.data = objs[0].data.copy()
copied_obj.animation_data_clear()
context.collection.objects.link(copied_obj)
if len(objs) > 1:
for i, obj in enumerate(objs):
if i == 0:
continue
modifier = copied_obj.modifiers.new(type="BOOLEAN", name="Boolean")
modifier.operation = "UNION"
modifier.object = obj
with context.temp_override(object=copied_obj):
bpy.ops.object.modifier_apply(modifier="Boolean")
copied_obj.name = "Formwork"
copied_obj.BIMObjectProperties.ifc_definition_id = 0
modifier = copied_obj.modifiers.new("Formwork", "REMESH")
modifier.mode = "SHARP"
# This hardcoded value may be optimised through a better understanding of the octree division.
# These values are based off some trial and error heuristics I've learned through experience.
max_dim = max(copied_obj.dimensions)
if max_dim > 45:
modifier.octree_depth = 9
elif max_dim > 35:
modifier.octree_depth = 8
elif max_dim > 12:
modifier.octree_depth = 7
elif max_dim > 5:
modifier.octree_depth = 6
else:
modifier.octree_depth = 5
mesh = copied_obj.evaluated_get(context.evaluated_depsgraph_get()).to_mesh()
for polygon in mesh.polygons:
if polygon.normal.z > 0.5:
continue
result += polygon.area
return result
def calculate_side_formwork_area(objs, context):
"""
Side formwork is defined as the surface area required to cover all exposed
surfaces of one or more objects, excluding top and bottom surfaces (i.e.
that have a face normal with a significant Z component).
"""
result = 0
for obj in objs:
mesh = obj.evaluated_get(context.evaluated_depsgraph_get()).to_mesh()
for polygon in mesh.polygons:
if abs(polygon.normal.z) > 0.8:
continue
result += polygon.area
return result