package com.revolsys.elevation.tin; import java.util.function.Consumer; import com.revolsys.geometry.index.quadtree.IdObjectQuadTree; import com.revolsys.geometry.index.quadtree.QuadTree; import com.revolsys.geometry.model.BoundingBox; import com.revolsys.geometry.model.GeometryFactory; import com.revolsys.geometry.model.Point; import com.revolsys.geometry.model.Triangle; import com.revolsys.geometry.model.impl.AbstractTriangle; import com.revolsys.geometry.model.impl.BaseBoundingBox; import com.revolsys.geometry.util.BoundingBoxUtil; import com.revolsys.spring.resource.Resource; public class IntArrayScaleTriangulatedIrregularNetwork implements TriangulatedIrregularNetwork { private class TinTriangle extends AbstractTriangle { private static final long serialVersionUID = 1L; private final int triangleIndex; public TinTriangle(final int triangleIndex) { this.triangleIndex = triangleIndex; } @Override public double getCoordinate(final int vertexIndex, final int axisIndex) { if (this.triangleIndex >= 0 && this.triangleIndex < IntArrayScaleTriangulatedIrregularNetwork.this.triangleCount && axisIndex >= 0 && axisIndex < 3) { final double coordinate = getTriangleVertexCoordinate(this.triangleIndex, vertexIndex, axisIndex); return coordinate; } return Double.NaN; } @Override public double[] getCoordinates() { final double[] coordinates = new double[12]; int coordinateIndex = 0; for (int vertexIndex = 0; vertexIndex < 3; vertexIndex++) { coordinates[coordinateIndex++] = getTriangleVertexX(this.triangleIndex, vertexIndex); coordinates[coordinateIndex++] = getTriangleVertexY(this.triangleIndex, vertexIndex); coordinates[coordinateIndex++] = getTriangleVertexZ(this.triangleIndex, vertexIndex); } coordinates[coordinateIndex++] = coordinates[0]; coordinates[coordinateIndex++] = coordinates[1]; coordinates[coordinateIndex++] = coordinates[2]; return coordinates; } @Override public GeometryFactory getGeometryFactory() { return IntArrayScaleTriangulatedIrregularNetwork.this.geometryFactory; } @Override public double getX(final int vertexIndex) { return getTriangleVertexX(this.triangleIndex, vertexIndex); } @Override public double getY(final int vertexIndex) { return getTriangleVertexY(this.triangleIndex, vertexIndex); } @Override public double getZ(final int vertexIndex) { return getTriangleVertexZ(this.triangleIndex, vertexIndex); } } private class TinTriangleBoundingBox extends BaseBoundingBox { private static final long serialVersionUID = 1L; private final int triangleIndex; public TinTriangleBoundingBox(final int triangleIndex) { this.triangleIndex = triangleIndex; } @Override public GeometryFactory getGeometryFactory() { return IntArrayScaleTriangulatedIrregularNetwork.this.geometryFactory; } @Override public double getMax(final int axisIndex) { if (axisIndex == 0 || axisIndex == 1) { double max = Double.NEGATIVE_INFINITY; for (int vertexIndex = 0; vertexIndex < 3; vertexIndex++) { final double value = getTriangleVertexCoordinate(this.triangleIndex, vertexIndex, axisIndex); if (value > max) { max = value; } } return max; } else { return Double.NaN; } } @Override public double getMin(final int axisIndex) { if (axisIndex == 0 || axisIndex == 1) { double min = Double.POSITIVE_INFINITY; for (int vertexIndex = 0; vertexIndex < 3; vertexIndex++) { final double value = getTriangleVertexCoordinate(this.triangleIndex, vertexIndex, axisIndex); if (value < min) { min = value; } } return min; } else { return Double.NaN; } } @Override public boolean isEmpty() { return false; } } private final int[] triangleXCoordinates; private final int[] triangleYCoordinates; private final int[] triangleZCoordinates; private final int triangleCount; protected final GeometryFactory geometryFactory; private QuadTree<Integer> triangleSpatialIndex; private final BoundingBox boundingBox; private final double scaleX; private final double scaleY; private final double scaleZ; public IntArrayScaleTriangulatedIrregularNetwork(final GeometryFactory geometryFactory, final BoundingBox boundingBox, final int triangleCount, final int[] triangleXCoordinates, final int[] triangleYCoordinates, final int[] triangleZCoordinates) { this.geometryFactory = geometryFactory; this.scaleX = geometryFactory.getScaleX(); this.scaleY = geometryFactory.getScaleY(); this.scaleZ = geometryFactory.getScaleZ(); this.triangleCount = triangleCount; this.boundingBox = boundingBox; this.triangleXCoordinates = triangleXCoordinates; this.triangleYCoordinates = triangleYCoordinates; this.triangleZCoordinates = triangleZCoordinates; } @Override public void forEachTriangle(final BoundingBox boundingBox, final Consumer<? super Triangle> action) { final QuadTree<Integer> index = getTriangleSpatialIndex(); index.forEach(boundingBox, (triangleIndex) -> { final Triangle triangle = newTriangle(triangleIndex); if (triangle != null) { action.accept(triangle); } }); } @Override public void forEachTriangle(final Consumer<? super Triangle> action) { for (int i = 0; i < this.triangleCount; i++) { final Triangle triangle = newTriangle(i); action.accept(triangle); } } @Override public void forEachVertex(final Consumer<Point> action) { throw new UnsupportedOperationException(); } @Override public BoundingBox getBoundingBox() { return this.boundingBox; } @Override public GeometryFactory getGeometryFactory() { return this.geometryFactory; } @Override public Resource getResource() { // TODO Auto-generated method stub return null; } @Override public int getTriangleCount() { return this.triangleCount; } public QuadTree<Integer> getTriangleSpatialIndex() { if (this.triangleSpatialIndex == null) { final QuadTree<Integer> triangleSpatialIndex = new IdObjectQuadTree<Integer>( this.geometryFactory) { private static final long serialVersionUID = 1L; @Override protected boolean intersectsBounds(final Object id, final double x, final double y) { final Integer triangleIndex = (Integer)id; return newTriangleBoundingBox(triangleIndex).intersects(x, y); } @Override protected boolean intersectsBounds(final Object id, final double minX, final double minY, final double maxX, final double maxY) { final Integer triangleIndex = (Integer)id; return newTriangleBoundingBox(triangleIndex).intersects(minX, minY, maxX, maxY); } }; triangleSpatialIndex.setUseEquals(true); final double[] bounds = BoundingBoxUtil.newBounds(2); for (int triangleIndex = 0; triangleIndex < this.triangleCount; triangleIndex++) { final BoundingBox triangleBoundingBox = newTriangleBoundingBox(triangleIndex); final double minX = triangleBoundingBox.getMinX(); final double minY = triangleBoundingBox.getMinY(); final double maxX = triangleBoundingBox.getMaxX(); final double maxY = triangleBoundingBox.getMaxY(); triangleSpatialIndex.insertItem(minX, minY, maxX, maxY, triangleIndex); BoundingBoxUtil.expand(bounds, 2, triangleBoundingBox); } this.triangleSpatialIndex = triangleSpatialIndex; } return this.triangleSpatialIndex; } public double getTriangleVertexCoordinate(final int triangleIndex, final int vertexIndex, final int axisIndex) { switch (axisIndex) { case 0: return getTriangleVertexX(triangleIndex, vertexIndex); case 1: return getTriangleVertexY(triangleIndex, vertexIndex); case 2: return getTriangleVertexZ(triangleIndex, vertexIndex); default: return Double.NaN; } } public double getTriangleVertexX(final int triangleIndex, final int vertexIndex) { final int intValue = this.triangleXCoordinates[triangleIndex * 3 + vertexIndex]; if (intValue == Integer.MIN_VALUE) { return Double.NaN; } else { return intValue / this.scaleX; } } public double getTriangleVertexY(final int triangleIndex, final int vertexIndex) { final int intValue = this.triangleYCoordinates[triangleIndex * 3 + vertexIndex]; if (intValue == Integer.MIN_VALUE) { return Double.NaN; } else { return intValue / this.scaleY; } } public double getTriangleVertexZ(final int triangleIndex, final int vertexIndex) { final int intValue = this.triangleZCoordinates[triangleIndex * 3 + vertexIndex]; if (intValue == Integer.MIN_VALUE) { return Double.NaN; } else { return intValue / this.scaleZ; } } @Override public int getVertexCount() { return 0; } public Triangle newTriangle(final int triangleIndex) { if (triangleIndex >= 0 && triangleIndex < this.triangleCount) { return new TinTriangle(triangleIndex); } else { return null; } } public BoundingBox newTriangleBoundingBox(final int triangleIndex) { return new TinTriangleBoundingBox(triangleIndex); } }