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

Buildings are now created in landuse.py and later used in building.py.

parent dcef6797
......@@ -13,7 +13,6 @@ import unittest
import buildings
import owbb.landuse as ol
import owbb.would_be_buildings as ow
import piers
import platforms
import pylons
......@@ -122,8 +121,6 @@ def process_scenery_tile(scenery_tile: SceneryTile, params_file_name: str,
the_coords_transform = coordinates.Transformation(parameters.get_center_global())
lit_areas, building_zones = ol.process(the_coords_transform)
my_fg_elev = FGElev(the_coords_transform, scenery_tile.tile_index)
my_stg_entries = utils.stg_io2.read_stg_entries_in_boundary(True, the_coords_transform)
......@@ -138,12 +135,10 @@ def process_scenery_tile(scenery_tile: SceneryTile, params_file_name: str,
my_airports)
# run programs
lit_areas, osm_buildings = ol.process(the_coords_transform)
if exec_argument in [Procedures.buildings, Procedures.main, Procedures.all]:
generated_buildings = list()
if parameters.OWBB_GENERATE_BUILDINGS:
generated_buildings = ow.process(the_coords_transform, building_zones)
buildings.process_buildings(the_coords_transform, my_fg_elev, my_blocked_areas, my_stg_entries,
generated_buildings, file_lock)
osm_buildings, file_lock)
if exec_argument in [Procedures.roads, Procedures.main, Procedures.all]:
roads.process_roads(the_coords_transform, my_fg_elev, my_blocked_areas, lit_areas,
my_stg_entries, file_lock)
......
......@@ -128,6 +128,9 @@ class Building(object):
self.ground_elev = 0.0 # the lowest elevation over sea of any point in the outer ring of the building
# set during owbb land-use zone processing or owbb building generation
self.zone = None # either a owbb.model.(Generated)BuildingZone or owbb.model.CityBlock
def make_building_from_part(self) -> None:
"""Make sure a former building_part gets tagged correctly"""
if 'building:part' in self.tags:
......
......@@ -593,16 +593,10 @@ def construct_buildings_from_osm(coords_transform: coordinates.Transformation) -
def process_buildings(coords_transform: coordinates.Transformation, fg_elev: utilities.FGElev,
blocked_areas: List[shg.Polygon], stg_entries: List[stg_io2.STGEntry],
generated_buildings: List[building_lib.Building],
the_buildings: List[building_lib.Building],
file_lock: mp.Lock=None) -> None:
random.seed(42)
# construct buildings from OSM data
the_buildings = construct_buildings_from_osm(coords_transform)
# add generated buildings
the_buildings.extend(generated_buildings)
if not the_buildings:
logging.info("No buildings found in OSM data. Stopping further processing.")
return
......
......@@ -439,8 +439,8 @@ Land-use data is only used for built-up area in ``osm2city``. All other land-use
============================================= ======== ======= ==============================================================================
Parameter Type Default Description / Example
============================================= ======== ======= ==============================================================================
OWBB_LANDUSE_CACHE Boolean False Instead of calculating land-use related stuff from scratch each time, use
cached (but possibly stale) data for speed-up.
OWBB_LANDUSE_CACHE Boolean False Instead of calculating land-use related stuff including buildings from scratch
each time, use cached (but possibly stale) data for speed-up.
============================================= ======== ======= ==============================================================================
......
......@@ -11,11 +11,12 @@ from typing import Dict, List, Tuple
from shapely.geometry import MultiPolygon, Polygon, CAP_STYLE, JOIN_STYLE
from shapely.ops import unary_union
import buildings
import buildings as bu
import building_lib as bl
import parameters
import owbb.models as m
import owbb.plotting as plotting
import owbb.would_be_buildings as wbb
import utils.osmparser as op
from utils.coordinates import disjoint_bounds, Transformation
from utils.utilities import time_logging
......@@ -37,14 +38,14 @@ def _generate_building_zones_from_buildings(building_zones: List[m.BuildingZone]
for candidate in zones_candidates.values():
if buffer_polygon.intersects(candidate.geometry):
candidate.geometry = candidate.geometry.union(buffer_polygon)
candidate.osm_buildings.append(my_building)
candidate.relate_building(my_building)
within_existing_building_zone = True
break
if not within_existing_building_zone:
my_candidate = m.GeneratedBuildingZone(op.get_next_pseudo_osm_id(op.OSMFeatureType.landuse),
buffer_polygon, m.BuildingZoneType.non_osm,
True)
my_candidate.osm_buildings.append(my_building)
my_candidate.relate_building(my_building)
zones_candidates[my_candidate.osm_id] = my_candidate
logging.debug("Candidate land-uses found: %s", len(zones_candidates))
# Search once again for intersections in order to account for randomness in checks
......@@ -56,7 +57,8 @@ def _generate_building_zones_from_buildings(building_zones: List[m.BuildingZone]
merged_candidate_ids.append(keys[i])
zones_candidates[keys[j]].geometry = zones_candidates[keys[j]].geometry.union(
zones_candidates[keys[i]].geometry)
zones_candidates[keys[j]].osm_buildings.extend(zones_candidates[keys[i]].osm_buildings)
for building in zones_candidates[keys[i]].osm_buildings:
zones_candidates[keys[j]].relate_building(building)
break
logging.debug("Candidate land-uses merged into others: %d", len(merged_candidate_ids))
# check for minimum size and then simplify geometry
......@@ -116,7 +118,7 @@ def _split_multipolygon_generated_building_zone(zone: m.GeneratedBuildingZone) -
my_building = zone.osm_buildings.pop()
for my_split_generated in new_generated:
if my_building.geometry.intersects(my_split_generated.geometry):
my_split_generated.osm_buildings.append(my_building)
my_split_generated.relate_building(my_building)
continue
for my_split_generated in new_generated:
if my_split_generated.from_buildings and len(my_split_generated.osm_buildings) == 0:
......@@ -362,13 +364,13 @@ def _link_building_zones_with_settlements(settlement_clusters: List[m.Settlement
break
def process(transformer: Transformation) -> Tuple[List[Polygon], List[m.BuildingZone]]:
def process(transformer: Transformation) -> Tuple[List[Polygon], List[bl.Building]]:
last_time = time.time()
# =========== TRY TO READ CACHED DATA FIRST =======
tile_index = parameters.get_tile_index()
cache_file_la = str(tile_index) + '_lit_areas.pkl'
cache_file_bz = str(tile_index) + '_building_zones.pkl'
cache_file_bz = str(tile_index) + '_buildings.pkl'
if parameters.OWBB_LANDUSE_CACHE:
try:
with open(cache_file_la, 'rb') as file_pickle:
......@@ -376,17 +378,17 @@ def process(transformer: Transformation) -> Tuple[List[Polygon], List[m.Building
logging.info('Successfully loaded %i objects from %s', len(lit_areas), cache_file_la)
with open(cache_file_bz, 'rb') as file_pickle:
building_zones = pickle.load(file_pickle)
logging.info('Successfully loaded %i objects from %s', len(building_zones), cache_file_bz)
return lit_areas, building_zones
osm_buildings = pickle.load(file_pickle)
logging.info('Successfully loaded %i objects from %s', len(osm_buildings), cache_file_bz)
return lit_areas, osm_buildings
except (IOError, EOFError) as reason:
logging.info("Loading of cache %s or %s failed (%s)", cache_file_la, cache_file_bz, reason)
# =========== READ OSM DATA =============
building_zones = m.process_osm_building_zone_refs(transformer)
urban_places, farm_places = m.process_osm_place_refs(transformer)
osm_buildings = buildings.construct_buildings_from_osm(transformer)
highways_dict, nodes_dict = m.process_osm_highway_refs(transformer)
osm_buildings = bu.construct_buildings_from_osm(transformer)
highways_dict = m.process_osm_highway_refs(transformer)
railways_dict = m.process_osm_railway_refs(transformer)
waterways_dict = m.process_osm_waterway_refs(transformer)
......@@ -399,7 +401,7 @@ def process(transformer: Transformation) -> Tuple[List[Polygon], List[m.Building
for building_zone in building_zones:
if candidate.geometry.within(building_zone.geometry) or candidate.geometry.intersects(
building_zone.geometry):
building_zone.osm_buildings.append(candidate)
building_zone.relate_building(candidate)
found = True
break
if not found:
......@@ -431,19 +433,25 @@ def process(transformer: Transformation) -> Tuple[List[Polygon], List[m.Building
_link_building_zones_with_settlements(settlement_clusters, building_zones, highways_dict)
last_time = time_logging('Time used in seconds for linking building zones with settlement_clusters', last_time)
# ============finally guess the land-use type ========================================
# ============ Finally guess the land-use type ========================================
for my_zone in building_zones:
if isinstance(my_zone, m.GeneratedBuildingZone):
my_zone.guess_building_zone_type(farm_places)
last_time = time_logging("Time used in seconds for guessing zone types", last_time)
# =========== FINALIZE PROCESSING ====================================================
# =========== FINALIZE Land-use PROCESSING =============================================
if parameters.DEBUG_PLOT:
bounds = m.Bounds.create_from_parameters(transformer)
logging.info('Start of plotting zones')
plotting.draw_zones(osm_buildings, building_zones, lit_areas, bounds)
time_logging("Time used in seconds for plotting", last_time)
# =========== Now generate buildings if asked for ======================================
if parameters.OWBB_GENERATE_BUILDINGS:
generated_buildings = wbb.process(transformer, building_zones, highways_dict, railways_dict,
waterways_dict)
osm_buildings.extend(generated_buildings)
# =========== WRITE TO CACHE AND RETURN
if parameters.OWBB_LANDUSE_CACHE:
try:
......@@ -453,9 +461,9 @@ def process(transformer: Transformation) -> Tuple[List[Polygon], List[m.Building
logging.info('Successfully saved %i objects to %s', len(lit_areas), cache_file_la)
with open(cache_file_bz, 'wb') as file_pickle:
pickle.dump(building_zones, file_pickle)
logging.info('Successfully saved %i objects to %s', len(building_zones), cache_file_bz)
pickle.dump(osm_buildings, file_pickle)
logging.info('Successfully saved %i objects to %s', len(osm_buildings), cache_file_bz)
except (IOError, EOFError) as reason:
logging.info("Saving of cache %s or %s failed (%s)", cache_file_la, cache_file_bz, reason)
return lit_areas, building_zones
return lit_areas, osm_buildings
......@@ -302,13 +302,13 @@ def get_building_class(building: building_lib.Building) -> BuildingClass:
elif type_ in [BuildingType.parking]:
return BuildingClass.parking_house
elif type_ in [BuildingType.cathedral, BuildingType.chapel, BuildingType.church,
BuildingType.mosque, BuildingType.temple, BuildingType.synagogue]:
BuildingType.mosque, BuildingType.temple, BuildingType.synagogue]:
return BuildingClass.religion
elif type_ in [BuildingType.public, BuildingType.civic, BuildingType.school, BuildingType.hospital,
BuildingType.hotel, BuildingType.kiosk]:
BuildingType.hotel, BuildingType.kiosk]:
return BuildingClass.public
elif type_ in [BuildingType.farm, BuildingType.barn, BuildingType.cowshed, BuildingType.farm_auxiliary,
BuildingType.greenhouse, BuildingType.stable, BuildingType.sty, BuildingType.riding_hall]:
BuildingType.greenhouse, BuildingType.stable, BuildingType.sty, BuildingType.riding_hall]:
return BuildingClass.farm
elif type_ in [BuildingType.hangar]:
return BuildingClass.airport
......@@ -337,6 +337,11 @@ class CityBlock:
self.osm_buildings = list() # List of already existing osm buildings
self.settlement_type = SettlementType.periphery
def relate_building(self, building: building_lib.Building) -> None:
"""Link the building to this zone and link this zone to the building."""
self.osm_buildings.append(building)
building.zone = self
class BuildingZone(OSMFeatureArea):
""" A 'Landuse' OSM map feature
......@@ -389,15 +394,22 @@ class BuildingZone(OSMFeatureArea):
self.linked_blocked_areas.extend(temp_buildings.generated_blocked_areas)
self.generated_buildings.extend(temp_buildings.generated_buildings)
def relate_building(self, building: building_lib.Building) -> None:
"""Link the building to this zone and link this zone to the building."""
self.osm_buildings.append(building)
building.zone = self
def add_city_block(self, city_block: CityBlock) -> None:
self.linked_city_blocks.append(city_block)
def reassign_osm_buildings_to_city_blocks(self) -> None:
"""AS far as possible buildings are related to city_blocks.
If there is none, then the existing relation to the zone is kept also from the building."""
for osm_building in self.osm_buildings:
for city_block in self.linked_city_blocks:
if osm_building.geometry.within(city_block.geometry) or osm_building.geometry.intersects(
city_block.geometry):
city_block.osm_buildings.append(osm_building)
city_block.relate_building(osm_building)
class GeneratedBuildingZone(BuildingZone):
......@@ -1173,7 +1185,7 @@ def process_osm_railway_refs(transformer: co.Transformation) -> Dict[int, Railwa
return my_ways
def process_osm_highway_refs(transformer: co.Transformation) -> Tuple[Dict[int, Highway], Dict[int, op.Node]]:
def process_osm_highway_refs(transformer: co.Transformation) -> Dict[int, Highway]:
osm_result = op.fetch_osm_db_data_ways_keys([HIGHWAY_KEY])
my_ways = dict()
for way in list(osm_result.ways_dict.values()):
......@@ -1181,7 +1193,7 @@ def process_osm_highway_refs(transformer: co.Transformation) -> Tuple[Dict[int,
if my_way.is_valid():
my_ways[my_way.osm_id] = my_way
logging.info("OSM highways found: %s", len(my_ways))
return my_ways, osm_result.nodes_dict
return my_ways
def process_osm_waterway_refs(transformer: co.Transformation) -> Dict[int, Waterway]:
......
......@@ -5,7 +5,7 @@ import logging
import pickle
import random
import time
from typing import List
from typing import Dict, List
import sys
from shapely import speedups
......@@ -31,7 +31,7 @@ def _prepare_building_zone_for_building_generation(building_zone, open_spaces_di
"""Prepares a building zone with blocked areas and highway parts.
As soon as an element is entirely within a building zone, it is removed
from the lists in order to speedup by reducing the number of stuff to compare in the next
building zone (the lists area shared / passed by reference.
building zone (the lists area shared / passed by reference).
In order to make these removals fast the data structures must be dicts instead of lists.
Another possibility would be parallel processing, but that would lead to big
......@@ -277,7 +277,9 @@ def _read_building_models_library() -> List[m.BuildingModel]:
return models
def process(transformer: co.Transformation, building_zones: List[m.BuildingZone]) -> List[building_lib.Building]:
def process(transformer: co.Transformation, building_zones: List[m.BuildingZone],
highways_dict: Dict[int, m.Highway], railways_dict: Dict[int, m.RailwayLine],
waterways_dict: Dict[int, m.Waterway]) -> List[building_lib.Building]:
last_time = time.time()
# =========== TRY TO READ CACHED DATA FIRST =======
......@@ -295,9 +297,6 @@ def process(transformer: co.Transformation, building_zones: List[m.BuildingZone]
# =========== READ OSM DATA =============
open_spaces_dict = m.process_osm_open_space_refs(transformer)
highways_dict, nodes_dict = m.process_osm_highway_refs(transformer)
railways_dict = m.process_osm_railway_refs(transformer)
waterways_dict = m.process_osm_waterway_refs(transformer)
last_time = time_logging("Time used in seconds for parsing OSM data", last_time)
bounds = m.Bounds.create_from_parameters(transformer)
......
......@@ -316,7 +316,7 @@ OWBB_PLACE_TILE_BORDER_EXTENSION = 10000
# ==================== BUILDING GENERATION ============
OWBB_GENERATED_BUILDINGS_CACHE = False
OWBB_GENERATED_BUILDINGS_CACHE = False # has only effect if OWBB_LANDUSE_CACHE = False
OWBB_GENERATE_BUILDINGS = False
OWBB_STEP_DISTANCE = 2 # in meters
OWBB_MIN_STREET_LENGTH = 10 # in meters
......
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