Source code for voxcity.geoprocessor.raster.export
import numpy as np
import geopandas as gpd
from shapely.geometry import box
from pyproj import CRS
from ..utils import setup_transformer
[docs]
def grid_to_geodataframe(grid_ori, rectangle_vertices, meshsize):
"""
Converts a 2D grid to a GeoDataFrame with cell polygons and values.
Output CRS: EPSG:4326
"""
# Grids arrive in uv_m (SOUTH_UP) after Phase 3: row 0 is the southern edge.
grid = grid_ori.copy()
min_lon = min(v[0] for v in rectangle_vertices)
max_lon = max(v[0] for v in rectangle_vertices)
min_lat = min(v[1] for v in rectangle_vertices)
max_lat = max(v[1] for v in rectangle_vertices)
rows, cols = grid.shape
transformer_to_mercator = setup_transformer("EPSG:4326", "EPSG:3857")
transformer_to_wgs84 = setup_transformer("EPSG:3857", "EPSG:4326")
min_x, min_y = transformer_to_mercator.transform(min_lon, min_lat)
max_x, max_y = transformer_to_mercator.transform(max_lon, max_lat)
cell_size_x = (max_x - min_x) / cols
cell_size_y = (max_y - min_y) / rows
# Vectorized: compute all cell edges at once
j_idx = np.arange(cols)
i_idx = np.arange(rows)
cell_min_xs = min_x + j_idx * cell_size_x
cell_max_xs = min_x + (j_idx + 1) * cell_size_x
cell_min_ys = min_y + i_idx * cell_size_y
cell_max_ys = min_y + (i_idx + 1) * cell_size_y
# Meshgrid for all cells (row-major: i varies slowest)
jj, ii = np.meshgrid(j_idx, i_idx)
min_xs_flat = cell_min_xs[jj.ravel()]
max_xs_flat = cell_max_xs[jj.ravel()]
min_ys_flat = cell_min_ys[ii.ravel()]
max_ys_flat = cell_max_ys[ii.ravel()]
# Batch transform all corners to WGS84
min_lons, min_lats = transformer_to_wgs84.transform(min_xs_flat, min_ys_flat)
max_lons, max_lats = transformer_to_wgs84.transform(max_xs_flat, max_ys_flat)
polygons = [box(lo1, la1, lo2, la2) for lo1, la1, lo2, la2 in zip(min_lons, min_lats, max_lons, max_lats)]
values = grid.ravel().tolist()
gdf = gpd.GeoDataFrame({'geometry': polygons, 'value': values}, crs=CRS.from_epsg(4326))
return gdf
[docs]
def grid_to_point_geodataframe(grid_ori, rectangle_vertices, meshsize):
"""
Converts a 2D grid to a GeoDataFrame with point geometries at cell centers and values.
Output CRS: EPSG:4326
"""
from shapely.geometry import Point
# Grids arrive in uv_m (SOUTH_UP) after Phase 3: row 0 is the southern edge.
grid = grid_ori.copy()
min_lon = min(v[0] for v in rectangle_vertices)
max_lon = max(v[0] for v in rectangle_vertices)
min_lat = min(v[1] for v in rectangle_vertices)
max_lat = max(v[1] for v in rectangle_vertices)
rows, cols = grid.shape
transformer_to_mercator = setup_transformer("EPSG:4326", "EPSG:3857")
transformer_to_wgs84 = setup_transformer("EPSG:3857", "EPSG:4326")
min_x, min_y = transformer_to_mercator.transform(min_lon, min_lat)
max_x, max_y = transformer_to_mercator.transform(max_lon, max_lat)
cell_size_x = (max_x - min_x) / cols
cell_size_y = (max_y - min_y) / rows
# Vectorized: compute all cell centers at once
j_idx = np.arange(cols)
i_idx = np.arange(rows)
center_xs = min_x + (j_idx + 0.5) * cell_size_x
center_ys = min_y + (i_idx + 0.5) * cell_size_y
jj, ii = np.meshgrid(j_idx, i_idx)
cx_flat = center_xs[jj.ravel()]
cy_flat = center_ys[ii.ravel()]
# Batch transform to WGS84
lons, lats = transformer_to_wgs84.transform(cx_flat, cy_flat)
points = [Point(lo, la) for lo, la in zip(lons, lats)]
values = grid.ravel().tolist()
gdf = gpd.GeoDataFrame({'geometry': points, 'value': values}, crs=CRS.from_epsg(4326))
return gdf