Generate facilities from buildings in a city
This commit is contained in:
parent
e3108e08ad
commit
2baf9ec518
BIN
__pycache__/hub_function_to_matsim_activity.cpython-39.pyc
Normal file
BIN
__pycache__/hub_function_to_matsim_activity.cpython-39.pyc
Normal file
Binary file not shown.
BIN
__pycache__/matsim_activity_to_matsim_schedule.cpython-39.pyc
Normal file
BIN
__pycache__/matsim_activity_to_matsim_schedule.cpython-39.pyc
Normal file
Binary file not shown.
BIN
__pycache__/matsim_engine.cpython-39.pyc
Normal file
BIN
__pycache__/matsim_engine.cpython-39.pyc
Normal file
Binary file not shown.
78
hub_function_to_matsim_activity.py
Normal file
78
hub_function_to_matsim_activity.py
Normal file
|
@ -0,0 +1,78 @@
|
|||
import hub.helpers.constants as cte
|
||||
|
||||
class HubFunctionToMatsimActivity:
|
||||
"""
|
||||
Hub function to nrcan construction function class
|
||||
"""
|
||||
def __init__(self):
|
||||
self._dictionary = {
|
||||
cte.RESIDENTIAL: 'home',
|
||||
cte.SINGLE_FAMILY_HOUSE: 'home',
|
||||
cte.MULTI_FAMILY_HOUSE: 'home',
|
||||
cte.ROW_HOUSE: 'home',
|
||||
cte.MID_RISE_APARTMENT: 'home',
|
||||
cte.HIGH_RISE_APARTMENT: 'home',
|
||||
cte.OFFICE_AND_ADMINISTRATION: 'work',
|
||||
cte.SMALL_OFFICE: 'work',
|
||||
cte.MEDIUM_OFFICE: 'work',
|
||||
cte.LARGE_OFFICE: 'work',
|
||||
cte.COURTHOUSE: 'work',
|
||||
cte.FIRE_STATION: 'work',
|
||||
cte.PENITENTIARY: 'work',
|
||||
cte.POLICE_STATION: 'work',
|
||||
cte.POST_OFFICE: 'work',
|
||||
cte.LIBRARY: 'edu',
|
||||
cte.EDUCATION: 'edu',
|
||||
cte.PRIMARY_SCHOOL: 'edu',
|
||||
cte.PRIMARY_SCHOOL_WITH_SHOWER: 'edu',
|
||||
cte.SECONDARY_SCHOOL: 'edu',
|
||||
cte.UNIVERSITY: 'edu',
|
||||
cte.LABORATORY_AND_RESEARCH_CENTER: 'edu',
|
||||
cte.STAND_ALONE_RETAIL: 'secondary',
|
||||
cte.HOSPITAL: 'work',
|
||||
cte.OUT_PATIENT_HEALTH_CARE: 'work',
|
||||
cte.HEALTH_CARE: 'work',
|
||||
cte.RETIREMENT_HOME_OR_ORPHANAGE: 'home',
|
||||
cte.COMMERCIAL: 'secondary',
|
||||
cte.STRIP_MALL: 'secondary',
|
||||
cte.SUPERMARKET: 'secondary',
|
||||
cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'secondary',
|
||||
cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'secondary',
|
||||
cte.RESTAURANT: 'secondary',
|
||||
cte.QUICK_SERVICE_RESTAURANT: 'secondary',
|
||||
cte.FULL_SERVICE_RESTAURANT: 'secondary',
|
||||
cte.HOTEL: 'work',
|
||||
cte.HOTEL_MEDIUM_CLASS: 'work',
|
||||
cte.SMALL_HOTEL: 'work',
|
||||
cte.LARGE_HOTEL: 'work',
|
||||
cte.DORMITORY: 'work',
|
||||
cte.EVENT_LOCATION: 'secondary',
|
||||
cte.CONVENTION_CENTER: 'secondary',
|
||||
cte.HALL: 'secondary',
|
||||
cte.GREEN_HOUSE: 'secondary',
|
||||
cte.INDUSTRY: 'work',
|
||||
cte.WORKSHOP: 'work',
|
||||
cte.WAREHOUSE: 'work',
|
||||
cte.WAREHOUSE_REFRIGERATED: 'work',
|
||||
cte.SPORTS_LOCATION: 'secondary',
|
||||
cte.SPORTS_ARENA: 'secondary',
|
||||
cte.GYMNASIUM: 'secondary',
|
||||
cte.MOTION_PICTURE_THEATRE: 'secondary',
|
||||
cte.MUSEUM: 'secondary',
|
||||
cte.PERFORMING_ARTS_THEATRE: 'secondary',
|
||||
cte.TRANSPORTATION: 'secondary',
|
||||
cte.AUTOMOTIVE_FACILITY: 'work',
|
||||
cte.PARKING_GARAGE: 'work',
|
||||
cte.RELIGIOUS: 'secondary',
|
||||
cte.NON_HEATED: 'secondary',
|
||||
cte.DATACENTER: 'work',
|
||||
cte.FARM: 'work'
|
||||
}
|
||||
|
||||
@property
|
||||
def dictionary(self) -> dict:
|
||||
"""
|
||||
Get the dictionary
|
||||
:return: {}
|
||||
"""
|
||||
return self._dictionary
|
2473
input_files/summerschool_all_buildings.geojson
Normal file
2473
input_files/summerschool_all_buildings.geojson
Normal file
File diff suppressed because it is too large
Load Diff
294
input_files/summerschool_one_building.geojson
Normal file
294
input_files/summerschool_one_building.geojson
Normal file
|
@ -0,0 +1,294 @@
|
|||
{
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": 12,
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[
|
||||
-73.57945149010348,
|
||||
45.49793915473101
|
||||
],
|
||||
[
|
||||
-73.57945502047383,
|
||||
45.497935600591106
|
||||
],
|
||||
[
|
||||
-73.57945748913181,
|
||||
45.49793681276347
|
||||
],
|
||||
[
|
||||
-73.57945995778985,
|
||||
45.49793802493576
|
||||
],
|
||||
[
|
||||
-73.57946108986009,
|
||||
45.49793688584562
|
||||
],
|
||||
[
|
||||
-73.57946222064952,
|
||||
45.49793574585649
|
||||
],
|
||||
[
|
||||
-73.57946503164756,
|
||||
45.497932909392325
|
||||
],
|
||||
[
|
||||
-73.5794800321942,
|
||||
45.497917804072586
|
||||
],
|
||||
[
|
||||
-73.57949503273288,
|
||||
45.49790269875081
|
||||
],
|
||||
[
|
||||
-73.57950823165471,
|
||||
45.49788939886833
|
||||
],
|
||||
[
|
||||
-73.57952143057031,
|
||||
45.497876098984314
|
||||
],
|
||||
[
|
||||
-73.57952481016481,
|
||||
45.49787269972034
|
||||
],
|
||||
[
|
||||
-73.57952818975889,
|
||||
45.49786930045622
|
||||
],
|
||||
[
|
||||
-73.57963374256275,
|
||||
45.49776298233438
|
||||
],
|
||||
[
|
||||
-73.57963739684415,
|
||||
45.497759299424665
|
||||
],
|
||||
[
|
||||
-73.57956562282082,
|
||||
45.49772405755894
|
||||
],
|
||||
[
|
||||
-73.5795624921933,
|
||||
45.497722521006246
|
||||
],
|
||||
[
|
||||
-73.57955974509859,
|
||||
45.4977252944393
|
||||
],
|
||||
[
|
||||
-73.57953557695755,
|
||||
45.497749634054365
|
||||
],
|
||||
[
|
||||
-73.5795114087957,
|
||||
45.497773973664174
|
||||
],
|
||||
[
|
||||
-73.57945076790263,
|
||||
45.49783505227953
|
||||
],
|
||||
[
|
||||
-73.57939012687844,
|
||||
45.49789613086214
|
||||
],
|
||||
[
|
||||
-73.57938759058709,
|
||||
45.49789868818189
|
||||
],
|
||||
[
|
||||
-73.57938505429556,
|
||||
45.49790124550157
|
||||
],
|
||||
[
|
||||
-73.57941717242674,
|
||||
45.49791701633786
|
||||
],
|
||||
[
|
||||
-73.5794136407655,
|
||||
45.497920563278754
|
||||
],
|
||||
[
|
||||
-73.57943256542505,
|
||||
45.497929854507255
|
||||
],
|
||||
[
|
||||
-73.57944202776348,
|
||||
45.49793450461953
|
||||
],
|
||||
[
|
||||
-73.57945149010348,
|
||||
45.49793915473101
|
||||
]
|
||||
]
|
||||
]
|
||||
},
|
||||
"properties": {
|
||||
"OBJECTID_12": 12,
|
||||
"gml_id": 1340982,
|
||||
"gml_parent": "fme-gen-5fa2a82b-c38e-4bf0-9e8f-10a47b9f64f7",
|
||||
"citygml_ta": "http://www.opengis.net/citygml/building/2.0",
|
||||
"citygml_fe": "cityObjectMember",
|
||||
"citygml__1": " ",
|
||||
"citygml__2": " ",
|
||||
"gml_descri": " ",
|
||||
"gml_name": " ",
|
||||
"citygml_cr": " ",
|
||||
"citygml_te": " ",
|
||||
"externalRe": " ",
|
||||
"external_1": " ",
|
||||
"external_2": " ",
|
||||
"citygml_ge": " ",
|
||||
"citygml_re": " ",
|
||||
"citygml__3": " ",
|
||||
"citygml_ap": " ",
|
||||
"citygml_cl": " ",
|
||||
"citygml__4": " ",
|
||||
"citygml_fu": " ",
|
||||
"citygml__5": " ",
|
||||
"citygml_us": " ",
|
||||
"citygml__6": " ",
|
||||
"citygml_ye": " ",
|
||||
"citygml__7": " ",
|
||||
"citygml_ro": " ",
|
||||
"citygml__8": " ",
|
||||
"citygml_me": 19.113,
|
||||
"citygml__9": "#m",
|
||||
"citygml_st": " ",
|
||||
"citygml_10": " ",
|
||||
"citygml_11": " ",
|
||||
"citygml_12": " ",
|
||||
"citygml_13": " ",
|
||||
"citygml_14": " ",
|
||||
"citygml_ou": " ",
|
||||
"citygml_in": " ",
|
||||
"citygml_bo": " ",
|
||||
"citygml_le": " ",
|
||||
"citygml_15": " ",
|
||||
"citygml_co": " ",
|
||||
"citygml_ad": " ",
|
||||
"Volume": "2931.350",
|
||||
"parcelle": " ",
|
||||
"OBJECTID": 1056,
|
||||
"gml_id_1": "384b2b1c-2e25-4f6a-b082-d272dba3453f",
|
||||
"gml_pare_1": 1340982,
|
||||
"citygml_16": "http://www.opengis.net/citygml/building/2.0",
|
||||
"citygml_17": "boundedBy",
|
||||
"citygml_18": " ",
|
||||
"citygml_19": " ",
|
||||
"gml_desc_1": " ",
|
||||
"gml_name_1": " ",
|
||||
"citygml_20": " ",
|
||||
"citygml_21": " ",
|
||||
"external_3": " ",
|
||||
"external_4": " ",
|
||||
"external_5": " ",
|
||||
"citygml_22": " ",
|
||||
"citygml_23": " ",
|
||||
"citygml_24": " ",
|
||||
"citygml_25": " ",
|
||||
"citygml_26": " ",
|
||||
"citygml_op": " ",
|
||||
"Area": 191.404,
|
||||
"FID_": 0,
|
||||
"Join_Count": 2,
|
||||
"TARGET_FID": 1058,
|
||||
"gml_id_12": 1340982,
|
||||
"gml_pare_2": "fme-gen-5fa2a82b-c38e-4bf0-9e8f-10a47b9f64f7",
|
||||
"citygml_27": "http://www.opengis.net/citygml/building/2.0",
|
||||
"citygml_28": "cityObjectMember",
|
||||
"citygml_29": " ",
|
||||
"citygml_30": " ",
|
||||
"gml_desc_2": " ",
|
||||
"gml_name_2": " ",
|
||||
"citygml_31": " ",
|
||||
"citygml_32": " ",
|
||||
"external_6": " ",
|
||||
"external_7": " ",
|
||||
"external_8": " ",
|
||||
"citygml_33": " ",
|
||||
"citygml_34": " ",
|
||||
"citygml_35": " ",
|
||||
"citygml_36": " ",
|
||||
"citygml_37": " ",
|
||||
"citygml_38": " ",
|
||||
"citygml_39": " ",
|
||||
"citygml_40": " ",
|
||||
"citygml_41": " ",
|
||||
"citygml_42": " ",
|
||||
"citygml_43": " ",
|
||||
"citygml_44": " ",
|
||||
"citygml_45": " ",
|
||||
"citygml_46": " ",
|
||||
"citygml_47": 19.113,
|
||||
"citygml_48": "#m",
|
||||
"citygml_49": " ",
|
||||
"citygml_50": " ",
|
||||
"citygml_51": " ",
|
||||
"citygml_52": " ",
|
||||
"citygml_53": " ",
|
||||
"citygml_54": " ",
|
||||
"citygml_55": " ",
|
||||
"citygml_56": " ",
|
||||
"citygml_57": " ",
|
||||
"citygml_58": " ",
|
||||
"citygml_59": " ",
|
||||
"citygml_60": " ",
|
||||
"citygml_61": " ",
|
||||
"Volume_1": "2931.350",
|
||||
"Field": 0,
|
||||
"Field1": 0,
|
||||
"OBJECTID_1": 1056,
|
||||
"gml_id_12_": "384b2b1c-2e25-4f6a-b082-d272dba3453f",
|
||||
"gml_pare_3": 1340982,
|
||||
"citygml_62": "http://www.opengis.net/citygml/building/2.0",
|
||||
"citygml_63": "boundedBy",
|
||||
"citygml_64": " ",
|
||||
"citygml_65": " ",
|
||||
"gml_desc_3": " ",
|
||||
"gml_name_3": " ",
|
||||
"citygml_66": " ",
|
||||
"citygml_67": " ",
|
||||
"external_9": " ",
|
||||
"externa_10": " ",
|
||||
"externa_11": " ",
|
||||
"citygml_68": " ",
|
||||
"citygml_69": " ",
|
||||
"citygml_70": " ",
|
||||
"citygml_71": " ",
|
||||
"citygml_72": " ",
|
||||
"citygml_73": " ",
|
||||
"Area_1": 191.404,
|
||||
"cityGML_hi": 0,
|
||||
"Z_Min": 46.1162,
|
||||
"Z_Max": 64.399,
|
||||
"Shape_Leng": 63.6906066955,
|
||||
"ID_UEV": "01036804",
|
||||
"CIVIQUE_DE": " 2170",
|
||||
"CIVIQUE_FI": " 2170",
|
||||
"NOM_RUE": "rue Bishop (MTL)",
|
||||
"MUNICIPALI": 50,
|
||||
"ETAGE_HORS": 3,
|
||||
"NOMBRE_LOG": 1,
|
||||
"ANNEE_CONS": 1900,
|
||||
"CODE_UTILI": 6000,
|
||||
"LIBELLE_UT": "Immeuble à bureaux",
|
||||
"CATEGORIE_": "Régulier",
|
||||
"MATRICULE8": "9839-57-7770-3-000-0000",
|
||||
"SUPERFICIE": 259,
|
||||
"SUPERFIC_1": 490,
|
||||
"NO_ARROND_": "REM19",
|
||||
"Shape_Le_1": 0.00093336765858,
|
||||
"Shape_Ar_1": 3.0845126501e-8,
|
||||
"Z_Min_1": null,
|
||||
"Z_Max_1": null,
|
||||
"Shape_Length": 63.69060669550123,
|
||||
"Shape_Area": 174.69050030775531
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
2473
input_files/test_buildings.geojson
Normal file
2473
input_files/test_buildings.geojson
Normal file
File diff suppressed because it is too large
Load Diff
45
main.py
45
main.py
|
@ -1,20 +1,37 @@
|
|||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
def run_matsim(config_file_path=None):
|
||||
java_path = "java"
|
||||
jar_path = "matsim.jar"
|
||||
command = [java_path, "-jar", jar_path]
|
||||
from hub.imports.geometry_factory import GeometryFactory
|
||||
from hub.imports.construction_factory import ConstructionFactory
|
||||
from hub.imports.usage_factory import UsageFactory
|
||||
from hub.helpers.dictionaries import Dictionaries
|
||||
|
||||
if config_file_path:
|
||||
command.append(config_file_path)
|
||||
from matsim_engine import MatSimEngine
|
||||
|
||||
subprocess.run(command)
|
||||
try:
|
||||
file_path = (Path(__file__).parent / 'input_files' / 'summerschool_all_buildings.geojson')
|
||||
construction_format = 'nrcan'
|
||||
usage_format = 'nrcan'
|
||||
energy_systems_format = 'montreal_custom'
|
||||
|
||||
out_path = (Path(__file__).parent / 'output_files')
|
||||
tmp_folder = (Path(__file__).parent / 'tmp')
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
config_file = sys.argv[1]
|
||||
else:
|
||||
config_file = None
|
||||
print('[simulation start]')
|
||||
city = GeometryFactory('geojson',
|
||||
path=file_path,
|
||||
height_field='citygml_me',
|
||||
year_of_construction_field='ANNEE_CONS',
|
||||
function_field='CODE_UTILI',
|
||||
function_to_hub=Dictionaries().montreal_function_to_hub_function).city
|
||||
|
||||
run_matsim(config_file)
|
||||
print(f'city created from {file_path}')
|
||||
ConstructionFactory(construction_format, city).enrich()
|
||||
print('enrich constructions... done')
|
||||
UsageFactory(usage_format, city).enrich()
|
||||
print('enrich usage... done')
|
||||
|
||||
MatSimEngine(city, 'output_files')
|
||||
|
||||
except Exception as ex:
|
||||
print('error: ', ex)
|
||||
print('[simulation abort]')
|
||||
|
|
19
matsim_activity_to_matsim_schedule.py
Normal file
19
matsim_activity_to_matsim_schedule.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
class MatsimActivityToMatsimSchedule:
|
||||
"""
|
||||
Hub function to nrcan construction function class
|
||||
"""
|
||||
def __init__(self):
|
||||
self._dictionary = {
|
||||
'work': '08:00:00-18:00:00',
|
||||
'home': '00:00:00-30:00:00',
|
||||
'edu': '08:00:00-18:00:00',
|
||||
'secondary': '08:00:00-20:00:00'
|
||||
}
|
||||
|
||||
@property
|
||||
def dictionary(self) -> dict:
|
||||
"""
|
||||
Get the dictionary
|
||||
:return: {}
|
||||
"""
|
||||
return self._dictionary
|
66
matsim_engine.py
Normal file
66
matsim_engine.py
Normal file
|
@ -0,0 +1,66 @@
|
|||
import subprocess
|
||||
import xmltodict
|
||||
|
||||
from matsim_activity_to_matsim_schedule import MatsimActivityToMatsimSchedule
|
||||
from hub_function_to_matsim_activity import HubFunctionToMatsimActivity
|
||||
|
||||
class MatSimEngine:
|
||||
def __init__(self, city, output_file_path):
|
||||
self._city = city
|
||||
self._output_file_path = output_file_path
|
||||
|
||||
facilities_dict = {
|
||||
'facilities': {
|
||||
'@name': 'Montreal Facilities',
|
||||
'facility': []
|
||||
}
|
||||
}
|
||||
|
||||
hub_function_to_matsim = HubFunctionToMatsimActivity()
|
||||
matsim_schedule = MatsimActivityToMatsimSchedule()
|
||||
|
||||
# 1- Facilities
|
||||
# TODO: Add the ability for a building to have multiple activities
|
||||
for building in city.buildings:
|
||||
activity = hub_function_to_matsim.dictionary[building.function]
|
||||
schedule = matsim_schedule.dictionary[activity]
|
||||
start_time, end_time = schedule.split('-')
|
||||
|
||||
facility = {
|
||||
'@id': building.name,
|
||||
'@x': str(building.centroid[0]),
|
||||
'@y': str(building.centroid[1]),
|
||||
'activity': {
|
||||
'@type': activity,
|
||||
'capacity': {
|
||||
'@value': '4.0' # TODO: Replace with a proper value taken from function
|
||||
},
|
||||
'opentime': {
|
||||
'@day': 'wkday',
|
||||
'@start_time': start_time,
|
||||
'@end_time': end_time
|
||||
}
|
||||
}
|
||||
}
|
||||
facilities_dict['facilities']['facility'].append(facility)
|
||||
|
||||
# Convert the Python dictionary to an XML string
|
||||
xml_content = xmltodict.unparse(facilities_dict, pretty=True)
|
||||
|
||||
# Write the XML to the file
|
||||
with open(f"{output_file_path}/montreal_facilities.xml", 'w') as file:
|
||||
file.write(xml_content)
|
||||
|
||||
# 2- Network
|
||||
# 3- Population
|
||||
# 4- Config Generation
|
||||
|
||||
def run(self):
|
||||
java_path = "java"
|
||||
jar_path = "matsim.jar"
|
||||
command = [java_path, "-jar", jar_path]
|
||||
|
||||
# Must generate this config file first.
|
||||
# command.append(config_file_path)
|
||||
|
||||
subprocess.run(command)
|
51
output_files/montreal_facilities.xml
Normal file
51
output_files/montreal_facilities.xml
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<facilities name="Montreal Facilities">
|
||||
<facility id="3" x="3854959.3147786935" y="6039970.256562924">
|
||||
<activity type="secondary">
|
||||
<capacity value="4.0"></capacity>
|
||||
<opentime day="wkday" start_time="08:00:00" end_time="20:00:00"></opentime>
|
||||
</activity>
|
||||
</facility>
|
||||
<facility id="5" x="3854967.9909430863" y="6039992.286574578">
|
||||
<activity type="home">
|
||||
<capacity value="4.0"></capacity>
|
||||
<opentime day="wkday" start_time="00:00:00" end_time="30:00:00"></opentime>
|
||||
</activity>
|
||||
</facility>
|
||||
<facility id="6" x="3854961.5685679" y="6039981.23266926">
|
||||
<activity type="home">
|
||||
<capacity value="4.0"></capacity>
|
||||
<opentime day="wkday" start_time="00:00:00" end_time="30:00:00"></opentime>
|
||||
</activity>
|
||||
</facility>
|
||||
<facility id="8" x="3854996.7269906714" y="6040014.087941397">
|
||||
<activity type="work">
|
||||
<capacity value="4.0"></capacity>
|
||||
<opentime day="wkday" start_time="08:00:00" end_time="18:00:00"></opentime>
|
||||
</activity>
|
||||
</facility>
|
||||
<facility id="9" x="3855012.732080259" y="6040010.546487992">
|
||||
<activity type="work">
|
||||
<capacity value="4.0"></capacity>
|
||||
<opentime day="wkday" start_time="08:00:00" end_time="18:00:00"></opentime>
|
||||
</activity>
|
||||
</facility>
|
||||
<facility id="12" x="3855004.9829044794" y="6040017.1087535">
|
||||
<activity type="work">
|
||||
<capacity value="4.0"></capacity>
|
||||
<opentime day="wkday" start_time="08:00:00" end_time="18:00:00"></opentime>
|
||||
</activity>
|
||||
</facility>
|
||||
<facility id="67" x="3854967.5354593457" y="6040000.320902303">
|
||||
<activity type="work">
|
||||
<capacity value="4.0"></capacity>
|
||||
<opentime day="wkday" start_time="08:00:00" end_time="18:00:00"></opentime>
|
||||
</activity>
|
||||
</facility>
|
||||
<facility id="68" x="3854966.6880635563" y="6040020.215150922">
|
||||
<activity type="work">
|
||||
<capacity value="4.0"></capacity>
|
||||
<opentime day="wkday" start_time="08:00:00" end_time="18:00:00"></opentime>
|
||||
</activity>
|
||||
</facility>
|
||||
</facilities>
|
249074
scenarios/sioux/Siouxfalls_facilities.xml/Siouxfalls_facilities.xml
Normal file
249074
scenarios/sioux/Siouxfalls_facilities.xml/Siouxfalls_facilities.xml
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user