/*
* Copyright (C) 2010 Paul Watts (paulcwatts@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onebusaway.android.io.elements;
import org.onebusaway.android.util.LocationUtils;
import android.location.Location;
import java.util.ArrayList;
import java.util.List;
public final class ObaShapeElement implements ObaShape {
public static final ObaShapeElement EMPTY_OBJECT = new ObaShapeElement();
public static final ObaShapeElement[] EMPTY_ARRAY = new ObaShapeElement[]{};
private final String points;
private final int length;
private final String levels;
private ObaShapeElement() {
points = "";
length = 0;
levels = "";
}
@Override
public int getLength() {
return length;
}
@Override
public String getRawLevels() {
return levels;
}
@Override
public List<Integer> getLevels() {
return decodeLevels(levels, length);
}
@Override
public List<Location> getPoints() {
return decodeLine(points, length);
}
@Override
public String getRawPoints() {
return points;
}
/**
* Decodes an encoded polyline into a list of points.
* Adapted from http://georgelantz.com/files/polyline_decoder.rb
* For the exact algorithm:
* http://code.google.com/apis/maps/documentation/polylinealgorithm.html
*
* @param encoded The encoded string.
* @param numPoints The number of points. This is purely used as a hint
* to allocate memory; the function will always return the number
* of points that are contained in the encoded string.
* @return A list of points from the encoded string.
*/
public static List<Location> decodeLine(String encoded, int numPoints) {
if (numPoints < 0) {
throw new IllegalArgumentException("numPoints must be >= 0");
}
ArrayList<Location> array = new ArrayList<Location>(numPoints);
final int len = encoded.length();
int i = 0;
int lat = 0, lon = 0;
while (i < len) {
int shift = 0;
int result = 0;
int a, b;
do {
a = encoded.charAt(i);
b = a - 63;
result |= (b & 0x1f) << shift;
shift += 5;
++i;
} while (b >= 0x20);
final int dlat = ((result & 1) == 1 ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
a = encoded.charAt(i);
b = a - 63;
result |= (b & 0x1f) << shift;
shift += 5;
++i;
} while (b >= 0x20);
final int dlon = ((result & 1) == 1 ? ~(result >> 1) : (result >> 1));
lon += dlon;
// The polyline encodes in degrees * 1E5, we need decimal degrees
array.add(LocationUtils.makeLocation(lat / 1E5, lon / 1E5));
}
return array;
}
/**
* Decodes encoded levels according to:
* http://code.google.com/apis/maps/documentation/polylinealgorithm.html
*
* @param encoded The encoded string.
* @param numPoints The number of points. This is purely used as a hint
* to allocate memory; the function will always return the number
* of points that are contained in the encoded string.
* @return A list of levels from the encoded string.
*/
public static List<Integer> decodeLevels(String encoded, int numPoints) {
if (numPoints < 0) {
throw new IllegalArgumentException("numPoints must be >= 0");
}
ArrayList<Integer> array = new ArrayList<Integer>(numPoints);
final int len = encoded.length();
int i = 0;
while (i < len) {
int shift = 0;
int result = 0;
int a, b;
do {
a = encoded.charAt(i);
b = a - 63;
result |= (b & 0x1f) << shift;
shift += 5;
++i;
} while (b >= 0x20);
array.add(result);
}
return array;
}
}