This commit is contained in:
Andrej730
2024-12-30 12:10:23 +05:00
parent da9cbbc61b
commit 6965399b2a
5 changed files with 42 additions and 24 deletions
@@ -38,7 +38,7 @@ import bonsai.core.root
import bonsai.core.drawing import bonsai.core.drawing
import bonsai.tool as tool import bonsai.tool as tool
import bonsai.bim.handler import bonsai.bim.handler
from mathutils import Vector, Matrix from mathutils import Vector, Matrix, Quaternion
from time import time from time import time
from bonsai.bim.ifc import IfcStore from bonsai.bim.ifc import IfcStore
from ifcopenshell.util.shape_builder import ShapeBuilder from ifcopenshell.util.shape_builder import ShapeBuilder
@@ -1399,9 +1399,9 @@ class RefreshLinkedAggregate(bpy.types.Operator, tool.Ifc.Operator):
self.pset_name = "BBIM_Linked_Aggregate" self.pset_name = "BBIM_Linked_Aggregate"
refresh_start_time = time() refresh_start_time = time()
old_to_new = {} old_to_new = {}
original_names = {} original_names: dict[int, dict[int, str]] = {}
def delete_objects(element): def delete_objects(element: ifcopenshell.entity_instance) -> None:
parts = ifcopenshell.util.element.get_parts(element) parts = ifcopenshell.util.element.get_parts(element)
if parts: if parts:
for part in parts: for part in parts:
@@ -1412,7 +1412,7 @@ class RefreshLinkedAggregate(bpy.types.Operator, tool.Ifc.Operator):
tool.Geometry.delete_ifc_object(tool.Ifc.get_object(element)) tool.Geometry.delete_ifc_object(tool.Ifc.get_object(element))
def get_original_names(element): def get_original_names(element: ifcopenshell.entity_instance) -> dict[int, dict[int, str]]:
group = [ group = [
r.RelatingGroup r.RelatingGroup
for r in getattr(element, "HasAssignments", []) or [] for r in getattr(element, "HasAssignments", []) or []
@@ -1429,6 +1429,7 @@ class RefreshLinkedAggregate(bpy.types.Operator, tool.Ifc.Operator):
if parts: if parts:
for part in parts: for part in parts:
if part.is_a("IfcElementAssembly"): if part.is_a("IfcElementAssembly"):
# TODO: missing assignment.
original_names | get_original_names(part) original_names | get_original_names(part)
else: else:
try: try:
@@ -1441,7 +1442,7 @@ class RefreshLinkedAggregate(bpy.types.Operator, tool.Ifc.Operator):
return original_names return original_names
def set_original_name(obj, original_names): def set_original_name(obj: bpy.types.Object, original_names: dict[int, dict[int, str]]) -> None:
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
aggregate = ifcopenshell.util.element.get_aggregate(element) aggregate = ifcopenshell.util.element.get_aggregate(element)
if ifcopenshell.util.element.get_parts( if ifcopenshell.util.element.get_parts(
@@ -1468,7 +1469,7 @@ class RefreshLinkedAggregate(bpy.types.Operator, tool.Ifc.Operator):
except: except:
return return
def get_element_assembly(element): def get_element_assembly(element: ifcopenshell.entity_instance) -> Union[ifcopenshell.entity_instance, None]:
if element.is_a("IfcElementAssembly"): if element.is_a("IfcElementAssembly"):
return element return element
elif element.Decomposes: elif element.Decomposes:
@@ -1478,7 +1479,9 @@ class RefreshLinkedAggregate(bpy.types.Operator, tool.Ifc.Operator):
else: else:
return None return None
def handle_selection(selected_objs): def handle_selection(
selected_objs: list[bpy.types.Object],
) -> tuple[list[int], list[ifcopenshell.entity_instance]]:
selected_elements = [tool.Ifc.get_entity(selected_obj) for selected_obj in selected_objs] selected_elements = [tool.Ifc.get_entity(selected_obj) for selected_obj in selected_objs]
if None in selected_elements: if None in selected_elements:
self.report({"INFO"}, "Object has no Ifc Metadata.") self.report({"INFO"}, "Object has no Ifc Metadata.")
@@ -1509,7 +1512,9 @@ class RefreshLinkedAggregate(bpy.types.Operator, tool.Ifc.Operator):
return list(set(linked_aggregate_groups)), selected_parents return list(set(linked_aggregate_groups)), selected_parents
def get_original_matrix(element, base_instance): def get_original_matrix(
element: ifcopenshell.entity_instance, base_instance: ifcopenshell.entity_instance
) -> tuple[Matrix, tuple[Vector, Quaternion, Vector]]:
selected_obj = tool.Ifc.get_object(base_instance) selected_obj = tool.Ifc.get_object(base_instance)
selected_matrix = selected_obj.matrix_world selected_matrix = selected_obj.matrix_world
object_duplicate = tool.Ifc.get_object(element) object_duplicate = tool.Ifc.get_object(element)
@@ -1517,7 +1522,9 @@ class RefreshLinkedAggregate(bpy.types.Operator, tool.Ifc.Operator):
return selected_matrix, duplicate_matrix return selected_matrix, duplicate_matrix
def set_new_matrix(selected_matrix, duplicate_matrix, old_to_new): def set_new_matrix(
selected_matrix: Matrix, duplicate_matrix: tuple[Vector, Quaternion, Vector], old_to_new: dict
) -> None:
for old, new in old_to_new.items(): for old, new in old_to_new.items():
new_obj = tool.Ifc.get_object(new[0]) new_obj = tool.Ifc.get_object(new[0])
new_base_matrix = Matrix.LocRotScale(*duplicate_matrix) new_base_matrix = Matrix.LocRotScale(*duplicate_matrix)
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>. # along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import bpy import bpy
import copy import copy
import math import math
@@ -46,6 +47,9 @@ class PolylineOperator:
# TODO Fill doc strings # TODO Fill doc strings
""" """ """ """
number_input: list[str]
input_type: tool.Polyline.InputType
@classmethod @classmethod
def poll(cls, context: bpy.types.Context) -> bool: def poll(cls, context: bpy.types.Context) -> bool:
return context.space_data.type == "VIEW_3D" return context.space_data.type == "VIEW_3D"
@@ -81,7 +85,6 @@ class PolylineOperator:
self.number_is_negative = False self.number_is_negative = False
self.input_options = ["D", "A", "X", "Y"] self.input_options = ["D", "A", "X", "Y"]
self.input_type = None self.input_type = None
self.input_type = None
self.input_value_xy = [None, None] self.input_value_xy = [None, None]
self.input_ui = tool.Polyline.create_input_ui() self.input_ui = tool.Polyline.create_input_ui()
self.is_typing = False self.is_typing = False
+6 -6
View File
@@ -41,7 +41,7 @@ from mathutils import Vector, Matrix
from bonsai.bim.module.model.opening import FilledOpeningGenerator from bonsai.bim.module.model.opening import FilledOpeningGenerator
from bonsai.bim.module.model.decorator import PolylineDecorator, ProductDecorator from bonsai.bim.module.model.decorator import PolylineDecorator, ProductDecorator
from bonsai.bim.module.model.polyline import PolylineOperator from bonsai.bim.module.model.polyline import PolylineOperator
from typing import Optional, assert_never, TYPE_CHECKING, get_args, Literal from typing import Optional, assert_never, TYPE_CHECKING, get_args, Literal, Union, Any
from lark import Lark, Transformer from lark import Lark, Transformer
@@ -330,7 +330,7 @@ class DrawPolylineWall(bpy.types.Operator, PolylineOperator):
if relating_type_id: if relating_type_id:
self.relating_type = tool.Ifc.get().by_id(int(relating_type_id)) self.relating_type = tool.Ifc.get().by_id(int(relating_type_id))
def create_walls_from_polyline(self, context): def create_walls_from_polyline(self, context: bpy.types.Context) -> Union[set[str], None]:
if not self.relating_type: if not self.relating_type:
return {"FINISHED"} return {"FINISHED"}
@@ -587,7 +587,7 @@ class DumbWallGenerator:
and bpy.context.scene.grease_pencil.layers[0].active_frame.strokes and bpy.context.scene.grease_pencil.layers[0].active_frame.strokes
) )
def derive_from_polyline(self): def derive_from_polyline(self) -> tuple[list[Union[dict[str, Any], None]], bool]:
polyline_data = bpy.context.scene.BIMPolylineProperties.insertion_polyline polyline_data = bpy.context.scene.BIMPolylineProperties.insertion_polyline
polyline_points = polyline_data[0].polyline_points if polyline_data else [] polyline_points = polyline_data[0].polyline_points if polyline_data else []
is_polyline_closed = False is_polyline_closed = False
@@ -658,7 +658,7 @@ class DumbWallGenerator:
bpy.context.scene.grease_pencil.layers.remove(layer) bpy.context.scene.grease_pencil.layers.remove(layer)
return objs return objs
def create_wall_from_2_points(self, coords, should_round=False): def create_wall_from_2_points(self, coords, should_round=False) -> Union[dict[str, Any], None]:
direction = coords[1] - coords[0] direction = coords[1] - coords[0]
length = direction.length length = direction.length
if round(length, 4) < 0.1: if round(length, 4) < 0.1:
@@ -696,7 +696,7 @@ class DumbWallGenerator:
def is_near(self, point1, point2): def is_near(self, point1, point2):
return (point1 - point2).length < 0.1 return (point1 - point2).length < 0.1
def derive_from_cursor(self): def derive_from_cursor(self) -> bpy.types.Object:
RAYCAST_PRECISION = 0.01 RAYCAST_PRECISION = 0.01
self.location = bpy.context.scene.cursor.location self.location = bpy.context.scene.cursor.location
if self.container: if self.container:
@@ -746,7 +746,7 @@ class DumbWallGenerator:
break break
return self.create_wall() return self.create_wall()
def create_wall(self): def create_wall(self) -> bpy.types.Object:
props = bpy.context.scene.BIMModelProperties props = bpy.context.scene.BIMModelProperties
ifc_class = self.get_relating_type_class(self.relating_type) ifc_class = self.get_relating_type_class(self.relating_type)
mesh = bpy.data.meshes.new("Dummy") mesh = bpy.data.meshes.new("Dummy")
+15 -7
View File
@@ -26,7 +26,7 @@ from dataclasses import dataclass
from lark import Lark, Transformer from lark import Lark, Transformer
from math import degrees, radians, sin, cos, tan from math import degrees, radians, sin, cos, tan
from mathutils import Vector, Matrix from mathutils import Vector, Matrix
from typing import Optional, Union from typing import Optional, Union, Literal
class Polyline(bonsai.core.tool.Polyline): class Polyline(bonsai.core.tool.Polyline):
@@ -75,6 +75,8 @@ class Polyline(bonsai.core.tool.Polyline):
else: else:
return Polyline.format_input_ui_units(value) return Polyline.format_input_ui_units(value)
InputType = Literal["D", "A", "X", "Y", None]
@dataclass @dataclass
class ToolState: class ToolState:
use_default_container: bool = None use_default_container: bool = None
@@ -83,8 +85,8 @@ class Polyline(bonsai.core.tool.Polyline):
lock_axis: bool = False lock_axis: bool = False
# angle_axis_start: Vector # angle_axis_start: Vector
# angle_axis_end: Vector # angle_axis_end: Vector
axis_method: str = None axis_method: Literal["X", "Y", "Z", None] = None
plane_method: str = None plane_method: Literal["XY", "XZ", "YZ", None] = None
plane_origin: Vector = Vector((0.0, 0.0, 0.0)) plane_origin: Vector = Vector((0.0, 0.0, 0.0))
instructions: str = """TAB: Cycle Input instructions: str = """TAB: Cycle Input
M: Modify Snap Point M: Modify Snap Point
@@ -94,8 +96,8 @@ class Polyline(bonsai.core.tool.Polyline):
L: Lock axis L: Lock axis
""" """
snap_info: str = None snap_info: str = None
mode: str = None mode: Literal["Mouse", "Select", "Edit", None] = None
input_type: str = None input_type: "Polyline.InputType" = None
@classmethod @classmethod
def create_input_ui(cls, init_z: bool = False, init_area: bool = False) -> PolylineUI: def create_input_ui(cls, init_z: bool = False, init_area: bool = False) -> PolylineUI:
@@ -307,7 +309,13 @@ class Polyline(bonsai.core.tool.Polyline):
return return
@classmethod @classmethod
def validate_input(cls, input_number, input_type) -> tuple[bool, str]: def validate_input(cls, input_number: str, input_type: InputType) -> tuple[bool, str]:
"""
:return: Tuple with a boolean indicating if the input is valid
and the final string output.
Distance units converted to meters, angles input/output is in degrees.
"""
grammar_imperial = """ grammar_imperial = """
start: (FORMULA dim expr) | dim start: (FORMULA dim expr) | dim
@@ -395,7 +403,7 @@ class Polyline(bonsai.core.tool.Polyline):
elif op == "/": elif op == "/":
return lambda x: x / value return lambda x: x / value
def FORMULA(cls, args): def FORMULA(self, args):
return args[0] return args[0]
def start(self, args): def start(self, args):
+1 -1
View File
@@ -250,7 +250,7 @@ class Snap(bonsai.core.tool.Snap):
return sorted_intersections return sorted_intersections
@classmethod @classmethod
def detect_snapping_points(cls, context, event, objs_2d_bbox, tool_state): def detect_snapping_points(cls, context: bpy.types.Context, event: bpy.types.Event, objs_2d_bbox, tool_state):
rv3d = context.region_data rv3d = context.region_data
space = context.space_data space = context.space_data
mouse_pos = event.mouse_region_x, event.mouse_region_y mouse_pos = event.mouse_region_x, event.mouse_region_y