379 lines
13 KiB
Python
379 lines
13 KiB
Python
|
|
# -------------------------------------------------------------------
|
|
# ORTHOGRAPHIC
|
|
# Your personal aerial satellite. Always on. At any altitude.*
|
|
# Developed by MarStrMind
|
|
# License: Open Software License 3.0
|
|
# Up to date version always on marstr.online
|
|
# -------------------------------------------------------------------
|
|
# tileprep.py
|
|
# This prepares a zoom level 18 tile for ortho generation. This class
|
|
# performs the edge detection, selects the required sources for each
|
|
# layer, and stores this information into files which are then used
|
|
# by layergen.
|
|
# -------------------------------------------------------------------
|
|
|
|
import glob
|
|
#from os import MFD_ALLOW_SEALING
|
|
from random import randrange
|
|
from PIL import Image
|
|
from osmxml import *
|
|
from maskgen import *
|
|
from defines import *
|
|
from functions import *
|
|
from log import *
|
|
from tileinfo import *
|
|
|
|
class mstr_tileprep:
|
|
|
|
# For this to work we need some fundamentals.
|
|
def __init__(self, lat, lng, v, h, tag, value, mask, is_completion):
|
|
self._lat = lat
|
|
self._lng = lng
|
|
self._tile_h = h
|
|
self._tile_v = v
|
|
self._tag = tag
|
|
self._value = value
|
|
self._edges = "" # To be filled by _edgeDetect call
|
|
self._source = ""
|
|
self._mask = mask
|
|
latlngfld = xplane_latlng_folder([lat, lng])
|
|
self._tileinfo = mstr_tileinfo(lat, lng, v, h, latlngfld)
|
|
self._already_visited = [] # To be filled later
|
|
self._all_visited = []
|
|
|
|
# Special case for the final step of an ortho
|
|
self._is_completion = is_completion
|
|
|
|
|
|
def _findCorrectTextureFolder(self):
|
|
srcfld = []
|
|
for lyr in mstr_ortho_layers:
|
|
if lyr[0] == self._tag and lyr[1] == self._value:
|
|
srcfld.append(lyr[2])
|
|
srcfld.append(lyr[3])
|
|
break
|
|
return srcfld
|
|
|
|
|
|
# Use the mask to determine the edges
|
|
def _determineEdges(self):
|
|
# Load the mask pixels
|
|
mp = self._mask.load()
|
|
imgsize = self._mask.width
|
|
|
|
# Run scan
|
|
|
|
# Check if pixels touch the borders of the image, and if so -
|
|
# make a not of that in the database.
|
|
at=False
|
|
ar=False
|
|
ab=False
|
|
al=False
|
|
|
|
# Top scan
|
|
for i in range(0, imgsize):
|
|
p = mp[i,0]
|
|
if p[3] > 0:
|
|
at=True
|
|
break
|
|
|
|
# Right scan
|
|
for i in range(0, imgsize):
|
|
p = mp[imgsize-1,i]
|
|
if p[3] > 0:
|
|
ar=True
|
|
break
|
|
|
|
# Bottom scan
|
|
for i in range(0, imgsize):
|
|
p = mp[i,imgsize-1]
|
|
if p[3] > 0:
|
|
ab=True
|
|
break
|
|
|
|
# Left scan
|
|
for i in range(0, imgsize):
|
|
p = mp[0,i]
|
|
if p[3] > 0:
|
|
al=True
|
|
break
|
|
|
|
# Construct adjacency string
|
|
adjstr = ""
|
|
if at==True: adjstr = adjstr + "t"
|
|
if ar==True: adjstr = adjstr + "r"
|
|
if ab==True: adjstr = adjstr + "b"
|
|
if al==True: adjstr = adjstr + "l"
|
|
|
|
# We will now write this down first, without a source being selected
|
|
if adjstr != "":
|
|
self._tileinfo.add_adjacency_data(self._tag, self._value, "0", adjstr)
|
|
|
|
|
|
# Set the latlng folder
|
|
def _setLatLngFold(self, latlngfld):
|
|
self._latlngfld = latlngfld
|
|
|
|
|
|
# Find out if there is already something in place for this tag of this tile
|
|
def _getResourceInfo(self, tv, th):
|
|
# This either remains 0 or a string different to "0" in the end
|
|
src = "0"
|
|
df = mstr_datafolder + "z_orthographic/data/" + self._latlngfld + "/" + str(tv) + "_" + str(th)
|
|
fnlines = []
|
|
if os.path.isfile(df) == True: # It is possible that the requested file does not yet exist
|
|
with open(df) as textfile:
|
|
fnlines = textfile.readlines()
|
|
|
|
for ln in fnlines:
|
|
l = ln.split(" ")
|
|
if l[0] == self._tag and l[1] == self._value:
|
|
src = l[2]
|
|
|
|
return src
|
|
|
|
|
|
# Find the edge touch info
|
|
def _getResourceTouch(self, tv, th):
|
|
touch = ""
|
|
df = mstr_datafolder + "z_orthographic/data/" + self._latlngfld + "/" + str(tv) + "_" + str(th)
|
|
fnlines = []
|
|
if os.path.isfile(df) == True: # It is possible that the requested file does not yet exist
|
|
with open(df) as textfile:
|
|
fnlines = textfile.readlines()
|
|
|
|
for ln in fnlines:
|
|
l = ln.split(" ")
|
|
if l[0] == self._tag and l[1] == self._value:
|
|
l[3] = l[3].replace("\n", "")
|
|
touch = l[3]
|
|
|
|
return touch
|
|
|
|
|
|
# Select a combination of resources
|
|
def _selectResources(self):
|
|
numbers = list(range(1, 16))
|
|
res = random.sample(numbers, 5)
|
|
|
|
# Construct a string of the array
|
|
resstr = ""
|
|
for r in range(len(res)):
|
|
resstr = resstr + str(res[r])
|
|
if r < len(res)-1:
|
|
resstr = resstr + ","
|
|
|
|
return resstr
|
|
|
|
|
|
# Store the required resource information into the appropriate tile
|
|
def _storeResourceInfo(self, tile_v, tile_h, res):
|
|
# Separate file for contrast values
|
|
ctrdata = mstr_datafolder + "z_orthographic/data/" + self._latlngfld + "/ctrdata"
|
|
|
|
df = mstr_datafolder + "z_orthographic/data/" + self._latlngfld + "/" + str(tile_v) + "_" + str(tile_h)
|
|
fnlines = []
|
|
if os.path.isfile(df) == True: # It is possible that the requested file does not yet exist
|
|
with open(df) as textfile:
|
|
fnlines = textfile.readlines()
|
|
curline = 0
|
|
|
|
for ln in fnlines:
|
|
l = ln.split(" ")
|
|
if len(l) > 1:
|
|
if l[0] == self._tag and l[1] == self._value:
|
|
l[2] = res
|
|
|
|
fnlines[curline] = l[0] + " " + l[1] + " " + l[2] + " " + l[3]
|
|
|
|
curline = curline+1
|
|
|
|
lines = ""
|
|
for l in range(len(fnlines)):
|
|
lines = lines + fnlines[l]
|
|
|
|
with open(df, 'w') as textfile:
|
|
textfile.write(lines)
|
|
|
|
# Take care of contrast value
|
|
ctrcontent = []
|
|
if os.path.isfile(ctrdata) == True:
|
|
with open(ctrdata) as textfile:
|
|
ctrcontent = textfile.readlines()
|
|
|
|
# Compare if we already have a data string for this particular resource
|
|
ctrpresent = False
|
|
if len(ctrcontent) > 0:
|
|
for ln in range(0, len(ctrcontent)):
|
|
cnt = ctrcontent[ln].split(" ")
|
|
if cnt[0] == self._tag and cnt[1] == self._value and cnt[2] == res:
|
|
ctrpresent = True
|
|
break
|
|
|
|
# Should there not be a contrast value for this resource, add it
|
|
if ctrpresent == False:
|
|
if (
|
|
(self._tag == "landuse" and self._value == "forest") or
|
|
(self._tag == "landuse" and self._value == "meadow") or
|
|
(self._tag == "landuse" and self._value == "grass") or
|
|
(self._tag == "leisure" and self._value == "nature_reserve") or
|
|
(self._tag == "natural" and self._value == "grassland") or
|
|
(self._tag == "landuse" and self._value == "greenfield") or
|
|
(self._tag == "natural" and self._value == "heath") or
|
|
(self._tag == "natural" and self._value == "wetland") or
|
|
(self._tag == "leisure" and self._value == "park") or
|
|
(self._tag == "building")
|
|
):
|
|
contrast = str(randrange(1, 4))
|
|
newline = self._tag + " " + self._value + " " + res + " " + str(contrast) + "\n"
|
|
|
|
with open(ctrdata, 'a') as textfile:
|
|
textfile.write(newline)
|
|
|
|
|
|
# Find neighborinf tiles
|
|
def _findNeighbors(self, tv, th):
|
|
return [ (tv+1, th), (tv, th+1), (tv-1, th), (tv, th-1) ]
|
|
|
|
|
|
# Scan connections of a specific tile
|
|
def _scanConnections(self, tile):
|
|
# The array of visited tiles
|
|
visited = []
|
|
|
|
# None of the edges have reached their end yet
|
|
edge_end = [0,0,0,0] # top, right, bottom, left
|
|
end_reached = False
|
|
while end_reached == False:
|
|
# Go north
|
|
tv = tile[0]
|
|
th = tile[1]
|
|
|
|
while edge_end[0] == 0:
|
|
owntouch = self._getResourceTouch(tv, th)
|
|
if "t" in owntouch:
|
|
if self._checkVisited(visited, (tv, th)) == False: visited.append((tv, th))
|
|
if self._checkVisited(visited, (tv+1, th)) == False: visited.append((tv+1, th))
|
|
tv=tv+1
|
|
else:
|
|
edge_end[0] = 1
|
|
|
|
# Go east
|
|
tv = tile[0]
|
|
th = tile[1]
|
|
|
|
while edge_end[1] == 0:
|
|
owntouch = self._getResourceTouch(tv, th)
|
|
if "r" in owntouch:
|
|
if self._checkVisited(visited, (tv, th)) == False: visited.append((tv, th))
|
|
if self._checkVisited(visited, (tv, th+1)) == False: visited.append((tv, th+1))
|
|
th=th+1
|
|
else:
|
|
edge_end[1] = 1
|
|
|
|
# Go south
|
|
tv = tile[0]
|
|
th = tile[1]
|
|
|
|
while edge_end[2] == 0:
|
|
owntouch = self._getResourceTouch(tv, th)
|
|
if "b" in owntouch:
|
|
if self._checkVisited(visited, (tv, th)) == False: visited.append((tv, th))
|
|
if self._checkVisited(visited, (tv-1, th)) == False: visited.append((tv-1, th))
|
|
tv=tv-1
|
|
else:
|
|
edge_end[2] = 1
|
|
|
|
# Go west
|
|
tv = tile[0]
|
|
th = tile[1]
|
|
|
|
while edge_end[3] == 0:
|
|
owntouch = self._getResourceTouch(tv, th)
|
|
if "b" in owntouch:
|
|
if self._checkVisited(visited, (tv, th)) == False: visited.append((tv, th))
|
|
if self._checkVisited(visited, (tv, th-1)) == False: visited.append((tv, th-1))
|
|
th=th-1
|
|
else:
|
|
edge_end[3] = 1
|
|
|
|
|
|
if edge_end[0] == 1 and edge_end[1] == 1 and edge_end[2] == 1 and edge_end[3] == 1:
|
|
end_reached = True # <- Break loop
|
|
|
|
return visited
|
|
|
|
|
|
# Let the orthographic class pass all visited tiles for this resource
|
|
def _setAlreadyVisitedTiles(self, tiles):
|
|
self._already_visited = tiles
|
|
|
|
|
|
# Walk through the now existing data files and make sure we always pick the correct
|
|
# sources for every tile, thus evading previous edge detection errors
|
|
def _placeTileSources(self, mlat, mlng):
|
|
|
|
# Check if this tile was already processed
|
|
alr_processed = self._checkAlrVisited((self._tile_v, self._tile_h))
|
|
|
|
# If this is not the case, we can proceed
|
|
if alr_processed == False:
|
|
|
|
# Initial scan "cross"
|
|
visited = self._scanConnections((self._tile_v, self._tile_h))
|
|
|
|
# Recursive scan of initial cross
|
|
for v in range(len(visited)):
|
|
vst = self._scanConnections((visited[v][0], visited[v][1]))
|
|
for l in range(len(vst)):
|
|
if self._checkVisited(visited, (vst[l][0], vst[l][1])) == False: visited.append((vst[l][0], vst[l][1]))
|
|
|
|
# Store this in the object array so orthographic can access the data
|
|
self._all_visited = visited
|
|
|
|
# Set coordinates
|
|
tv = self._tile_v
|
|
th = self._tile_h
|
|
|
|
# Pick a resource combination
|
|
resstring = self._selectResources()
|
|
|
|
# Store this for all encountered tiles
|
|
for v in range(0, len(visited)):
|
|
rs = self._getResourceInfo(visited[v][0], visited[v][1])
|
|
if rs == "0": self._storeResourceInfo(visited[v][0], visited[v][1], resstring)
|
|
|
|
|
|
# Check if a tile was visited
|
|
def _checkVisited(self, visited, tile):
|
|
v = False
|
|
for t in range(0, len(visited)):
|
|
if visited[t][0] == tile[0] and visited[t][1] == tile[1]:
|
|
v = True
|
|
break
|
|
return v
|
|
|
|
|
|
# Check if a tile was visited
|
|
def _checkAlrVisited(self, tile):
|
|
v = False
|
|
for t in range(1, len(self._already_visited)):
|
|
if self._already_visited[t][0] == tile[0] and self._already_visited[t][1] == tile[1]:
|
|
v = True
|
|
break
|
|
return v
|
|
|
|
|
|
# Show result of path tracing - DEBUG ONLY
|
|
def _debugRender(self, visited, mlat, mlng):
|
|
rmap = Image.new("RGBA", (mlng*10, mlat*10), color="#FFFFFF")
|
|
draw = ImageDraw.Draw(rmap)
|
|
for v in range(len(visited)):
|
|
sx, sy = (visited[v][1]-1)*10, (rmap.height-(visited[v][0]-1)*10)-10
|
|
dx, dy = ((visited[v][1]-1)*10)+10, (rmap.height-(visited[v][0]-1)*10)+10
|
|
shape = [ (sx, sy), (dx, dy) ]
|
|
fill = (0,0,0,255)
|
|
draw.rectangle(shape, fill=fill)
|
|
rmap.show()
|