From 639828711618b9009f633552d914c6312cebddce Mon Sep 17 00:00:00 2001 From: Xeon0X Date: Tue, 4 Jun 2024 15:59:39 +0200 Subject: [PATCH] Refactor curved_corner_by_distance --- main.py | 14 +- networks/geometry/point_tools.py | 151 +++++++++++-------- networks/geometry/segment_tools.py | 2 - networks/roads/intersections/Intersection.py | 11 +- 4 files changed, 103 insertions(+), 75 deletions(-) diff --git a/main.py b/main.py index 16e1490..c1256bc 100644 --- a/main.py +++ b/main.py @@ -12,7 +12,7 @@ import random from networks.roads import Road as Road from networks.roads.intersections import Intersection as Intersection -from networks.geometry.point_tools import curved_corner_intersection +from networks.geometry.point_tools import curved_corner editor = Editor(buffering=True) @@ -111,12 +111,12 @@ block_list = ["blue_concrete", "red_concrete", "green_concrete", # print(l.get_surface()) -circle = curved_corner_intersection( - ((-1365, 520), (-1326, 523)), ((-1344, 496), (-1336, 535)), 10, angle_adaptation=False, output_only_points=False) +# circle = curved_corner( +# ((-1365, 520), (-1326, 523)), ((-1344, 496), (-1336, 535)), 10, angle_adaptation=False, output_only_points=False) -for coordinate in circle[0]: - editor.placeBlock( - (round(coordinate[0]), 125, round(coordinate[1])), Block("green_concrete")) +# for coordinate in circle[0]: +# editor.placeBlock( +# (round(coordinate[0]), 125, round(coordinate[1])), Block("green_concrete")) # --- @@ -194,4 +194,4 @@ for k in range(len(i.intersections_curved)): if coordinate != None: if k >= 0: editor.placeBlock( - (coordinate[0], 75, coordinate[1]), Block("cyan_concrete")) + (coordinate[0], 75, coordinate[1]), Block("brown_concrete")) diff --git a/networks/geometry/point_tools.py b/networks/geometry/point_tools.py index fa5942c..616d43c 100644 --- a/networks/geometry/point_tools.py +++ b/networks/geometry/point_tools.py @@ -1,6 +1,6 @@ from math import sqrt, cos, pi, sin import numpy as np -from networks.geometry.segment_tools import discrete_segment, middle_point +from networks.geometry.segment_tools import discrete_segment, middle_point, parallel def circle(center, radius): @@ -35,11 +35,11 @@ def circle(center, radius): def is_in_triangle(point, xy0, xy1, xy2): # https://stackoverflow.com/questions/2049582/how-to-determine-if-a-point-is-in-a-2d-triangle#:~:text=A%20simple%20way%20is%20to,point%20is%20inside%20the%20triangle. dX = point[0] - xy0[0] - dY = point[1] - xy0[1] + dY = point[-1] - xy0[-1] dX20 = xy2[0] - xy0[0] - dY20 = xy2[1] - xy0[1] + dY20 = xy2[-1] - xy0[-1] dX10 = xy1[0] - xy0[0] - dY10 = xy1[1] - xy0[1] + dY10 = xy1[-1] - xy0[-1] s_p = (dY20 * dX) - (dX20 * dY) t_p = (dX10 * dY) - (dY10 * dX) @@ -328,77 +328,48 @@ def perpendicular(distance, xy1, xy2): return ((round(x3), round(y3)), (round(x4), round(y4))) -def curved_corner_intersection( - line0, line1, start_distance, angle_adaptation=False, full_line=True, center=(), output_only_points=True +def curved_corner( + intersection, xyz0, xyz1, distance, curvature, full_line=True, output_only_points=True ): - """ - Create points between the two lines to smooth the intersection. + # If curvature radius is set, compute the center of the circle as the intersection between the two lines, offseted by the curvature radius. + if curvature != None: + center = segments_intersection(parallel( + (xyz0, intersection), curvature), parallel((xyz1, intersection), -curvature)) - Args: - line0 (tuple): Tuple of tuple. Line coordinates. Order matters. - line1 (tuple): Tuple of tuple. Line coordinates. Order matters. - start_distance (int): distance from the intersection where the - curve should starts. - angleAdaptation (bool, optional): True will adapt the - start_distance depending of the angle between the two lines. - False will force the distance to be start_distance. Defaults to - False. + # If distance is set, compute where the arc should merge on the two intersecting lines. + elif distance != None: + start_curve_point = circle_segment_intersection( + intersection, distance, xy0[0], intersection, full_line + )[0] + start_curve_point = ( + round(start_curve_point[0]), round(start_curve_point[-1])) - Returns: - [list]: List of tuple of coordinates (2d) that forms the curve. - Starts on the line and end on the other line. + end_curve_point = circle_segment_intersection( + intersection, distance, xy1[0], intersection, full_line + )[0] + end_curve_point = ( + round(end_curve_point[0]), round(end_curve_point[-1])) - >>> curved_corner_intersection(((0, 0), (50, 20)), ((-5, 50), (25, -5)), 10) - """ - print("\nInput:") - print(line0, line1) - intersection = segments_intersection(line0, line1, full_line) + # Then compute the center as the intersection between perpendicular segment at the points computed before. + # Higher value for better precision + perpendicular0 = perpendicular( + 10e3, start_curve_point, intersection)[0] + perpendicular1 = perpendicular(10e3, end_curve_point, intersection)[-1] - if intersection == None: - return None - - # Define automatically the distance from the intersection, where the curve - # starts. - if angle_adaptation: - angle = get_angle( - (line0[0][0], line0[0][-1]), - intersection, - (line1[0][0], line1[0][-1]), - ) - # Set here the radius of the circle for a square angle. - start_distance = start_distance * abs(1 / (angle / 90)) - - start_curve_point = circle_segment_intersection( - intersection, start_distance, line0[0], intersection, full_line - )[0] - start_curve_point = ( - round(start_curve_point[0]), round(start_curve_point[-1])) - end_curve_point = circle_segment_intersection( - intersection, start_distance, line1[0], intersection, full_line - )[0] - end_curve_point = (round(end_curve_point[0]), round(end_curve_point[-1])) - # Higher value for better precision - perpendicular0 = perpendicular(10e3, start_curve_point, intersection)[0] - perpendicular1 = perpendicular(10e3, end_curve_point, intersection)[-1] - - if center == (): center = segments_intersection( - (perpendicular0, start_curve_point), (perpendicular1, end_curve_point) - ) + (perpendicular0, start_curve_point), (perpendicular1, end_curve_point)) center = round(center[0]), round(center[-1]) - # Distance with startCurvePoint and endCurvePoint from the center are the - # same. - radius = round(distance(start_curve_point, center)) + curvature = round(distance(start_curve_point, center)) if output_only_points: circle_data = circle_points( - center, radius, 32 - ) # n=round((2 * pi * radius) / 32) + center, curvature, 32 + ) else: - circle_data = circle(center, radius)[0] + circle_data = circle(center, curvature) - # Find the correct point on the circle. + # Find the correct points on the circle. curved_corner_points_temporary = [start_curve_point] for point in circle_data: if is_in_triangle(point, intersection, start_curve_point, end_curve_point): @@ -410,4 +381,58 @@ def curved_corner_intersection( # Be sure that all the points are in correct order. curve_corner_points = optimized_path( curved_corner_points_temporary, start_curve_point) - return curve_corner_points, center, radius + return curve_corner_points, center, curvature + + +def curved_corner_by_distance( + intersection, xyz0, xyz1, distance_from_intersection, resolution, full_line=True +): + # Comute the merging point on the first line + start_curve_point = circle_segment_intersection( + intersection, distance_from_intersection, xyz0, intersection, full_line + )[0] + start_curve_point = ( + round(start_curve_point[0]), round(start_curve_point[-1])) + + # Comute the merging point on the second line + end_curve_point = circle_segment_intersection( + intersection, distance_from_intersection, xyz1, intersection, full_line + )[0] + end_curve_point = ( + round(end_curve_point[0]), round(end_curve_point[-1])) + + # Compute the intersection between perpendicular lines at the merging points + # Higher value for better precision + perpendicular0 = perpendicular( + 10e3, start_curve_point, intersection)[0] + perpendicular1 = perpendicular(10e3, end_curve_point, intersection)[-1] + + center = segments_intersection( + (perpendicular0, start_curve_point), (perpendicular1, end_curve_point)) + center = round(center[0]), round(center[-1]) + + # Compute the curvature for indications + curvature = round(distance(start_curve_point, center)) + + # Return a full discrete circle or only some points of it + if resolution != 0: + circle_data = circle_points( + center, curvature, resolution + ) + else: + circle_data = circle(center, curvature)[0] + + # Find the correct points on the circle. + curved_corner_points_temporary = [start_curve_point] + for point in circle_data: + print(point, intersection, start_curve_point, end_curve_point, is_in_triangle( + point, intersection, start_curve_point, end_curve_point)) + if is_in_triangle(point, intersection, start_curve_point, end_curve_point): + curved_corner_points_temporary.append( + (round(point[0]), round(point[1]))) + curved_corner_points_temporary.append(end_curve_point) + + # Be sure that all the points are in correct order. + curve_corner_points = optimized_path( + curved_corner_points_temporary, start_curve_point) + return curve_corner_points, center, curvature diff --git a/networks/geometry/segment_tools.py b/networks/geometry/segment_tools.py index f45f6ed..e2c5b0a 100644 --- a/networks/geometry/segment_tools.py +++ b/networks/geometry/segment_tools.py @@ -50,8 +50,6 @@ def orthogonal(origin, point, distance, normal=np.array([0, 1, 0])): orthogonal = np.cross(normalized_vector, normalized_normal) if np.array_equal(orthogonal, np.zeros((3,))): - print(normalized_vector, normalized_normal, orthogonal, normal) - print(origin, point, distance) raise ValueError("The input vectors are not linearly independent.") orthogonal = np.add(np.multiply(orthogonal, distance), origin).astype(int) diff --git a/networks/roads/intersections/Intersection.py b/networks/roads/intersections/Intersection.py index 1e80418..44e46c6 100644 --- a/networks/roads/intersections/Intersection.py +++ b/networks/roads/intersections/Intersection.py @@ -1,5 +1,5 @@ from networks.geometry.segment_tools import parallel, orthogonal -from networks.geometry.point_tools import sort_by_clockwise, segments_intersection, curved_corner_intersection +from networks.geometry.point_tools import sort_by_clockwise, segments_intersection, curved_corner_by_distance from networks.roads import Road @@ -33,5 +33,10 @@ class Intersection: current_parallel = tuple(self.parallel_delimitations[j][1][0]), tuple( self.parallel_delimitations[j][1][1]) - self.intersections_curved.append(curved_corner_intersection( - ((current_parallel[0][0], current_parallel[0][-1]), (current_parallel[1][0], current_parallel[1][-1])), ((next_parallel[0][0], next_parallel[0][-1]), (next_parallel[1][0], next_parallel[1][-1])), 10, angle_adaptation=True, output_only_points=False)) + intersection2d = segments_intersection(((current_parallel[0][0], current_parallel[0][-1]), (current_parallel[1][0], current_parallel[1][-1])), (( + next_parallel[0][0], next_parallel[0][-1]), (next_parallel[1][0], next_parallel[1][-1])), full_line=False) + + intersection = ( + round(intersection2d[0]), 100, round(intersection2d[1])) + self.intersections_curved.append(curved_corner_by_distance( + intersection, current_parallel[0], next_parallel[0], 10, 0, full_line=True))