/* Copyright (c) 2014 Boundless and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/edl-v10.html
*
* Contributors:
* Gabriel Roldan (Boundless) - initial implementation
*/
package org.locationtech.geogig.osm.internal;
import static org.openstreetmap.osmosis.core.util.FixedPrecisionCoordinateConvertor.convertToDouble;
import static org.openstreetmap.osmosis.core.util.FixedPrecisionCoordinateConvertor.convertToFixed;
import java.io.Serializable;
import org.openstreetmap.osmosis.core.util.FixedPrecisionCoordinateConvertor;
import com.google.common.base.Preconditions;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.CoordinateSequence;
import com.vividsolutions.jts.geom.Envelope;
/**
* A {@link CoordinateSequence} implementation that packs ordinates in int arrays, following the
* math used by the OSM {@link FixedPrecisionCoordinateConvertor}. For instance, transforming
* {@code double} ordinates (in decimal degrees) to {@code int} values by keeping truncating the
* original ordinate to seven decimal places.
*
*/
public class OSMCoordinateSequence implements CoordinateSequence, Serializable {
private static final long serialVersionUID = 8104884314425638232L;
private int[] coords;
public OSMCoordinateSequence(int[] coords) {
Preconditions.checkArgument(coords.length % 2 == 0);
this.coords = coords;
}
public OSMCoordinateSequence(Coordinate[] coords) {
int[] c = new int[2 * coords.length];
for (int i = 0; i < coords.length; i++) {
c[2 * i] = convertToFixed(coords[i].x);
c[2 * i + 1] = convertToFixed(coords[i].y);
}
this.coords = c;
}
public OSMCoordinateSequence(int size) {
this.coords = new int[2 * size];
}
@Override
public double getOrdinate(int index, int ordinateIndex) {
int truncatedOrdinate = coords[2 * index + ordinateIndex];
double value = convertToDouble(truncatedOrdinate);
return value;
}
@Override
public void setOrdinate(int index, int ordinateIndex, double value) {
setOrdinate(index, ordinateIndex, convertToFixed(value));
}
public void setOrdinate(int index, int ordinateIndex, int fixedPrecisionValue) {
coords[2 * index + ordinateIndex] = fixedPrecisionValue;
}
/**
* @return {@code 2}
*/
@Override
public int getDimension() {
return 2;
}
@Override
public Coordinate getCoordinate(int i) {
return new Coordinate(getOrdinate(i, 0), getOrdinate(i, 1));
}
@Override
public Coordinate getCoordinateCopy(int i) {
return getCoordinate(i);
}
@Override
public void getCoordinate(int index, Coordinate coord) {
coord.x = getOrdinate(index, 0);
coord.y = getOrdinate(index, 1);
}
@Override
public double getX(int index) {
return getOrdinate(index, 0);
}
@Override
public double getY(int index) {
return getOrdinate(index, 1);
}
@Override
public int size() {
return coords.length / 2;
}
@Override
public Coordinate[] toCoordinateArray() {
int size = size();
Coordinate[] arr = new Coordinate[size];
for (int i = 0; i < size; i++) {
arr[i] = getCoordinate(i);
}
return arr;
}
@Override
public Envelope expandEnvelope(Envelope env) {
int size = size();
for (int i = 0; i < size; i++) {
env.expandToInclude(getOrdinate(i, 0), getOrdinate(i, 1));
}
return env;
}
@Override
public OSMCoordinateSequence clone() {
return new OSMCoordinateSequence(coords.clone());
}
/**
* Access to internal state, use carefully
*/
public int[] ordinates() {
return coords;
}
}