Finalize Polyline parsing but still arcs precision issue

This commit is contained in:
2024-06-15 01:41:26 +02:00
parent 9b87874e13
commit 4a611a4aa2
7 changed files with 260 additions and 113 deletions

148
main.py
View File

@@ -1,31 +1,33 @@
from Enums import LINE_OVERLAP, LINE_THICKNESS_MODE, ROTATION
from PIL import Image, ImageDraw
import matplotlib.pyplot as plt
from networks.geometry.Point3D import Point3D
from networks.geometry.Segment3D import Segment3D
from networks.geometry.Segment2D import Segment2D
from networks.geometry.Circle import Circle
from networks.geometry.Polyline import Polyline
from networks.geometry.Point2D import Point2D
import networks.roads.lines.Line as Line
import networks.roads.lanes.Lane as Lane
from gdpc import Editor, Block, geometry
import networks.geometry.curve_tools as curve_tools
import networks.geometry.Strip as Strip
import networks.geometry.segment_tools as segment_tools
import numpy as np
import json import json
from buildings.Building import Building
import random import random
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
from gdpc import Block, Editor, geometry
from PIL import Image, ImageDraw
import networks.geometry.curve_tools as curve_tools
import networks.geometry.segment_tools as segment_tools
import networks.geometry.Strip as Strip
import networks.roads.lanes.Lane as Lane
import networks.roads.lines.Line as Line
from buildings.Building import Building
from Enums import LINE_OVERLAP, LINE_THICKNESS_MODE, ROTATION
from networks.geometry.Circle import Circle
from networks.geometry.Point2D import Point2D
from networks.geometry.Point3D import Point3D
from networks.geometry.point_tools import (
curved_corner_by_curvature,
curved_corner_by_distance,
)
from networks.geometry.Polyline import Polyline
from networks.geometry.Segment2D import Segment2D
from networks.geometry.Segment3D import Segment3D
from networks.roads import Road as Road from networks.roads import Road as Road
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
import matplotlib
matplotlib.use('Agg') matplotlib.use('Agg')
@@ -286,18 +288,26 @@ block_list = ["blue_concrete", "red_concrete", "green_concrete",
# p = Polyline((Point2D(-1225, 468), Point2D(-1138, 481), # p = Polyline((Point2D(-1225, 468), Point2D(-1138, 481),
# Point2D(-1188, 451), Point2D(-1176, 409), Point2D(-1179, 399))) # Point2D(-1188, 451), Point2D(-1176, 409), Point2D(-1179, 399)))
w = 200 w = 100
n_points = 20 n_points = 8
min_val, max_val = -w, w min_val, max_val = -w, w
random_points = [Point2D(random.randint(min_val, max_val), random.randint( random_points = [Point2D(random.randint(min_val, max_val), random.randint(
min_val, max_val)) for _ in range(n_points)] min_val, max_val)) for _ in range(n_points)]
print(random_points)
print("\n\n")
# random_points = (Point2D(-75, -75), Point2D(0, -75), Point2D(75, 75), # random_points = (Point2D(-75, -75), Point2D(0, -75), Point2D(75, 75),
# Point2D(75, -50), Point2D(-50, 50), Point2D(0, 0)) # Point2D(75, -50), Point2D(-50, 50), Point2D(0, 0))
# random_points = random_points[0].optimized_path(random_points)
# random_points = [Point2D(-40, -56), Point2D(-94, 92), Point2D(19, -47), Point2D(
# 100, 59), Point2D(-85, -73), Point2D(-33, -9), Point2D(57, -25), Point2D(51, -34)]
random_points = random_points[0].optimized_path(random_points) random_points = random_points[0].optimized_path(random_points)
p = Polyline(random_points) p = Polyline(random_points)
@@ -316,10 +326,8 @@ image = Image.new('RGB', (width, height), 'black')
draw = ImageDraw.Draw(image) draw = ImageDraw.Draw(image)
print(p.output_points)
for i in range(len(p.output_points)-1): for i in range(len(p.output_points)-1):
if p.output_points[i] != None: if p.output_points[i] != 0:
s = Segment2D(Point2D(p.output_points[i].x, p.output_points[i].y), Point2D( s = Segment2D(Point2D(p.output_points[i].x, p.output_points[i].y), Point2D(
p.output_points[i+1].x, p.output_points[i+1].y)) p.output_points[i+1].x, p.output_points[i+1].y))
s.segment_thick(ww, LINE_THICKNESS_MODE.MIDDLE) s.segment_thick(ww, LINE_THICKNESS_MODE.MIDDLE)
@@ -331,40 +339,40 @@ for i in range(len(p.output_points)-1):
w-s.points_thick[j].y), fill='grey') w-s.points_thick[j].y), fill='grey')
for i in range(2, len(p.get_arcs_intersections())-2): # for i in range(2, len(p.get_arcs_intersections())-2):
s = Segment2D(Point2D(p.acrs_intersections[i][0].x, p.acrs_intersections[i][0].y), Point2D( # s = Segment2D(Point2D(p.acrs_intersections[i][0].x, p.acrs_intersections[i][0].y), Point2D(
p.acrs_intersections[i-1][-1].x, p.acrs_intersections[i-1][-1].y)) # p.acrs_intersections[i-1][-1].x, p.acrs_intersections[i-1][-1].y))
s.segment_thick(ww, LINE_THICKNESS_MODE.MIDDLE) # s.segment_thick(ww, LINE_THICKNESS_MODE.MIDDLE)
for j in range(len(s.points_thick)-1): # for j in range(len(s.points_thick)-1):
# editor.placeBlock( # # editor.placeBlock(
# s.coordinates[j].coordinate, Block("cyan_concrete")) # # s.coordinates[j].coordinate, Block("cyan_concrete"))
draw.point((s.points_thick[j].x+w, # draw.point((s.points_thick[j].x+w,
w-s.points_thick[j].y), fill='white') # w-s.points_thick[j].y), fill='green')
draw.point((p.acrs_intersections[i][0].x+w, # draw.point((p.acrs_intersections[i][0].x+w,
w-p.acrs_intersections[i][0].y), fill='blue') # w-p.acrs_intersections[i][0].y), fill='green')
draw.point((p.acrs_intersections[i][-1].x+w, # draw.point((p.acrs_intersections[i][-1].x+w,
w-p.acrs_intersections[i][-1].y), fill='red') # w-p.acrs_intersections[i][-1].y), fill='green')
for i in range(len(center)): # for i in range(len(center)):
if center[i]: # if center[i]:
circle = Circle(center[i]) # circle = Circle(center[i])
circle.circle_thick(round(radius[i]-ww/2), round(radius[i]+ww/2)) # circle.circle_thick(round(radius[i]-ww/2), round(radius[i]+ww/2))
for j in range(len(circle.points_thick)-1): # for j in range(len(circle.points_thick)-1):
if circle.points_thick[j].is_in_triangle(p.acrs_intersections[i][0], p.acrs_intersections[i][1], p.acrs_intersections[i][2]): # if circle.points_thick[j].is_in_triangle(p.acrs_intersections[i][0], p.acrs_intersections[i][1], p.acrs_intersections[i][2]):
# editor.placeBlock( # # editor.placeBlock(
# (circle.coordinates[j].x, y, circle.coordinates[j].y), Block("white_concrete")) # # (circle.coordinates[j].x, y, circle.coordinates[j].y), Block("white_concrete"))
draw.point((circle.points_thick[j].x+w, # draw.point((circle.points_thick[j].x+w,
w-circle.points_thick[j].y), fill='white') # w-circle.points_thick[j].y), fill='green')
circle.circle(radius[i]) # circle.circle(radius[i])
for j in range(len(circle.points)-1): # for j in range(len(circle.points)-1):
if circle.points[j].is_in_triangle(p.acrs_intersections[i][0], p.acrs_intersections[i][1], p.acrs_intersections[i][2]): # if circle.points[j].is_in_triangle(p.acrs_intersections[i][0], p.acrs_intersections[i][1], p.acrs_intersections[i][2]):
# editor.placeBlock( # # editor.placeBlock(
# (circle.coordinates[j].x, y, circle.coordinates[j].y), Block("white_concrete")) # # (circle.coordinates[j].x, y, circle.coordinates[j].y), Block("white_concrete"))
draw.point((circle.points[j].x+w, # draw.point(
w-circle.points[j].y), fill='purple') # (circle.points[j].x+w, w-circle.points[j].y), fill='green')
s1 = Segment2D(Point2D(p.acrs_intersections[1][0].x, p.acrs_intersections[1][0].y), Point2D( s1 = Segment2D(Point2D(p.acrs_intersections[1][0].x, p.acrs_intersections[1][0].y), Point2D(
p.output_points[0].x, p.output_points[0].y)) p.output_points[0].x, p.output_points[0].y))
@@ -372,7 +380,7 @@ s1.segment_thick(ww, LINE_THICKNESS_MODE.MIDDLE)
for j in range(len(s1.points_thick)-1): for j in range(len(s1.points_thick)-1):
draw.point((s1.points_thick[j].x+w, draw.point((s1.points_thick[j].x+w,
w-s1.points_thick[j].y), fill='white') w-s1.points_thick[j].y), fill='grey')
s1 = Segment2D(Point2D(p.acrs_intersections[-2][2].x, p.acrs_intersections[-2][2].y), Point2D( s1 = Segment2D(Point2D(p.acrs_intersections[-2][2].x, p.acrs_intersections[-2][2].y), Point2D(
p.output_points[-1].x, p.output_points[-1].y)) p.output_points[-1].x, p.output_points[-1].y))
@@ -380,10 +388,34 @@ s1.segment_thick(ww, LINE_THICKNESS_MODE.MIDDLE)
for j in range(len(s1.points_thick)-1): for j in range(len(s1.points_thick)-1):
draw.point((s1.points_thick[j].x+w, draw.point((s1.points_thick[j].x+w,
w-s1.points_thick[j].y), fill='white') w-s1.points_thick[j].y), fill='grey')
for i in range(0, len(p.arcs)):
for j in range(len(p.arcs[i])):
draw.point((p.arcs[i][j].x+w, w-p.arcs[i][j].y), fill='white')
for i in range(1, len(p.segments)-1):
for j in range(len(p.segments[i].segment())):
draw.point((p.segments[i].points[j].x+w,
w-p.segments[i].points[j].y), fill='white')
for i in range(1, len(p.centers)-1):
draw.point((p.centers[i].x+w, w-p.centers[i].y), fill='red')
draw.point((p.acrs_intersections[i][0].x+w,
w-p.acrs_intersections[i][0].y), fill='blue')
draw.point((p.acrs_intersections[i][1].x+w,
w-p.acrs_intersections[i][1].y), fill='purple')
draw.point((p.acrs_intersections[i][2].x+w,
w-p.acrs_intersections[i][2].y), fill='blue')
image.save('output_image.png') image.save('output_image.png')
# s = Segment2D(Point2D(-88, -12), Point2D(9, 75))
# s.segment_thick(3, LINE_THICKNESS_MODE.MIDDLE)
# print(s.points)
# s = Segment2D(Point2D(0, 0), Point2D(10, 10)).perpendicular(10) # s = Segment2D(Point2D(0, 0), Point2D(10, 10)).perpendicular(10)
# print(s) # print(s)

View File

@@ -1,21 +1,24 @@
from networks.geometry.Point2D import Point2D from math import cos, pi, sin
from math import cos, sin, pi
from typing import List from typing import List
import numpy as np
from networks.geometry.Point2D import Point2D
class Circle: class Circle:
def __init__(self, center: Point2D): def __init__(self, center: Point2D):
self.center = center self.center = center
self.radius = None self.radius = None
self.points = [] self.points: List[Point2D] = []
self.inner = None self.inner = None
self.outer = None self.outer = None
self.points_thick = [] self.points_thick: List[Point2D] = []
self.spaced_radius = None self.spaced_radius = None
self.spaced_points = [] self.spaced_points: List[Point2D] = []
def __repr__(self): def __repr__(self):
return f"Circle(center: {self.center}, radius: {self.radius}, spaced_radius: {self.spaced_radius}, inner: {self.inner}, outer: {self.outer})" return f"Circle(center: {self.center}, radius: {self.radius}, spaced_radius: {self.spaced_radius}, inner: {self.inner}, outer: {self.outer})"
@@ -43,6 +46,7 @@ class Circle:
continue continue
else: else:
break break
return self.points
def circle_thick(self, inner: int, outer: int) -> List[Point2D]: def circle_thick(self, inner: int, outer: int) -> List[Point2D]:
"""Compute discrete value of a 2d-circle with thickness. """Compute discrete value of a 2d-circle with thickness.
@@ -114,16 +118,17 @@ class Circle:
center = self.center center = self.center
self.spaced_points = [ self.spaced_points = [
Point2D(cos(2 * pi / number * i) * radius, Point2D(round(cos(2 * pi / number * i) * radius),
sin(2 * pi / number * i) * radius) round(sin(2 * pi / number * i) * radius))
for i in range(0, number + 1) for i in range(0, number + 1)
] ]
for i in range(len(self.spaced_points)): for i in range(len(self.spaced_points)):
self.spaced_points[i] = Point2D( current_point = Point2D(
self.spaced_points[i].x + center.x, self.spaced_points[i].x + center.x,
self.spaced_points[i].y + center.y self.spaced_points[i].y + center.y
).round() ).round()
self.spaced_points[i] = current_point
return self.spaced_points return self.spaced_points
def _x_line(self, x1, x2, y): def _x_line(self, x1, x2, y):

View File

@@ -1,6 +1,8 @@
import numpy as np
from typing import List
from math import atan2, sqrt from math import atan2, sqrt
from typing import List, Union
import numpy as np
from Enums import ROTATION from Enums import ROTATION
@@ -21,10 +23,26 @@ class Point2D:
return self.x == other.x and self.y == other.y return self.x == other.x and self.y == other.y
return False return False
def __add__(self, other):
if isinstance(other, np.ndarray) and other.shape == (2,):
return Point2D(self.x + other[0], self.y + other[1])
elif isinstance(other, Point2D):
return Point2D(self.x + other.x, self.y + other.y)
else:
raise TypeError(f"Unsupported type for addition: {type(other)}")
def __sub__(self, other):
if isinstance(other, np.ndarray) and other.shape == (2,):
return Point2D(self.x - other[0], self.y - other[1])
elif isinstance(other, Point2D):
return Point2D(self.x - other.x, self.y - other.y)
else:
raise TypeError(f"Unsupported type for subtraction: {type(other)}")
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.
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
Args: Args:
xy0 (Type[Point2D]): Point of the triangle. xy0 (Type[Point2D]): Point of the triangle.
@@ -190,12 +208,21 @@ class Point2D:
return abs(x1 * y2 - x2 * y1) < 1e-12 return abs(x1 * y2 - x2 * y1) < 1e-12
@staticmethod @staticmethod
def to_vectors(points: List["Point3D"]) -> List[np.array]: def to_arrays(points: Union[List["Point2D"], "Point2D"]) -> Union[List[np.array], "Point2D"]:
vectors = [] if isinstance(points, list):
for point in points: vectors = []
vectors.append(np.array(point.coordinates)) for point in points:
vectors.append(np.array(point.coordinates))
if (len(vectors) == 1):
return vectors[0]
else:
return vectors return vectors
else:
return np.array(points.coordinates)
@staticmethod
def from_arrays(vectors: Union[List[np.array], "Point2D"]) -> Union[List["Point2D"], "Point2D"]:
if isinstance(vectors, list):
points = []
for vector in vectors:
points.append(Point2D(vector[0], vector[1]))
return points
else:
return Point2D(vectors[0], vectors[1])

View File

@@ -1,5 +1,6 @@
from math import sqrt
from typing import List from typing import List
from math import atan2, sqrt
import numpy as np import numpy as np
@@ -80,3 +81,14 @@ class Point3D:
return vectors[0] return vectors[0]
else: else:
return vectors return vectors
@staticmethod
def from_arrays(vectors: List[np.array]) -> List["Point3D"]:
points = []
for vector in vectors:
points.append(Point3D(vector[0], vector[1], vector[2]))
if (len(points) == 1):
return points[0]
else:
return points

View File

@@ -1,11 +1,17 @@
from networks.geometry.Point2D import Point2D from math import inf, sqrt
from typing import List, Tuple, Union
from math import sqrt, inf
import numpy as np import numpy as np
from networks.geometry.Circle import Circle
from networks.geometry.Point2D import Point2D
from networks.geometry.Segment2D import Segment2D
# from Enums import LINE_THICKNESS_MODE, LINE_OVERLAP
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.
@@ -18,7 +24,8 @@ class Polyline:
>>> Polyline((Point2D(0, 0), Point2D(0, 10), Point2D(50, 10), Point2D(20, 20))) >>> Polyline((Point2D(0, 0), Point2D(0, 10), Point2D(50, 10), Point2D(20, 20)))
""" """
self.points_array = Point2D.to_vectors( self.output_points = points
self.points_array = Point2D.to_arrays(
self._remove_collinear_points(points)) self._remove_collinear_points(points))
self.length_polyline = len(self.points_array) self.length_polyline = len(self.points_array)
@@ -26,36 +33,46 @@ class Polyline:
raise ValueError("The list must contain at least 4 elements.") raise ValueError("The list must contain at least 4 elements.")
self.vectors = [None] * self.length_polyline # v self.vectors = [None] * self.length_polyline # v
self.lengths = [None] * (self.length_polyline - 1) # l self.lengths = [0] * (self.length_polyline - 1) # l
self.unit_vectors = [None] * self.length_polyline # n self.unit_vectors = [None] * self.length_polyline # n
self.tangente = [0] * self.length_polyline # f self.tangente = [0] * self.length_polyline # f
# alpha, maximum radius factor # alpha, maximum radius factor
self.alpha_radii = [None] * self.length_polyline self.alpha_radii = [0] * self.length_polyline
self.radii = [None] * self.length_polyline # r # Useful outputs. In order to not break indexation, each list has the same length, even if for n points, there is n-2 radius.
self.centers = [None] * self.length_polyline # c # Lists will start and end with None.
self.radii = [0] * self.length_polyline # r, list of points
self.centers = [None] * self.length_polyline # c, list of points
# list of tuple of points (first intersection, corresponding corner, last intersection)
self.acrs_intersections = [None] * self.length_polyline self.acrs_intersections = [None] * self.length_polyline
self.arcs = [[]] * self.length_polyline # list of points
# self.not_arcs = [[]] * self.length_polyline
# For n points, there is n-1 segments. Last element should stays None.
self.segments = [None] * \
self.length_polyline # list of segments
# Run procedure
self._compute_requirements() self._compute_requirements()
self._compute_alpha_radii() self._compute_alpha_radii()
self._alpha_assign(0, self.length_polyline-1) self._alpha_assign(0, self.length_polyline-1)
self.get_radii()
self.output_points = points self.get_centers()
self.get_arcs_intersections()
self.get_arcs()
self.get_segments()
def __repr__(self): def __repr__(self):
return str(self.alpha_radii) return str(self.alpha_radii)
def get_radii(self): def get_radii(self) -> List[Union[int]]:
for i in range(1, self.length_polyline-1): for i in range(1, self.length_polyline-1):
self.radii[i] = round(self.alpha_radii[i] * self.tangente[i]) self.radii[i] = round(self.alpha_radii[i] * self.tangente[i])
return self.radii return self.radii
def get_centers(self): def get_centers(self) -> List[Union[Point2D, None]]:
if self.radii == [None] * self.length_polyline:
raise ValueError("No radii found. Run get_radii before.")
for i in range(1, self.length_polyline-1): for i in range(1, self.length_polyline-1):
bisector = (self.unit_vectors[i] - self.unit_vectors[i-1]) / ( bisector = (self.unit_vectors[i] - self.unit_vectors[i-1]) / (
np.linalg.norm(self.unit_vectors[i] - self.unit_vectors[i-1])) np.linalg.norm(self.unit_vectors[i] - self.unit_vectors[i-1]))
@@ -65,16 +82,68 @@ class Polyline:
self.centers[i] = Point2D(array[0], array[1]).round() self.centers[i] = Point2D(array[0], array[1]).round()
return self.centers return self.centers
def get_arcs_intersections(self): def get_arcs_intersections(self) -> List[Tuple[Point2D]]:
"""Get arcs intersections points.
First and last elements elements of the list should be None. For n points, there are n-1 segments, and n-2 angle.
Returns:
list[tuple(Point2D)]: List of tuples composed - in order - of the first arc points, the corner points, the last arc points. The corresponding arc circle is inside this triangle.
"""
for i in range(1, self.length_polyline-1): for i in range(1, self.length_polyline-1):
point_1 = self.points_array[i] - \ point_1 = Point2D.from_arrays(self.points_array[i] -
self.alpha_radii[i] * self.unit_vectors[i-1] self.alpha_radii[i] * self.unit_vectors[i-1])
point_2 = self.points_array[i] + \ point_2 = Point2D.from_arrays(self.points_array[i] +
self.alpha_radii[i] * self.unit_vectors[i] self.alpha_radii[i] * self.unit_vectors[i])
self.acrs_intersections[i] = Point2D( self.acrs_intersections[i] = point_1.round(), Point2D.from_arrays(
point_1[0], point_1[1]).round(), Point2D(self.points_array[i][0], self.points_array[i][1]), Point2D(point_2[0], point_2[1]).round() self.points_array[i]), point_2.round()
return self.acrs_intersections return self.acrs_intersections
def get_arcs(self) -> List[Point2D]:
for i in range(1, self.length_polyline-1):
circle = Circle(self.centers[i])
circle.circle(self.radii[i])
for j in range(len(circle.points)):
if circle.points[j].is_in_triangle(self.acrs_intersections[i][0], self.acrs_intersections[i][1], self.acrs_intersections[i][2]):
self.arcs[i].append(circle.points[j])
# for j in range(len(circle.points)):
# if (circle.points[j] in Segment2D(self.acrs_intersections[i][0], self.acrs_intersections[i][1]).segment(LINE_OVERLAP.MINOR)):
# self.not_arcs[i].append(circle.points[j])
# print("hzeh")
# if (circle.points[j] in Segment2D(self.acrs_intersections[i][1], self.acrs_intersections[i][2]).segment(LINE_OVERLAP.MINOR)):
# self.not_arcs[i].append(circle.points[j])
# print("hzeh")
# if (circle.points[j] in Segment2D(self.acrs_intersections[i][2], self.acrs_intersections[i][0]).segment(LINE_OVERLAP.MINOR)):
# self.not_arcs[i].append(circle.points[j])
# print("hzeh")
return self.arcs
def get_segments(self) -> List[Segment2D]:
"""Get the segments between the circle arcs and at the start and end.
Last list element should be None, and last usable index is -2 or self.length_polyline - 2. For n points, there are n-1 segments.
Returns:
list[Segment2D]: List of segments in order.
"""
# Get first segment.
# segments index is 0, corresponding to the first points_array to the first point ([0]) of the first arc (acrs_intersections[1]).
# First arc index is 1 because index 0 is None due to fix list lenght. Is it a good choice?
self.segments[1] = Segment2D(Point2D.from_arrays(
self.points_array[0]), self.acrs_intersections[1][0])
# Get segments between arcs
for i in range(2, self.length_polyline - 2):
self.segments[i] = Segment2D(Point2D(self.acrs_intersections[i][0].x, self.acrs_intersections[i][0].y), Point2D(
self.acrs_intersections[i-1][-1].x, self.acrs_intersections[i-1][-1].y))
# Get last segment. Index is -2 because last index -1 should be None due to the same list lenght.
# For n points, there are n-1 segments.
self.segments[-2] = Segment2D(Point2D.from_arrays(
self.points_array[-1]), self.acrs_intersections[-2][2])
return self.segments
def _alpha_assign(self, start_index: int, end_index: int): 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.
@@ -101,8 +170,8 @@ class Polyline:
minimum_radius, minimum_index = current_radius, i minimum_radius, minimum_index = current_radius, i
alpha_low, alpha_high = alpha_a, alpha_b alpha_low, alpha_high = alpha_a, alpha_b
alpha_a = min(self.lengths[end_index-2], alpha_a = min(
self.lengths[end_index-1]-self.alpha_radii[end_index]) self.lengths[end_index-2], self.lengths[end_index-1]-self.alpha_radii[end_index])
current_radius = max(self.tangente[end_index-1]*alpha_a, self.tangente[end_index] current_radius = max(self.tangente[end_index-1]*alpha_a, self.tangente[end_index]
* self.alpha_radii[end_index]) # Radius at final segment * self.alpha_radii[end_index]) # Radius at final segment
@@ -123,9 +192,8 @@ class Polyline:
""" """
Returns the radius that balances the radii on either end segement i. Returns the radius that balances the radii on either end segement i.
""" """
alpha_a = min(self.lengths[i-1], (self.lengths[i] *
alpha_a = min(self.lengths[i-1], (self.lengths[i]*self.tangente[i+1]) / self.tangente[i+1])/(self.tangente[i] + self.tangente[i+1]))
(self.tangente[i] + self.tangente[i+1]))
alpha_b = min(self.lengths[i+1], self.lengths[i]-alpha_a) alpha_b = min(self.lengths[i+1], self.lengths[i]-alpha_a)
return alpha_a, alpha_b, min(self.tangente[i]*alpha_a, self.tangente[i+1]*alpha_b) return alpha_a, alpha_b, min(self.tangente[i]*alpha_a, self.tangente[i+1]*alpha_b)

View File

@@ -1,21 +1,23 @@
from typing import List from typing import List, Union
import numpy as np
from Enums import LINE_OVERLAP, LINE_THICKNESS_MODE from Enums import LINE_OVERLAP, LINE_THICKNESS_MODE
from networks.geometry.Point2D import Point2D from networks.geometry.Point2D import Point2D
from math import sqrt
class Segment2D: class Segment2D:
def __init__(self, start: Point2D, end: Point2D): def __init__(self, start: Point2D, end: Point2D):
self.start = start self.start = start
self.end = end self.end = end
self.points = [] self.points: List[Point2D] = []
self.points_thick = [] self.points_thick: List[Point2D] = []
self.thickness = None self.thickness = None
def __repr__(self): def __repr__(self):
return str(self.points) return str(f"Segment2D(start: {self.start}, end: {self.end}, points: {self.points})")
def segment(self, start: Point2D = None, end: Point2D = None, overlap: LINE_OVERLAP = LINE_OVERLAP.NONE, _is_computing_thickness: bool = False) -> List[Point2D]: def segment(self, start: Point2D = None, end: Point2D = None, overlap: LINE_OVERLAP = LINE_OVERLAP.NONE, _is_computing_thickness: bool = False) -> Union[List[Point2D], None]:
"""Modified Bresenham draw (line) with optional overlap. """Modified Bresenham draw (line) with optional overlap.
From: https://github.com/ArminJo/Arduino-BlueDisplay/blob/master/src/LocalGUI/ThickLine.hpp From: https://github.com/ArminJo/Arduino-BlueDisplay/blob/master/src/LocalGUI/ThickLine.hpp
@@ -29,7 +31,7 @@ class Segment2D:
>>> Segment2D(Point2D(0, 0), Point2D(10, 15)) >>> Segment2D(Point2D(0, 0), Point2D(10, 15))
""" """
if start == None or end == None: if start is None or end is None:
start = self.start.copy() start = self.start.copy()
end = self.end.copy() end = self.end.copy()
else: else:
@@ -90,6 +92,7 @@ class Segment2D:
if not _is_computing_thickness: if not _is_computing_thickness:
return self.points return self.points
return None
def segment_thick(self, thickness: int, thickness_mode: LINE_THICKNESS_MODE) -> List[Point2D]: def segment_thick(self, thickness: int, thickness_mode: LINE_THICKNESS_MODE) -> List[Point2D]:
"""Bresenham with thickness. """Bresenham with thickness.
@@ -208,7 +211,7 @@ class Segment2D:
self.segment( self.segment(
start, end, overlap=overlap, _is_computing_thickness=True) start, end, overlap=overlap, _is_computing_thickness=True)
return self.points return self.points_thick
def perpendicular(self, distance: int) -> List[Point2D]: def perpendicular(self, distance: int) -> List[Point2D]:
"""Compute perpendicular points from both side of the segment placed at start level. """Compute perpendicular points from both side of the segment placed at start level.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB