# ------------------------------------------------------------------- # 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._checkVisited(self._already_visited, (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])) self._all_visited = visited # We will take the resource of the original tile we have started # our scan from. If there is nothing, we can choose. # This is then used for all visited tiles. tv = self._tile_v th = self._tile_h resstring = self._selectResources() for v in range(0, len(visited)): 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 # 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()