Clean Polyline and Points

This commit is contained in:
2024-06-11 03:23:15 +02:00
parent 5ea926c9f8
commit d993232a1a
5 changed files with 58 additions and 62 deletions

18
main.py
View File

@@ -1,3 +1,5 @@
from networks.geometry.Polyline import Polyline
from networks.geometry.Point2D import Point2D
import networks.roads.lines.Line as Line import networks.roads.lines.Line as Line
import networks.roads.lanes.Lane as Lane import networks.roads.lanes.Lane as Lane
from gdpc import Editor, Block, geometry from gdpc import Editor, Block, geometry
@@ -244,7 +246,17 @@ block_list = ["blue_concrete", "red_concrete", "green_concrete",
# --- # ---
r = Road.Road(((-1829, 141, 553), (-1830, 110, 621), (-1711, 69, 625), (-1662, # r = Road.Road(((-1829, 141, 553), (-1830, 110, 621), (-1711, 69, 625), (-1662,
65, 627), (-1667, 65, 761), (-1683, 70, 800), (-1721, 70, 834)), "None") # 65, 627), (-1667, 65, 761), (-1683, 70, 800), (-1721, 70, 834)), "None")
r.place_roads() # r.place_roads()
polyline = Polyline((Point2D(0, 0), Point2D(0, 10),
Point2D(50, 10), Point2D(20, 20)))
# print(polyline.radius_balance(2))
# polyline._alpha_assign(1, polyline.length_polyline-1)
print(polyline.alpha_radii)

View File

@@ -1,21 +1,20 @@
from typing import Type import numpy as np
import math
class Point2D: class Point2D:
def __init__(self, x: int, y: int): def __init__(self, x: int, y: int):
self.x = x self.x = x
self.y = y self.y = y
self.coordinate = (self.x, self.y)
def copy(self): def copy(self):
return Point2D(self.x, self.y) return Point2D(self.x, self.y)
def coordinates(self):
return (self.x, self.y)
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 is_in_triangle(self, xy0: Type[Point2D], xy1: Type[Point2D], xy2: Type[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.
From: 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. From: 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.
@@ -27,6 +26,9 @@ class Point2D:
Returns: Returns:
bool: False if the point is not inside the triangle. bool: False if the point is not inside the triangle.
>>> Point2D(0, 0).is_in_triangle(Point2D(10, 10), Point2D(-10, 20), Point2D(0, -20)))
True
""" """
dx = self.x - xy0.x dx = self.x - xy0.x
dy = self.y - xy0.y dy = self.y - xy0.y
@@ -45,5 +47,31 @@ class Point2D:
else: else:
return (s_p <= 0) and (t_p <= 0) and (s_p + t_p) >= d return (s_p <= 0) and (t_p <= 0) and (s_p + t_p) >= d
def distance(self, point: Type[Point2D]): def distance(self, point: "Point2D"):
return sqrt((point.x - self.x) ** 2 + (point.y - self.y) ** 2) return sqrt((point.x - self.x) ** 2 + (point.y - self.y) ** 2)
def angle(self, xy1, xy2):
"""
Compute angle (in degrees). Corner in current point.
From: https://stackoverflow.com/questions/13226038/calculating-angle-between-two-vectors-in-python
Args:
xy0 (numpy.ndarray): Points in the form of [x,y].
xy1 (numpy.ndarray): Points in the form of [x,y].
xy2 (numpy.ndarray): Points in the form of [x,y].
Returns:
float: Angle negative for counterclockwise angle, angle positive
for counterclockwise angle.
>>> Point2D(0, 0).angle(Point2D(10, 10), Point2D(0, -20))
-135.0
"""
if xy2 is None:
xy2 = xy1.coordinate + np.array([1, 0])
v0 = np.array(xy1.coordinate) - np.array(self.coordinate)
v1 = np.array(xy2.coordinate) - np.array(self.coordinate)
angle = math.atan2(np.linalg.det([v0, v1]), np.dot(v0, v1))
return np.degrees(angle)

View File

@@ -1,6 +1,3 @@
from typing import Type
class Point3D: class Point3D:
def __init__(self, x: int, y: int, z: int): def __init__(self, x: int, y: int, z: int):
self.x = x self.x = x
@@ -16,5 +13,5 @@ class Point3D:
def __repr__(self): def __repr__(self):
return f"Point2D(x: {self.x}, y: {self.y}, z: {self.z})" return f"Point2D(x: {self.x}, y: {self.y}, z: {self.z})"
def distance(self, point: Type[Point3D]): def distance(self, point: "Point3D"):
return sqrt((point.x - self.x) ** 2 + (point.y - self.y) ** 2 + (point.z - self.z) ** 2) return sqrt((point.x - self.x) ** 2 + (point.y - self.y) ** 2 + (point.z - self.z) ** 2)

View File

@@ -1,12 +1,12 @@
from typing import Type
from networks.geometry.Point2D import Point2D from networks.geometry.Point2D import Point2D
from networks.geometry.point_tools import coordinates_to_vectors
from math import sqrt, inf from math import sqrt, inf
import numpy as np import numpy as np
class Polyline: class Polyline:
def __init__(self, points: List[Point2D]): def __init__(self, points: list["Point2D"]):
"""A polyline with smooth corners, only composed of segments and circle arc. """A polyline with smooth corners, only composed of segments and circle arc.
Mathematics and algorithms behind this can be found here: https://cdr.lib.unc.edu/concern/dissertations/pz50gw814?locale=en, E2 Construction of arc roads from polylines, page 210. Mathematics and algorithms behind this can be found here: https://cdr.lib.unc.edu/concern/dissertations/pz50gw814?locale=en, E2 Construction of arc roads from polylines, page 210.
@@ -16,6 +16,8 @@ class Polyline:
Raises: Raises:
ValueError: At least 4 points required. ValueError: At least 4 points required.
>>> Polyline((Point2D(0, 0), Point2D(0, 10), Point2D(50, 10), Point2D(20, 20)))
""" """
self.points = coordinates_to_vectors(points) self.points = coordinates_to_vectors(points)
self.length_polyline = len(points) self.length_polyline = len(points)
@@ -26,16 +28,16 @@ class Polyline:
self.vectors = [None] * self.length_polyline self.vectors = [None] * self.length_polyline
self.lengths = [None] * self.length_polyline self.lengths = [None] * self.length_polyline
self.unit_vectors = [None] * self.length_polyline self.unit_vectors = [None] * self.length_polyline
self.tangente = [None] * self.length_polyline self.tangente = [0] * self.length_polyline
self.alpha_radii = [None] * self.length_polyline self.alpha_radii = [None] * self.length_polyline
self._compute_requirements() self._compute_requirements()
self._compute_alpha_radii() self._compute_alpha_radii()
_alpha_assign(0, self.length_polyline-1) self._alpha_assign(0, self.length_polyline-1)
def _alpha_assign(self, start_index, end_index): def _alpha_assign(self, start_index: int, end_index: int):
""" """
The alpha-assign procedure assigning radii based on a polyline. The alpha-assign procedure assigning radii based on a polyline.
""" """
@@ -61,7 +63,6 @@ class Polyline:
# Assign alphas at ends of selected segment # Assign alphas at ends of selected segment
self.alpha_radii[minimum_index] = alpha_low self.alpha_radii[minimum_index] = alpha_low
self.alpha_radii[minimum_index+1] = alpha_high self.alpha_radii[minimum_index+1] = alpha_high
print(alpha_low, alpha_high)
# Recur on lower segments # Recur on lower segments
self._alpha_assign(start_index, minimum_index) self._alpha_assign(start_index, minimum_index)
@@ -100,16 +101,3 @@ class Polyline:
for i in range(1, self.length_polyline-2): for i in range(1, self.length_polyline-2):
self.alpha_radii[i] = min(self.lengths[i-1] - self.alpha_radii[i-1], (self.lengths[i] self.alpha_radii[i] = min(self.lengths[i-1] - self.alpha_radii[i-1], (self.lengths[i]
* self.tangente[i+1])/(self.tangente[i]+self.tangente[i+1])) * self.tangente[i+1])/(self.tangente[i]+self.tangente[i+1]))
# polyline = Polyline((Point2D(0, 9), Point2D(0, 10), Point2D(
# 10, 10), Point2D(10, 20), Point2D(20, 20), Point2D(20, 30), Point2D(60, 60), Point2D(-60, -60)))
polyline = Polyline((Point2D(0, 10), Point2D(-10, -10),
Point2D(20, 0), Point2D(20, 20)))
# print(polyline.radius_balance(2))
polyline._alpha_assign(1, polyline.length_polyline-1)
print(polyline.alpha_radii)

View File

@@ -3,35 +3,6 @@ import numpy as np
from networks.geometry.segment_tools import discrete_segment, middle_point, parallel from networks.geometry.segment_tools import discrete_segment, middle_point, parallel
def distance(xy1, xy2): # TODO : Can be better.
# Works in 2d but supports 3d.
return sqrt((xy2[0] - xy1[0]) ** 2 + (xy2[-1] - xy1[-1]) ** 2)
def get_angle(xy0, xy1, xy2):
"""
Compute angle (in degrees) for xy0, xy1, xy2 corner.
https://stackoverflow.com/questions/13226038/calculating-angle-between-two-vectors-in-python
Args:
xy0 (numpy.ndarray): Points in the form of [x,y].
xy1 (numpy.ndarray): Points in the form of [x,y].
xy2 (numpy.ndarray): Points in the form of [x,y].
Returns:
float: Angle negative for counterclockwise angle, angle positive
for counterclockwise angle.
"""
if xy2 is None:
xy2 = xy1 + np.array([1, 0])
v0 = np.array(xy0) - np.array(xy1)
v1 = np.array(xy2) - np.array(xy1)
angle = np.math.atan2(np.linalg.det([v0, v1]), np.dot(v0, v1))
return np.degrees(angle)
def circle_points(center_point, radius, number=100): def circle_points(center_point, radius, number=100):
# Works in 2d but supports 3d. # Works in 2d but supports 3d.
# https://stackoverflow.com/questions/8487893/generate-all-the-points-on-the-circumference-of-a-circle # https://stackoverflow.com/questions/8487893/generate-all-the-points-on-the-circumference-of-a-circle
@@ -467,7 +438,7 @@ def curved_corner_by_curvature(
def coordinates_to_vectors(coordinates): def coordinates_to_vectors(coordinates):
vectors = [] vectors = []
for coordinate in coordinates: for coordinate in coordinates:
vectors.append(np.array(coordinate.get_coordinates())) vectors.append(np.array(coordinate.coordinate))
if (len(vectors) == 1): if (len(vectors) == 1):
return vectors[0] return vectors[0]