render method

  1. @override
void render(
  1. Uint8List pixels,
  2. int tileSize,
  3. int px,
  4. int py,
  5. PixelProjection projection,
  6. double latitude,
  7. double longitude,
  8. int centerElev,
)
override

Implementation

@override
void render(Uint8List pixels, int tileSize, int px, int py, PixelProjection projection, double latitude, double longitude, int centerElev) {
  // Sample neighbours using a small geographic offset derived from meters-per-pixel.
  // This keeps the gradient scale stable across zoom levels.
  final mpp = projection.meterPerPixel(LatLong(latitude, longitude));
  if (mpp == 0) return;

  final dMeters = max(mpp, 1.0);
  final dLon = _metersToLongitudeDegrees(latitude, dMeters);
  final dLat = _metersToLatitudeDegrees(dMeters);

  final eW = _elevationAt(latitude, longitude - dLon, projection) ?? centerElev;
  final eE = _elevationAt(latitude, longitude + dLon, projection) ?? centerElev;
  final eN = _elevationAt(latitude + dLat, longitude, projection) ?? centerElev;
  final eS = _elevationAt(latitude - dLat, longitude, projection) ?? centerElev;

  final dzdx = (eE - eW) / (2 * dMeters);
  final dzdy = (eN - eS) / (2 * dMeters);

  final az = hillshadeAzimuthDeg * pi / 180;
  final alt = hillshadeAltitudeDeg * pi / 180;

  // Surface normal.
  final nx = -dzdx;
  final ny = -dzdy;
  final nz = 1.0;
  final nLen = sqrt(nx * nx + ny * ny + nz * nz);

  final ux = cos(alt) * sin(az);
  final uy = cos(alt) * cos(az);
  final uz = sin(alt);

  final dot = (nx / nLen) * ux + (ny / nLen) * uy + (nz / nLen) * uz;
  final intensity = (dot.clamp(0.0, 1.0) * 255).round();
  _setPixel(pixels, tileSize, px, py, intensity, intensity, intensity, 255);
}