Last minor adjustments and a needed feature for PBF generation (needed for a later stage)
This commit is contained in:
parent
817d65639d
commit
bd2594221d
@ -75,6 +75,7 @@ mstr_xp_scn_normalmaps = True
|
|||||||
mstr_xp_meshtool = "/home/marcus/Developer/Projects/orthographic/bin/MeshTool"
|
mstr_xp_meshtool = "/home/marcus/Developer/Projects/orthographic/bin/MeshTool"
|
||||||
mstr_xp_ddstool = "/home/marcus/Developer/Projects/orthographic/bin/DDSTool"
|
mstr_xp_ddstool = "/home/marcus/Developer/Projects/orthographic/bin/DDSTool"
|
||||||
mstr_xp_xessrc = "https://dev.x-plane.com/update/misc/MeshTool/"
|
mstr_xp_xessrc = "https://dev.x-plane.com/update/misc/MeshTool/"
|
||||||
|
mstr_xp_floor_height = 2.8 # 2.5m ceiling height + 30cm concrete per floor
|
||||||
|
|
||||||
# If you set the above to true, you can define for which features you
|
# If you set the above to true, you can define for which features you
|
||||||
# want to generate normal maps for. The below is my recommendation for
|
# want to generate normal maps for. The below is my recommendation for
|
||||||
|
@ -1123,7 +1123,7 @@ class mstr_layergen:
|
|||||||
ptc_src.append(Image.open(p))
|
ptc_src.append(Image.open(p))
|
||||||
|
|
||||||
osm_mask = Image.open( mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + ".png" )
|
osm_mask = Image.open( mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + ".png" )
|
||||||
lyr_mask = Image.open( mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_layer.png" )
|
#lyr_mask = Image.open( mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_layer.png" )
|
||||||
|
|
||||||
for i in mstr_mask_blur:
|
for i in mstr_mask_blur:
|
||||||
if i[0] == self._tag and i[1] == self._value:
|
if i[0] == self._tag and i[1] == self._value:
|
||||||
@ -1147,12 +1147,12 @@ class mstr_layergen:
|
|||||||
|
|
||||||
adj_image.alpha_composite( brd_src )
|
adj_image.alpha_composite( brd_src )
|
||||||
|
|
||||||
lyr_pix = lyr_mask.load()
|
#lyr_pix = lyr_mask.load()
|
||||||
for y in range(self._imgsize):
|
for y in range(self._imgsize):
|
||||||
for x in range(self._imgsize):
|
for x in range(self._imgsize):
|
||||||
if lyr_pix[x, y][3] > 0:
|
if mask_pix[x, y][3] > 0:
|
||||||
rgb=adj_pix[x,y]
|
rgb=adj_pix[x,y]
|
||||||
a=lyr_pix[x,y]
|
a=mask_pix[x,y]
|
||||||
adj_pix[x, y] = ( rgb[0], rgb[1], rgb[2], a[3])
|
adj_pix[x, y] = ( rgb[0], rgb[1], rgb[2], a[3])
|
||||||
|
|
||||||
# Up until here we mimiced the exact same behavior as layergen. However, now
|
# Up until here we mimiced the exact same behavior as layergen. However, now
|
||||||
|
16
maskgen.py
16
maskgen.py
@ -13,12 +13,6 @@
|
|||||||
# that this part of the code is the most crucial one, as the other
|
# that this part of the code is the most crucial one, as the other
|
||||||
# classes involved rely on what this code is doing, and by extension,
|
# classes involved rely on what this code is doing, and by extension,
|
||||||
# generating.
|
# generating.
|
||||||
#
|
|
||||||
# The PNG generated will be used in this progression:
|
|
||||||
# - Generate mask from OSM (here)
|
|
||||||
# - Generate colored photo layer from this mask, for example for
|
|
||||||
# landuse: forest
|
|
||||||
# - Compile actual satellite aerial
|
|
||||||
# -------------------------------------------------------------------
|
# -------------------------------------------------------------------
|
||||||
|
|
||||||
import math
|
import math
|
||||||
@ -83,9 +77,7 @@ class mstr_maskgen:
|
|||||||
# Builds the required mask
|
# Builds the required mask
|
||||||
def _build_mask(self):
|
def _build_mask(self):
|
||||||
# Generate empty image
|
# Generate empty image
|
||||||
imgsize = 0
|
imgsize = 2048
|
||||||
if mstr_photores == 2048: imgsize=2048
|
|
||||||
if mstr_photores == 4096: imgsize=6000
|
|
||||||
mask_img = Image.new("RGBA", (imgsize, imgsize))
|
mask_img = Image.new("RGBA", (imgsize, imgsize))
|
||||||
|
|
||||||
tilexml = mstr_datafolder + "_cache/tile.xml"
|
tilexml = mstr_datafolder + "_cache/tile.xml"
|
||||||
@ -119,7 +111,7 @@ class mstr_maskgen:
|
|||||||
for d in way:
|
for d in way:
|
||||||
if d[0] == w[0]:
|
if d[0] == w[0]:
|
||||||
if self._tag == "building" and bld_levels == 0:
|
if self._tag == "building" and bld_levels == 0:
|
||||||
bld_levels = xml.find_building_levels(tilexml, w[0])
|
bld_levels = xml.find_building_levels(w[0])
|
||||||
nd.append(d[1])
|
nd.append(d[1])
|
||||||
frs.append(nd)
|
frs.append(nd)
|
||||||
# Scout through relations as these also make up map data
|
# Scout through relations as these also make up map data
|
||||||
@ -160,9 +152,7 @@ class mstr_maskgen:
|
|||||||
p_lng = self.project_pixel(latlng[1], bbox[3])
|
p_lng = self.project_pixel(latlng[1], bbox[3])
|
||||||
pixlat = 0
|
pixlat = 0
|
||||||
pixlng = 0
|
pixlng = 0
|
||||||
pr = 0
|
pr = 2048
|
||||||
if mstr_photores == 2048: pr = 2048
|
|
||||||
if mstr_photores == 4096: pr = 6000
|
|
||||||
|
|
||||||
# Draw pixels in direction according to latitude and longitude positions -
|
# Draw pixels in direction according to latitude and longitude positions -
|
||||||
|
|
||||||
|
24
og.py
24
og.py
@ -22,7 +22,7 @@ from defines import *
|
|||||||
print(" ")
|
print(" ")
|
||||||
print(" ---------------------------------------------------------------- ")
|
print(" ---------------------------------------------------------------- ")
|
||||||
print(" ORTHOGRAPHIC: An ortho-photo generator, using real world data.")
|
print(" ORTHOGRAPHIC: An ortho-photo generator, using real world data.")
|
||||||
print(" Developed by MarStrMind - Code available on marstr.online")
|
print(" Developed by MarStr - Code available on marstr.online")
|
||||||
print(" ---------------------------------------------------------------- ")
|
print(" ---------------------------------------------------------------- ")
|
||||||
print(" ")
|
print(" ")
|
||||||
|
|
||||||
@ -30,9 +30,14 @@ print(" ")
|
|||||||
# Evaluate CLI arguments and process tile.
|
# Evaluate CLI arguments and process tile.
|
||||||
|
|
||||||
cli = False
|
cli = False
|
||||||
|
pbf = False
|
||||||
|
|
||||||
if len(sys.argv) == 3:
|
if len(sys.argv) == 3:
|
||||||
cli = True
|
cli = True
|
||||||
|
|
||||||
|
if len(sys.argv) == 4:
|
||||||
|
pbf = True
|
||||||
|
|
||||||
# Only if we find enough arguments, proceed.
|
# Only if we find enough arguments, proceed.
|
||||||
if cli == True:
|
if cli == True:
|
||||||
lat = int(sys.argv[1])
|
lat = int(sys.argv[1])
|
||||||
@ -44,10 +49,23 @@ if cli == True:
|
|||||||
og = mstr_orthographic(lat, lng, mstr_datafolder, os.getcwd())
|
og = mstr_orthographic(lat, lng, mstr_datafolder, os.getcwd())
|
||||||
og._buildTile()
|
og._buildTile()
|
||||||
|
|
||||||
else:
|
|
||||||
|
# Only if we find enough arguments, proceed.
|
||||||
|
if pbf == True:
|
||||||
|
lat = int(sys.argv[1])
|
||||||
|
lng = int(sys.argv[2])
|
||||||
|
pbf = sys.argv[3]
|
||||||
|
|
||||||
|
if pbf == "pbf":
|
||||||
|
# Create the class and init values
|
||||||
|
og = mstr_orthographic(lat, lng, mstr_datafolder, os.getcwd())
|
||||||
|
og._generateData()
|
||||||
|
|
||||||
|
|
||||||
|
if cli == False and pbf == False:
|
||||||
mstr_msg("_main", "Please provide Latitude and Longitude. Exiting.")
|
mstr_msg("_main", "Please provide Latitude and Longitude. Exiting.")
|
||||||
print ("")
|
print ("")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# * No Space Shuttle or SpaceShipOne needed to deploy.
|
# * No Space Shuttle or SpaceShipOne needed to deploy.
|
||||||
|
@ -77,6 +77,74 @@ class mstr_orthographic:
|
|||||||
return round(dm * 1000, 3)
|
return round(dm * 1000, 3)
|
||||||
|
|
||||||
|
|
||||||
|
# In this case we only want to acquire PBF for a latitude and longitude. Normally
|
||||||
|
# not needed for standard ortho generation.
|
||||||
|
def _generateData(self):
|
||||||
|
# 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("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.
|
||||||
|
for lat_grid in range(1, maxlatlng[0]+1):
|
||||||
|
for lng_grid in range(1, maxlatlng[1]+1):
|
||||||
|
# Adjust bounding box
|
||||||
|
osmxml.adjust_bbox(bb_lat, bb_lng, bb_lat_edge, bb_lng_edge)
|
||||||
|
|
||||||
|
osmxml.generate_osm(cur_tile_y, cur_tile_x) # <- This acquires current OSM info
|
||||||
|
|
||||||
|
# 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("orthographic", "Adjustment of longitude performed")
|
||||||
|
# Adjust peak longitude tile number
|
||||||
|
if cur_tile_x > top_lng:
|
||||||
|
top_lng = cur_tile_x
|
||||||
|
|
||||||
|
# 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("orthographic", "Adjustment of latitude performed")
|
||||||
|
# Adjust peak latitude number
|
||||||
|
if cur_tile_y > top_lat:
|
||||||
|
top_lat = cur_tile_y
|
||||||
|
|
||||||
|
|
||||||
# Builds and processes the tile with everything required, in one call.
|
# Builds and processes the tile with everything required, in one call.
|
||||||
def _buildTile(self):
|
def _buildTile(self):
|
||||||
mstr_msg("orthographic", "Beginning construction of tile")
|
mstr_msg("orthographic", "Beginning construction of tile")
|
||||||
@ -163,9 +231,6 @@ class mstr_orthographic:
|
|||||||
bb_lat = self._lat
|
bb_lat = self._lat
|
||||||
bb_lng = self._long
|
bb_lng = self._long
|
||||||
|
|
||||||
# For X-Plane scenery generation
|
|
||||||
xp_datagroup = 1
|
|
||||||
|
|
||||||
# Previously, I downloaded all XML files in one go - but to ease the
|
# 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
|
# stress on OSM servers and my server, we will do acquire the data
|
||||||
# only for the current processed part of the tile.
|
# only for the current processed part of the tile.
|
||||||
@ -363,4 +428,4 @@ class mstr_orthographic:
|
|||||||
lng = abs(int(self._long / 10) * 10)
|
lng = abs(int(self._long / 10) * 10)
|
||||||
earthnavdata.append(lat)
|
earthnavdata.append(lat)
|
||||||
earthnavdata.append(lng)
|
earthnavdata.append(lng)
|
||||||
return earthnavdata
|
return earthnavdata
|
||||||
|
78
osmxml.py
78
osmxml.py
@ -34,7 +34,27 @@ class mstr_osmxml:
|
|||||||
self._lng = round(lng, 4)
|
self._lng = round(lng, 4)
|
||||||
self._curB_lat = round(lat_e, 4)
|
self._curB_lat = round(lat_e, 4)
|
||||||
self._curB_lng = round(lng_e, 4)
|
self._curB_lng = round(lng_e, 4)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_osm(self, v, h, asobject=False):
|
||||||
|
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 = {
|
||||||
|
"bbox": {
|
||||||
|
"lat": str(self._lat),
|
||||||
|
"lng": str(self._lng),
|
||||||
|
"lat_b": str(self._curB_lat),
|
||||||
|
"lng_b": str(self._curB_lng)
|
||||||
|
},
|
||||||
|
"tile_lat": str(self._lat),
|
||||||
|
"tile_lng": str(self._lng),
|
||||||
|
"square_lat": str(v),
|
||||||
|
"square_lng": str(h),
|
||||||
|
"as_pbf": "true"
|
||||||
|
}
|
||||||
|
r = requests.post(mstr_osm_endpoint, json=data)
|
||||||
|
|
||||||
|
|
||||||
# Acquire XMLs in chunks, then store them
|
# Acquire XMLs in chunks, then store them
|
||||||
def acquire_osm(self, v, h, asobject=False):
|
def acquire_osm(self, v, h, asobject=False):
|
||||||
@ -65,7 +85,7 @@ class mstr_osmxml:
|
|||||||
# 1 second delay in case the request fails
|
# 1 second delay in case the request fails
|
||||||
if os.path.isfile(mstr_datafolder + "_cache/tile.xml") == False:
|
if os.path.isfile(mstr_datafolder + "_cache/tile.xml") == False:
|
||||||
sleep(1)
|
sleep(1)
|
||||||
|
|
||||||
# Provide the object directly
|
# Provide the object directly
|
||||||
if asobject == True:
|
if asobject == True:
|
||||||
xml_doc = xml.dom.minidom.parse("_cache/tile.xml")
|
xml_doc = xml.dom.minidom.parse("_cache/tile.xml")
|
||||||
@ -152,9 +172,9 @@ class mstr_osmxml:
|
|||||||
|
|
||||||
|
|
||||||
# Find the levels of a building (for shadow rendering)
|
# Find the levels of a building (for shadow rendering)
|
||||||
def find_building_levels(self, xmlfile, way_id):
|
def find_building_levels(self, way_id):
|
||||||
lvl = 3 # Standard if we don't find anything else
|
lvl = 2 # Standard if we don't find anything else
|
||||||
xml_doc = xml.dom.minidom.parse(xmlfile)
|
xml_doc = xml.dom.minidom.parse(mstr_datafolder + "_cache/tile.xml")
|
||||||
wpdata = xml_doc.getElementsByTagName("way")
|
wpdata = xml_doc.getElementsByTagName("way")
|
||||||
for wp in wpdata:
|
for wp in wpdata:
|
||||||
if wp.getAttribute("id") == way_id:
|
if wp.getAttribute("id") == way_id:
|
||||||
@ -167,6 +187,54 @@ class mstr_osmxml:
|
|||||||
break
|
break
|
||||||
return lvl
|
return lvl
|
||||||
|
|
||||||
|
# Find minimum level of a building
|
||||||
|
def find_building_minlevel(self, way_id):
|
||||||
|
lvl = 0 # Standard if we don't find anything else
|
||||||
|
xml_doc = xml.dom.minidom.parse(mstr_datafolder + "_cache/tile.xml")
|
||||||
|
wpdata = xml_doc.getElementsByTagName("way")
|
||||||
|
for wp in wpdata:
|
||||||
|
if wp.getAttribute("id") == way_id:
|
||||||
|
tags = wp.getElementsByTagName("tag")
|
||||||
|
for tag in tags:
|
||||||
|
a = tag.getAttribute("k")
|
||||||
|
v = tag.getAttribute("v")
|
||||||
|
if a == "building:min_level":
|
||||||
|
lvl = int(v)
|
||||||
|
break
|
||||||
|
return lvl
|
||||||
|
|
||||||
|
# Find the roof shape
|
||||||
|
def find_building_roof_shape(self, way_id):
|
||||||
|
rs = "flat" # Standard if we don't find anything else
|
||||||
|
xml_doc = xml.dom.minidom.parse(mstr_datafolder + "_cache/tile.xml")
|
||||||
|
wpdata = xml_doc.getElementsByTagName("way")
|
||||||
|
for wp in wpdata:
|
||||||
|
if wp.getAttribute("id") == way_id:
|
||||||
|
tags = wp.getElementsByTagName("tag")
|
||||||
|
for tag in tags:
|
||||||
|
a = tag.getAttribute("k")
|
||||||
|
v = tag.getAttribute("v")
|
||||||
|
if a == "roof:shape":
|
||||||
|
rs = v
|
||||||
|
break
|
||||||
|
return rs
|
||||||
|
|
||||||
|
# Find the roof levels
|
||||||
|
def find_building_roof_levels(self, way_id):
|
||||||
|
lvl = 0 # Standard if we don't find anything else
|
||||||
|
xml_doc = xml.dom.minidom.parse(mstr_datafolder + "_cache/tile.xml")
|
||||||
|
wpdata = xml_doc.getElementsByTagName("way")
|
||||||
|
for wp in wpdata:
|
||||||
|
if wp.getAttribute("id") == way_id:
|
||||||
|
tags = wp.getElementsByTagName("tag")
|
||||||
|
for tag in tags:
|
||||||
|
a = tag.getAttribute("k")
|
||||||
|
v = tag.getAttribute("v")
|
||||||
|
if a == "roof:levels":
|
||||||
|
lvl = int(v)
|
||||||
|
break
|
||||||
|
return lvl
|
||||||
|
|
||||||
|
|
||||||
# It turns out that some features hide themselves in the relations section.
|
# It turns out that some features hide themselves in the relations section.
|
||||||
# I figured this out during testing, and almost going insane over the
|
# I figured this out during testing, and almost going insane over the
|
||||||
@ -191,4 +259,4 @@ class mstr_osmxml:
|
|||||||
tgd.append(i.getAttribute("v"))
|
tgd.append(i.getAttribute("v"))
|
||||||
rls.append((rp.getAttribute("ref"), tgd))
|
rls.append((rp.getAttribute("ref"), tgd))
|
||||||
return rls
|
return rls
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user