227 lines
9.6 KiB
Python
227 lines
9.6 KiB
Python
|
|
||
|
# -------------------------------------------------------------------
|
||
|
# ORTHOGRAPHIC
|
||
|
# Your personal aerial satellite. Always on. At any altitude.*
|
||
|
# Developed by MarStrMind
|
||
|
# License: MIT
|
||
|
# 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))
|