Added textures. Changes to shadow generation. Refinements to layers and blurs. Made sure roads appear correctly. Removed streams for inland cutting as those are barely visible on actual satellite images. Proper testing to be done, close to public release.
35
defines.py
@ -22,7 +22,7 @@ mstr_datafolder = "/home/marcus/Data/Developer/Projects/orthographic/"
|
||||
mstr_osm_endpoint = "https://marstr.online/osm/v1/"
|
||||
|
||||
# Define the texture resolution you want to have your photos at.
|
||||
mstr_photores = 2048 # <- Change this to 4096 for 16k resolution
|
||||
mstr_photores = 2048
|
||||
|
||||
# Radius of zoom level 18 aerials around airports with ICAO code
|
||||
# Value is in tiles - not in km
|
||||
@ -54,20 +54,13 @@ mstr_show_log = True
|
||||
# You can, however, disable the shadow rendering layer here.
|
||||
mstr_shadow_enabled = True
|
||||
mstr_shadow_strength = 0.65
|
||||
mstr_shadow_shift = 15
|
||||
mstr_shadow_shift = 16
|
||||
mstr_shadow_floor_h = 2.8 # 2.5m ceiling height + 30cm concrete per floor
|
||||
# The tags that cast shadows
|
||||
mstr_shadow_casters = [
|
||||
("landuse", "forest"),
|
||||
("leisure", "nature_reserve"),
|
||||
("natural", "wood"),
|
||||
("natural", "tree_row"),
|
||||
("building", "semidetached_house"),
|
||||
("building", "apartments"),
|
||||
("building", "garage"),
|
||||
("building", "office"),
|
||||
("building", "retail"),
|
||||
("building", "industrial"),
|
||||
("building", "yes")
|
||||
("natural", "wood")
|
||||
]
|
||||
|
||||
|
||||
@ -248,19 +241,19 @@ mstr_mask_blur = [
|
||||
("water", "river", 10),
|
||||
("leisure", "swimming_pool", 10),
|
||||
("waterway", "river", 10),
|
||||
("waterway", "stream", 2),
|
||||
("waterway", "stream", 4),
|
||||
("amenity", "parking", 1),
|
||||
("amenity", "school", 1),
|
||||
("highway", "pedestrian", 12),
|
||||
# Z-Order 4
|
||||
("highway", "motorway", 2),
|
||||
("highway", "primary", 2),
|
||||
("highway", "secondary", 2),
|
||||
("highway", "tertiary", 2),
|
||||
("highway", "unclassified", 2),
|
||||
("highway", "living_street", 2),
|
||||
("highway", "residential", 2),
|
||||
("highway", "service", 2),
|
||||
("highway", "motorway", 1),
|
||||
("highway", "primary", 1),
|
||||
("highway", "secondary", 1),
|
||||
("highway", "tertiary", 1),
|
||||
("highway", "unclassified", 1),
|
||||
("highway", "living_street", 1),
|
||||
("highway", "residential", 1),
|
||||
("highway", "service", 1),
|
||||
("highway", "footway", 2),
|
||||
("highway", "track", 2),
|
||||
("highway", "path", 2),
|
||||
@ -395,8 +388,6 @@ mstr_building_base_colors = [
|
||||
]
|
||||
),
|
||||
("yes", [
|
||||
"#693333", "#592b2b", "#513434", "#4a1e1e", "#362626",
|
||||
"#534136", "#4d3424", "#534b45", "#553724", "#574c45",
|
||||
"#373942", "#40424a", "#363b4f", "#2c2d32", "#444651",
|
||||
"#454545", "#39393b", "#4b4b4c", "#363638", "#525252"
|
||||
]
|
||||
|
@ -86,3 +86,8 @@ def in_circle(center_x, center_y, radius, x, y):
|
||||
return square_dist <= radius ** 2
|
||||
|
||||
|
||||
# Find meters per pixel. Requires width of tile in meters
|
||||
# Needed for proper approximation of shadow length per building level
|
||||
def meters_per_pixel(lngwidth):
|
||||
mpx = lngwidth / mstr_photores
|
||||
return mpx
|
||||
|
161
layergen.py
@ -87,11 +87,13 @@ class mstr_layergen:
|
||||
brd_src = Image.open(root_folder + "/brd/b" + str(src) + ".png")
|
||||
ptc_src = []
|
||||
for p in ptc:
|
||||
ptc_src.append(Image.open(p))
|
||||
pimg = Image.open(p)
|
||||
pimg = pimg.rotate(randrange(0, 360), expand=True)
|
||||
ptc_src.append(pimg)
|
||||
mstr_msg("layergen", "Border sources selected")
|
||||
|
||||
# Begin producing a largely random image
|
||||
samples = 250 # <- We need this in a moment
|
||||
samples = 250 # <- We need this in a moment
|
||||
for i in range(samples):
|
||||
imgid = 0
|
||||
if len(ptc_src) == 1: imgid = 0
|
||||
@ -455,13 +457,28 @@ class mstr_layergen:
|
||||
|
||||
# Add trees only in some features
|
||||
if (self._tag == "landuse" and self._value == "cemetery") or (self._tag == "landuse" and self._value == "residential") or (self._tag == "leisure" and self._value == "park"):
|
||||
trees = Image.new("RGBA", (self._imgsize, self._imgsize))
|
||||
amt = 3500
|
||||
for i in range(1, amt+1):
|
||||
p = randrange(1, 11)
|
||||
p = randrange(1, 16)
|
||||
tree = Image.open(mstr_datafolder + "textures/building/area/p" + str(p) + ".png")
|
||||
lx = randrange( self._imgsize - tree.width )
|
||||
ly = randrange( self._imgsize - tree.height )
|
||||
layer.alpha_composite(tree, (lx, ly))
|
||||
trees.alpha_composite(tree, (lx, ly))
|
||||
|
||||
tree_shadow = Image.new("RGBA", (self._imgsize, self._imgsize))
|
||||
tree_pix = trees.load()
|
||||
shadow_pix = tree_shadow.load()
|
||||
for y in range(self._imgsize):
|
||||
for x in range(self._imgsize):
|
||||
tp = tree_pix[x,y]
|
||||
if tp[3] > 0:
|
||||
sc = (0,0,0,180)
|
||||
if x+8 < self._imgsize and y+5 < self._imgsize:
|
||||
shadow_pix[x+8,y+5] = sc
|
||||
tree_shadow = tree_shadow.filter(ImageFilter.GaussianBlur(radius=2))
|
||||
tree_shadow.alpha_composite(trees)
|
||||
layer.alpha_composite(tree_shadow)
|
||||
|
||||
mstr_msg("layergen", "Layer image completed")
|
||||
|
||||
@ -527,9 +544,21 @@ class mstr_layergen:
|
||||
if self._tag == "landuse" and self._value == "forest":
|
||||
# The residential layer MUST exist before we reach the forest part.
|
||||
fn = mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_landuse-residential_layer.png"
|
||||
if os.path.isfile(fn) == True:
|
||||
if os.path.isfile(fn):
|
||||
rsd = Image.open(fn)
|
||||
layer_comp.alpha_composite(rsd)
|
||||
rsd_pix = rsd.load()
|
||||
forest_layer = Image.new("RGBA", (self._imgsize, self._imgsize))
|
||||
for_pix = forest_layer.load()
|
||||
for y in range(self._imgsize):
|
||||
for x in range(self._imgsize):
|
||||
rpix = rsd_pix[x,y]
|
||||
lpix = layer_comp_pix[x,y]
|
||||
if rpix[3] > 0 and lpix[3] > 0:
|
||||
for_pix[x,y] = (rpix[0], rpix[1], rpix[2], rpix[3])
|
||||
layer_comp.alpha_composite(forest_layer)
|
||||
#if os.path.isfile(fn) == True:
|
||||
# rsd = Image.open(fn)
|
||||
# layer_comp.alpha_composite(rsd)
|
||||
|
||||
# Store layer
|
||||
if self._is_completion == False:
|
||||
@ -563,18 +592,40 @@ class mstr_layergen:
|
||||
mstr_msg("layergen", "Generating shadow for layer")
|
||||
shadow_pix = shadow.load()
|
||||
mask_pix = osm_mask.load()
|
||||
shf = 1
|
||||
while shf < mstr_shadow_shift:
|
||||
for y in range(self._imgsize):
|
||||
for x in range(self._imgsize):
|
||||
mp = layer_comp_pix[x,y]
|
||||
if mp[3] == 255:
|
||||
if x+(shf*2) < self._imgsize and y+shf < self._imgsize:
|
||||
rndshd = randrange(5, 210)
|
||||
shadow_pix[x+(shf*2), y+shf] = (0,0,0,rndshd)
|
||||
shf = shf+1
|
||||
|
||||
# Tree removal
|
||||
for y in range(self._imgsize):
|
||||
for x in range(self._imgsize):
|
||||
lp = layer_comp_pix[x,y]
|
||||
if lp[3] >= 250:
|
||||
shadow_pix[x,y] = (0,0,0,0)
|
||||
|
||||
shadow = shadow.filter(ImageFilter.GaussianBlur(radius=2))
|
||||
|
||||
"""
|
||||
for y in range(self._imgsize-1):
|
||||
for x in range(self._imgsize-1):
|
||||
m = mask_pix[x,y]
|
||||
shf_x = 0
|
||||
shf_x = x + mstr_shadow_shift
|
||||
if shf_x <= self._imgsize-1:
|
||||
if shf_x < self._imgsize:
|
||||
a = mask_pix[x,y][3]
|
||||
st = 0
|
||||
st = random.uniform(0.45, mstr_shadow_strength)
|
||||
ca = a * st
|
||||
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("layergen", "Shadow layer completed")
|
||||
|
||||
@ -643,7 +694,7 @@ class mstr_layergen:
|
||||
#self._tiledb.close_db()
|
||||
|
||||
# Create a water mask we need to remove from the DDS later
|
||||
if (self._tag == "natural" and self._value == "water") or (self._tag == "water" and self._value == "lake") or (self._tag == "water" and self._value == "pond") or (self._tag == "water" and self._value == "river") or (self._tag == "leisure" and self._value == "swimming_pool") or (self._tag == "waterway" and self._value == "stream"):
|
||||
if (self._tag == "natural" and self._value == "water") or (self._tag == "water" and self._value == "lake") or (self._tag == "water" and self._value == "pond") or (self._tag == "water" and self._value == "river") or (self._tag == "leisure" and self._value == "swimming_pool"):
|
||||
mstr_msg("layergen", "Generating inland water mask")
|
||||
inl_mask = Image.new("RGBA", (self._imgsize, self._imgsize), (0,0,0,0))
|
||||
lyr_pix = layer_comp.load()
|
||||
@ -681,7 +732,6 @@ class mstr_layergen:
|
||||
if i[0] == self._tag and i[1] == self._value:
|
||||
osm_mask = osm_mask.filter(ImageFilter.BoxBlur(radius=i[2]))
|
||||
break
|
||||
osm_edge = osm_edge.filter(ImageFilter.BoxBlur(radius=1))
|
||||
|
||||
|
||||
# And now for the Big Mac.
|
||||
@ -712,14 +762,15 @@ class mstr_layergen:
|
||||
d = randrange(41, 61)
|
||||
layer_comp_pix[x, y] = ( d,d,d,a[3] )
|
||||
if self._tag == "highway" and self._value != "motorway":
|
||||
d = randrange(85, 101)
|
||||
layer_comp_pix[x, y] = ( d,d,d,a[3] )
|
||||
dr = randrange(110,121)
|
||||
dg = randrange(110,121)
|
||||
db = randrange(115,130)
|
||||
layer_comp_pix[x, y] = ( dr,dg,db,a[3] )
|
||||
if self._tag == "highway" and self._value == "motorway":
|
||||
d = randrange(1,20)
|
||||
r = 86-d
|
||||
g = 97-d
|
||||
b = 106-d
|
||||
layer_comp_pix[x, y] = ( r,g,b,a[3] )
|
||||
dr = randrange(77,89)
|
||||
dg = randrange(88,96)
|
||||
db = randrange(90,101)
|
||||
layer_comp_pix[x, y] = ( dr,dg,db,a[3] )
|
||||
if self._tag == "waterway" and (self._value == "stream" or self._value == "river"):
|
||||
d = randrange(1, 15)
|
||||
# Rock, grass, water
|
||||
@ -730,7 +781,7 @@ class mstr_layergen:
|
||||
t = a[3]-d
|
||||
if t < 0: t = 0
|
||||
if e[3] > 0:
|
||||
layer_comp_pix[x, y] = ( mats[pick-1][0], mats[pick-1][1], mats[pick-1][2], t )
|
||||
layer_comp_pix[x, y] = ( mats[pick-1][0], mats[pick-1][1], mats[pick-1][2], 35 )
|
||||
|
||||
# A bit special here
|
||||
if self._tag == "building":
|
||||
@ -757,15 +808,31 @@ class mstr_layergen:
|
||||
|
||||
# A bit different for tree rows
|
||||
if self._tag == "natural" and self._value == "tree_row":
|
||||
trees = Image.new("RGBA", (self._imgsize, self._imgsize))
|
||||
for t in range(20001):
|
||||
lx = randrange(self._imgsize)
|
||||
ly = randrange(self._imgsize)
|
||||
a = mask_pix[lx,ly]
|
||||
if a[3] > 0:
|
||||
if lx < self._imgsize and ly < self._imgsize:
|
||||
p = randrange(1,11)
|
||||
p = randrange(1,16)
|
||||
tree = Image.open(mstr_datafolder + "textures/building/area/p" + str(p) + ".png")
|
||||
layer_comp.alpha_composite(tree, (lx, ly))
|
||||
trees.alpha_composite(tree, (lx, ly))
|
||||
if mstr_shadow_enabled == True:
|
||||
tree_shadow = Image.new("RGBA", (self._imgsize, self._imgsize))
|
||||
tree_pix = trees.load()
|
||||
shadow_pix = tree_shadow.load()
|
||||
for y in range(self._imgsize):
|
||||
for x in range(self._imgsize):
|
||||
tp = tree_pix[x,y]
|
||||
if tp[3] > 0:
|
||||
rndshd = randrange(5, 210)
|
||||
sc = (0,0,0,rndshd)
|
||||
if x+8 < self._imgsize and y+5 < self._imgsize:
|
||||
shadow_pix[x+8,y+5] = sc
|
||||
tree_shadow = tree_shadow.filter(ImageFilter.GaussianBlur(radius=2))
|
||||
tree_shadow.alpha_composite(trees)
|
||||
layer_comp.alpha_composite(tree_shadow)
|
||||
|
||||
# We will do some super magic here to let houses look more realistic
|
||||
if self._tag == "building":
|
||||
@ -815,7 +882,7 @@ class mstr_layergen:
|
||||
numtrees = randrange(1, 16)
|
||||
for i in range(1, numtrees+1):
|
||||
# Pick some file
|
||||
pick = str(randrange(1, 11))
|
||||
pick = str(randrange(1, 16))
|
||||
tree = Image.open(mstr_datafolder + "textures/building/area/p" + pick + ".png")
|
||||
# Do a correction for the location if needed
|
||||
if shf_x < 1: shf_x = 1
|
||||
@ -823,33 +890,39 @@ class mstr_layergen:
|
||||
if shf_x > self._imgsize - tree.width: shf_x = self._imgsize - tree.width - 1
|
||||
if shf_y > self._imgsize - tree.height: shf_y = self._imgsize - tree.height - 1
|
||||
trees.alpha_composite(tree, (shf_x, shf_y))
|
||||
trees.alpha_composite(layer_comp)
|
||||
layer_comp = trees
|
||||
|
||||
|
||||
if mstr_shadow_enabled == True:
|
||||
tree_shadow = Image.new("RGBA", (self._imgsize, self._imgsize))
|
||||
tree_pix = trees.load()
|
||||
shadow_pix = tree_shadow.load()
|
||||
for y in range(self._imgsize):
|
||||
for x in range(self._imgsize):
|
||||
tp = tree_pix[x,y]
|
||||
if tp[3] > 0:
|
||||
sc = (0,0,0,180)
|
||||
if x+8 < self._imgsize and y+5 < self._imgsize:
|
||||
shadow_pix[x+8,y+5] = sc
|
||||
tree_shadow = tree_shadow.filter(ImageFilter.GaussianBlur(radius=2))
|
||||
tree_shadow.alpha_composite(trees)
|
||||
|
||||
# Save this separately, so that we can blur buildings, but not the trees
|
||||
fn = mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_layer_building_trees.png"
|
||||
|
||||
if os.path.isfile(fn) == True:
|
||||
extrees = Image.open(fn)
|
||||
extrees.alpha_composite(tree_shadow)
|
||||
extrees.save(fn)
|
||||
else:
|
||||
tree_shadow.save(fn)
|
||||
|
||||
#layer_comp.alpha_composite(tree_shadow)
|
||||
#tree_shadow.alpha_composite(layer_comp)
|
||||
#layer_comp = tree_shadow
|
||||
|
||||
mstr_msg("layergen", "Layer image generated")
|
||||
|
||||
# Building shadow
|
||||
if mstr_shadow_enabled == True:
|
||||
if self._tag == "building":
|
||||
mstr_msg("layergen", "Generating shadow for layer")
|
||||
shadow = Image.new("RGBA", (self._imgsize, self._imgsize))
|
||||
shadow_pix = shadow.load()
|
||||
mask_pix = osm_mask.load()
|
||||
for y in range(self._imgsize-1):
|
||||
for x in range(self._imgsize-1):
|
||||
m = mask_pix[x,y]
|
||||
shf_x = x + mstr_shadow_shift
|
||||
shf_y = y + (mstr_shadow_shift/2)
|
||||
if shf_x < self._imgsize and shf_y < self._imgsize:
|
||||
a = mask_pix[x,y][3]
|
||||
st = random.uniform(0.3, mstr_shadow_strength)
|
||||
ca = a * st
|
||||
aa = int(ca)
|
||||
shadow_pix[shf_x, shf_y] = (0,0,0,aa)
|
||||
shadow = shadow.filter(ImageFilter.GaussianBlur(radius=2))
|
||||
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("layergen", "Shadow layer completed")
|
||||
|
||||
# Some funnies with shadows
|
||||
if self._tag == "building" and (self._value == "detached" or self._value == "semidetached_house" or self._value == "apartments" or self._value == "civic" or self._value == "house" or self._value == "terrace"):
|
||||
@ -890,6 +963,7 @@ class mstr_layergen:
|
||||
# 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"):
|
||||
# We will now add some white lines for coolness
|
||||
osm_edge = osm_mask.filter(ImageFilter.FIND_EDGES)
|
||||
mask_pix = osm_edge.load()
|
||||
layer_comp_pix = layer_comp.load()
|
||||
for y in range(self._imgsize):
|
||||
@ -901,13 +975,14 @@ class mstr_layergen:
|
||||
layer_comp_pix[x, y] = ( w,w,w,a[3] )
|
||||
|
||||
if self._tag == "highway" and self._value == "residential":
|
||||
osm_edge = osm_mask.filter(ImageFilter.FIND_EDGES)
|
||||
mask_pix = osm_edge.load()
|
||||
layer_comp_pix = layer_comp.load()
|
||||
for y in range(self._imgsize):
|
||||
for x in range(self._imgsize):
|
||||
if mask_pix[x, y][3] > 0:
|
||||
# Find a suitable color
|
||||
w = randrange(60, 96)
|
||||
w = randrange(150,181)
|
||||
a=mask_pix[x,y]
|
||||
layer_comp_pix[x, y] = ( w,w,w,a[3] )
|
||||
mstr_msg("layergen", "Street lines added")
|
||||
|
74
maskgen.py
@ -27,6 +27,7 @@ from defines import *
|
||||
from log import *
|
||||
from PIL import Image, ImageFilter, ImageDraw, ImagePath
|
||||
from random import randrange
|
||||
from functions import *
|
||||
import random
|
||||
|
||||
class mstr_maskgen:
|
||||
@ -65,11 +66,18 @@ class mstr_maskgen:
|
||||
latlng.append(float(i[2]))
|
||||
break
|
||||
return latlng
|
||||
|
||||
|
||||
# Only needed if X-Plane scenery is built
|
||||
def _set_xpscenery_datagroup(self, dg):
|
||||
self._xpdg = dg
|
||||
|
||||
# Set width of tile - for buildings
|
||||
def set_tile_width(self, tile_width):
|
||||
self._tile_width = tile_width
|
||||
|
||||
# Numbers needed for the possible building shadow layer
|
||||
def set_latlng_numbers(self, lat, tv, lng, th):
|
||||
self._latitude = lat
|
||||
self._lat_number = tv
|
||||
self._longitude = lng
|
||||
self._lng_number = th
|
||||
|
||||
|
||||
# Builds the required mask
|
||||
@ -99,6 +107,9 @@ class mstr_maskgen:
|
||||
# Longitude
|
||||
bbox.append(self._box[2] + ((self._box[3]-1) * mstr_zl_18))
|
||||
bbox.append(self._box[2] + ((self._box[3]-1) * mstr_zl_18) + mstr_zl_18)
|
||||
|
||||
# Building levels, if this is a building
|
||||
bld_levels = 0
|
||||
|
||||
# Generate mask for ONE tag only
|
||||
if self._subtag == None:
|
||||
@ -107,6 +118,8 @@ class mstr_maskgen:
|
||||
nd = []
|
||||
for d in way:
|
||||
if d[0] == w[0]:
|
||||
if self._tag == "building" and bld_levels == 0:
|
||||
bld_levels = xml.find_building_levels(tilexml, w[0])
|
||||
nd.append(d[1])
|
||||
frs.append(nd)
|
||||
# Scout through relations as these also make up map data
|
||||
@ -203,5 +216,58 @@ class mstr_maskgen:
|
||||
|
||||
# Save image
|
||||
mask_img.save(mstr_datafolder + "_cache/" + fstr + "_" + self._tag + "-" + self._value + ".png")
|
||||
|
||||
# If this is a building, we need to render the shadow here, as we only know the height
|
||||
# of the building in this loop.
|
||||
if mstr_shadow_enabled == True:
|
||||
if self._tag == "building":
|
||||
mpp = meters_per_pixel(self._tile_width) * mstr_zl_18
|
||||
pix_per_floor = mstr_shadow_floor_h / mpp
|
||||
total_pix = pix_per_floor * bld_levels
|
||||
shift = int(total_pix)
|
||||
|
||||
fn = mstr_datafolder + "_cache/" + fstr + "_" + self._tag + "-" + self._value + "_layer_shadow.png"
|
||||
|
||||
mask_pix = mask_img.load()
|
||||
|
||||
bld_shadow = Image.new("RGBA", (mstr_photores, mstr_photores))
|
||||
bld_shadow_pix = bld_shadow.load()
|
||||
|
||||
# Shadow sweep
|
||||
shf = 1
|
||||
while shf <= shift:
|
||||
for y in range(mstr_photores):
|
||||
for x in range(mstr_photores):
|
||||
mp = mask_pix[x,y]
|
||||
if mp[3] != 0:
|
||||
if x+(shf*2) < mstr_photores and y+shf < mstr_photores:
|
||||
bld_shadow_pix[x+(shf*2), y+shf] = (0,0,0,255)
|
||||
shf = shf+1
|
||||
|
||||
# Building removal sweep
|
||||
for y in range(mstr_photores):
|
||||
for x in range(mstr_photores):
|
||||
mp = mask_pix[x,y]
|
||||
if mp[3] != 0:
|
||||
bld_shadow_pix[x,y] = (0,0,0,0)
|
||||
|
||||
|
||||
# Correct alpha
|
||||
bld_shadow_pix = bld_shadow.load()
|
||||
for y in range(mstr_photores):
|
||||
for x in range(mstr_photores):
|
||||
sp = bld_shadow_pix[x,y]
|
||||
if sp[3] != 0:
|
||||
bld_shadow_pix[x,y] = (0,0,0,120)
|
||||
|
||||
# Store
|
||||
if os.path.isfile(fn) == True:
|
||||
lyr = Image.open(fn)
|
||||
lyr.alpha_composite(bld_shadow)
|
||||
lyr.save(fn)
|
||||
else:
|
||||
bld_shadow.save(fn)
|
||||
|
||||
|
||||
# Inform
|
||||
mstr_msg("maskgen", "Mask built.")
|
||||
|
@ -201,8 +201,9 @@ class mstr_orthographic:
|
||||
|
||||
# Generate the mask
|
||||
mg = mstr_maskgen( [self._lat, cur_tile_y, self._long, cur_tile_x], self._vstep, layer[0], layer[1], layer[2])
|
||||
if mstr_xp_genscenery == True:
|
||||
mg._set_xpscenery_datagroup(xp_datagroup)
|
||||
if layer[0] == "building":
|
||||
mg.set_tile_width(self._findWidthOfLongitude(bb_lat))
|
||||
mg.set_latlng_numbers(self._lat, lat_grid, self._long, lng_grid)
|
||||
mg._build_mask()
|
||||
|
||||
# Generate the layer
|
||||
|
17
osmxml.py
@ -149,6 +149,23 @@ class mstr_osmxml:
|
||||
|
||||
# Return the found surface type
|
||||
return surface
|
||||
|
||||
|
||||
# Find the levels of a building (for shadow rendering)
|
||||
def find_building_levels(self, xmlfile, way_id):
|
||||
lvl = 3 # Standard if we don't find anything else
|
||||
xml_doc = xml.dom.minidom.parse(xmlfile)
|
||||
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:levels":
|
||||
lvl = int(v)
|
||||
break
|
||||
return lvl
|
||||
|
||||
|
||||
# It turns out that some features hide themselves in the relations section.
|
||||
|
12
photogen.py
@ -52,6 +52,7 @@ class mstr_photogen:
|
||||
if l[0] == "building":
|
||||
if os.path.isfile(root_filename + l[0] + "-" + l[1] + "_layer_shadow.png"):
|
||||
shd = Image.open(root_filename + l[0] + "-" + l[1] + "_layer_shadow.png")
|
||||
shd = shd.filter(ImageFilter.GaussianBlur(radius=2))
|
||||
bldg_shadow.alpha_composite(shd)
|
||||
# Details merging
|
||||
bldg_details = Image.new("RGBA", (self._imgsize, self._imgsize))
|
||||
@ -69,10 +70,18 @@ class mstr_photogen:
|
||||
bld = Image.open(root_filename + l[0] + "-" + l[1] + "_layer.png")
|
||||
bld = bld.filter(ImageFilter.GaussianBlur(radius=1))
|
||||
bldg_main.alpha_composite(bld)
|
||||
# Trees merging
|
||||
tree_main = Image.new("RGBA", (self._imgsize, self._imgsize))
|
||||
for l in mstr_ortho_layers:
|
||||
if l[0] == "building":
|
||||
if os.path.isfile(root_filename + l[0] + "-" + l[1] + "_layer_building_trees.png"):
|
||||
trs= Image.open(root_filename + l[0] + "-" + l[1] + "_layer_building_trees.png")
|
||||
tree_main.alpha_composite(trs)
|
||||
# Merge the building layers
|
||||
bldg_final = Image.new("RGBA", (self._imgsize, self._imgsize))
|
||||
bldg_final.alpha_composite(bldg_details)
|
||||
bldg_final.alpha_composite(bldg_shadow)
|
||||
bldg_final.alpha_composite(tree_main)
|
||||
bldg_final.alpha_composite(bldg_main)
|
||||
|
||||
for l in mstr_ortho_layers:
|
||||
@ -153,8 +162,7 @@ class mstr_photogen:
|
||||
["water", "lake"],
|
||||
["water", "pond"],
|
||||
["water", "river"],
|
||||
["leisure", "swimming_pool"],
|
||||
["waterway", "stream"]
|
||||
["leisure", "swimming_pool"]
|
||||
)
|
||||
for l in water_layers:
|
||||
fn = mstr_datafolder + "_cache/" + str(self._lat) + "-" + str(self._ty) + "_" + str(self._lng) + "-" + str(self._tx) + "_" + l[0] + "-" + l[1] + "_layer_mask.png"
|
||||
|
Before Width: | Height: | Size: 1.6 MiB |
Before Width: | Height: | Size: 1.4 MiB |
Before Width: | Height: | Size: 1.7 MiB After Width: | Height: | Size: 2.5 MiB |
Before Width: | Height: | Size: 1.8 MiB After Width: | Height: | Size: 2.6 MiB |
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 2.8 MiB |
BIN
textures/boundary/administrative/brd/b4.png
Normal file
After Width: | Height: | Size: 2.6 MiB |
Before Width: | Height: | Size: 958 KiB After Width: | Height: | Size: 1.1 MiB |
Before Width: | Height: | Size: 578 KiB After Width: | Height: | Size: 1.2 MiB |
Before Width: | Height: | Size: 871 KiB After Width: | Height: | Size: 1.2 MiB |
Before Width: | Height: | Size: 716 KiB After Width: | Height: | Size: 1.0 MiB |
Before Width: | Height: | Size: 899 KiB After Width: | Height: | Size: 1.3 MiB |
Before Width: | Height: | Size: 904 KiB After Width: | Height: | Size: 1.1 MiB |
BIN
textures/boundary/administrative/ptc/b4_p1.png
Normal file
After Width: | Height: | Size: 1.1 MiB |
BIN
textures/boundary/administrative/ptc/b4_p2.png
Normal file
After Width: | Height: | Size: 1.2 MiB |
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 1.4 KiB |
BIN
textures/building/area/p11.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
textures/building/area/p12.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
textures/building/area/p13.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
textures/building/area/p14.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
textures/building/area/p15.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.7 MiB After Width: | Height: | Size: 2.5 MiB |
Before Width: | Height: | Size: 1.8 MiB After Width: | Height: | Size: 2.6 MiB |
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 2.8 MiB |
BIN
textures/landuse/residential-boundary/brd/b4.png
Normal file
After Width: | Height: | Size: 2.6 MiB |
Before Width: | Height: | Size: 958 KiB After Width: | Height: | Size: 1.1 MiB |
Before Width: | Height: | Size: 578 KiB After Width: | Height: | Size: 1.2 MiB |
Before Width: | Height: | Size: 871 KiB After Width: | Height: | Size: 1.2 MiB |
Before Width: | Height: | Size: 716 KiB After Width: | Height: | Size: 1.0 MiB |
Before Width: | Height: | Size: 899 KiB After Width: | Height: | Size: 1.3 MiB |
Before Width: | Height: | Size: 904 KiB After Width: | Height: | Size: 1.1 MiB |
BIN
textures/landuse/residential-boundary/ptc/b4_p1.png
Normal file
After Width: | Height: | Size: 1.1 MiB |
BIN
textures/landuse/residential-boundary/ptc/b4_p2.png
Normal file
After Width: | Height: | Size: 1.2 MiB |
Before Width: | Height: | Size: 1.7 MiB After Width: | Height: | Size: 2.5 MiB |
Before Width: | Height: | Size: 1.8 MiB After Width: | Height: | Size: 2.6 MiB |
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 2.8 MiB |
BIN
textures/landuse/residential/brd/b4.png
Normal file
After Width: | Height: | Size: 2.6 MiB |
Before Width: | Height: | Size: 958 KiB After Width: | Height: | Size: 1.1 MiB |
Before Width: | Height: | Size: 578 KiB After Width: | Height: | Size: 1.2 MiB |
Before Width: | Height: | Size: 871 KiB After Width: | Height: | Size: 1.2 MiB |
Before Width: | Height: | Size: 716 KiB After Width: | Height: | Size: 1.0 MiB |
Before Width: | Height: | Size: 899 KiB After Width: | Height: | Size: 1.3 MiB |
Before Width: | Height: | Size: 904 KiB After Width: | Height: | Size: 1.1 MiB |
BIN
textures/landuse/residential/ptc/b4_p1.png
Normal file
After Width: | Height: | Size: 1.1 MiB |
BIN
textures/landuse/residential/ptc/b4_p2.png
Normal file
After Width: | Height: | Size: 1.2 MiB |