Tessellation divides geographic areas of interest (AOIs) into smaller rectangular tiles. These tiles are normally sized to match the sensor field-of-view for Earth-imaging satellites. This enables larger areas, ones too big to be collected in a single imaging action, to be broken down into smaller parts which can be feasibly collected.
There are infinitely many ways to tile a large area if entirely unconstrained in the tile placement. Brahe implements an orbit-geometry based tessalator that generates tiles aligned with the orbital ground-track of a satellite. This approach is particular well-suited to satellites with push-broom imaging modes such as radar imaging satellites. The OrbitGeometryTessellator uses a satellite's orbital elements and a reference epoch to determine ground-track directions at any latitude. It then tiles the target location perpendicular and parallel to the ground track. Output tiles are PolygonLocation instances with metadata properties describing the tile geometry, making them compatible with the rest of the access computation system. The tesselation configuration should be setup such that the maximum width and length remain feasible to collect in a single imaging pass.
Default image_width: 5000.0 m
Default image_length: 5000.0 m
Default crosstrack_overlap: 200.0 m
Default alongtrack_overlap: 200.0 m
Default min_image_length: 5000.0 m
Default max_image_length: 5000.0 m
Custom image_width: 10000.0 m
Custom image_length: 15000.0 m
Custom asc_dsc: Ascending
Default image_width: 5000 m
Default image_length: 5000 m
Default crosstrack_overlap: 200 m
Default alongtrack_overlap: 200 m
Default min_image_length: 5000 m
Default max_image_length: 5000 m
Custom image_width: 10000 m
Custom image_length: 15000 m
Custom asc_dsc: Ascending
Tessellating a PointLocation creates one tile per pass direction, centered on the point. With AscDsc.ASCENDING, a single tile is created; with AscDsc.EITHER, up to two tiles are created (one per direction). At high latitudes where ascending and descending ground tracks converge, redundant tiles may be automatically merged.
Number of tiles: 1
Tile 0: center=(10.0000, 29.9999)
width=5000 m, length=5000 m
The figure below shows the difference between ascending-only and ascending+descending tessellation for a single point near San Francisco. Each tile direction produces a rectangle aligned to the satellite ground track at that latitude.
Tessellating a PolygonLocation divides the area into cross-track strips perpendicular to the satellite ground track, then subdivides each strip along-track into individual tiles. The algorithm handles concave polygons by detecting gaps in the along-track direction. Tiles at polygon edges may have adjusted lengths to fit the boundary.
Number of tiles: 12
Tile 0: group_id=bc66a83b... length=5000 m
Tile 1: group_id=bc66a83b... length=5000 m
Tile 2: group_id=bc66a83b... length=5000 m
Tile 3: group_id=bc66a83b... length=5000 m
Tile 4: group_id=bc66a83b... length=5000 m
Tile 5: group_id=bc66a83b... length=5000 m
Tile 6: group_id=bc66a83b... length=5000 m
Tile 7: group_id=bc66a83b... length=5000 m
Tile 8: group_id=bc66a83b... length=5000 m
Tile 9: group_id=bc66a83b... length=5000 m
Tile 10: group_id=bc66a83b... length=5000 m
Tile 11: group_id=bc66a83b... length=5000 m
Number of tiles: 12
Tile 0: group_id=4f1a8f93... length=5000 m
Tile 1: group_id=4f1a8f93... length=5000 m
Tile 2: group_id=4f1a8f93... length=5000 m
Tile 3: group_id=4f1a8f93... length=5000 m
Tile 4: group_id=4f1a8f93... length=5000 m
Tile 5: group_id=4f1a8f93... length=5000 m
Tile 6: group_id=4f1a8f93... length=5000 m
Tile 7: group_id=4f1a8f93... length=5000 m
Tile 8: group_id=4f1a8f93... length=5000 m
Tile 9: group_id=4f1a8f93... length=5000 m
Tile 10: group_id=4f1a8f93... length=5000 m
Tile 11: group_id=4f1a8f93... length=5000 m
The figure below shows England tessellated with 50 km tiles. Tiles are colored by tile_group_id — each color represents tiles sharing the same ground-track direction (ascending vs descending). The dashed line is the input polygon boundary.
# Figure 2: Polygon Tessellation — England with tiles colored by group# ------------------------------------------------------------------fig,ax=plt.subplots(1,1,figsize=(8,7),subplot_kw={"projection":ccrs.PlateCarree()})iftheme=="dark":set_dark_figure_bg(fig)ax.set_extent([-7,3,49,56],crs=ccrs.PlateCarree())style_map_axis(ax,theme)draw_tiles(ax,tiles_eng)draw_polygon_outline(ax,england_verts,color=outline_color)ax.set_title(f"England — {len(tiles_eng)} tiles, colored by tile_group_id",fontsize=10)style_gridlines(ax,theme)plt.tight_layout()save_themed(fig,"tessellation_polygon",theme)
Increasing image_width and image_length produces fewer, larger tiles. The left panel uses 5 km tiles and the right uses 15 km tiles for the same region near San Francisco.
Increasing crosstrack_overlap and alongtrack_overlap causes adjacent tiles to share more area, which produces more tiles for the same region. The left panel uses 0 m overlap; the right uses 1000 m overlap.
# Figure 3: Tile Length — 5 km vs 15 km# Figure 4: Overlap — 0 m vs 1000 m# ------------------------------------------------------------------# Tile Lengthfig,(ax1,ax2)=plt.subplots(1,2,figsize=(14,6),subplot_kw={"projection":ccrs.PlateCarree()})iftheme=="dark":set_dark_figure_bg(fig)foraxin(ax1,ax2):ax.set_extent(sf_extent,crs=ccrs.PlateCarree())style_map_axis(ax,theme)draw_tiles(ax1,tiles_5k)draw_polygon_outline(ax1,sf_verts,color=outline_color)ax1.set_title(f"5 km tiles ({len(tiles_5k)} tiles)",fontsize=10)draw_tiles(ax2,tiles_15k)draw_polygon_outline(ax2,sf_verts,color=outline_color)ax2.set_title(f"15 km tiles ({len(tiles_15k)} tiles)",fontsize=10)foraxin(ax1,ax2):style_gridlines(ax,theme)plt.tight_layout()save_themed(fig,"tessellation_tile_length",theme)# Overlapfig,(ax1,ax2)=plt.subplots(1,2,figsize=(14,6),subplot_kw={"projection":ccrs.PlateCarree()})iftheme=="dark":set_dark_figure_bg(fig)foraxin(ax1,ax2):ax.set_extent(sf_extent,crs=ccrs.PlateCarree())style_map_axis(ax,theme)draw_tiles(ax1,tiles_no_ol)draw_polygon_outline(ax1,sf_verts,color=outline_color)ax1.set_title(f"0 m overlap ({len(tiles_no_ol)} tiles)",fontsize=10)draw_tiles(ax2,tiles_ol)draw_polygon_outline(ax2,sf_verts,color=outline_color)ax2.set_title(f"1000 m overlap ({len(tiles_ol)} tiles)",fontsize=10)foraxin(ax1,ax2):style_gridlines(ax,theme)plt.tight_layout()save_themed(fig,"tessellation_overlap",theme)
Each output tile is a PolygonLocation with metadata properties stored in its properties dictionary. These properties describe the tile geometry and ownership.
Property
Type
Description
tile_direction
[x, y, z]
Along-track unit vector in ECEF coordinates
tile_width
float
Cross-track dimension in meters
tile_length
float
Along-track dimension in meters
tile_area
float
Tile area (\(\text{width} \times \text{length}\)) in m\(^2\)
tile_group_id
str
UUID shared by all tiles in the same tiling direction
When multiple spacecraft have similar orbital planes, their ground-track directions at a given latitude will be similar. The tile_merge_orbit_geometry function clusters tiles by direction and merges groups whose directions fall within a configurable angular threshold. Rather than creating duplicate tiles, it adds the additional spacecraft's ID to the base tile's spacecraft_ids list.
bh.initialize_eop()# SC-1 and SC-2 TLEs with slightly different inclinations (~1.4 degree offset)line1="1 25544U 98067A 08264.51782528 -.00002182 00000-0 -11606-4 0 2927"line2_sc1="2 25544 51.6416 247.4627 0006703 130.5360 325.0288 15.72125391563537"line2_sc2="2 25544 53.0000 247.4627 0006703 130.5360 325.0288 15.72125391563532"# Create two tessellators with different spacecraft IDsconfig=bh.OrbitGeometryTessellatorConfig(image_width=5000,image_length=5000,asc_dsc=bh.AscDsc.ASCENDING,)prop1=bh.SGPPropagator.from_tle(line1,line2_sc1,step_size=60.0)tess1=bh.OrbitGeometryTessellator(prop1,prop1.epoch,config,spacecraft_id="SC-1")prop2=bh.SGPPropagator.from_tle(line1,line2_sc2,step_size=60.0)tess2=bh.OrbitGeometryTessellator(prop2,prop2.epoch,config,spacecraft_id="SC-2")# Tessellate the same point with both spacecraftpoint=bh.PointLocation(10.0,30.0,0.0)tiles_sc1=tess1.tessellate_point(point)tiles_sc2=tess2.tessellate_point(point)all_tiles=tiles_sc1+tiles_sc2print(f"Before merge: {len(all_tiles)} tiles")# Merge tiles with similar directionsmerged=bh.tile_merge_orbit_geometry(all_tiles,200.0,200.0,2.0)print(f"After merge: {len(merged)} tiles")fortileinmerged:print(f" spacecraft_ids: {tile.properties['spacecraft_ids']}")
usebraheasbh;usebh::access::constraints::AscDsc;usebh::access::location::{AccessibleLocation,PointLocation};usebh::access::tessellation::{OrbitGeometryTessellator,OrbitGeometryTessellatorConfig,Tessellator,tile_merge_orbit_geometry,};usebh::propagators::SGPPropagator;fnmain(){bh::initialize_eop().unwrap();// SC-1 and SC-2 TLEs with slightly different inclinations (~1.4 degree offset)letline1="1 25544U 98067A 08264.51782528 -.00002182 00000-0 -11606-4 0 2927";letline2_sc1="2 25544 51.6416 247.4627 0006703 130.5360 325.0288 15.72125391563537";letline2_sc2="2 25544 53.0000 247.4627 0006703 130.5360 325.0288 15.72125391563532";// Create two tessellators with different spacecraft IDsletconfig=OrbitGeometryTessellatorConfig::default().with_asc_dsc(AscDsc::Ascending);letprop1=SGPPropagator::from_tle(line1,line2_sc1,60.0).unwrap();letepoch1=prop1.epoch;lettess1=OrbitGeometryTessellator::new(Box::new(prop1),epoch1,config.clone(),Some("SC-1".to_string()),);letprop2=SGPPropagator::from_tle(line1,line2_sc2,60.0).unwrap();letepoch2=prop2.epoch;lettess2=OrbitGeometryTessellator::new(Box::new(prop2),epoch2,config,Some("SC-2".to_string()),);// Tessellate the same point with both spacecraftletpoint=PointLocation::new(10.0,30.0,0.0);lettiles_sc1=tess1.tessellate(&point).unwrap();lettiles_sc2=tess2.tessellate(&point).unwrap();letmutall_tiles=tiles_sc1;all_tiles.extend(tiles_sc2);println!("Before merge: {} tiles",all_tiles.len());// Merge tiles with similar directionsletmerged=tile_merge_orbit_geometry(&all_tiles,200.0,200.0,2.0);println!("After merge: {} tiles",merged.len());fortilein&merged{println!(" spacecraft_ids: {}",tile.properties()["spacecraft_ids"]);}}
Before merge: 2 tiles
After merge: 1 tiles
spacecraft_ids: ["SC-1","SC-2"]
The figure below shows tiles from two spacecraft with slightly different inclinations (~1.4° offset). Before merging, the tiles from SC-1 and SC-2 are visibly offset; after merging with a 2° angular threshold, overlapping tiles are combined with both spacecraft IDs in the spacecraft_ids list.