package com.revolsys.elevation.tin; import java.util.function.Consumer; 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; public abstract class BaseCompactTriangulatedIrregularNetwork 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 < BaseCompactTriangulatedIrregularNetwork.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 triangleVertexIndex = 0; triangleVertexIndex < 3; triangleVertexIndex++) { final int vertexIndex = getTriangleVertexIndex(this.triangleIndex, triangleVertexIndex); for (int i = 0; i < 3; i++) { coordinates[coordinateIndex++] = getVertexCoordinate(vertexIndex, i); } } coordinates[coordinateIndex++] = coordinates[0]; coordinates[coordinateIndex++] = coordinates[1]; coordinates[coordinateIndex++] = coordinates[2]; return coordinates; } @Override public GeometryFactory getGeometryFactory() { return BaseCompactTriangulatedIrregularNetwork.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 BaseCompactTriangulatedIrregularNetwork.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; } } public static double[] increaseSize(final double[] array) { final int oldLength = array.length; final int newLength = oldLength + (oldLength >>> 1); final double[] newArray = new double[newLength]; System.arraycopy(array, 0, newArray, 0, oldLength); return newArray; } public static double[] increaseSize(final double[] array, final int minSize) { final int oldLength = array.length; final int newLength = Math.round(minSize / 2) * 2 + 16; final double[] newArray = new double[newLength]; System.arraycopy(array, 0, newArray, 0, oldLength); return newArray; } public static int[] increaseSize(final int[] array, final int minSize) { final int oldLength = array.length; final int newLength = Math.round(minSize / 2) * 2 + 16; final int[] newArray = new int[newLength]; System.arraycopy(array, 0, newArray, 0, oldLength); return newArray; } private int[] triangleVertex0Indices; private int[] triangleVertex1Indices; private int[] triangleVertex2Indices; protected double[] vertexXCoordinates = new double[1024]; protected double[] vertexYCoordinates = new double[1024]; protected double[] vertexZCoordinates = new double[1024]; protected int vertexCount; private int triangleCount; protected final GeometryFactory geometryFactory; public BaseCompactTriangulatedIrregularNetwork(final GeometryFactory geometryFactory, final int vertexCount, final double[] vertexXCoordinates, final double[] vertexYCoordinates, final double[] vertexZCoordinates, final int triangleCount, final int[] triangleVertex0Indices, final int[] triangleVertex1Indices, final int[] triangleVertex2Indices) { this.geometryFactory = geometryFactory.convertAxisCount(3); this.vertexCount = vertexCount; this.vertexXCoordinates = vertexXCoordinates; this.vertexYCoordinates = vertexYCoordinates; this.vertexZCoordinates = vertexZCoordinates; this.triangleCount = triangleCount; this.triangleVertex0Indices = triangleVertex0Indices; this.triangleVertex1Indices = triangleVertex1Indices; this.triangleVertex2Indices = triangleVertex2Indices; } protected int appendTriangleVertexIndices(final int vertexIndex1, final int vertexIndex2, final int vertexIndex3) { final int triangleCount = this.triangleCount; if (this.triangleVertex0Indices.length < triangleCount + 1) { final int newTriangleCapacity = triangleCount + (triangleCount >>> 1); setTriangleCapacity(newTriangleCapacity); } this.triangleCount++; setTriangleVertexIndices(triangleCount, vertexIndex1, vertexIndex2, vertexIndex3); return triangleCount; } @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) { for (int i = 0; i < getVertexCount(); i++) { final Point point = getVertex(i); action.accept(point); } } @Override public GeometryFactory getGeometryFactory() { return this.geometryFactory; } @Override public int getTriangleCount() { return this.triangleCount; } protected int[] getTriangleVertex0Indices() { return this.triangleVertex0Indices; } protected int[] getTriangleVertex1Indices() { return this.triangleVertex1Indices; } protected int[] getTriangleVertex2Indices() { return this.triangleVertex2Indices; } public double getTriangleVertexCoordinate(final int triangleIndex, final int vertexIndex, final int axisIndex) { final int triangleVertexVertexIndex = getTriangleVertexIndex(triangleIndex, vertexIndex); final double coordinate = getVertexCoordinate(triangleVertexVertexIndex, axisIndex); return coordinate; } public int getTriangleVertexIndex(final int triangleIndex, final int triangleVertexIndex) { switch (triangleVertexIndex) { case 0: return this.triangleVertex0Indices[triangleIndex]; case 1: return this.triangleVertex1Indices[triangleIndex]; case 2: return this.triangleVertex2Indices[triangleIndex]; default: throw new ArrayIndexOutOfBoundsException(); } } public double getTriangleVertexX(final int triangleIndex, final int vertexIndex) { final int triangleVertexVertexIndex = getTriangleVertexIndex(triangleIndex, vertexIndex); final double coordinate = getVertexX(triangleVertexVertexIndex); return coordinate; } public double getTriangleVertexY(final int triangleIndex, final int vertexIndex) { final int triangleVertexVertexIndex = getTriangleVertexIndex(triangleIndex, vertexIndex); final double coordinate = getVertexY(triangleVertexVertexIndex); return coordinate; } public double getTriangleVertexZ(final int triangleIndex, final int vertexIndex) { final int triangleVertexVertexIndex = getTriangleVertexIndex(triangleIndex, vertexIndex); final double coordinate = getVertexZ(triangleVertexVertexIndex); return coordinate; } public Point getVertex(final int vertexIndex) { final double x = getVertexX(vertexIndex); final double y = this.vertexYCoordinates[vertexIndex]; final double z = this.vertexZCoordinates[vertexIndex]; final GeometryFactory geometryFactory = getGeometryFactory(); return geometryFactory.point(x, y, z); } public double getVertexCoordinate(final int vertexIndex, final int axisIndex) { switch (axisIndex) { case 0: return this.vertexXCoordinates[vertexIndex]; case 1: return this.vertexYCoordinates[vertexIndex]; case 2: return this.vertexZCoordinates[vertexIndex]; default: return Double.NaN; } } @Override public int getVertexCount() { return this.vertexCount; } public double getVertexX(final int vertexIndex) { return this.vertexXCoordinates[vertexIndex]; } public double getVertexY(final int vertexIndex) { return this.vertexYCoordinates[vertexIndex]; } public double getVertexZ(final int vertexIndex) { return this.vertexZCoordinates[vertexIndex]; } 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); } protected void setTriangleCapacity(final int triangleCapacity) { if (this.triangleVertex0Indices.length < triangleCapacity) { this.triangleVertex0Indices = increaseSize(this.triangleVertex0Indices, triangleCapacity); this.triangleVertex1Indices = increaseSize(this.triangleVertex1Indices, triangleCapacity); this.triangleVertex2Indices = increaseSize(this.triangleVertex2Indices, triangleCapacity); } } protected void setTriangleCount(final int triangleCount) { this.triangleCount = triangleCount; } protected void setTriangleVertexIndices(final int triangleIndex, final int vertexIndex1, final int vertexIndex2, final int vertexIndex3) { this.triangleVertex0Indices[triangleIndex] = vertexIndex1; this.triangleVertex1Indices[triangleIndex] = vertexIndex2; this.triangleVertex2Indices[triangleIndex] = vertexIndex3; } }