This commit is contained in:
2024-06-13 17:27:50 +02:00
parent d76f4aefa9
commit f82d02cd06
7 changed files with 115 additions and 178 deletions

View File

@@ -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(

View File

@@ -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

View File

@@ -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 = []

View File

@@ -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 = []

View File

@@ -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())

View File

@@ -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),
)

View File

@@ -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),
)