Clean up
This commit is contained in:
2
main.py
2
main.py
@@ -323,7 +323,7 @@ for i in range(len(p.coordinates)-1):
|
||||
if p.coordinates[i] != None:
|
||||
s = Segment2D(Point2D(p.coordinates[i].x, p.coordinates[i].y), Point2D(
|
||||
p.coordinates[i+1].x, p.coordinates[i+1].y))
|
||||
s.compute_thick_segment(ww, LINE_THICKNESS_MODE.MIDDLE)
|
||||
s.segment_thick(ww, LINE_THICKNESS_MODE.MIDDLE)
|
||||
print(s.coordinates)
|
||||
for j in range(len(s.coordinates)-1):
|
||||
# editor.placeBlock(
|
||||
|
||||
@@ -4,28 +4,52 @@ from typing import List
|
||||
|
||||
|
||||
class Circle:
|
||||
def __init__(self, center: Point2D, inner: int, outer: int):
|
||||
def __init__(self, center: Point2D):
|
||||
self.center = center
|
||||
|
||||
self.inner = inner
|
||||
self.outer = outer
|
||||
self.radius = None
|
||||
self.coordinates = []
|
||||
|
||||
self.radius = None # Used with circle_points()
|
||||
self.inner = None
|
||||
self.outer = None
|
||||
self.coordinates_thick = []
|
||||
|
||||
self.spaced_radius = None
|
||||
self.spaced_coordinates = []
|
||||
|
||||
self.circle(self.center, self.inner, self.outer)
|
||||
|
||||
def __repr__(self):
|
||||
return f"Circle(center: {self.center}, 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})"
|
||||
|
||||
def circle(self, center: Point2D, inner: int, outer: int) -> List[Point2D]:
|
||||
def cirlce(self, radius: int) -> List[Point2D]:
|
||||
self.radius = radius
|
||||
center = self.center.copy()
|
||||
|
||||
x = -radius
|
||||
y = 0
|
||||
error = 2-2*radius
|
||||
while (True):
|
||||
self.coordinates.append(Point2D(center.x-x, center.y+y))
|
||||
self.coordinates.append(Point2D(center.x-y, center.y-x))
|
||||
self.coordinates.append(Point2D(center.x+x, center.y-y))
|
||||
self.coordinates.append(Point2D(center.x+y, center.y+x))
|
||||
r = error
|
||||
if (r <= y):
|
||||
y += 1
|
||||
error += y*2+1
|
||||
if (r > x or error > y):
|
||||
x += 1
|
||||
error += x*2+1
|
||||
if (x < 0):
|
||||
continue
|
||||
else:
|
||||
break
|
||||
|
||||
def circle_thick(self, inner: int, outer: int) -> List[Point2D]:
|
||||
"""Compute discrete value of a 2d-circle with thickness.
|
||||
|
||||
https://stackoverflow.com/questions/27755514/circle-with-thickness-drawing-algorithm
|
||||
From: https://stackoverflow.com/questions/27755514/circle-with-thickness-drawing-algorithm
|
||||
|
||||
Args:
|
||||
center (Type[Point2D]): Center of the circle. Circles always have an odd diameter due to the central coordinate.
|
||||
inner (int): The minimum radius at which the disc is filled (included).
|
||||
outer (int): The maximum radius where disc filling stops (included).
|
||||
|
||||
@@ -34,8 +58,14 @@ class Circle:
|
||||
|
||||
>>> Circle(Point2D(0, 0), 5, 10)
|
||||
"""
|
||||
|
||||
self.inner = inner
|
||||
self.outer = outer
|
||||
center = self.center.copy()
|
||||
|
||||
xo = outer
|
||||
xi = inner
|
||||
|
||||
y = 0
|
||||
erro = 1 - xo
|
||||
erri = 1 - xi
|
||||
@@ -66,21 +96,23 @@ class Circle:
|
||||
else:
|
||||
xi -= 1
|
||||
erri += 2 * (y - xi + 1)
|
||||
return self.coordinates
|
||||
return self.coordinates_thick
|
||||
|
||||
def circle_points(self, number: int, radius: int) -> List[Point2D]:
|
||||
def circle_spaced(self, number: int, radius: int) -> List[Point2D]:
|
||||
"""Get evenly spaced coordinates of the circle.
|
||||
|
||||
https://stackoverflow.com/questions/8487893/generate-all-the-points-on-the-circumference-of-a-circle
|
||||
From: https://stackoverflow.com/questions/8487893/generate-all-the-points-on-the-circumference-of-a-circle
|
||||
|
||||
Args:
|
||||
number (int): Number of coordinates to be returned.
|
||||
radius (int, optional): Radius of the circle. Defaults to self.inner.
|
||||
radius (int): Radius of the circle.
|
||||
|
||||
Returns:
|
||||
list(Point2D): List of evenly spaced 2d-coordinates forming the circle.
|
||||
"""
|
||||
print(self.center.x)
|
||||
self.spaced_radius = radius
|
||||
center = self.center
|
||||
|
||||
self.spaced_coordinates = [
|
||||
Point2D(cos(2 * pi / number * i) * radius,
|
||||
sin(2 * pi / number * i) * radius)
|
||||
@@ -89,17 +121,17 @@ class Circle:
|
||||
|
||||
for i in range(len(self.spaced_coordinates)):
|
||||
self.spaced_coordinates[i] = Point2D(
|
||||
self.spaced_coordinates[i].x + self.center.x,
|
||||
self.spaced_coordinates[i].y + self.center.y
|
||||
self.spaced_coordinates[i].x + center.x,
|
||||
self.spaced_coordinates[i].y + center.y
|
||||
).round()
|
||||
return self.spaced_coordinates
|
||||
|
||||
def _x_line(self, x1, x2, y):
|
||||
while x1 <= x2:
|
||||
self.coordinates.append(Point2D(x1, y))
|
||||
self.coordinates_thick.append(Point2D(x1, y))
|
||||
x1 += 1
|
||||
|
||||
def _y_line(self, x, y1, y2):
|
||||
while y1 <= y2:
|
||||
self.coordinates.append(Point2D(x, y1))
|
||||
self.coordinates_thick.append(Point2D(x, y1))
|
||||
y1 += 1
|
||||
|
||||
@@ -54,9 +54,6 @@ class Point2D:
|
||||
else:
|
||||
return (s_p <= 0) and (t_p <= 0) and (s_p + t_p) >= d
|
||||
|
||||
def distance(self, point: "Point2D") -> int:
|
||||
return sqrt((point.x - self.x) ** 2 + (point.y - self.y) ** 2)
|
||||
|
||||
def nearest(self, points: List["Point2D"]) -> "Point2D":
|
||||
"""Return the nearest point. If multiple nearest point, returns the first in the list.
|
||||
|
||||
@@ -182,6 +179,9 @@ class Point2D:
|
||||
self.coordinate = (self.x, self.y)
|
||||
return self
|
||||
|
||||
def distance(self, point: "Point2D") -> int:
|
||||
return sqrt((point.x - self.x) ** 2 + (point.y - self.y) ** 2)
|
||||
|
||||
@staticmethod
|
||||
def to_vectors(points: List["Point3D"]) -> List[np.array]:
|
||||
vectors = []
|
||||
|
||||
@@ -13,14 +13,12 @@ class Point3D:
|
||||
def copy(self):
|
||||
return Point3D(self.x, self.y, self.z)
|
||||
|
||||
def coordinates(self):
|
||||
return (self.x, self.y, self.z)
|
||||
|
||||
def __repr__(self):
|
||||
return f"Point3D(x: {self.x}, y: {self.y}, z: {self.z})"
|
||||
|
||||
def distance(self, point: "Point3D"):
|
||||
return sqrt((point.x - self.x) ** 2 + (point.y - self.y) ** 2 + (point.z - self.z) ** 2)
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, Point3D):
|
||||
return self.x == other.x and self.y == other.y and self.z == other.z
|
||||
|
||||
def nearest(self, points: List["Point3D"]) -> "Point3D":
|
||||
"""Return the nearest point. If multiple nearest point, returns the first in the list.
|
||||
@@ -69,6 +67,9 @@ class Point3D:
|
||||
self.coordinate = (self.x, self.y, self.z)
|
||||
return self
|
||||
|
||||
def distance(self, point: "Point3D"):
|
||||
return sqrt((point.x - self.x) ** 2 + (point.y - self.y) ** 2 + (point.z - self.z) ** 2)
|
||||
|
||||
@staticmethod
|
||||
def to_vectors(points: List["Point3D"]):
|
||||
vectors = []
|
||||
|
||||
@@ -5,20 +5,20 @@ from math import sqrt
|
||||
|
||||
|
||||
class Segment2D:
|
||||
def __init__(self, start: Point2D, end: Point2D, thickness_mode: LINE_THICKNESS_MODE = LINE_THICKNESS_MODE.MIDDLE):
|
||||
def __init__(self, start: Point2D, end: Point2D):
|
||||
self.start = start
|
||||
self.end = end
|
||||
self.coordinates = []
|
||||
self.coordinates_thick = []
|
||||
self.thickness = None
|
||||
self.thickness_mode = thickness_mode
|
||||
|
||||
def __repr__(self):
|
||||
return str(self.coordinates)
|
||||
|
||||
def compute_segment_overlap(self, start: Point2D, end: Point2D, overlap: LINE_OVERLAP):
|
||||
def segment(self, overlap: LINE_OVERLAP = LINE_OVERLAP.NONE, is_computing_thickness: bool = False) -> List[Point2D]:
|
||||
"""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
|
||||
|
||||
Args:
|
||||
start (Point2D): Start point of the segment.
|
||||
@@ -28,8 +28,8 @@ class Segment2D:
|
||||
>>> Segment2D(Point2D(0, 0), Point2D(10, 15))
|
||||
"""
|
||||
|
||||
start = start.copy()
|
||||
end = end.copy()
|
||||
start = self.start.copy()
|
||||
end = self.end.copy()
|
||||
|
||||
# Direction
|
||||
delta_x = end.x - start.x
|
||||
@@ -50,7 +50,7 @@ class Segment2D:
|
||||
delta_2x = 2*delta_x
|
||||
delta_2y = 2*delta_y
|
||||
|
||||
self.coordinates.append(start.copy())
|
||||
self._add_coordinates(start, is_computing_thickness)
|
||||
|
||||
if (delta_x > delta_y):
|
||||
error = delta_2y - delta_x
|
||||
@@ -58,36 +58,39 @@ class Segment2D:
|
||||
start.x += step_x
|
||||
if (error >= 0):
|
||||
if (overlap == LINE_OVERLAP.MAJOR):
|
||||
self.coordinates.append(start.copy())
|
||||
self._add_coordinates(start, is_computing_thickness)
|
||||
|
||||
start.y += step_y
|
||||
if (overlap == LINE_OVERLAP.MINOR):
|
||||
self.coordinates.append(
|
||||
Point2D(start.copy().x - step_x, start.copy().y))
|
||||
self._add_coordinates(
|
||||
Point2D(start.copy().x - step_x, start.copy().y), is_computing_thickness)
|
||||
error -= delta_2x
|
||||
error += delta_2y
|
||||
self.coordinates.append(start.copy())
|
||||
self._add_coordinates(start, is_computing_thickness)
|
||||
else:
|
||||
error = delta_2x - delta_y
|
||||
while (start.y != end.y):
|
||||
start.y += step_y
|
||||
if (error >= 0):
|
||||
if (overlap == LINE_OVERLAP.MAJOR):
|
||||
self.coordinates.append(start.copy())
|
||||
self._add_coordinates(start, is_computing_thickness)
|
||||
|
||||
start.x += step_x
|
||||
if (overlap == LINE_OVERLAP.MINOR):
|
||||
self.coordinates.append(
|
||||
Point2D(start.copy().x, start.copy().y - step_y))
|
||||
self._add_coordinates(
|
||||
Point2D(start.copy().x, start.copy().y - step_y), is_computing_thickness)
|
||||
error -= delta_2y
|
||||
error += delta_2x
|
||||
self.coordinates.append(start.copy())
|
||||
self._add_coordinates(start, is_computing_thickness)
|
||||
|
||||
def compute_thick_segment(self, thickness: int, thickness_mode: LINE_THICKNESS_MODE):
|
||||
if not is_computing_thickness:
|
||||
return self.coordinates
|
||||
|
||||
def segment_thick(self, thickness: int, thickness_mode: LINE_THICKNESS_MODE) -> List[Point2D]:
|
||||
"""Bresenham with thickness.
|
||||
|
||||
From https://github.com/ArminJo/Arduino-BlueDisplay/blob/master/src/LocalGUI/ThickLine.hpp
|
||||
Probably inspired from Murphy's Modified Bresenham algorithm : http://zoo.co.uk/murphy/thickline/index.html
|
||||
From: https://github.com/ArminJo/Arduino-BlueDisplay/blob/master/src/LocalGUI/ThickLine.hpp
|
||||
Murphy's Modified Bresenham algorithm : http://zoo.co.uk/murphy/thickline/index.html
|
||||
|
||||
Args:
|
||||
start (Point2D): Start point of the segment.
|
||||
@@ -146,7 +149,8 @@ class Segment2D:
|
||||
error -= delta_2x
|
||||
error += delta_2x
|
||||
|
||||
self.compute_segment_overlap(start, end, LINE_OVERLAP.NONE)
|
||||
self.segment(
|
||||
start, end, LINE_OVERLAP.NONE, is_computing_thickness=True)
|
||||
|
||||
error = delta_2x - delta_x
|
||||
for i in range(thickness, 1, -1):
|
||||
@@ -160,7 +164,8 @@ class Segment2D:
|
||||
overlap = LINE_OVERLAP.MAJOR
|
||||
error += delta_2y
|
||||
|
||||
self.compute_segment_overlap(start, end, overlap)
|
||||
self.segment(
|
||||
start, end, overlap, is_computing_thickness=True)
|
||||
|
||||
else:
|
||||
if swap:
|
||||
@@ -180,7 +185,8 @@ class Segment2D:
|
||||
error -= delta_2y
|
||||
error += delta_2x
|
||||
|
||||
self.compute_segment_overlap(start, end, LINE_OVERLAP.NONE)
|
||||
self.segment(
|
||||
start, end, LINE_OVERLAP.NONE, is_computing_thickness=True)
|
||||
|
||||
error = delta_2x - delta_y
|
||||
for i in range(thickness, 1, -1):
|
||||
@@ -194,7 +200,10 @@ class Segment2D:
|
||||
overlap = LINE_OVERLAP.MAJOR
|
||||
error += delta_2x
|
||||
|
||||
self.compute_segment_overlap(start, end, overlap)
|
||||
self.segment(
|
||||
start, end, overlap, is_computing_thickness=True)
|
||||
|
||||
return self.coordinates
|
||||
|
||||
def perpendicular(self, distance: int) -> List[Point2D]:
|
||||
"""Compute perpendicular points from both side of the segment placed at start level.
|
||||
@@ -217,3 +226,14 @@ class Segment2D:
|
||||
x4 = self.start.x - (distance / 2) * dy
|
||||
y4 = self.start.y + (distance / 2) * dx
|
||||
return Point2D(x3, y3).round(), Point2D(x4, y4).round()
|
||||
|
||||
def middle_point(self):
|
||||
return (np.round((self.start.x + self.end.x) / 2.0).astype(int),
|
||||
np.round((self.start.y + self.end.y) / 2.0).astype(int),
|
||||
)
|
||||
|
||||
def _add_coordinates(self, coordinates, is_computing_thickness):
|
||||
if is_computing_thickness:
|
||||
self.coordinates_thick.append(coordinates.copy())
|
||||
else:
|
||||
self.coordinates.append(coordinates.copy())
|
||||
|
||||
@@ -4,33 +4,28 @@ from networks.geometry.Point3D import Point3D
|
||||
|
||||
|
||||
class Segment3D:
|
||||
def __init__(self, start: Point3D, end: Point3D, overlap: bool = True):
|
||||
def __init__(self, start: Point3D, end: Point3D):
|
||||
self.start = start
|
||||
self.end = end
|
||||
self.coordinates = []
|
||||
self.overlap = overlap
|
||||
|
||||
self._compute_segment(self.start, self.end, self.overlap)
|
||||
|
||||
def __repr__(self):
|
||||
return str(self.coordinates)
|
||||
|
||||
def _compute_segment(self, start: Point3D, end: Point3D, overlap: bool = False):
|
||||
def discrete_coordinates(self, overlap: bool = False):
|
||||
"""Calculate a segment between two points in 3D space. 3d Bresenham algorithm.
|
||||
|
||||
From: https://www.geeksforgeeks.org/bresenhams-algorithm-for-3-d-line-drawing/
|
||||
|
||||
Args:
|
||||
start (Point3D): First coordinates.
|
||||
end (Point3D): Second coordinates.
|
||||
overlap (bool, optional): If False, remove unnecessary coordinates connecting to other coordinates side by side, leaving only a diagonal connection. Defaults to False.
|
||||
|
||||
>>> Segment3D(Point3D(0, 0, 0), Point3D(10, 10, 15))
|
||||
"""
|
||||
self.coordinates.append(start.copy())
|
||||
dx = abs(end.x - start.x)
|
||||
dy = abs(end.y - start.y)
|
||||
dz = abs(end.z - start.z)
|
||||
dx = abs(self.end.x - self.start.x)
|
||||
dy = abs(self.end.y - self.start.y)
|
||||
dz = abs(self.end.z - self.start.z)
|
||||
if end.x > start.x:
|
||||
xs = 1
|
||||
else:
|
||||
@@ -109,3 +104,10 @@ class Segment3D:
|
||||
p2 -= 2 * dz
|
||||
p1 += 2 * dy
|
||||
p2 += 2 * dx
|
||||
return self.coordinates
|
||||
|
||||
def middle_point(self):
|
||||
return (np.round((self.start.x + self.end.x) / 2.0).astype(int),
|
||||
np.round((self.start.y + self.end.y) / 2.0).astype(int),
|
||||
np.round((self.start.z + self.end.z) / 2.0).astype(int),
|
||||
)
|
||||
|
||||
@@ -54,121 +54,3 @@ def orthogonal(origin, point, distance, normal=np.array([0, 1, 0])):
|
||||
|
||||
orthogonal = np.add(np.multiply(orthogonal, distance), origin).astype(int)
|
||||
return orthogonal
|
||||
|
||||
|
||||
def discrete_segment(start_point, end_point, pixel_perfect=True):
|
||||
"""
|
||||
Calculate a line between two points in 3D space.
|
||||
|
||||
https://www.geeksforgeeks.org/bresenhams-algorithm-for-3-d-line-drawing/
|
||||
|
||||
Args:
|
||||
start_point (tuple): (x, y, z) First coordinates.
|
||||
end_point (tuple): (x, y, z) Second coordinates.
|
||||
pixel_perfect (bool, optional): If true, remove unnecessary coordinates connecting to other coordinates side by side, leaving only a diagonal connection. Defaults to True.
|
||||
|
||||
Returns:
|
||||
list: List of coordinates.
|
||||
"""
|
||||
(x1, y1, z1) = start_point
|
||||
(x2, y2, z2) = end_point
|
||||
x1, y1, z1, x2, y2, z2 = (
|
||||
round(x1),
|
||||
round(y1),
|
||||
round(z1),
|
||||
round(x2),
|
||||
round(y2),
|
||||
round(z2),
|
||||
)
|
||||
|
||||
points = []
|
||||
points.append((x1, y1, z1))
|
||||
dx = abs(x2 - x1)
|
||||
dy = abs(y2 - y1)
|
||||
dz = abs(z2 - z1)
|
||||
if x2 > x1:
|
||||
xs = 1
|
||||
else:
|
||||
xs = -1
|
||||
if y2 > y1:
|
||||
ys = 1
|
||||
else:
|
||||
ys = -1
|
||||
if z2 > z1:
|
||||
zs = 1
|
||||
else:
|
||||
zs = -1
|
||||
|
||||
# Driving axis is X-axis
|
||||
if dx >= dy and dx >= dz:
|
||||
p1 = 2 * dy - dx
|
||||
p2 = 2 * dz - dx
|
||||
while x1 != x2:
|
||||
x1 += xs
|
||||
points.append((x1, y1, z1))
|
||||
if p1 >= 0:
|
||||
y1 += ys
|
||||
if not pixel_perfect:
|
||||
if points[-1][1] != y1:
|
||||
points.append((x1, y1, z1))
|
||||
p1 -= 2 * dx
|
||||
if p2 >= 0:
|
||||
z1 += zs
|
||||
if not pixel_perfect:
|
||||
if points[-1][2] != z1:
|
||||
points.append((x1, y1, z1))
|
||||
p2 -= 2 * dx
|
||||
p1 += 2 * dy
|
||||
p2 += 2 * dz
|
||||
|
||||
# Driving axis is Y-axis
|
||||
elif dy >= dx and dy >= dz:
|
||||
p1 = 2 * dx - dy
|
||||
p2 = 2 * dz - dy
|
||||
while y1 != y2:
|
||||
y1 += ys
|
||||
points.append((x1, y1, z1))
|
||||
if p1 >= 0:
|
||||
x1 += xs
|
||||
if not pixel_perfect:
|
||||
if points[-1][0] != x1:
|
||||
points.append((x1, y1, z1))
|
||||
p1 -= 2 * dy
|
||||
if p2 >= 0:
|
||||
z1 += zs
|
||||
if not pixel_perfect:
|
||||
if points[-1][2] != z1:
|
||||
points.append((x1, y1, z1))
|
||||
p2 -= 2 * dy
|
||||
p1 += 2 * dx
|
||||
p2 += 2 * dz
|
||||
|
||||
# Driving axis is Z-axis
|
||||
else:
|
||||
p1 = 2 * dy - dz
|
||||
p2 = 2 * dx - dz
|
||||
while z1 != z2:
|
||||
z1 += zs
|
||||
points.append((x1, y1, z1))
|
||||
if p1 >= 0:
|
||||
y1 += ys
|
||||
if not pixel_perfect:
|
||||
if points[-1][1] != y1:
|
||||
points.append((x1, y1, z1))
|
||||
p1 -= 2 * dz
|
||||
if p2 >= 0:
|
||||
x1 += xs
|
||||
if not pixel_perfect:
|
||||
if points[-1][0] != x1:
|
||||
points.append((x1, y1, z1))
|
||||
p2 -= 2 * dz
|
||||
p1 += 2 * dy
|
||||
p2 += 2 * dx
|
||||
return points
|
||||
|
||||
|
||||
def middle_point(start_point, end_point):
|
||||
return (np.round((start_point[0] + end_point[0]) / 2.0).astype(int),
|
||||
np.round((start_point[1] + end_point[1]) / 2.0).astype(int),
|
||||
np.round((start_point[2] + end_point[2]) / 2.0).astype(int),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user