From 41cab8c2ac72628e880f904c89f20555d0c4c2d7 Mon Sep 17 00:00:00 2001 From: Xeon0X Date: Tue, 11 Jun 2024 02:13:16 +0200 Subject: [PATCH] Add 3d objects --- networks/geometry/Point3D.py | 17 ++ networks/geometry/Segment2D.py | 4 +- networks/geometry/Segment3D.py | 93 ++++++++++ networks/test.py | 322 --------------------------------- 4 files changed, 112 insertions(+), 324 deletions(-) create mode 100644 networks/geometry/Point3D.py delete mode 100644 networks/test.py diff --git a/networks/geometry/Point3D.py b/networks/geometry/Point3D.py new file mode 100644 index 0000000..c85b250 --- /dev/null +++ b/networks/geometry/Point3D.py @@ -0,0 +1,17 @@ +from typing import Type + + +class Point3D: + def __init__(self, x: int, y: int, z: int): + self.x = x + self.y = y + self.z = z + + 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"Point2D(x: {self.x}, y: {self.y}, z: {self.z})" diff --git a/networks/geometry/Segment2D.py b/networks/geometry/Segment2D.py index 98eb9c8..e8748f0 100644 --- a/networks/geometry/Segment2D.py +++ b/networks/geometry/Segment2D.py @@ -9,7 +9,7 @@ class Segment2D: self.end = end self.coordinates = [] - def draw_line_overlap(start: Type[Point2D], end: Type[Point2D], overlap: Type[LINE_OVERLAP]): + def compute_segment_overlap(start: Type[Point2D], end: Type[Point2D], overlap: Type[LINE_OVERLAP]): """Modified Bresenham draw (line) with optional overlap. From https://github.com/ArminJo/Arduino-BlueDisplay/blob/master/src/LocalGUI/ThickLine.hpp @@ -74,7 +74,7 @@ class Segment2D: error += delta_2x self.coordinates.append(start) - def draw_thick_line(start: Type[Point2D], end: Type[Point2D], thickness: int, thickness_mode: Type[LINE_THICKNESS_MODE]): + def compute_thick_segment(start: Type[Point2D], end: Type[Point2D], thickness: int, thickness_mode: Type[LINE_THICKNESS_MODE]): """Bresenham with thickness. From https://github.com/ArminJo/Arduino-BlueDisplay/blob/master/src/LocalGUI/ThickLine.hpp diff --git a/networks/geometry/Segment3D.py b/networks/geometry/Segment3D.py index 5179edb..98a2a15 100644 --- a/networks/geometry/Segment3D.py +++ b/networks/geometry/Segment3D.py @@ -8,3 +8,96 @@ class Segment3D: self.start = start self.end = end self.coordinates = [] + + def compute_segment(start: Type[Point3D], end: Type[Point3D], overlap=True): + """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 (Type[Point3D]): First coordinates. + end (Type[Point3D]): Second coordinates. + overlap (bool, optional): If true, remove unnecessary coordinates connecting to other coordinates side by side, leaving only a diagonal connection. Defaults to True. + """ + self.coordinates.append(start) + dx = abs(end.x - start.x) + dy = abs(end.y - start.y) + dz = abs(end.z - start.z) + if end.x > start.x: + xs = 1 + else: + xs = -1 + if end.y > start.y: + ys = 1 + else: + ys = -1 + if end.z > start.z: + 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 start.x != end.x: + start.x += xs + self.coordinates.append(start) + if p1 >= 0: + start.y += ys + if not overlap: + if self.coordinates[-1].y != start.y: + self.coordinates.append(start) + p1 -= 2 * dx + if p2 >= 0: + start.z += zs + if not overlap: + if self.coordinates[-1].z != start.z: + self.coordinates.append(start) + 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 start.y != end.y: + start.y += ys + self.coordinates.append(start) + if p1 >= 0: + start.x += xs + if not overlap: + if self.coordinates[-1].x != start.x: + self.coordinates.append(start) + p1 -= 2 * dy + if p2 >= 0: + start.z += zs + if not overlap: + if self.coordinates[-1].z != start.z: + self.coordinates.append(start) + p2 -= 2 * dy + p1 += 2 * dx + p2 += 2 * dz + + # Driving axis is Z-axis + else: + p1 = 2 * dy - dz + p2 = 2 * dx - dz + while start.z != end.z: + start.z += zs + self.coordinates.append(start) + if p1 >= 0: + start.y += ys + if not overlap: + if self.coordinates[-1].y != start.y: + self.coordinates.append(start) + p1 -= 2 * dz + if p2 >= 0: + start.x += xs + if not overlap: + if self.coordinates[-1].x != start.x: + self.coordinates.append(start) + p2 -= 2 * dz + p1 += 2 * dy + p2 += 2 * dx diff --git a/networks/test.py b/networks/test.py deleted file mode 100644 index 1caf8fc..0000000 --- a/networks/test.py +++ /dev/null @@ -1,322 +0,0 @@ -from gdpc import Editor, Block, geometry -from enum import Enum -import random - - -def circle(xm, ym, r, pixel_perfect=True): - editor = Editor(buffering=True) - block = random.choices(("white_concrete", "red_concrete", "blue_concrete", "green_concrete", - "yellow_concrete", "black_concrete", "purple_concrete", "pink_concrete"))[0] - x = -r - y = 0 - err = 2-2*r - while (True): - editor.placeBlock((xm-x, 141, ym+y), - Block(block)) - editor.placeBlock((xm-y, 141, ym-x), - Block(block)) - editor.placeBlock((xm+x, 141, ym-y), - Block(block)) - editor.placeBlock((xm+y, 141, ym+x), - Block(block)) - print(xm-x, ym+y) - print(xm-y, ym-x) - print(xm+x, ym-y) - print(xm+y, ym+x) - r = err - update = False - if (r <= y): - y += 1 - update = True - err += y*2+1 - if ((r > x or err > y)): - if (pixel_perfect == True or update == False): - x += 1 - err += x*2+1 - update = True - if (x < 0): - continue - else: - break - - -def set_pixel(x, y, colour): - editor = Editor(buffering=True) - editor.placeBlock((x, 160, y), - Block(colour)) - - -def x_line(x1, x2, y, colour): - while x1 <= x2: - set_pixel(x1, y, colour) - x1 += 1 - - -def y_line(x, y1, y2, colour): - while y1 <= y2: - set_pixel(x, y1, colour) - y1 += 1 - - -def circle2(xc, yc, inner, outer): - # https://stackoverflow.com/questions/27755514/circle-with-thickness-drawing-algorithm - xo = outer - xi = inner - y = 0 - erro = 1 - xo - erri = 1 - xi - - while xo >= y: - colour = random.choices(("white_concrete", "red_concrete", "blue_concrete", "green_concrete", - "yellow_concrete", "black_concrete", "purple_concrete", "pink_concrete"))[0] - x_line(xc + xi, xc + xo, yc + y, colour) - y_line(xc + y, yc + xi, yc + xo, colour) - x_line(xc - xo, xc - xi, yc + y, colour) - y_line(xc - y, yc + xi, yc + xo, colour) - x_line(xc - xo, xc - xi, yc - y, colour) - y_line(xc - y, yc - xo, yc - xi, colour) - x_line(xc + xi, xc + xo, yc - y, colour) - y_line(xc + y, yc - xo, yc - xi, colour) - - y += 1 - - if erro < 0: - erro += 2 * y + 1 - else: - xo -= 1 - erro += 2 * (y - xo + 1) - - if y > inner: - xi = y - else: - if erri < 0: - erri += 2 * y + 1 - else: - xi -= 1 - erri += 2 * (y - xi + 1) - - -# print("\n") -# circle2(-1606, 758, 5, 15) -# circle2(-1606, 758, 5, 5) -# circle2(-1606, 758, 10, 10) -circle2(-1606, 758, 15, 17) - - -class LineOverlap(Enum): - NONE = 0 - MAJOR = 1 - MINOR = 2 - - -class LineThicknessMode(Enum): - MIDDLE = 0 - DRAW_COUNTERCLOCKWISE = 1 - DRAW_CLOCKWISE = 2 - - -class Point2D: - def __init__(self, x, y): - self.x = x - self.y = y - - def __repr__(self): - return f"({self.x} {self.y})" - - def copy(self): - return Point2D(self.x, self.y) - - def get_coordinates(self): - return (self.x, self.y) - - -def drawLineOverlap(start, end, overlap): - y = 120 - block = random.choices(("white_concrete", "red_concrete", "blue_concrete", "green_concrete", - "yellow_concrete", "black_concrete", "purple_concrete", "pink_concrete"))[0] - print(block) - editor = Editor(buffering=True) - - start = start.copy() - end = end.copy() - - # Direction - delta_x = end.x - start.x - delta_y = end.y - start.y - - if (delta_x < 0): - delta_x = -delta_x - step_x = -1 - else: - step_x = +1 - - if (delta_y < 0): - delta_y = -delta_y - step_y = -1 - else: - step_y = +1 - - delta_2x = 2*delta_x - delta_2y = 2*delta_y - - print(start.x, start.y) - editor.placeBlock((start.x, y, start.y), Block(block)) - - if (delta_x > delta_y): - error = delta_2y - delta_x - while (start.x != end.x): - start.x += step_x - if (error >= 0): - if (overlap == LineOverlap.MAJOR): - print(start.x, start.y) - editor.placeBlock((start.x, y, start.y), - Block(block)) - - start.y += step_y - if (overlap == LineOverlap.MINOR): - print(start.x - step_x, start.y) - editor.placeBlock((start.x - step_x, y, start.y), - Block(block)) - error -= delta_2x - error += delta_2y - print(start.x, start.y) - editor.placeBlock((start.x, y, start.y), - Block(block)) - else: - error = delta_2x - delta_y - while (start.y != end.y): - start.y += step_y - if (error >= 0): - if (overlap == LineOverlap.MAJOR): - print(start) - editor.placeBlock((start.x, y, start.y), - Block(block)) - start.x += step_x - if (overlap == LineOverlap.MINOR): - print(start.x, start.y - step.y, start.z, ) - editor.placeBlock((start.x, y, start.y - step.y), - Block(block)) - error -= delta_2y - error += delta_2x - print(start.x, start.y) - editor.placeBlock((start.x, y, start.y), - Block("white_concrete")) - - -# drawLineOverlap(Point2D(-10, 0, 0,), Point2D(10, 0, 3), -# LineOverlap.NONE) - - -def drawThickLine(start, end, thickness, thickness_mode): - delta_y = end.x - start.x - delta_x = end.y - start.y - - print("START", start) - - swap = True - if delta_x < 0: - delta_x = -delta_x - step_x = -1 - swap = not swap - else: - step_x = +1 - - if (delta_y < 0): - delta_y = -delta_y - step_y = -1 - swap = not swap - else: - step_y = +1 - - delta_2x = 2 * delta_x - delta_2y = 2 * delta_y - - draw_start_adjust_count = int(thickness / 2) - if (thickness_mode == LineThicknessMode.DRAW_COUNTERCLOCKWISE): - draw_start_adjust_count = thickness - 1 - elif (thickness_mode == LineThicknessMode.DRAW_CLOCKWISE): - draw_start_adjust_count = 0 - print("START", start) - if (delta_x >= delta_y): - if swap: - draw_start_adjust_count = (thickness - 1) - draw_start_adjust_count - step_y = -step_y - else: - step_x = -step_x - - error = delta_2y - delta_x - for i in range(draw_start_adjust_count, 0, -1): - print("START", start) - start.x -= step_x - end.x -= step_x - if error >= 0: - start.y -= step_y - end.y -= step_y - error -= delta_2x - error += delta_2x - print("START", start) - print("First print") - print(start, end) - drawLineOverlap(start, end, LineOverlap.NONE) - print(start, end) - print("End print") - - error = delta_2x - delta_x - for i in range(thickness, 1, -1): - start.x += step_x - end.x += step_x - overlap = LineOverlap.NONE - if (error >= 0): - start.y += step_y - end.y += step_y - error -= delta_2x - overlap = LineOverlap.MAJOR - error += delta_2y - print("Second print") - print(start, end) - drawLineOverlap(start, end, overlap) - print(start, end) - print("End print") - else: - if swap: - step_x = -step_x - else: - draw_start_adjust_count = (thickness - 1) - draw_start_adjust_count - step_y = -step_y - - error = delta_2x - delta_y - for i in range(draw_start_adjust_count, 0, -1): - start.y -= step_y - end.y -= step_y - if (error >= 0): - start.x -= step_x - end.x -= step_x - error -= delta_2y - error += delta_2x - - print("Third line") - print(start, end) - drawLineOverlap(start, end, LineOverlap.NONE) - print(start, end) - print("End line") - error = delta_2x - delta_y - for i in range(thickness, 1, -1): - start.y += step_y - end.y += step_y - overlap = LineOverlap.NONE - if (error >= 0): - start.x += step_x - end.x += step_x - error -= delta_2y - overlap = LineOverlap.MAJOR - error += delta_2x - print("Fourth line") - print(start, end) - drawLineOverlap(start, end, overlap) - print(start, end) - print("End") - - -print("SPACE\n\n") -drawThickLine(Point2D(-1681, 864), Point2D(-1804, 920), - 21, LineThicknessMode.MIDDLE)