Error detection in bresenham circle
109
main.py
@@ -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):
|
||||||
|
|||||||
@@ -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,6 +52,57 @@ 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.
|
||||||
|
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 255 B After Width: | Height: | Size: 117 B |
|
Before Width: | Height: | Size: 311 B After Width: | Height: | Size: 89 B |
|
Before Width: | Height: | Size: 972 B After Width: | Height: | Size: 418 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 766 B |
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 269 B After Width: | Height: | Size: 194 B |
|
Before Width: | Height: | Size: 825 B After Width: | Height: | Size: 608 B |
|
Before Width: | Height: | Size: 604 B After Width: | Height: | Size: 121 B |
|
Before Width: | Height: | Size: 540 B After Width: | Height: | Size: 322 B |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 292 B After Width: | Height: | Size: 290 B |
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 354 B After Width: | Height: | Size: 505 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 627 B |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 569 B |
|
Before Width: | Height: | Size: 101 B After Width: | Height: | Size: 208 B |