Files
GDMC-2024/networks/roads_2/Road.py

194 lines
10 KiB
Python

import json
from typing import List
from networks.geometry.Polyline import Polyline
from networks.geometry.Point3D import Point3D
from networks.geometry.Point2D import Point2D
from networks.geometry.Segment2D import Segment2D
from networks.geometry.Segment3D import Segment3D
from networks.geometry.Circle import Circle
from utils.Enums import LINE_THICKNESS_MODE
from gdpc import Block, Editor, geometry
class Road:
def __init__(self, coordinates: List[Point3D], width: int):
self.coordinates = self._remove_collinear_points(coordinates)
self.output_block = []
# with open(road_configuration) as f:
# self.road_configuration = json.load(f)
# self.width = self.road_configuration["width"]
self.width = width
self.polyline_height = None
self.polyline_total_line_output = None
self.segment_total_line_output = None
self.index_factor = 0
if len(self._remove_collinear_points(self.coordinates)) >= 4:
self.polyline = Polyline(Point3D.to_2d(coordinates, 'y'))
self.polyline_total_line_output = [
[] for _ in range(len(self.polyline.total_line_output))]
self._projection_polyline()
if len(self.coordinates) == 2:
self.segment_total_line_output = Segment2D(
Point3D.to_2d([self.coordinates[0]], 'y')[0], Point3D.to_2d([self.coordinates[1]], 'y')[0]).segment_thick(self.width, LINE_THICKNESS_MODE.MIDDLE)
self._projection_segment()
self.place()
@staticmethod
def _remove_collinear_points(points):
output_points = [points[0]]
for i in range(1, len(points) - 1):
if isinstance(points[0], Point3D):
if not Point2D.collinear(
Point3D.to_2d([points[i-1]], 'y')[0], Point3D.to_2d([points[i]], 'y')[0], Point3D.to_2d([points[i+1]], 'y')[0]):
output_points.append(points[i])
else:
if not Point2D.collinear(points[i-1], points[i], points[i+1]):
output_points.append(points[i])
output_points.append(points[-1])
return output_points
def _surface(self):
# Segments
for i in range(1, len(self.polyline.segments)):
if len(self.polyline.segments[i].segment()) > 2:
for j in range(len(self.polyline.segments[i].segment_thick(self.width, LINE_THICKNESS_MODE.MIDDLE))):
# 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")))
for k in range(len(self.polyline.segments[i].points_thick_by_line)):
kk = k % 7
match kk:
case 0:
blob = 'pink_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 m in range(len(self.polyline.segments[i].gaps[k])):
nearest = self.polyline.segments[i].gaps[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].gaps[k][m]], 'y', [self.polyline_total_line_output[nearest[0]].y])[0].coordinates, Block("black_concrete")))
for i in range(1, len(self.polyline.centers)-1):
# Circle
circle, gaps = Circle(self.polyline.centers[i]).circle_thick_by_line(int(
(self.polyline.radii[i]-self.width/2))+1, int((self.polyline.radii[i]+self.width/2))+1)
# Better to do here than drawing circle arc inside big triangle!
double_point_a = Point2D.from_arrays(Point2D.to_arrays(self.polyline.acrs_intersections[i][0]) + 5 * (Point2D.to_arrays(
self.polyline.acrs_intersections[i][0]) - Point2D.to_arrays(self.polyline.centers[i])))
double_point_b = Point2D.from_arrays(Point2D.to_arrays(self.polyline.acrs_intersections[i][2]) + 5 * (Point2D.to_arrays(
self.polyline.acrs_intersections[i][2]) - Point2D.to_arrays(self.polyline.centers[i])))
editor = Editor(buffering=True)
editor.placeBlock(Point3D.insert_3d(
[self.polyline.acrs_intersections[i][0]], 'y', [230])[0].coordinates, Block("purple_concrete"))
editor.placeBlock(Point3D.insert_3d(
[self.polyline.acrs_intersections[i][2]], 'y', [230])[0].coordinates, Block("pink_concrete"))
geometry.placeLine(editor, Point3D.insert_3d([double_point_a], 'y', [229])[
0].coordinates, Point3D.insert_3d([self.polyline.centers[i]], 'y', [229])[0].coordinates, Block("blue_concrete"))
geometry.placeLine(editor, Point3D.insert_3d([double_point_b], 'y', [229])[
0].coordinates, Point3D.insert_3d([self.polyline.centers[i]], 'y', [229])[0].coordinates, Block("red_concrete"))
for j in range(len(circle)):
for k in range(len(circle[j])):
jj = j % 7
match jj:
case 0:
blob = 'pink_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'
if circle[j][k].is_in_triangle(double_point_a, self.polyline.centers[i], double_point_b):
nearest = circle[j][k].nearest(
Point3D.to_2d(self.polyline_total_line_output, removed_axis='y'), True)
self.output_block.append(
(Point3D.insert_3d([circle[j][k]], 'y', [
self.polyline_total_line_output[nearest[0]].y])[0].coordinates, Block(blob)))
for j in range(len(gaps)):
for k in range(len(gaps[j])):
if gaps[j][k].is_in_triangle(double_point_a, self.polyline.centers[i], double_point_b):
nearest = gaps[j][k].nearest(
Point3D.to_2d(self.polyline_total_line_output, removed_axis='y'), True)
self.output_block.append(
(Point3D.insert_3d([gaps[j][k]], 'y', [
self.polyline_total_line_output[nearest[0]].y])[0].coordinates, Block("white_concrete")))
def _projection_polyline(self):
nearest_points_to_reference = []
for i in range(len(self.coordinates)):
# nearest_points_to_reference.append(Point3D.insert_3d([Point3D.to_2d([self.coordinates[i]], 'y')[0].nearest(
# self.polyline.total_line_output, return_index=True)], 'y', [self.coordinates[i].y])[0])
index, point = Point3D.to_2d([self.coordinates[i]], 'y')[0].nearest(
self.polyline.total_line_output, return_index=True)
nearest_points_to_reference.append(
Point2D(index, self.coordinates[i].y))
if len(self._remove_collinear_points(nearest_points_to_reference)) >= 4:
self.polyline_height = Polyline(nearest_points_to_reference)
self.index_factor = len(
self.polyline_height.total_line_output)/len(self.polyline.total_line_output)
for i in range(len(self.polyline.total_line_output)):
self.polyline_total_line_output[i] = Point3D(
self.polyline.total_line_output[i].x, self.polyline_height.total_line_output[round(i*self.index_factor)].y, self.polyline.total_line_output[i].y)
self._surface()
self.place()
# self.polyline_total_line_output = self.polyline_total_line_output[0].optimized_path(
# self.polyline_total_line_output)
def _projection_segment(self):
s = Segment3D(
self.coordinates[0], self.coordinates[1])
reference = s.segment()
for i in range(len(self.segment_total_line_output)):
self.output_block.append(((
self.segment_total_line_output[i].x, reference[self.segment_total_line_output[i].nearest(Point3D.to_2d(reference, 'y'), True)[0]].y, self.segment_total_line_output[i].y), Block("black_concrete")))
def place(self):
editor = Editor(buffering=True)
for i in range(len(self.output_block)):
editor.placeBlock(self.output_block[i][0],
self.output_block[i][1])