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: * *
    *
  1. Take the initial signed value:
    * -179.9832104 *
  2. Take the decimal value and multiply it by 1e5, * flooring the result: * -17998321 *
  3. 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
    *
  4. Shift the binary value:
    * 11111110 11101101 01011110 00001111 0 *
  5. If the original decimal value is negative, * invert this encoding:
    * 00000001 00010010 10100001 11110000 1 *
  6. Break the binary value out into 5-bit chunks * (starting from the right hand side):
    * 00001 00010 01010 10000 11111 00001 *
  7. Place the 5-bit chunks into reverse order:
    * 00001 11111 10000 01010 00010 00001 *
  8. OR each value with 0x20 if another bit chunk * follows:<*> * 100001 111111 110000 101010 100010 000001
    *
  9. Convert each value to decimal:
    * 33 63 48 42 34 1 *
  10. Add 63 to each value: * 96 126 111 105 97 64 *
  11. 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