package com.revolsys.elevation.gridded; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import com.revolsys.elevation.gridded.compactbinary.CompactBinaryGriddedElevationWriter; import com.revolsys.geometry.model.BoundingBox; import com.revolsys.geometry.model.GeometryFactory; import com.revolsys.geometry.model.Point; import com.revolsys.geometry.model.impl.PointDoubleXY; import com.revolsys.io.channels.ChannelWriter; import com.revolsys.util.Debug; public class IntArrayScaleGriddedElevationModel extends AbstractGriddedElevationModel { private static final int NULL_VALUE = Integer.MIN_VALUE; private final int[] elevations; public IntArrayScaleGriddedElevationModel(final GeometryFactory geometryFactory, final BoundingBox boundingBox, final int gridWidth, final int gridHeight, final int gridCellSize, final int[] elevations) { super(geometryFactory, boundingBox, gridWidth, gridHeight, gridCellSize); this.elevations = elevations; } public IntArrayScaleGriddedElevationModel(final GeometryFactory geometryFactory, final double x, final double y, final int gridWidth, final int gridHeight, final int gridCellSize) { super(geometryFactory, x, y, gridWidth, gridHeight, gridCellSize); final int size = gridWidth * gridHeight; final int[] elevations = new int[size]; Arrays.fill(elevations, NULL_VALUE); this.elevations = elevations; } @Override public void clear() { super.clear(); Arrays.fill(this.elevations, NULL_VALUE); } @Override protected void expandZ() { int min = Integer.MAX_VALUE; int max = Integer.MIN_VALUE; for (final int elevationInt : this.elevations) { if (elevationInt != NULL_VALUE) { if (elevationInt < min) { min = elevationInt; } if (elevationInt > max) { max = elevationInt; } } } final double minZ = toDoubleZ(min); final double maxZ = toDoubleZ(max); setZRange(minZ, maxZ); } @Override protected double getElevationDo(final int gridX, final int gridY, final int gridWidth) { final int index = gridY * gridWidth + gridX; final int elevationInt = this.elevations[index]; if (elevationInt == NULL_VALUE) { return Double.NaN; } else { return toDoubleZ(elevationInt); } } public int getElevationInt(final int gridX, final int gridY) { final int width = getGridWidth(); final int height = getGridHeight(); if (gridX >= 0 && gridX < width && gridY >= 0 && gridY < height) { final int index = gridY * width + gridX; return this.elevations[index]; } else { return NULL_VALUE; } } public List<Point> getNullBoundaryPoints() { final List<Point> points = new ArrayList<>(); final double minX = getMinX(); final double minY = getMinY(); final int gridCellSize = getGridCellSize(); final int gridHeight = getGridHeight(); final int gridWidth = getGridWidth(); final int[] elevations = this.elevations; int index = 0; for (int gridY = 0; gridY < gridHeight; gridY++) { for (int gridX = 0; gridX < gridWidth; gridX++) { final int elevation = elevations[index]; if (index != gridY * gridWidth + gridX) { Debug.noOp(); } if (elevation == NULL_VALUE) { boolean hasNeighbour = false; if (gridX == 0) { if (gridY == 0) { hasNeighbour = elevations[index + 1] != NULL_VALUE // || elevations[index + gridWidth] != NULL_VALUE // || elevations[index + gridWidth + 1] != NULL_VALUE// ; } else if (gridY == gridHeight - 1) { hasNeighbour = elevations[index - 1] != NULL_VALUE // || elevations[index - gridWidth - 1] != NULL_VALUE // || elevations[index - gridWidth] != NULL_VALUE // ; } else { hasNeighbour = elevations[index + 1] != NULL_VALUE // || elevations[index - gridWidth] != NULL_VALUE // || elevations[index - gridWidth + 1] != NULL_VALUE // || elevations[index + gridWidth] != NULL_VALUE // || elevations[index + gridWidth + 1] != NULL_VALUE// ; } } else if (gridX == gridWidth - 1) { if (gridY == 0) { hasNeighbour = elevations[index - 1] != NULL_VALUE // || elevations[index + gridWidth - 1] != NULL_VALUE // || elevations[index + gridWidth] != NULL_VALUE // ; } else if (gridY == gridHeight - 1) { hasNeighbour = elevations[index - 1] != NULL_VALUE // || elevations[index - gridWidth - 1] != NULL_VALUE // || elevations[index - gridWidth] != NULL_VALUE // ; } else { hasNeighbour = elevations[index - 1] != NULL_VALUE // || elevations[index - gridWidth - 1] != NULL_VALUE // || elevations[index - gridWidth] != NULL_VALUE // || elevations[index + gridWidth - 1] != NULL_VALUE // || elevations[index + gridWidth] != NULL_VALUE // ; } } else { if (gridY == 0) { hasNeighbour = elevations[index - 1] != NULL_VALUE // || elevations[index + 1] != NULL_VALUE // || elevations[index + gridWidth - 1] != NULL_VALUE // || elevations[index + gridWidth] != NULL_VALUE // || elevations[index + gridWidth + 1] != NULL_VALUE// ; } else if (gridY == gridHeight - 1) { hasNeighbour = elevations[index - 1] != NULL_VALUE // || elevations[index + 1] != NULL_VALUE // || elevations[index - gridWidth - 1] != NULL_VALUE // || elevations[index - gridWidth] != NULL_VALUE // || elevations[index - gridWidth + 1] != NULL_VALUE // ; } else { hasNeighbour = elevations[index - 1] != NULL_VALUE // || elevations[index + 1] != NULL_VALUE // || elevations[index - gridWidth - 1] != NULL_VALUE // || elevations[index - gridWidth] != NULL_VALUE // || elevations[index - gridWidth + 1] != NULL_VALUE // || elevations[index + gridWidth - 1] != NULL_VALUE // || elevations[index + gridWidth] != NULL_VALUE // || elevations[index + gridWidth + 1] != NULL_VALUE// ; } } if (hasNeighbour) { final double x = minX + gridCellSize * gridX; final double y = minY + gridCellSize * gridY; final PointDoubleXY point = new PointDoubleXY(x, y); points.add(point); } } index++; } } return points; } @Override public IntArrayScaleGriddedElevationModel newElevationModel(final GeometryFactory geometryFactory, final double x, final double y, final int width, final int height, final int cellSize) { return new IntArrayScaleGriddedElevationModel(geometryFactory, x, y, width, height, cellSize); } @Override public GriddedElevationModel resample(final int newGridCellSize) { final int gridCellSize = getGridCellSize(); final double cellRatio = (double)gridCellSize / newGridCellSize; final int step = (int)Math.round(1 / cellRatio); final int gridWidth = getGridWidth(); final int gridHeight = getGridHeight(); final int newGridWidth = (int)Math.round(gridWidth * cellRatio); final int newGridHeight = (int)Math.round(gridHeight * cellRatio); final GeometryFactory geometryFactory = getGeometryFactory(); final int[] oldElevations = this.elevations; final int[] newElevations = new int[newGridWidth * newGridHeight]; int newIndex = 0; for (int gridYMin = 0; gridYMin < gridHeight; gridYMin += step) { final int gridYMax = gridYMin + step; for (int gridXMin = 0; gridXMin < gridWidth; gridXMin += step) { final int gridXMax = gridXMin + step; int count = 0; long sum = 0; for (int gridY = gridYMin; gridY < gridYMax; gridY++) { for (int gridX = gridXMin; gridX < gridXMax; gridX++) { final int elevation = oldElevations[gridY * gridWidth + gridX]; if (elevation != NULL_VALUE) { count++; sum += elevation; } } } if (count > 0) { newElevations[newIndex] = (int)(sum / count); } else { newElevations[newIndex] = NULL_VALUE; } newIndex++; } } final BoundingBox boundingBox = getBoundingBox(); final GriddedElevationModel newDem = new IntArrayScaleGriddedElevationModel(geometryFactory, boundingBox, newGridWidth, newGridHeight, newGridCellSize, newElevations); return newDem; } @Override public void setElevation(final int gridX, final int gridY, final double elevation) { final int width = getGridWidth(); final int height = getGridHeight(); final GeometryFactory geometryFactory = getGeometryFactory(); if (gridX >= 0 && gridX < width && gridY >= 0 && gridY < height) { final int index = gridY * width + gridX; final int elevationInt = geometryFactory.toIntZ(elevation); this.elevations[index] = elevationInt; clearCachedObjects(); } } @Override protected void setGeometryFactory(final GeometryFactory geometryFactory) { if (geometryFactory.getScaleZ() <= 0) { throw new IllegalArgumentException("Geometry factory must have a z scale factor"); } super.setGeometryFactory(geometryFactory); } public void writeIntArray(final CompactBinaryGriddedElevationWriter writer, final ChannelWriter out) throws IOException { final int[] elevations = this.elevations; for (final int elevation : elevations) { out.putInt(elevation); } } }