From 97d2e08286bd8cadffee7e4cf8991a36a5e0759b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Perdig=C3=A3o?= Date: Fri, 23 Aug 2024 17:32:08 -0300 Subject: [PATCH] Initial implementation of unit handling for wall polyline tool. The input panel now works with meters, millimeters and imperial units. --- .../bonsai/bim/module/model/decorator.py | 38 +++++++++- src/bonsai/bonsai/bim/module/model/wall.py | 3 +- src/bonsai/bonsai/tool/snap.py | 70 ++++++++++++++++--- 3 files changed, 99 insertions(+), 12 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/model/decorator.py b/src/bonsai/bonsai/bim/module/model/decorator.py index 2465770f81..c416bc3559 100644 --- a/src/bonsai/bonsai/bim/module/model/decorator.py +++ b/src/bonsai/bonsai/bim/module/model/decorator.py @@ -28,6 +28,7 @@ from bpy_extras import view3d_utils from mathutils import Vector, Matrix from gpu_extras.batch import batch_for_shader from typing import Union +from bonsai.bim.module.drawing.helper import format_distance def transparent_color(color, alpha=0.1): @@ -511,6 +512,15 @@ class PolylineDecorator: def draw_input_panel(self, context): texts = {"D": "Distance:", "A": "Angle:", "X": "X coord:", "Y": "Y coord:", "Z": "Z coord:", "AREA": "Area:"} + + unit_system = tool.Drawing.get_unit_system() + if unit_system == "IMPERIAL": + precision = context.scene.DocProperties.imperial_precision + factor = 3.28084 + else: + precision = None + factor = 1 + self.addon_prefs = tool.Blender.get_addon_preferences() self.font_id = 0 blf.size(self.font_id, 12) @@ -521,6 +531,15 @@ class PolylineDecorator: offset = 20 new_line = 20 for i, (key, value) in enumerate(self.input_panel.items()): + + if key != "A" and key != self.input_type: + value = float(value) + if context.scene.unit_settings.length_unit == 'MILLIMETERS': + value = value * 1000 + formatted_value = format_distance(value*factor, precision=precision, suppress_zero_inches=True, in_unit_length=True) + else: + formatted_value = value + if key not in list(texts.keys()): continue if key == self.input_type: @@ -528,7 +547,7 @@ class PolylineDecorator: else: blf.color(self.font_id, *color) blf.position(self.font_id, self.mouse_pos[0] + offset, self.mouse_pos[1] - (new_line * i), 0) - blf.draw(self.font_id, texts[key] + value) + blf.draw(self.font_id, texts[key] + formatted_value) def draw_measurements(self, context): region = context.region @@ -550,8 +569,23 @@ class PolylineDecorator: continue pos_dim = (Vector(measurement_prop[i].position) + Vector(measurement_prop[i-1].position)) / 2 coords_dim = view3d_utils.location_3d_to_region_2d(region, rv3d, pos_dim) + + unit_system = tool.Drawing.get_unit_system() + if unit_system == "IMPERIAL": + precision = context.scene.DocProperties.imperial_precision + factor = 3.28084 + else: + precision = None + factor = 1 + + value = measurement_prop[i].dim + value = float(value) + if context.scene.unit_settings.length_unit == 'MILLIMETERS': + value = value * 1000 + formatted_value = format_distance(value*factor, precision=precision, suppress_zero_inches=True, in_unit_length=True) + blf.position(self.font_id, coords_dim[0], coords_dim[1], 0) - blf.draw(self.font_id, "d: " + measurement_prop[i].dim) + blf.draw(self.font_id, "d: " + formatted_value) pos_angle = measurement_prop[i-1].position coords_angle = view3d_utils.location_3d_to_region_2d(region, rv3d, pos_angle) diff --git a/src/bonsai/bonsai/bim/module/model/wall.py b/src/bonsai/bonsai/bim/module/model/wall.py index 1d3c31c6ae..769b5bb84b 100644 --- a/src/bonsai/bonsai/bim/module/model/wall.py +++ b/src/bonsai/bonsai/bim/module/model/wall.py @@ -294,7 +294,7 @@ class DrawPolylineWall(bpy.types.Operator): self.action_count = 0 self.visible_objs = [] self.objs_2d_bbox = [] - self.number_options = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "+", "-", "*", "/"} + self.number_options = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", " ", ".", "+", "-", "*", "/", "'", "\"", "="} self.number_input = [] self.number_output = "" self.number_is_negative = False @@ -416,6 +416,7 @@ class DrawPolylineWall(bpy.types.Operator): self.is_input_on = True self.input_type = event.type self.number_input = [] + self.input_panel[self.input_type] = "" PolylineDecorator.set_input_panel(self.input_panel, self.input_type) tool.Blender.update_viewport() diff --git a/src/bonsai/bonsai/tool/snap.py b/src/bonsai/bonsai/tool/snap.py index 64721295d1..23b5c8e94e 100644 --- a/src/bonsai/bonsai/tool/snap.py +++ b/src/bonsai/bonsai/tool/snap.py @@ -455,10 +455,21 @@ class Snap(bonsai.core.tool.Snap): @classmethod def validate_input(cls, input_number): + grammar = """ - start: dim expr? - dim: NUMBER - expr: (ADD | SUB | MUL | DIV) NUMBER + start: FORMULA? dim expr? + dim: metric | imperial + + FORMULA: "=" + + metric: NUMBER + + imperial: feet? "-"? inches? + feet: NUMBER? " "? fraction? "'" + inches: NUMBER? " "? fraction? "\\"" + fraction: NUMBER "/" NUMBER + + expr: (ADD | SUB | MUL | DIV) dim NUMBER: /-?\\d+(?:\\.\\d+)?/ ADD: "+" @@ -470,8 +481,34 @@ class Snap(bonsai.core.tool.Snap): """ class InputTransform(Transformer): + def NUMBER(self, n): + return float(n) + + def fraction(self, numbers): + return numbers[0] / numbers[1] + + def inches(self, args): + if len(args) > 1: + result = (args[0] + args[1]) + else: + result = args[0] + return result / 12 + + def feet(self, args): + return args[0] + + def imperial(self, args): + if len(args) > 1: + result = (args[0] + args[1]) + else: + result = args[0] + return result * 0.3048 + + def metric(self, args): + return args[0] + def dim(self, args): - return float(args[0]) + return args[0] def expr(self, args): op = args[0] @@ -485,17 +522,32 @@ class Snap(bonsai.core.tool.Snap): elif op == "/": return lambda x: x / value + def FORMULA(cls, args): + return args[0] + def start(self, args): - dimension = args[0] - if len(args) > 1: - expression = args[1] + i = 0 + if args[0] == "=": + i += 1 + else: + if len(args) > 1: + raise ValueError("Invalid input.") + dimension = args[i] + if len(args) > i+1: + expression = args[i + 1] return expression(dimension) else: return dimension + try: - parser = Lark(grammar, parser="lalr", transformer=InputTransform()) - result = parser.parse(input_number) + parser = Lark(grammar) + parse_tree = parser.parse(input_number) + + transformer = InputTransform() + result = transformer.transform(parse_tree) + if bpy.context.scene.unit_settings.length_unit == 'MILLIMETERS': + result /= 1000 return True, str(result) except: return False, "0"