mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-10-02 04:59:52 +00:00
Changed input validantion to Snap tool
This commit is contained in:
committed by
Bruno Perdigão
parent
d1d9db3ed8
commit
b137197586
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user