Change to zoom level 16, attempt to generate contour maps for each OSM tag. Not yet complete. Perlin implementation to follow. Switched to local storage of XML data.

This commit is contained in:
Marcus Str. 2025-01-17 20:31:56 +01:00
parent e82ecc9d32
commit c77002b930
4 changed files with 92 additions and 62 deletions

View File

@ -15,11 +15,13 @@
# stored. # stored.
#mstr_datafolder = "M:/Developer/Projects/orthographic/" #mstr_datafolder = "M:/Developer/Projects/orthographic/"
mstr_datafolder = "D:/Developer/Projects/orthographic/" mstr_datafolder = "D:/Developer/Projects/orthographic/"
#mstr_datafolder = "/home/marcus/Developer/Projects/orthographic/"
# Switched to Linux, so path is amended # Switched to Linux, so path is amended
# API endpoint to acquire OSM data (bonus: I have my own) # API endpoint to acquire OSM data (bonus: I have my own)
mstr_osm_endpoint = "https://marstr.online/osm/v1/" #mstr_osm_endpoint = "https://marstr.online/osm/v1/"
mstr_osm_endpoint = "http://localhost/og.php"
# Define the texture resolution you want to have your photos at. # Define the texture resolution you want to have your photos at.
mstr_photores = 2048 mstr_photores = 2048
@ -100,7 +102,7 @@ mstr_xp_normal_maps = [
# How much of a tile we need for each zoom level. The higher # How much of a tile we need for each zoom level. The higher
# the zoom level, the smaller the area to generate a mask of - but also # the zoom level, the smaller the area to generate a mask of - but also
# higher detail. # higher detail.
mstr_zl_16 = 0.08 mstr_zl_16 = 0.064
mstr_zl_17 = 0.048 mstr_zl_17 = 0.048
mstr_zl_18 = 0.016 mstr_zl_18 = 0.016
mstr_zl_19 = 0.008 mstr_zl_19 = 0.008

View File

@ -37,6 +37,7 @@ class mstr_maskgen:
self._vstep = vstep self._vstep = vstep
self._scale = 1 / math.cos(math.radians(self._box[0])) self._scale = 1 / math.cos(math.radians(self._box[0]))
self._isline = isline self._isline = isline
self._zoomlevel = mstr_zl_16
#mstr_msg("maskgen", "Intialized mask gen.") #mstr_msg("maskgen", "Intialized mask gen.")
@ -98,8 +99,8 @@ class mstr_maskgen:
bbox.append(self._box[0] + ((self._box[1]-1) * self._vstep)) bbox.append(self._box[0] + ((self._box[1]-1) * self._vstep))
bbox.append(self._box[0] + ((self._box[1]-1) * self._vstep) + self._vstep) bbox.append(self._box[0] + ((self._box[1]-1) * self._vstep) + self._vstep)
# Longitude # Longitude
bbox.append(self._box[2] + ((self._box[3]-1) * mstr_zl_18)) bbox.append(self._box[2] + ((self._box[3]-1) * self._zoomlevel))
bbox.append(self._box[2] + ((self._box[3]-1) * mstr_zl_18) + mstr_zl_18) bbox.append(self._box[2] + ((self._box[3]-1) * self._zoomlevel) + self._zoomlevel)
# Building levels, if this is a building # Building levels, if this is a building
bld_levels = 0 bld_levels = 0
@ -213,7 +214,7 @@ class mstr_maskgen:
# of the building in this loop. # of the building in this loop.
if mstr_shadow_enabled == True and is_prep == False: if mstr_shadow_enabled == True and is_prep == False:
if self._tag == "building": if self._tag == "building":
mpp = meters_per_pixel(self._tile_width) * mstr_zl_18 mpp = meters_per_pixel(self._tile_width) * self._zoomlevel
pix_per_floor = mstr_shadow_floor_h / mpp pix_per_floor = mstr_shadow_floor_h / mpp
total_pix = pix_per_floor * bld_levels total_pix = pix_per_floor * bld_levels
shift = int(total_pix) shift = int(total_pix)

View File

@ -30,6 +30,7 @@ class mstr_orthographic:
# Constructor of class. Takes longitude and latitude. # Constructor of class. Takes longitude and latitude.
def __init__(self, lat, lng, outfolder, pwd, prep=False): def __init__(self, lat, lng, outfolder, pwd, prep=False):
self._zoomlevel = mstr_zl_16
self._lat = lat self._lat = lat
self._long = lng self._long = lng
self._output = outfolder self._output = outfolder
@ -68,7 +69,7 @@ class mstr_orthographic:
# orthos can only be a power of 2, such as 2048x2048 # orthos can only be a power of 2, such as 2048x2048
def _findVerticalStepping(self): def _findVerticalStepping(self):
scale = 1 / math.cos(math.radians(self._lat)) scale = 1 / math.cos(math.radians(self._lat))
maxlat = (1 / scale) * mstr_zl_18 maxlat = (1 / scale) * self._zoomlevel
return maxlat return maxlat
@ -90,7 +91,7 @@ class mstr_orthographic:
bb_lat = self._lat bb_lat = self._lat
bb_lng = self._long bb_lng = self._long
bb_lat_edge = self._lat+self._vstep bb_lat_edge = self._lat+self._vstep
bb_lng_edge = self._long+mstr_zl_18 bb_lng_edge = self._long+self._zoomlevel
cur_tile_x = 1 cur_tile_x = 1
cur_tile_y = 1 cur_tile_y = 1
osmxml = mstr_osmxml(0,0) osmxml = mstr_osmxml(0,0)
@ -109,7 +110,7 @@ class mstr_orthographic:
bb_lat = bb_lat + self._vstep bb_lat = bb_lat + self._vstep
mlat = mlat+1 mlat = mlat+1
while bb_lng < self._long + 1: while bb_lng < self._long + 1:
bb_lng = bb_lng + mstr_zl_18 bb_lng = bb_lng + self._zoomlevel
mlng = mlng+1 mlng = mlng+1
mstr_msg("orthographic", "Max lat tile: " + str(mlat) + " - max lng tile: " + str(mlng)) mstr_msg("orthographic", "Max lat tile: " + str(mlat) + " - max lng tile: " + str(mlng))
maxlatlng = [ mlat, mlng ] maxlatlng = [ mlat, mlng ]
@ -130,8 +131,8 @@ class mstr_orthographic:
# Adjust longitude coordinates # Adjust longitude coordinates
cur_tile_x = cur_tile_x+1 cur_tile_x = cur_tile_x+1
bb_lng = bb_lng + mstr_zl_18 bb_lng = bb_lng + self._zoomlevel
bb_lng_edge = bb_lng_edge + mstr_zl_18 bb_lng_edge = bb_lng_edge + self._zoomlevel
mstr_msg("orthographic", "Adjustment of longitude performed") mstr_msg("orthographic", "Adjustment of longitude performed")
# Adjust peak longitude tile number # Adjust peak longitude tile number
if cur_tile_x > top_lng: if cur_tile_x > top_lng:
@ -141,7 +142,7 @@ class mstr_orthographic:
cur_tile_y = cur_tile_y+1 cur_tile_y = cur_tile_y+1
cur_tile_x = 1 cur_tile_x = 1
bb_lng = self._long bb_lng = self._long
bb_lng_edge = self._long + mstr_zl_18 bb_lng_edge = self._long + self._zoomlevel
bb_lat = bb_lat + self._vstep bb_lat = bb_lat + self._vstep
bb_lat_edge = bb_lat_edge + self._vstep bb_lat_edge = bb_lat_edge + self._vstep
mstr_msg("orthographic", "Adjustment of latitude performed") mstr_msg("orthographic", "Adjustment of latitude performed")
@ -159,14 +160,14 @@ class mstr_orthographic:
bb_lat = self._lat bb_lat = self._lat
bb_lng = self._long bb_lng = self._long
bb_lat_edge = self._lat+self._vstep bb_lat_edge = self._lat+self._vstep
bb_lng_edge = self._long+mstr_zl_18 bb_lng_edge = self._long+self._zoomlevel
mlat = 1 mlat = 1
mlng = 1 mlng = 1
while bb_lat < self._lat + 1: while bb_lat < self._lat + 1:
bb_lat = bb_lat + self._vstep bb_lat = bb_lat + self._vstep
mlat = mlat+1 mlat = mlat+1
while bb_lng < self._long + 1: while bb_lng < self._long + 1:
bb_lng = bb_lng + mstr_zl_18 bb_lng = bb_lng + self._zoomlevel
mlng = mlng+1 mlng = mlng+1
mstr_msg("orthographic", "Max lat tile: " + str(mlat) + " - max lng tile: " + str(mlng)) mstr_msg("orthographic", "Max lat tile: " + str(mlat) + " - max lng tile: " + str(mlng))
maxlatlng = [ mlat, mlng ] maxlatlng = [ mlat, mlng ]
@ -197,7 +198,7 @@ class mstr_orthographic:
bb_lat = self._lat bb_lat = self._lat
bb_lng = self._long bb_lng = self._long
bb_lat_edge = self._lat+self._vstep bb_lat_edge = self._lat+self._vstep
bb_lng_edge = self._long+mstr_zl_18 bb_lng_edge = self._long+self._zoomlevel
# We need to know the highest possible latitude and longitude tile numbers, # We need to know the highest possible latitude and longitude tile numbers,
# in case we render at the edge # in case we render at the edge
@ -207,7 +208,7 @@ class mstr_orthographic:
bb_lat = bb_lat + self._vstep bb_lat = bb_lat + self._vstep
mlat = mlat+1 mlat = mlat+1
while bb_lng < self._long + 1: while bb_lng < self._long + 1:
bb_lng = bb_lng + mstr_zl_18 bb_lng = bb_lng + self._zoomlevel
mlng = mlng+1 mlng = mlng+1
mstr_msg("orthographic", "Max lat tile: " + str(mlat) + " - max lng tile: " + str(mlng)) mstr_msg("orthographic", "Max lat tile: " + str(mlat) + " - max lng tile: " + str(mlng))
maxlatlng = [ mlat, mlng ] maxlatlng = [ mlat, mlng ]
@ -217,9 +218,9 @@ class mstr_orthographic:
if os.path.isfile(ddsf) == False: if os.path.isfile(ddsf) == False:
# Reset these two # Reset these two
bb_lat = self._lat + ((grid_lat-1)*self._vstep) bb_lat = self._lat + ((grid_lat-1)*self._vstep)
bb_lng = self._long + ((grid_lng-1)*mstr_zl_18) bb_lng = self._long + ((grid_lng-1)*self._zoomlevel)
bb_lat_edge = self._lat + ((grid_lat-1)*self._vstep) + self._vstep bb_lat_edge = self._lat + ((grid_lat-1)*self._vstep) + self._vstep
bb_lng_edge = self._long + ((grid_lng-1)*mstr_zl_18) + mstr_zl_18 bb_lng_edge = self._long + ((grid_lng-1)*self._zoomlevel) + self._zoomlevel
osmxml = mstr_osmxml() osmxml = mstr_osmxml()
osmxml.adjust_bbox(bb_lat, bb_lng, bb_lat_edge, bb_lng_edge) osmxml.adjust_bbox(bb_lat, bb_lng, bb_lat_edge, bb_lng_edge)
@ -355,7 +356,7 @@ class mstr_orthographic:
bb_lat = self._lat bb_lat = self._lat
bb_lng = self._long bb_lng = self._long
bb_lat_edge = self._lat+self._vstep bb_lat_edge = self._lat+self._vstep
bb_lng_edge = self._long+mstr_zl_18 bb_lng_edge = self._long+self._zoomlevel
cur_tile_x = 1 cur_tile_x = 1
cur_tile_y = 1 cur_tile_y = 1
#osmxml = mstr_osmxml(0,0) #osmxml = mstr_osmxml(0,0)
@ -374,7 +375,7 @@ class mstr_orthographic:
bb_lat = bb_lat + self._vstep bb_lat = bb_lat + self._vstep
mlat = mlat+1 mlat = mlat+1
while bb_lng < self._long + 1: while bb_lng < self._long + 1:
bb_lng = bb_lng + mstr_zl_18 bb_lng = bb_lng + self._zoomlevel
mlng = mlng+1 mlng = mlng+1
mstr_msg("orthographic", "Max lat tile: " + str(mlat) + " - max lng tile: " + str(mlng)) mstr_msg("orthographic", "Max lat tile: " + str(mlat) + " - max lng tile: " + str(mlng))
maxlatlng = [ mlat, mlng ] maxlatlng = [ mlat, mlng ]
@ -387,8 +388,8 @@ class mstr_orthographic:
contours = [] contours = []
# Generate images for all resources # Generate images for all resources
cnt_w = mlng * 20 cnt_w = mlng * 80
cnt_h = mlat * 20 cnt_h = mlat * 80
for l in mstr_ortho_layers: for l in mstr_ortho_layers:
if l[0] != "building": if l[0] != "building":
cntimg = Image.new("RGBA", (cnt_w, cnt_h), (255,255,255,255)) cntimg = Image.new("RGBA", (cnt_w, cnt_h), (255,255,255,255))
@ -401,6 +402,11 @@ class mstr_orthographic:
# 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.
# Total number of tiles to be generated
total_tiles = mlng * mlat
nextstep = 20
mstr_important_msg("orthographic", "Generating map data required to build orthos")
for lat_grid in range(1, maxlatlng[0]+1): for lat_grid in range(1, maxlatlng[0]+1):
for lng_grid in range(1, maxlatlng[1]+1): for lng_grid in range(1, maxlatlng[1]+1):
# Adjust bounding box # Adjust bounding box
@ -422,7 +428,7 @@ class mstr_orthographic:
mg = mstr_maskgen( [self._lat, cur_tile_y, self._long, cur_tile_x], self._vstep, layer[0], layer[1], layer[2]) mg = mstr_maskgen( [self._lat, cur_tile_y, self._long, cur_tile_x], self._vstep, layer[0], layer[1], layer[2])
mask = mg._build_mask(osmxml, is_prep=True) # We need an object here mask = mg._build_mask(osmxml, is_prep=True) # We need an object here
mask = mask.resize((20,20), Image.Resampling.BILINEAR) mask = mask.resize((80,80), Image.Resampling.BILINEAR)
idx = 0 idx = 0
for c in contours: for c in contours:
if c[0] == layer[0] and c[1] == layer[1]: if c[0] == layer[0] and c[1] == layer[1]:
@ -430,8 +436,8 @@ class mstr_orthographic:
else: else:
idx=idx+1 idx=idx+1
cnx = (lng_grid-1) * 20 cnx = (lng_grid-1) * 80
cny = cnt_h - (lat_grid * 20) cny = cnt_h - (lat_grid * 80)
contours[idx][2].alpha_composite(mask, dest=(cnx,cny)) contours[idx][2].alpha_composite(mask, dest=(cnx,cny))
#tp = mstr_tileprep(self._lat, self._long, lat_grid, lng_grid, layer[0], layer[1], mask, False) #tp = mstr_tileprep(self._lat, self._long, lat_grid, lng_grid, layer[0], layer[1], mask, False)
@ -441,18 +447,25 @@ class mstr_orthographic:
# Adjust longitude coordinates # Adjust longitude coordinates
cur_tile_x = cur_tile_x+1 cur_tile_x = cur_tile_x+1
bb_lng = bb_lng + mstr_zl_18 bb_lng = bb_lng + self._zoomlevel
bb_lng_edge = bb_lng_edge + mstr_zl_18 bb_lng_edge = bb_lng_edge + self._zoomlevel
mstr_msg("orthographic", "Adjustment of longitude performed") mstr_msg("orthographic", "Adjustment of longitude performed")
# Adjust peak longitude tile number # Adjust peak longitude tile number
if cur_tile_x > top_lng: if cur_tile_x > top_lng:
top_lng = cur_tile_x top_lng = cur_tile_x
totaldata = glob.glob("D:/Developer/webserver/htdocs/server/osm/*.xml")
progress = int( (len(totaldata) / total_tiles) * 100 )
if progress >= nextstep:
mstr_important_msg("orthographic", str(progress) + " percent complete")
nextstep = nextstep + 20
# Adjust latitude and all other values when we get here # Adjust latitude and all other values when we get here
cur_tile_y = cur_tile_y+1 cur_tile_y = cur_tile_y+1
cur_tile_x = 1 cur_tile_x = 1
bb_lng = self._long bb_lng = self._long
bb_lng_edge = self._long + mstr_zl_18 bb_lng_edge = self._long + self._zoomlevel
bb_lat = bb_lat + self._vstep bb_lat = bb_lat + self._vstep
bb_lat_edge = bb_lat_edge + self._vstep bb_lat_edge = bb_lat_edge + self._vstep
mstr_msg("orthographic", "Adjustment of latitude performed") mstr_msg("orthographic", "Adjustment of latitude performed")
@ -526,12 +539,12 @@ class mstr_orthographic:
bb_lat = self._lat bb_lat = self._lat
bb_lng = self._long bb_lng = self._long
bb_lat_edge = self._lat+self._vstep bb_lat_edge = self._lat+self._vstep
bb_lng_edge = self._long+mstr_zl_18 bb_lng_edge = self._long+self._zoomlevel
while bb_lat < self._lat + 1: while bb_lat < self._lat + 1:
bb_lat = bb_lat + self._vstep bb_lat = bb_lat + self._vstep
mlat = mlat+1 mlat = mlat+1
while bb_lng < self._long + 1: while bb_lng < self._long + 1:
bb_lng = bb_lng + mstr_zl_18 bb_lng = bb_lng + self._zoomlevel
mlng = mlng+1 mlng = mlng+1
mstr_msg("orthographic", "Max lat tile: " + str(mlat) + " - max lng tile: " + str(mlng)) mstr_msg("orthographic", "Max lat tile: " + str(mlat) + " - max lng tile: " + str(mlng))
maxlatlng = [ mlat, mlng ] maxlatlng = [ mlat, mlng ]

View File

@ -63,42 +63,56 @@ class mstr_osmxml:
# Acquire XMLs in chunks, then store them # Acquire XMLs in chunks, then store them
def acquire_osm(self, v, h): def acquire_osm(self, v, h):
mstr_msg("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.
parse = False
while parse == False:
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)
}
r = requests.post(mstr_osm_endpoint, json=data)
try: # We switched to a local storage model to ease load on the server. We will check if we already have the data we need.
# Attempt to parse the XML string # If not, go an acquire it.
dom = xml.dom.minidom.parseString(r.content) fn = mstr_datafolder + "z_orthographic/data/+++++/osm/" + str(self._lat) + "-" + str(v) + "_" + str(self._lng) + "-" + str(h) + ".xml"
if os.path.isfile(fn) == False:
# We will use our self-hosted API for this.
parse = False
while parse == False:
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)
}
r = requests.post(mstr_osm_endpoint, json=data)
# Check if the DOM object has a document element try:
if dom.documentElement: # Attempt to parse the XML string
# Store the content in memory dom = xml.dom.minidom.parseString(r.content)
self._xmlcontent = r.content
self._xmldata = xml.dom.minidom.parseString(self._xmlcontent)
self._xmlcontent = "" # Clear
parse = True
except ExpatError as e: # Check if the DOM object has a document element
parse = False if dom.documentElement:
time.sleep(1) # Store the content in memory
except Exception as e: self._xmlcontent = r.content
parse = False self._xmldata = xml.dom.minidom.parseString(self._xmlcontent)
time.sleep(1) self._xmlcontent = "" # Clear
parse = True
except ExpatError as e:
parse = False
time.sleep(1)
except Exception as e:
parse = False
time.sleep(1)
else:
# Attempt to parse the XML string
dom = xml.dom.minidom.parse(fn)
# Check if the DOM object has a document element
if dom.documentElement:
# Store the content in memory
self._xmlcontent = r.content
self._xmldata = xml.dom.minidom.parseString(self._xmlcontent)
self._xmlcontent = "" # Clear
# Get all nodes from the specified OSM file # Get all nodes from the specified OSM file