Source code for dtcc_builder.geometry_builders.buildings
from dtcc_model import Building, GeometryType
from dtcc_model import Surface, MultiSurface, PointCloud, Raster
from dtcc_builder.model import create_builder_polygon, create_builder_pointcloud
from dtcc_builder import _dtcc_builder
from dtcc_builder.logging import debug, info, warning, error
from shapely.geometry import Polygon
import numpy as np
from typing import List, Tuple
from .surface import extrude_surface
def extrude_building(
building: Building, default_ground_height=0, always_use_default=False
) -> MultiSurface:
"""
Extrudes the LOD0 representation of a building from its height to the ground leve.
Parameters
----------
`building` : dtcc_model.Building
The building to extrude.
`default_ground_height` : float, optional
If building does not have a ground_height property, the default ground
level to use, by default 0.
`always_use_default_ground` : bool, optional
Whether to always use the default ground height or use ground_height attribute, by default False.
Returns
-------
`MultiSurface`
The extruded building.
"""
if always_use_default:
ground_height = default_ground_height
else:
ground_height = building.attributes.get("ground_height", default_ground_height)
geometry = building.lod0
if geometry is None:
error(f"Building {building.id} has no LOD0 geometry.")
return None
if isinstance(geometry, Surface):
geometry = MultiSurface(surfaces=[geometry])
if not isinstance(geometry, MultiSurface):
error(f"Building {building.id} LOD0 geometry is not a (Multi)Surface.")
return None
extrusion = MultiSurface()
for surface in geometry.surfaces:
extrusion = extrusion.merge(extrude_surface(surface, ground_height))
return extrusion
[docs]
def compute_building_heights(
buildings: List[Building],
terrain: Raster,
min_building_height=2.5,
roof_percentile=0.9,
overwrite=False,
) -> List[Building]:
info("Computing building heights...")
for building in buildings:
footprint = building.lod0
if footprint is None:
warning(f"Building {building.id} has no LOD0 geometry.")
continue
centroid = footprint.centroid
ground_height = terrain.get_value(centroid[0], centroid[1])
building.attributes["ground_height"] = ground_height
if overwrite or footprint.zmax == 0:
roof_points = building.point_cloud
if roof_points is None or len(roof_points) == 0:
warning(f"Building {building.id} has no roof points. using min height")
footprint.set_z(ground_height + min_building_height)
building.attributes["height"] = min_building_height
else:
z_values = roof_points.points[:, 2]
roof_top = np.percentile(z_values, roof_percentile * 100)
height = roof_top - ground_height
if height < min_building_height:
height = min_building_height
footprint.set_z(ground_height + height)
building.attributes["height"] = height
return buildings
[docs]
def build_lod1_buildings(
buildings: [Building],
default_ground_height=0,
always_use_default_ground=False,
rebuild=True,
) -> List[Building]:
"""
Build the LOD1 representation of the given buildings.
Parameters
----------
`buildings` : [dtcc_model.Building]
The buildings to build the LOD1 representation of.
`default_ground_height` : float, optional
If building does not have a ground_height property, the default ground
level to use, by default 0.
`always_use_default_ground` : bool, optional
Whether to always use the default ground height or use groun_height attribute, by default False.
`rebuild` : bool, optional
Whether to rebuild the LOD1 representation if it already exists, by default True.
Returns
-------
[dtcc_model.Building]
The buildings with the LOD1 representation built.
"""
info(f"Building LOD1 representations of {len(buildings )} buildings...")
for building in buildings:
if building.lod1 is not None and not rebuild:
continue
if building.lod0 is None:
warning(f"Building {building.id} has no LOD0 geometry.")
continue
geometry = extrude_building(
building, default_ground_height, always_use_default_ground
)
if geometry is not None:
building.add_geometry(geometry, GeometryType.LOD1)
else:
warning(f"Building {building.id} LOD1 geometry could not be built.")
return buildings