package com.revolsys.elevation.gridded; import java.util.Collections; import java.util.Map; import com.revolsys.awt.WebColors; import com.revolsys.collection.map.MapEx; import com.revolsys.elevation.gridded.compactbinary.CompactBinaryGriddedElevation; import com.revolsys.elevation.gridded.esriascii.EsriAsciiGriddedElevation; import com.revolsys.elevation.gridded.usgsdem.UsgsGriddedElevation; import com.revolsys.geometry.model.BoundingBox; import com.revolsys.geometry.model.Geometry; import com.revolsys.geometry.model.GeometryFactory; import com.revolsys.geometry.model.GeometryFactoryProxy; import com.revolsys.geometry.model.Point; import com.revolsys.geometry.model.Triangle; import com.revolsys.geometry.model.editor.GeometryEditor; import com.revolsys.geometry.model.vertex.Vertex; import com.revolsys.io.IoFactory; import com.revolsys.io.IoFactoryRegistry; import com.revolsys.properties.ObjectWithProperties; import com.revolsys.spring.resource.Resource; public interface GriddedElevationModel extends ObjectWithProperties, GeometryFactoryProxy { String GEOMETRY_FACTORY = "geometryFactory"; int NULL_COLOUR = WebColors.colorToRGB(0, 0, 0, 0); static int getGridCellX(final double minX, final int gridCellSize, final double x) { final double deltaX = x - minX; final double cellDiv = deltaX / gridCellSize; final int gridX = (int)Math.floor(cellDiv); return gridX; } static int getGridCellY(final double minY, final int gridCellSize, final double y) { final double deltaY = y - minY; final double cellDiv = deltaY / gridCellSize; final int gridY = (int)Math.floor(cellDiv); return gridY; } public static void ioFactoryInit() { IoFactoryRegistry.addFactory(new CompactBinaryGriddedElevation()); IoFactoryRegistry.addFactory(new EsriAsciiGriddedElevation()); IoFactoryRegistry.addFactory(new UsgsGriddedElevation()); } static GriddedElevationModel newGriddedElevationModel(final Object source) { final Map<String, Object> properties = Collections.emptyMap(); return newGriddedElevationModel(source, properties); } static GriddedElevationModel newGriddedElevationModel(final Object source, final Map<String, ? extends Object> properties) { final GriddedElevationModelReadFactory factory = IoFactory .factory(GriddedElevationModelReadFactory.class, source); if (factory == null) { return null; } else { final Resource resource = Resource.getResource(source); final GriddedElevationModel dem = factory.newGriddedElevationModel(resource, properties); return dem; } } default void cancelChanges() { } void clear(); default double getAspectRatio() { final int width = getGridWidth(); final int height = getGridHeight(); if (width > 0 && height > 0) { return (double)width / height; } else { return 0; } } BoundingBox getBoundingBox(); default int getColour(final int gridX, final int gridY) { throw new UnsupportedOperationException(); } default double getElevation(final double x, final double y) { final int gridX = getGridCellX(x); final int gridY = getGridCellY(y); return getElevation(gridX, gridY); } double getElevation(final int x, final int y); default double getElevation(Point point) { point = convertGeometry(point); final double x = point.getX(); final double y = point.getY(); return getElevation(x, y); } double getElevationFast(int gridX, int gridY); @Override default GeometryFactory getGeometryFactory() { final BoundingBox boundingBox = getBoundingBox(); return boundingBox.getGeometryFactory(); } int getGridCellSize(); default int getGridCellX(final double x) { final double minX = getMinX(); final int gridCellSize = getGridCellSize(); return getGridCellX(minX, gridCellSize, x); } default int getGridCellY(final double y) { final double minY = getMinY(); final int gridCellSize = getGridCellSize(); return getGridCellY(minY, gridCellSize, y); } int getGridHeight(); int getGridWidth(); default double getMaxX() { final BoundingBox boundingBox = getBoundingBox(); return boundingBox.getMaxX(); } default double getMaxY() { final BoundingBox boundingBox = getBoundingBox(); return boundingBox.getMaxY(); } default double getMaxZ() { final BoundingBox boundingBox = getBoundingBox(); return boundingBox.getMaxZ(); } default double getMinX() { final BoundingBox boundingBox = getBoundingBox(); return boundingBox.getMinX(); } default double getMinY() { final BoundingBox boundingBox = getBoundingBox(); return boundingBox.getMinY(); } default double getMinZ() { final BoundingBox boundingBox = getBoundingBox(); return boundingBox.getMinZ(); } Resource getResource(); default double getScaleXY() { final GeometryFactory geometryFactory = getGeometryFactory(); final double scaleXy = geometryFactory.getScaleXY(); return scaleXy; } default double getX(final int i) { final double minX = getMinX(); final int gridCellSize = getGridCellSize(); return minX + i * gridCellSize; } default double getY(final int i) { final double maxY = getMaxY(); final int gridCellSize = getGridCellSize(); return maxY - i * gridCellSize; } boolean isEmpty(); default boolean isNull(final double x, final double y) { final int i = getGridCellX(x); final int j = getGridCellY(y); return isNull(i, j); } default boolean isNull(final int x, final int y) { final double elevation = getElevation(x, y); return Double.isNaN(elevation); } default GriddedElevationModel newElevationModel(final BoundingBox boundingBox, final int gridCellSize) { final GeometryFactory geometryFactory = boundingBox.getGeometryFactory(); final int minX = (int)boundingBox.getMinX(); final int minY = (int)boundingBox.getMinY(); final double width = boundingBox.getWidth(); final double height = boundingBox.getHeight(); final int modelWidth = (int)Math.ceil(width / gridCellSize); final int modelHeight = (int)Math.ceil(height / gridCellSize); final GriddedElevationModel elevationModel = newElevationModel(geometryFactory, minX, minY, modelWidth, modelHeight, gridCellSize); final int maxX = minX + modelWidth * gridCellSize; final int maxY = minY + modelHeight * gridCellSize; for (double y = minY; y < maxY; y += gridCellSize) { for (double x = minX; x < maxX; x += gridCellSize) { setElevation(elevationModel, x, y); } } return elevationModel; } default GriddedElevationModel newElevationModel(final double x, final double y, final int width, final int height) { final GeometryFactory geometryFactory = getGeometryFactory(); final int gridCellSize = getGridCellSize(); return newElevationModel(geometryFactory, x, y, width, height, gridCellSize); } GriddedElevationModel newElevationModel(GeometryFactory geometryFactory, double x, double y, int width, int height, int gridCellSize); default GriddedElevationModel resample(final int newGridCellSize) { final int tileX = (int)getMinX(); final int tileY = (int)getMinY(); 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 GriddedElevationModel newDem = new IntArrayScaleGriddedElevationModel(geometryFactory, tileX, tileY, newGridWidth, newGridHeight, newGridCellSize); int newGridY = 0; for (int gridYMin = 0; gridYMin < gridHeight; gridYMin += step) { final int gridYMax = gridYMin + step; int newGridX = 0; for (int gridXMin = 0; gridXMin < gridWidth; gridXMin += step) { final int gridXMax = gridXMin + step; int count = 0; double sum = 0; for (int gridY = gridYMin; gridY < gridYMax; gridY++) { for (int gridX = gridXMin; gridX < gridXMax; gridX++) { final double elevation = getElevation(gridX, gridY); if (Double.isFinite(elevation)) { count++; sum += elevation; } } } if (count > 0) { final double elevation = geometryFactory.makeZPrecise(sum / count); newDem.setElevation(newGridX, newGridY, elevation); } newGridX++; } newGridY++; } return newDem; } void setBoundingBox(BoundingBox boundingBox); default void setElevation(final double x, final double y, final double elevation) { final int gridX = getGridCellX(x); final int gridY = getGridCellY(y); setElevation(gridX, gridY, elevation); } default void setElevation(final GriddedElevationModel elevationModel, final double x, final double y) { final int gridX = getGridCellX(x); final int gridY = getGridCellY(y); final double elevation = elevationModel.getElevation(x, y); setElevation(gridX, gridY, elevation); } void setElevation(final int gridX, final int gridY, final double elevation); default void setElevation(final int gridX, final int gridY, final GriddedElevationModel elevationModel, final double x, final double y) { final double elevation = elevationModel.getElevation(x, y); if (Double.isFinite(elevation)) { setElevation(gridX, gridY, elevation); } } default void setElevationNull(final int gridX, final int gridY) { setElevation(gridX, gridY, Double.NaN); } default void setElevations(final GriddedElevationModel elevationModel) { final double minX1 = elevationModel.getMinX(); final double minY1 = elevationModel.getMinY(); int startX = getGridCellX(minX1); if (startX < 0) { startX = 0; } int startY = getGridCellY(minY1); if (startY < 0) { startY = 0; } final int gridCellSize = getGridCellSize(); final int minX = (int)getMinX() + startX * gridCellSize; final int minY = (int)getMinY() + startY * gridCellSize; double y = minY; final int gridWidth = getGridWidth(); final int gridHeight = getGridHeight(); for (int gridY = startY; gridY < gridHeight; gridY++) { double x = minX; for (int gridX = startX; gridX < gridWidth; gridX++) { setElevation(gridX, gridY, elevationModel, x, y); x += gridCellSize; } y += gridCellSize; } } default void setElevationsForTriangle(final double x1, final double y1, final double z1, final double x2, final double y2, final double z2, final double x3, final double y3, final double z3) { final double scaleXy = getScaleXY(); double minX = x1; double maxX = x1; if (x2 < minX) { minX = x2; } else if (x2 > maxX) { maxX = x2; } if (x2 < minX) { minX = x2; } else if (x2 > maxX) { maxX = x2; } if (x3 < minX) { minX = x3; } else if (x3 > maxX) { maxX = x3; } double minY = y1; double maxY = y1; if (y2 < minY) { minY = y2; } else if (y2 > maxY) { maxY = y2; } if (y3 < minY) { minY = y3; } else if (y3 > maxY) { maxY = y3; } final int gridCellSize = getGridCellSize(); final double gridMinX = getMinX(); final double gridMaxX = getMaxX(); final double startX; if (minX < gridMinX) { startX = gridMinX; } else { startX = Math.ceil(minX / gridCellSize) * gridCellSize; } if (maxX > gridMaxX) { maxX = gridMaxX; } final double gridMinY = getMinY(); final double gridMaxY = getMaxY(); final double startY; if (minY < gridMinY) { startY = gridMinY; } else { startY = Math.ceil(minY / gridCellSize) * gridCellSize; } if (maxY > gridMaxY) { maxY = gridMaxY; } for (double y = startY; y < maxY; y += gridCellSize) { for (double x = startX; x < maxX; x += gridCellSize) { if (Triangle.containsPoint(scaleXy, x1, y1, x2, y2, x3, y3, x, y)) { final double elevation = Triangle.getElevation(x1, y1, z1, x2, y2, z2, x3, y3, z3, x, y); if (Double.isFinite(elevation)) { setElevation(x, y, elevation); } } } } } default void setElevationsNull(final GriddedElevationModel elevationModel) { final double minX1 = elevationModel.getMinX(); final double minY1 = elevationModel.getMinY(); int startX = getGridCellX(minX1); if (startX < 0) { startX = 0; } int startY = getGridCellY(minY1); if (startY < 0) { startY = 0; } final int gridCellSize = getGridCellSize(); final int minX = (int)getMinX() + startX * gridCellSize; final int minY = (int)getMinY() + startY * gridCellSize; double y = minY; final int gridWidth = getGridWidth(); final int gridHeight = getGridHeight(); for (int gridY = startY; gridY < gridHeight; gridY++) { double x = minX; for (int gridX = startX; gridX < gridWidth; gridX++) { final GriddedElevationModel elevationModel1 = elevationModel; final double elevation = elevationModel1.getElevation(x, y); if (Double.isFinite(elevation)) { setElevationNull(gridX, gridY); } x += gridCellSize; } y += gridCellSize; } } default void setElevationsNullFast(final Iterable<? extends Point> points) { for (final Point point : points) { final double x = point.getX(); final double y = point.getY(); final int gridX = getGridCellX(x); final int gridY = getGridCellY(y); setElevationNull(gridX, gridY); } } @SuppressWarnings("unchecked") default <G extends Geometry> G setGeometryElevations(final G geometry) { final GeometryEditor editor = geometry.newGeometryEditor(); editor.setAxisCount(3); for (final Vertex vertex : geometry.vertices()) { final double x = vertex.getX(); final double y = vertex.getY(); final double elevation = getElevation(x, y); if (Double.isFinite(elevation)) { final int[] vertexId = vertex.getVertexId(); editor.setZ(elevation, vertexId); } } return (G)editor.newGeometry(); } void setResource(Resource resource); void updateZBoundingBox(); default boolean writeGriddedElevationModel() { return writeGriddedElevationModel(MapEx.EMPTY); } default boolean writeGriddedElevationModel(final Map<String, ? extends Object> properties) { final Resource resource = getResource(); if (resource == null) { return false; } else { writeGriddedElevationModel(resource, properties); return true; } } default void writeGriddedElevationModel(final Object target) { final Map<String, ? extends Object> properties = Collections.emptyMap(); writeGriddedElevationModel(target, properties); } default void writeGriddedElevationModel(final Object target, final Map<String, ? extends Object> properties) { try ( GriddedElevationModelWriter writer = GriddedElevationModelWriter .newGriddedElevationModelWriter(target, properties)) { if (writer == null) { throw new IllegalArgumentException("No elevation model writer exists for " + target); } else { writer.write(this); } } } }