Skip to content

Commit bba33f5

Browse files
authored
Merge pull request #772 from KaplanOpenSource/issue641
docs(user-guide): Expand Buildings toolkit with full usage guide
2 parents 197083e + 940427c commit bba33f5

1 file changed

Lines changed: 221 additions & 10 deletions

File tree

docs/toolkits/measurements/gis/buildings.md

Lines changed: 221 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,32 @@
22

33
**Toolkit name:** `GIS_Buildings`
44

5-
Manages building footprint data and generates 3D meshes for CFD simulations.
5+
Manages building footprint data — query by bounding box, extract heights, compute urban morphology parameters (plan area fraction, frontal area density, average building height), generate 3D STL meshes for CFD simulations, and group buildings into convex clusters.
66

7-
**Data source format:**
7+
```python
8+
from hera import toolkitHome
9+
10+
# Tip: if you created the project with `hera-project project create`, you can omit projectName
11+
buildings = toolkitHome.getToolkit(toolkitHome.GIS_BUILDINGS, projectName="MY_PROJECT")
12+
13+
# Get building footprints in a bounding box
14+
gdf = buildings.getBuildingsFromRectangle(
15+
minx=35.0, miny=32.0, maxx=35.1, maxy=32.1
16+
)
17+
18+
# Compute urban morphology (lambda_P, lambda_F, hc) per block
19+
morphology = buildings.analysis.LambdaFromBuildingData(
20+
windMeteorologicalDirection=270,
21+
resolution=250,
22+
buildingsData=gdf,
23+
)
24+
```
25+
26+
For the full API, see the [API Reference](../../developer_guide/api/measurements.md). For implementation details, see the [Developer Guide](../../developer_guide/measurements/gis.md).
27+
28+
---
29+
30+
## Data source format
831

932
| Property | Value |
1033
|----------|-------|
@@ -13,22 +36,210 @@ Manages building footprint data and generates 3D meshes for CFD simulations.
1336
| Required columns | `geometry` |
1437
| Height column | `BLDG_HT` (or as specified in `desc.BuildingHeightColumn`) — building height in meters |
1538
| Ground height | `HT_LAND` (or as specified in `desc.LandHeightColumns`) — ground elevation |
16-
| Fallback | If no height column, uses `building:levels × 3` meters |
39+
| Fallback | If no height column, uses `building:levels * 3` meters |
1740
| CRS | Any (must be defined; methods handle transformation) |
1841
| Config key | `defaultBuildingDataSource` |
1942

43+
---
44+
45+
## Querying buildings
46+
47+
### By bounding box
48+
2049
```python
21-
buildings = toolkitHome.getToolkit(toolkitHome.GIS_BUILDINGS, projectName="MY_PROJECT")
50+
# WGS84 coordinates (default inputCRS)
51+
gdf = buildings.getBuildingsFromRectangle(
52+
minx=35.0, miny=32.0, maxx=35.1, maxy=32.1,
53+
)
2254

23-
# Get building footprints in a bounding box
24-
gdf = buildings.getBuildingsFromRectangle(minx=35.0, miny=32.0, maxx=35.1, maxy=32.1)
55+
# ITM coordinates
56+
from hera.measurements.GIS import ITM
57+
gdf = buildings.getBuildingsFromRectangle(
58+
minx=175000, miny=658000, maxx=185000, maxy=668000,
59+
inputCRS=ITM,
60+
)
61+
62+
# With elevation from raster topography toolkit
63+
gdf = buildings.getBuildingsFromRectangle(
64+
minx=35.0, miny=32.0, maxx=35.1, maxy=32.1,
65+
withElevation=True, # adds 'elevation' column from SRTM data
66+
)
67+
68+
# From a specific data source
69+
gdf = buildings.getBuildingsFromRectangle(
70+
minx=35.0, miny=32.0, maxx=35.1, maxy=32.1,
71+
dataSourceName="BNTL",
72+
)
73+
```
74+
75+
### From GeoJSON
76+
77+
```python
78+
# Filter buildings from a GeoJSON-like dict
79+
gdf = BuildingsToolkit.filter_buildings_in_area(
80+
buildings_data=geojson_dict,
81+
min_longitude=35.0, min_latitude=32.0,
82+
max_longitude=35.1, max_latitude=32.1,
83+
)
84+
```
85+
86+
---
87+
88+
## Extracting building heights
89+
90+
```python
91+
# Extract heights from a GeoDataFrame
92+
# Uses BLDG_HT column if available; falls back to building:levels * 3
93+
height_gdf = BuildingsToolkit.get_buildings_height(gdf)
94+
# Returns GeoDataFrame with columns: name, geometry, height
95+
```
96+
97+
### Height with raster topography
98+
99+
```python
100+
# Add ground elevation to each building (at centroid)
101+
gdf_with_elev = buildings.getBuildingHeightFromRasterTopographyToolkit(
102+
buildingData=gdf,
103+
topographyDataSource="SRTM_30m", # optional, uses default if None
104+
)
105+
# Adds 'elevation' column from the TopographyToolkit
106+
```
107+
108+
---
109+
110+
## Analysis: urban morphology
25111

26-
# Generate 3D STL using raster topography for ground elevation
112+
The analysis layer computes block-averaged urban morphology parameters used in boundary-layer meteorology and CFD modeling.
113+
114+
### Lambda parameters
115+
116+
Compute plan area fraction (**lambda_P**), frontal area density (**lambda_F**), and average building height (**hc**) for each block in a domain:
117+
118+
```python
119+
morphology = buildings.analysis.LambdaFromBuildingData(
120+
windMeteorologicalDirection=270, # wind direction in degrees
121+
resolution=250, # block size in meters
122+
buildingsData=gdf, # GeoDataFrame with CRS set
123+
overwrite=False, # recompute even if cached
124+
saveCache=True, # cache results in DB
125+
)
126+
```
127+
128+
**Returns** a GeoDataFrame with one row per block:
129+
130+
| Column | Description |
131+
|--------|-------------|
132+
| `geometry` | Block polygon |
133+
| `lambdaP` | Plan area fraction: total building footprint area / block area |
134+
| `lambdaF` | Frontal area density: total building frontal area / block area (wind-direction dependent) |
135+
| `hc` | Area-weighted average building height within the block |
136+
| `i0`, `j0` | Block grid indices |
137+
138+
Results are cached in the project's cache collection (type `Lambda_Buildings`). Subsequent calls with the same bounds, wind direction, resolution, and CRS return the cached result. Use `overwrite=True` to force recomputation.
139+
140+
### How it works
141+
142+
1. The domain (from `buildingsData.total_bounds`) is divided into a grid of square blocks at the given resolution
143+
2. For each block:
144+
- **lambda_P** = sum of building plan areas / block area (excludes buildings with `FTYPE` 14 or 16, and buildings with zero height)
145+
- **lambda_F** = sum of building frontal areas / block area (frontal area is computed by rotating each building footprint to the wind direction and measuring the projected width * height)
146+
- **hc** = sum(area * height) / sum(area) — area-weighted mean building height
147+
3. Buildings with no land height (`HT_LAND=0`) use the nearest building's land height as a fallback
148+
149+
### Convex building clusters
150+
151+
Group nearby buildings into convex hulls (useful for identifying urban blocks):
152+
153+
```python
154+
clusters = buildings.analysis.ConvexPolygons(
155+
regionNameOrData=gdf, # GeoDataFrame or region name
156+
buffer=100, # buffer distance for grouping (meters)
157+
)
158+
# Returns GeoDataFrame of convex hull polygons, sorted by area
159+
```
160+
161+
The algorithm:
162+
1. Buffers each building footprint by `buffer` meters
163+
2. Groups intersecting buffered footprints
164+
3. Computes the convex hull of each group
165+
4. Recursively merges overlapping hulls
166+
167+
---
168+
169+
## 3D STL generation
170+
171+
Generate 3D building meshes for CFD simulations using the FreeCAD module.
172+
173+
### From a bounding box (recommended)
174+
175+
```python
27176
buildings.regionToSTL(
28177
minx=35.0, miny=32.0, maxx=35.1, maxy=32.1,
29-
dxdy=30, inputCRS=4326, outputCRS=2039,
30-
solidName="Buildings", fileName="buildings.stl"
178+
dxdy=30, # grid resolution
179+
inputCRS=4326, # input coordinate system
180+
outputCRS=2039, # output coordinate system (ITM)
181+
solidName="Buildings",
182+
fileName="buildings.stl",
31183
)
32184
```
33185

34-
For the full API, see the [API Reference](../../developer_guide/api/measurements.md).
186+
### From a GeoDataFrame (low-level)
187+
188+
```python
189+
buildings.buildingsGeopandasToSTLRasterTopography(
190+
buildingData=gdf,
191+
buildingHeightColumn="BLDG_HT",
192+
buildingElevationColumn="elevation",
193+
outputFileName="/output/buildings.stl",
194+
flatTerrain=False, # True: use referenceTopography for all
195+
referenceTopography=0, # base height if flatTerrain=True
196+
nonFlatTopographyShift=10, # shift buildings above topography
197+
)
198+
```
199+
200+
!!! note "FreeCAD required"
201+
STL generation requires the FreeCAD Python module. Install it and add to `PYTHONPATH` before using these methods.
202+
203+
---
204+
205+
## Complete example
206+
207+
```python
208+
from hera import toolkitHome
209+
from hera.measurements.GIS import ITM
210+
211+
# Tip: if you created the project with `hera-project project create`, you can omit projectName
212+
buildings = toolkitHome.getToolkit(toolkitHome.GIS_BUILDINGS, projectName="TelAvivStudy")
213+
214+
# 1. Query buildings in Tel Aviv (ITM coordinates)
215+
gdf = buildings.getBuildingsFromRectangle(
216+
minx=175000, miny=658000, maxx=185000, maxy=668000,
217+
inputCRS=ITM,
218+
withElevation=True,
219+
)
220+
221+
print(f"Found {len(gdf)} buildings")
222+
print(gdf[["BLDG_HT", "HT_LAND", "geometry"]].head())
223+
224+
# 2. Compute urban morphology for westerly wind
225+
morphology = buildings.analysis.LambdaFromBuildingData(
226+
windMeteorologicalDirection=270,
227+
resolution=250,
228+
buildingsData=gdf,
229+
)
230+
231+
print(morphology[["lambdaP", "lambdaF", "hc"]].describe())
232+
233+
# 3. Generate 3D STL for CFD
234+
buildings.buildingsGeopandasToSTLRasterTopography(
235+
buildingData=gdf,
236+
buildingHeightColumn="BLDG_HT",
237+
buildingElevationColumn="elevation",
238+
outputFileName="tel_aviv_buildings.stl",
239+
flatTerrain=False,
240+
)
241+
242+
# 4. Group buildings into urban blocks
243+
clusters = buildings.analysis.ConvexPolygons(gdf, buffer=50)
244+
print(f"Identified {len(clusters)} building clusters")
245+
```

0 commit comments

Comments
 (0)