Sightline
Computes and visualizes line-of-sight visibility to orbiting or celestial targets over terrain.
SPICE
Site administrators are responsible for keeping SPICE kernels up-to-date in /spice/kernels/ and CHRONOS setup files relevant in /spice/chronosSetups/.
There are two SPICE python scripts that require these backend kernel setups:
chronice.py(time conversion)- Converts between time systems.
- Looks for
/spice/chronosSetups/chronos-{target}.setupwhere{target}here is filled in as a lowercased SightlineTool variables"observers"s"value".
ll2aerll.py(geometry)- Turns a lnglat and target into a directional azimuth, elevation, range, and lntlat
- Reads in all kernels from
/spice/kernels/. /spice/getKernelUtilshas some wget scripts as examples for downloading new kernels (however these resources will quickly become outdated)
Tool Configuration
Example
{
"dem": "Data/missionDEM.tif",
"data": [
{
"name": "MSL_DEM",
"demtileurl": "pathToDEMTiles/MSL_Gale_DEM_Mosaic_1m_v3/{z}/{x}/{y}.png",
"minZoom": 8,
"maxNativeZoom": 18
}
],
"sources": [
{
"name": "MRO",
"value": "MRO"
},
{
"name": "ODY",
"value": "-53"
},
{
"name": "TGO",
"value": "TGO"
},
{
"name": "MVN",
"value": "MAVEN"
},
{
"name": "The Sun",
"value": "SUN"
}
],
"observers": [
{
"name": "MSL",
"value": "MSL"
}
],
"defaultHeight": 0,
"observerTimePlaceholder": null,
"utcTimeFormat": null
}
dem - A path to a DEM.tif. This is used to get the current center elevation. This can/should be the same file used for the Measure Tool and the Coordinate’s elevation.
data - At minimum, the Sightline tool requires at least one “data” source. A data source describes a DEM tileset (see /auxiliary/gdal2customtiles or /auxiliary/1bto4b) and allows users to select it by name to generate sightline maps over.
source - An array of objects with the properties “name” and “value”. “name” is the display name for the Source Entity dropdown. “value” is the SPICE spacecraft ID that gets passed to the backend ll2aerll.py script. Ensure the right kernels for the configured source entities/targets exist in /private/api/spice/kernels.
observers - An array of objects with the properties “name” and “value”. “name” is the display name for the Source Entity dropdown. “value” is the SPICE spacecraft ID that gets passed to the backend chronos.py scripts. Ensure the right kernels for the configured observers exist in /private/api/spice/kernels and that there is a proper chronos setup file for each observer’s value private/api/spice/chronosSetups/chronos-{lowercased_observer_value}.setup.
defaultHeight - Sets a default for the ‘Height’ parameter (see below). The regular default is 0 meters.
observerTimePlaceholder - Sets the placeholder information for when the observer time’s input box is cleared. Useful for denoting the expected time format to be inputed. For example “SOL DDDD HH:MM:SS”. Default null.
utcTimeFormat - Sets the placeholder information for when the observer time’s input box is cleared. Useful for denoting the expected time format to be inputed. Uses d3 time syntax. Example for day-of-year: "%Y-%j %H:%M:%S". Defaults to times like so: 2023 SEP 06 19:27:05.
Tool Use
Note: Terrain beyond the screen’s current extent is not factored into the displayed visibility map — only observer-target direction and on-screen terrain is considered. A distant off-screen mountain will not cast shadows.
Interface
- Time
- The desired datetime to query. Formatted as
YYYY MMM DD HH:MM:SSand for example2023 SEP 06 19:27:05(or based onutcTimeFormat). Updating this time and pressing ‘Enter’ will set it as the current time for the SightlineTool and for all of MMGIS. It is both connected to the Observer’s local time as well as MMGIS’ timeline (expandable via the clock icon in the bottom left of the screen).
- The desired datetime to query. Formatted as
Source
- Entity
- Indicates which spacecraft, orbiter or celestial body to “look towards” and to “shine light back” upon the visible terrain.
- Include Sun + Earth
- If true, the relative Sun and Earth positions will also be computed and their directional arrows will be rendered in the bottom azimuth and elevation indicators. In the azimuth and elevation indicators, the Sun is represented by a medium-length yellow arrow and the Earth is represented by a short-length blue-green arrow. These do not cast shadows on the visible terrain — only the source entity casts shadows.
Observer
- Entity
- Which observing spacecraft/orbiter to use. This is only used for formatting and converting the upcoming ‘Time’ parameter. The true observer position is always the visible map’s center longitude and latitude value (represented by a green circle) and always facing north with zero tilt.
- Time
- Offers the ability to set the current working time using a mission/spacecraft’s custom date type.
- Height
- Height in meters above the surface to use when calculating line-of-sight shading. For instance, a point on the surface (0m) may not be visible to a ‘Source Entity’, say the Mars Reconnaissance Orbiter (MRO), but 2m above that point may be. This value does not only apply to the center longitude and latitude but to all points on the visible terrain. Gradually increasing this value shows the sightline map n-meters above the surface.
Visibility Region Options
- Color
- The color to highlight the visible regions on the map.
- Opacity
- The opaqueness of the visible regions on the map. A value of 0 is fully transparent and a value of 1 is fully opaque.
- Resolution
- MMGIS downloads terrain data needed for the visibility algorithm. Increasing the resolution improves the quality of the sightline map and the cost of download and render speed. Each higher option is 4x the resolution of the previous one (i.e. ‘ultra’ is 4x more terrain data than ‘high’ and 16x more data than ‘medium’). To save on performance, if the resolution is ‘high’ or ‘ultra’, the Sightline Tool will no longer regenerate the visibility map whenever any parameter changes and instead ‘Generate/Regenerate’ must manually be pressed.
-
Elevation Map
- Specifies the terrain dataset to use.
- Generate/Regenerate
- Submits a request to generate a sightline map with the provided parameters. Note that if the resolution is ‘high’ or ‘ultra’, the Sightline Tool will not regenerate the visibility map whenever any parameter changes and instead ‘Generate/Regenerate’ must manually be pressed.
Results
- Azimuth: The compass-angle in (0 -> 360) degrees clockwise from north of the direction of the ‘Source Entity’ as seen from the map’s center longitude and latitude. 0 = North, 90 = East, 180 = South, 270 = West.
- Elevation: The angular height (-90 -> 90) between the horizon and the ‘Source Entity’. -90 = Straight Down, 0 = Level with the Horizon, 90 = Straight Overhead.
- Range: The straight-line distance in kilometers between the map’s center longitude, latitude and terrain elevation and the ‘Source Entity’.
- Longitude: The map’s center longitude value used in the computation.
- Latitude: The map’s center latitude value used in the computation.
- Altitude: The distance in kilometers above the map’s center position’s tangential plane and the ‘Source Entity’. In other words, in a 3D cartesian coordinate-system where the Z-axis goes through both the center of the visible map and the center of the planet, this ‘Altitude’ is the Z distance between that center and the ‘Source Entity’.
Indicators
- Azimuth: A top-down birds-eye view of the surface with north up. The long yellow-orange arrow visualizes the azimuthal direction towards the ‘Source Entity’. If ‘Include Sun + Earth’ is on, shorter Sun and Earth arrows will also appear in the indicator with the respective yellow and green-blue colors.
- Elevation: A horizontal and half-submerged side view of the surface. The long yellow-orange arrow visualizes the elevational direction towards the ‘Source Entity’. If ‘Include Sun + Earth’ is on, shorter Sun and Earth arrows will also appear in the indicator with the respective yellow and green-blue colors. Note that elevation values only goes from -90 -> 90 but that the rendered elevation arrow can be drawn between 0 -> 360. This is because, while only half a circle is needed, the elevation arrow will choose whether to draw in the left or right half circle depending on which half-circle the azimuth value is in. Azimuth values from 0 -> 180 will result in an elevation arrow drawn in the right half-circle and azimuth values from 180 -> 360 will results in an elevation arrow drawn in the left half-circle. This is to aid in visualizing the ‘Source Entity’s 3D direction.
Sightline Modes
Each sightline map item can be set to one of three modes:
- Static: Generates a single sightline map at the current time. The sightline map regenerates when parameters change.
- Composite: Sweeps through a time range and produces a cumulative heatmap showing how often each point on the ground has line-of-sight across all time steps.
- Playback: Sweeps through a time range and stores each frame. Users can play back the sweep as an animation, stepping through individual sightline frames with time controls.
Multiple sightline maps can be created simultaneously (e.g., Sun + Moon). Each element tracks its own sweep progress independently — starting a sweep on one element does not cancel another.
Charts (Horizon Profile + Visibility Timeline)
Clicking the Charts button on a sightline map item opens a combined bottom panel with two visualizations:
Horizon Profile
A 360° terrain horizon profile centered on the observer (map center). The chart shows:
- Terrain silhouette (brown fill) — computed by ray-casting from the observer across the DEM in all azimuth directions.
- Source trajectory arcs — the path of each source entity (Sun, Moon, etc.) across the sky during the sweep time range.
- Current-frame marker — a dot on the trajectory showing the source’s current position.
- 0° elevation line (dashed) — the geometric horizon.
- Curvature correction — when the tool’s
curvatureoption is enabled, the horizon profile accounts for planetary curvature by subtractingd²/2Rfrom sampled terrain elevations (whereRis the planet radius). - Near-field skip — DEM samples within the configured minimum distance (default 1m) of the observer are ignored to reduce blockiness from close-in pixels.
- Fog shading — The terrain fill opacity varies by distance: nearby horizon terrain is rendered opaque; distant terrain fades out (log-scale mapping). This provides depth perception.
- Hover tooltip — Mousing over the horizon chart shows the azimuth, elevation angle, and distance to the horizon at that point.
- Range slider — A dual-handle log-scale slider in the panel header controls the min/max horizon lookup distance (default 1m–250km). Adjusting and releasing refetches the profile.
The chart is north-centered (0° N at center, ±180° at edges) and adapts to the current light/dark theme.
Visibility Timeline
A per-source horizontal bar showing when the source is visible vs. occluded over the sweep time range:
- Colored segments indicate the source is visible (lit pixel at observer position in the sightmap grid), using the element’s configured color.
- Gray/white segments indicate the source is occluded.
- Visibility is determined by the sightmap grid pixel at the observer’s position — if the pixel is lit (value 1 or 2) the source is visible, if shadowed (value 0) the source is occluded.
- A red slider indicator tracks the current playback frame position.
- Time labels along the bottom show UTC timestamps spanning the full time range.
Azimuth Lines on Map
While the charts panel is open, colored dashed lines are drawn on the map for each sightline element, showing the current azimuth direction toward each source entity. These update in real-time during playback.
Time Controls
The combined panel includes shared time controls:
- Play/Pause — auto-advance through frames at the configured interval.
- Fast-forward — 4× playback speed.
- Step forward/back — advance or rewind one frame at a time.
- Time slider — scrub to any frame in the sweep.
- Time display — shows the current frame’s UTC timestamp.
Sky Dome
In playback mode, the results section includes a Sky Dome — a polar plot showing the full-sky trajectory of source entities. The dome maps azimuth (compass direction, clockwise from north) and elevation (0° at horizon, 90° at zenith) onto a circular projection:
- Cardinal directions (N, S, E, W) are labeled around the perimeter.
- Elevation rings at 30° and 60° are drawn as dashed circles.
- Each source’s trajectory is plotted as a colored arc; above-horizon points are dots, below-horizon points are smaller/dimmer.
- The current-frame position is highlighted with a larger marker.
The sky dome background uses a fixed dark color for legibility in both light and dark themes.
Algorithms
Sightmap (Viewshed)
Endpoint: POST /api/sightline/sightmap
The sightmap computes a 2D visibility grid showing which terrain cells have direct line-of-sight to a source entity.
Core Algorithm:
- Source position — SPICE computes the azimuth, elevation, and range from the observer (map center lat/lng/height) to the target entity at the given time. For custom sources, user-supplied az/el is used directly.
- DEM composite — A terrain raster is read from the configured DEM, padded by
shadowReachin all directions beyond the viewport to capture shadows cast by off-screen terrain. The composite is read at a managed resolution (working dim proportional to viewport, capped at 4× max working dim) to prevent memory exhaustion. - Tangent-plane projection — The observer position and source vector are projected onto a local tangent plane. The source’s effective position is expressed as (x, y, z) in a grid-aligned coordinate system.
- Ray-march viewshed — From each grid cell, a ray is cast toward the source. The algorithm (a modified version of Generating Viewsheds without Using Sightlines by Jianjun Wang, Gary J. Robinson, and Kevin White) checks if any intervening terrain along the ray exceeds the line-of-sight slope from that cell to the source. If so, the cell is shadowed; otherwise it is visible.
- Output — A 2D integer grid where:
0= shadowed,1= visible from target,2= also visible from secondary source (Earth),8= no DEM data,9= out of bounds.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
dem | string | — | Path to DEM raster (under /Missions/) |
lat, lng | number | — | Observer latitude/longitude |
height | number | 0 | Observer height above terrain (meters) |
target | string | — | SPICE target name (e.g. SUN, MRO) |
time | string | — | ISO 8601 UTC time (single mode) |
startTime, endTime, stepSeconds | string/number | — | Batch sweep parameters |
obsRefFrame | string | IAU_MOON | SPICE observer reference frame |
obsBody | string | MOON | SPICE observer body name |
planetRadius | number | 0 | Planet radius in meters (for curvature correction) |
maxOutputDim | number | 400 | Max grid dimension (capped at 4096) |
shadowReach | number | 0 | Extra DEM padding in meters for off-screen shadow casting |
isCustom | string | 'false' | If 'true', use customAz/customEl instead of SPICE |
customAz, customEl | number | 0 | Custom source azimuth/elevation (degrees) |
viewportBounds | string | — | Optional viewport bounds for clipping |
Performance:
- Managed resolution — The composite DEM working dimension is capped (4× max working dim) so large shadow reach values don’t cause OOM.
- Curvature clamp — Shadow reach is server-side clamped to
√(2 × planetRadius × 10km)to prevent excessive padding. - Batch streaming — In batch mode (multiple timestamps), the DEM and SPICE kernels are loaded once; each frame only recomputes the source vector and re-runs the march kernel. Progress is reported per-frame via stderr.
- Frame limits — Max frames scale inversely with resolution: 2048 frames at low res, 256 at ultra.
Horizon Profile
Endpoint: POST /api/sightline/horizonprofile
The horizon profile computes the terrain skyline as seen from the observer in all azimuth directions.
Core Algorithm:
For each azimuth (default 360 directions at 1° intervals):
- Ray initialization — A ray is cast outward from the observer pixel in the DEM, in the direction given by the current azimuth angle. The step direction accounts for non-square pixels.
- Sample terrain — At each step along the ray, the terrain elevation is bilinearly interpolated from the DEM grid.
- Curvature correction — If a planet radius is provided, the sampled elevation is reduced by
d² / (2R)to account for the surface curving away from the observer (wheredis horizontal distance,Ris planet radius). - Elevation angle — The elevation angle from the observer to the sample point is computed:
el = atan2(terrain_elev - observer_elev, horizontal_distance). - Track maximum — The maximum elevation angle encountered along the entire ray is recorded as “the horizon” for that azimuth. The distance to this maximum-angle point is also recorded.
- Output — An array of
[azimuth_deg, max_elevation_angle_deg, distance_meters]for each azimuth direction.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
path | string | — | Path to DEM raster (under /Missions/) |
lat, lng | number | — | Observer latitude/longitude |
observerHeight | number | 0 | Observer height above terrain (meters) |
numAzimuths | number | 360 | Number of azimuth directions (capped at 3600) |
maxRadius | number | 5000 | Maximum ray march distance in meters (capped at 500km) |
minSkipRadius | number | 0 | Skip terrain samples within this distance (meters) |
planetRadius | number | 0 | Planet radius in meters (for curvature correction; 0 = flat) |
Performance:
- Logarithmic stepping — Instead of stepping 1 pixel per sample, the step size increases logarithmically with distance:
step = max(1, log₂(r + 1))pixels. Near the observer (r < 2px) it steps 1px for fine detail; at r = 1000px it steps ~10px. This preserves accuracy for nearby terrain (which subtends large angles) while skipping redundant samples at distance (where per-pixel angle change is negligible). Reduces ~2500 samples/ray to ~600 for a 250km radius. - Early termination — After each sample beyond 1km, the algorithm checks: “Could the tallest plausible terrain (10km relief, minus curvature drop) at this distance produce a steeper angle than the current maximum?” If not, the ray terminates immediately. For typical terrain where the horizon is found within a few km, rays terminate well before the max radius — often at 50–200 samples instead of 600+.
- Combined speedup — Together, logarithmic stepping + early termination yield a 4–8× reduction in samples per ray compared to naïve 1px stepping to max radius.