Changed input validantion to Snap tool

This commit is contained in:
Bruno Perdigão
2024-08-13 17:32:57 -03:00
committed by Bruno Perdigão
parent d1d9db3ed8
commit b137197586
3 changed files with 94 additions and 12 deletions
@@ -21,7 +21,7 @@ import gpu
import gpu_extras import gpu_extras
import bmesh import bmesh
import bonsai.tool as tool import bonsai.tool as tool
from math import sin, cos, radians from math import sin, cos, radians, degrees, atan2, acos
from bpy.types import SpaceView3D from bpy.types import SpaceView3D
from mathutils import Vector, Matrix from mathutils import Vector, Matrix
from gpu_extras.batch import batch_for_shader from gpu_extras.batch import batch_for_shader
@@ -343,12 +343,22 @@ class WallPolylineDecorator:
@classmethod @classmethod
def calculate_distance_and_angle(cls, context, is_input_on): def calculate_distance_and_angle(cls, context, is_input_on):
def calculate_angle(snap_vector, last_point, second_to_last_point):
v1 = snap_vector - last_point
v2 = last_point - second_to_last_point
cos_angle = (v1.dot(v2)) / (v1.length * v2.length)
if cos_angle > 1:
cos_angle = 1
angle = acos(cos_angle)
return degrees(angle)
try: try:
polyline_data = context.scene.BIMModelProperties.polyline_point polyline_data = context.scene.BIMModelProperties.polyline_point
default_container_elevation = tool.Ifc.get_object(tool.Root.get_default_container()).location.z default_container_elevation = tool.Ifc.get_object(tool.Root.get_default_container()).location.z
last_point_data = polyline_data[len(polyline_data) - 1] last_point_data = polyline_data[len(polyline_data) - 1]
except: except:
last_point_data = None last_point_data = None
second_to_last_point_data = None
default_container_elevation = 0 default_container_elevation = 0
snap_prop = context.scene.BIMModelProperties.snap_mouse_point[0] snap_prop = context.scene.BIMModelProperties.snap_mouse_point[0]
@@ -358,6 +368,11 @@ class WallPolylineDecorator:
else: else:
last_point = Vector((0, 0, 0)) last_point = Vector((0, 0, 0))
second_to_last_point = None
if len(polyline_data) > 1:
second_to_last_point_data = polyline_data[len(polyline_data) - 2]
second_to_last_point = Vector((second_to_last_point_data.x, second_to_last_point_data.y, second_to_last_point_data.z))
if is_input_on: if is_input_on:
snap_vector = Vector( snap_vector = Vector(
(float(cls.input_panel["X"]), float(cls.input_panel["Y"]), default_container_elevation) (float(cls.input_panel["X"]), float(cls.input_panel["Y"]), default_container_elevation)
@@ -373,12 +388,22 @@ class WallPolylineDecorator:
Vector((0, 0)), Vector((0, 0)),
Vector((1, 0)), Vector((1, 0)),
) )
if second_to_last_point:
previous_axis = (
Vector((second_to_last_point.x, second_to_last_point.y)),
Vector((last_point.x, last_point.y)),
)
else:
second_to_last_point = Vector((last_point.x + 10, last_point.y, last_point.z))
previous_axis = x_axis_edge
current_axis = ( current_axis = (
Vector((last_point.x, last_point.y)), Vector((last_point.x, last_point.y)),
Vector((snap_vector.x, snap_vector.y)), Vector((snap_vector.x, snap_vector.y)),
) )
if distance > 0: if distance > 0:
angle = tool.Cad.angle_edges(x_axis_edge, current_axis, degrees=True, signed=True) angle = tool.Cad.angle_3_vectors(snap_vector, last_point, second_to_last_point, degrees=True)
angle = 180 - angle
if cls.input_panel: if cls.input_panel:
cls.input_panel["X"] = str(round(snap_vector.x, 4)) cls.input_panel["X"] = str(round(snap_vector.x, 4))
cls.input_panel["Y"] = str(round(snap_vector.y, 4)) cls.input_panel["Y"] = str(round(snap_vector.y, 4))
@@ -400,11 +425,20 @@ class WallPolylineDecorator:
return return
last_point = Vector((last_point_data.x, last_point_data.y, last_point_data.z)) last_point = Vector((last_point_data.x, last_point_data.y, last_point_data.z))
second_to_last_point = None
if len(polyline_data) > 2:
second_to_last_point_data = polyline_data[len(polyline_data) - 2]
second_to_last_point = Vector((second_to_last_point_data.x, second_to_last_point_data.y, second_to_last_point_data.z))
else:
second_to_last_point = Vector((0, 0, 0))
distance = float(cls.input_panel["D"]) distance = float(cls.input_panel["D"])
if distance < 0 or distance > 0: if distance < 0 or distance > 0:
angle_degrees = float(cls.input_panel["A"]) angle_degrees = float(cls.input_panel["A"])
angle_radians = radians(360 - angle_degrees) # Substracting from 360 to make it clockwise reference_vector = second_to_last_point - last_point
reference_angle = degrees(atan2(reference_vector[1], reference_vector[0]))
angle_radians = radians(360 - (angle_degrees - reference_angle)) # Substracting from 360 to make it clockwise
x = last_point[0] + distance * cos(angle_radians) x = last_point[0] + distance * cos(angle_radians)
y = last_point[1] + distance * sin(angle_radians) y = last_point[1] + distance * sin(angle_radians)
if cls.input_panel: if cls.input_panel:
@@ -503,11 +537,9 @@ class WallPolylineDecorator:
# Line between last polyline point and mouse # Line between last polyline point and mouse
edges = [[0, 1]] edges = [[0, 1]]
if polyline_points: if polyline_points:
print("PP", polyline_points)
if snap_prop.snap_type != "Plane" and projection_point: if snap_prop.snap_type != "Plane" and projection_point:
self.draw_batch("LINES", [polyline_points[-1]] + projection_point, decorator_color_unselected, edges) self.draw_batch("LINES", [polyline_points[-1]] + projection_point, decorator_color_unselected, edges)
else: else:
print("FOI")
self.draw_batch("LINES", [polyline_points[-1]] + mouse_point, decorator_color_unselected, edges) self.draw_batch("LINES", [polyline_points[-1]] + mouse_point, decorator_color_unselected, edges)
# Line for angle axis snap # Line for angle axis snap
+7 -7
View File
@@ -285,7 +285,6 @@ class DrawPolylineWall(bpy.types.Operator):
bl_label = "Draw Polyline Wall" bl_label = "Draw Polyline Wall"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
return context.space_data.type == "VIEW_3D" return context.space_data.type == "VIEW_3D"
@@ -482,14 +481,18 @@ class DrawPolylineWall(bpy.types.Operator):
def recalculate_inputs(self, context): def recalculate_inputs(self, context):
if self.number_input: if self.number_input:
is_valid, self.number_output = self.validate_input(self.number_output) is_valid, self.number_output = tool.Snap.validate_input(self.number_output)
self.input_panel[self.input_type] = self.number_output self.input_panel[self.input_type] = self.number_output
if is_valid: if not is_valid:
self.report({"WARNING"}, "The number typed is not valid.")
else:
if self.input_type in {"X", "Y"}: if self.input_type in {"X", "Y"}:
self.input_panel = WallPolylineDecorator.calculate_distance_and_angle(context, self.is_input_on) self.input_panel = WallPolylineDecorator.calculate_distance_and_angle(context, self.is_input_on)
elif self.input_type in {"D", "A"}: elif self.input_type in {"D", "A"}:
self.input_panel = WallPolylineDecorator.calculate_x_and_y(context) self.input_panel = WallPolylineDecorator.calculate_x_and_y(context)
self.input_panel[self.input_type] = self.number_output self.input_panel[self.input_type] = self.number_output
WallPolylineDecorator.set_input_panel(self.input_panel, self.input_type) WallPolylineDecorator.set_input_panel(self.input_panel, self.input_type)
tool.Blender.update_viewport() tool.Blender.update_viewport()
@@ -509,15 +512,12 @@ class DrawPolylineWall(bpy.types.Operator):
relating_type = tool.Ifc.get().by_id(int(relating_type_id)) relating_type = tool.Ifc.get().by_id(int(relating_type_id))
walls, is_polyline_closed = DumbWallGenerator(relating_type).generate(True) walls, is_polyline_closed = DumbWallGenerator(relating_type).generate(True)
print(is_polyline_closed)
if walls: if walls:
if is_polyline_closed: if is_polyline_closed:
for wall1, wall2 in zip(walls, walls[1:] + [walls[0]]): for wall1, wall2 in zip(walls, walls[1:] + [walls[0]]):
print(wall1["obj"], wall2["obj"])
DumbWallJoiner().join_V(wall1["obj"], wall2["obj"]) DumbWallJoiner().join_V(wall1["obj"], wall2["obj"])
else: else:
for wall1, wall2 in zip(walls[:-1], walls[1:]): for wall1, wall2 in zip(walls[:-1], walls[1:]):
print(wall1["obj"], wall2["obj"])
DumbWallJoiner().join_V(wall1["obj"], wall2["obj"]) DumbWallJoiner().join_V(wall1["obj"], wall2["obj"])
def modal(self, context, event): def modal(self, context, event):
@@ -660,7 +660,7 @@ class DrawPolylineWall(bpy.types.Operator):
WallPolylineDecorator.install(context) WallPolylineDecorator.install(context)
tool.Snap.set_use_default_container(True) tool.Snap.set_use_default_container(True)
WallPolylineDecorator.set_use_default_container(True) WallPolylineDecorator.set_use_default_container(True)
tool.Snap.set_snap_plane_method('XY') tool.Snap.set_snap_plane_method("XY")
WallPolylineDecorator.set_input_panel(self.input_panel, self.input_type) WallPolylineDecorator.set_input_panel(self.input_panel, self.input_type)
self.visible_objs = tool.Raycast.get_visible_objects(context) self.visible_objs = tool.Raycast.get_visible_objects(context)
for obj in self.visible_objs: for obj in self.visible_objs:
+50
View File
@@ -23,6 +23,7 @@ from bonsai.bim.module.model.decorator import WallPolylineDecorator
import math import math
import mathutils import mathutils
from mathutils import Matrix, Vector from mathutils import Matrix, Vector
from lark import Lark, Transformer
class Snap(bonsai.core.tool.Snap): class Snap(bonsai.core.tool.Snap):
@@ -327,3 +328,52 @@ class Snap(bonsai.core.tool.Snap):
cls.update_snaping_point(rot_intersection, "Axis") cls.update_snaping_point(rot_intersection, "Axis")
else: else:
cls.update_snaping_point(intersection, "Plane") cls.update_snaping_point(intersection, "Plane")
@classmethod
def validate_input(cls, input_number):
grammar = """
start: dim expr?
dim: NUMBER
expr: (ADD | SUB | MUL | DIV) NUMBER
NUMBER: /-?\\d+(?:\\.\\d+)?/
ADD: "+"
SUB: "-"
MUL: "*"
DIV: "/"
%ignore " "
"""
class InputTransform(Transformer):
def dim(self, args):
return float(args[0])
def expr(self, args):
op = args[0]
value = float(args[1])
if op == "+":
return lambda x: x + value
elif op == "-":
return lambda x: x - value
elif op == "*":
return lambda x: x * value
elif op == "/":
return lambda x: x / value
def start(self, args):
dimension = args[0]
if len(args) > 1:
expression = args[1]
return expression(dimension)
else:
return dimension
try:
parser = Lark(grammar, parser="lalr", transformer=InputTransform())
result = parser.parse(input_number)
return True, str(result)
except:
return False, "0"