mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 02:02:22 +00:00
typing
This commit is contained in:
@@ -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":
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user