Expand description
Hillshade of a DEM, as a fused kernel.
Mirrors TerraTexture.derivatives’ hillshade() exactly, including
its az = 360 - azimuth + 90 convention and np.gradient’s
edge_order=1 boundary handling. Verified against derivatives.py
in tests/test_derivatives_rust.py.
§NaN handling
Same as curvature: the DEM must be NaN-free,
and the Python caller nan-fills before and re-masks after.
§Formula
The textbook form is
slope = π/2 - atan(hypot(zx, zy))
aspect = atan2(-zx, zy)
shaded = sin(alt)·sin(slope) + cos(alt)·cos(slope)·cos(az - aspect)Expanding it with sin(atan g) = g/√(1+g²), cos(atan g) = 1/√(1+g²)
and the angle-difference identity, the g = hypot(zx, zy) factor
cancels, leaving
shaded = (sin(alt) + cos(alt)·(cos(az)·zy - sin(az)·zx)) / √(1 + zx² + zy²)That is one square root per pixel and no inverse trig. Flat cells
(zx = zy = 0) need no special case, since the denominator is 1 rather
than the 0/0 that hypot(0, 0) would produce in the aspect term.
Functions§
- hillshade_
core - Compute a hillshade (simulated illumination) of a DEM.