Add legacy support
18
main.py
@@ -6,6 +6,7 @@ from world_maker.world_maker import *
|
|||||||
from world_maker.Skeleton import Skeleton, transpose_form_heightmap, simplify_coordinates
|
from world_maker.Skeleton import Skeleton, transpose_form_heightmap, simplify_coordinates
|
||||||
from networks.geometry.Point3D import Point3D
|
from networks.geometry.Point3D import Point3D
|
||||||
from networks.roads_2.Road import Road
|
from networks.roads_2.Road import Road
|
||||||
|
from networks.legacy_roads import roads
|
||||||
from world_maker.District import Road as Road_grid
|
from world_maker.District import Road as Road_grid
|
||||||
from House import *
|
from House import *
|
||||||
|
|
||||||
@@ -17,9 +18,11 @@ def main():
|
|||||||
editor = Editor(buffering=True)
|
editor = Editor(buffering=True)
|
||||||
buildArea = editor.getBuildArea()
|
buildArea = editor.getBuildArea()
|
||||||
|
|
||||||
set_roads(skeleton_mountain)
|
# set_roads(skeleton_mountain)
|
||||||
set_roads(skeleton_highway)
|
# set_roads(skeleton_highway)
|
||||||
set_roads_grids(road_grid)
|
# set_roads_grids(road_grid)
|
||||||
|
roads.setRoads(skeleton_mountain)
|
||||||
|
roads.setRoads(skeleton_highway)
|
||||||
|
|
||||||
blocks = {
|
blocks = {
|
||||||
"wall": "blackstone",
|
"wall": "blackstone",
|
||||||
@@ -39,6 +42,15 @@ def main():
|
|||||||
|
|
||||||
entranceDirection = ["N", "S", "E", "W"]
|
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:
|
for houses in rectangle_house_mountain:
|
||||||
start = (houses[0][0]+buildArea.begin[0], houses[0]
|
start = (houses[0][0]+buildArea.begin[0], houses[0]
|
||||||
[1], houses[0][2]+buildArea.begin[2])
|
[1], houses[0][2]+buildArea.begin[2])
|
||||||
|
|||||||
210
networks/legacy_roads/Skeleton.py
Normal file
@@ -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
|
||||||
2005
networks/legacy_roads/house.py
Normal file
117
networks/legacy_roads/list_block.py
Normal file
@@ -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'
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
1155
networks/legacy_roads/maths.py
Normal file
662
networks/legacy_roads/roads.py
Normal file
@@ -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")
|
||||||
40
networks/legacy_roads/tools.py
Normal file
@@ -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]))
|
||||||
|
Before Width: | Height: | Size: 344 B After Width: | Height: | Size: 509 B |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 843 B After Width: | Height: | Size: 439 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 989 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 824 B |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 876 B After Width: | Height: | Size: 469 B |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 119 B |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 813 B After Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 119 B |