Commit bc0d4676 authored by Rick Gruber-Riemer's avatar Rick Gruber-Riemer

Removing landuse.py and cleaning some code/imports

parent a8b197a3
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import logging
import math
from shapely.geometry import LineString
from shapely.geometry import Polygon
import parameters
def process_osm_building_refs(nodes_dict, ways_dict, my_coord_transformator):
my_buildings = dict() # osm_id as key, Polygon
for way in ways_dict.values():
for key in way.tags:
if "building" == key:
coordinates = list()
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
class LinearOSMFeature(object):
def __init__(self, osm_id):
self.osm_id = osm_id
self.type_ = 0
self.linear = None # The LinearString of the line
def get_width(self):
"""The width incl. border as a float in meters"""
raise NotImplementedError("Please implement this method")
class Highway(LinearOSMFeature):
TYPE_MOTORWAY = 11
TYPE_TRUNK = 12
TYPE_PRIMARY = 13
TYPE_SECONDARY = 14
TYPE_TERTIARY = 15
TYPE_UNCLASSIFIED = 16
TYPE_ROAD = 17
TYPE_RESIDENTIAL = 18
TYPE_LIVING_STREET = 19
TYPE_SERVICE = 20
TYPE_PEDESTRIAN = 21
TYPE_SLOW = 30 # cycle ways, tracks, footpaths etc
def __init__(self, osm_id):
super(Highway, self).__init__(osm_id)
self.is_roundabout = False
def get_width(self): # FIXME: replace with parameters and a bit of logic including number of lanes
my_width = 3.0 # TYPE_SLOW
if self.type_ in [Highway.TYPE_SERVICE, Highway.TYPE_RESIDENTIAL, Highway.TYPE_LIVING_STREET
, Highway.TYPE_PEDESTRIAN]:
my_width = 5.0
elif self.type_ in [Highway.TYPE_ROAD, Highway.TYPE_UNCLASSIFIED, Highway.TYPE_TERTIARY]:
my_width = 6.0
elif self.type_ in [Highway.TYPE_SECONDARY, Highway.TYPE_PRIMARY, Highway.TYPE_TRUNK]:
my_width = 7.0
else: # MOTORWAY
my_width = 14.0
return my_width
def process_osm_highway(nodes_dict, ways_dict, my_coord_transformator):
my_highways = dict() # osm_id as key, Highway
for way in ways_dict.values():
my_highway = Highway(way.osm_id)
valid_highway = False
is_challenged = False
for key in way.tags:
value = way.tags[key]
if "highway" == key:
valid_highway = True
if value in ["motorway", "motorway_link"]:
my_highway.type_ = Highway.TYPE_MOTORWAY
elif value in ["trunk", "trunk_link"]:
my_highway.type_ = Highway.TYPE_TRUNK
elif value in ["primary", "primary_link"]:
my_highway.type_ = Highway.TYPE_PRIMARY
elif value in ["secondary", "secondary_link"]:
my_highway.type_ = Highway.TYPE_SECONDARY
elif value in ["tertiary", "tertiary_link"]:
my_highway.type_ = Highway.TYPE_TERTIARY
elif value == "unclassified":
my_highway.type_ = Highway.TYPE_UNCLASSIFIED
elif value == "road":
my_highway.type_ = Highway.TYPE_ROAD
elif value == "residential":
my_highway.type_ = Highway.TYPE_RESIDENTIAL
elif value == "living_street":
my_highway.type_ = Highway.TYPE_LIVING_STREET
elif value == "service":
my_highway.type_ = Highway.TYPE_SERVICE
elif value == "pedestrian":
my_highway.type_ = Highway.TYPE_PEDESTRIAN
elif value in ["tack", "footway", "cycleway", "bridleway", "steps", "path"]:
my_highway.type_ = Highway.TYPE_SLOW
else:
valid_highway = False
elif ("tunnel" == key) and ("yes" == value):
is_challenged = True
elif ("junction" == key) and ("roundabout" == value):
my_highway.is_roundabout = True
if valid_highway and not is_challenged:
# Process the Nodes
my_coordinates = list()
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) >= 2:
my_highway.linear = LineString(my_coordinates)
my_highways[my_highway.osm_id] = my_highway
return my_highways
class Landuse(object):
TYPE_COMMERCIAL = 10
TYPE_INDUSTRIAL = 20
TYPE_RESIDENTIAL = 30
TYPE_RETAIL = 40
TYPE_NON_OSM = 50 # used for land-uses constructed with heuristics and not in original data from OSM
def __init__(self, osm_id):
self.osm_id = osm_id
self.type_ = 0
self.polygon = None # the polygon defining its outer boundary
self.number_of_buildings = 0 # only set for generated TYPE_NON_OSM land-uses during generation
def process_osm_landuse_refs(nodes_dict, ways_dict, my_coord_transformator):
my_landuses = dict() # osm_id as key, Landuse as value
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 = list()
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))
return my_landuses
def generate_landuse_from_buildings(osm_landuses, building_refs):
"""Adds "missing" landuses based on building clusters"""
my_landuse_candidates = dict()
index = 10000000000
for my_building in building_refs.values():
# check whether the building already is in a land use
within_existing_landuse = False
for osm_landuse in osm_landuses.values():
if my_building.intersects(osm_landuse.polygon):
within_existing_landuse = True
break
if not within_existing_landuse:
# create new clusters of land uses
buffer_distance = parameters.LU_LANDUSE_BUILDING_BUFFER_DISTANCE
if my_building.area > parameters.LU_LANDUSE_BUILDING_BUFFER_DISTANCE**2:
factor = math.sqrt(my_building.area / parameters.LU_LANDUSE_BUILDING_BUFFER_DISTANCE**2)
buffer_distance = min(factor*parameters.LU_LANDUSE_BUILDING_BUFFER_DISTANCE
, parameters.LU_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.values():
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[my_candidate.osm_id] = my_candidate
# add landuse candidates to landuses
logging.debug("Candidate land-uses found: %s", len(my_landuse_candidates))
for candidate in my_landuse_candidates.values():
if candidate.polygon.area < parameters.LU_LANDUSE_MIN_AREA:
del my_landuse_candidates[candidate.osm_id]
logging.debug("Candidate land-uses with sufficient area found: %s", len(my_landuse_candidates))
return my_landuse_candidates
def main():
pass
if __name__ == "__main__":
main()
This diff is collapsed.
This diff is collapsed.
......@@ -7,9 +7,10 @@ Use a tool like Osmosis to pre-process data.
@author: vanosten
"""
import xml.sax
import logging
import unittest
import xml.sax
import shapely.geometry as shg
......@@ -18,12 +19,13 @@ class OSMElement(object):
self.osm_id = osm_id
self.tags = {}
def addTag(self, key, value):
def add_tag(self, key, value):
self.tags[key] = value
def __str__(self):
return "<%s OSM_ID %i at %s>" % (type(self).__name__, self.osm_id, hex(id(self)))
class Node(OSMElement):
def __init__(self, osm_id, lat, lon):
OSMElement.__init__(self, osm_id)
......@@ -121,11 +123,11 @@ class OSMContentHandler(xml.sax.ContentHandler):
value = attrs.getValue("v")
if "node" == self._within_element:
if key in self._valid_node_keys:
self._current_node.addTag(key, value)
self._current_node.add_tag(key, value)
elif "way" == self._within_element:
self._current_way.addTag(key, value)
self._current_way.add_tag(key, value)
elif "relation" == self._within_element:
self._current_relation.addTag(key, value)
self._current_relation.add_tag(key, value)
elif name == "nd":
ref = int(attrs.getValue("ref"))
self._current_way.addRef(ref)
......
......@@ -5,7 +5,7 @@ A wrapper for OSMContentHandler, enabling backwards compatibility.
import xml.sax
import logging
import unittest
import osmparser as op
......@@ -48,7 +48,7 @@ class OSMContentHandler(xml.sax.ContentHandler):
current_way.tags = {}
for key, value in all_tags.items():
if key in self.valid_way_keys:
current_way.addTag(key, value)
current_way.add_tag(key, value)
self.ways_dict[current_way.osm_id] = current_way
def process_relation(self, current_relation):
......@@ -56,7 +56,7 @@ class OSMContentHandler(xml.sax.ContentHandler):
current_relation.tags = {}
for key, value in all_tags.items():
if key in self.valid_way_keys:
current_relation.addTag(key, value)
current_relation.add_tag(key, value)
self.relations_dict[current_relation.osm_id] = current_relation
......@@ -78,23 +78,3 @@ def main(source_file_name):
if __name__ == "__main__":
main("C:\\FlightGear\\customscenery2\\LSZS\\ch.osm")
# ================ UNITTESTS =======================
class TestOSMParser(unittest.TestCase):
def test_parse_length(self):
self.assertAlmostEqual(1.2, op.parse_length(' 1.2 '), 2, "Correct number with trailing spaces")
self.assertAlmostEqual(1.2, op.parse_length(' 1.2 m'), 2, "Correct number with meter unit incl. space")
self.assertAlmostEqual(1.2, op.parse_length(' 1.2m'), 2, "Correct number with meter unit without space")
self.assertAlmostEqual(1200, op.parse_length(' 1.2 km'), 2, "Correct number with km unit incl. space")
self.assertAlmostEqual(2092.1472, op.parse_length(' 1.3mi'), 2, "Correct number with mile unit without space")
self.assertAlmostEqual(3.048, op.parse_length("10'"), 2, "Correct number with feet unit without space")
self.assertAlmostEqual(3.073, op.parse_length('10\'1"'), 2, "Correct number with feet unit without space")
self.assertEquals(0, op.parse_length('m'), "Only valid unit")
self.assertEquals(0, op.parse_length('"'), "Only inches, no feet")
def test_is_parsable_float(self):
self.assertFalse(op.is_parsable_float('1,2'))
self.assertFalse(op.is_parsable_float('x'))
self.assertTrue(op.is_parsable_float('1.2'))
......@@ -14,18 +14,19 @@ Ludomotico contributed a cleaner version of read_from_file().
"""
import argparse
import logging
import os
import sys
import types
from os.path import os
from vec2d import vec2d
from pdb import pm
import logging
import traceback
import textures.road
import vec2d as v
# default_args_start # DO NOT MODIFY THIS LINE
# -*- coding: utf-8 -*-
# The preceeding line sets encoding of this file to utf-8. Needed for non-ascii
# The preceding line sets encoding of this file to utf-8. Needed for non-ascii
# object names. It must stay on the first or second line.
#=============================================================================
......@@ -90,7 +91,7 @@ MAX_OBJECTS = 50000 # -- maximum number of buildings to read from OSM da
CONCURRENCY = 1 # -- number of parallel OSM parsing threads. Unused ATM.
# -- skip buildings based on their OSM name tag or OSM ID, in case there's already
# a static model for these, and the overlap check fails.
# a static model for these, and the overlap check fails.
# Use unicode strings as in the first example if there are non-ASCII characters.
SKIP_LIST = [u"Theologische Fakultät", "Rhombergpassage", 55875208]
# -- keep buildings based on their OSM name tag or OSM ID.
......@@ -216,7 +217,7 @@ C2P_STREETLAMPS_OTHER_DISTANCE = 70
C2P_STREETLAMPS_MIN_STREET_LENGTH = 20
#=============================================================================
# PARAMETERS RELATED TO landuse.py
# PARAMETERS RELATED TO landuse.py - might be replaced by another library
#=============================================================================
LU_LANDUSE_GENERATE_LANDUSE = True
LU_LANDUSE_BUILDING_BUFFER_DISTANCE = 25
......@@ -237,7 +238,7 @@ DEBUG_PLOT = 0
CREATE_BRIDGES_ONLY = 0 # create only bridges and embankments
BRIDGE_LAYER_HEIGHT = 4. # bridge height per layer
BRIDGE_BODY_HEIGHT = 0.9 # height of bridge body
EMBANKMENT_TEXTURE = textures.road.EMBANKMENT_1 # Texture for the embankement
EMBANKMENT_TEXTURE = textures.road.EMBANKMENT_1 # Texture for the embankment
quiet = False
# default_args_end # DO NOT MODIFY THIS LINE
......@@ -251,15 +252,17 @@ def get_OSM_file_name():
def get_center_global():
cmin = vec2d(BOUNDARY_WEST, BOUNDARY_SOUTH)
cmax = vec2d(BOUNDARY_EAST, BOUNDARY_NORTH)
cmin = v.vec2d(BOUNDARY_WEST, BOUNDARY_SOUTH)
cmax = v.vec2d(BOUNDARY_EAST, BOUNDARY_NORTH)
return (cmin + cmax) * 0.5
def get_extent_global():
cmin = vec2d(BOUNDARY_WEST, BOUNDARY_SOUTH)
cmax = vec2d(BOUNDARY_EAST, BOUNDARY_NORTH)
cmin = v.vec2d(BOUNDARY_WEST, BOUNDARY_SOUTH)
cmax = v.vec2d(BOUNDARY_EAST, BOUNDARY_NORTH)
return cmin, cmax
def get_clipping_extent():
rect = [(BOUNDARY_WEST-BOUNDARY_CLIPPING_BORDER_SIZE, BOUNDARY_SOUTH-BOUNDARY_CLIPPING_BORDER_SIZE),
(BOUNDARY_EAST+BOUNDARY_CLIPPING_BORDER_SIZE, BOUNDARY_SOUTH-BOUNDARY_CLIPPING_BORDER_SIZE),
......@@ -267,12 +270,14 @@ def get_clipping_extent():
(BOUNDARY_WEST-BOUNDARY_CLIPPING_BORDER_SIZE, BOUNDARY_NORTH+BOUNDARY_CLIPPING_BORDER_SIZE)]
return rect
def show():
"""
Prints all parameters as key = value
"""
global quiet
if quiet: return
if quiet:
return
print '--- Using the following parameters: ---'
my_globals = globals()
for k in sorted(my_globals.iterkeys()):
......@@ -294,7 +299,7 @@ def show():
def read_from_file(filename):
logging.info('Reading parameters from file: %s' % filename)
default_globals = globals()
file_globals = {'textures' : default_globals['textures']}
file_globals = {'textures': default_globals['textures']}
try:
execfile(filename, file_globals)
except IOError, reason:
......@@ -304,9 +309,9 @@ def read_from_file(filename):
print traceback.format_exc()
logging.error("Error while reading " + filename + ". Perhaps an unquoted string in your parameters file?")
sys.exit(1)
for k, v in file_globals.iteritems():
if k.startswith('_'):
if k.startswith('_'):
continue
k = k.upper()
if k in default_globals:
......@@ -329,15 +334,16 @@ def show_default():
return
if do_print:
print line,
def set_loglevel(args_loglevel = None):
"""set loglevel from paramters or command line"""
def set_loglevel(args_loglevel=None):
"""Set loglevel from parameters or command line."""
global LOGLEVEL
if args_loglevel != None:
if args_loglevel is not None:
LOGLEVEL = args_loglevel
LOGLEVEL = LOGLEVEL.upper()
# -- add another log level VERBOSE. Use this when logging stuff in loops, e.g. per-OSM-object,
# potentiallially flooding the screen
# potentially flooding the screen
logging.VERBOSE = 5
logging.addLevelName(logging.VERBOSE, "VERBOSE")
logging.Logger.verbose = lambda inst, msg, *args, **kwargs: inst.log(logging.VERBOSE, msg, *args, **kwargs)
......@@ -348,11 +354,12 @@ def set_loglevel(args_loglevel = None):
raise ValueError('Invalid log level: %s' % LOGLEVEL)
logging.basicConfig(level=numeric_level)
logging.getLogger().setLevel(LOGLEVEL)
global quiet
if numeric_level > logging.INFO:
quiet = True
if __name__ == "__main__":
# Handling arguments and parameters
parser = argparse.ArgumentParser(
......
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