From 4ce7a898c942d73e3143cf1688a5935f945f6bde Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Thu, 28 Mar 2024 12:26:19 +0500 Subject: [PATCH] typing, format --- .../blenderbim/bim/module/geometry/helper.py | 17 ++++--- .../blenderbim/bim/module/model/slab.py | 11 ++--- src/blenderbim/blenderbim/core/tool.py | 2 +- src/blenderbim/blenderbim/tool/model.py | 45 +++++++++++-------- 4 files changed, 44 insertions(+), 31 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/geometry/helper.py b/src/blenderbim/blenderbim/bim/module/geometry/helper.py index 383bdb6a4b..6f7374f80c 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/helper.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/helper.py @@ -23,10 +23,11 @@ import ifcopenshell import ifcopenshell.util.unit from math import pi, pow from mathutils import Vector, Matrix, geometry +from typing import Union class Helper: - def __init__(self, file): + def __init__(self, file: ifcopenshell.file): self.file = file self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file) @@ -34,7 +35,7 @@ class Helper: # edge that shares a single vertex only with that face to find the extrusion # edge. A face with the normal facing down is prioritised. A limited # dissolve ensure that faces are quads and not tris. - def auto_detect_rectangle_profile_extruded_area_solid(self, mesh): + def auto_detect_rectangle_profile_extruded_area_solid(self, mesh: bpy.types.Mesh) -> dict: bm = bmesh.new() bm.from_mesh(mesh) bmesh.ops.dissolve_limit(bm, angle_limit=pi / 180 * 1, verts=bm.verts, edges=bm.edges) @@ -115,7 +116,9 @@ class Helper: return {"profile": profile, "extrusion": extrusion} - def auto_detect_arbitrary_profile_with_voids(self, obj, mesh): + def auto_detect_arbitrary_profile_with_voids( + self, obj: bpy.types.Object, mesh: bpy.types.Mesh + ) -> Union[tuple, dict]: groups = {"IFCARCINDEX": [], "IFCCIRCLE": []} for i, group in enumerate(obj.vertex_groups): if "IFCARCINDEX" in group.name: @@ -148,18 +151,18 @@ class Helper: if total_groups > 1: # A vert can only belong to one group return (False, "AMBIGUOUS_SPECIAL_VERTEX") elif is_circle: - pass # Circles are allowed to be unclosed + pass # Circles are allowed to be unclosed elif total_groups == 0 and len(vert.link_edges) != 2: # Unclosed loop or forked loop return (False, "UNCLOSED_LOOP") for group_type, group_counts in group_verts.items(): if group_type == "IFCARCINDEX": for group_count in group_counts.values(): - if group_count != 3: # Each arc needs 3 verts + if group_count != 3: # Each arc needs 3 verts return (False, "3POINT_ARC") elif group_type == "IFCCIRCLE": for group_count in group_counts.values(): - if group_count != 2: # Each circle needs 2 verts + if group_count != 2: # Each circle needs 2 verts return (False, "CIRCLE") loop_edges = set(bm.edges) @@ -269,7 +272,7 @@ class Helper: inner_loops.remove(outer_loop) # Copy vectors to prevent random data mangling after bmesh is freed. - points = [Vector(list(v.co)) for v in bm.verts] + points = [v.co.copy() for v in bm.verts] bm.to_mesh(mesh) mesh.update() diff --git a/src/blenderbim/blenderbim/bim/module/model/slab.py b/src/blenderbim/blenderbim/bim/module/model/slab.py index 624d41e2bd..fb042a9046 100644 --- a/src/blenderbim/blenderbim/bim/module/model/slab.py +++ b/src/blenderbim/blenderbim/bim/module/model/slab.py @@ -20,9 +20,12 @@ import bpy import json import bmesh import ifcopenshell -import ifcopenshell.util.type -import ifcopenshell.util.unit +import ifcopenshell.api import ifcopenshell.util.element +import ifcopenshell.util.placement +import ifcopenshell.util.representation +import ifcopenshell.util.unit +import ifcopenshell.util.type import blenderbim.bim.handler import blenderbim.core.type import blenderbim.core.geometry @@ -698,9 +701,7 @@ class EditExtrusionProfile(bpy.types.Operator, tool.Ifc.Operator): 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" - ) + 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) diff --git a/src/blenderbim/blenderbim/core/tool.py b/src/blenderbim/blenderbim/core/tool.py index 54bc12d513..c3688ab283 100644 --- a/src/blenderbim/blenderbim/core/tool.py +++ b/src/blenderbim/blenderbim/core/tool.py @@ -519,7 +519,7 @@ class Misc: class Model: def convert_si_to_unit(cls, value): pass def convert_unit_to_si(cls, value): pass - def export_curve(cls, position, edge_indices, points=None): pass + def export_curve(cls, position, edge_indices): pass def export_points(cls, position, indices): pass def export_profile(cls, obj, position=None): pass def generate_occurrence_name(cls, element_type, ifc_class): pass diff --git a/src/blenderbim/blenderbim/tool/model.py b/src/blenderbim/blenderbim/tool/model.py index 95fe41da0c..32c2856389 100644 --- a/src/blenderbim/blenderbim/tool/model.py +++ b/src/blenderbim/blenderbim/tool/model.py @@ -20,6 +20,7 @@ import bpy import json import bmesh import collections +import collections.abc import numpy as np import ifcopenshell import ifcopenshell.util.unit @@ -36,23 +37,26 @@ from blenderbim.bim import import_ifc from blenderbim.bim.module.geometry.helper import Helper from blenderbim.bim.module.model.data import AuthoringData, RailingData, RoofData, WindowData, DoorData from ifcopenshell.util.shape_builder import V, ShapeBuilder +from typing import Optional, Union, TypeVar, Any + +T = TypeVar("T") class Model(blenderbim.core.tool.Model): @classmethod - def convert_si_to_unit(cls, value): + def convert_si_to_unit(cls, value: T) -> T: if isinstance(value, (tuple, list)): return [v / cls.unit_scale for v in value] return value / cls.unit_scale @classmethod - def convert_unit_to_si(cls, value): + def convert_unit_to_si(cls, value: T) -> T: if isinstance(value, (tuple, list)): return [v * cls.unit_scale for v in value] return value * cls.unit_scale @classmethod - def convert_data_to_project_units(cls, data, non_si_props=[]): + def convert_data_to_project_units(cls, data: dict[str, Any], non_si_props: list[str] = []) -> dict[str, Any]: si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) for prop_name in data: if prop_name in non_si_props: @@ -65,7 +69,7 @@ class Model(blenderbim.core.tool.Model): return data @classmethod - def convert_data_to_si_units(cls, data, non_si_props=[]): + def convert_data_to_si_units(cls, data: dict[str, Any], non_si_props: list[str] = []) -> dict[str, Any]: si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) for prop_name in data: if prop_name in non_si_props: @@ -78,34 +82,35 @@ class Model(blenderbim.core.tool.Model): return data @classmethod - def export_curve(cls, position, edge_indices, points=None): + def export_curve(cls, position: Matrix, edge_indices: list[tuple[int, int]]) -> ifcopenshell.entity_instance: position_i = position.inverted() + ifc_file = tool.Ifc.get() if len(edge_indices) == 2: diameter = edge_indices[0] p1 = cls.bm.verts[diameter[0]].co p2 = cls.bm.verts[diameter[1]].co center = cls.convert_si_to_unit(list(position_i @ p1.lerp(p2, 0.5))) radius = cls.convert_si_to_unit((p1 - p2).length / 2) - return tool.Ifc.get().createIfcCircle( - tool.Ifc.get().createIfcAxis2Placement2D(tool.Ifc.get().createIfcCartesianPoint(center[0:2])), radius + return ifc_file.createIfcCircle( + ifc_file.createIfcAxis2Placement2D(ifc_file.createIfcCartesianPoint(center[0:2])), radius ) - if tool.Ifc.get().schema == "IFC2X3": + if ifc_file.schema == "IFC2X3": points = [] for edge in edge_indices: local_point = (position_i @ Vector(cls.bm.verts[edge[0]].co)).to_2d() - points.append(tool.Ifc.get().createIfcCartesianPoint(cls.convert_si_to_unit(local_point))) + points.append(ifc_file.createIfcCartesianPoint(cls.convert_si_to_unit(local_point))) points.append(points[0]) - return tool.Ifc.get().createIfcPolyline(points) + return ifc_file.createIfcPolyline(points) segments = [] for segment in edge_indices: if len(segment) == 2: - segments.append(tool.Ifc.get().createIfcLineIndex([i + 1 for i in segment])) + segments.append(ifc_file.createIfcLineIndex([i + 1 for i in segment])) elif len(segment) == 3: - segments.append(tool.Ifc.get().createIfcArcIndex([i + 1 for i in segment])) - return tool.Ifc.get().createIfcIndexedPolyCurve(cls.points, segments, False) + segments.append(ifc_file.createIfcArcIndex([i + 1 for i in segment])) + return ifc_file.createIfcIndexedPolyCurve(cls.points, segments, False) @classmethod - def export_points(cls, position, indices): + def export_points(cls, position: Matrix, indices: list[Vector]) -> ifcopenshell.entity_instance: position_i = position.inverted() points = [] for point in indices: @@ -114,7 +119,10 @@ class Model(blenderbim.core.tool.Model): return tool.Ifc.get().createIfcCartesianPointList2D(points) @classmethod - def export_profile(cls, obj, position=None): + def export_profile( + cls, obj: bpy.types.Object, position: Optional[Matrix] = None + ) -> Union[ifcopenshell.entity_instance, None]: + """Returns `None` in case if profile was invalid.""" if position is None: position = Matrix() @@ -150,7 +158,7 @@ class Model(blenderbim.core.tool.Model): return profile @classmethod - def export_surface(cls, obj): + def export_surface(cls, obj: bpy.types.Object) -> Union[ifcopenshell.entity_instance, None]: p1, p2, p3 = [v.co.copy() for v in obj.data.vertices[0:3]] edge1 = p2 - p1 @@ -202,7 +210,7 @@ class Model(blenderbim.core.tool.Model): return surface @classmethod - def generate_occurrence_name(cls, element_type: ifcopenshell.entity_instance, ifc_class: str): + def generate_occurrence_name(cls, element_type: ifcopenshell.entity_instance, ifc_class: str) -> str: props = bpy.context.scene.BIMModelProperties if props.occurrence_name_style == "CLASS": return ifc_class[3:] @@ -216,7 +224,8 @@ class Model(blenderbim.core.tool.Model): return "Instance" @classmethod - def get_extrusion(cls, representation): + def get_extrusion(cls, representation: ifcopenshell.entity_instance) -> Union[ifcopenshell.entity_instance, None]: + """return first found IfcExtrudedAreaSolid""" item = representation.Items[0] while True: if item.is_a("IfcExtrudedAreaSolid"):