
org.opentripplanner.util.PolylineEncoder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of otp Show documentation
Show all versions of otp Show documentation
The OpenTripPlanner multimodal journey planning system
/* This program is free software: you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see . */
package org.opentripplanner.util;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.List;
import org.opentripplanner.util.model.EncodedPolylineBean;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.MultiLineString;
public class PolylineEncoder {
public static EncodedPolylineBean createEncodings(double[] lat, double[] lon) {
return createEncodings(new PointAdapterList(lat, lon));
}
public static EncodedPolylineBean createEncodings(double[] lat, double[] lon, int level) {
return createEncodings(new PointAdapterList(lat, lon), level);
}
public static EncodedPolylineBean createEncodings(double[] lat, double[] lon, int offset,
int length, int level) {
return createEncodings(new PointAdapterList(lat, lon, offset, length), level);
}
public static EncodedPolylineBean createEncodings(Iterable points) {
return createEncodings(points, -1);
}
public static EncodedPolylineBean createEncodings(Geometry geometry) {
if (geometry instanceof LineString) {
LineString string = (LineString) geometry;
Coordinate[] coordinates = string.getCoordinates();
return createEncodings(new CoordinateList(coordinates));
} else if (geometry instanceof MultiLineString) {
MultiLineString mls = (MultiLineString) geometry;
return createEncodings(new CoordinateList(mls.getCoordinates()));
} else {
throw new IllegalArgumentException(geometry.toString());
}
}
/**
* If level < 0, then {@link EncodedPolylineBean#getLevels()} will be null.
*
* @param points
* @param level
* @return
*/
public static EncodedPolylineBean createEncodings(Iterable points, int level) {
StringBuilder encodedPoints = new StringBuilder();
StringBuilder encodedLevels = new StringBuilder();
int plat = 0;
int plng = 0;
int count = 0;
for (Coordinate point : points) {
int late5 = floor1e5(point.y);
int lnge5 = floor1e5(point.x);
int dlat = late5 - plat;
int dlng = lnge5 - plng;
plat = late5;
plng = lnge5;
encodedPoints.append(encodeSignedNumber(dlat)).append(encodeSignedNumber(dlng));
if (level >= 0)
encodedLevels.append(encodeNumber(level));
count++;
}
String pointsString = encodedPoints.toString();
String levelsString = level >= 0 ? encodedLevels.toString() : null;
return new EncodedPolylineBean(pointsString, levelsString, count);
}
public static List decode(EncodedPolylineBean polyline) {
String pointString = polyline.getPoints();
double lat = 0;
double lon = 0;
int strIndex = 0;
List points = new ArrayList();
while (strIndex < pointString.length()) {
int[] rLat = decodeSignedNumberWithIndex(pointString, strIndex);
lat = lat + rLat[0] * 1e-5;
strIndex = rLat[1];
int[] rLon = decodeSignedNumberWithIndex(pointString, strIndex);
lon = lon + rLon[0] * 1e-5;
strIndex = rLon[1];
points.add(new Coordinate(lon, lat));
}
return points;
}
/*****************************************************************************
* Private Methods
****************************************************************************/
private static final int floor1e5(double coordinate) {
return (int) Math.floor(coordinate * 1e5);
}
public static String encodeSignedNumber(int num) {
int sgn_num = num << 1;
if (num < 0) {
sgn_num = ~(sgn_num);
}
return (encodeNumber(sgn_num));
}
public static int decodeSignedNumber(String value) {
int[] r = decodeSignedNumberWithIndex(value, 0);
return r[0];
}
public static int[] decodeSignedNumberWithIndex(String value, int index) {
int[] r = decodeNumberWithIndex(value, index);
int sgn_num = r[0];
if ((sgn_num & 0x01) > 0) {
sgn_num = ~(sgn_num);
}
r[0] = sgn_num >> 1;
return r;
}
public static String encodeNumber(int num) {
StringBuffer encodeString = new StringBuffer();
while (num >= 0x20) {
int nextValue = (0x20 | (num & 0x1f)) + 63;
encodeString.append((char) (nextValue));
num >>= 5;
}
num += 63;
encodeString.append((char) (num));
return encodeString.toString();
}
public static int decodeNumber(String value) {
int[] r = decodeNumberWithIndex(value, 0);
return r[0];
}
public static int[] decodeNumberWithIndex(String value, int index) {
if (value.length() == 0)
throw new IllegalArgumentException("string is empty");
int num = 0;
int v = 0;
int shift = 0;
do {
v = value.charAt(index++) - 63;
num |= (v & 0x1f) << shift;
shift += 5;
} while (v >= 0x20);
return new int[] { num, index };
}
private static class PointAdapterList extends AbstractList {
private double[] _lat;
private double[] _lon;
private int _offset;
private int _length;
public PointAdapterList(double[] lat, double[] lon) {
this(lat, lon, 0, lat.length);
}
public PointAdapterList(double[] lat, double[] lon, int offset, int length) {
_lat = lat;
_lon = lon;
_offset = offset;
_length = length;
}
@Override
public Coordinate get(int index) {
return new Coordinate(_lon[_offset + index], _lat[_offset + index]);
}
@Override
public int size() {
return _length;
}
}
private static class CoordinateList extends AbstractList {
private Coordinate[] _coordinates;
public CoordinateList(Coordinate[] coordinates) {
_coordinates = coordinates;
}
@Override
public Coordinate get(int index) {
return _coordinates[index];
}
@Override
public int size() {
return _coordinates.length;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy