Viewshed Sightline
Visibility-from-observer overlay computed against the source elevation model rather than the rendered terrain mesh. Sampling resolution is decoupled from the camera's terrain LoD, so far-away coverage areas remain accurate even when the visible terrain tiles are coarse.
Each dirty render frame snapshots inputs and starts a coroutine that samples the elevation grid off the render thread on Dispatchers.Default. When sampling completes, the next render frame populates a DrawableViewshedKernel with the snapshot + elevation array and enqueues it via RenderContext.offerSurfaceDrawable. The drawable runs on the GL thread during that frame's draw phase: uploads the elevations as an R32F texture, runs the per-fragment Amanatides–Woo kernel via earth.worldwind.render.program.ViewshedKernelShaderProgram into an RGBA8 render target, and the SurfaceImage samples that texture in place — no CPU readback round-trip.
Requires GLES 3 / WebGL 2 / GL 3.3 core for R32F sampling and texelFetch. The drawable detects Kgl.supportsSizedTextureFormats == false and silently skips rather than rendering garbage.
GPU memory cost is roughly samplesPerSide² * 12 bytes per shape: 4 B for the RGBA8 output texture + 4 B for the R32F elevation sampler + ~4 B for the FBO depth/scratch state. At the default 1024² that's ~12 MB GPU, plus two pooled CPU FloatArrays of samplesPerSide² * 4 bytes (8 MB) on the host side. Multiple sightlines multiply linearly. Use samplesForResolution to size against the underlying DEM rather than oversampling - kernel work is O(N³) so dropping N saves both memory and GPU time. Call dispose when removing a sightline to reclaim GPU resources before engine teardown.
Constructors
Properties
Altitude reference for position. Defaults to ABSOLUTE.
The geographic footprint analysed by this sightline. Replacing it triggers a recompute.
Attributes used to color terrain that is visible from the observer. Only interiorColor is consumed.
Resolution multiplier applied to samplesPerSide while the observer is being dragged. When the position has been settled for settleFrames frames, the kernel re-runs at full resolution. 1.0 disables draft mode (always full-res). Default 0.5 halves both axes during interaction for ~4× faster GPU dispatch.
Number of consecutive frames with a stable RenderContext.elevationModelTimestamp required before a tile-arrival burst triggers a re-sample. Default ~30 frames (~0.5 s at 60 fps). On Kotlin/JS where the elevation grid sample runs on the event loop, an unfiltered tick-per-tile would stall the page repeatedly during initial map load; debouncing collapses the burst into one sample after tiles settle. Position changes still bypass this and trigger immediately.
Indicates the shape's highlight attributes.
Indicates whether the shape is highlighted.
Picking flows through the inner per-window surfaceImage (it owns the surface texture drawable the user actually clicks on), so propagate the outer's pick state onto every window's SurfaceImage. Without this, a click on the viewshed overlay returns the internal SurfaceImage as the picked userObject instead of this ViewshedSightline. The outer's render() gate already suppresses pick rendering when isPickEnabled is false, but we still mirror the flag onto each SurfaceImage for defence in depth.
true when this shape's referencePosition coincides with where the user actually sees the shape (Placemark, Label, sightlines — the reference is the rendered location). false for shapes whose reference is computed from extended geometry and may sit far from where the user grabbed (Polygon centroid, Path centroid, Mesh).
Attributes used to color terrain that is occluded from the observer.
The observer's geographic position. Resolution honors altitudeMode when the position is sampled. Mutated in place (via Position.copy) and detected by doRender comparing against cachedPosition, so direct field writes (position.latitude = ...) trigger a recompute too.
A position associated with the object that indicates its aggregate geographic position. The chosen position varies among implementers of this interface. For objects defined by a list of positions, the reference position is typically the first position in the list. For symmetric objects the reference position is often the center of the object. In many cases the object's reference position may be explicitly specified by the application.
Number of grid samples along each side of the area-of-interest (output raster is samplesPerSide square). Clamped to [2, MAX_SAMPLES_PER_SIDE] (default MAX_SAMPLES_PER_SIDE is 4096) to prevent GPU allocation footguns - at 4096² the output + sampler textures alone are ~64 MB each.
Number of consecutive frames with no position change required to trigger a full-resolution refresh after a draft-resolution dispatch. Default ~30 frames (~0.5 s at 60 fps).
Functions
Release all GPU resources owned by this sightline (output texture, kernel sampler texture, framebuffer). The actual glDelete* calls run on the next render frame's GL thread - the call itself is safe from any thread. After dispose, doRender is a no-op; reuse requires a fresh instance.
Marks the cached visibility raster stale; the next render frame will resample the elevation model and re-run the kernel. Useful when attributes / occludeAttributes colors are mutated in-place.
Compute the samplesPerSide count that yields approximately metersPerPixel resolution given the shape's current area. Useful when the caller wants the kernel grid to match the native resolution of an underlying DEM — for example 30.0 for NASADEM or 90.0 for SRTM3 — so the kernel doesn't oversample beyond what the source data actually provides. Result is clamped to >= 2 and computed against the longer axis of the area.