Error detection in bresenham circle

This commit is contained in:
2024-06-19 13:42:26 +02:00
parent 07c36d2bf7
commit f301f46f91
24 changed files with 156 additions and 57 deletions

View File

@@ -1,5 +1,5 @@
from math import cos, pi, sin
from typing import List
from typing import List, Dict
import numpy as np
@@ -17,6 +17,9 @@ class Circle:
self.outer = None
self.points_thick: List[Point2D] = []
self.points_thick_by_line: List[List[Point2D]] = []
self.gaps: List[Point2D] = []
self.spaced_radius = None
self.spaced_points: List[Point2D] = []
@@ -24,6 +27,7 @@ class Circle:
return f"Circle(center: {self.center}, radius: {self.radius}, spaced_radius: {self.spaced_radius}, inner: {self.inner}, outer: {self.outer})"
def circle(self, radius: int) -> List[Point2D]:
self.points = []
self.radius = radius
center = self.center.copy()
@@ -48,8 +52,59 @@ class Circle:
break
return self.points
def circle_thick_by_line(self, inner: int, outter: int) -> List[List[Point2D]]:
width = outter - inner
self.circle_thick_by_line = [[] for _ in range(width)]
for i in range(width):
self.circle_thick_by_line[i] = self.circle(inner + i)
if i > 0:
self.gaps.append(Circle._remove_gaps(
self.circle_thick_by_line[i], self.circle_thick_by_line[i-1]))
return self.circle_thick_by_line, self.gaps
@staticmethod
def _remove_gaps(outter_line: List[Point2D], inner_line: List[Point2D]) -> List[Point2D]:
gaps = []
for i in range(len(outter_line)):
if Circle._count_neighbors(outter_line[i], inner_line) == 0:
if Circle._count_neighbors(Point2D(outter_line[i].x-1, outter_line[i].y), inner_line) > 1:
if Point2D(outter_line[i].x-1, outter_line[i].y) not in outter_line:
gaps.append(
Point2D(outter_line[i].x-1, outter_line[i].y))
if Circle._count_neighbors(Point2D(outter_line[i].x+1, outter_line[i].y), inner_line) > 1:
if Point2D(outter_line[i].x+1, outter_line[i].y) not in outter_line:
gaps.append(
Point2D(outter_line[i].x+1, outter_line[i].y))
if Circle._count_neighbors(Point2D(outter_line[i].x, outter_line[i].y-1), inner_line) > 1:
if Point2D(outter_line[i].x, outter_line[i].y-1) not in outter_line:
gaps.append(
Point2D(outter_line[i].x, outter_line[i].y-1))
if Circle._count_neighbors(Point2D(outter_line[i].x, outter_line[i].y+1), inner_line) > 1:
if Point2D(outter_line[i].x, outter_line[i].y+1) not in outter_line:
gaps.append(
Point2D(outter_line[i].x, outter_line[i].y+1))
return gaps
@ staticmethod
def _count_neighbors(point: Point2D, line: List[Point2D]) -> int:
neighbors = 0
for i in range(len(line)):
if point.x == line[i].x:
if point.y == line[i].y:
return 0
if point.y-1 == line[i].y:
neighbors += 1
if point.y+1 == line[i].y:
neighbors += 1
if point.y == line[i].y:
if point.x-1 == line[i].x:
neighbors += 1
if point.x+1 == line[i].x:
neighbors += 1
return neighbors
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.
From: https://stackoverflow.com/questions/27755514/circle-with-thickness-drawing-algorithm
@@ -108,7 +163,7 @@ class 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.
number (int): Number of coordinates to be returned.
radius (int): Radius of the circle.
Returns:

View File

@@ -12,12 +12,13 @@ class Segment2D:
self.end = end
self.points: List[Point2D] = []
self.points_thick: List[Point2D] = []
self.points_thick_by_line: List[Union[Point2D, int]] = []
self.thickness = None
def __repr__(self):
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) -> Union[List[Point2D], None]:
def segment(self, start: Point2D = None, end: Point2D = None, overlap: LINE_OVERLAP = LINE_OVERLAP.NONE, _is_computing_thickness: int = 0) -> Union[List[Point2D], None]:
"""Modified Bresenham draw (line) with optional overlap.
From: https://github.com/ArminJo/Arduino-BlueDisplay/blob/master/src/LocalGUI/ThickLine.hpp
@@ -108,6 +109,8 @@ class Segment2D:
>>> self.compute_thick_segment(self.start, self.end, self.thickness, self.thickness_mode)
"""
self.points_thick_by_line = [[] for _ in range(thickness+1)]
start = self.start.copy()
end = self.end.copy()
@@ -158,7 +161,7 @@ class Segment2D:
error += delta_2x
self.segment(
start, end, overlap=LINE_OVERLAP.NONE, _is_computing_thickness=True)
start, end, overlap=LINE_OVERLAP.NONE, _is_computing_thickness=1)
error = delta_2x - delta_x
for i in range(thickness, 1, -1):
@@ -173,7 +176,7 @@ class Segment2D:
error += delta_2y
self.segment(
start, end, overlap=overlap, _is_computing_thickness=True)
start, end, overlap=overlap, _is_computing_thickness=i)
else:
if swap:
@@ -194,7 +197,7 @@ class Segment2D:
error += delta_2x
self.segment(
start, end, overlap=LINE_OVERLAP.NONE, _is_computing_thickness=True)
start, end, overlap=LINE_OVERLAP.NONE, _is_computing_thickness=1)
error = delta_2x - delta_y
for i in range(thickness, 1, -1):
@@ -209,7 +212,7 @@ class Segment2D:
error += delta_2x
self.segment(
start, end, overlap=overlap, _is_computing_thickness=True)
start, end, overlap=overlap, _is_computing_thickness=i)
return self.points_thick
@@ -241,7 +244,9 @@ class Segment2D:
)
def _add_points(self, points, is_computing_thickness):
if is_computing_thickness:
if is_computing_thickness > 0:
self.points_thick.append(points.copy())
self.points_thick_by_line[is_computing_thickness].append(
(points.copy()))
else:
self.points.append(points.copy())

View File

@@ -62,8 +62,30 @@ class Road:
# Get nearest in x,z projection
nearest = self.polyline.segments[i].points_thick[j].nearest(
Point3D.to_2d(self.polyline_total_line_output, removed_axis='y'), True)
self.output_block.append(
(Point3D.insert_3d([self.polyline.segments[i].points_thick[j]], 'y', [self.polyline_total_line_output[nearest[0]].y])[0].coordinates, Block("stone")))
# self.output_block.append(
# (Point3D.insert_3d([self.polyline.segments[i].points_thick[j]], 'y', [self.polyline_total_line_output[nearest[0]].y])[0].coordinates, Block("stone")))
for k in range(len(self.polyline.segments[i].points_thick_by_line)):
match k:
case 0:
blob = 'black_concrete'
case 1:
blob = 'red_concrete'
case 2:
blob = 'orange_concrete'
case 3:
blob = 'yellow_concrete'
case 4:
blob = 'green_concrete'
case 5:
blob = 'blue_concrete'
case 6:
blob = 'purple_concrete'
for m in range(len(self.polyline.segments[i].points_thick_by_line[k])):
nearest = self.polyline.segments[i].points_thick_by_line[k][m].nearest(
Point3D.to_2d(self.polyline_total_line_output, removed_axis='y'), True)
self.output_block.append(
(Point3D.insert_3d([self.polyline.segments[i].points_thick_by_line[k][m]], 'y', [self.polyline_total_line_output[nearest[0]].y])[0].coordinates, Block(blob)))
for i in range(1, len(self.polyline.centers)-1):
# Circle