import java.awt.Point2D;
/**
* Utility-class for working with the Google Maps polyline encoding.
* The documentation can be found at
* {@link http://www.google.com/apis/maps/documentation/overlays.html#Drawing_Polylines}.
*
* @author David Lee Lambert
*/
public class GMapPolylineUtil {
/**
* This is basically a base64-encoded, sign-magnitude,
* fixed-point representation, also compressed by only
* including significant pentets. The formal description
* of the algorithm (from Google's wesite) is as follows:
*
*
* - Take the initial signed value:
* -179.9832104
* - Take the decimal value and multiply it by 1e5,
* flooring the result:
* -17998321
*
- Convert the decimal value to binary. Note that
* a negative value must be inverted and provide
* padded values toward the byte boundary:
* 00000001 00010010 10100001 11110001
* 11111110 11101101 10100001 00001110
* 11111110 11101101 01011110 00001111
* - Shift the binary value:
* 11111110 11101101 01011110 00001111 0
* - If the original decimal value is negative,
* invert this encoding:
* 00000001 00010010 10100001 11110000 1
* - Break the binary value out into 5-bit chunks
* (starting from the right hand side):
* 00001 00010 01010 10000 11111 00001
* - Place the 5-bit chunks into reverse order:
* 00001 11111 10000 01010 00010 00001
* - OR each value with 0x20 if another bit chunk
* follows:<*>
* 100001 111111 110000 101010 100010 000001
* - Convert each value to decimal:
* 33 63 48 42 34 1
* - Add 63 to each value:
* 96 126 111 105 97 64
*
- Convert each value to its ASCII equivalent:
* `~oia@
*
*/
private static String f(double x) {
int xx = (int)(x * 1e5),j,i;
StringBuffer s = new StringBuffer(6);
xx <<= 1;
if (x<0) xx = ~xx;
for (j=6; j>=0; j--)
if (((xx>>(5*j))&0x1F)!=0)
break;
if (j==-1) j=0;
for (i=0 ; i<=j ; i++) {
char ch = (char)( (((xx>>(5*i))&0x1F)
| (j==i ? 0x0 : 0x20)) + 63 );
s.append(ch);
}
return s.toString();
}
/**
* Encode a path. Only the initial points
* and differential distances to successive ones
* are encoded.
*/
public static encode(Number[] coordSeq) {
if (coordSeq==null || coordSeq.length==0)
return "";
if (coordSeq.length%2 == 1)
throw new IllegalArgumentException("even number of points required");
StringBuffer buf = new StringBuffer(6*coordSeq.length);
buf.append(f(coordSeq[0]));
buf.append(f(coordSeq[1]));
for (int i=2; i