package com.revolsys.geometry.model.impl;
import java.util.Arrays;
import com.revolsys.geometry.model.Geometry;
import com.revolsys.geometry.model.GeometryFactory;
import com.revolsys.geometry.model.LineString;
import com.revolsys.geometry.model.LinearRing;
import com.revolsys.geometry.model.Point;
import com.revolsys.geometry.model.Polygon;
public class LineStringDoubleBuilder extends AbstractLineString {
private static final long serialVersionUID = 7579865828939708871L;
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private static int hugeCapacity(final int minCapacity) {
if (minCapacity < 0) {
throw new OutOfMemoryError();
}
return minCapacity > MAX_ARRAY_SIZE ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}
public static LineStringDoubleBuilder newLineStringDoubleBuilder(final LineString line) {
final GeometryFactory geometryFactory = line.getGeometryFactory();
final int axisCount = line.getAxisCount();
final double[] coordinates = line.getCoordinates();
return new LineStringDoubleBuilder(geometryFactory, axisCount, coordinates);
}
protected GeometryFactory geometryFactory;
private final int axisCount;
private double[] coordinates;
private int vertexCount;
public LineStringDoubleBuilder(final GeometryFactory geometryFactory) {
this.geometryFactory = geometryFactory;
this.axisCount = geometryFactory.getAxisCount();
this.coordinates = new double[0];
this.vertexCount = this.coordinates.length / this.axisCount;
}
public LineStringDoubleBuilder(final GeometryFactory geometryFactory, int vertexCapacity) {
if (vertexCapacity < 0) {
vertexCapacity = 0;
}
this.geometryFactory = geometryFactory;
this.axisCount = geometryFactory.getAxisCount();
this.coordinates = new double[vertexCapacity * this.axisCount];
Arrays.fill(this.coordinates, Double.NaN);
this.vertexCount = 0;
}
public LineStringDoubleBuilder(final GeometryFactory geometryFactory, final int axisCount,
final double... coordinates) {
if (axisCount < 2) {
throw new IllegalArgumentException("axisCount=" + axisCount + " must be >= 2");
}
this.geometryFactory = geometryFactory.convertAxisCount(axisCount);
this.axisCount = axisCount;
if (coordinates == null || coordinates.length == 0) {
this.coordinates = new double[0];
} else {
this.coordinates = coordinates;
}
this.vertexCount = this.coordinates.length / axisCount;
}
public LineStringDoubleBuilder(final int axisCount, final int vertexCount,
final double... coordinates) {
if (coordinates == null || coordinates.length == 0) {
this.axisCount = 2;
this.coordinates = new double[0];
this.vertexCount = 0;
} else {
assert axisCount >= 2;
this.axisCount = (byte)axisCount;
final int coordinateCount = vertexCount * axisCount;
if (coordinates.length % axisCount != 0) {
throw new IllegalArgumentException("coordinates.length=" + coordinates.length
+ " must be a multiple of axisCount=" + axisCount);
} else if (coordinateCount == coordinates.length) {
this.coordinates = coordinates;
} else if (coordinateCount > coordinates.length) {
throw new IllegalArgumentException("axisCount=" + axisCount + " * vertexCount="
+ vertexCount + " > coordinates.length=" + coordinates.length);
} else {
this.coordinates = coordinates;
this.vertexCount = 0;
}
}
}
public int appendVertex(final double... coordinates) {
final int index = getVertexCount();
insertVertex(index, coordinates);
return index;
}
public int appendVertex(final double x, final double y) {
final int index = getVertexCount();
if (insertVertex(index, x, y)) {
return index;
} else {
return -1;
}
}
public int appendVertex(final Point point) {
final int index = getVertexCount();
if (insertVertex(index, point)) {
return index;
} else {
return -1;
}
}
public int appendVertex(final Point point, final boolean allowRepeated) {
final int index = getVertexCount();
if (insertVertex(index, point, allowRepeated)) {
return index;
} else {
return -1;
}
}
@Override
public LineStringDoubleBuilder clone() {
final LineStringDoubleBuilder clone = (LineStringDoubleBuilder)super.clone();
clone.coordinates = this.coordinates.clone();
return clone;
}
private void ensureCapacity(final int vertexCount) {
if (vertexCount >= this.vertexCount) {
final int coordinateCount = vertexCount * this.axisCount;
if (coordinateCount - this.coordinates.length > 0) {
grow(coordinateCount);
}
}
}
@Override
public int getAxisCount() {
return this.axisCount;
}
@Override
public double getCoordinate(final int index, final int axisIndex) {
final int axisCount = this.axisCount;
if (index >= 0 && index < this.vertexCount && axisIndex < axisCount) {
return this.coordinates[index * axisCount + axisIndex];
} else {
return Double.NaN;
}
}
@Override
public double[] getCoordinates() {
final double[] coordinates = new double[this.vertexCount * this.axisCount];
System.arraycopy(this.coordinates, 0, coordinates, 0, coordinates.length);
return coordinates;
}
@Override
public GeometryFactory getGeometryFactory() {
return this.geometryFactory;
}
@Override
public int getVertexCount() {
return this.vertexCount;
}
private void grow(final int minCapacity) {
// overflow-conscious code
final int oldCapacity = this.coordinates.length;
int newCapacity;
if (oldCapacity == 0) {
newCapacity = 10;
} else {
newCapacity = oldCapacity + (oldCapacity >> 1);
}
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
if (newCapacity - MAX_ARRAY_SIZE > 0) {
newCapacity = hugeCapacity(minCapacity);
}
// minCapacity is usually close to size, so this is a win:
this.coordinates = Arrays.copyOf(this.coordinates, newCapacity);
Arrays.fill(this.coordinates, oldCapacity, this.coordinates.length, Double.NaN);
}
public void insertVertex(final int index, final double... coordinates) {
final int axisCount = getAxisCount();
if (index >= this.vertexCount) {
ensureCapacity(index);
this.vertexCount = index + 1;
} else {
ensureCapacity(this.vertexCount + 1);
final int offset = index * axisCount;
final int newOffset = offset + axisCount;
System.arraycopy(this.coordinates, offset, this.coordinates, newOffset,
this.coordinates.length - newOffset);
this.vertexCount++;
}
setVertex(index, coordinates);
}
public boolean insertVertex(final int index, final double x, final double y) {
final int axisCount = getAxisCount();
if (index >= this.vertexCount) {
ensureCapacity(index + 1);
this.vertexCount = index + 1;
} else {
ensureCapacity(this.vertexCount + 1);
final int offset = index * axisCount;
final int newOffset = offset + axisCount;
System.arraycopy(this.coordinates, offset, this.coordinates, newOffset,
this.coordinates.length - newOffset);
this.vertexCount++;
}
return setVertex(index, x, y);
}
public boolean insertVertex(final int index, final Point point) {
final int axisCount = getAxisCount();
if (index >= this.vertexCount) {
ensureCapacity(index + 1);
this.vertexCount = index + 1;
} else {
ensureCapacity(this.vertexCount + 1);
final int offset = index * axisCount;
final int newOffset = offset + axisCount;
System.arraycopy(this.coordinates, offset, this.coordinates, newOffset,
this.vertexCount * axisCount - offset);
this.vertexCount++;
}
return setVertex(index, point);
}
public boolean insertVertex(final int index, final Point point, final boolean allowRepeated) {
if (!allowRepeated) {
final int vertexCount = getVertexCount();
if (vertexCount > 0) {
if (index > 0) {
if (equalsVertex(index - 1, point)) {
return false;
}
}
if (index < vertexCount) {
if (equalsVertex(index, point)) {
return false;
}
}
}
}
return insertVertex(index, point);
}
@Override
public boolean isEmpty() {
return this.vertexCount == 0;
}
public Geometry newGeometry() {
final int vertexCount = getVertexCount();
if (vertexCount == 1) {
return newPoint();
} else if (vertexCount == 2) {
return newLineString();
} else if (vertexCount == 3) {
if (isClosed()) {
final GeometryFactory geometryFactory = getGeometryFactory();
return geometryFactory.lineString(this.axisCount, 2, this.coordinates);
}
}
return newPolygon();
}
@Override
public LinearRing newLinearRing() {
final int coordinateCount = this.vertexCount * this.axisCount;
final double[] coordinates = new double[coordinateCount];
System.arraycopy(this.coordinates, 0, coordinates, 0, coordinateCount);
return new LinearRingDoubleGf(this.geometryFactory, this.axisCount, this.vertexCount,
coordinates);
}
public Point newPoint() {
return this.geometryFactory.point(this.coordinates);
}
public Polygon newPolygon() {
final LinearRing ring = newLinearRing();
return this.geometryFactory.polygon(ring);
}
public void setCoordinate(final int index, final int axisIndex, final double coordinate) {
if (index < 0) {
throw new IllegalArgumentException("index=" + index + " must be >=0");
} else {
if (index >= this.vertexCount) {
ensureCapacity(index + 1);
this.vertexCount = index + 1;
}
final int axisCount = getAxisCount();
if (axisIndex < axisCount) {
this.coordinates[index * axisCount + axisIndex] = this.geometryFactory
.makePrecise(axisIndex, coordinate);
}
}
}
public void setVertex(final int index, final double... coordinates) {
if (index >= 0 && index < this.vertexCount) {
final int axisCount = getAxisCount();
int coordinateAxisCount = coordinates.length;
if (coordinateAxisCount > axisCount) {
coordinateAxisCount = axisCount;
}
int offset = index * axisCount;
this.coordinates[offset++] = this.geometryFactory.makeXyPrecise(coordinates[0]);
this.coordinates[offset++] = this.geometryFactory.makeXyPrecise(coordinates[1]);
for (int axisIndex = 2; axisIndex < coordinateAxisCount; axisIndex++) {
this.coordinates[offset++] = this.geometryFactory.makePrecise(axisIndex,
coordinates[axisIndex]);
}
}
}
public boolean setVertex(final int index, final double x, final double y) {
if (index >= 0 && index < this.vertexCount) {
final int axisCount = getAxisCount();
final int offset = index * axisCount;
this.coordinates[offset] = this.geometryFactory.makeXyPrecise(x);
this.coordinates[offset + 1] = this.geometryFactory.makeXyPrecise(y);
return true;
} else {
return false;
}
}
public boolean setVertex(final int index, final Point point) {
if (index >= 0 && index < this.vertexCount && point != null && !point.isEmpty()) {
final int axisCount = getAxisCount();
int pointAxisCount = point.getAxisCount();
if (pointAxisCount > axisCount) {
pointAxisCount = axisCount;
}
int offset = index * axisCount;
final Point convertPoint2d = point.convertPoint2d(this.geometryFactory);
this.coordinates[offset++] = this.geometryFactory.makeXyPrecise(convertPoint2d.getX());
this.coordinates[offset++] = this.geometryFactory.makeXyPrecise(convertPoint2d.getY());
for (int axisIndex = 2; axisIndex < pointAxisCount; axisIndex++) {
this.coordinates[offset++] = this.geometryFactory.makePrecise(axisIndex,
point.getCoordinate(axisIndex));
}
return true;
} else {
return false;
}
}
}