/* (c) 2016 Open Source Geospatial Foundation - all rights reserved * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geogig.geoserver.gwc; import static com.google.common.base.Preconditions.checkArgument; import com.google.common.primitives.Floats; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.CoordinateSequence; import com.vividsolutions.jts.geom.Envelope; /** * A {@link CoordinateSequence} that grows as needed when coordinates are * {@link #add(double, double) added}, and stores all coordinates in a single {@code float[]} * <p> * A subset of this coordinate sequence can be obtained as a view sharing internal state using * {@link #subSequence(int, int)} */ class GrowableCoordinateSequence implements CoordinateSequence { private float[] ordinates; private int size; public GrowableCoordinateSequence() { this(new float[100], 0); } private GrowableCoordinateSequence(float[] ordinates, int size) { this.ordinates = ordinates; this.size = size; } /** * Adds the {@code x,y} coordinate to this coordinate sequence, increasing the internal buffer * as necessary to acommodate for the expanded size if needed. */ public void add(double x, double y) { final int index = this.size; this.size++; ensureCapacity(size); setOrdinate(index, 0, x); setOrdinate(index, 1, y); } /** * @return a "view" of this coordinate sequence limited by {@code fromIndex} and {@code toIndex} */ public CoordinateSequence subSequence(int fromIndex, int toIndex) { return new SubSequence(this, fromIndex, toIndex); } private void ensureCapacity(int size) { ordinates = Floats.ensureCapacity(ordinates, 2 * size, 100); } @Override public int getDimension() { return 2; } @Override public Coordinate getCoordinate(int i) { return new Coordinate(getX(i), getY(i)); } @Override public Coordinate getCoordinateCopy(int i) { return getCoordinate(i); } @Override public void getCoordinate(int index, Coordinate coord) { coord.x = getX(index); coord.y = getY(index); coord.z = 0D; } @Override public double getX(int index) { return getOrdinate(index, 0); } @Override public double getY(int index) { return getOrdinate(index, 1); } @Override public double getOrdinate(int index, int ordinateIndex) { return ordinates[index * getDimension() + ordinateIndex]; } @Override public int size() { return size; } @Override public void setOrdinate(int index, int ordinateIndex, double value) { if (index >= size) { throw new IndexOutOfBoundsException(); } ordinates[index * getDimension() + ordinateIndex] = (float) value; } @Override public Coordinate[] toCoordinateArray() { Coordinate[] coords = new Coordinate[size()]; for (int i = 0; i < coords.length; i++) { coords[i] = getCoordinate(i); } return coords; } @Override public Envelope expandEnvelope(Envelope env) { final int size = size(); final int dimension = getDimension(); for (int i = 0; i < size; i += dimension) { env.expandToInclude(getX(i), getY(i)); } return env; } @Override public GrowableCoordinateSequence clone() { return new GrowableCoordinateSequence(ordinates.clone(), size); } private static class SubSequence implements CoordinateSequence { private CoordinateSequence orig; private int toIndex; private int fromIndex; public SubSequence(CoordinateSequence orig, int fromIndex, int toIndex) { checkArgument(fromIndex > -1); checkArgument(toIndex >= fromIndex); checkArgument(toIndex < orig.size()); this.orig = orig; this.fromIndex = fromIndex; this.toIndex = toIndex; } @Override public int getDimension() { return orig.getDimension(); } @Override public Coordinate getCoordinate(int i) { return orig.getCoordinate(fromIndex + i); } @Override public Coordinate getCoordinateCopy(int i) { return orig.getCoordinateCopy(fromIndex + i); } @Override public void getCoordinate(int index, Coordinate coord) { orig.getCoordinate(fromIndex + index, coord); } @Override public double getX(int index) { return orig.getX(fromIndex + index); } @Override public double getY(int index) { return orig.getY(fromIndex + index); } @Override public double getOrdinate(int index, int ordinateIndex) { return orig.getOrdinate(fromIndex + index, ordinateIndex); } @Override public int size() { return 1 + (toIndex - fromIndex); } @Override public void setOrdinate(int index, int ordinateIndex, double value) { orig.setOrdinate(fromIndex + index, ordinateIndex, value); } @Override public Coordinate[] toCoordinateArray() { final int size = size(); Coordinate[] coords = new Coordinate[size]; for (int i = 0; i < size; i++) { coords[i] = getCoordinate(i); } return coords; } @Override public Envelope expandEnvelope(Envelope env) { final int size = size(); for (int i = 0; i < size; i++) { env.expandToInclude(getOrdinate(i, 0), getOrdinate(i, 1)); } return env; } @Override public Object clone() { return new SubSequence(orig, fromIndex, toIndex); } } }