From ed5d7f85a5b7aa7bc883ab2817f4be45f893b77f Mon Sep 17 00:00:00 2001 From: Xeon0X Date: Sun, 16 Jun 2024 16:35:15 +0200 Subject: [PATCH] Add legacy support --- main.py | 18 +- networks/legacy_roads/Skeleton.py | 210 ++ networks/legacy_roads/house.py | 2005 +++++++++++++++++++ networks/legacy_roads/list_block.py | 117 ++ networks/legacy_roads/maths.py | 1155 +++++++++++ networks/legacy_roads/roads.py | 662 ++++++ networks/legacy_roads/tools.py | 40 + world_maker/data/building.png | Bin 344 -> 509 bytes world_maker/data/city_map.png | Bin 3122 -> 1317 bytes world_maker/data/district.png | Bin 5701 -> 1474 bytes world_maker/data/heightmap.png | Bin 20128 -> 11218 bytes world_maker/data/highwaymap.png | Bin 843 -> 439 bytes world_maker/data/mountain_map.png | Bin 1573 -> 989 bytes world_maker/data/roadmap.png | Bin 1571 -> 824 bytes world_maker/data/skeleton_highway.png | Bin 19763 -> 10911 bytes world_maker/data/skeleton_highway_area.png | Bin 876 -> 469 bytes world_maker/data/skeleton_mountain.png | Bin 21966 -> 10706 bytes world_maker/data/skeleton_mountain_area.png | Bin 1398 -> 119 bytes world_maker/data/smooth_sobel_watermap.png | Bin 3782 -> 2003 bytes world_maker/data/sobelmap.png | Bin 25992 -> 14284 bytes world_maker/data/treemap.png | Bin 813 -> 6698 bytes world_maker/data/watermap.png | Bin 2466 -> 119 bytes 22 files changed, 4204 insertions(+), 3 deletions(-) create mode 100644 networks/legacy_roads/Skeleton.py create mode 100644 networks/legacy_roads/house.py create mode 100644 networks/legacy_roads/list_block.py create mode 100644 networks/legacy_roads/maths.py create mode 100644 networks/legacy_roads/roads.py create mode 100644 networks/legacy_roads/tools.py diff --git a/main.py b/main.py index 7639db0..e81366e 100644 --- a/main.py +++ b/main.py @@ -6,6 +6,7 @@ from world_maker.world_maker import * from world_maker.Skeleton import Skeleton, transpose_form_heightmap, simplify_coordinates from networks.geometry.Point3D import Point3D from networks.roads_2.Road import Road +from networks.legacy_roads import roads from world_maker.District import Road as Road_grid from House import * @@ -17,9 +18,11 @@ def main(): editor = Editor(buffering=True) buildArea = editor.getBuildArea() - set_roads(skeleton_mountain) - set_roads(skeleton_highway) - set_roads_grids(road_grid) + # set_roads(skeleton_mountain) + # set_roads(skeleton_highway) + # set_roads_grids(road_grid) + roads.setRoads(skeleton_mountain) + roads.setRoads(skeleton_highway) blocks = { "wall": "blackstone", @@ -39,6 +42,15 @@ def main(): entranceDirection = ["N", "S", "E", "W"] + for houses in rectangle_building: + 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: start = (houses[0][0]+buildArea.begin[0], houses[0] [1], houses[0][2]+buildArea.begin[2]) diff --git a/networks/legacy_roads/Skeleton.py b/networks/legacy_roads/Skeleton.py new file mode 100644 index 0000000..277f584 --- /dev/null +++ b/networks/legacy_roads/Skeleton.py @@ -0,0 +1,210 @@ +import numpy as np +import skan +from skimage.morphology import skeletonize +from skan.csr import skeleton_to_csgraph +from collections import Counter +from PIL import Image +import random + +from gdpc import Editor + + +class Skeleton: + def __init__(self): + self.lines = [] + self.intersections = [] + self.centers = [] + self.graph = [] + self.coordinates = [] + + def setSkeleton(self, data): + binary_skeleton = skeletonize(data) + + graph, coordinates = skeleton_to_csgraph(binary_skeleton) + self.graph = graph.tocoo() + + # List of lists. Inverted coordinates. + coordinates = list(coordinates) + print(coordinates) + for i in range(len(coordinates)): + coordinates[i] = list(coordinates[i]) + + print(coordinates) + coordinates_final = [] + + for i in range(len(coordinates[0])): + print((coordinates[0][i], coordinates[1][i], coordinates[2][i])) + coordinates_final.append( + (coordinates[0][i], coordinates[1][i], coordinates[2][i])) + + self.coordinates = coordinates_final + + def findNextElements(self, key): + """Find the very nearest elements""" + + line = [] + + values = np.array(self.graph.row) + indices = np.where(values == key)[0] + + for i in range(len(indices)): + if self.graph.row[indices[i]] == key: + line.append(self.graph.col[indices[i]]) + return line + + def findLine(self, key): + nextKeys = self.findNextElements(key) + + if len(nextKeys) >= 3: # Intersections. + return nextKeys + + if len(nextKeys) == 2 or len(nextKeys) == 1: # In line or endpoints. + line = [] + line.append(key) + line.insert(0, nextKeys[0]) + if len(nextKeys) == 2: + line.insert(len(line), nextKeys[1]) + + nextKeys = line[0], line[-1] + + while len(nextKeys) == 2 or len(nextKeys) == 1: + extremity = [] + for key in nextKeys: + nextKeys = self.findNextElements(key) + + if len(nextKeys) <= 2: + # Add the neighbors that is not already in the line. + for element in nextKeys: + if element not in line: + extremity.append(element) + line.append(element) + + if len(nextKeys) >= 3: + # Add the intersection only. + extremity.append(key) + + nextKeys = [] + for key in extremity: + ends = self.findNextElements(key) + if len(ends) == 2: + nextKeys.append(key) + return line + + def parseGraph(self): + for key, value in sorted( + Counter(self.graph.row).items(), key=lambda kv: kv[1], reverse=True + ): + # Start from the biggest intersections. + if value != 2: # We don't want to be in the middle of a line. + line = self.findLine(key) + + # We have now all the connected points if it's an + # intersection. We need to find the line. + + if value != 1: + # It's not an endpoint. + self.centers.append(key) + self.intersections.append(line) + for i in line: + line = self.findLine(i) + + if i in line: + # The key is inside the result : it's a line. + alreadyInside = False + for l in self.lines: + # Verification if not already inside. + if Counter(l) == Counter(line): + alreadyInside = True + # print(line, "inside", lines) + + if alreadyInside == False: + self.lines.append(line) + else: + # The key is not inside the result, it's an + # intersection directly connected to the key. + line = [key, i] + alreadyInside = False + for l in self.lines: + # Verification if not already inside. + if Counter(l) == Counter(line): + alreadyInside = True + # print(line, "inside", lines) + + if alreadyInside == False: + self.lines.append(line) + + def map(self): + """ + + Generate an image to visualize 2D path of the skeleton. + + Returns: + image: 2D path of the skeleton on top of the heightmap. + """ + editor = Editor() + + buildArea = editor.getBuildArea() + buildRect = buildArea.toRect() + xzStart = buildRect.begin + xzDistance = (max(buildRect.end[0], buildRect.begin[0]) - min(buildRect.end[0], buildRect.begin[0]), max( + buildRect.end[1], buildRect.begin[1]) - min(buildRect.end[1], buildRect.begin[1])) + + heightmap = Image.open("data/heightmap.png").convert('RGB') + roadsArea = Image.new("L", xzDistance, 0) + width, height = heightmap.size + + # Lines + for i in range(len(self.lines)): + r, g, b = (random.randint(0, 255), random.randint( + 0, 255), random.randint(0, 255)) + + for j in range(len(self.lines[i])): + + z = self.coordinates[self.lines[i][j]][0] + y = self.coordinates[self.lines[i][j]][1] + x = self.coordinates[self.lines[i][j]][2] + + heightmap.putpixel( + ( + int(z), + int(x), + ), + (r + j, g + j, b + j), + ) + + roadsArea.putpixel( + ( + int(z), + int(x), + ), + (255), + ) + + # Centers + for i in range(len(self.centers)): + print(self.coordinates[self.centers[i]]) + heightmap.putpixel( + (int(self.coordinates[self.centers[i]][0]), int( + self.coordinates[self.centers[i]][2])), + (255, 255, 0), + ) + + roadsArea.putpixel( + (int(self.coordinates[self.centers[i]][0]), int( + self.coordinates[self.centers[i]][2])), + (255), + ) + + # # Intersections + # for i in range(len(self.intersections)): + # intersection = [] + # for j in range(len(self.intersections[i])): + # intersection.append(self.coordinates[self.intersections[i][j]]) + + # for i in range(len(intersection)): + # heightmap.putpixel( + # (int(self.intersections[i][2]), int(self.intersections[i][0])), + # (255, 0, 255), + # ) + + return heightmap, roadsArea diff --git a/networks/legacy_roads/house.py b/networks/legacy_roads/house.py new file mode 100644 index 0000000..141b67f --- /dev/null +++ b/networks/legacy_roads/house.py @@ -0,0 +1,2005 @@ +from gdpc import * +import networks.legacy_roads.list_block +from random import randint + + +def delete(co1,co2): + editor = Editor(buffering= True) + x=abs((co2[0])-(co1[0])) + z=abs((co2[2])-(co1[2])) + y= abs(co2[1]-co1[1]) + for i in range(y): + for j in range(z): + for a in range(x): + editor.placeBlock((co1[0]+a,co1[1]+i,co1[2]+j),air) + + +def mur_sol(co1,co2,block): + x1=co1[0] + y1=co1[1] + z1=co1[2] + x2=co2[0] + y2=co2[1] + z2=co2[2] + + + if x1<0 or x2<0: + if x1<0 and x2>0: + tailleX=co2[0]-co1[0] + midtailleX=(tailleX//2)+x1 + elif x1<0 and x2<0: + + tailleX=abs(co2[0])-abs(co1[0]) + midtailleX=(tailleX//2)+x1 + else: + + tailleX=co2[0]-co1[0] + midtailleX=(tailleX//2)+x1 + + if z1<0 or z2<0: + if z1<0 and z2>0: + tailleZ=co2[2]-co1[2] + midtailleZ=(tailleZ//2)+z1 + elif z1<0 and z2<0: + + tailleZ=abs(co2[2])-abs(co1[2]) + midtailleZ=(tailleZ//2)+z1 + else: + + tailleZ=co2[2]-co1[2] + midtailleZ=(tailleZ//2)+z1 + editor = Editor(buffering= True) + + if y1==y2: + + for i in range(abs(co2[0]-(co1[0]))): + for j in range((abs((co2[2])-(co1[2])))): + editor.placeBlock((co1[0]+i,co1[1],co1[2]+j),block) + elif x1==x2: + if z1<0 or z2<0: + if z1<0 and z2>=0: + for i in range(abs(abs(co2[1])-abs(co1[1]))): + for j in range((z2-z1)): + + editor.placeBlock((co1[0],co1[1]+i,co1[2]+j),block) + elif z1<0 and z2<0: + + for i in range(abs(abs(co2[1])-abs(co1[1]))): + for j in range(abs(z2-z1)): + + editor.placeBlock((co1[0],co1[1]+i,co1[2]+j),block) + else: + for i in range(abs(abs(co2[1])-abs(co1[1]))): + for j in range((abs(co2[2])-abs(co1[2]))): + + editor.placeBlock((co1[0],co1[1]+i,co1[2]+j),block) + + + elif z2==z1: + if x1<0 or x2<0: + if x1<0 and x2>=0: + print(abs(abs(co2[1])-abs(co1[1]))) + print(x2-x1) + for i in range(abs(abs(co2[1])-abs(co1[1]))): + for j in range(x2-x1): + + editor.placeBlock((co1[0]+j,co1[1]+i,co1[2]),block) + elif x1<0 and x2<0: + for i in range(abs(abs(co2[1])-abs(co1[1]))): + for j in range(abs(x2-x1)): + + editor.placeBlock((co1[0]+j,co1[1]+i,co1[2]),block) + else: + for i in range(abs(abs(co2[1])-abs(co1[1]))): + for j in range( (abs(co2[0])-abs(co1[0]))): + + editor.placeBlock((co1[0]+j,co1[1]+i,co1[2]),block) + + + + + + + +def poserEscalier(co1,co2,type): + + editor = Editor(buffering= True) + x1=co1[0] + y1=co1[1] + z1=co1[2] + x2=co2[0] + y2=co2[1] + z2=co2[2] + + if x1==x2: + + if z1<0 or z2<0: + + if z1<0 and z2>=0: + + for i in range((z2-z1)): + print(1) + editor.placeBlock((co1[0],co1[1],co1[2]+i),type) + elif z1<0 and z2<0: + + + for i in range(abs(z2-z1)): + + editor.placeBlock((co1[0],co1[1],co1[2]+i),type) + else: + print(z1) + + for i in range((abs(co2[2])-abs(co1[2]))): + editor.placeBlock((co1[0],co1[1],co1[2]+i),type) + + + elif z2==z1: + print(x1) + if x1<0 or x2<0: + if x1<0 and x2>=0: + + + for i in range(x2-x1): + + editor.placeBlock((co1[0]+i,co1[1],co1[2]),type) + elif x1<0 and x2<0: + + for i in range(abs(x2-x1)): + + editor.placeBlock((co1[0]+i,co1[1],co1[2]),type) + else: + + for i in range((abs(co2[0])-abs(co1[0]))): + editor.placeBlock((co1[0]+i,co1[1],co1[2]),type) + + +def poserPorte(co,type): + editor = Editor(buffering= True) + editor.placeBlock((co[0],co[1],co[2]),type) + + + +def poserToit(co1,co2,hauteurMax,cotegarage,style,direction): + x1=co1[0] + y1=co1[1] + z1=co1[2] + x2=co2[0] + y2=co2[1] + z2=co2[2] + + toit_esca_devant=Block(style['toit_esca'],{"facing": "east"}) + toit_esca_derriere=Block(style['toit_esca'],{"facing": "west"}) + toit_esca_droite=Block(style['toit_esca'],{"facing": "north"}) + toit_esca_gauche=Block(style['toit_esca'],{"facing": "south"}) + toit_esca_devant_ret=Block(style['toit_esca'],{"facing": "east","half":"top"}) + toit_esca_derriere_ret=Block(style['toit_esca'],{"facing": "west","half":"top"}) + toit_esca_droite_ret=Block(style['toit_esca'],{"facing": "north","half":"top"}) + toit_esca_gauch_rete=Block(style['toit_esca'],{"facing": "south","half":"top"}) + toit_planche=Block(style['toit_planche']) + toit_slab=Block(style['toit_slab']) + mur=Block(style['mur']) + + + editor = Editor(buffering= True) + if x1<0 or x2<0: + if x1<0 and x2>=0: + tailleX=x2-x1 + midtailleX=(tailleX//2)+x1 + elif x1<0 and x2<0: + + tailleX=abs(co2[0]-co1[0]) + midtailleX=(tailleX//2)+x1 + else: + + tailleX=co2[0]-co1[0] + midtailleX=(tailleX//2)+x1 + + if z1<0 or z2<0: + if z1<0 and z2>=0: + tailleZ=co2[2]-co1[2] + midtailleZ=(tailleZ//2)+z1 + elif z1<0 and z2<0: + + tailleZ=abs(co2[2]-co1[2]) + midtailleZ=(tailleZ//2)+z1 + else: + + tailleZ=co2[2]-co1[2] + midtailleZ=(tailleZ//2)+z1 + + + if direction=='west': + if cotegarage=='left': + if x1==0 and z1==0: + for i in range(3): + if i==2: + mur_sol((x1-1,y1+4+i,z1+i),(x2-i,y1+4+i,midtailleZ-i),toit_planche) + mur_sol((midtailleX+i,y1+4+i,midtailleZ-i),(x2-i,y1+4+i,z2+1),toit_planche) + mur_sol((x1-1,y1+5+i,z1+i),(x2-i,y1+5+i,midtailleZ-i),toit_slab) + mur_sol((midtailleX+i,y1+5+i,midtailleZ-i),(x2-i,y1+5+i,z2+1),toit_slab) + + else: + mur_sol((x1,y1+4+i,z1+i),(x2-i,y1+4+i,midtailleZ-i),mur) + mur_sol((midtailleX+i,y1+4+i,midtailleZ-i),(x2-i,y1+4+i,z2),mur) + + poserEscalier((x1-1,y1+4+i,z1-1+i),(x2+3-i,y1+4+i,z1-1+i),toit_esca_gauche) + poserEscalier((x2-i,y1+4+i,z1+i),(x2-i,y1+4+i,z2+1),toit_esca_derriere) + poserEscalier((x1-1,y1+4+i,midtailleZ-i),(midtailleX+2+i,y1+4+i,midtailleZ-i),toit_esca_droite) + poserEscalier((midtailleX-1+i,y1+4+i,midtailleZ+1-i),(midtailleX-1+i,y1+4+i,z2+1),toit_esca_devant) + if hauteurMax==5+i: + break + for i in range(2): + editor.placeBlock((x1-1,y1+4+i,z1+i),toit_esca_droite_ret) + editor.placeBlock((x1-1,y1+4+i,midtailleZ-i-1),toit_esca_gauch_rete) + editor.placeBlock((x2-1-i,y1+4+i,z2),toit_esca_devant_ret) + editor.placeBlock((midtailleX+i,y1+4+i,z2),toit_esca_derriere_ret) + elif x1==0: + for i in range(3): + if i==2: + mur_sol((x1-1,y1+4+i,z1+i),(x2+2-i,y1+4+i,midtailleZ-i),toit_planche) + mur_sol((midtailleX+i,y1+4+i,midtailleZ-i),(x2-i,y1+4+i,z2+1),toit_planche) + mur_sol((x1-1,y1+5+i,z1+i),(x2+2-i,y1+5+i,midtailleZ-i),toit_slab) + mur_sol((midtailleX+i,y1+5+i,midtailleZ-i),(x2-i,y1+5+i,z2+1),toit_slab) + + else: + mur_sol((x1,y1+4+i,z1+i),(x2-i,y1+4+i,midtailleZ-i),mur) + mur_sol((midtailleX+i,y1+4+i,midtailleZ-i),(x2-i,y1+4+i,z2),mur) + + poserEscalier((x1-1,y1+4+i,z1-1+i),(x2+3-i,y1+4+i,z1-1+i),toit_esca_gauche) + poserEscalier((x2-i,y1+4+i,z1+i),(x2-i,y1+4+i,z2+1),toit_esca_derriere) + poserEscalier((x1-1,y1+4+i,midtailleZ-i),(midtailleX+2+i,y1+4+i,midtailleZ-i),toit_esca_droite) + poserEscalier((midtailleX-1+i,y1+4+i,midtailleZ+1-i),(midtailleX-1+i,y1+4+i,z2+1),toit_esca_devant) + if hauteurMax==5+i: + break + for i in range(2): + editor.placeBlock((x1-1,y1+4+i,z1+i),toit_esca_droite_ret) + editor.placeBlock((x1-1,y1+4+i,midtailleZ-i-1),toit_esca_gauch_rete) + editor.placeBlock((x2-1-i,y1+4+i,z2),toit_esca_devant_ret) + editor.placeBlock((midtailleX+i,y1+4+i,z2),toit_esca_derriere_ret) + + elif z1==0: + for i in range(3): + if i==2: + mur_sol((x1-1,y1+4+i,z1+i),(x2-i,y1+4+i,midtailleZ-i),toit_planche) + mur_sol((midtailleX+i,y1+4+i,midtailleZ-i),(x2-i,y1+4+i,z2+1),toit_planche) + mur_sol((x1-1,y1+5+i,z1+i),(x2-i,y1+5+i,midtailleZ-i),toit_slab) + mur_sol((midtailleX+i,y1+5+i,midtailleZ-i),(x2-i,y1+5+i,z2+1),toit_slab) + + else: + mur_sol((x1,y1+4+i,z1+i),(x2-i,y1+4+i,midtailleZ-i),mur) + mur_sol((midtailleX+i,y1+4+i,midtailleZ-i),(x2-i,y1+4+i,z2),mur) + + poserEscalier((x1-1,y1+4+i,z1-1+i),(x2+1-i,y1+4+i,z1-1+i),toit_esca_gauche) + poserEscalier((x2-i,y1+4+i,z1+i),(x2-i,y1+4+i,z2+1),toit_esca_derriere) + poserEscalier((x1-1,y1+4+i,midtailleZ-i),(midtailleX+i,y1+4+i,midtailleZ-i),toit_esca_droite) + poserEscalier((midtailleX-1+i,y1+4+i,midtailleZ+1-i),(midtailleX-1+i,y1+4+i,z2+1),toit_esca_devant) + if hauteurMax==5+i: + break + for i in range(2): + editor.placeBlock((x1-1,y1+4+i,z1+i),toit_esca_droite_ret) + editor.placeBlock((x1-1,y1+4+i,midtailleZ-i-1),toit_esca_gauch_rete) + editor.placeBlock((x2-1-i,y1+4+i,z2),toit_esca_devant_ret) + editor.placeBlock((midtailleX+i,y1+4+i,z2),toit_esca_derriere_ret) + + + + + else: + for i in range(3): + if i==2: + mur_sol((x1-1,y1+4+i,z1+i),(x2-i,y1+4+i,midtailleZ-i),toit_planche) + mur_sol((midtailleX+i,y1+4+i,midtailleZ-i),(x2-i,y1+4+i,z2+1),toit_planche) + mur_sol((x1-1,y1+5+i,z1+i),(x2-i,y1+5+i,midtailleZ-i),toit_slab) + mur_sol((midtailleX+i,y1+5+i,midtailleZ-i),(x2-i,y1+5+i,z2+1),toit_slab) + + else: + mur_sol((x1,y1+4+i,z1+i),(x2-i,y1+4+i,midtailleZ-i),mur) + mur_sol((midtailleX+i,y1+4+i,midtailleZ-i),(x2-i,y1+4+i,z2),mur) + + + poserEscalier((x1-1,y1+4+i,z1-1+i),(x2+1-i,y1+4+i,z1-1+i),toit_esca_gauche) + poserEscalier((x2-i,y1+4+i,z1+i),(x2-i,y1+4+i,z2+1),toit_esca_derriere) + poserEscalier((x1-1,y1+4+i,midtailleZ-i),(midtailleX+i,y1+4+i,midtailleZ-i),toit_esca_droite) + poserEscalier((midtailleX-1+i,y1+4+i,midtailleZ+1-i),(midtailleX-1+i,y1+4+i,z2+1),toit_esca_devant) + if hauteurMax==5+i: + break + for i in range(2): + editor.placeBlock((x1-1,y1+4+i,z1+i),toit_esca_droite_ret) + editor.placeBlock((x1-1,y1+4+i,midtailleZ-i-1),toit_esca_gauch_rete) + editor.placeBlock((x2-1-i,y1+4+i,z2),toit_esca_devant_ret) + editor.placeBlock((midtailleX+i,y1+4+i,z2),toit_esca_derriere_ret) + + + elif cotegarage=='right': + if x1==0 and z1==0: + + for i in range(3): + if i==2: + + + mur_sol((midtailleX+i,y1+4+i,z1-1),(x2-i,y1+4+i,z2-i),toit_planche) + mur_sol((x1-1,y1+4+i,midtailleZ+i),(x2-i,y1+4+i,z2-i),toit_planche) + mur_sol((midtailleX+i,y1+5+i,z1-1),(x2-i,y1+5+i,z2-i),toit_slab) + mur_sol((x1-1,y1+5+i,midtailleZ+i),(x2-i,y1+5+i,z2-i),toit_slab) + + else: + mur_sol((midtailleX+i,y1+4+i,z1),(x2-i,y1+4+i,z2-i),mur) + mur_sol((x1,y1+4+i,midtailleZ+i),(x2-i,y1+4+i,z2-i),mur) + + poserEscalier((x1-1,y1+4+i,midtailleZ-1+i),(midtailleX+2+i,y1+4+i,midtailleZ-1+i),toit_esca_gauche) + poserEscalier((x2-i,y1+4+i,z1-1),(x2-i,y1+4+i,z2+3-i),toit_esca_derriere) + poserEscalier((x1-1,y1+4+i,z2-i),(x2-i+2,y1+4-i,z2-i),toit_esca_droite) + poserEscalier((midtailleX-1+i,y1+4+i,z1-1),(midtailleX-1+i,y1+4+i,midtailleZ+1+i),toit_esca_devant) + if hauteurMax==5+i: + break + for i in range(2): + editor.placeBlock((midtailleX+i,y1+4+i,z1-1),toit_esca_derriere_ret) + editor.placeBlock((x2-1-i,y1+4+i,z1-1),toit_esca_devant_ret) + editor.placeBlock((x1-1,y1+4+i,midtailleZ+i),toit_esca_droite_ret) + editor.placeBlock((x1-1,y1+4+i,z2-1-i),toit_esca_gauch_rete) + pass + elif x1==0: + for i in range(3): + if i==2: + + + mur_sol((midtailleX+i,y1+4+i,z1-1),(x2-i,y1+4+i,z2-i),toit_planche) + mur_sol((x1-1,y1+4+i,midtailleZ+i),(x2-i,y1+4+i,z2-i),toit_planche) + mur_sol((midtailleX+i,y1+5+i,z1-1),(x2-i,y1+5+i,z2-i),toit_slab) + mur_sol((x1-1,y1+5+i,midtailleZ+i),(x2-i,y1+5+i,z2-i),toit_slab) + + else: + mur_sol((midtailleX+i,y1+4+i,z1),(x2-i,y1+4+i,z2-i),mur) + mur_sol((x1,y1+4+i,midtailleZ+i),(x2-i,y1+4+i,z2-i),mur) + + poserEscalier((x1-1,y1+4+i,midtailleZ-1+i),(midtailleX+2+i,y1+4+i,midtailleZ-1+i),toit_esca_gauche) + poserEscalier((x2-i,y1+4+i,z1-1),(x2-i,y1+4+i,z2+1-i),toit_esca_derriere) + poserEscalier((x1-1,y1+4+i,z2-i),(x2-i+2,y1+4-i,z2-i),toit_esca_droite) + poserEscalier((midtailleX-1+i,y1+4+i,z1-1),(midtailleX-1+i,y1+4+i,midtailleZ+i),toit_esca_devant) + if hauteurMax==5+i: + break + for i in range(2): + editor.placeBlock((midtailleX+i,y1+4+i,z1-1),toit_esca_derriere_ret) + editor.placeBlock((x2-1-i,y1+4+i,z1-1),toit_esca_devant_ret) + editor.placeBlock((x1-1,y1+4+i,midtailleZ+i),toit_esca_droite_ret) + editor.placeBlock((x1-1,y1+4+i,z2-1-i),toit_esca_gauch_rete) + pass + + elif z1==0: + + for i in range(3): + if i==2: + + + mur_sol((midtailleX+i,y1+4+i,z1-1),(x2-i,y1+4+i,z2-i),toit_planche) + mur_sol((x1-1,y1+4+i,midtailleZ+i),(x2-i,y1+4+i,z2-i),toit_planche) + mur_sol((midtailleX+i,y1+5+i,z1-1),(x2-i,y1+5+i,z2-i+1),toit_slab) + mur_sol((x1-1,y1+5+i,midtailleZ+i),(x2-i,y1+5+i,z2-i),toit_slab) + + else: + mur_sol((midtailleX+i,y1+4+i,z1),(x2-i,y1+4+i,z2-i),mur) + mur_sol((x1,y1+4+i,midtailleZ+i),(x2-i,y1+4+i,z2-i),mur) + + poserEscalier((x1-1,y1+4+i,midtailleZ-1+i),(midtailleX+i,y1+4+i,midtailleZ-1+i),toit_esca_gauche) + poserEscalier((x2-i,y1+4+i,z1-1),(x2-i,y1+4+i,z2+2-i),toit_esca_derriere) + poserEscalier((x1-1,y1+4+i,z2-i),(x2-i+1,y1+4-i,z2-i),toit_esca_droite) + poserEscalier((midtailleX-1+i,y1+4+i,z1-1),(midtailleX-1+i,y1+4+i,midtailleZ+1+i),toit_esca_devant) + if hauteurMax==5+i: + break + for i in range(2): + editor.placeBlock((midtailleX+i,y1+4+i,z1-1),toit_esca_derriere_ret) + editor.placeBlock((x2-1-i,y1+4+i,z1-1),toit_esca_devant_ret) + editor.placeBlock((x1-1,y1+4+i,midtailleZ+i),toit_esca_droite_ret) + editor.placeBlock((x1-1,y1+4+i,z2-1-i),toit_esca_gauch_rete) + + else: + + for i in range(3): + if i==2: + + + mur_sol((midtailleX+i,y1+4+i,z1-1),(x2-i,y1+4+i,z2-i),toit_planche) + mur_sol((x1-1,y1+4+i,midtailleZ+i),(x2-i,y1+4+i,z2-i),toit_planche) + mur_sol((midtailleX+i,y1+5+i,z1-1),(x2-i,y1+5+i,z2-i),toit_slab) + mur_sol((x1-1,y1+5+i,midtailleZ+i),(x2-i,y1+5+i,z2-i),toit_slab) + + else: + mur_sol((midtailleX+i,y1+4+i,z1),(x2-i,y1+4+i,z2-i),mur) + mur_sol((x1,y1+4+i,midtailleZ+i),(x2-i,y1+4+i,z2-i),mur) + + + poserEscalier((x1-1,y1+4+i,midtailleZ-1+i),(midtailleX+i,y1+4+i,midtailleZ-1+i),toit_esca_gauche) + poserEscalier((x2-i,y1+4+i,z1-1),(x2-i,y1+4+i,z2-i),toit_esca_derriere) + poserEscalier((x1-1,y1+4+i,z2-i),(x2-i+1,y1+4-i,z2-i),toit_esca_droite) + poserEscalier((midtailleX-1+i,y1+4+i,z1-1),(midtailleX-1+i,y1+4+i,midtailleZ+i),toit_esca_devant) + if hauteurMax==5+i: + break + for i in range(2): + editor.placeBlock((midtailleX+i,y1+4+i,z1-1),toit_esca_derriere_ret) + editor.placeBlock((x2-1-i,y1+4+i,z1-1),toit_esca_devant_ret) + editor.placeBlock((x1-1,y1+4+i,midtailleZ+i),toit_esca_droite_ret) + editor.placeBlock((x1-1,y1+4+i,z2-1-i),toit_esca_gauch_rete) + pass + + + + + + + + + + elif direction=='east': + + + if cotegarage=='left': + if x1==0 and z1==0: + for i in range(3): + if i==2: + i=1 + mur_sol((x1+1+i,y1+5+i,midtailleZ+1+i),(x2+1,y1+5+i,z2-1-i),toit_planche) + mur_sol((x1+1+i,y1+5+i,z1-1),(midtailleX-i,y1+5+i,midtailleZ+2),toit_planche) + mur_sol((x1+1+i,y1+6+i,midtailleZ+1+i),(x2+1,y1+6+i,z2-1-i),toit_slab) + mur_sol((x1+1+i,y1+6+i,z1-1),(midtailleX-i,y1+6+i,midtailleZ+2),toit_slab) + i=2 + + else: + mur_sol((x1+1+i,y1+5+i,midtailleZ+1+i),(x2,y1+5+i,z2-1-i),mur) + mur_sol((x1+1+i,y1+5+i,z1),(midtailleX-i,y1+5+i,midtailleZ+2),mur) + + poserEscalier((midtailleX+1-i,y1+4+i,midtailleZ-1+i),(x2+1,y1+4+i,midtailleZ-1+i),toit_esca_gauche) + poserEscalier((midtailleX+1-i,y1+4+i,z1-1),(midtailleX+1-i,y1+4+i,midtailleZ+i+1),toit_esca_derriere) + poserEscalier((x1+i,y1+4+i,z2-i),(x2+1,y1+4+i,z2-i),toit_esca_droite) + poserEscalier((x1-1+i,y1+4+i,z1-1),(x1-1+i,y1+4+i,z2+3-i),toit_esca_devant) + if hauteurMax==5+i: + break + for i in range(2): + pass + editor.placeBlock((x2,y1+4+i,midtailleZ+i),toit_esca_droite_ret) + editor.placeBlock((x2,y1+4+i,z2-1-i),toit_esca_gauch_rete) + editor.placeBlock((midtailleX-i,y1+4+i,z1-1),toit_esca_devant_ret) + editor.placeBlock((x1+i,y1+4+i,z1-1),toit_esca_derriere_ret) + + + + elif x1==0: + for i in range(3): + if i==2: + i=1 + mur_sol((x1+1+i,y1+5+i,midtailleZ+1+i),(x2+1,y1+5+i,z2-1-i),toit_planche) + mur_sol((x1+1+i,y1+5+i,z1-1),(midtailleX-i,y1+5+i,midtailleZ+2),toit_planche) + mur_sol((x1+1+i,y1+6+i,midtailleZ+1+i),(x2+1,y1+6+i,z2-1-i),toit_slab) + mur_sol((x1+1+i,y1+6+i,z1-1),(midtailleX-i,y1+6+i,midtailleZ+2),toit_slab) + i=2 + + else: + mur_sol((x1+1+i,y1+5+i,midtailleZ+1+i),(x2,y1+5+i,z2-1-i),mur) + mur_sol((x1+1+i,y1+5+i,z1),(midtailleX-i,y1+5+i,midtailleZ+2),mur) + + poserEscalier((midtailleX+1-i,y1+4+i,midtailleZ-1+i),(x2+1,y1+4+i,midtailleZ-1+i),toit_esca_gauche) + poserEscalier((midtailleX+1-i,y1+4+i,z1-1),(midtailleX+1-i,y1+4+i,midtailleZ+i),toit_esca_derriere) + poserEscalier((x1+i,y1+4+i,z2-i),(x2+1,y1+4+i,z2-i),toit_esca_droite) + poserEscalier((x1-1+i,y1+4+i,z1-1),(x1-1+i,y1+4+i,z2+1-i),toit_esca_devant) + if hauteurMax==5+i: + break + for i in range(2): + pass + editor.placeBlock((x2,y1+4+i,midtailleZ+i),toit_esca_droite_ret) + editor.placeBlock((x2,y1+4+i,z2-1-i),toit_esca_gauch_rete) + editor.placeBlock((midtailleX-i,y1+4+i,z1-1),toit_esca_devant_ret) + editor.placeBlock((x1+i,y1+4+i,z1-1),toit_esca_derriere_ret) + + + + elif z1==0: + for i in range(3): + if i==2: + i=1 + mur_sol((x1+1+i,y1+5+i,midtailleZ+1+i),(x2+1,y1+5+i,z2-1-i),toit_planche) + mur_sol((x1+1+i,y1+5+i,z1-1),(midtailleX-i,y1+5+i,midtailleZ+2),toit_planche) + mur_sol((x1+1+i,y1+6+i,midtailleZ+1+i),(x2+1,y1+6+i,z2-1-i),toit_slab) + mur_sol((x1+1+i,y1+6+i,z1-1),(midtailleX-i,y1+6+i,midtailleZ+2),toit_slab) + i=2 + + else: + mur_sol((x1+1+i,y1+5+i,midtailleZ+1+i),(x2,y1+5+i,z2-1-i),mur) + mur_sol((x1+1+i,y1+5+i,z1),(midtailleX-i,y1+5+i,midtailleZ+2),mur) + + poserEscalier((midtailleX+1-i,y1+4+i,midtailleZ-1+i),(x2+1,y1+4+i,midtailleZ-1+i),toit_esca_gauche) + poserEscalier((midtailleX+1-i,y1+4+i,z1-1),(midtailleX+1-i,y1+4+i,midtailleZ+i+1),toit_esca_derriere) + poserEscalier((x1+i,y1+4+i,z2-i),(x2+1,y1+4+i,z2-i),toit_esca_droite) + poserEscalier((x1-1+i,y1+4+i,z1-1),(x1-1+i,y1+4+i,z2+3-i),toit_esca_devant) + if hauteurMax==5+i: + break + for i in range(2): + pass + editor.placeBlock((x2,y1+4+i,midtailleZ+i),toit_esca_droite_ret) + editor.placeBlock((x2,y1+4+i,z2-1-i),toit_esca_gauch_rete) + editor.placeBlock((midtailleX-i,y1+4+i,z1-1),toit_esca_devant_ret) + editor.placeBlock((x1+i,y1+4+i,z1-1),toit_esca_derriere_ret) + + + + + else: + for i in range(3): + if i==2: + i=1 + mur_sol((x1+1+i,y1+5+i,midtailleZ+1+i),(x2+1,y1+5+i,z2-1-i),toit_planche) + mur_sol((x1+1+i,y1+5+i,z1-1),(midtailleX-i,y1+5+i,midtailleZ+2),toit_planche) + mur_sol((x1+1+i,y1+6+i,midtailleZ+1+i),(x2+1,y1+6+i,z2-1-i),toit_slab) + mur_sol((x1+1+i,y1+6+i,z1-1),(midtailleX-i,y1+6+i,midtailleZ+2),toit_slab) + i=2 + + else: + mur_sol((x1+1+i,y1+5+i,midtailleZ+1+i),(x2,y1+5+i,z2-1-i),mur) + mur_sol((x1+1+i,y1+5+i,z1),(midtailleX-i,y1+5+i,midtailleZ+2),mur) + + poserEscalier((midtailleX+1-i,y1+4+i,midtailleZ-1+i),(x2+1,y1+4+i,midtailleZ-1+i),toit_esca_gauche) + poserEscalier((midtailleX+1-i,y1+4+i,z1-1),(midtailleX+1-i,y1+4+i,midtailleZ+i),toit_esca_derriere) + poserEscalier((x1+i,y1+4+i,z2-i),(x2+1,y1+4+i,z2-i),toit_esca_droite) + poserEscalier((x1-1+i,y1+4+i,z1-1),(x1-1+i,y1+4+i,z2+1-i),toit_esca_devant) + if hauteurMax==5+i: + break + for i in range(2): + pass + editor.placeBlock((x2,y1+4+i,midtailleZ+i),toit_esca_droite_ret) + editor.placeBlock((x2,y1+4+i,z2-1-i),toit_esca_gauch_rete) + editor.placeBlock((midtailleX-i,y1+4+i,z1-1),toit_esca_devant_ret) + editor.placeBlock((x1+i,y1+4+i,z1-1),toit_esca_derriere_ret) + + + elif cotegarage=='right': + if x1==0 and z1==0: + for i in range(3): + if i==2: + i=1 + mur_sol((x1+2,y1+5+i,z1+i+1),(x2+1,y1+5+i,midtailleZ-i-1),toit_planche) + mur_sol((x1+i+1,y1+5+i,midtailleZ-2),(midtailleX-i,y1+5+i,z2+1),toit_planche) + mur_sol((x1+2,y1+6+i,z1+i+1),(x2+1,y1+6+i,midtailleZ-i-1),toit_slab) + mur_sol((x1+i+1,y1+6+i,midtailleZ-2),(midtailleX-i,y1+6+i,z2+1),toit_slab) + i=2 + + else: + mur_sol((x1+2,y1+5+i,z1+i+1),(x2,y1+5+i,midtailleZ-i-1),mur) + mur_sol((x1+i+1,y1+5+i,midtailleZ),(midtailleX-i,y1+5+i,z2),mur) + + poserEscalier((x1+i,y1+4+i,z1-1+i),(x2+1,y1+4+i,z1-1+i),toit_esca_gauche) + poserEscalier((midtailleX+1-i,y1+4+i,midtailleZ-i),(midtailleX+1-i,y1+4+i,z2+1),toit_esca_derriere) + poserEscalier((midtailleX+2-i,y1+4+i,midtailleZ-i),(x2+1,y1+4+i,midtailleZ-i),toit_esca_droite) + poserEscalier((x1-1+i,y1+4+i,z1+i),(x1-1+i,y1+4+i,z2+1),toit_esca_devant) + editor.placeBlock((x1-1+i,y1+4+i,z1-1+i),toit_esca_devant) + if hauteurMax==5+i: + break + for i in range(2): + pass + editor.placeBlock((x2,y1+4+i,z1+i),toit_esca_droite_ret) + editor.placeBlock((x2,y1+4+i,midtailleZ-1-i),toit_esca_gauch_rete) + editor.placeBlock((midtailleX-i,y1+4+i,z2),toit_esca_devant_ret) + editor.placeBlock((x1+i,y1+4+i,z2),toit_esca_derriere_ret) + + + + elif x1==0: + for i in range(3): + if i==2: + i=1 + mur_sol((x1+2,y1+5+i,z1+i+1),(x2+1,y1+5+i,midtailleZ-i-1),toit_planche) + mur_sol((x1+i+1,y1+5+i,midtailleZ-2),(midtailleX-i,y1+5+i,z2+1),toit_planche) + mur_sol((x1+2,y1+6+i,z1+i+1),(x2+1,y1+6+i,midtailleZ-i-1),toit_slab) + mur_sol((x1+i+1,y1+6+i,midtailleZ-2),(midtailleX-i,y1+6+i,z2+1),toit_slab) + i=2 + + else: + mur_sol((x1+2,y1+5+i,z1+i+1),(x2,y1+5+i,midtailleZ-i-1),mur) + mur_sol((x1+i+1,y1+5+i,midtailleZ),(midtailleX-i,y1+5+i,z2),mur) + + poserEscalier((x1+i,y1+4+i,z1-1+i),(x2+1,y1+4+i,z1-1+i),toit_esca_gauche) + poserEscalier((midtailleX+1-i,y1+4+i,midtailleZ-i),(midtailleX+1-i,y1+4+i,z2+1),toit_esca_derriere) + poserEscalier((midtailleX+2-i,y1+4+i,midtailleZ-i),(x2+1,y1+4+i,midtailleZ-i),toit_esca_droite) + poserEscalier((x1-1+i,y1+4+i,z1+i),(x1-1+i,y1+4+i,z2+1),toit_esca_devant) + editor.placeBlock((x1-1+i,y1+4+i,z1-1+i),toit_esca_devant) + if hauteurMax==5+i: + break + for i in range(2): + pass + editor.placeBlock((x2,y1+4+i,z1+i),toit_esca_droite_ret) + editor.placeBlock((x2,y1+4+i,midtailleZ-1-i),toit_esca_gauch_rete) + editor.placeBlock((midtailleX-i,y1+4+i,z2),toit_esca_devant_ret) + editor.placeBlock((x1+i,y1+4+i,z2),toit_esca_derriere_ret) + + + elif z1==0: + for i in range(3): + if i==2: + i=1 + mur_sol((x1+2,y1+5+i,z1+i+1),(x2+1,y1+5+i,midtailleZ-i-1),toit_planche) + mur_sol((x1+i+1,y1+5+i,midtailleZ-2),(midtailleX-i,y1+5+i,z2+1),toit_planche) + mur_sol((x1+2,y1+6+i,z1+i+1),(x2+1,y1+6+i,midtailleZ-i-1),toit_slab) + mur_sol((x1+i+1,y1+6+i,midtailleZ-2),(midtailleX-i,y1+6+i,z2+1),toit_slab) + i=2 + + else: + mur_sol((x1+2,y1+5+i,z1+i+1),(x2,y1+5+i,midtailleZ-i-1),mur) + mur_sol((x1+i+1,y1+5+i,midtailleZ),(midtailleX-i,y1+5+i,z2),mur) + + poserEscalier((x1+i,y1+4+i,z1-1+i),(x2+1,y1+4+i,z1-1+i),toit_esca_gauche) + poserEscalier((midtailleX+1-i,y1+4+i,midtailleZ-i),(midtailleX+1-i,y1+4+i,z2+1),toit_esca_derriere) + poserEscalier((midtailleX+2-i,y1+4+i,midtailleZ-i),(x2+1,y1+4+i,midtailleZ-i),toit_esca_droite) + poserEscalier((x1-1+i,y1+4+i,z1+i),(x1-1+i,y1+4+i,z2+1),toit_esca_devant) + editor.placeBlock((x1-1+i,y1+4+i,z1-1+i),toit_esca_devant) + if hauteurMax==5+i: + break + for i in range(2): + pass + editor.placeBlock((x2,y1+4+i,z1+i),toit_esca_droite_ret) + editor.placeBlock((x2,y1+4+i,midtailleZ-1-i),toit_esca_gauch_rete) + editor.placeBlock((midtailleX-i,y1+4+i,z2),toit_esca_devant_ret) + editor.placeBlock((x1+i,y1+4+i,z2),toit_esca_derriere_ret) + + + + + else: + for i in range(3): + if i==2: + i=1 + mur_sol((x1+2,y1+5+i,z1+i+1),(x2+1,y1+5+i,midtailleZ-i-1),toit_planche) + mur_sol((x1+i+1,y1+5+i,midtailleZ-2),(midtailleX-i,y1+5+i,z2+1),toit_planche) + mur_sol((x1+2,y1+6+i,z1+i+1),(x2+1,y1+6+i,midtailleZ-i-1),toit_slab) + mur_sol((x1+i+1,y1+6+i,midtailleZ-2),(midtailleX-i,y1+6+i,z2+1),toit_slab) + i=2 + + else: + mur_sol((x1+2,y1+5+i,z1+i+1),(x2,y1+5+i,midtailleZ-i-1),mur) + mur_sol((x1+i+1,y1+5+i,midtailleZ),(midtailleX-i,y1+5+i,z2),mur) + + poserEscalier((x1+i,y1+4+i,z1-1+i),(x2+1,y1+4+i,z1-1+i),toit_esca_gauche) + poserEscalier((midtailleX+1-i,y1+4+i,midtailleZ-i),(midtailleX+1-i,y1+4+i,z2+1),toit_esca_derriere) + poserEscalier((midtailleX+2-i,y1+4+i,midtailleZ-i),(x2+1,y1+4+i,midtailleZ-i),toit_esca_droite) + poserEscalier((x1-1+i,y1+4+i,z1+i),(x1-1+i,y1+4+i,z2+1),toit_esca_devant) + editor.placeBlock((x1-1+i,y1+4+i,z1-1+i),toit_esca_devant) + if hauteurMax==5+i: + break + for i in range(2): + pass + editor.placeBlock((x2,y1+4+i,z1+i),toit_esca_droite_ret) + editor.placeBlock((x2,y1+4+i,midtailleZ-1-i),toit_esca_gauch_rete) + editor.placeBlock((midtailleX-i,y1+4+i,z2),toit_esca_devant_ret) + editor.placeBlock((x1+i,y1+4+i,z2),toit_esca_derriere_ret) + + + + elif direction=='north': + + + if cotegarage=='left': + if x1==0 and z1==0: + for i in range(3): + if i==2: + i=1 + mur_sol((x1-1,y1+5+i,midtailleZ+i+1),(x2-1-i,y1+5+i,z2-i-1),toit_planche) + mur_sol((midtailleX+i+1,y1+5+i,z1-1),(x2-i-1,y1+5+i,z2-1-i),toit_planche) + mur_sol((x1-1,y1+6+i,midtailleZ+i+1),(x2-1-i,y1+6+i,z2-i-1),toit_slab) + mur_sol((midtailleX+i+1,y1+6+i,z1-1),(x2-i-1,y1+6+i,z2-1-i),toit_slab) + i=2 + + else: + pass + mur_sol((x1,y1+5+i,midtailleZ+i+1),(x2-i,y1+5+i,z2-i-1),mur) + mur_sol((midtailleX+i+1,y1+5+i,z1),(x2-i-1,y1+5+i,z2-i),mur) + + poserEscalier((x1-1,y1+4+i,midtailleZ-1+i),(midtailleX+1+i,y1+4+i,midtailleZ-1+i),toit_esca_gauche) + poserEscalier((x2-i,y1+4+i,z1-1),(x2-i,y1+4+i,z2+3-i),toit_esca_derriere) + poserEscalier((x1-1,y1+4+i,z2-i),(x2+3-i,y1+4+i,z2-i),toit_esca_droite) + poserEscalier((midtailleX+i-1,y1+4+i,z1-1),(midtailleX+i-1,y1+4+i,midtailleZ+2+i),toit_esca_devant) + + if hauteurMax==5+i: + break + for i in range(2): + pass + editor.placeBlock((midtailleX+i,y1+4+i,z1-1),toit_esca_derriere_ret) + editor.placeBlock((x2-1-i,y1+4+i,z1-1),toit_esca_devant_ret) + editor.placeBlock((x1-1,y1+4+i,z2-1-i),toit_esca_gauch_rete) + editor.placeBlock((x1-1,y1+4+i,midtailleZ+i),toit_esca_droite_ret) + + + + elif x1==0: + for i in range(3): + if i==2: + i=1 + mur_sol((x1-1,y1+5+i,midtailleZ+i+1),(x2-1-i,y1+5+i,z2-i-1),toit_planche) + mur_sol((midtailleX+i+1,y1+5+i,z1-1),(x2-i-1,y1+5+i,z2-1-i),toit_planche) + mur_sol((x1-1,y1+6+i,midtailleZ+i+1),(x2-1-i,y1+6+i,z2-i-1),toit_slab) + mur_sol((midtailleX+i+1,y1+6+i,z1-1),(x2-i-1,y1+6+i,z2-1-i),toit_slab) + i=2 + + else: + pass + mur_sol((x1,y1+5+i,midtailleZ+i+1),(x2-i,y1+5+i,z2-i-1),mur) + mur_sol((midtailleX+i+1,y1+5+i,z1),(x2-i-1,y1+5+i,z2-i),mur) + + poserEscalier((x1-1,y1+4+i,midtailleZ-1+i),(midtailleX+1+i,y1+4+i,midtailleZ-1+i),toit_esca_gauche) + poserEscalier((x2-i,y1+4+i,z1-1),(x2-i,y1+4+i,z2-i),toit_esca_derriere) + poserEscalier((x1-1,y1+4+i,z2-i),(x2+3-i,y1+4+i,z2-i),toit_esca_droite) + poserEscalier((midtailleX+i-1,y1+4+i,z1-1),(midtailleX+i-1,y1+4+i,midtailleZ+i),toit_esca_devant) + + if hauteurMax==5+i: + break + for i in range(2): + pass + editor.placeBlock((midtailleX+i,y1+4+i,z1-1),toit_esca_derriere_ret) + editor.placeBlock((x2-1-i,y1+4+i,z1-1),toit_esca_devant_ret) + editor.placeBlock((x1-1,y1+4+i,z2-1-i),toit_esca_gauch_rete) + editor.placeBlock((x1-1,y1+4+i,midtailleZ+i),toit_esca_droite_ret) + elif z1==0: + for i in range(3): + if i==2: + i=1 + mur_sol((x1-1,y1+5+i,midtailleZ+i+1),(x2-1-i,y1+5+i,z2-i-1),toit_planche) + mur_sol((midtailleX+i+1,y1+5+i,z1-1),(x2-i-1,y1+5+i,z2-1-i),toit_planche) + mur_sol((x1-1,y1+6+i,midtailleZ+i+1),(x2-1-i,y1+6+i,z2-i-1),toit_slab) + mur_sol((midtailleX+i+1,y1+6+i,z1-1),(x2-i-1,y1+6+i,z2-1-i),toit_slab) + i=2 + + else: + pass + mur_sol((x1,y1+5+i,midtailleZ+i+1),(x2-i,y1+5+i,z2-i-1),mur) + mur_sol((midtailleX+i+1,y1+5+i,z1),(x2-i-1,y1+5+i,z2-i),mur) + + poserEscalier((x1-1,y1+4+i,midtailleZ-1+i),(midtailleX+1+i,y1+4+i,midtailleZ-1+i),toit_esca_gauche) + poserEscalier((x2-i,y1+4+i,z1-1),(x2-i,y1+4+i,z2+3-i),toit_esca_derriere) + poserEscalier((x1-1,y1+4+i,z2-i),(x2-i,y1+4+i,z2-i),toit_esca_droite) + poserEscalier((midtailleX+i-1,y1+4+i,z1-1),(midtailleX+i-1,y1+4+i,midtailleZ+2+i),toit_esca_devant) + + if hauteurMax==5+i: + break + for i in range(2): + pass + editor.placeBlock((midtailleX+i,y1+4+i,z1-1),toit_esca_derriere_ret) + editor.placeBlock((x2-1-i,y1+4+i,z1-1),toit_esca_devant_ret) + editor.placeBlock((x1-1,y1+4+i,z2-1-i),toit_esca_gauch_rete) + editor.placeBlock((x1-1,y1+4+i,midtailleZ+i),toit_esca_droite_ret) + + + + + else: + for i in range(3): + if i==2: + i=1 + mur_sol((x1-1,y1+5+i,midtailleZ+i+1),(x2-1-i,y1+5+i,z2-i-1),toit_planche) + mur_sol((midtailleX+i+1,y1+5+i,z1-1),(x2-i-1,y1+5+i,z2-1-i),toit_planche) + mur_sol((x1-1,y1+6+i,midtailleZ+i+1),(x2-1-i,y1+6+i,z2-i-1),toit_slab) + mur_sol((midtailleX+i+1,y1+6+i,z1-1),(x2-i-1,y1+6+i,z2-1-i),toit_slab) + i=2 + + else: + pass + mur_sol((x1,y1+5+i,midtailleZ+i+1),(x2-i,y1+5+i,z2-i-1),mur) + mur_sol((midtailleX+i+1,y1+5+i,z1),(x2-i-1,y1+5+i,z2-i),mur) + + poserEscalier((x1-1,y1+4+i,midtailleZ-1+i),(midtailleX+1+i,y1+4+i,midtailleZ-1+i),toit_esca_gauche) + poserEscalier((x2-i,y1+4+i,z1-1),(x2-i,y1+4+i,z2+1-i),toit_esca_derriere) + poserEscalier((x1-1,y1+4+i,z2-i),(x2-i,y1+4+i,z2-i),toit_esca_droite) + poserEscalier((midtailleX+i-1,y1+4+i,z1-1),(midtailleX+i-1,y1+4+i,midtailleZ+i),toit_esca_devant) + + if hauteurMax==5+i: + break + for i in range(2): + pass + editor.placeBlock((midtailleX+i,y1+4+i,z1-1),toit_esca_derriere_ret) + editor.placeBlock((x2-1-i,y1+4+i,z1-1),toit_esca_devant_ret) + editor.placeBlock((x1-1,y1+4+i,z2-1-i),toit_esca_gauch_rete) + editor.placeBlock((x1-1,y1+4+i,midtailleZ+i),toit_esca_droite_ret) + + + elif cotegarage=='right': + if x1==0 and z1==0: + for i in range(3): + if i==2: + i=1 + mur_sol((x1+i+1,y1+5+i,midtailleZ+1+i),(x2+1,y1+5+i,z2-1-i),toit_planche) + mur_sol((x1+i+1,y1+5+i,z1-1),(midtailleX-i-1,y1+5+i,z2-1-i),toit_planche) + mur_sol((x1+i+1,y1+6+i,midtailleZ+1+i),(x2+1,y1+6+i,z2-1-i),toit_slab) + mur_sol((x1+i+1,y1+6+i,z1-1),(midtailleX-i-1,y1+6+i,z2-1-i),toit_slab) + i=2 + + else: + pass + mur_sol((x1+i,y1+5+i,midtailleZ+i+1),(x2,y1+5+i,z2-i-1),mur) + mur_sol((x1+i+1,y1+5+i,z1),(midtailleX-i-1,y1+5+i,z2-i),mur) + + poserEscalier((midtailleX-i,y1+4+i,midtailleZ-1+i),(x2+1,y1+4+i,midtailleZ-1+i),toit_esca_gauche) + poserEscalier((midtailleX-i,y1+4+i,z1-1),(midtailleX-i,y1+4+i,midtailleZ+1+i),toit_esca_derriere) + poserEscalier((x1+i,y1+4+i,z2-i),(x2+1,y1+4+i,z2-i),toit_esca_droite) + poserEscalier((x1+i-1,y1+4+i,z1-1),(x1+i-1,y1+4+i,z2+3-i),toit_esca_devant) + + if hauteurMax==5+i: + break + for i in range(2): + pass + editor.placeBlock((x1+i,y1+4+i,z1-1),toit_esca_derriere_ret) + editor.placeBlock((midtailleX-1-i,y1+4+i,z1-1),toit_esca_devant_ret) + editor.placeBlock((x2,y1+4+i,z2-1-i),toit_esca_gauch_rete) + editor.placeBlock((x2,y1+4+i,midtailleZ+i),toit_esca_droite_ret) + + + + elif x1==0: + for i in range(3): + if i==2: + i=1 + mur_sol((x1+i+1,y1+5+i,midtailleZ+1+i),(x2+1,y1+5+i,z2-1-i),toit_planche) + mur_sol((x1+i+1,y1+5+i,z1-1),(midtailleX-i-1,y1+5+i,z2-1-i),toit_planche) + mur_sol((x1+i+1,y1+6+i,midtailleZ+1+i),(x2+1,y1+6+i,z2-1-i),toit_slab) + mur_sol((x1+i+1,y1+6+i,z1-1),(midtailleX-i-1,y1+6+i,z2-1-i),toit_slab) + i=2 + + else: + pass + mur_sol((x1+i,y1+5+i,midtailleZ+i+1),(x2,y1+5+i,z2-i-1),mur) + mur_sol((x1+i+1,y1+5+i,z1),(midtailleX-i-1,y1+5+i,z2-i),mur) + + poserEscalier((midtailleX-i,y1+4+i,midtailleZ-1+i),(x2+1,y1+4+i,midtailleZ-1+i),toit_esca_gauche) + poserEscalier((midtailleX-i,y1+4+i,z1-1),(midtailleX-i,y1+4+i,midtailleZ+i),toit_esca_derriere) + poserEscalier((x1+i,y1+4+i,z2-i),(x2+1,y1+4+i,z2-i),toit_esca_droite) + poserEscalier((x1+i-1,y1+4+i,z1-1),(x1+i-1,y1+4+i,z2+1-i),toit_esca_devant) + + if hauteurMax==5+i: + break + for i in range(2): + pass + editor.placeBlock((x1+i,y1+4+i,z1-1),toit_esca_derriere_ret) + editor.placeBlock((midtailleX-1-i,y1+4+i,z1-1),toit_esca_devant_ret) + editor.placeBlock((x2,y1+4+i,z2-1-i),toit_esca_gauch_rete) + editor.placeBlock((x2,y1+4+i,midtailleZ+i),toit_esca_droite_ret) + + + elif z1==0: + for i in range(3): + if i==2: + i=1 + mur_sol((x1+i+1,y1+5+i,midtailleZ+1+i),(x2+1,y1+5+i,z2-1-i),toit_planche) + mur_sol((x1+i+1,y1+5+i,z1-1),(midtailleX-i-1,y1+5+i,z2-1-i),toit_planche) + mur_sol((x1+i+1,y1+6+i,midtailleZ+1+i),(x2+1,y1+6+i,z2-1-i),toit_slab) + mur_sol((x1+i+1,y1+6+i,z1-1),(midtailleX-i-1,y1+6+i,z2-1-i),toit_slab) + i=2 + + else: + pass + mur_sol((x1+i,y1+5+i,midtailleZ+i+1),(x2,y1+5+i,z2-i-1),mur) + mur_sol((x1+i+1,y1+5+i,z1),(midtailleX-i-1,y1+5+i,z2-i),mur) + + poserEscalier((midtailleX-i,y1+4+i,midtailleZ-1+i),(x2+1,y1+4+i,midtailleZ-1+i),toit_esca_gauche) + poserEscalier((midtailleX-i,y1+4+i,z1-1),(midtailleX-i,y1+4+i,midtailleZ+1+i),toit_esca_derriere) + poserEscalier((x1+i,y1+4+i,z2-i),(x2+1,y1+4+i,z2-i),toit_esca_droite) + poserEscalier((x1+i-1,y1+4+i,z1-1),(x1+i-1,y1+4+i,z2+3-i),toit_esca_devant) + + if hauteurMax==5+i: + break + for i in range(2): + pass + editor.placeBlock((x1+i,y1+4+i,z1-1),toit_esca_derriere_ret) + editor.placeBlock((midtailleX-1-i,y1+4+i,z1-1),toit_esca_devant_ret) + editor.placeBlock((x2,y1+4+i,z2-1-i),toit_esca_gauch_rete) + editor.placeBlock((x2,y1+4+i,midtailleZ+i),toit_esca_droite_ret) + + + + + else: + for i in range(3): + if i==2: + i=1 + mur_sol((x1+i+1,y1+5+i,midtailleZ+1+i),(x2+1,y1+5+i,z2-1-i),toit_planche) + mur_sol((x1+i+1,y1+5+i,z1-1),(midtailleX-i-1,y1+5+i,z2-1-i),toit_planche) + mur_sol((x1+i+1,y1+6+i,midtailleZ+1+i),(x2+1,y1+6+i,z2-1-i),toit_slab) + mur_sol((x1+i+1,y1+6+i,z1-1),(midtailleX-i-1,y1+6+i,z2-1-i),toit_slab) + i=2 + + else: + pass + mur_sol((x1+i,y1+5+i,midtailleZ+i+1),(x2,y1+5+i,z2-i-1),mur) + mur_sol((x1+i+1,y1+5+i,z1),(midtailleX-i-1,y1+5+i,z2-i),mur) + + poserEscalier((midtailleX-i,y1+4+i,midtailleZ-1+i),(x2+1,y1+4+i,midtailleZ-1+i),toit_esca_gauche) + poserEscalier((midtailleX-i,y1+4+i,z1-1),(midtailleX-i,y1+4+i,midtailleZ+i),toit_esca_derriere) + poserEscalier((x1+i,y1+4+i,z2-i),(x2+1,y1+4+i,z2-i),toit_esca_droite) + poserEscalier((x1+i-1,y1+4+i,z1-1),(x1+i-1,y1+4+i,z2+1-i),toit_esca_devant) + + if hauteurMax==5+i: + break + for i in range(2): + pass + editor.placeBlock((x1+i,y1+4+i,z1-1),toit_esca_derriere_ret) + editor.placeBlock((midtailleX-1-i,y1+4+i,z1-1),toit_esca_devant_ret) + editor.placeBlock((x2,y1+4+i,z2-1-i),toit_esca_gauch_rete) + editor.placeBlock((x2,y1+4+i,midtailleZ+i),toit_esca_droite_ret) + + + elif direction=='south': + + + if cotegarage=='left': + if x1==0 and z1==0: + for i in range(3): + if i==2: + i=1 + mur_sol((x1+1+i,y1+5+i,z1+i+1),(x2+1,y1+5+i,midtailleZ-i-1),toit_planche) + mur_sol((x1+i+1,y1+5+i,z1+1+i),(midtailleX-i-1,y1+5+i,z2+1),toit_planche) + mur_sol((x1+1+i,y1+6+i,z1+i+1),(x2+1,y1+6+i,midtailleZ-i-1),toit_slab) + mur_sol((x1+i+1,y1+6+i,z1+1+i),(midtailleX-i-1,y1+6+i,z2+1),toit_slab) + i=2 + + else: + pass + mur_sol((x1+1+i,y1+5+i,z1+i+1),(x2,y1+5+i,midtailleZ-i-1),mur) + mur_sol((x1+i+1,y1+5+i,z1+1+i),(midtailleX-i-1,y1+5+i,z2),mur) + + poserEscalier((x1+i,y1+4+i,z1-1+i),(x2+1,y1+4+i,z1-1+i),toit_esca_gauche) + poserEscalier((midtailleX-i,y1+4+i,midtailleZ-i),(midtailleX-i,y1+4+i,z2+1),toit_esca_derriere) + poserEscalier((midtailleX-i,y1+4+i,midtailleZ-i),(x2+1,y1+4+i,midtailleZ-i),toit_esca_droite) + poserEscalier((x1+i-1,y1+4+i,z1+i),(x1+i-1,y1+4+i,z2+1),toit_esca_devant) + editor.placeBlock((x1-1+i,y1+4+i,z1-1+i),toit_esca_devant) + if hauteurMax==5+i: + break + for i in range(2): + pass + editor.placeBlock((midtailleX-i-1,y1+4+i,z2),toit_esca_devant_ret) + editor.placeBlock((x1+i,y1+4+i,z2),toit_esca_derriere_ret) + editor.placeBlock((x2,y1+4+i,midtailleZ-1-i),toit_esca_gauch_rete) + editor.placeBlock((x2,y1+4+i,z1+i),toit_esca_droite_ret) + + + + elif x1==0: + for i in range(3): + if i==2: + i=1 + mur_sol((x1+1+i,y1+5+i,z1+i+1),(x2+1,y1+5+i,midtailleZ-i-1),toit_planche) + mur_sol((x1+i+1,y1+5+i,z1+1+i),(midtailleX-i-1,y1+5+i,z2+1),toit_planche) + mur_sol((x1+1+i,y1+6+i,z1+i+1),(x2+1,y1+6+i,midtailleZ-i-1),toit_slab) + mur_sol((x1+i+1,y1+6+i,z1+1+i),(midtailleX-i-1,y1+6+i,z2+1),toit_slab) + i=2 + + else: + pass + mur_sol((x1+1+i,y1+5+i,z1+i+1),(x2,y1+5+i,midtailleZ-i-1),mur) + mur_sol((x1+i+1,y1+5+i,z1+1+i),(midtailleX-i-1,y1+5+i,z2),mur) + + poserEscalier((x1+i,y1+4+i,z1-1+i),(x2+1,y1+4+i,z1-1+i),toit_esca_gauche) + poserEscalier((midtailleX-i,y1+4+i,midtailleZ-i),(midtailleX-i,y1+4+i,z2+1),toit_esca_derriere) + poserEscalier((midtailleX-i,y1+4+i,midtailleZ-i),(x2+1,y1+4+i,midtailleZ-i),toit_esca_droite) + poserEscalier((x1+i-1,y1+4+i,z1+i),(x1+i-1,y1+4+i,z2+1),toit_esca_devant) + editor.placeBlock((x1-1+i,y1+4+i,z1-1+i),toit_esca_devant) + if hauteurMax==5+i: + break + for i in range(2): + pass + editor.placeBlock((midtailleX-i-1,y1+4+i,z2),toit_esca_devant_ret) + editor.placeBlock((x1+i,y1+4+i,z2),toit_esca_derriere_ret) + editor.placeBlock((x2,y1+4+i,midtailleZ-1-i),toit_esca_gauch_rete) + editor.placeBlock((x2,y1+4+i,z1+i),toit_esca_droite_ret) + elif z1==0: + for i in range(3): + if i==2: + i=1 + mur_sol((x1+1+i,y1+5+i,z1+i+1),(x2+1,y1+5+i,midtailleZ-i-1),toit_planche) + mur_sol((x1+i+1,y1+5+i,z1+1+i),(midtailleX-i-1,y1+5+i,z2+1),toit_planche) + mur_sol((x1+1+i,y1+6+i,z1+i+1),(x2+1,y1+6+i,midtailleZ-i-1),toit_slab) + mur_sol((x1+i+1,y1+6+i,z1+1+i),(midtailleX-i-1,y1+6+i,z2+1),toit_slab) + i=2 + + else: + pass + mur_sol((x1+1+i,y1+5+i,z1+i+1),(x2,y1+5+i,midtailleZ-i-1),mur) + mur_sol((x1+i+1,y1+5+i,z1+1+i),(midtailleX-i-1,y1+5+i,z2),mur) + + poserEscalier((x1+i,y1+4+i,z1-1+i),(x2+1,y1+4+i,z1-1+i),toit_esca_gauche) + poserEscalier((midtailleX-i,y1+4+i,midtailleZ-i),(midtailleX-i,y1+4+i,z2+1),toit_esca_derriere) + poserEscalier((midtailleX-i,y1+4+i,midtailleZ-i),(x2+1,y1+4+i,midtailleZ-i),toit_esca_droite) + poserEscalier((x1+i-1,y1+4+i,z1+i),(x1+i-1,y1+4+i,z2+1),toit_esca_devant) + editor.placeBlock((x1-1+i,y1+4+i,z1-1+i),toit_esca_devant) + if hauteurMax==5+i: + break + for i in range(2): + pass + editor.placeBlock((midtailleX-i-1,y1+4+i,z2),toit_esca_devant_ret) + editor.placeBlock((x1+i,y1+4+i,z2),toit_esca_derriere_ret) + editor.placeBlock((x2,y1+4+i,midtailleZ-1-i),toit_esca_gauch_rete) + editor.placeBlock((x2,y1+4+i,z1+i),toit_esca_droite_ret) + + + + + else: + for i in range(3): + if i==2: + i=1 + mur_sol((x1+1+i,y1+5+i,z1+i+1),(x2+1,y1+5+i,midtailleZ-i-1),toit_planche) + mur_sol((x1+i+1,y1+5+i,z1+1+i),(midtailleX-i-1,y1+5+i,z2+1),toit_planche) + mur_sol((x1+1+i,y1+6+i,z1+i+1),(x2+1,y1+6+i,midtailleZ-i-1),toit_slab) + mur_sol((x1+i+1,y1+6+i,z1+1+i),(midtailleX-i-1,y1+6+i,z2+1),toit_slab) + i=2 + + else: + pass + mur_sol((x1+1+i,y1+5+i,z1+i+1),(x2,y1+5+i,midtailleZ-i-1),mur) + mur_sol((x1+i+1,y1+5+i,z1+1+i),(midtailleX-i-1,y1+5+i,z2),mur) + + poserEscalier((x1+i,y1+4+i,z1-1+i),(x2+1,y1+4+i,z1-1+i),toit_esca_gauche) + poserEscalier((midtailleX-i,y1+4+i,midtailleZ-i),(midtailleX-i,y1+4+i,z2+1),toit_esca_derriere) + poserEscalier((midtailleX-i,y1+4+i,midtailleZ-i),(x2+1,y1+4+i,midtailleZ-i),toit_esca_droite) + poserEscalier((x1+i-1,y1+4+i,z1+i),(x1+i-1,y1+4+i,z2+1),toit_esca_devant) + editor.placeBlock((x1-1+i,y1+4+i,z1-1+i),toit_esca_devant) + if hauteurMax==5+i: + break + for i in range(2): + pass + editor.placeBlock((midtailleX-i-1,y1+4+i,z2),toit_esca_devant_ret) + editor.placeBlock((x1+i,y1+4+i,z2),toit_esca_derriere_ret) + editor.placeBlock((x2,y1+4+i,midtailleZ-1-i),toit_esca_gauch_rete) + editor.placeBlock((x2,y1+4+i,z1+i),toit_esca_droite_ret) + + + elif cotegarage=='right': + if x1==0 and z1==0: + for i in range(3): + if i==2: + i=1 + mur_sol((x1-1,y1+5+i,z1+i+1),(x2-1-i,y1+5+i,midtailleZ-i-1),toit_planche) + mur_sol((midtailleX+i+1,y1+5+i,z1+1+i),(x2-i-1,y1+5+i,z2+1),toit_planche) + mur_sol((x1-1,y1+6+i,z1+i+1),(x2-1-i,y1+6+i,midtailleZ-i-1),toit_slab) + mur_sol((midtailleX+i+1,y1+6+i,z1+1+i),(x2-i-1,y1+6+i,z2+1),toit_slab) + i=2 + + else: + pass + mur_sol((x1,y1+5+i,z1+i+1),(x2-1-i,y1+5+i,midtailleZ-i-1),mur) + mur_sol((midtailleX+i+1,y1+5+i,z1+1+i),(x2-i-1,y1+5+i,z2),mur) + + poserEscalier((x1-1,y1+4+i,z1-1+i),(x2+3-i,y1+4+i,z1-1+i),toit_esca_gauche) + poserEscalier((x2-i,y1+4+i,z1+i),(x2-i,y1+4+i,z2+1),toit_esca_derriere) + poserEscalier((x1-1,y1+4+i,midtailleZ-i),(midtailleX+1+i,y1+4+i,midtailleZ-i),toit_esca_droite) + poserEscalier((midtailleX-1+i,y1+4+i,midtailleZ-i),(midtailleX-1+i,y1+4+i,z2+1),toit_esca_devant) + #editor.placeBlock((x1-1+i,y1+4+i,z1-1+i),toit_esca_devant) + if hauteurMax==5+i: + break + for i in range(2): + pass + editor.placeBlock((x2-i-1,y1+4+i,z2),toit_esca_devant_ret) + editor.placeBlock((midtailleX+i,y1+4+i,z2),toit_esca_derriere_ret) + editor.placeBlock((x1-1,y1+4+i,midtailleZ-1-i),toit_esca_gauch_rete) + editor.placeBlock((x1-1,y1+4+i,z1+i),toit_esca_droite_ret) + + + + elif x1==0: + for i in range(3): + if i==2: + i=1 + mur_sol((x1-1,y1+5+i,z1+i+1),(x2-1-i,y1+5+i,midtailleZ-i-1),toit_planche) + mur_sol((midtailleX+i+1,y1+5+i,z1+1+i),(x2-i-1,y1+5+i,z2+1),toit_planche) + mur_sol((x1-1,y1+6+i,z1+i+1),(x2-1-i,y1+6+i,midtailleZ-i-1),toit_slab) + mur_sol((midtailleX+i+1,y1+6+i,z1+1+i),(x2-i-1,y1+6+i,z2+1),toit_slab) + i=2 + + else: + pass + mur_sol((x1,y1+5+i,z1+i+1),(x2-1-i,y1+5+i,midtailleZ-i-1),mur) + mur_sol((midtailleX+i+1,y1+5+i,z1+1+i),(x2-i-1,y1+5+i,z2),mur) + + poserEscalier((x1-1,y1+4+i,z1-1+i),(x2+3-i,y1+4+i,z1-1+i),toit_esca_gauche) + poserEscalier((x2-i,y1+4+i,z1+i),(x2-i,y1+4+i,z2+1),toit_esca_derriere) + poserEscalier((x1-1,y1+4+i,midtailleZ-i),(midtailleX+1+i,y1+4+i,midtailleZ-i),toit_esca_droite) + poserEscalier((midtailleX-1+i,y1+4+i,midtailleZ-i),(midtailleX-1+i,y1+4+i,z2+1),toit_esca_devant) + #editor.placeBlock((x1-1+i,y1+4+i,z1-1+i),toit_esca_devant) + if hauteurMax==5+i: + break + for i in range(2): + pass + editor.placeBlock((x2-i-1,y1+4+i,z2),toit_esca_devant_ret) + editor.placeBlock((midtailleX+i,y1+4+i,z2),toit_esca_derriere_ret) + editor.placeBlock((x1-1,y1+4+i,midtailleZ-1-i),toit_esca_gauch_rete) + editor.placeBlock((x1-1,y1+4+i,z1+i),toit_esca_droite_ret) + elif z1==0: + for i in range(3): + if i==2: + i=1 + mur_sol((x1-1,y1+5+i,z1+i+1),(x2-1-i,y1+5+i,midtailleZ-i-1),toit_planche) + mur_sol((midtailleX+i+1,y1+5+i,z1+1+i),(x2-i-1,y1+5+i,z2+1),toit_planche) + mur_sol((x1-1,y1+6+i,z1+i+1),(x2-1-i,y1+6+i,midtailleZ-i-1),toit_slab) + mur_sol((midtailleX+i+1,y1+6+i,z1+1+i),(x2-i-1,y1+6+i,z2+1),toit_slab) + i=2 + + else: + pass + mur_sol((x1,y1+5+i,z1+i+1),(x2-1-i,y1+5+i,midtailleZ-i-1),mur) + mur_sol((midtailleX+i+1,y1+5+i,z1+1+i),(x2-i-1,y1+5+i,z2),mur) + + poserEscalier((x1-1,y1+4+i,z1-1+i),(x2+1-i,y1+4+i,z1-1+i),toit_esca_gauche) + poserEscalier((x2-i,y1+4+i,z1+i),(x2-i,y1+4+i,z2+1),toit_esca_derriere) + poserEscalier((x1-1,y1+4+i,midtailleZ-i),(midtailleX+1+i,y1+4+i,midtailleZ-i),toit_esca_droite) + poserEscalier((midtailleX-1+i,y1+4+i,midtailleZ-i),(midtailleX-1+i,y1+4+i,z2+1),toit_esca_devant) + #editor.placeBlock((x1-1+i,y1+4+i,z1-1+i),toit_esca_devant) + if hauteurMax==5+i: + break + for i in range(2): + pass + editor.placeBlock((x2-i-1,y1+4+i,z2),toit_esca_devant_ret) + editor.placeBlock((midtailleX+i,y1+4+i,z2),toit_esca_derriere_ret) + editor.placeBlock((x1-1,y1+4+i,midtailleZ-1-i),toit_esca_gauch_rete) + editor.placeBlock((x1-1,y1+4+i,z1+i),toit_esca_droite_ret) + + + + + else: + for i in range(3): + if i==2: + i=1 + mur_sol((x1-1,y1+5+i,z1+i+1),(x2-1-i,y1+5+i,midtailleZ-i-1),toit_planche) + mur_sol((midtailleX+i+1,y1+5+i,z1+1+i),(x2-i-1,y1+5+i,z2+1),toit_planche) + mur_sol((x1-1,y1+6+i,z1+i+1),(x2-1-i,y1+6+i,midtailleZ-i-1),toit_slab) + mur_sol((midtailleX+i+1,y1+6+i,z1+1+i),(x2-i-1,y1+6+i,z2+1),toit_slab) + i=2 + + else: + pass + mur_sol((x1,y1+5+i,z1+i+1),(x2-1-i,y1+5+i,midtailleZ-i-1),mur) + mur_sol((midtailleX+i+1,y1+5+i,z1+1+i),(x2-i-1,y1+5+i,z2),mur) + + poserEscalier((x1-1,y1+4+i,z1-1+i),(x2+1-i,y1+4+i,z1-1+i),toit_esca_gauche) + poserEscalier((x2-i,y1+4+i,z1+i),(x2-i,y1+4+i,z2+1),toit_esca_derriere) + poserEscalier((x1-1,y1+4+i,midtailleZ-i),(midtailleX+1+i,y1+4+i,midtailleZ-i),toit_esca_droite) + poserEscalier((midtailleX-1+i,y1+4+i,midtailleZ-i),(midtailleX-1+i,y1+4+i,z2+1),toit_esca_devant) + #editor.placeBlock((x1-1+i,y1+4+i,z1-1+i),toit_esca_devant) + if hauteurMax==5+i: + break + for i in range(2): + pass + editor.placeBlock((x2-i-1,y1+4+i,z2),toit_esca_devant_ret) + editor.placeBlock((midtailleX+i,y1+4+i,z2),toit_esca_derriere_ret) + editor.placeBlock((x1-1,y1+4+i,midtailleZ-1-i),toit_esca_gauch_rete) + editor.placeBlock((x1-1,y1+4+i,z1+i),toit_esca_droite_ret) + +def poserFenetre(co1,co2,type): + editor = Editor(buffering= True) + + x=abs((co2[0])-(co1[0])) + z=abs((co2[2])-(co1[2])) + y= abs(co2[1]-co1[1]) + + if co1[0]==co2[0]: + if z%2==0: + if z==4: + + editor.placeBlock((co1[0],co1[1]+1,co1[2]+1),type) + editor.placeBlock((co1[0],co1[1]+1,co1[2]+2),type) + else: + + for i in range(z//2): + if i%2==0: + editor.placeBlock((co1[0],co1[1]+1,co1[2]+i*2),type) + editor.placeBlock((co1[0],co1[1]+1,co1[2]+i*2+1),type) + else: + if z<=5: + for i in range(z): + + + editor.placeBlock((co1[0],co1[1]+1,co1[2]+i),type) + else: + + for i in range((z//3)): + if 3*(i+1)+(i)>abs(co2[2]-co1[2]): + break + else: + editor.placeBlock((co1[0],co1[1]+1,co1[2]+i*4),type) + editor.placeBlock((co1[0],co1[1]+1,co1[2]+i*4+1),type) + editor.placeBlock((co1[0],co1[1]+1,co1[2]+i*4+2),type) + + + + + if co1[2]==co2[2]: + + if x%2==0: + if x==4: + + editor.placeBlock((co1[0]+1,co1[1]+1,co1[2]),type) + editor.placeBlock((co1[0]+2,co1[1]+1,co1[2]),type) + else: + for i in range(x//2): + if i%2==0: + editor.placeBlock((co1[0]+i*2,co1[1]+1,co1[2]),type) + editor.placeBlock((co1[0]+i*2+1,co1[1]+1,co1[2]),type) + else: + if x<=5: + + + for i in range(x): + + + editor.placeBlock((co1[0]+i,co1[1]+1,co1[2]),type) + else: + + for i in range((x//3)): + if 3*(i+1)+i>abs(co2[0]-co1[0]): + break + else: + editor.placeBlock((co1[0]+i*4,co1[1]+1,co1[2]),type) + editor.placeBlock((co1[0]+i*4+1,co1[1]+1,co1[2]),type) + editor.placeBlock((co1[0]+i*4+2,co1[1]+1,co1[2]),type) + + + + + + + +def poserGarage(co1,co2): + + x1=co1[0] + y1=co1[1] + z1=co1[2] + x2=co2[0] + y2=co2[1] + z2=co2[2] + editor = Editor(buffering= True) + if x1<0 or x2<0: + if x1<0 and x2>=0: + x=x2-x1 + + elif x1<0 and x2<0: + + x=abs(co2[0]-co1[0]) + + else: + + x=co2[0]-co1[0] + + if z1<0 or z2<0: + if z1<0 and z2>=0: + z=co2[2]-co1[2] + + elif z1<0 and z2<0: + + z=abs(co2[2]-co1[2]) + + else: + + z=co2[2]-co1[2] + + + + + + + if x1==x2: + if z1<0 or z2<0: + if z1<0 and z2>=0: + for i in range(abs(abs(co2[1])-abs(co1[1]))): + for j in range((z2-z1)): + + editor.placeBlock((co1[0],co1[1]+i,co1[2]+j),block_quartz) + elif z1<0 and z2<0: + + for i in range(abs(abs(co2[1])-abs(co1[1]))): + for j in range(abs(z2-z1)): + + editor.placeBlock((co1[0],co1[1]+i,co1[2]+j),block_quartz) + else: + for i in range(abs(abs(co2[1])-abs(co1[1]))): + for j in range((abs(co2[2])-abs(co1[2]))): + + editor.placeBlock((co1[0],co1[1]+i,co1[2]+j),block_quartz) + + + elif z2==z1: + if x1<0 or x2<0: + if x1<0 and x2>=0: + print(abs(abs(co2[1])-abs(co1[1]))) + print(x2-x1) + for i in range(abs(abs(co2[1])-abs(co1[1]))): + for j in range(x2-x1): + + editor.placeBlock((co1[0]+j,co1[1]+i,co1[2]),block_quartz) + elif x1<0 and x2<0: + for i in range(abs(abs(co2[1])-abs(co1[1]))): + for j in range(abs(x2-x1)): + + editor.placeBlock((co1[0]+j,co1[1]+i,co1[2]),block_quartz) + else: + for i in range(abs(abs(co2[1])-abs(co1[1]))): + for j in range( (abs(co2[0])-abs(co1[0]))): + + editor.placeBlock((co1[0]+j,co1[1]+i,co1[2]),block_quartz) + + + + + + + + if co1[0]==co2[0]: + + if z%3==0: + for i in range(z//3): + editor.placeBlock((co1[0],co2[1],co1[2]+i*3),stairs_quartz_droite) + editor.placeBlock((co1[0],co2[1],co1[2]+1+i*3),quartz_slab_up) + editor.placeBlock((co1[0],co2[1],co1[2]+2+i*3),stairs_quartz_gauche) + elif z%2==0: + for i in range(z): + if i%2==0: + editor.placeBlock((co1[0],co2[1],co1[2]+i),stairs_quartz_droite) + else: + editor.placeBlock((co1[0],co2[1],co1[2]+i),stairs_quartz_gauche) + if z%5==0: + for i in range((z//5)): + + editor.placeBlock((co1[0],co2[1],co1[2]+i*5),stairs_quartz_droite) + editor.placeBlock((co1[0],co2[1],co1[2]+1+i*5),stairs_quartz_gauche) + editor.placeBlock((co1[0],co2[1],co1[2]+2+i*5),block_quartz) + editor.placeBlock((co1[0],co2[1],co1[2]+3+i*5),stairs_quartz_droite) + editor.placeBlock((co1[0],co2[1],co1[2]+4+i*5),stairs_quartz_gauche) + + elif co1[2]==co2[2]: + + if x%3==0: + + for i in range(x//3): + editor.placeBlock((co1[0]+i*3,co2[1],co1[2]),stairs_quartz_derriere) + editor.placeBlock((co1[0]+1+i*3,co2[1],co1[2]),quartz_slab_up) + editor.placeBlock((co1[0]+2+i*3,co2[1],co1[2]),stairs_quartz_devant) + elif x%2==0: + for i in range(x): + if i%2==0: + editor.placeBlock((co1[0]+i,co2[1],co1[2]),stairs_quartz_derriere) + else: + editor.placeBlock((co1[0]+i,co2[1],co1[2]),stairs_quartz_devant) + elif x%5==0: + for i in range((x//5)): + + editor.placeBlock((co1[0]+i*5,co2[1],co1[2]),stairs_quartz_derriere) + editor.placeBlock((co1[0]+1+i*5,co2[1],co1[2]),stairs_quartz_devant) + editor.placeBlock((co1[0]+2+i*5,co2[1],co1[2]),block_quartz) + editor.placeBlock((co1[0]+3+i*5,co2[1],co1[2]),stairs_quartz_derriere) + editor.placeBlock((co1[0]+4+i*5,co2[1],co1[2]),stairs_quartz_devant) + + + + + + + +def house(co1,co2,cotegarage,hauteurMax,nb_style,direction):# ,etage): + """ + Minimun 10*10 + """ + + if nb_style==0: + style=style_basique + elif nb_style==1: + style=style_birch + elif nb_style==2: + style=style_end + else: + style=style_jungle + + + sol=Block(style['sol']) + mur=Block(style['mur']) + grass=Block(style['grass']) + chemin=Block(style['chemin']) + fence=Block(style['fence']) + + glass=Block(style['glass']) + + + + + + + + + tailleX=abs(co2[0])-abs(co1[0]) + + hauteurMin=min(co2[1],co1[1]) + tailleZ=abs(co2[2])-abs(co1[2]) + + editor = Editor(buffering= True) + + + + x1=co1[0] + y1=co1[1] + z1=co1[2] + x2=co2[0] + y2=co2[1] + z2=co2[2] + + if x1<0 or x2<0: + if x1<0 and x2>=0: + tailleX=x2-x1 + midtailleX=(tailleX//2)+x1 + elif x1<0 and x2<0: + print(abs(co2[0]-co1[0]),(tailleX//2)+x1) + tailleX=abs(co2[0]-co1[0]) + midtailleX=(tailleX//2)+x1 + else: + + tailleX=co2[0]-co1[0] + midtailleX=(tailleX//2)+x1 + + if z1<0 or z2<0: + if z1<0 and z2>=0: + tailleZ=co2[2]-co1[2] + midtailleZ=(tailleZ//2)+z1 + elif z1<0 and z2<0: + + tailleZ=abs(co2[2]-co1[2]) + midtailleZ=(tailleZ//2)+z1 + else: + + tailleZ=co2[2]-co1[2] + midtailleZ=(tailleZ//2)+z1 + + + + + + if direction=='west': + door=Block(style['door'],{"facing": "east"}) + if cotegarage=='right': + + + + + #murs + poserGarage((x1+1,y1+1,midtailleZ+1),(x1+1,y1+3,z2-1)) + mur_sol((x1,y1+1,z2-1),(x2,y1+5,z2-1),mur) + mur_sol((x1,y1+1,midtailleZ),(x1,y1+5,z2 ),mur) + mur_sol((x2-1,y1+1,z1),(x2-1,y1+5,z2),mur) + mur_sol((x1,y1+1,midtailleZ),(midtailleX+1,y1+5,midtailleZ),mur) + mur_sol((midtailleX,y1+1,z1),(x2,y1+5,z1),mur) + mur_sol((midtailleX,y1+1,z1),(midtailleX,y1+5,midtailleZ),mur) + + + mur_sol((x1,y1+1,midtailleZ+1),(x1,y1+4,z2-1 ),air) + + #sols/plafonds + mur_sol((midtailleX,y1+4,z1),(x2,y1+4,z2),mur) + mur_sol((midtailleX,y1,z1),(x2,y1,z2),sol) + mur_sol((x1,y1+4,midtailleZ),(midtailleX,y1+4,z2),mur) + mur_sol((x1,y1,midtailleZ),(midtailleX,y1,z2),sol) + mur_sol((x1,y1,z1),(midtailleX,y1,midtailleZ),grass) + + + + poserFenetre((midtailleX,y1+1,z1+1),(midtailleX,y1+5,midtailleZ-1),glass) + poserFenetre((midtailleX+1,y1+1,z1),(x2-1,y1+5,z1),glass) + poserFenetre((x1+2,y1+1,midtailleZ),(midtailleX-1,y1+5,midtailleZ),glass) + poserFenetre((x2-1,y1+1,z1+1),(x2-1,y1+5,z2-1),glass) + poserFenetre((x1+2,y1+1,z2-1),(x2-1,y1+4,z2-1),glass) + + if ((z2-z1)//2)%2==0: + + poserPorte((x1+tailleX//2,hauteurMin+1,z1+(tailleZ//4)),door) + poserPorte((x1+tailleX//2,hauteurMin+1,z1+(tailleZ//4)-1),door) + mur_sol((x1,y1,z1+(tailleZ//4)-1),(x1+tailleX//2,y1,z1+(tailleZ//4)+1),chemin) + for i in range(tailleX): + for j in range(tailleZ): + if(z1+j != z1+(tailleZ//4) and z1+j != z1+(tailleZ//4)-1 ) and (x1+i< x1+(tailleX//2) and z1+j=z2-tailleZ//2 ) and(x1+i==x1 or z2-j==z2) and z2-j != z2-(tailleZ//4)-1 and z2-j != z2-(tailleZ//4): + + editor.placeBlock((x1+i,y1+1,z2-1-j),fence) + else: + + poserPorte((x1+tailleX//2,hauteurMin+1,z2-(tailleZ//4)-1),door) + mur_sol((x1,y1,z2-(tailleZ//4)-1),(x1+tailleX//2,y1,z2-(tailleZ//4)),chemin) + for i in range(tailleX): + for j in range(tailleZ): + if (x1+i< x1+(tailleX//2) and z2-j>=z2-tailleZ//2 ) and (x1+i==x1 or z2-j==z2) and z2-j != z2-(tailleZ//4): + + editor.placeBlock((x1+i,y1+1,z2-1-j),fence) + + + + + poserToit(co1,co2,hauteurMax,cotegarage,style,direction) + + + + + + + + + + elif direction=='east' : + door=Block(style['door'],{"facing": "west"}) + if cotegarage=='right': + + + + + #murs + #murs + poserGarage((x2-2,y1+1,z1+1),(x2-2,y1+3,midtailleZ-1)) + mur_sol((x1,y1+1,z1),(x2,y1+5,z1),mur) + mur_sol((x1,y1+1,z1),(x1,y1+5,z2 ),mur) + mur_sol((x2-1,y1+1,z1),(x2-1,y1+5,midtailleZ),mur) + mur_sol((midtailleX,y1+1,midtailleZ),(midtailleX,y1+5,z2),mur) + mur_sol((midtailleX,y1+1,midtailleZ-1),(x2,y1+5,midtailleZ-1),mur) + mur_sol((x1,y1+1,z2-1),(midtailleX,y1+5,z2-1),mur) + + + mur_sol((x2-1,y1+1,z1+1),(x2-1,y1+4,midtailleZ-1),air) + + + #sols/plafonds + mur_sol((x1,y1+4,z1),(x2,y1+4,midtailleZ),mur) + mur_sol((x1,y1,z1),(x2,y1,midtailleZ),sol) + mur_sol((x1,y1+4,midtailleZ),(midtailleX+1,y1+4,z2),mur) + mur_sol((x1,y1,midtailleZ),(midtailleX+1,y1,z2),sol) + mur_sol((midtailleX+1,y1,midtailleZ),(x2,y1,z2),grass) + + poserFenetre((x1+1,y1+1,z2-1),(midtailleX-1,y1+5,z2-1),glass) + poserFenetre((midtailleX+1,y1+1,midtailleZ-1),(x2-2,y1+5,midtailleZ-1),glass) + poserFenetre((midtailleX,y1+1,midtailleZ+1),(midtailleX,y1+5,z2-1),glass) + poserFenetre((x1+1,y1+1,z1),(x2-1,y1+5,z1),glass) + poserFenetre((x1,y1+1,z1+1),(x1,y1+5,z2-1 ),glass) + + + + + + if (tailleZ-((z2-z1)//2))%2==0: + + poserPorte((x1+tailleX//2,hauteurMin+1,z2-1-(tailleZ//4)),door) + poserPorte((x1+tailleX//2,hauteurMin+1,z2-(tailleZ//4)-2),door) + mur_sol((midtailleX,y1,z2-2-(tailleZ//4)),(x2,y1,z2-(tailleZ//4)-4),chemin) + for i in range(tailleX): + for j in range(tailleZ): + if (midtailleX+1+i< x2 and z1+j>=midtailleZ ) and (midtailleX+i+1==x2-1 or z1+j==z2-1) and z1+j != z2-1-(tailleZ//4) and z1+j != z2-2-(tailleZ//4) : + + editor.placeBlock((midtailleX+1+i,y1+1,z1+j),fence) + else: + + poserPorte((x1+tailleX//2,hauteurMin+1,z2-1-(tailleZ//4)),door) + mur_sol((midtailleX,y1,z2-1-(tailleZ//4)),(x2,y1,z2-(tailleZ//4)-2),chemin) + for i in range(tailleX): + for j in range(tailleZ): + if (midtailleX+1+i< x2 and z1+j>=midtailleZ ) and (midtailleX+i+1==x2-1 or z1+j==z2-1) and z1+j != z2-1-(tailleZ//4): + + editor.placeBlock((midtailleX+i+1,y1+1,z1+j),fence) + + + + + poserToit(co1,co2,hauteurMax,cotegarage,style,direction ) + + + + + elif cotegarage=='left': + + + + + + + + + + + + #murs + poserGarage((x2-2,y1+1,midtailleZ+1),(x2-2,y1+3,z2-1)) + mur_sol((x1,y1+1,z1),(midtailleX,y1+5,z1),mur) + mur_sol((x1,y1+1,z1),(x1,y1+5,z2 ),mur) + mur_sol((x2-1,y1+1,midtailleZ),(x2-1,y1+5,z2),mur) + mur_sol((midtailleX,y1+1,z1),(midtailleX,y1+5,midtailleZ),mur) + mur_sol((midtailleX,y1+1,midtailleZ),(x2,y1+5,midtailleZ),mur) + mur_sol((x1,y1+1,z2-1),(x2,y1+5,z2-1),mur) + + + mur_sol((x2-1,y1+1,midtailleZ+1),(x2-1,y1+4,z2-1),air) + + + #sols/plafonds + mur_sol((x1,y1+4,midtailleZ),(x2,y1+4,z2),mur) + mur_sol((x1,y1,midtailleZ),(x2,y1,z2),sol) + mur_sol((x1,y1+4,z1),(midtailleX+1,y1+4,midtailleZ),mur) + mur_sol((x1,y1,z1),(midtailleX+1,y1,midtailleZ),sol) + mur_sol((midtailleX+1,y1,z1),(x2,y1,midtailleZ),grass) + + poserFenetre((x1+1,y1+1,z1),(midtailleX,y1+5,z1),glass) + poserFenetre((x1,y1+1,z1+1),(x1,y1+5,z2-1 ),glass) + poserFenetre((midtailleX,y1+1,z1+1),(midtailleX,y1+5,midtailleZ-1),glass) + poserFenetre((midtailleX+2,y1+1,midtailleZ),(x2-2,y1+5,midtailleZ),glass) + poserFenetre((x1+1,y1+1,z2-1),(x2-1,y1+5,z2-1),glass) + + + + + + if ((z2-z1)//2)%2==0: + + poserPorte((x1+tailleX//2,hauteurMin+1,z1+(tailleZ//4)),door) + poserPorte((x1+tailleX//2,hauteurMin+1,z1+(tailleZ//4)+1),door) + mur_sol((midtailleX,y1,z1+(tailleZ//4)),(x2,y1,z1+(tailleZ//4)+2),chemin) + for i in range(tailleX): + for j in range(tailleZ): + if (midtailleX+1+i< x2 and z1+j= midtailleX and z1+j= midtailleX and z1+j= midtailleX and z1+j=midtailleZ )and (x1+i==x1 or z1+j==z2-1) and x1+i != x1+tailleX//4 and x1+i != x1+1+tailleX//4: + + editor.placeBlock((x1+i,y1+1,z1+j),fence) + else: + + poserPorte((x1+tailleX//4,hauteurMin+1,midtailleZ-1),door) + mur_sol((x1+tailleX//4,y1,midtailleZ),(x1+1+tailleX//4,y1,z2),chemin) + for i in range(tailleX): + for j in range(tailleZ): + if (x1+i< midtailleX and z1+j>=midtailleZ )and (x1+i==x1 or z1+j==z2-1) and x1+i != x1+tailleX//4: + + editor.placeBlock((x1+i,y1+1,z1+j),fence) + + + + + poserToit(co1,co2,hauteurMax,cotegarage,style,direction ) + + + + elif cotegarage=='left': + #murs + #murs + poserGarage((x1+1,y1+1,z2-2),(midtailleX-1,y1+3,z2-2)) + mur_sol((midtailleX,y1+1,midtailleZ-1),(x2,y1+5,midtailleZ-1),mur) + mur_sol((x2-1,y1+1,z1),(x2-1,y1+5,midtailleZ ),mur) + mur_sol((x1,y1+1,z1),(x1,y1+5,z2),mur) + mur_sol((x1,y1+1,z1),(x2,y1+5,z1),mur) + mur_sol((midtailleX-1,y1+1,midtailleZ ),(midtailleX-1,y1+5,z2),mur) + + + + + + + #sols/plafonds + mur_sol((x1,y1+4,z1),(x2,y1+4,z2),mur) + mur_sol((x1,y1,z1),(x2,y1,z2),sol) + + mur_sol((midtailleX,y1+4,midtailleZ),(x2,y1+4,z2),air) + + mur_sol((midtailleX,y1,midtailleZ),(x2,y1,z2),grass) + + poserFenetre((midtailleX+1,y1+1,midtailleZ-1),(x2-1,y1+5,midtailleZ-1),glass) + poserFenetre((x2-1,y1+1,z1+1),(x2-1,y1+5,midtailleZ-1 ),glass) + poserFenetre((x1,y1+1,z1+1),(x1,y1+5,z2-1),glass) + poserFenetre((x1+1,y1+1,z1),(x2-1,y1+5,z1),glass) + poserFenetre((midtailleX-1,y1+1,midtailleZ+1 ),(midtailleX-1,y1+5,z2-2),glass) + + + + + + if (((x2-x1)//2))%2==0: + + poserPorte((x2-tailleX//4,hauteurMin+1,midtailleZ),door) + poserPorte((x2-1-tailleX//4,hauteurMin+1,midtailleZ),door) + mur_sol((x2-1-tailleX//4,y1,midtailleZ),(x2-3-tailleX//4,y1,z2),chemin) + for i in range(tailleX): + for j in range(tailleZ): + if (x1+i>= midtailleX and z1+j>=midtailleZ )and (x1+i==x2-1 or z1+j==z2-1) and x1+i != x2-2-tailleX//4 and x1+i != x2-1-tailleX//4: + + editor.placeBlock((x1+i,y1+1,z1+j),fence) + else: + + poserPorte((x2-1-tailleX//4,hauteurMin+1,midtailleZ-1),door) + mur_sol((x2-1-tailleX//4,y1,midtailleZ),(x2-2-tailleX//4,y1,z2),chemin) + for i in range(tailleX): + for j in range(tailleZ): + if (x1+i>= midtailleX and z1+j>=midtailleZ )and (x1+i==x2-1 or z1+j==z2-1) and x1+i != x2-1-tailleX//4: + + editor.placeBlock((x1+i,y1+1,z1+j),fence) + + + + + poserToit(co1,co2,hauteurMax,cotegarage,style,direction ) + + + +if __name__=="__main__": + + + + + + nb_style=randint(0,3) + + delete((-40,-60,-40),(50,-40,50)) + + house((-20,-60,-20),(-10,-60,-10),"right",10,nb_style,'north') + + + + + + + + + + diff --git a/networks/legacy_roads/list_block.py b/networks/legacy_roads/list_block.py new file mode 100644 index 0000000..b3dd29d --- /dev/null +++ b/networks/legacy_roads/list_block.py @@ -0,0 +1,117 @@ +from gdpc import Block + + +air = Block('air') + +stairs_devant = Block("oak_stairs", {"facing": "east"}) +stairs_derriere = Block("oak_stairs", {"facing": "west"}) +stairs_droite = Block("oak_stairs", {"facing": "north"}) +stairs_gauche = Block("oak_stairs", {"facing": "south"}) + +stairs_devant_retourner = Block( + "oak_stairs", {"facing": "east", "half": "top"}) +stairs_derriere_retourner = Block( + "oak_stairs", {"facing": "west", "half": "top"}) +stairs_droite_retourner = Block( + "oak_stairs", {"facing": "north", "half": "top"}) +stairs_gauche_retourner = Block( + "oak_stairs", {"facing": "south", "half": "top"}) + + +stairs_quartz_devant = Block( + "quartz_stairs", {"facing": "east", "half": "top"}) +stairs_quartz_derriere = Block( + "quartz_stairs", {"facing": "west", "half": "top"}) +stairs_quartz_droite = Block( + "quartz_stairs", {"facing": "north", "half": "top"}) +stairs_quartz_gauche = Block( + "quartz_stairs", {"facing": "south", "half": "top"}) + + +door_east = Block("oak_door", {"facing": "east"}) + + +oak_planks = Block("oak_planks") +oak_log = Block("oak_log") +spruce_wood = Block("spruce_wood") + + +black_stained_glass = Block("black_stained_glass") + + +white_concrete_powder = Block("white_concrete_powder") +white_concrete = Block("white_concrete") + +grass_block = Block("grass_block") +podzol = Block("podzol") + +block_quartz = Block("quartz_block") + + +block_white_concrete = Block("white_concrete") + + +oak_slab = Block('oak_slab') +quartz_slab_up = Block('quartz_slab', {"type": "top"}) + +oak_fence = Block('oak_fence') + + +style_basique = { + 'mur': "white_concrete", + 'sol': "oak_planks", + 'grass': "grass_block", + 'chemin': "quartz_block", + 'fence': 'oak_fence', + 'toit_esca': 'oak_stairs', + 'toit_planche': "oak_planks", + 'toit_slab': 'oak_slab', + 'glass': "glass", + 'door': 'oak_door' + + +} + +style_jungle = { + 'mur': "light_gray_concrete", + 'sol': "acacia_planks", + 'grass': "grass_block", + 'chemin': "podzol", + 'fence': 'acacia_fence', + 'toit_esca': 'acacia_stairs', + 'toit_planche': "acacia_planks", + 'toit_slab': 'acacia_slab', + 'glass': "glass", + 'door': 'acacia_door' + + +} +style_end = { + 'mur': "purple_concrete", + 'sol': "crimson_planks", + 'grass': "grass_block", + 'chemin': "amethyst_block", + 'fence': 'crimson_fence', + 'toit_esca': 'crimson_stairs', + 'toit_planche': "crimson_planks", + 'toit_slab': 'crimson_slab', + 'glass': "glass", + 'door': 'crimson_door' + + +} + +style_birch = { + 'mur': "yellow_concrete", + 'sol': "birch_planks", + 'grass': "grass_block", + 'chemin': "rooted_dirt", + 'fence': 'birch_fence', + 'toit_esca': 'birch_stairs', + 'toit_planche': "birch_planks", + 'toit_slab': 'birch_slab', + 'glass': "glass", + 'door': 'birch_door' + + +} diff --git a/networks/legacy_roads/maths.py b/networks/legacy_roads/maths.py new file mode 100644 index 0000000..c6afee8 --- /dev/null +++ b/networks/legacy_roads/maths.py @@ -0,0 +1,1155 @@ +from math import sqrt +from math import pi +from math import cos, sin +import matplotlib.pyplot as plt +import numpy as np +from scipy import interpolate + + +def line(xyz1, xyz2, pixelPerfect=True): + """ + Calculate a line between two points in 3D space. + + https://www.geeksforgeeks.org/bresenhams-algorithm-for-3-d-line-drawing/ + + Args: + xyz1 (tuple): First coordinates. + xyz2 (tuple): Second coordinates. + pixelPerfect (bool, optional): Blocks will be placed diagonally, + not side by side if pixelPerfect is True. Defaults to True. + + Returns: + list: List of blocks. + """ + (x1, y1, z1) = xyz1 + (x2, y2, z2) = xyz2 + x1, y1, z1, x2, y2, z2 = ( + round(x1), + round(y1), + round(z1), + round(x2), + round(y2), + round(z2), + ) + + ListOfPoints = [] + ListOfPoints.append((x1, y1, z1)) + dx = abs(x2 - x1) + dy = abs(y2 - y1) + dz = abs(z2 - z1) + if x2 > x1: + xs = 1 + else: + xs = -1 + if y2 > y1: + ys = 1 + else: + ys = -1 + if z2 > z1: + 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 x1 != x2: + x1 += xs + ListOfPoints.append((x1, y1, z1)) + if p1 >= 0: + y1 += ys + if not pixelPerfect: + if ListOfPoints[-1][1] != y1: + ListOfPoints.append((x1, y1, z1)) + p1 -= 2 * dx + if p2 >= 0: + z1 += zs + if not pixelPerfect: + if ListOfPoints[-1][2] != z1: + ListOfPoints.append((x1, y1, z1)) + 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 y1 != y2: + y1 += ys + ListOfPoints.append((x1, y1, z1)) + if p1 >= 0: + x1 += xs + if not pixelPerfect: + if ListOfPoints[-1][0] != x1: + ListOfPoints.append((x1, y1, z1)) + p1 -= 2 * dy + if p2 >= 0: + z1 += zs + if not pixelPerfect: + if ListOfPoints[-1][2] != z1: + ListOfPoints.append((x1, y1, z1)) + p2 -= 2 * dy + p1 += 2 * dx + p2 += 2 * dz + + # Driving axis is Z-axis + else: + p1 = 2 * dy - dz + p2 = 2 * dx - dz + while z1 != z2: + z1 += zs + ListOfPoints.append((x1, y1, z1)) + if p1 >= 0: + y1 += ys + if not pixelPerfect: + if ListOfPoints[-1][1] != y1: + ListOfPoints.append((x1, y1, z1)) + p1 -= 2 * dz + if p2 >= 0: + x1 += xs + if not pixelPerfect: + if ListOfPoints[-1][0] != x1: + ListOfPoints.append((x1, y1, z1)) + p2 -= 2 * dz + p1 += 2 * dy + p2 += 2 * dx + return ListOfPoints + + +def offset(distance, xy1, xy2): + """ + Compute the coordinates of perpendicular points from two points. 2D + only. + + Args: + distance (int): Distance from the line[xy1;xy2] of the + perpendicular points. + xy1 (tuple): First position. + xy2 (tuple): Second position. + + Returns: + tuple: The coordinates of perpendicular points. + A: Perpendicular from [xy1;xy2] at distance from pos1. + B: perpendicular from [xy1;xy2] at -distance from pos1. + C: perpendicular from [xy2;xy1] at distance from pos2. + D: perpendicular from [xy2;xy1] at -distance from pos2. + """ + A, B = perpendicular(distance * 2, xy1, xy2) + C, D = perpendicular(distance * 2, xy2, xy1) + return ([A, D], [B, C]) + + +def perpendicular(distance, xy1, xy2): + """ + Return a tuple of the perpendicular coordinates. + + Args: + distance (int): Distance from the line[xy1;xy2]. + xy1 (tuple): First coordinates. + xy2 (tuple): Second coordinates. + + Returns: + tuple: Coordinates of the line length distance, perpendicular + to [xy1; xy2] at xy1. + """ + (x1, y1) = xy1 + (x2, y2) = xy2 + dx = x1 - x2 + dy = y1 - y2 + dist = sqrt(dx * dx + dy * dy) + dx /= dist + dy /= dist + x3 = x1 + (distance / 2) * dy + y3 = y1 - (distance / 2) * dx + x4 = x1 - (distance / 2) * dy + y4 = y1 + (distance / 2) * dx + return ((round(x3), round(y3)), (round(x4), round(y4))) + + +def curve(points, number_true_pts=40, debug=False): + """ + Returns a 3d curve. + + https://stackoverflow.com/questions/18962175/spline-interpolation-coefficients-of-a-line-curve-in-3d-space + + Args: + points (np.array): Points where the curves should pass. + number_true_pts (int, optional): Number of points to compute. Defaults to 40. + debug (bool, optional): Just a visual graphic. Defaults to False. + + Returns: + tuple: Tuple of list of each coordinate. + """ + # Remove duplicates. + points = tuple(map(tuple, points)) + points = sorted(set(points), key=points.index) + + x_sample = [] + y_sample = [] + z_sample = [] + + for i in range(len(points)): + x_sample.append(points[i][0]) + z_sample.append(points[i][1]) + y_sample.append(points[i][2]) + + x_sample = np.array(x_sample) + y_sample = np.array(y_sample) + z_sample = np.array(z_sample) + + tck, u = interpolate.splprep([x_sample, y_sample, z_sample], s=2, k=2) + x_knots, y_knots, z_knots = interpolate.splev(tck[0], tck) + u_fine = np.linspace(0, 1, number_true_pts) + x_fine, y_fine, z_fine = interpolate.splev(u_fine, tck) + + if debug: + fig2 = plt.figure(2) + ax3d = fig2.add_subplot(111, projection="3d") + ax3d.plot(x_sample, y_sample, z_sample, "r*") + ax3d.plot(x_knots, y_knots, z_knots, "go") + ax3d.plot(x_fine, y_fine, z_fine, "r") + fig2.show() + plt.show() + + x = x_fine.tolist() + z = y_fine.tolist() + y = z_fine.tolist() + + for i in x: + i = round(i) + for i in y: + i = round(i) + for i in z: + i = round(i) + + return x, y, z + + +def curveOffset(x, y, z, distance=5): + """ + Offset a curve. + + Args: + x (list): List of x coordinates. + y (list): List of y coordinates. + z (list): List of z coordinates. + distance (int, optional): Distance of offsetting. Defaults to 5. + + Returns: + tuple: Lists of points from the upper curve and the lower curve. + + TODO: + The accuracy can be improved by finding the inner and outer arc: + connect the points of the arc and not calculate their + middle. + """ + lineA = [] + lineB = [] + line0 = [] + line1 = [] + + # Offsetting + for i in range(len(x) - 1): + parallel = offset(distance, (x[i], z[i]), (x[i + 1], z[i + 1])) + lineA.append( + ( + (parallel[0][0][0], y[i], parallel[0][0][1]), + (parallel[0][1][0], y[i + 1], parallel[0][1][1]), + ) + ) + lineB.append( + ( + (parallel[1][0][0], y[i], parallel[1][0][1]), + (parallel[1][1][0], y[i + 1], parallel[1][1][1]), + ) + ) + + # First points + # print(x, y, z, distance) + # print(x, len(x)) + # print("lineA:", lineA) + # print("parallel:", parallel) + line0.append( + ( + round(lineA[0][0][0]), + round(lineA[0][0][1]), + round(lineA[0][0][2]), + ) + ) + line1.append( + ( + round(lineB[0][0][0]), + round(lineB[0][0][1]), + round(lineB[0][0][2]), + ) + ) + + # Middle of between segments + for i in range(len(lineA) - 1): + line0.append( + ( + round((lineA[i][1][0] + lineA[i + 1][0][0]) / 2), + round((lineA[i][1][1] + lineA[i + 1][0][1]) / 2), + round((lineA[i][1][2] + lineA[i + 1][0][2]) / 2), + ) + ) + line1.append( + ( + round((lineB[i][1][0] + lineB[i + 1][0][0]) / 2), + round((lineB[i][1][1] + lineB[i + 1][0][1]) / 2), + round((lineB[i][1][2] + lineB[i + 1][0][2]) / 2), + ) + ) + + # Last points + line0.append( + ( + round(lineA[-1][1][0]), + round(lineA[-1][1][1]), + round(lineA[-1][1][2]), + ) + ) + line1.append( + ( + round(lineB[-1][1][0]), + round(lineB[-1][1][1]), + round(lineB[-1][1][2]), + ) + ) + + return line0, line1 + + +def pixelPerfect(path): + """ + Remove blocks that are side by side in the path. Keep the blocks + that are in diagonal. + + Args: + path (list): List of coordinates from a path. + + Returns: + list: List cleaned. + + TODO: + Add 3D. + """ + # NotPixelPerfect detection + if len(path) == 1 or len(path) == 0: + return path + else: + notPixelPerfect = [] + c = 0 + while c < len(path): + if c > 0 and c + 1 < len(path): + if ( + ( + path[c - 1][0] == path[c][0] + or path[c - 1][1] == path[c][1] + ) + and ( + path[c + 1][0] == path[c][0] + or path[c + 1][1] == path[c][1] + ) + and path[c - 1][1] != path[c + 1][1] + and path[c - 1][0] != path[c + 1][0] + ): + notPixelPerfect.append(path[c]) + c += 1 + + # Double notPixelPerfect detection + if len(notPixelPerfect) == 1 or len(notPixelPerfect) == 0: + return notPixelPerfect + else: + d = 0 + while d < len(notPixelPerfect): + if d + 1 < len(notPixelPerfect): + if ( + notPixelPerfect[d][0] == notPixelPerfect[d + 1][0] + and (notPixelPerfect[d][1] - notPixelPerfect[d + 1][1]) + in {1, -1} + ) or ( + notPixelPerfect[d][1] == notPixelPerfect[d + 1][1] + and (notPixelPerfect[d][0] - notPixelPerfect[d + 1][0]) + in {1, -1} + ): + notPixelPerfect.remove(notPixelPerfect[d + 1]) + d += 1 + + # Remove notPixelPerfect from path + for i in range(len(notPixelPerfect)): + path.remove(notPixelPerfect[i]) + + return path + + +def cleanLine(path): # HERE + """ + Clean and smooth a list of blocks. Works in 2d but supports 3d. + + Args: + path (list): List of blocks. + + Returns: + list: List cleaned. + + TODO: + Do not work perfectly since 16/04/2021. + Add new patterns. + Problem with i -= 10 : solved but not understand why. + 16/04/2021. + """ + + pathTemp = [] + for i in path: + if i not in pathTemp: + pathTemp.append(i) + path = pathTemp + + i = 0 + + while i < len(path): + + # 2 blocks, 90 degrees, 2 blocks = 1 block, 1 block, 1 block + if i + 3 < len(path): + if ( + path[i][0] == path[i + 1][0] + and path[i + 2][-1] == path[i + 3][-1] + ): + if len(path[i + 1]) == 3: + path.insert( + (i + 1), + (path[i + 2][0], path[i + 2][1], path[i + 1][-1]), + ) + else: + path.insert((i + 1), (path[i + 2][0], path[i + 1][-1])) + del path[i + 2] # 2nd block + del path[i + 2] # 3rd block + i -= 1 + continue + elif ( + path[i][-1] == path[i + 1][-1] + and path[i + 2][0] == path[i + 3][0] + ): + if len(path[i + 1]) == 3: + path.insert( + (i + 1), + (path[i + 1][0], path[i + 1][1], path[i + 2][-1]), + ) + else: + path.insert( + (i + 1), + (path[i + 1][0], path[i + 2][-1]), + ) + del path[i + 2] # 2nd block + del path[i + 2] # 3rd block + i -= 1 + continue + + # 1 block, 3 blocks, 1 block = 1 block, 2 blocks, 2 blocks + if i - 1 >= 0 and i + 5 <= len(path): + if ( + ( + path[i + 1][-1] == path[i + 2][-1] + and path[i + 2][-1] == path[i + 3][-1] + ) + and ( + path[i + 1][-1] != path[i][-1] + and path[i + 3][-1] != path[i + 4][-1] + ) + and ( + path[i - 1][-1] != path[i][-1] + and path[i + 4][-1] != path[i + 5][-1] + ) + ): + if len(path[i]) == 3: + path.insert( + (i + 1), (path[i + 1][0], path[i + 1][1], path[i][-1]) + ) + else: + path.insert((i + 1), (path[i + 1][0], path[i][-1])) + del path[i + 2] # 2nd block + i -= 1 + continue + elif ( + ( + path[i + 1][0] == path[i + 2][0] + and path[i + 2][0] == path[i + 3][0] + ) + and ( + path[i + 1][0] != path[i][0] + and path[i + 3][0] != path[i + 4][0] + ) + and ( + path[i - 1][0] != path[i][0] + and path[i + 4][0] != path[i + 5][0] + ) + ): + if len(path[i]) == 3: + path.insert( + (i + 1), (path[i][0], path[i][1], path[i + 1][-1]) + ) + else: + path.insert((i + 1), (path[i][0], path[i + 1][-1])) + del path[i + 2] # 2nd block + i -= 1 + continue + + i += 1 + + return path + + +def distance2D(A, B): # TODO : Can be better. + return sqrt((B[0] - A[0]) ** 2 + (B[1] - A[1]) ** 2) + + +def curveSurface( + points, + distance, + resolution=7, + pixelPerfect=False, + factor=2, + start=0, + returnLine=True, +): # HERE + """ + Create a curve with a thickness. + + Args: + points (numpy.ndarray): Points where the curve should go. + distance (int): Thickness. + resolution (int, optional): Number of blocks that separate each + point to calculate parallel curves. 0 to use the points + calculated to create the curve. Defaults to 7. + pixelPerfect (bool, optional): True to avoid heaps. Defaults to + False. + factor (int, optional): Number of sub-line that will be + calculated to avoid hole with coordinates. Defaults to 2. + + Returns: + dict: Key 0 is the list of coordinates of the center line. + Positive keys are lists of coordinates of lines on the right + side, negative keys are for the left side. + + >>> curveSurface( + np.array( + [ + [12, 248, -103], + [-5, 219, -85], + [-22, 205, -128], + [-51, 70, -240], + [40, 198, -166], + [19, 241, -102], + [-6, 62, -223], + ] + ), + 5, + resolution=7, + ) + """ + if len((points)) >= 3: + # Calculate resolution of the main curve depending of the total curve length. + lenCurve = 0 + for i in range(len(points) - 1): + lenCurve += sqrt( + ((points[i][0] - points[i + 1][0]) ** 2) + + ((points[i][1] - points[i + 1][1]) ** 2) + + ((points[i][2] - points[i + 1][2]) ** 2) + ) + number_true_pts = round(lenCurve / 6) + + # Calculate the main line. + X, Y, Z = curve(points, number_true_pts) + if len(X) < 2: + X, Y, Z = ( + (points[0][0], points[1][0]), + (points[0][1], points[1][1]), + (points[0][2], points[1][2]), + ) + else: + X, Y, Z = ( + (points[0][0], points[1][0]), + (points[0][1], points[1][1]), + (points[0][2], points[1][2]), + ) + + centerLineTemp = [] + for i in range(len(X) - 1): + xyz0 = X[i], Y[i], Z[i] + xyz1 = (X[i + 1], Y[i + 1], Z[i + 1]) + centerLineTemp.extend(line(xyz0, xyz1)) + + if not returnLine: + returnPoints = [] + for i in range(len(X)): + returnPoints.append((round(X[i]), round(Y[i]), round(Z[i]))) + + # Clean the main line. + # centerLine = cleanLine(centerLineTemp) + centerLine = centerLineTemp + + # Offset. + centerPoints = [] + + if resolution != 0: + for i in range(0, len(centerLine), resolution): + centerPoints.append(centerLine[i]) + else: + for i in range(len(X)): + centerPoints.append((X[i], Y[i], Z[i])) + + X = [centerPoints[i][0] for i in range(len(centerPoints))] + Y = [centerPoints[i][1] for i in range(len(centerPoints))] + Z = [centerPoints[i][2] for i in range(len(centerPoints))] + + rightPoints = [] + leftPoints = [] + + # print(centerLine, "XYZ centerPoint to offset") + # print(cleanLine(centerLineTemp), "with cleanLine") + for i in range(start * factor, distance * factor): + rightPoint, leftPoint = curveOffset(X, Y, Z, i / factor) + rightPoints.append(rightPoint) + leftPoints.append(leftPoint) + + rightLine = [] + leftLine = [] + rightSide = [] + leftSide = [] + + if returnLine == True: # Creating lines on each side between each point. + for i in range(len(rightPoints)): + for j in range(len(rightPoints[i]) - 1): + rightLine.extend( + line( + rightPoints[i][j], + rightPoints[i][j + 1], + pixelPerfect, + ) + ) + rightSide.append(rightLine) + rightLine = [] + + for i in range(len(leftPoints)): + for j in range(len(leftPoints[i]) - 1): + leftLine.extend( + line( + leftPoints[i][j], + leftPoints[i][j + 1], + pixelPerfect, + ) + ) + leftSide.append(leftLine) + leftLine = [] + + else: # Do not create lines. Points instead. + for i in range(len(rightPoints)): + for j in range(len(rightPoints[i])): + rightLine.append(rightPoints[i][j]) + rightSide.append(rightLine) + rightLine = [] + + for i in range(len(leftPoints)): + for j in range(len(leftPoints[i])): + leftLine.append(leftPoints[i][j]) + leftSide.append(leftLine) + leftLine = [] + + # Returns. 0 is the center line, positive values ​​are lines on the + # right, negative values ​​are lines on the left. + smoothCurveSurfaceDict = {} + if returnLine: + smoothCurveSurfaceDict[0] = centerLine + else: + smoothCurveSurfaceDict[0] = returnPoints + + countLine = 0 + for l in rightSide: + # l = cleanLine(l) + countLine += 1 + smoothCurveSurfaceDict[countLine] = l + countLine = 0 + for l in leftSide: + # l = cleanLine(l) + countLine -= 1 + smoothCurveSurfaceDict[countLine] = l + + return smoothCurveSurfaceDict + + +def getAngle(xy0, xy1, xy2): + """ + Compute angle (in degrees) for xy0, xy1, xy2 corner. + + https://stackoverflow.com/questions/13226038/calculating-angle-between-two-vectors-in-python + + Args: + xy0 (numpy.ndarray): Points in the form of [x,y]. + xy1 (numpy.ndarray): Points in the form of [x,y]. + xy2 (numpy.ndarray): Points in the form of [x,y]. + + Returns: + float: Angle negative for counterclockwise angle, angle positive + for counterclockwise angle. + """ + if xy2 is None: + xy2 = xy1 + np.array([1, 0]) + v0 = np.array(xy0) - np.array(xy1) + v1 = np.array(xy2) - np.array(xy1) + + angle = np.math.atan2(np.linalg.det([v0, v1]), np.dot(v0, v1)) + return np.degrees(angle) + + +def lineIntersection(line0, line1, fullLine=True): + """ + Find (or not) intersection between two lines. Works in 2d but + supports 3d. + + https://stackoverflow.com/questions/20677795/how-do-i-compute-the-intersection-point-of-two-lines + + Args: + line0 (tuple): Tuple of tuple of coordinates. + line1 (tuple): Tuple of tuple of coordinates. + fullLine (bool, optional): True to find intersections along + full line - not just in the segment. + + Returns: + tuple: Coordinates (2d). + + >>> lineIntersection(((0, 0), (0, 5)), ((2.5, 2.5), (-2.5, 2.5))) + """ + xdiff = (line0[0][0] - line0[1][0], line1[0][0] - line1[1][0]) + ydiff = (line0[0][-1] - line0[1][-1], line1[0][-1] - line1[1][-1]) + + def det(a, b): + return a[0] * b[-1] - a[-1] * b[0] + + div = det(xdiff, ydiff) + if div == 0: + return None + + d = (det(*line0), det(*line1)) + x = det(d, xdiff) / div + y = det(d, ydiff) / div + + if not fullLine: + if ( + min(line0[0][0], line0[1][0]) <= x <= max(line0[0][0], line0[1][0]) + and min(line1[0][0], line1[1][0]) + <= x + <= max(line1[0][0], line1[1][0]) + and min(line0[0][-1], line0[1][-1]) + <= y + <= max(line0[0][-1], line0[1][-1]) + and min(line1[0][-1], line1[1][-1]) + <= y + <= max(line1[0][-1], line1[1][-1]) + ): + return x, y + else: + return None + else: + return x, y + + +def circleLineSegmentIntersection( + circleCenter, circleRadius, xy0, xy1, fullLine=True, tangentTol=1e-9 +): + """ + Find the points at which a circle intersects a line-segment. This + can happen at 0, 1, or 2 points. Works in 2d but supports 3d. + + https://stackoverflow.com/questions/30844482/what-is-most-efficient-way-to-find-the-intersection-of-a-line-and-a-circle-in-py + Note: We follow: http://mathworld.wolfram.com/Circle-LineIntersection.html + + Args: + circleCenter (tuple): The (x, y) location of the circle center. + circleRadius (int): The radius of the circle. + xy0 (tuple): The (x, y) location of the first point of the + segment. + xy1 ([tuple]): The (x, y) location of the second point of the + segment. + fullLine (bool, optional): True to find intersections along + full line - not just in the segment. False will just return + intersections within the segment. Defaults to True. + tangentTol (float, optional): Numerical tolerance at which we + decide the intersections are close enough to consider it a + tangent. Defaults to 1e-9. + + Returns: + list: A list of length 0, 1, or 2, where each element is a point + at which the circle intercepts a line segment (2d). + """ + + (p1x, p1y), (p2x, p2y), (cx, cy) = ( + (xy0[0], xy0[-1]), + (xy1[0], xy1[-1]), + (circleCenter[0], circleCenter[1]), + ) + (x1, y1), (x2, y2) = (p1x - cx, p1y - cy), (p2x - cx, p2y - cy) + dx, dy = (x2 - x1), (y2 - y1) + dr = (dx ** 2 + dy ** 2) ** 0.5 + big_d = x1 * y2 - x2 * y1 + discriminant = circleRadius ** 2 * dr ** 2 - big_d ** 2 + + if discriminant < 0: # No intersection between circle and line + return [] + else: # There may be 0, 1, or 2 intersections with the segment + intersections = [ + ( + cx + + ( + big_d * dy + + sign * (-1 if dy < 0 else 1) * dx * discriminant ** 0.5 + ) + / dr ** 2, + cy + + (-big_d * dx + sign * abs(dy) * discriminant ** 0.5) + / dr ** 2, + ) + for sign in ((1, -1) if dy < 0 else (-1, 1)) + ] # This makes sure the order along the segment is correct + if ( + not fullLine + ): # If only considering the segment, filter out intersections that do not fall within the segment + fraction_along_segment = [ + (xi - p1x) / dx if abs(dx) > abs(dy) else (yi - p1y) / dy + for xi, yi in intersections + ] + intersections = [ + pt + for pt, frac in zip(intersections, fraction_along_segment) + if 0 <= frac <= 1 + ] + if ( + len(intersections) == 2 and abs(discriminant) <= tangentTol + ): # If line is tangent to circle, return just one point (as both intersections have same location) + return [intersections[0]] + else: + return intersections + + +def circle(xyC, r): + """ + Can be used for circle or disc. + + Args: + xyC (tuple): Coordinates of the center. + r (int): Radius of the circle. + + Returns: + dict: Keys are distance from the circle. Value is a list of all + coordinates at this distance. 0 for a circle. Negative values + for a disc, positive values for a hole. + """ + area = ( + (round(xyC[0]) - round(r), round(xyC[1]) - round(r)), + (round(xyC[0]) + round(r) + 1, round(xyC[1]) + round(r) + 1), + ) + + circle = {} + for x in range(area[0][0], area[1][0]): + for y in range(area[0][1], area[1][1]): + d = round(distance2D((x, y), (xyC))) - r + if circle.get(d) == None: + circle[d] = [] + circle[d].append((x, y)) + return circle + + +def circleIntersections(xy0, r0, xy1, r1): + # https://stackoverflow.com/questions/55816902/finding-the-intersection-of-two-circles + + x0, y0 = xy0 + x1, y1 = xy1 + d = sqrt((x1 - x0) ** 2 + (y1 - y0) ** 2) + + # Non intersecting. + if d > r0 + r1: + return None + # One circle within other. + if d < abs(r0 - r1): + return None + # Coincident circles. + if d == 0 and r0 == r1: + return None + else: + a = (r0 ** 2 - r1 ** 2 + d ** 2) / (2 * d) + h = sqrt(r0 ** 2 - a ** 2) + x2 = x0 + a * (x1 - x0) / d + y2 = y0 + a * (y1 - y0) / d + x3 = x2 + h * (y1 - y0) / d + y3 = y2 - h * (x1 - x0) / d + + x4 = x2 - h * (y1 - y0) / d + y4 = y2 + h * (x1 - x0) / d + + return ((x3, y3), (x4, y4)) + + +def InTriangle(point, xy0, xy1, xy2): + # https://stackoverflow.com/questions/2049582/how-to-determine-if-a-point-is-in-a-2d-triangle#:~:text=A%20simple%20way%20is%20to,point%20is%20inside%20the%20triangle. + dX = point[0] - xy0[0] + dY = point[1] - xy0[1] + dX20 = xy2[0] - xy0[0] + dY20 = xy2[1] - xy0[1] + dX10 = xy1[0] - xy0[0] + dY10 = xy1[1] - xy0[1] + + s_p = (dY20 * dX) - (dX20 * dY) + t_p = (dX10 * dY) - (dY10 * dX) + D = (dX10 * dY20) - (dY10 * dX20) + + if D > 0: + return (s_p >= 0) and (t_p >= 0) and (s_p + t_p) <= D + else: + return (s_p <= 0) and (t_p <= 0) and (s_p + t_p) >= D + + +def circlePoints(xyC, r, n=100): + # https://stackoverflow.com/questions/8487893/generate-all-the-points-on-the-circumference-of-a-circle + points = [ + (cos(2 * pi / n * x) * r, sin(2 * pi / n * x) * r) + for x in range(0, n + 1) + ] + + for i in range(len(points)): + points[i] = ( + points[i][0] + xyC[0], + points[i][1] + xyC[1], + ) + + return points + + +def optimizedPath(coords, start=None): + # https://stackoverflow.com/questions/45829155/sort-points-in-order-to-have-a-continuous-curve-using-python + if start is None: + start = coords[0] + pass_by = coords + path = [start] + pass_by.remove(start) + while pass_by: + nearest = min(pass_by, key=lambda x: distance2D(path[-1], x)) + path.append(nearest) + pass_by.remove(nearest) + return path + + +def nearest(points, start): + return min(points, key=lambda x: distance2D(start, x)) + + +def sortRotation(points): + """ + Sort point in a rotation order. Works in 2d but supports 3d. + + https://stackoverflow.com/questions/58377015/counterclockwise-sorting-of-x-y-data + + Args: + points: List of points to sort in the form of [(x, y, z), (x, y, + z)] or [(x, y), (x, y), (x, y), (x, y)]... + + Returns: + list: List of tuples of coordinates sorted (2d or 3d). + + >>> sortRotation([(0, 45, 100), (4, -5, 5),(-5, 36, -2)]) + [(0, 45, 100), (-5, 36, -2), (4, -5, 5)] + """ + x, y = [], [] + for i in range(len(points)): + x.append(points[i][0]) + y.append(points[i][-1]) + x, y = np.array(x), np.array(y) + + x0 = np.mean(x) + y0 = np.mean(y) + + r = np.sqrt((x - x0) ** 2 + (y - y0) ** 2) + + angles = np.where( + (y - y0) > 0, + np.arccos((x - x0) / r), + 2 * np.pi - np.arccos((x - x0) / r), + ) + + mask = np.argsort(angles) + + x_sorted = list(x[mask]) + y_sorted = list(y[mask]) + + # Rearrange tuples to get the right coordinates. + sortedPoints = [] + for i in range(len(points)): + j = 0 + while (x_sorted[i] != points[j][0]) and (y_sorted[i] != points[j][-1]): + j += 1 + else: + if len(points[0]) == 3: + sortedPoints.append((x_sorted[i], points[j][1], y_sorted[i])) + else: + sortedPoints.append((x_sorted[i], y_sorted[i])) + + return sortedPoints + + +def curveCornerIntersectionPoints( + line0, line1, startDistance, angleAdaptation=False +): + """ + Create points between the two lines to smooth the intersection. + + Args: + line0 (tuple): Tuple of tuple. Line coordinates. Order matters. + line1 (tuple): Tuple of tuple. Line coordinates. Order matters. + startDistance (int): distance from the intersection where the + curve should starts. + angleAdaptation (bool, optional): True will adapt the + startDistance depending of the angle between the two lines. + False will force the distance to be startDistance. Defaults to + False. + + Returns: + [list]: List of tuple of coordinates (2d) that forms the curve. + Starts on the line and end on the other line. + + >>> curveCornerIntersectionPoints(((0, 0), (50, 20)), ((-5, 50), (25, -5)), 10) + """ + intersection = lineIntersection(line0, line1, fullLine=True) + + if intersection == None: + return None + + # Define automatically the distance from the intersection, where the curve + # starts. + if angleAdaptation: + angle = getAngle( + (line0[0][0], line0[0][-1]), + intersection, + (line1[0][0], line1[0][-1]), + ) + # Set here the radius of the circle for a square angle. + startDistance = startDistance * abs(1 / (angle / 90)) + + startCurvePoint = circleLineSegmentIntersection( + intersection, startDistance, line0[0], intersection, fullLine=True + )[0] + endCurvePoint = circleLineSegmentIntersection( + intersection, startDistance, line1[0], intersection, fullLine=True + )[0] + # Higher value for better precision + perpendicular0 = perpendicular(10e3, startCurvePoint, intersection)[0] + perpendicular1 = perpendicular(10e3, endCurvePoint, intersection)[1] + + center = lineIntersection( + (perpendicular0, startCurvePoint), (perpendicular1, endCurvePoint) + ) + + # Distance with startCurvePoint and endCurvePoint from the center are the + # same. + radius = distance2D(startCurvePoint, center) + + circle = circlePoints( + center, round(radius), 32 + ) # n=round((2 * pi * radius) / 32) + + # Find the correct point on the circle. + curveCornerPointsTemp = [startCurvePoint] + for point in circle: + if InTriangle(point, intersection, startCurvePoint, endCurvePoint): + curveCornerPointsTemp.append(point) + curveCornerPointsTemp.append(endCurvePoint) + + # Be sure that all the points are in correct order. + curveCornerPoints = optimizedPath(curveCornerPointsTemp, startCurvePoint) + return curveCornerPoints + + +def curveCornerIntersectionLine( + line0, line1, startDistance, angleAdaptation=False, center=() +): + """ + Create a continuous circular line between the two lines to smooth + the intersection. + + Args: + line0 (tuple): Tuple of tuple. Line coordinates. Order matters. + line1 (tuple): Tuple of tuple. Line coordinates. Order matters. + startDistance (int): distance from the intersection where the + curve should starts. + angleAdaptation (bool, optional): True will adapt the + startDistance depending of the angle between the two lines. + False will force the distance to be startDistance. Defaults to + False. + + Returns: + [list]: List of tuple of coordinates (2d) that forms the curve. + Starts on the line and end on the other line. + + TODO: + angleAdaptation : Set circle radius and not startDistance. + Polar coordinates / Unit circle instead of InTriangle. + + >>> curveCornerIntersectionLine(((0, 0), (50, 20)), ((-5, 50), (25, -5)), 10) + """ + intersection = lineIntersection(line0, line1, fullLine=True) + + if intersection == None: + return None + + # Define automatically the distance from the intersection, where the curve + # starts. + if angleAdaptation: + angle = getAngle( + (line0[0][0], line0[0][-1]), + intersection, + (line1[0][0], line1[0][-1]), + ) + # Set here the radius of the circle for a square angle. + startDistance = startDistance * abs(1 / (angle / 90)) + + startCurvePoint = circleLineSegmentIntersection( + intersection, startDistance, line0[0], intersection, fullLine=True + )[0] + endCurvePoint = circleLineSegmentIntersection( + intersection, startDistance, line1[0], intersection, fullLine=True + )[0] + # Higher value for better precision + perpendicular0 = perpendicular(10e3, startCurvePoint, intersection)[0] + perpendicular1 = perpendicular(10e3, endCurvePoint, intersection)[1] + + if center == (): + center = lineIntersection( + (perpendicular0, startCurvePoint), (perpendicular1, endCurvePoint) + ) + + # Distance with startCurvePoint and endCurvePoint from the center + # are almost the same. + radius = distance2D(startCurvePoint, center) + + circleArc = circle(center, round(radius))[0] + + # Find the correct point on the circle. + curveCornerPointsTemp = [startCurvePoint] + for point in circleArc: + if InTriangle(point, intersection, startCurvePoint, endCurvePoint): + curveCornerPointsTemp.append(point) + # curveCornerPointsTemp.append(endCurvePoint) + + # Be sure that all the points are in correct order. + curveCornerPoints = optimizedPath(curveCornerPointsTemp, startCurvePoint) + return curveCornerPoints, center + + +def middleLine(xyz0, xyz1): + x = (xyz0[0] + xyz1[0]) / 2 + z = (xyz0[-1] + xyz1[-1]) / 2 + if len(xyz0) <= 2: + return (x, z) + else: + y = (xyz0[1] + xyz1[1]) / 2 + return (round(x), round(y), round(z)) diff --git a/networks/legacy_roads/roads.py b/networks/legacy_roads/roads.py new file mode 100644 index 0000000..e398a34 --- /dev/null +++ b/networks/legacy_roads/roads.py @@ -0,0 +1,662 @@ +import networks.legacy_roads.Skeleton as Skeleton +import networks.legacy_roads.house as house +from math import sqrt +from gdpc import Editor +import sys +from gdpc import Block as place +import numpy as np +import networks.legacy_roads.maths as maths +import math + +import networks.legacy_roads.tools as tools + +import random +from random import randint + +from PIL import Image +from collections import Counter + +alreadyGenerated = [] + + +######################## Lanes materials presets ####################### + + +standard_modern_lane_composition = { + "road_surface": { + "black_concrete": 3, + "coal_block": 1, + "black_concrete_powder": 2, + }, + "median_strip": {"stone": 1}, + "structure": {"stone": 3, "andesite": 1}, + "central_lines": {"yellow_concrete": 3, "yellow_concrete_powder": 1}, + "external_lines": {"white_concrete": 3, "white_concrete_powder": 1}, + "lines": {"white_concrete": 3, "white_concrete_powder": 1}, +} + +# editor.placeBlock((x, y, z), place("minecraft:white_concrete")) + +######################### Additional functions ######################### + + +def cleanLanes(lanes): + cleanLanes = {} + for lane in lanes: + for xyz in lanes[lane]: + if (round(xyz[0]), round(xyz[1]), round(xyz[2]),) not in [ + cleanLanes[i][j] + for __, i in enumerate(cleanLanes) + for j in range(len(cleanLanes[i])) + ]: + if cleanLanes.get(lane) == None: + cleanLanes[lane] = [] + cleanLanes[lane].append( + (round(xyz[0]), round(xyz[1]), round(xyz[2])) + ) + return cleanLanes + + +def findGround(xzStart, xz): # TODO: Change error. + """ + Find the surface at xz using heightmap. + + Args: + xzStart (tuple): Starting coordinates of the heightmap (northwest corner). + xz (tuple): Coordinates xz in the Minecraft world. + + Returns: + tuple: Coordinates xyz in the Minecraft world. + """ + im = Image.open("./world_maker/data/heightmap.png") + x = round(xz[0] - xzStart[0]) + z = round(xz[-1] - xzStart[-1]) + # Alpha is defined as the height ([3]). + width, height = im.size + if x >= width or z >= height: + print("img:", x, z) + print(width, height) + print(xzStart, xz) + try: + return xz[0], (im.getpixel((x, z))[2]) - 1, xz[-1] + except: + print("Error getpixel in map.py:42 with ", x, z) + return None + + +############################ Lanes functions ########################### + +housesCoordinates = [] + + +def singleLaneLeft(XYZ, blocks=standard_modern_lane_composition): + """Left side.""" + + factor = 8 + distance = 2 + + roadMarkings = maths.curveSurface( + np.array(XYZ), + distance + 1, + resolution=0, + pixelPerfect=True, + factor=1, + start=2, + ) + roadMarkings = cleanLanes(roadMarkings) + + roadSurface = maths.curveSurface( + np.array(XYZ), + distance, + resolution=0, + pixelPerfect=False, + factor=factor, + ) + roadSurface = cleanLanes(roadSurface) + + walkway = maths.curveSurface( + np.array(XYZ), + distance + 3, + resolution=0, + pixelPerfect=False, + factor=4, + start=3, + ) + walkway = cleanLanes(walkway) + + houses = maths.curveSurface( + np.array(XYZ), + distance + 14, + resolution=0, + pixelPerfect=False, + factor=1, + start=distance + 13, + ) + houses = cleanLanes(houses) + + road_surface = blocks.get("road_surface") + structure = blocks.get("structure") + + for lane in roadSurface: + for xyz in roadSurface[lane]: + tools.fillBlock( + "air", (xyz[0], xyz[1], xyz[2], xyz[0], xyz[1] + 4, xyz[2]) + ) + tools.setBlock( + random.choices( + list(structure.keys()), + weights=structure.values(), + k=1, + )[0], + (xyz[0], xyz[1] - 1, xyz[2]), + ) + tools.setBlock( + random.choices( + list(road_surface.keys()), + weights=road_surface.values(), + k=1, + )[0], + xyz, + ) + alreadyGenerated.append((xyz[0], xyz[2])) + + lines = blocks.get("lines") + for lane in roadMarkings: + for xyz in roadMarkings[lane]: + if lane == -1: + tools.setBlock( + random.choices( + list(structure.keys()), + weights=structure.values(), + k=1, + )[0], + (xyz[0], xyz[1] - 1, xyz[2]), + ) + tools.setBlock( + random.choices( + list(lines.keys()), + weights=lines.values(), + k=1, + )[0], + (xyz[0], xyz[1], xyz[2]), + ) + + for lane in walkway: + for xyz in walkway[lane]: + if lane <= -1: + counterSegments = 0 + tools.fillBlock( + "air", + (xyz[0], xyz[1] + 1, xyz[2], xyz[0], xyz[1] + 4, xyz[2]), + ) + tools.fillBlock( + random.choices( + list(structure.keys()), + weights=structure.values(), + k=1, + )[0], + (xyz[0], xyz[1] + 1, xyz[2], xyz[0], xyz[1] - 1, xyz[2]), + ) + alreadyGenerated.append((xyz[0], xyz[2])) + + counterSegments = 0 + for lane in houses: + for xyz in houses[lane]: + if lane <= -1: + counterSegments += 1 + if counterSegments % 10 == 0: + housesCoordinates.append((xyz[0], xyz[1], xyz[2])) + + +def singleLaneRight(XYZ, blocks=standard_modern_lane_composition): + """Right side.""" + + factor = 8 + distance = 2 + + roadMarkings = maths.curveSurface( + np.array(XYZ), + distance + 1, + resolution=0, + pixelPerfect=True, + factor=1, + start=2, + ) + roadMarkings = cleanLanes(roadMarkings) + + roadSurface = maths.curveSurface( + np.array(XYZ), + distance, + resolution=0, + pixelPerfect=False, + factor=factor, + ) + roadSurface = cleanLanes(roadSurface) + + walkway = maths.curveSurface( + np.array(XYZ), + distance + 3, + resolution=0, + pixelPerfect=False, + factor=4, + start=3, + ) + walkway = cleanLanes(walkway) + + houses = maths.curveSurface( + np.array(XYZ), + distance + 14, + resolution=0, + pixelPerfect=False, + factor=1, + start=distance + 13, + ) + houses = cleanLanes(houses) + + road_surface = blocks.get("road_surface") + structure = blocks.get("structure") + central_lines = blocks.get("central_lines") + + for lane in roadSurface: + for xyz in roadSurface[lane]: + tools.fillBlock( + "air", (xyz[0], xyz[1], xyz[2], xyz[0], xyz[1] + 4, xyz[2]) + ) + tools.setBlock( + random.choices( + list(structure.keys()), + weights=structure.values(), + k=1, + )[0], + (xyz[0], xyz[1] - 1, xyz[2]), + ) + tools.setBlock( + random.choices( + list(road_surface.keys()), + weights=road_surface.values(), + k=1, + )[0], + xyz, + ) + alreadyGenerated.append((xyz[0], xyz[2])) + + lines = blocks.get("lines") + counterSegments = 0 + for lane in roadMarkings: + for xyz in roadMarkings[lane]: + if lane == 1: + tools.setBlock( + random.choices( + list(structure.keys()), + weights=structure.values(), + k=1, + )[0], + (xyz[0], xyz[1] - 1, xyz[2]), + ) + tools.setBlock( + random.choices( + list(lines.keys()), + weights=lines.values(), + k=1, + )[0], + (xyz[0], xyz[1], xyz[2]), + ) + + if lane == -1: # Central Lane. + counterSegments += 1 + if counterSegments % 4 != 0: + tools.setBlock( + random.choices( + list(structure.keys()), + weights=structure.values(), + k=1, + )[0], + (xyz[0], xyz[1] - 1, xyz[2]), + ) + tools.setBlock( + random.choices( + list(central_lines.keys()), + weights=central_lines.values(), + k=1, + )[0], + (xyz[0], xyz[1], xyz[2]), + ) + else: + tools.setBlock( + random.choices( + list(structure.keys()), + weights=structure.values(), + k=1, + )[0], + (xyz[0], xyz[1] - 1, xyz[2]), + ) + tools.setBlock( + random.choices( + list(road_surface.keys()), + weights=road_surface.values(), + k=1, + )[0], + (xyz[0], xyz[1], xyz[2]), + ) + + for lane in walkway: + for xyz in walkway[lane]: + if lane >= 1: + tools.fillBlock( + "air", + (xyz[0], xyz[1] + 1, xyz[2], xyz[0], xyz[1] + 4, xyz[2]), + ) + tools.fillBlock( + random.choices( + list(structure.keys()), + weights=structure.values(), + k=1, + )[0], + (xyz[0], xyz[1] + 1, xyz[2], xyz[0], xyz[1] - 1, xyz[2]), + ) + alreadyGenerated.append((xyz[0], xyz[2])) + + counterSegments = 0 + for lane in houses: + for xyz in houses[lane]: + if lane >= 1: + counterSegments += 1 + if counterSegments % 10 == 0: + housesCoordinates.append((xyz[0], xyz[1], xyz[2])) + + +############################ Roads Generator ########################### + + +class RoadCurve: + def __init__(self, roadData, XYZ): + print("road, first input:", XYZ) + """Create points that forms the lanes depending of the roadData.""" + self.roadData = roadData + self.XYZ = XYZ + + # Find the offset, where the lanes is. + self.lanesXYZ = {} + for __, i in enumerate(self.roadData["lanes"]): + laneCenterDistance = self.roadData["lanes"][i]["centerDistance"] + self.lanesXYZ[i] = maths.curveSurface( + np.array(XYZ), + abs(laneCenterDistance), + resolution=0, + pixelPerfect=True, + factor=1, + start=abs(laneCenterDistance) - 1, + returnLine=False, + ) + # We only take the desired side. + if laneCenterDistance == 0: + self.lanesXYZ[i] = self.lanesXYZ[i][0] + if laneCenterDistance > 0: + self.lanesXYZ[i] = self.lanesXYZ[i][1] + if laneCenterDistance < 0: + self.lanesXYZ[i] = self.lanesXYZ[i][-1] + + def setLanes(self, lanes=[]): + """Generate the lanes depending of the function name.""" + for __, i in enumerate(self.roadData["lanes"]): + if i in lanes or lanes == []: + self.roadData["lanes"][i]["type"](np.array(self.lanesXYZ[i])) + + def getLanes(self, lanes=[]): + """Return the points that forms the lanes.""" + lanesDict = {} + for __, i in enumerate(self.roadData["lanes"]): + if i in lanes or lanes == []: + lanesDict[i] = self.lanesXYZ[i] + return lanesDict + + +############################# Lanes Preset ############################# + + +standard_modern_lane_agencement = { + "lanes": { + -1: {"type": singleLaneLeft, "centerDistance": -3}, + 1: {"type": singleLaneRight, "centerDistance": 3}, + }, +} + + +standard_modern_lanes_agencement = { + "mainRoads": { + 0: { + "lanes": { + -1: {"type": singleLaneLeft, "centerDistance": -5}, + 0: {"type": singleLaneLeft, "centerDistance": 0}, + 1: {"type": singleLaneRight, "centerDistance": 5}, + } + }, + 1: { + "lanes": { + -1: {"type": singleLaneRight, "centerDistance": -5}, + 0: {"type": singleLaneRight, "centerDistance": 0}, + 1: {"type": singleLaneRight, "centerDistance": 5}, + } + }, + }, + "sideRoads": { + 0: { + "lanes": { + -1: {"type": singleLaneLeft, "centerDistance": -5}, + 1: {"type": singleLaneLeft, "centerDistance": 0}, + 2: {"type": singleLaneLeft, "centerDistance": 5}, + } + }, + 1: { + "lanes": { + -1: {"type": singleLaneLeft, "centerDistance": -5}, + 1: {"type": singleLaneLeft, "centerDistance": 0}, + 2: {"type": singleLaneLeft, "centerDistance": 5}, + } + }, + }, +} + + +###### + + +sys.path.append("Terraformer/mapAnalysis/") + + +def get_distance(point1, point2): + # Calculate the Euclidean distance between two points + return sqrt((point1[0] - point2[0]) ** 2 + (point1[1] - point2[1]) ** 2 + (point1[2] - point2[2]) ** 2) + + +def simplify_coordinates(coordinates, epsilon): + if len(coordinates) < 3: + return coordinates + + # Find the point with the maximum distance + max_distance = 0 + max_index = 0 + end_index = len(coordinates) - 1 + + for i in range(1, end_index): + distance = get_distance(coordinates[i], coordinates[0]) + if distance > max_distance: + max_distance = distance + max_index = i + + simplified_coordinates = [] + + # If the maximum distance is greater than epsilon, recursively simplify + if max_distance > epsilon: + rec_results1 = simplify_coordinates(coordinates[:max_index+1], epsilon) + rec_results2 = simplify_coordinates(coordinates[max_index:], epsilon) + + # Combine the simplified sub-results + simplified_coordinates.extend(rec_results1[:-1]) + simplified_coordinates.extend(rec_results2) + else: + # The maximum distance is less than epsilon, retain the endpoints + simplified_coordinates.append(coordinates[0]) + simplified_coordinates.append(coordinates[end_index]) + + return simplified_coordinates + + +def irlToMc(coordinates): + + heightmap = Image.open('./world_maker/data/heightmap.png') + + editor = Editor() + buildArea = editor.getBuildArea() + xMin = (editor.getBuildArea().begin).x + yMin = (editor.getBuildArea().begin).y + zMin = (editor.getBuildArea().begin).z + + print(xMin, yMin, zMin) + + coordinates_final = [] + + coordinates_final.append(coordinates[0] + xMin) + coordinates_final.append(heightmap.getpixel( + (coordinates[0], coordinates[2]))[0]) + coordinates_final.append(coordinates[2] + zMin) + + return coordinates_final + + +def setRoads(skeleton): + # Generation + for i in range(len(skeleton.lines)): + for j in range(len(skeleton.lines[i])): + xyz = irlToMc(skeleton.coordinates[skeleton.lines[i][j]]) + skeleton.lines[i][j] = xyz + print(skeleton.lines[i][j]) + + # Simplification + + for i in range(len(skeleton.lines)): + skeleton.lines[i] = simplify_coordinates(skeleton.lines[i], 10) + + for i in range(len(skeleton.lines)): # HERE -------------------------------------- + print(skeleton.lines[i]) + road = RoadCurve(standard_modern_lane_agencement, skeleton.lines[i]) + road.setLanes() + print(road.getLanes(), "LANES ***********") + + rejected = [] + accepted = [] + # print(housesCoordinates) + for i in range(len(housesCoordinates)): + pos = housesCoordinates[i] + # print(pos, "pos0") + editor = Editor() + xMin = (editor.getBuildArea().begin).x + yMin = (editor.getBuildArea().begin).y + zMin = (editor.getBuildArea().begin).z + base = findGround((xMin, zMin), pos) + if base != None: + # print(pos, "pos1") + pos1 = ( + pos[0] - random.randint(3, 6), + base[1], + pos[2] - random.randint(3, 6), + ) + pos2 = ( + pos[0] + random.randint(3, 6), + base[1], + pos[2] + random.randint(3, 6), + ) + pos3 = ( + pos1[0], + base[1], + pos2[2], + ) + pos4 = ( + pos2[0], + base[1], + pos1[2], + ) + # print(pos1, pos2, pos3, pos4, "pos") + xMin = (editor.getBuildArea().begin).x + yMin = (editor.getBuildArea().begin).y + zMin = (editor.getBuildArea().begin).z + Ypos1 = findGround((xMin, zMin), pos1) + Ypos2 = findGround((xMin, zMin), pos2) + Ypos3 = findGround((xMin, zMin), pos3) + Ypos4 = findGround((xMin, zMin), pos4) + + if ( + Ypos1 != None + and Ypos2 != None + and Ypos3 != None + and Ypos4 != None + ): + + pos2 = ( + pos2[0], + max(Ypos1[1], Ypos2[1], base[1], Ypos3[1], Ypos4[1]), + pos2[2], + ) + pos1 = ( + pos1[0], + max(Ypos1[1], Ypos2[1], base[1], Ypos3[1], Ypos4[1]), + pos1[2], + ) + if ( + (pos1[0], pos1[2]) not in alreadyGenerated + and ( + pos2[0], + pos2[2], + ) + not in alreadyGenerated + and (pos1[0], pos2[2]) not in alreadyGenerated + and (pos2[0], pos1[2]) + ): # HERE, remove print and find why house gen on self + + for xi in range( + -5, + (max(pos1[0], pos2[0]) - min(pos1[0], pos2[0])) + 5, + ): + for yi in range( + -5, + (max(pos1[2], pos2[2]) - min(pos1[2], pos2[2])) + + 5, + ): + alreadyGenerated.append( + ( + min(pos1[0], pos2[0]) + xi, + min(pos1[2], pos2[2]) + yi, + ) + ) + + nb_style = randint(0, 3) + door = ["left", "right"] + r2 = random.randint(0, 1) + facing = ["south", "north", "east", "west"] + r3 = random.randint(0, 3) + + xyz1 = (min(pos1[0], pos2[0]), min( + pos1[1], pos2[1]), min(pos1[2], pos2[2])) + xyz2 = (max(pos1[0], pos2[0]), max( + pos1[1], pos2[1]), max(pos1[2], pos2[2])) + + house.house(xyz1, xyz2, door[r2], 10, nb_style, facing[r3]) + accepted.append( + ( + pos1[0], + pos1[2], + pos2[0], + pos2[2], + ) + ) + else: + rejected.append( + ( + pos1[0], + pos1[2], + pos2[0], + pos2[2], + ) + ) + + print("Done") diff --git a/networks/legacy_roads/tools.py b/networks/legacy_roads/tools.py new file mode 100644 index 0000000..f27f0ba --- /dev/null +++ b/networks/legacy_roads/tools.py @@ -0,0 +1,40 @@ +from gdpc import Block as place +from gdpc import Editor +import networks.legacy_roads.maths as maths + + +USE_BATCHING = True +editor = Editor(buffering=True, caching=True, multithreading=True) + + +def setBlock(block, xyz): + x, y, z = xyz + editor.placeBlock((x, y, z), place(block)) + + +def getBlock(xyz): + print("You used getBlock in a deprecated manner.") + # x, y, z = xyz + # return minecraft.getBlock(x, y, z) + + +def fillBlock(block, xyz): + print("fill", xyz) + xDistance = max(xyz[0], xyz[3]) - min(xyz[0], xyz[3]) + yDistance = max(xyz[1], xyz[4]) - min(xyz[1], xyz[4]) + zDistance = max(xyz[2], xyz[5]) - min(xyz[2], xyz[5]) + + coordinates = [] + + for i in range(min(xyz[0], xyz[3]), max(xyz[0], xyz[3])+1): + for j in range(min(xyz[1], xyz[4]), max(xyz[1], xyz[4])+1): + for k in range(min(xyz[2], xyz[5]), max(xyz[2], xyz[5])+1): + coordinates.append((i, j, k)) + + editor.placeBlock(coordinates, place(block)) + + +def setLine(block, xyz0, xyz1, pixelPerfect=True): + points = maths.line(xyz0, xyz1, pixelPerfect) + for i in points: + setBlock(block, (i[0], i[1], i[2])) diff --git a/world_maker/data/building.png b/world_maker/data/building.png index c3ad1ebc3fecaa55106a51af5f6ab244a9432284..a36ebd6d12b844c43ab7ab45b5842b6c0bb3405a 100644 GIT binary patch literal 509 zcmeAS@N?(olHy`uVBq!ia0vp^CqbBl2}rUnX#@%|9`ST>45^s&_O5qOvxA7k#Un)r zBfZLUmi0}!&nk6JGP>p9TKC)Ao_u6rSn$Q>7u&nne?R~Go*sAp`Zn>HvZty0UhzNJ zw#C&oIs`wluYVt-+2+F&*F>Jt)w;E4k*?OYXzAId8Gmmf`0bXr%dR{F@}FIs5cbb( z*ZC7B+gD_CcWna^TmKx>+rQah?oPN}Yo6w3wNGC>3)SkQRLWxIzqYqoZyc?ZY@S@yavWrY Mr>mdKI;Vst0Ik^8L;wH) literal 344 zcmeAS@N?(olHy`uVBq!ia0y~yVAKU+4kn<;rN)IjfgE{H7srr_Id2a#@&W}9E%@%A j%V)j-$Q%U>3=fVosH-qA?r=;00tyaKS3j3^P6 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 M07*qoM6N<$g2Cth&Hw-a diff --git a/world_maker/data/district.png b/world_maker/data/district.png index e21d7115c56e7200fcb992aa80064009465fb5f2..7552641ebae2638e19aebeca04fe730b447192a0 100644 GIT binary patch literal 1474 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

1Dp(t2PMC|10Ab|D+G!!41{He$}aZ1jMUe@QN} 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 literal 20128 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 FV1l<}FvI`= diff --git a/world_maker/data/highwaymap.png b/world_maker/data/highwaymap.png index 5d713b26bdc5d0fdb02e9372aa4a19369e9f8a21..5b97f9375da2d8593bb61aafbdd898263dcf9f3f 100644 GIT binary patch literal 439 zcmV;o0Z9IdP)^e zR2@sLW>qvOPEJJie3O~fPuaThMuu;Sv>sC&Z3+f=ohW7Ty?Nu(@aav~!BU^W2W$3ljLFykR)%*v1r zkiESVdo=5F8fM7*v0{|4Bs-E7EdCfVcuSNeov(YMEa{4JiLyGu;@ct`x;V-oYr89} ziJ`(x#P6>SS;CTKm3sYN7%2+XO|1F(FKi9qHHH>zZ=wb;z&8MV&7e?~MBSVT(=4CA zUlkJzC4+*MGe{nfM1GIiA^+_ivz%%bP(@xHqo&Zpy6YA;ShpDJaV*QkP|sso+-lBl zxMHLx|%tS~-Y`m8YET4pW3-ArZu4cqXnACEOECVUA2Q2BleCPP4_ hL4Z{upwgg!uU{=Gop3nVO>h7J002ovPDHLkV1ie_!9@T7 literal 843 zcmV-R1GM~!P)D^-V+_F?9AYYZGWZR{~#*=x2JOG^7cA93c9i;*h(dtIBL%sq4sQQkX zLPSJt?qJ6rGy9PW{nCFVcTyjFH}hI4x9ax!IqZgmbcj+THvN9YGn`!fvqam{X|oB0 zp2pCr>j<~p$PZwpv0d|6#cVr5Lz;E7x~OC^Qa)xK$z$D8b0>>+%gmjW#e{A-b$Yg2 zDZ_+rmARu>jFkV#Aa#DBk-TOwdh*?NYO5HG{@%82D;X?x4=fof#Bv79+yhI73bBmA z@-;(+Sju4KnxR7Mz+lyyq3^@IA;WpU!@~-pGcl&NxaW3_3SAewd_*XNxo`H}7NIk- zmci;ZLxorq=cZ?c3NgK?8;3Qr?-gh%GISQUZ0JyZM!CHWGyWxrz5WupwZml71+fNx z415UF@Y-)Ylc(YKo5HP(8mn>A4dFIR{|;hT0C)iac;Ygl7|PeeEMrNx4thJ@42rSv zFN`$}(yhmSW&x}P?vb{1njQc{RHzUm7L+`!vzLGZZk>OK!de+d$ipt=FhaR$fqfEO zTb*>)001hut~;u**N2!ZRgJyRV4s-c_>ST*x47WlEOL{!uf=~w+mdk@53X!KxPuHS)i1XyXT{oeJ20)~FCpZ1lQ*I| zSjyZp(cNp!Tntu+-7*3RxIN3T7Z~2Tf*6)>6@3N(`j-_A0HCxa6wo%C*S)O_1E7~- zR()iMHm(1ndbMC9L~RpW%@mmPQ|hX(toMn>1kn!XA2$-3kcMO>omW`Py1 zN=(5h$p_ZcC84&l0njIR+l=r0e$i!J!ni3huf>o`V&U_LsXXm*XB0b+TuM0~B?=)S zx6iHWOnm6lPgEYsgxXQDof|^B2S`a$H7Y}^*lSWjCl1l2?jzX%6DerKM^{H@@5*Ix zB@4#%N0aEPUM(bk4p9P9((8#BJ2k_5ywbebvG2*2vE)|AalCOe@aUSKzbiJc|PSI6k%g zG1)VW*OLXAm6GhTwvHeeB?a?BvVAJtg1A=oN!Izu8osoSJ}I4kz$>We5|O%nsS$%p zV9^ySS;{08Bl}5Ni-iN3(Q**fJFr}0Ta z%gjK`t6C{&ned8V-Bpn?Q~F^S^|``Of{0STuE_V@QaO<}^T?ZC( zs<2t2HWNwAc@FZ<K^c%%EqOKsb@F7A`h@Et$BcPJg8%im?S=F(subG-#H)=@p$imI8 zGE`9FqD$M=%PQ*6PNFxADnzQI1oR zn0j}L&LP#@wZ)jxWRSFhlDEvSyW}o|8)0ql)koY%J?zv{iK(o z6sH;PiF~!yJ3(`WN#S6R|FATB1IZtcf4*zg0s~Ho)e9S?R$xkwM{BI6p)>95@oefq zTaUj0t9sjIfk$h&C!be0__}-imz$IqE4fK|vyu(|n~xb+DeqQdoe;e-c)frSLI@#* z5JCtcgb+dqA%qY@2qAEGh00000 LNkvXXu0mjfpy=g| literal 1573 zcmbu9`!^E`0LRy@ZdhWs@>b`XM>SJMGDTtD%VTI|BpTVQ)QnK*>S6P4nHg40k(d}! z^0;bOgp@n9Tcntx*UH)T&?4 z2(#s0C%i5Uae5ISOA?sZ^`0+mSF3l})TDnY`M75aR-}oH!K(&~JeNFAfoWVFm(OIp}>ip^xVX7bT9`V8b*0ggI-pNSDva~r%Prx1AFBab?W zM1e)O{UVqpD@D8Ts~YdSX?w#$pZ(rYwR;l=G>kc0HCI({q~u}H$`R=J@W~KG@0q_$ zo+z8d>rxUvBXPVvbg}gdKZyO z_u83z)^+HfM$J_RX>U)s;Rp(OJuo+3`j`;XDL$-uUe2ADirb47CBskt=(_TDSYv3m zVU%%Z9*00ymTO~PN#!OK(fCx~KzE7`EcnQ9e9`OT6MK2f@`(KkLtRg+UxdWsSIZ5=3?MOsU%A7bC! z`MD-!23DFr+rv;Uh1${+>?%n)fe!QE z6Ht^k%@f6iAk`yv`z}yA`^?59vf9rouCtB*xIAF{YLQKMmLEM-B)ikiZ@?>N z;@ZY?+u<#j*#gT?&G^`lU2?4OTgu`S`HmXBK4H5wHL|ju!z1_;!UP8e^u-deWwSuI zYc`S!Vzzl&kfBMC0rFa*=oW>NXJzz18G4^}%xvf!x9N)-EL6nD!|D*nvG9jm~Nk6!^zxNY$RU@7KOqPPa z7{xNeT~;2zxY622iL@XZ%>_2~Xqiyl z*s40|?6C0gOF~OD^RhY*b7ASjYTSYq8QUOaip}XJEo}Gb*mR!;z2(?yqZO-f@*CFc zoe%5?J#B?veSt8=>`Cis6~o5eHZKG@U_zat zy&O4;U);%U{{KcaE9${PXtzer?jZEk1L{gCoyp{&Rm^V)ggt zZ^j=Hw-znZ)gqqQbjPag!1_5?BGU5$FN%rgA`y}|78YLTa6UtdaR|E~^(|rSo5E|j zeMLrh*ES?#hjQkppg)+_A#DG+?~mHPh&|0aU0tI?wt$Fz-|86Bs#Z>yISX>kr>(V7 zRq^u_pP{-JY{19bM|pO2hp*jPR5UYM{{Qt3bz@`~*p$|vw!G~unQ=Oe#re(Y;@oR~ z&#kwbexH9ucXjMvxyjWX=RZNLjC=I?+U}aZpC6TP?Y8;zd1iD-TvDEG#{H9qwaz1P<1@Z zjL97+1ojoN1Ygy;^ruh1U;O^4zo!4JRWT?$cPMvuA;O1m*Z!?ZU+g%(-?)mG9 zK+KSbx$wJ!+|xPdb%9PV&R)Gb|48lCzuI6!!3r$GeUJVZc7ClNZT+0N{1S2)KVS8H z&9QQ9!H$T$Lb2pC`|~&by|B#yIpD!Y$DEV3=>B*jOaBwYyXFT1$o_w-ug>|pSB&AC RA23HSc)I$ztaD0e0svNAjP3vc literal 1571 zcmeAS@N?(olHy`uVBq!ia0y~yVAKU+4kn<;rN)Ij85me!dAc};RLpsM_jcZ6GZBZ2 zJ5K!nzv;Ju!^LGYd-NBXxvu+a;V{Q%&RgZllWKm?IQF;h|F`@3+oS*eSX^&r_C5SB zGlNwN=L>-_b)xZL^0ODNO);=5^|_uQOT$zdz&L52?p&nA@t?=Nwmif)}r_iIYGl;+gx+PNo?yZ^2_xKjo&q|-Wc~#ESDh2g2y$5snWT!iw zw~;wv6LYD9GgA%`w7=W`9RJ-daQe>tXJ=B)Wcj|lDX#zYH#6qD3BT+*=lttW|DweJ zBwjZ6*E8nNODKKwGx8jl#KHF^O6#Qev0P_7JPSFxECi#OZhtzmKKV}R0ke>QxkpYf zt*!a@X61gH@5?J2`6@4da{hE?JLf%lgnLk8{rpc8X5XS?CvEK8gm2a#2M6x+9bYOY z%di(IK0`QcvtRMNi@Vbwzw6fUbzn%J|EE~}v-H`4#^+mq-Z716;am88$CSssR*qll_OGwfw*mR+ zVZqO<%poB5%AALGk{R>@Af9#_8`19`23(miT|d>&pK}uh%YWSPzWZ<4gCP zu>QtTu07{iEAJlrUT!(}wMAe2%hJkvY!| zfB*a2dG*5rwbv%S^W$I6xxP&r=y&V^2o(Ltw*S_wO=U!22WQ%mvv4FO#q%) BDe3?K diff --git a/world_maker/data/skeleton_highway.png b/world_maker/data/skeleton_highway.png index e2d8875f76bbfe7a45cb873ac628eaea8fb3b090..d48cab2854d149413eb2c79404049741ef2e1e26 100644 GIT binary patch literal 10911 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�xAF0*zM_`eRROlm0nW2od>a$CMB`Akdmw<8| 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 BSl9pn literal 19763 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 LNkvXXu0mjfRAk<_ literal 876 zcmeAS@N?(olHy`uVBq!ia0y~yVAKU+4xj)-MMtI)0|T?Mr;B4q#hkZy@8&Hw5NHUD zc>8;Q(YL&-ZTlsXtB+YeU*!=hT`#4PDHI_F)bwE9*NO8#RsCXT`+DS2+Yc<5} zy#rTUgstAi`Rz!wcmC#eKQ@=<``z*h{}EL_{jN&*2iuKlXL+ZIRc~9xw&Y+*>pIb= zM;`7!u{A5%R^GZ`ZNcQNI`!`M4bIm$UhCiY+OskJ^{HJtr#F@TT`c#F=TTNho!y7U z?`vxcBh#~O?__9ZuKilFdFGU@+t^p%jX7_ACL;TetF!R6UtgNG#DBLbJpNGAxu3hU zZEfj>8f@^3=?{JO`sjoG;IC1_M5;2 z*IBsL=v`OZ>LUlDb{`h4e&lv8?2S=%+q=%iabkON-xR*K_4^R9xc}4ZlVJ{v|Euv; oMt<1F(0}3VLq?R4LvYl-@c(HFzM=nOp*l#=)78&qol`;+0L`ndFaQ7m diff --git a/world_maker/data/skeleton_mountain.png b/world_maker/data/skeleton_mountain.png index 6ea1561e1897e65a72222fc3da485662e6bd0385..14f9cb78f9eadf7cc0ab090c0053ae8526bf166e 100644 GIT binary patch literal 10706 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 delta 1362 zcmV-Y1+Dsb_6mQAP)>2ljJ3nmt{xXet;QSra}M!00000i^S_UDf=EW zelB09$3LiXv6U_#p~z2v6L^6w4cO9fw?*TsL$)+rY%zb;>O!_O6l~GBs+6*Yt{PWc zG_D>W*?Q_CTovf@8a{1Ni*3l3hO#XhSD8w-&{ZU}MdNCcXNyTh3%b09n=NXwK{Z>H zVu5-kqU+Ax)~giJb)%3iI#-oaC8DbaGYAbWTQsg5vZbMDi^f%fY-zxj25f1-mIiET zXxd`Jl|g^DG?Z;|ytxe7(onI*Y`(~!&5wW9+dDQ^VoK?>w|8`GO^oy{>Kt9YYz>d} z97Pvuwhn4G3#n#{DOUmJTN>)NsKq;EOGDoljq8mdTj+Yxutnp#(aIK+h#b1ShNi7W zwRlcRlPwJ*TQsf*vTUL2A8lJpI?g$5tCy_>lZbzktdwk~byt^v*(k~iMvJ>=Yp{&E zvTW+wJcFpqGKtidZivsV50fR&)~Z1^YxLXc+L{?u>%JCcNp`wbR?Rz=$Y_g@+%@O)H4{mNEu4At@PeT48;*TH$%$W>l7Dz9pz4;U6?sWr=oNSU=*PWLB1J z&n17la#yix&#o-tu6K21W@6(;!?L9N-qO{YUWp#S4$_^!kG9^X%8!{;zwbL4nV`p@ zcXbBxu^m1+5TO`dU)R~Hf^L8vUB|mp4zZ=nfh+AGE4o~m3Ss^LgBwvH1pR33A4iyB z^oWf|SNd1Td|G-k`g)@AL&k$}{+0%8X~2J$2DL5MZGJdgF55hns6lVbb19Bz%VQ~0 zi5doMIez;O+0rm#%Wt^ImWCl)ZYL2_*>YEkRHBA4TVDG-+0rm*%W1gCmWEMVJ|_{g z+45D2)0OB-*RU;@7qS`8mdDODQHc(9Eto+#Dn;g78fI+yo6wUj4O6z<^?9 zme_LB=E;_ZIa}V^JlWE)#+H}HwJ2LobWPfF*0^S~HDX*6@6`E`yfm%jo*BEB=G8!&a>#WG-C`c38CPPw^h+Y|U3OP>=(k8N1i!oC$H{cC@0y74uv%T{rr!1|JS7G*89RjkU&bSyr9V#?Yw zTlb}yv)_>JKTK=(;Qz7VIWZf4`uKF+#NIUwc3iJI>tN~D(XO&gF+UFAc8Cl!c-lwE$Z6-zUtdHmTU1B&X+e_i!*D0$L#wn!t3Q4V`81=$LFG!rYpPQ8ee%>GI{89 zDRa7p{;HOq;a%I(+$&>G_ICN2R;$m8TW!^)^o#i`S!OHVziz%v-MK9NJK1pF>Enm? zT=ZFcPV?!k>swZz=QQw6VGa9^*qq3MYzdwLPhmwR#@7dtK_HP(5s^>}7=Ul)FC7HV UY=8;%^#A|>07*qoM6N<$f__?~V*mgE diff --git a/world_maker/data/smooth_sobel_watermap.png b/world_maker/data/smooth_sobel_watermap.png index e60ab191522f8923ed5746a92b2deb060c46e347..3ec92a1f24b307c73eab3bcc9f940a6c117075d0 100644 GIT binary patch literal 2003 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 diff --git a/world_maker/data/sobelmap.png b/world_maker/data/sobelmap.png index d755e406721344f12f80fe46b321d53536563ffc..83ff8f6e24d430be02aa89c8f78f056ba4055d28 100644 GIT binary patch literal 14284 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�gBY;(W6)Fbg@XOl|hat?`@+)Tu6 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 AZU6uP literal 813 zcmeAS@N?(olHy`uVBq!ia0y~yVAKU+4mO}j>|?Wc3=B+PJY5_^D(1Ysb2{&lg8=J= ztZsR46&b;atX%s&PaG2R`c!DzJyXrEt)0XF{2XP)7M(w9*10gTExu{b@}SH_aFuR?h1dU=iAU1sYZ>#u3a-rJh&i;P z{!;!9d8r77=>}G21;3_B9@zQUV#}}jr_WT>)^0UnIhVJk{zO?-#DS%zx0}+#S<^H* zVoqCaNZWk#n98qv6V{*o6|B#`{PN5A`}a%ddhz{uq~^3xKEhPx_tiNcm{!gH;aYRO zbm{9|m)5`fGhI-kXZiBwYmWP#c59d&rmEKt?)Vg2mE|p zTr`WgBo>@Zne^M8ku=k&qvjn8#|OAl06(elF{r5}E*G@D=(1 literal 2466 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