Commit 046231b1 authored by Rick Gruber-Riemer's avatar Rick Gruber-Riemer

Re-structure of land-use related code

parent 1e7d0bd2
......@@ -5,6 +5,7 @@ shamelessly translated from calc-tile.pl
"""
import os
from math import floor
import numpy as np
def bucket_span(lat):
......@@ -27,7 +28,7 @@ def bucket_span(lat):
return .125
def format_lon (lon):
def format_lon(lon):
"""Format longitude as e/w."""
if lon < 0.:
return "w%03d" % int(0. - lon)
......@@ -35,7 +36,7 @@ def format_lon (lon):
return "e%03d" % int(lon)
def format_lat (lat):
def format_lat(lat):
"""Format latitude as n/s."""
if lat < 0.:
return "s%02d" % int(0. - lat)
......@@ -43,13 +44,14 @@ def format_lat (lat):
return "n%02d" % int(lat)
def root_directory_name ((lon, lat)):
def root_directory_name((lon, lat)):
"""Generate the directory name for a location."""
lon_chunk = floor(lon/10.0) * 10
lat_chunk = floor(lat/10.0) * 10
return format_lon(lon_chunk) + format_lat(lat_chunk) + os.sep
def directory_name ((lon, lat)):
def directory_name((lon, lat)):
"""Generate the directory name for a location."""
lon_floor = floor(lon)
lat_floor = floor(lat)
......@@ -62,8 +64,7 @@ def directory_name ((lon, lat)):
def tile_index((lon, lat), x=0, y=0):
if x == 0 and y == 0:
y = calc_y(lat)
x = calc_x(lon,lat)
x = calc_x(lon, lat)
index = (int(floor(lon)) + 180) << 14
index += (int(floor(lat)) + 90) << 6
......@@ -81,30 +82,39 @@ def construct_stg_file_name(center_global):
"""Returns the file name of the stg-file at a given global lat/lon location"""
return "%07i.stg" % tile_index(center_global)
def construct_btg_file_name(center_global):
"""Returns the file name of the stg-file at a given global lat/lon location"""
return "%07i.btg.gz" % tile_index(center_global)
def get_north_lat(lat,y):
return float(floor(lat)) + y / 8.0 + .125;
def get_south_lat(lat,y):
return float(floor(lat)) + y / 8.0;
def get_north_lat(lat, y):
return float(floor(lat)) + y / 8.0 + .125
def get_south_lat(lat, y):
return float(floor(lat)) + y / 8.0
def get_west_lon(lon,lat, x):
if( x == 0):
def get_west_lon(lon, lat, x):
if x == 0:
return float(floor(lon))
else:
return float(floor(lon)) + x * (bucket_span(lat))
def get_east_lon(lon,lat, x):
if( x == 0):
def get_east_lon(lon, lat, x):
if x == 0:
return float(floor(lon)) + (bucket_span(lat))
else:
return float(floor(lon)) + x * (bucket_span(lat)) + (bucket_span(lat))
def calc_x(lon,lat):
def calc_x(lon, lat):
"""
FIXME: is this correct? Also: some returns do not take calculations into account.
According to http://wiki.flightgear.org/Tile_Index_Scheme it would be calculated differently
"""
EPSILON = 0.0000001
span = bucket_span(lat)
if span < EPSILON:
......@@ -121,12 +131,22 @@ def calc_x(lon,lat):
lon = -180
return 0
def calc_y(lat):
return int((lat - floor(lat)) * 8)
def get_stg_files_in_boundary(boundary_west, boundary_south, boundary_east, boundary_north, path_to_scenery):
"""Based on boundary rectangle returns a list of stg-files (incl. full path) to be found within the boundary of
the scenery"""
stg_files = []
for my_lat in np.arange(boundary_south, boundary_north, 0.125): # latitude
for my_lon in np.arange(boundary_west, boundary_east, bucket_span(my_lat)): # longitude
coords = (my_lon, my_lat)
stg_files.append(construct_path_to_stg(path_to_scenery, coords) + construct_stg_file_name(coords))
return stg_files
if __name__ == "__main__":
for lon, lat, idx in ((13.687944, 51.074664, 3171138),
(13.9041667, 51.1072222, 3171139),
......
This diff is collapsed.
......@@ -27,6 +27,7 @@ import unittest
import xml.sax
import coordinates
import landuse
import osmparser
import osmparser_wrapper
import parameters
......@@ -372,20 +373,6 @@ class LineWithoutCables(object):
return my_shared_pylon.lon, my_shared_pylon.lat
class Landuse(LineWithoutCables):
TYPE_COMMERCIAL = 10
TYPE_INDUSTRIAL = 20
TYPE_RESIDENTIAL = 30
TYPE_RETAIL = 40
TYPE_NON_OSM = 50 # used for landuses constructed by osm2pylons and not in original data from OSM
def __init__(self, osm_id):
super(Landuse, self).__init__(osm_id)
self.type_ = 0
self.polygon = None
self.number_of_buildings = 0
class Highway(LineWithoutCables):
TYPE_MOTORWAY = 11
TYPE_TRUNK = 12
......@@ -858,23 +845,6 @@ class RailLine(Line):
return is_right
def process_osm_building_refs(nodes_dict, ways_dict, my_coord_transformator):
my_buildings = {} # osm_id as key, Polygon
for way in ways_dict.values():
for key in way.tags:
if "building" == key:
coordinates = []
for ref in way.refs:
if ref in nodes_dict:
my_node = nodes_dict[ref]
coordinates.append(my_coord_transformator.toLocal((my_node.lon, my_node.lat)))
if 2 < len(coordinates):
my_polygon = Polygon(coordinates)
if my_polygon.is_valid and not my_polygon.is_empty:
my_buildings[way.osm_id] = my_polygon.convex_hull
return my_buildings
def process_osm_rail_overhead(nodes_dict, ways_dict, my_elev_interpolator, my_coord_transformator):
my_railways = {} # osm_id as key, RailLine
my_shared_nodes = {} # node osm_id as key, list of WayLine objects as value
......@@ -1076,84 +1046,6 @@ def merge_streetlamp_buffers(landuse_refs):
return landuse_buffers
def process_osm_landuse_refs(nodes_dict, ways_dict, my_coord_transformator, building_refs):
my_landuses = {} # osm_id as key, Landuse
for way in ways_dict.values():
my_landuse = Landuse(way.osm_id)
valid_landuse = True
for key in way.tags:
value = way.tags[key]
if "landuse" == key:
if value == "commercial":
my_landuse.type_ = Landuse.TYPE_COMMERCIAL
elif value == "industrial":
my_landuse.type_ = Landuse.TYPE_INDUSTRIAL
elif value == "residential":
my_landuse.type_ = Landuse.TYPE_RESIDENTIAL
elif value == "retail":
my_landuse.type_ = Landuse.TYPE_RETAIL
else:
valid_landuse = False
else:
valid_landuse = False
if valid_landuse:
# Process the Nodes
my_coordinates = []
for ref in way.refs:
if ref in nodes_dict:
my_node = nodes_dict[ref]
x, y = my_coord_transformator.toLocal((my_node.lon, my_node.lat))
my_coordinates.append((x, y))
if len(my_coordinates) >= 3:
my_landuse.polygon = Polygon(my_coordinates)
if my_landuse.polygon.is_valid and not my_landuse.polygon.is_empty:
my_landuses[my_landuse.osm_id] = my_landuse
logging.debug("OSM land-uses found: %s", len(my_landuses))
if parameters.C2P_LANDUSE_GENERATE_LANDUSE:
# Add "missing" landuses based on building clusters
my_landuse_candidates = []
index = 10000000000
for my_building in building_refs.values():
# check whether the building already is in a land use
within_existing_landuse = False
for my_landuse in my_landuses.values():
if my_building.intersects(my_landuse.polygon):
within_existing_landuse = True
break
if not within_existing_landuse:
# create new clusters of land uses
buffer_distance = parameters.C2P_LANDUSE_BUILDING_BUFFER_DISTANCE
if my_building.area > parameters.C2P_LANDUSE_BUILDING_BUFFER_DISTANCE**2:
factor = math.sqrt(my_building.area / parameters.C2P_LANDUSE_BUILDING_BUFFER_DISTANCE**2)
buffer_distance = min(factor*parameters.C2P_LANDUSE_BUILDING_BUFFER_DISTANCE
, parameters.C2P_LANDUSE_BUILDING_BUFFER_DISTANCE_MAX)
buffer_polygon = my_building.buffer(buffer_distance)
buffer_polygon = buffer_polygon
within_existing_landuse = False
for candidate in my_landuse_candidates:
if buffer_polygon.intersects(candidate.polygon):
candidate.polygon = candidate.polygon.union(buffer_polygon)
candidate.number_of_buildings += 1
within_existing_landuse = True
break
if not within_existing_landuse:
index += 1
my_candidate = Landuse(index)
my_candidate.polygon = buffer_polygon
my_candidate.number_of_buildings = 1
my_candidate.type_ = Landuse.TYPE_NON_OSM
my_landuse_candidates.append(my_candidate)
# add landuse candidates to landuses
logging.debug("Candidate land-uses found: %s", len(my_landuse_candidates))
for candidate in my_landuse_candidates:
if candidate.polygon.area >= parameters.C2P_LANDUSE_MIN_AREA:
my_landuses[candidate.osm_id] = candidate
return my_landuses
def process_osm_power_aerialway(nodes_dict, ways_dict, my_elev_interpolator, my_coord_transformator, building_refs):
"""
Transforms a dict of Node and a dict of Way OSMElements from osmparser.py to a dict of WayLine objects for
......@@ -1461,14 +1353,12 @@ def main():
logging.info("Transforming OSM data to Line and Pylon objects")
# the lists below are in sequence: buildings references, power/aerialway, railway overhead, landuse and highway
valid_node_keys = ["power", "structure", "material", "height", "colour", "aerialway"
, "railway"
]
, "railway"]
valid_way_keys = ["building"
, "power", "aerialway", "voltage", "cables", "wires"
, "railway", "electrified", "tunnel"
, "landuse"
, "highway", "junction"
]
, "highway", "junction"]
valid_relation_keys = []
req_relation_keys = []
req_way_keys = ["building", "power", "aerialway", "railway", "landuse", "highway"]
......@@ -1479,7 +1369,7 @@ def main():
# References for buildings
building_refs = {}
if parameters.C2P_PROCESS_POWERLINES or parameters.C2P_PROCESS_AERIALWAYS or parameters.C2P_PROCESS_STREETLAMPS:
building_refs = process_osm_building_refs(handler.nodes_dict, handler.ways_dict, coord_transformator)
building_refs = landuse.process_osm_building_refs(handler.nodes_dict, handler.ways_dict, coord_transformator)
logging.info('Number of reference buildings: %s', len(building_refs))
# Power lines and aerialways
powerlines = {}
......@@ -1508,7 +1398,11 @@ def main():
# street lamps
highways = {}
if parameters.C2P_PROCESS_STREETLAMPS:
landuse_refs = process_osm_landuse_refs(handler.nodes_dict, handler.ways_dict, coord_transformator, building_refs)
landuse_refs = landuse.process_osm_landuse_refs(handler.nodes_dict, handler.ways_dict, coord_transformator)
if parameters.LU_LANDUSE_GENERATE_LANDUSE:
generated_landuses = landuse.generate_landuse_from_buildings(landuse_refs, building_refs)
for generated in generated_landuses.values():
landuse_refs[generated.osm_id] = generated
logging.info('Number of landuse references: %s', len(landuse_refs))
streetlamp_buffers = merge_streetlamp_buffers(landuse_refs)
logging.info('Number of streetlamp buffers: %s', len(streetlamp_buffers))
......
......@@ -167,15 +167,18 @@ C2P_CATENARY_MIN_DISTANCE = 30
C2P_POWER_LINE_ALLOW_100M = False
C2P_LANDUSE_GENERATE_LANDUSE = True
C2P_LANDUSE_BUILDING_BUFFER_DISTANCE = 25
C2P_LANDUSE_BUILDING_BUFFER_DISTANCE_MAX = 50
C2P_LANDUSE_MIN_AREA = 5000
C2P_STREETLAMPS_MAX_DISTANCE_LANDUSE = 100
C2P_STREETLAMPS_RESIDENTIAL_DISTANCE = 40
C2P_STREETLAMPS_OTHER_DISTANCE = 70
#=============================================================================
# PARAMETERS RELATED TO landuse.py
#=============================================================================
LU_LANDUSE_GENERATE_LANDUSE = True
LU_LANDUSE_BUILDING_BUFFER_DISTANCE = 25
LU_LANDUSE_BUILDING_BUFFER_DISTANCE_MAX = 50
LU_LANDUSE_MIN_AREA = 5000
#=============================================================================
# PARAMETERS RELATED TO ROADS IN roads.py
#=============================================================================
......
......@@ -147,45 +147,83 @@ class STG_Manager(object):
the_stg.write()
def read(path, stg_fname, our_magic):
"""Accepts a scenery sub-path, as in 'w010n40/w005n48/', and an .stg file name.
In the future, take care of multiple scenery paths here.
Returns list of buildings representing static/shared objects in .stg, with full path.
"""
objs = []
our_magic_start = delimiter_string(our_magic, True)
our_magic_end = delimiter_string(our_magic, False)
ours = False
class STGEntry(object):
SHARED_OBJECT = "OBJECT_SHARED"
STATIC_OBJECT = "OBJECT_STATIC"
def __init__(self, type_string, obj_filename, stg_path, lon, lat, elev, hdg):
self.is_static = True
if type_string == STGEntry.SHARED_OBJECT:
self.is_static = False
self.obj_filename = obj_filename
self.stg_path = stg_path # the path of the stg_file without file name and trailing path-separator
self.lon = lon
self.lat = lat
self.elev = elev
self.hdg = hdg
def get_object_type_as_string(self):
if self.is_static:
return STGEntry.STATIC_OBJECT
return STGEntry.SHARED_OBJECT
def get_obj_path_and_name(self):
return self.stg_path + os.sep + self.obj_filename
def read_stg_entries(stg_path_and_name, our_magic):
"""Reads an stg-file and extracts STGEntry objects outside of marked areas for our_magic.
TODO: In the future, take care of multiple scenery paths here.
TODO: should be able to take a list of our_magic"""
entries = [] # list of STGEntry objects
if None is not our_magic:
our_magic_start = delimiter_string(our_magic, True)
our_magic_end = delimiter_string(our_magic, False)
ours = False
try:
f = open(path + stg_fname)
for line in f.readlines():
if line.startswith(our_magic_start):
ours = True
continue
if line.startswith(our_magic_end):
ours = False
continue
if ours:
continue
if line.startswith('#') or line.lstrip() == "":
continue
splitted = line.split()
typ, ac_path = splitted[0:2]
lon = float(splitted[2])
lat = float(splitted[3])
# alt = float(splitted[4])
point = shg.Point(tools.transform.toLocal((lon, lat)))
hdg = float(splitted[5])
logging.debug("stg: %s %s", typ, path + ac_path)
objs.append(osm2city.Building(osm_id=-1, tags=-1, outer_ring=point, name=path + ac_path, height=0, levels=0, stg_typ=typ, stg_hdg=hdg))
f.close()
with open(stg_path_and_name, 'r') as my_file:
path, stg_name = os.path.split(stg_path_and_name)
for line in my_file:
if None is not our_magic:
if line.startswith(our_magic_start):
ours = True
continue
if line.startswith(our_magic_end):
ours = False
continue
if ours:
continue
if line.startswith('#') or line.lstrip() == "":
continue
splitted = line.split()
type_ = splitted[0]
obj_filename = splitted[1]
lon = float(splitted[2])
lat = float(splitted[3])
elev = float(splitted[4])
hdg = float(splitted[5])
entries.append(STGEntry(type_, obj_filename, path, lon, lat, elev, hdg))
logging.debug("stg: %s %s", type_, path + os.sep + obj_filename)
except IOError, reason:
logging.warning("stg_io:read: Ignoring unreadable file %s", reason)
return []
return entries
return objs
def read(path, stg_fname, our_magic):
"""Same as read_stg_entries, but returns osm2city.Building objects"""
stg_entries = read_stg_entries(path + stg_fname, our_magic)
building_objs = []
for entry in stg_entries:
point = shg.Point(tools.transform.toLocal((entry.lon, entry.lat)))
building_objs.append(osm2city.Building(osm_id=-1, tags=-1, outer_ring=point
, name=entry.get_obj_path_and_name()
, height=0, levels=0, stg_typ=entry.get_object_type_as_string()
, stg_hdg=entry.hdg))
return building_objs
def delimiter_string(our_magic, is_start):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment