# ------------------------------------------------------------------- # 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 # ------------------------------------------------------------------- # orthographic.py # Main class which handles the generation of the ortho tile. # ------------------------------------------------------------------- import math import os import glob from defines import * from log import * from maskgen import * from layergen import * from photogen import * from osmxml import * # The main class which handles the rest class mstr_orthographic: # This will determine the vertical stepping in degrees in order to generate # masks with a 1:1 square ratio. This is important as X-Plane textures for # orthos can only be a power of 2, such as 2048x2048 def _findVerticalStepping(self): scale = 1 / math.cos(math.radians(self._lat)) maxlat = (1 / scale) * mstr_zl_18 return maxlat # To write down X-Plane .ter files, we will need to know the exact size # of the particular longitude we are in, as this value varies depending # on where you are on a sphere. # Returned values is in meters. # The current latitude is needed. def _findWidthOfLongitude(self, lat): dm = math.cos(math.radians(lat)) * 111.321 # <- 1 deg width at equator in km return round(dm * 1000, 3) # Builds and processes the tile with everything required, in one call. def _buildTile(self): mstr_msg("mstr_orthographic", "Beginning construction of tile") # Create the _cache folder, should it not exist. # 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.") # 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.") # 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)) # Note down diameter of entire tile #tile_dm = round(self._findWidthOfLongitude(), 3) #mstr_msg("mstr_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") # The tile is constructed of many smaller parts. We walk through the # smallest possible, from which the bigger ones are later built. bb_lat = self._lat bb_lng = self._long bb_lat_edge = self._lat+self._vstep bb_lng_edge = self._long+mstr_zl_18 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") # 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. while bb_lat < self._lat + 1: 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") # 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") # Check for work to be done layers = self.determineLayerWork() # We need to walk through the array of layers, # 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") # 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") # 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") for layer in 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] ) mg._build_mask() # Generate the layer lg = mstr_layergen(layer[0], layer[1], self._lat, cur_tile_y, self._long, cur_tile_x, layer[2]) lg.genlayer() mstr_msg("mstr_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) pg.genphoto() mstr_msg("mstr_orthographic", "Ortho photo generated") mstr_msg("", "") # <- Spacer mstr_msg("", "") # <- Spacer # Store a terrain file ''' dmt = self._findWidthOfLongitude(bb_lat) * mstr_zl_18 sy = bb_lat + (self._vstep / 2) sx = bb_lng + (mstr_zl_18 / 2) ter_content = """A 800 TERRAIN LOAD_CENTER """ + str(sy) + " " + str(sx) + " " + str(dmt) + " " + str(mstr_photores) + """ BASE_TEX_NOWRAP ../Textures/"""+str(cur_tile_y)+"_"+str(cur_tile_x)+".jpg"+""" NO_ALPHA""" with open(self._output + "\\Tiles\\"+str(bb_lat)+"_"+str(bb_lng)+"\\terrain\\"+str(cur_tile_y)+"_"+str(cur_tile_x)+".ter", 'w') as textfile: textfile.write(ter_content) mstr_msg("mstr_orthographic", "Wrote .ter file") ''' # Adjust longitude coordinates 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") # Clear out cache if mstr_clear_cache == True: ch = glob.glob(mstr_datafolder + "_cache\\*") for f in ch: os.remove(f) mstr_msg("mstr_orthographic", "Cleared cache") # Adjust latitude and all other values when we get here cur_tile_y = cur_tile_y+1 cur_tile_x = 1 bb_lng = self._long 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") # 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") layers = [] tilexml = mstr_datafolder + "_cache\\tile.xml" xml = mstr_osmxml(0,0) way = xml.acquire_waypoint_data(tilexml) rls = xml.acquire_relations(tilexml) for l in mstr_ortho_layers: # Check if there is anything to render has_way = False has_rls = False for w in way: if w[2] == l[0] and w[3] == l[1]: has_way = True break for r in rls: if l[0] in r[1] and l[1] in r[1]: has_rls = True break if has_way == True or has_rls == True: mstr_msg("mstr_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]: if isinstance(s[2], int) == False: is_line = False break if isinstance(s[2], int) == True: is_line = True break ly = (l[0], l[1], is_line) layers.append(ly) mstr_msg("mstr_orthographic", "A total of " + str(len(layers)) + " layers were found") return layers # Constructor of class. Takes longitude and latitude. def __init__(self, lat, lng, outfolder, pwd): self._lat = lat self._long = lng self._output = outfolder self._pwd = pwd self._vstep = self._findVerticalStepping() mstr_msg("mstr_orthographic", "Initiated with LAT: " + str(lat) + ", LNG: " + str(lng))