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

Replacing parameters BUILDING_ROOF_*_RATIO with BUILDING_ROOF_SHAPE_RATIO as a dictionary

parent 5c9a421f
......@@ -53,22 +53,8 @@ KeyValueDict = Dict[str, str]
def _random_roof_shape() -> roofs.RoofShape:
ratio = random.uniform(0, 1)
accumulated_ratio = parameters.BUILDING_ROOF_FLAT_RATIO
if ratio <= accumulated_ratio:
return roofs.RoofShape.flat
accumulated_ratio += parameters.BUILDING_ROOF_SKILLION_RATIO
if ratio <= accumulated_ratio:
return roofs.RoofShape.skillion
accumulated_ratio += parameters.BUILDING_ROOF_GABLED_RATIO
if ratio <= accumulated_ratio:
return roofs.RoofShape.gabled
accumulated_ratio += parameters.BUILDING_ROOF_HIPPED_RATIO
if ratio <= accumulated_ratio:
return roofs.RoofShape.hipped
else:
return roofs.RoofShape.pyramidal
random_shape = utilities.random_value_from_ratio_dict_parameter(parameters.BUILDING_ROOF_SHAPE_RATIO)
return roofs.map_osm_roof_shape(random_shape)
@unique
class BuildingClass(IntEnum):
......
......@@ -311,19 +311,14 @@ BUILDING_SKEL_MAX_NODES Integer 10 The maximum
the number, the longer the execution time but the more houses actually get
realistic roofs.
============================================= ======== ======= ==============================================================================
BUILDING_ROOF_SHAPE_RATIO Dict . If the ``roof:shape`` tag is missing in OSM (which it most often is), then
this parameter can help to make region specific decisions on what roof types
are to be applied randomly with a given ratio.
The sum of the ratios must give 1.0 and the values must be one of the values
defined for RoofShapes in roof.py.
If the ``roof:shape`` tag is missing in OSM (which it most often is), then the following parameters can help to make region specific decisions on what roof types are to be applied randomly with a given ratio. The sum of the ratios must give 1.0.
============================================= ======== ======= ==============================================================================
============================================= ======== =======
Parameter Type Default
============================================= ======== =======
BUILDING_ROOF_FLAT_RATIO Decimal 0.2
BUILDING_ROOF_SKILLION_RATIO Decimal 0.1
BUILDING_ROOF_GABLED_RATIO Decimal 0.55
BUILDING_ROOF_HIPPED_RATIO Decimal 0.1
BUILDING_ROOF_PYRAMIDAL_RATIO Decimal 0.05
============================================= ======== =======
Finally the following parameters let you play around with how complex roofs are done.
......
......@@ -133,11 +133,8 @@ BUILDING_SKEL_ROOF_MAX_HEIGHT = 6. # -- skip skeleton roofs (gabled, pyramidal,
BUILDING_SKEL_ROOF_DEFAULT_HEIGHT = 2.5 # if the roof_height is not given what we use to calculate real building heihgt temporarily
# If the roof_type is missing, what shall be the distribution of roof_types (must sum up to 1.0)
BUILDING_ROOF_FLAT_RATIO = 0.2
BUILDING_ROOF_SKILLION_RATIO = 0.1
BUILDING_ROOF_GABLED_RATIO = 0.55
BUILDING_ROOF_HIPPED_RATIO = 0.1
BUILDING_ROOF_PYRAMIDAL_RATIO = 0.05
# The keys are the shapes and must correspond to valid RoofShape values in roofs.py
BUILDING_ROOF_SHAPE_RATIO = {'flat': 0.1, 'skillion': 0.05, 'gabled': 0.75, 'hipped': 0.1}
# ==================== RECTIFY BUILDINGS ============
RECTIFY_ENABLED = True
......@@ -410,7 +407,7 @@ def get_clipping_border():
return rect
def _check_ratio_dict_parameter(ratio_dict: typing.Optional[typing.Dict], name: str) -> None:
def _check_ratio_dict_parameter(ratio_dict: typing.Optional[typing.Dict], name: str, is_int: bool=True) -> None:
if ratio_dict is None:
raise ValueError('Parameter {} must not be None'.format(name))
if not isinstance(ratio_dict, dict):
......@@ -420,14 +417,18 @@ def _check_ratio_dict_parameter(ratio_dict: typing.Optional[typing.Dict], name:
total = 0.
prev_key = -9999
for key, ratio in ratio_dict.items():
if not isinstance(key, int):
raise ValueError('key {} in parameter {} must be an int'.format(str(key), name))
if prev_key > key:
raise ValueError('key {} in parameter {} must be larger than previous key'.format(str(key), name))
if is_int:
if not isinstance(key, int):
raise ValueError('key {} in parameter {} must be an int'.format(str(key), name))
if prev_key > key:
raise ValueError('key {} in parameter {} must be larger than previous key'.format(str(key), name))
prev_key = key
else:
if not isinstance(key, str):
raise ValueError('key {} in parameter {} must be a string'.format(str(key), name))
if not isinstance(ratio, float):
raise ValueError('ratio {} for key {} in param {} must be a float'.format(str(ratio), str(key), name))
total += ratio
prev_key = key
if abs(total - 1) > 0.001:
raise ValueError('The total of all ratios in param {} must be 1'.format(name))
......@@ -497,6 +498,8 @@ def read_from_file(filename):
global BUILDING_NUMBER_LEVELS_INDUSTRIAL
global BUILDING_NUMBER_LEVELS_OTHER
global BUILDING_ROOF_SHAPE_RATIO
_check_ratio_dict_parameter(BUILDING_NUMBER_LEVELS_CENTRE, 'BUILDING_NUMBER_LEVELS_CENTRE')
_check_ratio_dict_parameter(BUILDING_NUMBER_LEVELS_BLOCK, 'BUILDING_NUMBER_LEVELS_BLOCK')
_check_ratio_dict_parameter(BUILDING_NUMBER_LEVELS_DENSE, 'BUILDING_NUMBER_LEVELS_DENSE')
......@@ -505,6 +508,7 @@ def read_from_file(filename):
_check_ratio_dict_parameter(BUILDING_NUMBER_LEVELS_APARTMENTS, 'BUILDING_NUMBER_LEVELS_APARTMENTS')
_check_ratio_dict_parameter(BUILDING_NUMBER_LEVELS_INDUSTRIAL, 'BUILDING_NUMBER_LEVELS_INDUSTRIAL')
_check_ratio_dict_parameter(BUILDING_NUMBER_LEVELS_OTHER, 'BUILDING_NUMBER_LEVELS_OTHER')
_check_ratio_dict_parameter(BUILDING_ROOF_SHAPE_RATIO, 'BUILDING_ROOF_SHAPE_RATIO', False)
def show_default():
......
......@@ -59,7 +59,9 @@ def map_osm_roof_shape(osm_roof_shape: str) -> RoofShape:
if _shape == 'onion':
return RoofShape.onion
# fall back for all not directly handled OSM types
# fall back for all not directly handled OSM types. The rational for using "hipped" as default is that most
# probably if someone actually has tried to specify a shape, then 'flat' is unliekly to be misspelled and
# most probably a form with a ridge was meant.
logging.debug('Not handled roof shape found: %s. Therefore transformed to "hipped".', _shape)
return RoofShape.hipped
......
......@@ -15,7 +15,7 @@ import subprocess
import sys
import textwrap
import time
from typing import Dict, List, Optional, Tuple
from typing import Any, Dict, List, Optional, Tuple
import unittest
import numpy as np
......@@ -543,15 +543,15 @@ def bounds_from_list(bounds_list: List[Tuple[float, float, float, float]]) -> Tu
return min_x, min_y, max_x, max_y
def random_value_from_ratio_dict_parameter(ratio_parameter: Dict[int, float]) -> int:
def random_value_from_ratio_dict_parameter(ratio_parameter: Dict[Any, float]):
target_ratio = random.random()
return value_from_ratio_dict_parameter(target_ratio, ratio_parameter)
def value_from_ratio_dict_parameter(target_ratio: float, ratio_parameter: Dict[int, float]) -> int:
def value_from_ratio_dict_parameter(target_ratio: float, ratio_parameter: Dict[Any, float]):
"""Finds the key value closet to and below the target ratio."""
total_ratio = 0.
return_value = 0
return_value = None
for key, ratio in ratio_parameter.items():
if target_ratio <= total_ratio:
return return_value
......
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