Line-of-Sight Visibility Analysis¶
This notebook demonstrates how to compute visible areas from a viewpoint or multiple points using:
Fast approximate visibility (suitable for quick overviews)
Accurate visibility analysis (respecting occlusions)
Parallelized visibility from multiple locations
# Import necessary libraries
from objectnat import get_visibility
import geopandas as gpd
from shapely.geometry import Point
1. Load Obstacle Data¶
Load a building layer representing line-of-sight obstacles. This dataset is used to compute occlusions in the urban environment.
# Load buildings as obstacles
obstacles = gpd.read_parquet('examples_data/buildings.parquet')
2. Define Viewpoint¶
Specify the observation point from which visibility will be computed. Coordinates must match the CRS of the obstacles dataset.
# Define a single viewpoint in WGS 84
point_from = gpd.GeoDataFrame(geometry=[Point(30.2312112, 59.9482336)], crs=4326)
radius = 800
3. Fast Visibility Calculation¶
Compute visibility using a fast, approximate method. This is suitable for real-time feedback or exploratory analysis. Note: May produce artifacts (e.g., visibility behind walls).
# Fast visibility (less accurate)
result_fast = get_visibility(point_from, obstacles, view_distance=radius,method='simple')
# Computes visibility polygon from the viewpoint with a 500-meter radius using low-resolution simulation.
4. Accurate Visibility Calculation¶
Use get_visibility(..., method="accurate") for the more precise algorithm, which simulates occlusion and limited sightlines.
This method is slower but produces more reliable results.
# Accurate visibility (includes occlusion and bottleneck modeling)
result_accurate = get_visibility(point_from, obstacles, view_distance=radius,method='accurate')
# Simulates realistic visibility by tracing around buildings and respecting occlusions.
5. Visualization¶
Visualize obstacles and both visibility methods
from shapely import Point
# Red area = False Positive (Simple method only)
simple_only = gpd.overlay(result_fast, result_accurate, how="difference")
# Green area = Advantage (Accurate method only)
accurate_only = gpd.overlay(result_accurate, result_fast, how="difference")
# Blue area = Agreement Area (both methods overlap)
common_area = gpd.overlay(result_fast, result_accurate, how="intersection")
# Light gray = Obstacles (context layer)
m = common_area.explore(color='blue', tiles='CartoDB positron')
obstacles[["geometry"]].explore(m=m, color='lightgray')
simple_only.explore(m=m, color='red')
accurate_only.explore(m=m, color='green')