From a4c0291e745e83fcf6c5b4ef4927185665378258 Mon Sep 17 00:00:00 2001 From: marstr Date: Mon, 2 Sep 2024 08:03:45 +0200 Subject: [PATCH] RC4 - Implemented cross-degree adjacency checks, corrected major issue in tile completion adjacency checks --- layergen.py | 178 ++++++++++++++++++++++++++++++++++++++++-------- maskgen.py | 6 +- orthographic.py | 82 +++++++++++++--------- osmxml.py | 2 +- photogen.py | 14 ++-- tiledb.py | 64 +++++++++++++++-- tilegen.py | 32 ++++----- 7 files changed, 285 insertions(+), 93 deletions(-) diff --git a/layergen.py b/layergen.py index 8e366e9..d8ef1e7 100644 --- a/layergen.py +++ b/layergen.py @@ -45,8 +45,13 @@ class mstr_layergen: self._isline = is_line if mstr_photores == 2048: self._imgsize = 3000 if mstr_photores == 4096: self._imgsize = 6000 - #mstr_msg("mstr_layergen", "Layer gen initialized") + #mstr_msg("layergen", "Layer gen initialized") + # Define maximum latitude and longitude tile numbers + def set_max_latlng_tile(self, maxlatlng): + self._maxlat = maxlatlng[0] + self._maxlng = maxlatlng[1] + mstr_msg("layergen", "Maximum latitude and longitude tile numbers received") # This generates a "border" image, for example farmland usually has a small space of grass # before the actual crop of farm field itself. This generates this "border" layer, @@ -71,7 +76,7 @@ class mstr_layergen: ptc_src = [] for p in ptc: ptc_src.append(Image.open(p)) - mstr_msg("mstr_layergen", "Border sources selected") + mstr_msg("layergen", "Border sources selected") # Begin producing a largely random image samples = 250 # <- We need this in a moment @@ -85,11 +90,11 @@ class mstr_layergen: t = 0 - int(ptc_src[imgid].height / 2) b = layer.height - int(ptc_src[imgid].height / 2) layer.alpha_composite( ptc_src[imgid], ( randrange(l, r), randrange(t, b) ) ) - mstr_msg("mstr_layergen", "Border image generated") + mstr_msg("layergen", "Border image generated") # We now need to add the seamless border layer.alpha_composite( brd_src ) - mstr_msg("mstr_layergen", "Layer image completed") + mstr_msg("layergen", "Layer image completed") # And now for the Big Mac. # Generate the layer from the mask. @@ -103,13 +108,13 @@ class mstr_layergen: # This generates the layer from the defined mask def genlayer(self): - mstr_msg("mstr_layergen", "Layer to be generated: " + str(self._latitude) + "-" + str(self._lat_number) + ":" + str(self._longitude) + "-" + str(self._lng_number) + " -- tag: " + self._tag + " - value: " + self._value ) + mstr_msg("layergen", "Layer to be generated: " + str(self._latitude) + "-" + str(self._lat_number) + ":" + str(self._longitude) + "-" + str(self._lng_number) + " -- tag: " + self._tag + " - value: " + self._value ) # Before we generate the layer, let's check for airports in this chunk - mstr_msg("mstr_layergen", "Checking for airport/s with ICAO code") + mstr_msg("layergen", "Checking for airport/s with ICAO code") osmxml = mstr_osmxml(0,0) icao = osmxml.find_icao_codes(mstr_datafolder + "_cache\\tile.xml") - mstr_msg("mstr_layergen", "Found " + str(len(icao)) + " airport/s") + mstr_msg("layergen", "Found " + str(len(icao)) + " airport/s") # Runway surface, if any other than concrete/asphalt rw_surface = "" # If we find an airport, make a note ... @@ -119,7 +124,7 @@ class mstr_layergen: iccheck = self._tiledb.perform_query("SELECT * FROM airports WHERE icao='" + i +"';") if len(iccheck) == 0: self._tiledb.insert_icao(i, self._lat_number, self._lng_number, self._latitude, self._longitude) - mstr_msg("mstr_layergen", "Airport/s noted in data file") + mstr_msg("layergen", "Airport/s noted in data file") rw_surface = osmxml.find_runway_surface(mstr_datafolder + "_cache\\tile.xml") # The image for the layer itself @@ -146,7 +151,7 @@ class mstr_layergen: # Find our adjacent tiles adjtiles = findAdjacentTilesTo(self._lat_number, self._lng_number) - mstr_msg("mstr_layergen", "Performing adjacency check") + mstr_msg("layergen", "Performing adjacency check") # Walk through each tile and see what we can find in relation to this # tile in the center # Since we already know the order in adjtiles, we can do this real easy @@ -156,10 +161,30 @@ class mstr_layergen: ab = self._tiledb.get_adjacency_for_source(adjtiles[2][0], adjtiles[2][1], self._tag, self._value) # Bottom al = self._tiledb.get_adjacency_for_source(adjtiles[3][0], adjtiles[3][1], self._tag, self._value) # Left if self._is_completion == True: - at = self._tiledb.get_adjacency_for_completion(adjtiles[0][0], adjtiles[0][1], self._tag, self._value) # Top - ar = self._tiledb.get_adjacency_for_completion(adjtiles[1][0], adjtiles[1][1], self._tag, self._value) # Right - ab = self._tiledb.get_adjacency_for_completion(adjtiles[2][0], adjtiles[2][1], self._tag, self._value) # Bottom - al = self._tiledb.get_adjacency_for_completion(adjtiles[3][0], adjtiles[3][1], self._tag, self._value) # Left + at = self._tiledb.get_adjacency_for_completion(adjtiles[0][0], adjtiles[0][1]) # Top + ar = self._tiledb.get_adjacency_for_completion(adjtiles[1][0], adjtiles[1][1]) # Right + ab = self._tiledb.get_adjacency_for_completion(adjtiles[2][0], adjtiles[2][1]) # Bottom + al = self._tiledb.get_adjacency_for_completion(adjtiles[3][0], adjtiles[3][1]) # Left + + if len(at) == 1: + self._tag = at[0][2] + self._value = at[0][3] + if len(ar) == 1: + self._tag = ar[0][2] + self._value = ar[0][3] + if len(ab) == 1: + self._tag = ab[0][2] + self._value = ab[0][3] + if len(al) == 1: + self._tag = al[0][2] + self._value = al[0][3] + + root_folder = mstr_datafolder + "Textures\\" + for s in mstr_ortho_layers: + if s[0] == self._tag and s[1] == self._value: + fld_main = len(s)-2 + fld_sub = len(s)-1 + root_folder = root_folder + s[fld_main] + "\\" + s[fld_sub] # We are south to the top tile. if len(at) == 1 and src == -1: @@ -173,8 +198,94 @@ class mstr_layergen: # We are east to the left tile. if len(al) == 1 and src == -1: if "r" in al[0][5]: src = int(al[0][4]) + + # Should we be at the border of the degree for latitude and longitude, we need to perform + # additional checks + is_deg_brd_t = False + is_deg_brd_r = False + is_deg_brd_b = False + is_deg_brd_l = False + if self._lat_number == 1: is_deg_brd_b = True + if self._lat_number == self._maxlat: is_deg_brd_t = True + if self._lng_number == 1: is_deg_brd_l = True + if self._lng_number == self._maxlng: is_deg_brd_r = True + + # Adjacent latitude and longitude tiles + deg_tiles = [] + deg_tiles.append( ( self._latitude+1, self._longitude ) ) # Top + deg_tiles.append( ( self._latitude, self._longitude+1 ) ) # Right + deg_tiles.append( ( self._latitude-1, self._longitude ) ) # Bottom + deg_tiles.append( ( self._latitude, self._longitude-1 ) ) # Left + + # Perform degree border checks + # - and make sure we do not run into errors - this drove me crazy in testing + atd = [] + ard = [] + abd = [] + ald = [] + if is_deg_brd_t == True: + if self._is_completion == False: + atd = self._tiledb.get_adjacency_for_source_in_lat_lng(deg_tiles[0][0], deg_tiles[0][1], 1, self._lng_number, self._tag, self._value) # Top + if self._is_completion == True: + atd = self._tiledb.get_adjacency_for_completion_in_lat_lng(deg_tiles[0][0], deg_tiles[0][1], 1, self._lng_number) # Top + if is_deg_brd_r == True: + if self._is_completion == False: + ard = self._tiledb.get_adjacency_for_source_in_lat_lng(deg_tiles[1][0], deg_tiles[1][1], self._lat_number, 1, self._tag, self._value) # Right + if self._is_completion == True: + ard = self._tiledb.get_adjacency_for_completion_in_lat_lng(deg_tiles[1][0], deg_tiles[1][1], self._lat_number, 1) # Right + if is_deg_brd_b == True: + maxlatlng = self._tiledb.get_highest_latlong_from_tile(self._latitude-1, self._longitude) + if self._is_completion == False: + abd = self._tiledb.get_adjacency_for_source_in_lat_lng(deg_tiles[2][0], deg_tiles[2][1], maxlatlng[0], self._lng_number, self._tag, self._value) # Bottom + if self._is_completion == True: + abd = self._tiledb.get_adjacency_for_completion_in_lat_lng(deg_tiles[2][0], deg_tiles[2][1], maxlatlng[0], self._lng_number) # Bottom + if is_deg_brd_l == True: + maxlatlng = self._tiledb.get_highest_latlong_from_tile(self._latitude, self._longitude-1) + if self._is_completion == False: + ald = self._tiledb.get_adjacency_for_source_in_lat_lng(deg_tiles[2][0], deg_tiles[2][1], self._lat_number, maxlatlng[1], self._tag, self._value) # Left + if self._is_completion == True: + ald = self._tiledb.get_adjacency_for_completion_in_lat_lng(deg_tiles[2][0], deg_tiles[2][1], self._lat_number, maxlatlng[1]) # Left + + if (is_deg_brd_t == True or is_deg_brd_r == True or is_deg_brd_b == True or is_deg_brd_l == True): + if src == -1 and self._is_completion == True: + if len(atd) == 1: + self._tag = atd[0][2] + self._value = atd[0][3] + if len(ard) == 1: + self._tag = ard[0][2] + self._value = ard[0][3] + if len(abd) == 1: + self._tag = abd[0][2] + self._value = abd[0][3] + if len(ald) == 1: + self._tag = ald[0][2] + self._value = ald[0][3] + + root_folder = mstr_datafolder + "Textures\\" + for s in mstr_ortho_layers: + if s[0] == self._tag and s[1] == self._value: + fld_main = len(s)-2 + fld_sub = len(s)-1 + root_folder = root_folder + s[fld_main] + "\\" + s[fld_sub] + + + # Should we get here and one of the degree border checks turns out true, + # we need to make sure that we select the source we found. This should + # enable seamless tiling... around the entire planet + if is_deg_brd_t == True and len(at) == 0 and src == -1: + if len(atd) == 1: + if "b" in atd[0][5]: src = int(atd[0][4]) + if is_deg_brd_r == True and len(ar) == 0 and src == -1: + if len(ard) == 1: + if "l" in ard[0][5]: src = int(ard[0][4]) + if is_deg_brd_b == True and len(ab) == 0 and src == -1: + if len(abd) == 1: + if "t" in abd[0][5]: src = int(abd[0][4]) + if is_deg_brd_l == True and len(al) == 0 and src == -1: + if len(ald) == 1: + if "r" in ald[0][5]: src = int(ald[0][4]) - mstr_msg("mstr_layergen", "Adjacency check completed") + mstr_msg("layergen", "Adjacency check completed") brd = glob.glob(root_folder + "\\brd\\b*.png") @@ -192,7 +303,7 @@ class mstr_layergen: ptc_src = [] for p in ptc: ptc_src.append(Image.open(p)) - mstr_msg("mstr_layergen", "Layer sources selected") + mstr_msg("layergen", "Layer sources selected") # OK! Load the mask if self._is_completion == False: @@ -203,7 +314,7 @@ class mstr_layergen: # Generate an edge mask from the original osm_edge = osm_mask.filter(ImageFilter.FIND_EDGES) osm_edge = osm_edge.filter(ImageFilter.MaxFilter) - mstr_msg("mstr_layergen", "Edge mask generated") + mstr_msg("layergen", "Edge mask generated") # This adds some natural looking shapes to these types of features if self._value == "forest" or self._value == "nature_reserve": @@ -250,7 +361,7 @@ class mstr_layergen: t = 0 - int(ptc_src[imgid].height / 2) b = layer.height - int(ptc_src[imgid].height / 2) layer.alpha_composite( ptc_src[imgid], ( randrange(l, r), randrange(t, b) ) ) - mstr_msg("mstr_layergen", "Layer image generated") + mstr_msg("layergen", "Layer image generated") # Here we need to do some magic to make some features look more natural @@ -266,7 +377,7 @@ class mstr_layergen: # We now need to add the seamless border layer.alpha_composite( brd_src ) - mstr_msg("mstr_layergen", "Layer image completed") + mstr_msg("layergen", "Layer image completed") # And now for the Big Mac. @@ -301,7 +412,7 @@ class mstr_layergen: if self._is_completion == True: layer_comp.save( mstr_datafolder + "_cache\\" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_tile-completion_layer.png" ) #layer_final.save( mstr_datafolder + "_cache\\" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_layer.png" ) - mstr_msg("mstr_layergen", "Layer image finalized and saved.") + mstr_msg("layergen", "Layer image finalized and saved.") # Let's try our hand at pseudo shadows @@ -310,7 +421,7 @@ class mstr_layergen: shadow = Image.new("RGBA", (self._imgsize, self._imgsize)) for sh in mstr_shadow_casters: if self._tag == sh[0] and self._value == sh[1]: - mstr_msg("mstr_layergen", "Generating shadow for layer") + mstr_msg("layergen", "Generating shadow for layer") shadow_pix = shadow.load() mask_pix = osm_mask.load() for y in range(self._imgsize-1): @@ -333,7 +444,7 @@ class mstr_layergen: aa = int(ca) shadow_pix[shf_x, y] = (0,0,0,aa) shadow.save(mstr_datafolder + "_cache\\" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_layer_shadow.png") - mstr_msg("mstr_layergen", "Shadow layer completed") + mstr_msg("layergen", "Shadow layer completed") @@ -383,12 +494,19 @@ class mstr_layergen: # Store into DB - but only if there is something to store if adjstr != "": if self._is_completion == False: - self._tiledb.insert_info(self._lat_number, self._lng_number, self._tag, self._value, src, adjstr) + r = self._tiledb.get_adjacency_for_source(self._lat_number, self._lng_number, self._tag, self._value) + if len(r) == 0: + self._tiledb.insert_info(self._lat_number, self._lng_number, self._tag, self._value, src, adjstr) + mstr_msg("layergen", "Adjacency info stored in database") + if self._is_completion == True: - self._tiledb.insert_completion_info(self._lat_number, self._lng_number, self._tag, self._value, src, adjstr) + r = self._tiledb.get_adjacency_for_completion(self._lat_number, self._lng_number) + if len(r) == 0: + self._tiledb.insert_completion_info(self._lat_number, self._lng_number, self._tag, self._value, src, adjstr) + mstr_msg("layergen", "Adjacency info for completion stored in database") + self._tiledb.commit_query() self._tiledb.close_db() - mstr_msg("mstr_layergen", "Adjacency info stored in database") # If we encounter one of these road-specific tags, we need to proceed differently. @@ -401,7 +519,7 @@ class mstr_layergen: # Generate an edge mask from the original osm_edge = osm_mask.filter(ImageFilter.FIND_EDGES) osm_edge = osm_edge.filter(ImageFilter.MaxFilter) - mstr_msg("mstr_layergen", "Edge mask generated") + mstr_msg("layergen", "Edge mask generated") # As above, we will apply the blur as noted in the defines for i in mstr_mask_blur: @@ -486,12 +604,12 @@ class mstr_layergen: b = 138 - d layer_comp_pix[x, y] = ( r,g,b,a[3] ) - mstr_msg("mstr_layergen", "Layer image generated") + mstr_msg("layergen", "Layer image generated") # Building shadow if mstr_shadow_enabled == True: if self._tag == "building": - mstr_msg("mstr_layergen", "Generating shadow for layer") + mstr_msg("layergen", "Generating shadow for layer") shadow = Image.new("RGBA", (self._imgsize, self._imgsize)) shadow_pix = shadow.load() mask_pix = osm_mask.load() @@ -506,7 +624,7 @@ class mstr_layergen: aa = int(ca) shadow_pix[shf_x, y] = (0,0,0,aa) shadow.save(mstr_datafolder + "_cache\\" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_layer_shadow.png") - mstr_msg("mstr_layergen", "Shadow layer completed") + mstr_msg("layergen", "Shadow layer completed") # Highways and runways of any kind get some special treatment if (self._tag == "highway" and self._value == "motorway") or (self._tag == "highway" and self._value == "primary") or (self._tag == "highway" and self._value == "secondary") or (self._tag == "highway" and self._value == "tertiary") or (self._tag == "aeroway" and self._value == "runway"): @@ -521,11 +639,11 @@ class mstr_layergen: a=mask_pix[x,y] layer_comp_pix[x, y] = ( w,w,w,a[3] ) - mstr_msg("mstr_layergen", "Street lines added") + mstr_msg("layergen", "Street lines added") if self._tag == "waterway" and (self._value == "river" or self._value == "stream"): layer_comp = layer_comp.filter(ImageFilter.GaussianBlur(radius=4)) # Store layer layer_comp.save( mstr_datafolder + "_cache\\" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_layer.png" ) - mstr_msg("mstr_layergen", "Layer image finalized and saved.") + mstr_msg("layergen", "Layer image finalized and saved.") diff --git a/maskgen.py b/maskgen.py index c661d19..a31b2a8 100644 --- a/maskgen.py +++ b/maskgen.py @@ -42,7 +42,7 @@ class mstr_maskgen: self._vstep = vstep self._scale = 1 / math.cos(math.radians(self._box[0])) self._isline = isline - #mstr_msg("mstr_maskgen", "Intialized mask gen.") + #mstr_msg("maskgen", "Intialized mask gen.") # Projects a point into the canvas of the mask. @@ -81,7 +81,7 @@ class mstr_maskgen: way = xml.acquire_waypoint_data(tilexml) rls = xml.acquire_relations(tilexml) - mstr_msg("mstr_maskgen", "Building mask for " + str(self._box[0]) + "-" + str(self._box[1]) + ", " + str(self._box[2]) + "-" + str(self._box[3]) + ", for " + self._tag + ": " + self._value ) + mstr_msg("maskgen", "Building mask for " + str(self._box[0]) + "-" + str(self._box[1]) + ", " + str(self._box[2]) + "-" + str(self._box[3]) + ", for " + self._tag + ": " + self._value ) frs = [] @@ -181,4 +181,4 @@ class mstr_maskgen: # Save image mask_img.save(mstr_datafolder + "_cache\\" + fstr + "_" + self._tag + "-" + self._value + ".png") # Inform - mstr_msg("mstr_maskgen", "Mask built.") + mstr_msg("maskgen", "Mask built.") diff --git a/orthographic.py b/orthographic.py index 8434e75..451112e 100644 --- a/orthographic.py +++ b/orthographic.py @@ -77,7 +77,7 @@ class mstr_orthographic: # Builds and processes the tile with everything required, in one call. def _buildTile(self): - mstr_msg("mstr_orthographic", "Beginning construction of tile") + mstr_msg("orthographic", "Beginning construction of tile") # We need to know which platform we are on os_platform = os.name @@ -86,23 +86,23 @@ class mstr_orthographic: # Temporary images for the ortho tile generation go here if not os.path.exists(self._output + "/_cache"): os.makedirs(self._output + "/_cache") - mstr_msg("mstr_orthographic", "Created _cache folder.") + mstr_msg("orthographic", "Created _cache folder.") # Generate the Tiles folder for the finished products if not os.path.exists(self._output + "/Tiles"): os.makedirs(self._output + "/Tiles") - mstr_msg("mstr_orthographic", "Created Tiles folder.") + mstr_msg("orthographic", "Created Tiles folder.") # Generate the Tiles/lat-lng folder for the finished tile if not os.path.exists(self._output + "/Tiles/"+str(self._lat)+"_"+str(self._long)): os.makedirs(self._output + "/Tiles/"+str(self._lat)+"_"+str(self._long)) - mstr_msg("mstr_orthographic", "Created Tiles sub folder: " +str(self._lat)+"_"+str(self._long)) + mstr_msg("orthographic", "Created Tiles sub folder: " +str(self._lat)+"_"+str(self._long)) # Note down diameter of entire tile #tile_dm = round(self._findWidthOfLongitude(), 3) - #mstr_msg("mstr_orthographic", "Tile diameter: " + str(tile_dm) + "m") + #mstr_msg("orthographic", "Tile diameter: " + str(tile_dm) + "m") #dm_of_18 = round(tile_dm * mstr_zl_18, 3) - #mstr_msg("mstr_orthographic", "Diameter of ZL 18 tile: " + str(dm_of_18) + "m") + #mstr_msg("orthographic", "Diameter of ZL 18 tile: " + str(dm_of_18) + "m") # The tile is constructed of many smaller parts. We walk through the # smallest possible, from which the bigger ones are later built. @@ -113,13 +113,30 @@ class mstr_orthographic: cur_tile_x = 1 cur_tile_y = 1 osmxml = mstr_osmxml(0,0) - mstr_msg("mstr_orthographic", "Set initial coordinates and bounding box for OSM acquisition") + mstr_msg("orthographic", "Set initial coordinates and bounding box for OSM acquisition") # The highest encountered tile numbers # This is needed to produce the zoom level 16 images top_lat = 1 top_lng = 1 + # We need to know the highest possible latitude and longitude tile numbers, + # in case we render at the edge + mlat = 1 + mlng = 1 + while bb_lat < self._lat + 1: + bb_lat = bb_lat + self._vstep + mlat = mlat+1 + while bb_lng < self._long + 1: + bb_lng = bb_lng + mstr_zl_18 + mlng = mlng+1 + mstr_msg("orthographic", "Max lat tile: " + str(mlat) + " - max lng tile: " + str(mlng)) + maxlatlng = [ mlat, mlng ] + + # Reset these two + bb_lat = self._lat + bb_lng = self._long + # Previously, I downloaded all XML files in one go - but to ease the # stress on OSM servers and my server, we will do acquire the data # only for the current processed part of the tile. @@ -127,17 +144,17 @@ class mstr_orthographic: while bb_lng < self._long + 1: # Adjust bounding box osmxml.adjust_bbox(bb_lat, bb_lng, bb_lat_edge, bb_lng_edge) - mstr_msg("mstr_orthographic", "Adjusted bounding box for XML object") + mstr_msg("orthographic", "Adjusted bounding box for XML object") # Determine what to do... maybe work was interrupted if os.path.isfile(mstr_datafolder + "Tiles\\" + str(self._lat) + "_" + str(self._long) + "\\Textures\\" + str(cur_tile_y) + "_" + str(cur_tile_x) + ".jpg") == False: # Let the user know - mstr_msg("mstr_orthographic", "Generating missing orthophoto " + str(cur_tile_y) + "-" + str(cur_tile_x)) + mstr_msg("orthographic", "Generating missing orthophoto " + str(cur_tile_y) + "-" + str(cur_tile_x)) # Get the data osmxml.acquire_osm(cur_tile_y, cur_tile_x) # <- This acquires current OSM info - mstr_msg("mstr_orthographic", "Acquired current OSM info from marstr.online repository") + mstr_msg("orthographic", "Acquired current OSM info from marstr.online repository") # Check for work to be done layers = self.determineLayerWork() @@ -146,22 +163,22 @@ class mstr_orthographic: # in their z-order. # For each layer, we will generate the mask, the layer image # itself, and finally, compose the ortho photo. - mstr_msg("mstr_orthographic", "Beginning generation of layers") + mstr_msg("orthographic", "Beginning generation of layers") # Generate the Tiles/lat-lng folder for the finished tile if not os.path.exists(self._output + "/Tiles/"+str(self._lat)+"_"+str(self._long) + "\\Textures"): os.makedirs(self._output + "/Tiles/"+str(self._lat)+"_"+str(self._long)+"\\Textures") - mstr_msg("mstr_orthographic", "Created tile textures folder") + mstr_msg("orthographic", "Created tile textures folder") # Generate the Tiles/terrain folder for the finished tile if not os.path.exists(self._output + "/Tiles/"+str(self._lat)+"_"+str(self._long) + "\\terrain"): os.makedirs(self._output + "/Tiles/"+str(self._lat)+"_"+str(self._long)+"\\terrain") - mstr_msg("mstr_orthographic", "Created tile terrain folder") + mstr_msg("orthographic", "Created tile terrain folder") curlyr = 1 for layer in layers: # Let the user know - mstr_msg("mstr_orthographic", "Processing layer " + str(curlyr) + " of " + str(len(layers))) + mstr_msg("orthographic", "Processing layer " + str(curlyr) + " of " + str(len(layers))) # Generate the mask mg = mstr_maskgen( [self._lat, cur_tile_y, self._long, cur_tile_x], self._vstep, layer[0], layer[1], layer[2] ) @@ -169,16 +186,17 @@ class mstr_orthographic: # Generate the layer lg = mstr_layergen(layer[0], layer[1], self._lat, cur_tile_y, self._long, cur_tile_x, layer[2]) + lg.set_max_latlng_tile(maxlatlng) lg.genlayer() curlyr = curlyr+1 - mstr_msg("mstr_orthographic", "All layers created") + mstr_msg("orthographic", "All layers created") # We should have all layers now. # Snap a photo with our satellite :) - mstr_msg("mstr_orthographic", "Generating ortho photo") - pg = mstr_photogen(self._lat, self._long, cur_tile_y, cur_tile_x) + mstr_msg("orthographic", "Generating ortho photo") + pg = mstr_photogen(self._lat, self._long, cur_tile_y, cur_tile_x, maxlatlng[0], maxlatlng[1]) pg.genphoto() - mstr_msg("mstr_orthographic", "Ortho photo generated") + mstr_msg("orthographic", " -- Ortho photo generated -- ") print("") print("") @@ -186,7 +204,7 @@ class mstr_orthographic: cur_tile_x = cur_tile_x+1 bb_lng = bb_lng + mstr_zl_18 bb_lng_edge = bb_lng_edge + mstr_zl_18 - mstr_msg("mstr_orthographic", "Adjustment of longitude performed") + mstr_msg("orthographic", "Adjustment of longitude performed") # Adjust peak longitude tile number if cur_tile_x > top_lng: top_lng = cur_tile_x @@ -201,7 +219,7 @@ class mstr_orthographic: if os_platform == "posix": if self._isFileAccessiblePosix(f) == True: os.remove(f) - mstr_msg("mstr_orthographic", "Cleared cache") + mstr_msg("orthographic", "Cleared cache") # Adjust latitude and all other values when we get here @@ -211,25 +229,25 @@ class mstr_orthographic: bb_lng_edge = self._long + mstr_zl_18 bb_lat = bb_lat + self._vstep bb_lat_edge = bb_lat_edge + self._vstep - mstr_msg("mstr_orthographic", "Adjustment of latitude performed") + mstr_msg("orthographic", "Adjustment of latitude performed") # Adjust peak latitude number if cur_tile_y > top_lat: top_lat = cur_tile_y - mstr_msg("mstr_orthographic", "Generation of all tiles completed!") + mstr_msg("orthographic", "Generation of all tiles completed!") - mstr_msg("mstr_orthographic", "Generating ZL16 tiles and keeping airport tiles") + mstr_msg("orthographic", "Generating ZL16 tiles and keeping airport tiles") tg = mstr_tilegen(self._lat, self._lng, self._vstep, top_lat, top_lng) tg.genTiles() - mstr_msg("mstr_orthographic", "Final step completed.") + mstr_msg("orthographic", "Final step completed.") print("") print("") - mstr_msg("mstr_orthographic", "Tile data in: " + mstr_datafolder + "\\Tiles\\" + str(self._lat) + "_" + self._lng) - mstr_msg("mstr_orthographic", "Orthos are in the Textures subfolder") - mstr_msg("mstr_orthographic", "X-Plane .ter's are in the terrain subfolder") + mstr_msg("orthographic", "Tile data in: " + mstr_datafolder + "\\Tiles\\" + str(self._lat) + "_" + self._lng) + mstr_msg("orthographic", "Orthos are in the Textures subfolder") + mstr_msg("orthographic", "X-Plane .ter's are in the terrain subfolder") print("") print("") - mstr_msg("mstr_orthographic", "Thanks for using Orthographic! -- Best, Marcus") + mstr_msg("orthographic", "Thanks for using Orthographic! -- Best, Marcus") print("") @@ -239,7 +257,7 @@ class mstr_orthographic: # Checks which layers need to be generated, and what kind of layer it is def determineLayerWork(self): - mstr_msg("mstr_orthographic", "Checking for work to be performed") + mstr_msg("orthographic", "Checking for work to be performed") layers = [] @@ -262,7 +280,7 @@ class mstr_orthographic: break if has_way == True or has_rls == True: - mstr_msg("mstr_orthographic", "Adding: " + l[0]+":"+l[1]) + mstr_msg("orthographic", "Adding: " + l[0]+":"+l[1]) is_line = False for s in mstr_ortho_layers: if s[0] == l[0] and s[1] == l[1]: @@ -275,7 +293,7 @@ class mstr_orthographic: ly = (l[0], l[1], is_line) layers.append(ly) - mstr_msg("mstr_orthographic", "A total of " + str(len(layers)) + " layers were found") + mstr_msg("orthographic", "A total of " + str(len(layers)) + " layers were found") return layers @@ -287,4 +305,4 @@ class mstr_orthographic: self._output = outfolder self._pwd = pwd self._vstep = self._findVerticalStepping() - mstr_msg("mstr_orthographic", "Initiated with LAT: " + str(lat) + ", LNG: " + str(lng)) \ No newline at end of file + mstr_msg("orthographic", "Initiated with LAT: " + str(lat) + ", LNG: " + str(lng)) \ No newline at end of file diff --git a/osmxml.py b/osmxml.py index e7c5cf8..cae22eb 100644 --- a/osmxml.py +++ b/osmxml.py @@ -38,7 +38,7 @@ class mstr_osmxml: # Acquire XMLs in chunks, then store them def acquire_osm(self, v, h): - mstr_msg("mstr_osmxml", "Acquiring OSM data for " + str(self._lat)+","+str(self._lng)+" - "+str(self._curB_lat)+","+str(self._curB_lng)) + mstr_msg("osmxml", "Acquiring OSM data for " + str(self._lat)+","+str(self._lng)+" - "+str(self._curB_lat)+","+str(self._curB_lng)) # We will use our self-hosted API for this. data = { diff --git a/photogen.py b/photogen.py index 870ca7c..066c969 100644 --- a/photogen.py +++ b/photogen.py @@ -21,18 +21,19 @@ from log import * class mstr_photogen: # Initializer doesn't need much - def __init__ (self, lat, lng, ty, tx): + def __init__ (self, lat, lng, ty, tx, maxlat, maxlng): self._lat = lat self._lng = lng self._ty = ty self._tx = tx + self._maxlatlng = [ maxlat, maxlng ] # Define layer size depending on what is wanted self._imgsize = 0 if mstr_photores == 2048: self._imgsize = 3000 if mstr_photores == 4096: self._imgsize = 6000 # Empty image where everything goes into self._tile = Image.new("RGBA", (self._imgsize, self._imgsize)) - mstr_msg("mstr_photogen", "Photogen initialized") + mstr_msg("photogen", "Photogen initialized") # This puts it all together. Bonus: AND saves it. @@ -41,7 +42,7 @@ class mstr_photogen: root_filename = mstr_datafolder + "\\_cache\\" + str(self._lat) + "-" + str(self._ty) + "_" + str(self._lng) + "-" + str(self._tx) + "_" # First, we walk through all layers and blend them on top of each other, in order - mstr_msg("mstr_photogen", "Merging layers") + mstr_msg("photogen", "Merging layers") for l in mstr_ortho_layers: if os.path.isfile(root_filename + l[0] + "-" + l[1] + "_layer.png"): @@ -67,7 +68,7 @@ class mstr_photogen: # First, we will check if there is something to fix: emptyspace = self.checkForEmptySpace() - mstr_msg("mstr_photogen", "Checked for empty patches") + mstr_msg("photogen", "Checked for empty patches") # If this check comes back as true, we need to perform # aforementioned fix: @@ -79,11 +80,12 @@ class mstr_photogen: tag = mstr_ortho_layers[ltp][0] value = mstr_ortho_layers[ltp][1] - mstr_msg("mstr_photogen", "Patching empty space") + mstr_msg("photogen", "Patching empty space") self.buildCompletionMask() # Generate the layer as if it were part of the OSM data lg = mstr_layergen(tag, value, self._lat, self._ty, self._lng, self._tx, False, is_completion=True) + lg.set_max_latlng_tile(self._maxlatlng) lg.genlayer() # Load the image @@ -146,4 +148,4 @@ class mstr_photogen: # exact pixel positions. mask.save( mstr_datafolder + "_cache\\" + str(self._lat) + "-" + str(self._ty) + "_" + str(self._lng) + "-" + str(self._tx) + "_tile-completion.png" ) - mstr_msg("mstr_photogen", "Generated and saved empty space mask") \ No newline at end of file + mstr_msg("photogen", "Generated and saved empty space mask") \ No newline at end of file diff --git a/tiledb.py b/tiledb.py index 9c81c50..4732dfd 100644 --- a/tiledb.py +++ b/tiledb.py @@ -26,7 +26,7 @@ class mstr_tiledb: # The db file will be created, should it not exist self._conn = sqlite3.connect(mstr_datafolder + "Tiles\\" + str(self._latitude) + "_" + str(self._longitude) + "\\data.db") self._crs = self._conn.cursor() - #mstr_msg("mstr_tiledb", "Database object initiated") + #mstr_msg("tiledb", "Database object initiated") # Opens a database file - used by maskgen @@ -40,7 +40,7 @@ class mstr_tiledb: self._conn.execute("CREATE TABLE IF NOT EXISTS tiledata (tile_v INTEGER, tile_h INTEGER, tag TEXT, value TEXT, source INTEGER, adjacent TEXT);") self._conn.execute("CREATE TABLE IF NOT EXISTS airports (icao TEXT, tile_v INTEGER, tile_h INTEGER, latitude REAL, longitude REAL);") self._conn.execute("CREATE TABLE IF NOT EXISTS completion (tile_v INTEGER, tile_h INTEGER, tag TEXT, value TEXT, source INTEGER, adjacent TEXT);") - #mstr_msg("mstr_tiledb", "Tables created") + #mstr_msg("tiledb", "Tables created") # Insert data into their segments @@ -68,10 +68,64 @@ class mstr_tiledb: return rws # Retrieve the adjacency info for completion of a tile - def get_adjacency_for_completion(self, v, h, tag, value): - r = self._crs.execute("SELECT * FROM completion where tile_v="+str(v)+" and tile_h="+str(h)+" and tag='"+tag+"' and value='"+value+"';") + def get_adjacency_for_completion(self, v, h): + r = self._crs.execute("SELECT * FROM completion where tile_v="+str(v)+" and tile_h="+str(h)+";") rws = r.fetchall() return rws + + # These calls are a bit more complex. We also need to know adjacency info when we are directly + # next to another latitude or longitude. We want seamless generation in those situations too. + def get_adjacency_for_source_in_lat_lng(self, lat, lng, v, h, tag, value): + # The rows to return + rws = [] + + # For this we need to tap into the database of the tile, should there be one. + dbn = mstr_datafolder + "Tiles\\" + str(lat) + "_" + str(lng) + "\\data.db" + if os.path.isfile(dbn): + tileconn = sqlite3.connect(dbn) + tilecrsr = tileconn.cursor() + r = tilecrsr.execute("SELECT * from tiledata WHERE tile_v="+str(v)+" AND tile_h="+str(h)+" AND tag='"+tag+"' AND value='"+value+"';") + rws = r.fetchall() + tileconn.close() + + return rws + + # These calls are a bit more complex. We also need to know adjacency info when we are directly + # next to another latitude or longitude. We want seamless generation in those situations too. + def get_adjacency_for_completion_in_lat_lng(self, lat, lng, v, h): + # The rows to return + rws = [] + + # For this we need to tap into the database of the tile, should there be one. + dbn = mstr_datafolder + "Tiles\\" + str(lat) + "_" + str(lng) + "\\data.db" + if os.path.isfile(dbn): + tileconn = sqlite3.connect(dbn) + tilecrsr = tileconn.cursor() + r = tilecrsr.execute("SELECT * from completion WHERE tile_v="+str(v)+" AND tile_h="+str(h)+";") + rws = r.fetchall() + tileconn.close() + + return rws + + # Acquire the highest latitude and longitude tile number of a neighbouring tile + def get_highest_latlong_from_tile(self, lat, lng): + latlng = [-1, -1] + # For this we need to tap into the database of the tile, should there be one. + dbn = mstr_datafolder + "Tiles\\" + str(lat) + "_" + str(lng) + "\\data.db" + if os.path.isfile(dbn): + tileconn = sqlite3.connect(dbn) + tilecrsr = tileconn.cursor() + lt = tilecrsr.execute("SELECT * FROM tiledata ORDER BY tile_v DESC") + rws = lt.fetchall() + lat = rws[0][0] + ln = tilecrsr.execute("SELECT * FROM tiledata ORDER BY tile_h DESC") + rws = ln.fetchall() + lng = rws[0][1] + latlng[0] = lat + latlng[1] = lng + tileconn.close() + + return latlng # Get all tiles with detected airports (ICAO codes) def get_tiles_with_airports(self): @@ -89,6 +143,6 @@ class mstr_tiledb: # Close DB def close_db(self): - mstr_msg("mstr_tiledb", "Closing database connection") + mstr_msg("tiledb", "Closing database connection") self._conn.close() diff --git a/tilegen.py b/tilegen.py index bdb1e13..eb30f5c 100644 --- a/tilegen.py +++ b/tilegen.py @@ -32,7 +32,7 @@ class mstr_tilegen: self._maxlng = max_lng # Connection to DB self._tiledb = mstr_tiledb(lat, lng) - mstr_msg("mstr_tilegen", "Tilegen initialized") + mstr_msg("tilegen", "Tilegen initialized") # To write down X-Plane .ter files, we will need to know the exact size @@ -62,7 +62,7 @@ class mstr_tilegen: # Find out how many steps we can walk in every direction steps_lat = int(math.ceil(self._maxlat/4)) steps_lng = int(math.ceil(self._maxlng/4)) - mstr_msg("mstr_tilegen", "Latitude and longitude steps determined") + mstr_msg("tilegen", "Latitude and longitude steps determined") # OK... so. Let's finish this. for lt in range(1, steps_lat): @@ -70,7 +70,7 @@ class mstr_tilegen: # Check if we need to do something if os.path.isfile(mstr_datafolder + "Tiles\\" + str(self._lat) + "_" + str(self._lng) + "\\Textures\\" + str(self._lat) + "-" + str(ln) + "_" + str(self._lng) + "-" + str(lt) + "_OG16.jpg") == False: - mstr_msg("mstr_tilegen", "Generating missing zoom level 16 ortho " + str(self._lat) + "-" + str(ln) + "_" + str(self._lng) + "-" + str(lt) + "_OG16.jpg") + mstr_msg("tilegen", "Generating missing zoom level 16 ortho " + str(self._lat) + "-" + str(ln) + "_" + str(self._lng) + "-" + str(lt) + "_OG16.jpg") # Find out which tiles to process tiles = findZL16tiles(cur_lat, cur_lng) @@ -107,45 +107,45 @@ LOAD_CENTER """ + str(a_lat) + " " + str(a_lng) + " " + str(dmt) + " " + "../Tex NO_ALPHA""" with open(mstr_datafolder + "\\Tiles\\"+str(self._lat)+"_"+str(self._lng)+"\\terrain\\"+str(self._lat)+"_"+str(lt)+"-"+str(self._lng)+"-"+str(ln)+"_OG16.ter", 'w') as textfile: textfile.write(ter_content) - mstr_msg("mstr_tilegen", "Wrote .ter file") + mstr_msg("tilegen", "Wrote .ter file") # Adjust a_lng = a_lng + (mstr_zl_16 * 4) cur_lng = cur_lng + 4 - mstr_msg("mstr_tilegen", "Adjusted coordinate values") + mstr_msg("tilegen", "Adjusted coordinate values") # Adjust a_lng = self._lat + (mstr_zl_16 * 2) a_lat = a_lat + (self._vstep * 4) cur_lat = cur_lat + 4 cur_lng = self._lng - mstr_msg("mstr_tilegen", "Adjusted coordinate values for next tile loop") + mstr_msg("tilegen", "Adjusted coordinate values for next tile loop") - mstr_msg("mstr_tilegen", "Tile generation... completed (wow.jpg)") + mstr_msg("tilegen", "Tile generation... completed (wow.jpg)") # BUT! This is not the end. Yet. # Make sure we keep tiles around airports. airports = self._tiledb.get_tiles_with_airports() - mstr_msg("mstr_tilegen", "Filtering ZL18 tiles for airports") + mstr_msg("tilegen", "Filtering ZL18 tiles for airports") # The ZL 18 tiles to keep in the end tiles = [] - mstr_msg("mstr_tilegen", "Finding ZL18 tiles to keep") + mstr_msg("tilegen", "Finding ZL18 tiles to keep") for a in airports: tiles.append(findAirportTiles(int(a[1]), int(a[2]))) - mstr_msg("mstr_tilegen", "Determined ZL18 tiles") + mstr_msg("tilegen", "Determined ZL18 tiles") # Create a final array to make life easier - mstr_msg("mstr_tilegen", "Generating arrays for tiles to keep") + mstr_msg("tilegen", "Generating arrays for tiles to keep") keeping = [] for t in tiles: for i in t: keeping.append(i) # Perform the cleanup - mstr_msg("mstr_tilegen", "Cleaning up non-needed tiles") + mstr_msg("tilegen", "Cleaning up non-needed tiles") for y in range(1, self._maxlat): for x in range(1, self._maxlng): fn = str(y) + "_" + str(x) + ".jpg" @@ -157,11 +157,11 @@ NO_ALPHA""" break if found == False: os.remove(mstr_datafolder + "\\Tiles\\" + str(self._lat) + "_" + str(self._lng) + "\\Textures\\" + fn) - mstr_msg("mstr_tilegen", "Cleanup completed") + mstr_msg("tilegen", "Cleanup completed") # And now for the final act of tonight's entertainment - mstr_msg("mstr_tilegen", "Writing .ter files for ZL18 tiles") + mstr_msg("tilegen", "Writing .ter files for ZL18 tiles") for k in keeping: k_lat = self._lat + (k[0] * self._vstep) + (self._vstep * 0.5) @@ -176,9 +176,9 @@ LOAD_CENTER """ + str(k_lat) + " " + str(k_lng) + " " + str(k_dmt) + " " + "../T NO_ALPHA""" with open(k_fln, 'w') as textfile: textfile.write(ter_content) - mstr_msg("mstr_tilegen", "Wrote all .ter files for ZL18 tiles.") + mstr_msg("tilegen", "Wrote all .ter files for ZL18 tiles.") - mstr_msg("mstr_tilegen", "Work complete.") + mstr_msg("tilegen", "Work complete.") -- 2.30.2