File size: 4,050 Bytes
b939fb6 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
import geopandas as gpd
import pandas as pd
from arcgis.features import FeatureLayer
from arcgis.geometry import Geometry
from shapely.geometry import shape
from shapely.ops import unary_union
# all data processing functions
def get_gdf_from_feature_layer(url):
# Access the ArcGIS feature layer
feature_layer = FeatureLayer(url)
# Use the query() method to get all features where 'Borough' is 'MN'
sdf = feature_layer.query(where="Borough='MN'", out_sr=4326, as_df=True)
# Convert the 'SHAPE' column from ArcGIS's JSON-based format into a Shapely geometry
sdf['geometry'] = sdf['SHAPE'].apply(lambda x: Geometry(x).as_shapely)
# Convert the SpatialDataFrame to a GeoDataFrame
gdf = gpd.GeoDataFrame(sdf, geometry='geometry')
return gdf
def process_buildings(input_gdf, sensitive_sites_gdf, default_building_height_m, multiplier_factor):
# List to store all intersected sensitive sites
intersected_sites = []
# List to store all buffers
buffers = []
intersection_desc = ""
# Iterate over each building in the input file
for idx, building in input_gdf.iterrows():
building_name = building.get('building_name', 'Unnamed building')
# If the 'building_height' field exists and its value is not null or zero for this building,
# use it as the building height. Otherwise, use the default building height provided by the user.
if 'building_height' in building and pd.notnull(building['building_height']) and building['building_height'] != 0:
building_height_m = building['building_height'] * 0.3048
else:
building_height_m = default_building_height_m
buffer_distance_m = building_height_m * multiplier_factor
# Convert building's geometry to EPSG:3857 for accurate meter-based distance measurement
building_geometry = gpd.GeoSeries([building['geometry']], crs="EPSG:4326")
building_geometry_m = building_geometry.to_crs("EPSG:3857")
# Create a buffer around the building and convert it to a GeoDataFrame
building_buffer = building_geometry_m.buffer(buffer_distance_m)
building_buffer_gdf = gpd.GeoDataFrame(geometry=building_buffer, crs="EPSG:3857")
building_buffer_gdf = building_buffer_gdf.to_crs("EPSG:4326")
# Convert back to feet for storing and printing, rounding to the nearest foot
building_height_ft = round(building_height_m / 0.3048)
buffer_distance_ft = round(buffer_distance_m / 0.3048)
# Assign additional attributes
building_buffer_gdf['building_name'] = building_name
building_buffer_gdf['building_height'] = building_height_ft
building_buffer_gdf['buffer_distance'] = buffer_distance_ft
buffers.append(building_buffer_gdf)
# Check if the buffer intersects with any sensitive sites
intersects = gpd.overlay(building_buffer_gdf, sensitive_sites_gdf, how='intersection')
if not intersects.empty:
building_intersect_desc = f"Building {idx} ({building_name}), height: {building_height_ft}, buffer distance: {buffer_distance_ft} is in the vicinity of a sensitive site."
intersected_sites.append(intersects)
else:
building_intersect_desc = f"Building {idx} ({building_name}), height: {building_height_ft}, buffer distance: {buffer_distance_ft} is not in the vicinity of any sensitive sites."
if intersection_desc == "":
intersection_desc = building_intersect_desc
else:
intersection_desc += "\n" + building_intersect_desc
return buffers, intersected_sites, intersection_desc
def get_max_extent(*gdfs): # takes in unlimited number of gdfs and calculates max/min xy extents
minx = min(gdf.total_bounds[0] for gdf in gdfs)
miny = min(gdf.total_bounds[1] for gdf in gdfs)
maxx = max(gdf.total_bounds[2] for gdf in gdfs)
maxy = max(gdf.total_bounds[3] for gdf in gdfs)
return minx, miny, maxx, maxy |