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')
Make this Notebook Trusted to load map: File -> Trust Notebook