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

109
main.py
View File

@@ -7,66 +7,83 @@ from world_maker.data_analysis import transpose_form_heightmap
from world_maker.Skeleton import Skeleton, simplify_coordinates from world_maker.Skeleton import Skeleton, simplify_coordinates
from world_maker.terraforming import remove_trees, smooth_terrain from world_maker.terraforming import remove_trees, smooth_terrain
from networks.geometry.Point3D import Point3D from networks.geometry.Point3D import Point3D
from networks.geometry.Point2D import Point2D
from networks.roads_2.Road import Road from networks.roads_2.Road import Road
from networks.legacy_roads import roads from networks.legacy_roads import roads
from world_maker.District import Road as Road_grid from world_maker.District import Road as Road_grid
from networks.geometry.Circle import Circle
from House import * from House import *
from gdpc import Editor, Block
def main(): def main():
rectangle_house_mountain, rectangle_building, skeleton_highway, skeleton_mountain, road_grid = world_maker()
editor = Editor(buffering=True) editor = Editor(buffering=True)
buildArea = editor.getBuildArea() c = Circle(Point2D(400, -75)).circle_thick_by_line(5, 32)
origin = ((buildArea.begin).x, (buildArea.begin).z) for i in range(len(c[0])):
for j in range(len(c[0][i])):
if i % 2 == 0:
editor.placeBlock(
(c[0][i][j].x, 110, c[0][i][j].y), Block("white_concrete"))
else:
editor.placeBlock(
(c[0][i][j].x, 110, c[0][i][j].y), Block("black_concrete"))
print(c[1])
for i in range(len(c[1])):
for j in range(len(c[1][i])):
editor.placeBlock(
(c[1][i][j].x, 110, c[1][i][j].y), Block("red_concrete"))
# rectangle_house_mountain, rectangle_building, skeleton_highway, skeleton_mountain, road_grid = world_maker()
remove_trees('./world_maker/data/heightmap.png', './world_maker/data/treemap.png', # editor = Editor(buffering=True)
'./world_maker/data/smooth_sobel_watermap.png') # buildArea = editor.getBuildArea()
smooth_terrain('./world_maker/data/heightmap.png', # origin = ((buildArea.begin).x, (buildArea.begin).z)
'./world_maker/data/heightmap_smooth.png', './world_maker/data/smooth_sobel_watermap.png')
# set_roads(skeleton_mountain, origin) # remove_trees('./world_maker/data/heightmap.png', './world_maker/data/treemap.png',
# set_roads(skeleton_highway, origin) # './world_maker/data/smooth_sobel_watermap.png')
# set_roads_grids(road_grid, origin) # smooth_terrain('./world_maker/data/heightmap.png',
# roads.setRoads(skeleton_mountain) # './world_maker/data/heightmap_smooth.png', './world_maker/data/smooth_sobel_watermap.png')
# roads.setRoads(skeleton_highway)
blocks = { # # set_roads(skeleton_mountain, origin)
"wall": "blackstone", # # set_roads(skeleton_highway, origin)
"roof": "blackstone", # # set_roads_grids(road_grid, origin)
"roof_slab": "blackstone_slab", # # roads.setRoads(skeleton_mountain)
"door": "oak_door", # # roads.setRoads(skeleton_highway)
"window": "glass_pane",
"entrance": "oak_door",
"stairs": "quartz_stairs",
"stairs_slab": "quartz_slab",
"celling": "quartz_block",
"floor": "quartz_block",
"celling_slab": "quartz_slab",
"garden_outline": "oak_leaves",
"garden_floor": "grass_block"
}
entranceDirection = ["N", "S", "E", "W"] # blocks = {
# "wall": "blackstone",
# "roof": "blackstone",
# "roof_slab": "blackstone_slab",
# "door": "oak_door",
# "window": "glass_pane",
# "entrance": "oak_door",
# "stairs": "quartz_stairs",
# "stairs_slab": "quartz_slab",
# "celling": "quartz_block",
# "floor": "quartz_block",
# "celling_slab": "quartz_slab",
# "garden_outline": "oak_leaves",
# "garden_floor": "grass_block"
# }
for houses in rectangle_building: # entranceDirection = ["N", "S", "E", "W"]
start = (houses[0][0]+buildArea.begin[0], houses[0]
[1], houses[0][2]+buildArea.begin[2])
end = (houses[1][0]+buildArea.begin[0], houses[1]
[1], houses[1][2]+buildArea.begin[2])
house = House(editor, start, end,
entranceDirection[random.randint(0, 3)], blocks)
house.build()
for houses in rectangle_house_mountain: # for houses in rectangle_building:
start = (houses[0][0]+buildArea.begin[0], houses[0] # start = (houses[0][0]+buildArea.begin[0], houses[0]
[1], houses[0][2]+buildArea.begin[2]) # [1], houses[0][2]+buildArea.begin[2])
end = (houses[1][0]+buildArea.begin[0], houses[1] # end = (houses[1][0]+buildArea.begin[0], houses[1]
[1], houses[1][2]+buildArea.begin[2]) # [1], houses[1][2]+buildArea.begin[2])
house = House(editor, start, end, # house = House(editor, start, end,
entranceDirection[random.randint(0, 3)], blocks) # entranceDirection[random.randint(0, 3)], blocks)
house.build() # house.build()
# for houses in rectangle_house_mountain:
# start = (houses[0][0]+buildArea.begin[0], houses[0]
# [1], houses[0][2]+buildArea.begin[2])
# end = (houses[1][0]+buildArea.begin[0], houses[1]
# [1], houses[1][2]+buildArea.begin[2])
# house = House(editor, start, end,
# entranceDirection[random.randint(0, 3)], blocks)
# house.build()
def set_roads_grids(road_grid: Road_grid, origin): def set_roads_grids(road_grid: Road_grid, origin):

View File

@@ -1,5 +1,5 @@
from math import cos, pi, sin from math import cos, pi, sin
from typing import List from typing import List, Dict
import numpy as np import numpy as np
@@ -17,6 +17,9 @@ class Circle:
self.outer = None self.outer = None
self.points_thick: List[Point2D] = [] self.points_thick: List[Point2D] = []
self.points_thick_by_line: List[List[Point2D]] = []
self.gaps: List[Point2D] = []
self.spaced_radius = None self.spaced_radius = None
self.spaced_points: List[Point2D] = [] 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})" 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]: def circle(self, radius: int) -> List[Point2D]:
self.points = []
self.radius = radius self.radius = radius
center = self.center.copy() center = self.center.copy()
@@ -48,8 +52,59 @@ class Circle:
break break
return self.points 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]: 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 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 From: https://stackoverflow.com/questions/8487893/generate-all-the-points-on-the-circumference-of-a-circle
Args: Args:
number (int): Number of coordinates to be returned. number (int): Number of coordinates to be returned.
radius (int): Radius of the circle. radius (int): Radius of the circle.
Returns: Returns:

View File

@@ -12,12 +12,13 @@ class Segment2D:
self.end = end self.end = end
self.points: List[Point2D] = [] self.points: List[Point2D] = []
self.points_thick: List[Point2D] = [] self.points_thick: List[Point2D] = []
self.points_thick_by_line: List[Union[Point2D, int]] = []
self.thickness = None self.thickness = None
def __repr__(self): def __repr__(self):
return str(f"Segment2D(start: {self.start}, end: {self.end}, points: {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) -> 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. """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
@@ -108,6 +109,8 @@ class Segment2D:
>>> self.compute_thick_segment(self.start, self.end, self.thickness, self.thickness_mode) >>> 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() start = self.start.copy()
end = self.end.copy() end = self.end.copy()
@@ -158,7 +161,7 @@ class Segment2D:
error += delta_2x error += delta_2x
self.segment( 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 error = delta_2x - delta_x
for i in range(thickness, 1, -1): for i in range(thickness, 1, -1):
@@ -173,7 +176,7 @@ class Segment2D:
error += delta_2y error += delta_2y
self.segment( self.segment(
start, end, overlap=overlap, _is_computing_thickness=True) start, end, overlap=overlap, _is_computing_thickness=i)
else: else:
if swap: if swap:
@@ -194,7 +197,7 @@ class Segment2D:
error += delta_2x error += delta_2x
self.segment( 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 error = delta_2x - delta_y
for i in range(thickness, 1, -1): for i in range(thickness, 1, -1):
@@ -209,7 +212,7 @@ class Segment2D:
error += delta_2x error += delta_2x
self.segment( self.segment(
start, end, overlap=overlap, _is_computing_thickness=True) start, end, overlap=overlap, _is_computing_thickness=i)
return self.points_thick return self.points_thick
@@ -241,7 +244,9 @@ class Segment2D:
) )
def _add_points(self, points, is_computing_thickness): 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.append(points.copy())
self.points_thick_by_line[is_computing_thickness].append(
(points.copy()))
else: else:
self.points.append(points.copy()) self.points.append(points.copy())

View File

@@ -62,8 +62,30 @@ class Road:
# Get nearest in x,z projection # Get nearest in x,z projection
nearest = self.polyline.segments[i].points_thick[j].nearest( nearest = self.polyline.segments[i].points_thick[j].nearest(
Point3D.to_2d(self.polyline_total_line_output, removed_axis='y'), True) Point3D.to_2d(self.polyline_total_line_output, removed_axis='y'), True)
self.output_block.append( # 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"))) # (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): for i in range(1, len(self.polyline.centers)-1):
# Circle # Circle

Binary file not shown.

Before

Width:  |  Height:  |  Size: 255 B

After

Width:  |  Height:  |  Size: 117 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 311 B

After

Width:  |  Height:  |  Size: 89 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 972 B

After

Width:  |  Height:  |  Size: 418 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 269 B

After

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 825 B

After

Width:  |  Height:  |  Size: 608 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 604 B

After

Width:  |  Height:  |  Size: 121 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 540 B

After

Width:  |  Height:  |  Size: 322 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 292 B

After

Width:  |  Height:  |  Size: 290 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 354 B

After

Width:  |  Height:  |  Size: 505 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 627 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 569 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 B

After

Width:  |  Height:  |  Size: 208 B