package com.revolsys.elevation.gridded; import com.revolsys.awt.WebColors; import com.revolsys.util.MathUtil; public class HillShadeConfiguration { private static final double PI_TIMES_2_MINUS_PI_OVER_2 = MathUtil.PI_TIMES_2 - MathUtil.PI_OVER_2; private GriddedElevationModel elevationModel; private int width; private int height; private double zenithRadians; private double azimuthRadians; private double cosZenithRadians; private double sinZenithRadians; private double oneDivCellSizeTimes8; private final double zFactor = 1; public HillShadeConfiguration(final GriddedElevationModel elevationModel) { setElevationModel(elevationModel); setZenithDegrees(45.0); setAzimuthDegrees(315.0); } private int getHillShade(final double a, final double b, final double c, final double d, final double f, final double g, final double h, final double i) { final double oneDivCellSizeTimes8 = this.oneDivCellSizeTimes8; final double dzDivDx = (c + 2 * f + i - (a + 2 * d + g)) * oneDivCellSizeTimes8; final double dzDivDy = (g + 2 * h + i - (a + 2 * b + c)) * oneDivCellSizeTimes8; final double slopeRadians = Math .atan(this.zFactor * Math.sqrt(dzDivDx * dzDivDx + dzDivDy * dzDivDy)); double aspectRadians; if (dzDivDx == 0) { if (dzDivDy > 0) { aspectRadians = MathUtil.PI_OVER_2; } else if (dzDivDy < 0) { aspectRadians = PI_TIMES_2_MINUS_PI_OVER_2; } else { aspectRadians = 0; } } else { aspectRadians = Math.atan2(dzDivDy, -dzDivDx); if (aspectRadians < 0) { aspectRadians = MathUtil.PI_TIMES_2 + aspectRadians; } } final int hillshade = (int)(255.0 * (this.cosZenithRadians * Math.cos(slopeRadians) + this.sinZenithRadians * Math.sin(slopeRadians) * Math.cos(this.azimuthRadians - aspectRadians))); return WebColors.colorToRGB(255, hillshade, hillshade, hillshade); } public int getHillShade(final int index) { final int width = this.width; final int height = this.height; final int x = index % width; final int y = height - 1 - (index - x) / width; return getHillShade(x, y); } private int getHillShade(final int gridX, final int gridY) { final GriddedElevationModel elevationModel = this.elevationModel; final int width = this.width; final int height = this.height; double a; double b; double c; double d; final double e = elevationModel.getElevationFast(gridX, gridY); if (Double.isFinite(e)) { double f; double g; double h; double i; final boolean firstX = gridX == 0; final boolean firstY = gridY == 0; final boolean lastX = gridX == width - 1; final boolean lastY = gridY == height - 1; if (firstX) { d = e; } else { d = elevationModel.getElevationFast(gridX - 1, gridY); } if (lastX) { f = e; } else { f = elevationModel.getElevationFast(gridX + 1, gridY); } if (firstY) { g = d; h = e; i = f; } else { if (firstX) { g = e; } else { g = elevationModel.getElevationFast(gridX - 1, gridY - 1); } h = elevationModel.getElevationFast(gridX, gridY - 1); if (lastX) { i = e; } else { i = elevationModel.getElevationFast(gridX + 1, gridY - 1); } } if (lastY) { a = d; b = e; c = f; } else { if (firstX) { a = e; } else { a = elevationModel.getElevationFast(gridX - 1, gridY + 1); } b = elevationModel.getElevationFast(gridX, gridY + 1); if (lastX) { c = e; } else { c = elevationModel.getElevationFast(gridX + 1, gridY + 1); } } return getHillShade(a, b, c, d, f, g, h, i); } else { return GriddedElevationModel.NULL_COLOUR; } } private void setAzimuthDegrees(final double azimuth) { this.azimuthRadians = Math.toRadians(360 - azimuth + 90); } private void setElevationModel(final GriddedElevationModel elevationModel) { this.elevationModel = elevationModel; this.width = elevationModel.getGridWidth(); this.height = elevationModel.getGridHeight(); final int cellSize = elevationModel.getGridCellSize(); this.oneDivCellSizeTimes8 = 1.0 / (8 * cellSize); } private void setZenithDegrees(final double zenith) { this.zenithRadians = Math.toRadians(90 - zenith); this.cosZenithRadians = Math.cos(this.zenithRadians); this.sinZenithRadians = Math.sin(this.zenithRadians); } }