File size: 6,083 Bytes
3894000
 
a767f1e
3894000
de3d1f9
3894000
de3d1f9
 
 
 
 
 
 
 
a767f1e
 
de3d1f9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a767f1e
de3d1f9
a767f1e
de3d1f9
 
a767f1e
de3d1f9
a767f1e
 
 
 
de3d1f9
 
a767f1e
3894000
de3d1f9
 
 
 
 
 
 
 
 
 
 
 
 
a767f1e
3894000
de3d1f9
 
 
 
3894000
de3d1f9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3894000
a767f1e
de3d1f9
3894000
 
de3d1f9
3894000
de3d1f9
 
 
86258b2
 
3894000
de3d1f9
 
 
c3c16bf
de3d1f9
 
 
3894000
86258b2
3894000
 
 
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import gradio as gr
import geopandas as gpd
import os
from shapely.geometry import shape
#from datasets import load_dataset

#ds = load_dataset('psalama/NYC_sensitive_sites', data_files=data_files)

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."

        intersection_desc = "\n".join(intersection_desc, building_intersect_desc)
        
    
    return buffers, intersected_sites, intersection_desc


def ss_intersect(geojson1, ss_geoselect, multiplier_factor, default_building_height): 
    # Read the GeoJSON files
    input_gdf = gpd.read_file(geojson1.name)

    # Check that CRS is EPSG:4326
    if input_gdf.crs.to_epsg() != 4326 or sensitive_sites_gdf.crs.to_epsg() != 4326:
        raise ValueError("Input GeoJSON files must be in CRS EPSG:4326")
    
    if ss_geoselect==0:
        sensitive_sites_gdf = gpd.read_file("sensitive_sites/NYC_Parks_Properties.geojson")
    else:
        sensitive_sites_gdf = gpd.read_file("sensitive_sites/NYC_Parks_Zones.geojson")

    default_building_height_m = default_building_height * 0.3048

    buffers, intersected_sites, intersection_desc = process_buildings(input_gdf, sensitive_sites_gdf, default_building_height_m, multiplier_factor)

    # Concatenate all buffer GeoDataFrames and save as a GeoJSON file
    buffers_gdf = pd.concat(buffers, ignore_index=True)
    buffers_gdf = buffers_gdf.to_crs("EPSG:4326")
    buffers_gdf.to_file("building_buffers.geojson", driver='GeoJSON')

    # Concatenate all intersected sensitive sites and save as a GeoJSON file
    if intersected_sites:
        intersected_sites_gdf = pd.concat(intersected_sites, ignore_index=True)
        intersected_sites_gdf = intersected_sites_gdf.to_crs("EPSG:4326")
        intersected_sites_gdf.to_file("intersected_sensitive_sites.geojson", driver='GeoJSON')
    else:
        print("No buildings are in the vicinity of any sensitive sites.")

    # Perform the union operation if there is more than one buffer
    if len(buffers) > 1:
        # Perform a unary union on the geometry column of the GeoDataFrame
        buffer_union = unary_union(buffers_gdf['geometry'])

        # Create a new GeoDataFrame from the union result
        buffer_union_gdf = gpd.GeoDataFrame(geometry=[buffer_union], crs="EPSG:4326")

        # Save the union GeoDataFrame as a GeoJSON file
        buffer_union_gdf.to_file("buffer_union.geojson", driver='GeoJSON')

            
    # Return the image
    return "building_buffers.geojson", intersection_desc


iface = gr.Interface(
    fn=ss_intersect, 
    inputs=[
        gr.inputs.File(label="Building Footprints GeoJSON"),
        gr.Radio(["Parks Properties", "Park Zones"], label="Which Sensitive Sites?", info="From NYC DPR", type="index"),
        #gr.inputs.File(label="Sensitive Sites GeoJSON"), #Replaced by radio button above
        gr.inputs.Slider(minimum=0.0, maximum=10.0, default=4.3, label="Building Height Multiplier"),
        gr.inputs.Number(default=200, label="Default Building Height"), #Can I make this optional?
    ], 
    outputs=[
        gr.outputs.File(label="Intersecting Buildings"),
        gr.outputs.Textbox(label="Building and Sensitive Site Vicinities"),
    ],
    examples=[
        ["files/building4test.geojson", "Parks Properties", 4.3, 200],
    ],
    title="Shadow Proximity",
    description="Upload proposed building footprints in a GeoJSON file and select a numeric value to get the building proximity prediction.",
)

iface.launch()