This commit is contained in:
Andrej730
2024-10-22 11:13:59 +05:00
parent 9eaecdb0a4
commit 71c5e83fa0
10 changed files with 60 additions and 27 deletions
@@ -45,8 +45,8 @@ class CoveringTool(WorkSpaceTool):
CoveringToolUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
def add_layout_hotkey(layout, text, hotkey, description):
args = ["covering", layout, text, hotkey, description]
def add_layout_hotkey(layout: bpy.types.UILayout, text: str, hotkey: str, description: str) -> None:
args = ("covering", layout, text, hotkey, description)
tool.Blender.add_layout_hotkey_operator(*args)
@@ -19,6 +19,9 @@
import bpy
import numpy as np
import ifcopenshell
import ifcopenshell.util.geolocation
import ifcopenshell.util.placement
import ifcopenshell.util.unit
import bonsai.tool as tool
import bonsai.core.misc as core
import bonsai.core.geometry as core_geometry
@@ -519,7 +519,7 @@ class AlignProduct(bpy.types.Operator):
obj.matrix_world = Matrix.Translation(active_y_axis * -y_distances[i]) @ obj.matrix_world
return {"FINISHED"}
def get_axis_distances(self, point, axis, context):
def get_axis_distances(self, point: Vector, axis: Vector, context: bpy.types.Context) -> list[float]:
results = []
for obj in context.selected_objects:
if self.align_type == "CENTERLINE":
+8 -8
View File
@@ -412,11 +412,11 @@ class DumbWallAligner:
# An alignment shifts the origin of all walls to the closest point on the
# local X axis of the reference wall. In addition, the Z rotation is copied.
# Z translations are ignored for alignment.
def __init__(self, wall, reference_wall):
def __init__(self, wall: bpy.types.Object, reference_wall: bpy.types.Object):
self.wall = wall
self.reference_wall = reference_wall
def align_centerline(self):
def align_centerline(self) -> None:
self.align_rotation()
l_start = Vector(self.reference_wall.bound_box[0]).lerp(Vector(self.reference_wall.bound_box[3]), 0.5)
@@ -434,7 +434,7 @@ class DumbWallAligner:
new_origin = point - offset
self.wall.matrix_world.translation[0], self.wall.matrix_world.translation[1] = new_origin.xy
def align_last_layer(self):
def align_last_layer(self) -> None:
self.align_rotation()
if self.is_rotation_flipped():
@@ -457,7 +457,7 @@ class DumbWallAligner:
new_origin = point - offset
self.wall.matrix_world.translation[0], self.wall.matrix_world.translation[1] = new_origin.xy
def align_first_layer(self):
def align_first_layer(self) -> None:
self.align_rotation()
if self.is_rotation_flipped():
@@ -480,7 +480,7 @@ class DumbWallAligner:
new_origin = point - offset
self.wall.matrix_world.translation[0], self.wall.matrix_world.translation[1] = new_origin.xy
def align_rotation(self):
def align_rotation(self) -> None:
reference = (self.reference_wall.matrix_world.to_quaternion() @ Vector((1, 0, 0))).to_2d()
wall = (self.wall.matrix_world.to_quaternion() @ Vector((1, 0, 0))).to_2d()
angle = reference.angle_signed(wall)
@@ -492,7 +492,7 @@ class DumbWallAligner:
self.wall.rotation_euler[2] += angle
bpy.context.view_layer.update()
def is_rotation_flipped(self):
def is_rotation_flipped(self) -> bool:
reference = (self.reference_wall.matrix_world.to_quaternion() @ Vector((1, 0, 0))).to_2d()
wall = (self.wall.matrix_world.to_quaternion() @ Vector((1, 0, 0))).to_2d()
angle = reference.angle_signed(wall)
@@ -835,7 +835,7 @@ class DumbWallJoiner:
body = copy.deepcopy(axis1["reference"])
self.recreate_wall(element1, wall1, axis, body)
def split(self, wall1, target):
def split(self, wall1: bpy.types.Object, target: Vector) -> None:
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
element1 = tool.Ifc.get_entity(wall1)
@@ -895,7 +895,7 @@ class DumbWallJoiner:
self.recreate_wall(element1, wall1, axis1["reference"], axis1["reference"])
self.recreate_wall(element2, wall2, axis2["reference"], axis2["reference"])
def flip(self, wall1):
def flip(self, wall1: bpy.types.Object) -> None:
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
if tool.Ifc.is_moved(wall1):
@@ -49,8 +49,8 @@ class SpatialTool(WorkSpaceTool):
SpatialToolUI.draw(context, layout)
def add_layout_hotkey(layout, text, hotkey, description):
args = ["spatial", layout, text, hotkey, description]
def add_layout_hotkey(layout: bpy.types.UILayout, text: str, hotkey: str, description: str) -> None:
args = ("spatial", layout, text, hotkey, description)
tool.Blender.add_layout_hotkey_operator(*args)
@@ -41,8 +41,8 @@ class StructuralTool(WorkSpaceTool):
StructuralToolUI.draw(context, layout)
def add_layout_hotkey(layout, text, hotkey, description):
args = ["structural", layout, text, hotkey, description]
def add_layout_hotkey(layout: bpy.types.UILayout, text: str, hotkey: str, description: str) -> None:
args = ("structural", layout, text, hotkey, description)
tool.Blender.add_layout_hotkey_operator(*args)
+9 -1
View File
@@ -16,8 +16,16 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
from typing import TYPE_CHECKING, Optional
def resize_to_storey(misc, obj=None, total_storeys=None):
if TYPE_CHECKING:
import bpy
import ifcopenshell
import bonsai.tool as tool
def resize_to_storey(misc: tool.Misc, obj: bpy.types.Object, total_storeys: int) -> None:
storey = misc.get_object_storey(obj)
if not storey:
return
+18 -9
View File
@@ -19,28 +19,33 @@
import bpy
import bmesh
import ifcopenshell
import ifcopenshell.util.element
import ifcopenshell.util.placement
import ifcopenshell.util.unit
import bonsai.core.tool
import bonsai.core.root
import bonsai.tool as tool
from mathutils import Vector, Matrix
from bonsai.bim.ifc import IfcStore
from typing import Union
class Misc(bonsai.core.tool.Misc):
@classmethod
def get_object_storey(cls, obj):
storey = ifcopenshell.util.element.get_container(tool.Ifc.get_entity(obj))
def get_object_storey(cls, obj: bpy.types.Object) -> Union[ifcopenshell.entity_instance, None]:
element = tool.Ifc.get_entity(obj)
assert element
storey = ifcopenshell.util.element.get_container(element)
if storey and storey.is_a("IfcBuildingStorey"):
return storey
@classmethod
def get_storey_elevation_in_si(cls, storey):
def get_storey_elevation_in_si(cls, storey: ifcopenshell.entity_instance) -> float:
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
elevation = ifcopenshell.util.placement.get_storey_elevation(storey)
return elevation * unit_scale
@classmethod
def get_storey_height_in_si(cls, storey, total_storeys):
def get_storey_height_in_si(cls, storey: ifcopenshell.entity_instance, total_storeys: int) -> Union[float, None]:
building = ifcopenshell.util.element.get_aggregate(storey)
related_objects = []
for rel in building.IsDecomposedBy:
@@ -60,11 +65,12 @@ class Misc(bonsai.core.tool.Misc):
return (next_storey_elevation - storey_elevation) * unit_scale
@classmethod
def set_object_origin_to_bottom(cls, obj):
def set_object_origin_to_bottom(cls, obj: bpy.types.Object) -> None:
absolute_bound_box = [obj.matrix_world @ Vector(c) for c in obj.bound_box]
min_z = min([c[2] for c in absolute_bound_box])
new_origin = obj.matrix_world.translation.copy()
new_origin[2] = min_z
assert isinstance(obj.data, bpy.types.Mesh)
obj.data.transform(
Matrix.Translation(
(obj.matrix_world.inverted().to_quaternion() @ (obj.matrix_world.translation - new_origin))
@@ -73,15 +79,15 @@ class Misc(bonsai.core.tool.Misc):
obj.matrix_world.translation = new_origin
@classmethod
def move_object_to_elevation(cls, obj, elevation):
def move_object_to_elevation(cls, obj: bpy.types.Object, elevation: float) -> None:
obj.matrix_world.translation[2] = elevation
@classmethod
def run_root_copy_class(cls, obj=None):
def run_root_copy_class(cls, obj: bpy.types.Object) -> ifcopenshell.entity_instance:
return bonsai.core.root.copy_class(tool.Ifc, tool.Collector, tool.Geometry, tool.Root, obj=obj)
@classmethod
def scale_object_to_height(cls, obj, height):
def scale_object_to_height(cls, obj: bpy.types.Object, height: float) -> None:
absolute_bound_box = [obj.matrix_world @ Vector(c) for c in obj.bound_box]
max_z = max([c[2] for c in absolute_bound_box])
min_z = min([c[2] for c in absolute_bound_box])
@@ -101,6 +107,7 @@ class Misc(bonsai.core.tool.Misc):
cls, objs: list[bpy.types.Object], cutter: bpy.types.Object
) -> list[bpy.types.Object]:
cutter_mesh = cutter.data
assert isinstance(cutter_mesh, bpy.types.Mesh)
bm = bmesh.new()
bm.from_mesh(cutter_mesh)
@@ -119,6 +126,7 @@ class Misc(bonsai.core.tool.Misc):
collection.objects.link(new_obj)
mod = new_obj.modifiers.new(type="BOOLEAN", name="Boolean")
assert isinstance(mod, bpy.types.BooleanModifier)
mod.object = cutter
with bpy.context.temp_override(object=new_obj):
bpy.ops.object.modifier_apply(modifier="Boolean")
@@ -126,6 +134,7 @@ class Misc(bonsai.core.tool.Misc):
bm_flipped.to_mesh(cutter_mesh)
mod = obj.modifiers.new(type="BOOLEAN", name="Boolean")
assert isinstance(mod, bpy.types.BooleanModifier)
mod.object = cutter
with bpy.context.temp_override(object=obj):
bpy.ops.object.modifier_apply(modifier="Boolean")
+13
View File
@@ -762,6 +762,12 @@ class Spatial(bonsai.core.tool.Spatial):
@classmethod
def get_x_y_z_h_mat_from_obj(cls, obj: bpy.types.Object) -> tuple[float, float, float, float, Matrix]:
"""
`x`, `y` - object's center XY in world space;\n
`z` - object's local Z- in world space;\n
`h` - object's Z dimension;\n
`mat` - object's matrix
"""
mat = obj.matrix_world
local_bbox_center = 0.125 * sum((Vector(b) for b in obj.bound_box), Vector())
global_bbox_center = mat @ local_bbox_center
@@ -774,6 +780,12 @@ class Spatial(bonsai.core.tool.Spatial):
@classmethod
def get_x_y_z_h_mat_from_cursor(cls) -> tuple[float, float, float, float, Matrix]:
"""
`x`, `y` - from cursor;\n
`z` - from default container Z location (if set);\n
`h` - default value of 3;\n
`mat` - identity matrix
"""
x, y, z = bpy.context.scene.cursor.location.xyz
if container := tool.Root.get_default_container():
if container_obj := tool.Ifc.get_object(container):
@@ -940,6 +952,7 @@ class Spatial(bonsai.core.tool.Spatial):
@classmethod
def edit_active_space_obj_from_mesh(cls, mesh: bpy.types.Mesh) -> None:
active_obj = bpy.context.active_object
assert active_obj and isinstance(active_obj.data, bpy.types.Mesh)
mesh.name = active_obj.data.name
mesh.BIMMeshProperties.ifc_definition_id = active_obj.data.BIMMeshProperties.ifc_definition_id
tool.Geometry.change_object_data(active_obj, mesh, is_global=True)
+2 -2
View File
@@ -50,8 +50,8 @@ HEADER_FIELDS = {
class Transaction:
def __init__(self, ifc_file):
self.file = ifc_file
def __init__(self, ifc_file: file):
self.file: file = ifc_file
self.operations = []
self.is_batched = False
self.batch_delete_index = 0