Add sort_by_rotation

This commit is contained in:
2024-06-11 18:45:16 +02:00
parent 9c215a5d24
commit 229c43c308
4 changed files with 73 additions and 5 deletions

View File

@@ -16,6 +16,7 @@ from buildings.Building import Building
import random import random
from networks.roads import Road as Road from networks.roads import Road as Road
from networks.geometry.Enums import ROTATION
from networks.roads.intersections import Intersection as Intersection from networks.roads.intersections import Intersection as Intersection
from networks.geometry.point_tools import curved_corner_by_curvature, curved_corner_by_distance from networks.geometry.point_tools import curved_corner_by_curvature, curved_corner_by_distance
@@ -266,4 +267,4 @@ block_list = ["blue_concrete", "red_concrete", "green_concrete",
# print(polyline.alpha_radii) # print(polyline.alpha_radii)
print( print(
Point2D(-2, -5).optimized_path([Point2D(0, 0), Point2D(10, 5), Point2D(1, 3)])) Point2D(-10, -10).sort_by_rotation([Point2D(10, 10), Point2D(-10, 10), Point2D(10, -10)], rotation=ROTATION.CLOCKWISE))

View File

@@ -11,3 +11,8 @@ class LINE_THICKNESS_MODE(Enum):
MIDDLE = 0 MIDDLE = 0
DRAW_COUNTERCLOCKWISE = 1 DRAW_COUNTERCLOCKWISE = 1
DRAW_CLOCKWISE = 2 DRAW_CLOCKWISE = 2
class ROTATION(Enum):
CLOCKWISE = 0
COUNTERCLOCKWISE = 1

View File

@@ -1,6 +1,7 @@
import numpy as np import numpy as np
from typing import List from typing import List
from math import atan2, sqrt from math import atan2, sqrt
from networks.geometry.Enums import ROTATION
class Point2D: class Point2D:
@@ -15,6 +16,11 @@ class Point2D:
def __repr__(self): def __repr__(self):
return f"Point2D(x: {self.x}, y: {self.y})" return f"Point2D(x: {self.x}, y: {self.y})"
def __eq__(self, other):
if isinstance(other, Point2D):
return self.x == other.x and self.y == other.y
return False
def is_in_triangle(self, xy0: "Point2D", xy1: "Point2D", xy2: "Point2D"): def is_in_triangle(self, xy0: "Point2D", xy1: "Point2D", xy2: "Point2D"):
"""Returns True is the point is in a triangle defined by 3 others points. """Returns True is the point is in a triangle defined by 3 others points.
@@ -62,7 +68,7 @@ class Point2D:
""" """
return min(points, key=lambda point: self.distance(point)) return min(points, key=lambda point: self.distance(point))
def optimized_path(self, points: List["Point2D"]): def optimized_path(self, points: List["Point2D"]) -> List["Point2D"]:
"""Get an optimized ordered path starting from the current point. """Get an optimized ordered path starting from the current point.
From: https://stackoverflow.com/questions/45829155/sort-points-in-order-to-have-a-continuous-curve-using-python From: https://stackoverflow.com/questions/45829155/sort-points-in-order-to-have-a-continuous-curve-using-python
@@ -88,6 +94,62 @@ class Point2D:
pass_by.remove(nearest) pass_by.remove(nearest)
return path return path
def sort_by_rotation(self, points: List["Point2D"], rotation: ROTATION = ROTATION.CLOCKWISE) -> List["Point2D"]:
"""Sort points in clockwise order, starting from current point.
From: https://stackoverflow.com/questions/58377015/counterclockwise-sorting-of-x-y-data
Args:
points (List[Point2D]): List of 2d-points. Current point can be included here.
rotation (ROTATION): Can be ROTATION.CLOCKWISE or ROTATION.COUNTERCLOCKWISE. Optional. Defaults to ROTATION.CLOCKWISE.
Returns:
List[Point2D]: List of 2d-points.
>>> Point2D(-10, -10).sort_by_rotation([Point2D(10, 10), Point2D(-10, 10), Point2D(10, -10)])
[Point2D(x: -10, y: -10), Point2D(x: 10, y: -10), Point2D(x: 10, y: 10), Point2D(x: -10, y: 10)]
"""
if self not in points:
points.append(self)
x, y = [], []
for i in range(len(points)):
x.append(points[i].x)
y.append(points[i].y)
x, y = np.array(x), np.array(y)
x0 = np.mean(x)
y0 = np.mean(y)
r = np.sqrt((x - x0) ** 2 + (y - y0) ** 2)
angles = np.where(
(y - y0) > 0,
np.arccos((x - x0) / r),
2 * np.pi - np.arccos((x - x0) / r),
)
mask = np.argsort(angles)
x_sorted = list(x[mask])
y_sorted = list(y[mask])
# Rearrange tuples to get the correct coordinates.
sorted_points = []
for i in range(len(points)):
j = 0
while (x_sorted[i] != points[j].x) and (y_sorted[i] != points[j].y):
j += 1
else:
sorted_points.append(Point2D(x_sorted[i], y_sorted[i]))
if rotation == ROTATION.CLOCKWISE:
sorted_points.reverse()
start_index = sorted_points.index(self)
return sorted_points[start_index:] + sorted_points[:start_index]
else:
start_index = sorted_points.index(self)
return sorted_points[start_index:] + sorted_points[:start_index]
def angle(self, xy1, xy2): def angle(self, xy1, xy2):
""" """
Compute angle (in degrees). Corner in current point. Compute angle (in degrees). Corner in current point.

View File

@@ -34,16 +34,16 @@ class Point3D:
""" """
return min(points, key=lambda point: self.distance(point)) return min(points, key=lambda point: self.distance(point))
def optimized_path(self, points: List["Point3D"]): def optimized_path(self, points: List["Point3D"]) -> List["Point3D"]:
"""Get an optimized ordered path starting from the current point. """Get an optimized ordered path starting from the current point.
From: https://stackoverflow.com/questions/45829155/sort-points-in-order-to-have-a-continuous-curve-using-python From: https://stackoverflow.com/questions/45829155/sort-points-in-order-to-have-a-continuous-curve-using-python
Args: Args:
points (List[Point2D]): List of 3d-points. Could contain the current point. points (List[Point3D]): List of 3d-points. Could contain the current point.
Returns: Returns:
List[Point2D]: Ordered list of 3d-points starting from the current point. List[Point3D]: Ordered list of 3d-points starting from the current point.
>>> Point3D(-2, -5, 6).optimized_path([Point3D(0, 0, 7), Point3D(10, 5, 1), Point3D(1, 3, 3)]) >>> Point3D(-2, -5, 6).optimized_path([Point3D(0, 0, 7), Point3D(10, 5, 1), Point3D(1, 3, 3)])
[Point3D(x: -2, y: -5, z: 6), Point3D(x: 0, y: 0, z: 7), Point3D(x: 1, y: 3, z: 3), Point3D(x: 10, y: 5, z: 1)] [Point3D(x: -2, y: -5, z: 6), Point3D(x: 0, y: 0, z: 7), Point3D(x: 1, y: 3, z: 3), Point3D(x: 10, y: 5, z: 1)]