Initial implementation of unit handling for wall polyline tool.

The input panel now works with meters, millimeters and imperial units.
This commit is contained in:
Bruno Perdigão
2024-08-23 17:32:08 -03:00
parent f440a3ca17
commit 97d2e08286
3 changed files with 99 additions and 12 deletions
@@ -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)
+2 -1
View File
@@ -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()
+61 -9
View File
@@ -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"