Skip to content
Browse files

Encoded Polyline Algorithm Format. Java port of : http://facstaff.unc…

  • Loading branch information...
0 parents commit 76406bab39b0aaffe4c4e843de80fe07004be593 @scoutant committed Sep 2, 2010
30 pom.xml
@@ -0,0 +1,30 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.orange.labs.transport</groupId>
+ <artifactId>gis</artifactId>
+ <packaging>jar</packaging>
+ <version>1.0-SNAPSHOT</version>
+ <name>gis</name>
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.8.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.0.2</version>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
442 src/main/java/it/rambow/master/javautils/PolylineEncoder.java
@@ -0,0 +1,442 @@
+/**
+ * Reimplementation of Mark McClures Javascript PolylineEncoder
+ * All the mathematical logic is more or less copied by McClure
+ *
+ * @author Mark Rambow
+ * @e-mail markrambow[at]gmail[dot]com
+ * @version 0.1
+ *
+ */
+
+package it.rambow.master.javautils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Stack;
+import java.util.StringTokenizer;
+
+public class PolylineEncoder {
+
+ private int numLevels = 18;
+
+ private int zoomFactor = 2;
+
+ private double verySmall = 0.00001;
+
+ private boolean forceEndpoints = true;
+
+ private double[] zoomLevelBreaks;
+
+ private HashMap<String, Double> bounds;
+
+ // constructor
+ public PolylineEncoder(int numLevels, int zoomFactor, double verySmall,
+ boolean forceEndpoints) {
+
+ this.numLevels = numLevels;
+ this.zoomFactor = zoomFactor;
+ this.verySmall = verySmall;
+ this.forceEndpoints = forceEndpoints;
+
+ this.zoomLevelBreaks = new double[numLevels];
+
+ for (int i = 0; i < numLevels; i++) {
+ this.zoomLevelBreaks[i] = verySmall
+ * Math.pow(this.zoomFactor, numLevels - i - 1);
+ }
+ }
+
+ public PolylineEncoder() {
+ this.zoomLevelBreaks = new double[numLevels];
+
+ for (int i = 0; i < numLevels; i++) {
+ this.zoomLevelBreaks[i] = verySmall
+ * Math.pow(this.zoomFactor, numLevels - i - 1);
+ }
+ }
+
+ public static void main(String[] args) {
+
+ // initialize trackpoints
+ // dirty hack just to show how it works :)
+
+ Track trk = new Track();
+
+ trk.addTrackpoint(new Trackpoint(new Double(52.29834), new Double(
+ 8.94328)));
+ trk.addTrackpoint(new Trackpoint(new Double(52.29767), new Double(
+ 8.93614)));
+ trk.addTrackpoint(new Trackpoint(new Double(52.29322), new Double(
+ 8.93301)));
+ trk.addTrackpoint(new Trackpoint(new Double(52.28938), new Double(
+ 8.93036)));
+ trk.addTrackpoint(new Trackpoint(new Double(52.27014), new Double(
+ 8.97475)));
+
+ // encodeSignedNumber(floor1e5(coordinate)));
+ System.out.println(createEncodings(trk, 17, 1));
+
+ }
+
+ /**
+ * Douglas-Peucker algorithm, adapted for encoding
+ *
+ * @return HashMap [EncodedPoints;EncodedLevels]
+ *
+ */
+ public HashMap<String, String> dpEncode(Track track) {
+ int i, maxLoc = 0;
+ Stack<int[]> stack = new Stack<int[]>();
+ double[] dists = new double[track.getTrackpoints().size()];
+ double maxDist, absMaxDist = 0.0, temp = 0.0;
+ int[] current;
+ String encodedPoints, encodedLevels;
+
+ if (track.getTrackpoints().size() > 2) {
+ int[] stackVal = new int[] { 0, (track.getTrackpoints().size() - 1) };
+ stack.push(stackVal);
+
+ while (stack.size() > 0) {
+ current = stack.pop();
+ maxDist = 0;
+
+ for (i = current[0] + 1; i < current[1]; i++) {
+ temp = this.distance(track.getTrackpoints().get(i), track
+ .getTrackpoints().get(current[0]), track
+ .getTrackpoints().get(current[1]));
+ if (temp > maxDist) {
+ maxDist = temp;
+ maxLoc = i;
+ if (maxDist > absMaxDist) {
+ absMaxDist = maxDist;
+ }
+ }
+ }
+ if (maxDist > this.verySmall) {
+ dists[maxLoc] = maxDist;
+ int[] stackValCurMax = { current[0], maxLoc };
+ stack.push(stackValCurMax);
+ int[] stackValMaxCur = { maxLoc, current[1] };
+ stack.push(stackValMaxCur);
+ }
+ }
+ }
+
+ // System.out.println("createEncodings(" + track.getTrackpoints().size()
+ // + "," + dists.length + ")");
+ encodedPoints = createEncodings(track.getTrackpoints(), dists);
+ // System.out.println("encodedPoints \t\t: " + encodedPoints);
+ // encodedPoints.replace("\\","\\\\");
+ encodedPoints = replace(encodedPoints, "\\", "\\\\");
+ // System.out.println("encodedPoints slashy?\t\t: " + encodedPoints);
+
+ encodedLevels = encodeLevels(track.getTrackpoints(), dists, absMaxDist);
+ // System.out.println("encodedLevels: " + encodedLevels);
+
+ HashMap<String, String> hm = new HashMap<String, String>();
+ hm.put("encodedPoints", encodedPoints);
+ hm.put("encodedLevels", encodedLevels);
+ return hm;
+
+ }
+
+ public String replace(String s, String one, String another) {
+ // In a string replace one substring with another
+ if (s.equals(""))
+ return "";
+ String res = "";
+ int i = s.indexOf(one, 0);
+ int lastpos = 0;
+ while (i != -1) {
+ res += s.substring(lastpos, i) + another;
+ lastpos = i + one.length();
+ i = s.indexOf(one, lastpos);
+ }
+ res += s.substring(lastpos); // the rest
+ return res;
+ }
+
+ /**
+ * distance(p0, p1, p2) computes the distance between the point p0 and the
+ * segment [p1,p2]. This could probably be replaced with something that is a
+ * bit more numerically stable.
+ *
+ * @param p0
+ * @param p1
+ * @param p2
+ * @return
+ */
+ public double distance(Trackpoint p0, Trackpoint p1, Trackpoint p2) {
+ double u, out = 0.0;
+
+ if (p1.getLatDouble() == p2.getLatDouble()
+ && p1.getLonDouble() == p2.getLonDouble()) {
+ out = Math.sqrt(Math.pow(p2.getLatDouble() - p0.getLatDouble(), 2)
+ + Math.pow(p2.getLonDouble() - p0.getLonDouble(), 2));
+ } else {
+ u = ((p0.getLatDouble() - p1.getLatDouble())
+ * (p2.getLatDouble() - p1.getLatDouble()) + (p0
+ .getLonDouble() - p1.getLonDouble())
+ * (p2.getLonDouble() - p1.getLonDouble()))
+ / (Math.pow(p2.getLatDouble() - p1.getLatDouble(), 2) + Math
+ .pow(p2.getLonDouble() - p1.getLonDouble(), 2));
+
+ if (u <= 0) {
+ out = Math.sqrt(Math.pow(p0.getLatDouble() - p1.getLatDouble(),
+ 2)
+ + Math.pow(p0.getLonDouble() - p1.getLonDouble(), 2));
+ }
+ if (u >= 1) {
+ out = Math.sqrt(Math.pow(p0.getLatDouble() - p2.getLatDouble(),
+ 2)
+ + Math.pow(p0.getLonDouble() - p2.getLonDouble(), 2));
+ }
+ if (0 < u && u < 1) {
+ out = Math.sqrt(Math.pow(p0.getLatDouble() - p1.getLatDouble()
+ - u * (p2.getLatDouble() - p1.getLatDouble()), 2)
+ + Math.pow(p0.getLonDouble() - p1.getLonDouble() - u
+ * (p2.getLonDouble() - p1.getLonDouble()), 2));
+ }
+ }
+ return out;
+ }
+
+ /**
+ * @param points
+ * set the points that should be encoded all points have to be in
+ * the following form: Latitude, longitude\n
+ */
+ public static Track pointsToTrack(String points) {
+ Track trk = new Track();
+
+ StringTokenizer st = new StringTokenizer(points, "\n");
+ while (st.hasMoreTokens()) {
+ String[] pointStrings = st.nextToken().split(", ");
+ trk.addTrackpoint(new Trackpoint(new Double(pointStrings[0]),
+ new Double(pointStrings[1])));
+ }
+ return trk;
+ }
+
+ /**
+ * @param LineString
+ * set the points that should be encoded all points have to be in
+ * the following form: Longitude,Latitude,Altitude"_"...
+ */
+ public static Track kmlLineStringToTrack(String points) {
+ Track trk = new Track();
+ StringTokenizer st = new StringTokenizer(points, " ");
+
+ while (st.hasMoreTokens()) {
+ String[] pointStrings = st.nextToken().split(",");
+ trk.addTrackpoint(new Trackpoint(new Double(pointStrings[1]),
+ new Double(pointStrings[0]), new Double(pointStrings[2])));
+ }
+ return trk;
+ }
+
+ /**
+ * Goolge cant show Altitude, but its in some GPS/GPX Files Altitude will be
+ * ignored here so far
+ *
+ * @param points
+ * @return
+ */
+ public static Track pointsAndAltitudeToTrack(String points) {
+ System.out.println("pointsAndAltitudeToTrack");
+ Track trk = new Track();
+ StringTokenizer st = new StringTokenizer(points, "\n");
+ while (st.hasMoreTokens()) {
+ String[] pointStrings = st.nextToken().split(",");
+ trk.addTrackpoint(new Trackpoint(new Double(pointStrings[1]),
+ new Double(pointStrings[0])));
+ System.out.println(new Double(pointStrings[1]).toString() + ", "
+ + new Double(pointStrings[0]).toString());
+ }
+ return trk;
+ }
+
+ private static int floor1e5(double coordinate) {
+ return (int) Math.floor(coordinate * 1e5);
+ }
+
+ private static String encodeSignedNumber(int num) {
+ int sgn_num = num << 1;
+ if (num < 0) {
+ sgn_num = ~(sgn_num);
+ }
+ return (encodeNumber(sgn_num));
+ }
+
+ private 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();
+ }
+
+ /**
+ * Now we can use the previous function to march down the list of points and
+ * encode the levels. Like createEncodings, we ignore points whose distance
+ * (in dists) is undefined.
+ */
+ private String encodeLevels(ArrayList<Trackpoint> points, double[] dists,
+ double absMaxDist) {
+ int i;
+ StringBuffer encoded_levels = new StringBuffer();
+
+ if (this.forceEndpoints) {
+ encoded_levels.append(encodeNumber(this.numLevels - 1));
+ } else {
+ encoded_levels.append(encodeNumber(this.numLevels
+ - computeLevel(absMaxDist) - 1));
+ }
+ for (i = 1; i < points.size() - 1; i++) {
+ if (dists[i] != 0) {
+ encoded_levels.append(encodeNumber(this.numLevels
+ - computeLevel(dists[i]) - 1));
+ }
+ }
+ if (this.forceEndpoints) {
+ encoded_levels.append(encodeNumber(this.numLevels - 1));
+ } else {
+ encoded_levels.append(encodeNumber(this.numLevels
+ - computeLevel(absMaxDist) - 1));
+ }
+ // System.out.println("encodedLevels: " + encoded_levels);
+ return encoded_levels.toString();
+ }
+
+ /**
+ * This computes the appropriate zoom level of a point in terms of it's
+ * distance from the relevant segment in the DP algorithm. Could be done in
+ * terms of a logarithm, but this approach makes it a bit easier to ensure
+ * that the level is not too large.
+ */
+ private int computeLevel(double absMaxDist) {
+ int lev = 0;
+ if (absMaxDist > this.verySmall) {
+ lev = 0;
+ while (absMaxDist < this.zoomLevelBreaks[lev]) {
+ lev++;
+ }
+ return lev;
+ }
+ return lev;
+ }
+
+ private String createEncodings(ArrayList<Trackpoint> points, double[] dists) {
+ StringBuffer encodedPoints = new StringBuffer();
+
+ double maxlat = 0, minlat = 0, maxlon = 0, minlon = 0;
+
+ int plat = 0;
+ int plng = 0;
+
+ for (int i = 0; i < points.size(); i++) {
+
+ // determin bounds (max/min lat/lon)
+ if (i == 0) {
+ maxlat = minlat = points.get(i).getLatDouble();
+ maxlon = minlon = points.get(i).getLonDouble();
+ } else {
+ if (points.get(i).getLatDouble() > maxlat) {
+ maxlat = points.get(i).getLatDouble();
+ } else if (points.get(i).getLatDouble() < minlat) {
+ minlat = points.get(i).getLatDouble();
+ } else if (points.get(i).getLonDouble() > maxlon) {
+ maxlon = points.get(i).getLonDouble();
+ } else if (points.get(i).getLonDouble() < minlon) {
+ minlon = points.get(i).getLonDouble();
+ }
+ }
+
+ if (dists[i] != 0 || i == 0 || i == points.size() - 1) {
+ Trackpoint point = points.get(i);
+
+ int late5 = floor1e5(point.getLatDouble());
+ int lnge5 = floor1e5(point.getLonDouble());
+
+ int dlat = late5 - plat;
+ int dlng = lnge5 - plng;
+
+ plat = late5;
+ plng = lnge5;
+
+ encodedPoints.append(encodeSignedNumber(dlat));
+ encodedPoints.append(encodeSignedNumber(dlng));
+
+ }
+ }
+
+ HashMap<String, Double> bounds = new HashMap<String, Double>();
+ bounds.put("maxlat", new Double(maxlat));
+ bounds.put("minlat", new Double(minlat));
+ bounds.put("maxlon", new Double(maxlon));
+ bounds.put("minlon", new Double(minlon));
+
+ this.setBounds(bounds);
+ return encodedPoints.toString();
+ }
+
+ private void setBounds(HashMap<String, Double> bounds) {
+ this.bounds = bounds;
+ }
+
+ public static HashMap createEncodings(Track track, int level, int step) {
+
+ HashMap<String, String> resultMap = new HashMap<String, String>();
+ StringBuffer encodedPoints = new StringBuffer();
+ StringBuffer encodedLevels = new StringBuffer();
+
+ ArrayList trackpointList = (ArrayList) track.getTrackpoints();
+
+ int plat = 0;
+ int plng = 0;
+ int counter = 0;
+
+ int listSize = trackpointList.size();
+
+ Trackpoint trackpoint;
+
+ for (int i = 0; i < listSize; i += step) {
+ counter++;
+ trackpoint = (Trackpoint) trackpointList.get(i);
+
+ int late5 = floor1e5(trackpoint.getLatDouble());
+ int lnge5 = floor1e5(trackpoint.getLonDouble());
+
+ int dlat = late5 - plat;
+ int dlng = lnge5 - plng;
+
+ plat = late5;
+ plng = lnge5;
+
+ encodedPoints.append(encodeSignedNumber(dlat)).append(
+ encodeSignedNumber(dlng));
+ encodedLevels.append(encodeNumber(level));
+
+ }
+
+ System.out.println("listSize: " + listSize + " step: " + step
+ + " counter: " + counter);
+
+ resultMap.put("encodedPoints", encodedPoints.toString());
+ resultMap.put("encodedLevels", encodedLevels.toString());
+
+ return resultMap;
+ }
+
+ public HashMap<String, Double> getBounds() {
+ return bounds;
+ }
+}
31 src/main/java/it/rambow/master/javautils/Track.java
@@ -0,0 +1,31 @@
+/**
+ * Reimplementation of Mark McClures Javascript PolylineEncoder
+ * All the mathematical logic is more or less copied by McClure
+ *
+ * @author Mark Rambow
+ * @e-mail markrambow[at]gmail[dot]com
+ * @version 0.1
+ *
+ */
+
+package it.rambow.master.javautils;
+
+import java.util.ArrayList;
+
+public class Track {
+
+ private ArrayList<Trackpoint> trackpoints = new ArrayList<Trackpoint>();
+
+ public ArrayList<Trackpoint> getTrackpoints() {
+ return this.trackpoints;
+ }
+
+ public void setTrackpoints(ArrayList<Trackpoint> trackpoints) {
+ this.trackpoints = trackpoints;
+ }
+
+ public void addTrackpoint(Trackpoint trkpt) {
+ this.trackpoints.add(trkpt);
+ }
+
+}
52 src/main/java/it/rambow/master/javautils/Trackpoint.java
@@ -0,0 +1,52 @@
+/**
+ * Reimplementation of Mark McClures Javascript PolylineEncoder
+ * All the mathematical logic is more or less copied by McClure
+ *
+ * @author Mark Rambow
+ * @e-mail markrambow[at]gmail[dot]com
+ * @version 0.1
+ *
+ */
+
+package it.rambow.master.javautils;
+
+public class Trackpoint {
+ private double latDouble;
+ private double lonDouble;
+ private double altitude;
+
+ public Trackpoint(double lat, double lon) {
+ this.latDouble = lat;
+ this.lonDouble = lon;
+ }
+ public Trackpoint(double lat, double lon, double altitude) {
+ this.latDouble = lat;
+ this.lonDouble = lon;
+ this.altitude = altitude;
+ }
+
+ public void setLatDouble(double latDouble) {
+ this.latDouble = latDouble;
+ }
+
+ public void setLonDouble(double lonDouble) {
+ this.lonDouble = lonDouble;
+ }
+
+ public double getLatDouble() {
+ return latDouble;
+ }
+
+ public double getLonDouble() {
+ return lonDouble;
+ }
+
+ public double getAltitude() {
+ return altitude;
+ }
+
+ public void setAltitude(double altitude) {
+ this.altitude = altitude;
+ }
+
+}
45 src/main/java/org/scoutant/polyline/Point.java
@@ -0,0 +1,45 @@
+package org.scoutant.polyline;
+
+import java.io.Serializable;
+
+/**
+ * Simple geographical point represented by a couple of doubles.
+ * Google's GeoPoint is a couple of micro-degrees represented by integers.
+ */
+public class Point implements Serializable {
+ private static final long serialVersionUID = 1L;
+ private double lat;
+ private double lng;
+
+ public Point(double lat, double lng) {
+ this.lat=lat;
+ this.lng=lng;
+ }
+
+ public double getLat(){
+ return lat;
+ }
+ public double getLng(){
+ return lng;
+ }
+ @Override
+ public String toString(){
+ return "("+lat+", "+lng+")";
+ }
+
+ /**
+ * We consider that two point are equals if both latitude and longitude are "nearly" the same.
+ * With a precision of 1e-3 degree
+ */
+
+ @Override
+ public boolean equals(Object o){
+ if ( ! (o instanceof Point)) return false;
+ Point that = (Point)o;
+ if (Math.abs( that.getLat() - lat) > 0.001) return false;
+ if (Math.abs( that.getLng() - lng) > 0.001) return false;
+ return true;
+ }
+
+
+}
43 src/main/java/org/scoutant/polyline/PolylineDecoder.java
@@ -0,0 +1,43 @@
+package org.scoutant.polyline;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Port to Java of Mark McClures Javascript PolylineEncoder :
+ * http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/decode.js
+ */
+public class PolylineDecoder {
+
+ public List<Point> decode(String encoded) {
+ List<Point> track = new ArrayList<Point>();
+ int index = 0;
+ int lat = 0, lng = 0;
+
+ while (index < encoded.length()) {
+ int b, shift = 0, result = 0;
+ do {
+ b = encoded.charAt(index++) - 63;
+ result |= (b & 0x1f) << shift;
+ shift += 5;
+ } while (b >= 0x20);
+ int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
+ lat += dlat;
+
+ shift = 0;
+ result = 0;
+ do {
+ b = encoded.charAt(index++) - 63;
+ result |= (b & 0x1f) << shift;
+ shift += 5;
+ } while (b >= 0x20);
+ int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
+ lng += dlng;
+
+ Point p = new Point( (double)lat/1E5, (double)lng/1E5 );
+ track.add(p);
+ }
+ return track;
+ }
+
+}
23 src/main/java/org/scoutant/polyline/PolylineUtils.java
@@ -0,0 +1,23 @@
+package org.scoutant.polyline;
+
+import java.util.List;
+
+public class PolylineUtils {
+
+ public static String toString(List<Point> polyline) {
+ String str = "[ ";
+ for( Point p : polyline) {
+ str += p;
+ }
+ return str + " ]";
+ }
+
+ public static String toMarkers(List<Point> polyline) {
+ String str = "";
+ for( Point p : polyline) {
+ str += "|" + p.getLat()+","+p.getLng();
+ }
+ return str.substring(1, str.length());
+ }
+
+}
120 src/test/java/org/scoutant/polyline/PolylineDecoderTest.java
@@ -0,0 +1,120 @@
+package org.scoutant.polyline;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class PolylineDecoderTest {
+
+ protected PolylineDecoder decoder = new PolylineDecoder();
+
+ List<Point> line = new ArrayList<Point>();
+
+ Point orange = new Point(45.20919, 5.79387);
+
+ @Before public void init(){
+ }
+
+ /**
+ * Address "28 chemin du vieux chene, meylan, france" gives position (45.20919, 5.79387). Once encoded : m||rGurjb@
+ */
+ @Test public void testSinglePoint() {
+ line.add( orange);
+ line = decoder.decode( "m||rGurjb@");
+ assertTrue( line.size() == 1);
+ Point p = line.get(0);
+ System.out.println("p : " + p);
+ assertTrue(p.equals(orange));
+ }
+
+ // Caution with "\\" here to represent \...
+ String polyline = "y||rGuxjb@KdDh@jEZnESRE`@Rd@\\CXjAjF~Kf@nDrAdN@dAQt@kBnCQf@G|@XbBjEsAlACd@FnB`Av@t@nAvBv@hCxA|LhI~gAhCnZbAtKhBhOMh@@XvC~F~i@h|@rKlQ|GtLpB~DhGhSnNlf@_CnQOb@o`@bd@vAvRtBhV?PqAf@";
+ Point station = new Point(45.1908, 5.7156);
+
+ @Test public void testPolyline(){
+ line = decoder.decode( "y||rGuxjb@KdDh@jEZnE");
+ assertTrue( line.size() > 0);
+ Point p = line.get(0);
+ System.out.println("p : " + p);
+ assertTrue(p.equals(orange));
+ System.out.println( PolylineUtils.toString(line));
+
+ }
+
+ @Test public void test46PointPolyline(){
+ line = decoder.decode( polyline);
+ assertTrue( line.size() > 0);
+ Point p = line.get(0);
+ System.out.println("p : " + p);
+ assertTrue(p.equals(orange));
+ System.out.println( PolylineUtils.toString(line));
+ assertTrue( line.size() == 46);
+ Point destination = line.get(line.size()-1);
+ assertTrue( line.size() == 46);
+ assertTrue( destination.equals(station));
+ }
+
+ // 2 av Pierre Marzin, lannion, france --> (48.75378, -3.4611) --> cfqhHh_cT
+ Point lannion = new Point(48.75378, -3.4611);
+ @Test public void testNegativePoints(){
+ line = decoder.decode( "cfqhHh_cT");
+ Point p = line.get(0);
+ System.out.println("p : " + p);
+ assertTrue(p.equals(lannion));
+
+ }
+
+
+ String meylan_lyon = "y||rGuxjb@^vRvHlOzBtSOzB}BvDP`DjEsA~CPze@tR`ECnViGdf@RtPvCdOjHvH~GnIbL~Z`s@rKrQzM`Px`@j]nm@zp@zQhV`GjMdHbUbFfZ`Bd]}@h_@yFvh@uAjFgN~Q}LnKkDdIcBxMMf]kCnHoCbAckEuGuIXgH`BgF|CgFzFqv@vlAsHvF_VzJuHpGiWdk@_NbQmz@vk@_bAve@oh@~\\}LjKo_@|i@qX`l@}H|Lua@vh@iI`HyNhHyo@bVoQbFqa@~HsS|BcLN{Mq@mb@aG{KDoKrAwPtGiUjN{OvLiWrV{RvUmVl`@e\\`q@q^dn@_W|o@sSn[cFdMeStm@uBbNkFdp@cJrj@gHpV{Ol`@uCvKiGhv@sDnToGjReFtJc^bf@qJ~SsLnf@qN`[cLly@mCbLcDjHgLxNu\\fTgm@hn@uQhNeMjHoV~JmWjGsy@jHaNvGyVvU{H`LaLrZsTdd@yEvSuKpv@eKr[gQnZw[n`@kKfVqNxf@s\\xm@yG~G_JfD_IPa]cHoOu@gQwDmGSgPxB}X`@ak@`NmXrAwURcg@kCom@CaXyAeQaCiSmGsP}Isc@}[wKaGeMgEkK{@_]zAgStE}EpC}HlI}J`PwIxXyItf@uW`j@_Kfy@aD`H_OnN_HzJsLnj@{NjY{Otb@uIbNiHrHgLhGwUrFgHdGwCdGyD|\\wOru@}AtW_@jn@wB|Y{CvSeIpWeGnK_IlHmJhEqc@|J{OlJuPtRqJnUiE|QeLvv@kXx~@eEfTgm@|aFmS~hAuMviByJbl@kN|f@uj@trA}`@xiAmIfRks@`sAgOf`@uLvh@uJh`Aoa@rgCqQb_BkGr`@uo@rjCwqAtmEuKbf@oWj`BkMvj@cH~UsJrVai@tfAuShg@cj@n}AsO~_@ibAniBoOd`@{Jna@_F~]e\\zfE_c@fqBgOtPyFfKsM`k@sFb^yKxIoBdDlF~Eid@z~@o[rdAqImGfCwO";
+
+ @Test public void testMultiZoomLevel(){
+ line = decoder.decode( meylan_lyon);
+ assertTrue( line.size() > 0);
+ Point p = line.get(0);
+ System.out.println("p : " + p);
+ assertTrue(p.equals(orange));
+ System.out.println( PolylineUtils.toMarkers(line));
+ System.out.println( "nb of points " + line.size());
+ }
+
+ String meylan_saint_egreve = "y||rGuxjb@KdDh@jEZnESRE`@Rd@\\CXjAjF~Kf@nDrAdN@dAQt@kBnCQf@G|@XbBjEsAlACd@FnB`Av@t@nAvBv@hCxA|LhI~gAhCnZbAtKhBhOMh@@XvC~F~i@h|@rKlQ|GtLpB~DhGhSnNlf@_CnQ[p@ab@|e@kCnCRdCGlBaAv@cE`Ce@fAU`AEjDUnA]l@{AbBeBjAqAl@}Ad@_BRsCGyIgBsCGgBVcBj@{Az@uAhA}BpCsMfReCnFcBrGsBrEaBnBmB|AaCpCSFQKQFY|AoG`NcCfCmOnR}BnFqB|Gu@|AgBrCoNfMgJpH{BxAwCnC}SxPqFdFwXxUyQnVMD{HxKmKxK[j@cCtBqErCmAj@W?iFnAZa@~E_Ds@k@c@q@uAiEm@sC";
+
+ @Test public void testAnotherRoute(){
+ line = decoder.decode( meylan_saint_egreve);
+ assertTrue( line.size() > 0);
+ Point p = line.get(0);
+ System.out.println("p : " + p);
+ assertTrue(p.equals(orange));
+ System.out.println( PolylineUtils.toMarkers(line));
+ System.out.println( "nb of points " + line.size());
+ }
+
+ String meylan_grenoble_gare = "y||rGuxjb@KdDh@jEZnESRE`@Rd@\\CXjAjF~Kf@nDrAdN@dAQt@kBnCQf@G|@XbBjEsAlACd@FnB`Av@t@nAvBv@hCxA|LhI~gAhCnZbAtKhBhOMh@@XvC~F~i@h|@rKlQ|GtLpB~DhGhSnNlf@_CnQOb@o`@bd@vAvRtBhV?PqAf@";
+
+ @Test public void testDirectionInTown(){
+ line = decoder.decode( meylan_grenoble_gare);
+ assertTrue( line.size() > 0);
+ Point p = line.get(0);
+ System.out.println("p : " + p);
+ assertTrue(p.equals(orange));
+ System.out.println( PolylineUtils.toMarkers(line));
+ System.out.println( "nb of points " + line.size());
+ }
+
+ String concorde_trocadero = "isfiH{t}L@aBf@{@eHma@i@uFw@o_@LmAx@aDRqCMyE}@}|ABa@Vw@@_DMm@H[?mCCi@e@MqA{@";
+
+ @Test public void testParis(){
+ line = decoder.decode( concorde_trocadero);
+ assertTrue( line.size() > 0);
+ Point p = line.get(0);
+ System.out.println("p : " + p);
+ System.out.println( PolylineUtils.toMarkers(line));
+ System.out.println( "nb of points " + line.size());
+ }
+
+
+}
130 src/test/java/org/scoutant/polyline/PolylineDecoderTest.java~
@@ -0,0 +1,130 @@
+package org.scoutant.polyline;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class PolylineDecoderTest {
+
+ /*
+ public static String polylineToString(List<Point> polyline) {
+ String str = "[ ";
+ for( Point p : polyline) {
+ str += p;
+ }
+ return str + " ]";
+ }
+ */
+
+ protected PolylineDecoder decoder = new PolylineDecoder();
+
+ List<Point> line = new ArrayList<Point>();
+
+ Point orange = new Point(45.20919, 5.79387);
+
+ @Before public void init(){
+ }
+
+ /**
+ * Address "28 chemin du vieux chene, meylan, france" gives position (45.20919, 5.79387). Once encoded : m||rGurjb@
+ */
+ @Test public void testSinglePoint() {
+ line.add( orange);
+ line = decoder.decode( "m||rGurjb@");
+ assertTrue( line.size() == 1);
+ Point p = line.get(0);
+ System.out.println("p : " + p);
+ assertTrue(p.equals(orange));
+ }
+
+ // Caution with "\\" here to represent \...
+ String polyline = "y||rGuxjb@KdDh@jEZnESRE`@Rd@\\CXjAjF~Kf@nDrAdN@dAQt@kBnCQf@G|@XbBjEsAlACd@FnB`Av@t@nAvBv@hCxA|LhI~gAhCnZbAtKhBhOMh@@XvC~F~i@h|@rKlQ|GtLpB~DhGhSnNlf@_CnQOb@o`@bd@vAvRtBhV?PqAf@";
+ Point station = new Point(45.1908, 5.7156);
+
+ @Test public void testPolyline(){
+ line = decoder.decode( "y||rGuxjb@KdDh@jEZnE");
+ assertTrue( line.size() > 0);
+ Point p = line.get(0);
+ System.out.println("p : " + p);
+ assertTrue(p.equals(orange));
+ System.out.println( PolylineUtils.toString(line));
+
+ }
+
+ @Test public void test46PointPolyline(){
+ line = decoder.decode( polyline);
+ assertTrue( line.size() > 0);
+ Point p = line.get(0);
+ System.out.println("p : " + p);
+ assertTrue(p.equals(orange));
+ System.out.println( PolylineUtils.toString(line));
+ assertTrue( line.size() == 46);
+ Point destination = line.get(line.size()-1);
+ assertTrue( line.size() == 46);
+ assertTrue( destination.equals(station));
+ }
+
+ // 2 av Pierre Marzin, lannion, france --> (48.75378, -3.4611) --> cfqhHh_cT
+ Point lannion = new Point(48.75378, -3.4611);
+ @Test public void testNegativePoints(){
+ line = decoder.decode( "cfqhHh_cT");
+ Point p = line.get(0);
+ System.out.println("p : " + p);
+ assertTrue(p.equals(lannion));
+
+ }
+
+
+ String meylan_lyon = "y||rGuxjb@^vRvHlOzBtSOzB}BvDP`DjEsA~CPze@tR`ECnViGdf@RtPvCdOjHvH~GnIbL~Z`s@rKrQzM`Px`@j]nm@zp@zQhV`GjMdHbUbFfZ`Bd]}@h_@yFvh@uAjFgN~Q}LnKkDdIcBxMMf]kCnHoCbAckEuGuIXgH`BgF|CgFzFqv@vlAsHvF_VzJuHpGiWdk@_NbQmz@vk@_bAve@oh@~\\}LjKo_@|i@qX`l@}H|Lua@vh@iI`HyNhHyo@bVoQbFqa@~HsS|BcLN{Mq@mb@aG{KDoKrAwPtGiUjN{OvLiWrV{RvUmVl`@e\\`q@q^dn@_W|o@sSn[cFdMeStm@uBbNkFdp@cJrj@gHpV{Ol`@uCvKiGhv@sDnToGjReFtJc^bf@qJ~SsLnf@qN`[cLly@mCbLcDjHgLxNu\\fTgm@hn@uQhNeMjHoV~JmWjGsy@jHaNvGyVvU{H`LaLrZsTdd@yEvSuKpv@eKr[gQnZw[n`@kKfVqNxf@s\\xm@yG~G_JfD_IPa]cHoOu@gQwDmGSgPxB}X`@ak@`NmXrAwURcg@kCom@CaXyAeQaCiSmGsP}Isc@}[wKaGeMgEkK{@_]zAgStE}EpC}HlI}J`PwIxXyItf@uW`j@_Kfy@aD`H_OnN_HzJsLnj@{NjY{Otb@uIbNiHrHgLhGwUrFgHdGwCdGyD|\\wOru@}AtW_@jn@wB|Y{CvSeIpWeGnK_IlHmJhEqc@|J{OlJuPtRqJnUiE|QeLvv@kXx~@eEfTgm@|aFmS~hAuMviByJbl@kN|f@uj@trA}`@xiAmIfRks@`sAgOf`@uLvh@uJh`Aoa@rgCqQb_BkGr`@uo@rjCwqAtmEuKbf@oWj`BkMvj@cH~UsJrVai@tfAuShg@cj@n}AsO~_@ibAniBoOd`@{Jna@_F~]e\\zfE_c@fqBgOtPyFfKsM`k@sFb^yKxIoBdDlF~Eid@z~@o[rdAqImGfCwO";
+
+ @Test public void testMultiZoomLevel(){
+ line = decoder.decode( meylan_lyon);
+ assertTrue( line.size() > 0);
+ Point p = line.get(0);
+ System.out.println("p : " + p);
+ assertTrue(p.equals(orange));
+ System.out.println( PolylineUtils.toMarkers(line));
+ System.out.println( "nb of points " + line.size());
+ }
+
+ String meylan_saint_egreve = "y||rGuxjb@KdDh@jEZnESRE`@Rd@\\CXjAjF~Kf@nDrAdN@dAQt@kBnCQf@G|@XbBjEsAlACd@FnB`Av@t@nAvBv@hCxA|LhI~gAhCnZbAtKhBhOMh@@XvC~F~i@h|@rKlQ|GtLpB~DhGhSnNlf@_CnQ[p@ab@|e@kCnCRdCGlBaAv@cE`Ce@fAU`AEjDUnA]l@{AbBeBjAqAl@}Ad@_BRsCGyIgBsCGgBVcBj@{Az@uAhA}BpCsMfReCnFcBrGsBrEaBnBmB|AaCpCSFQKQFY|AoG`NcCfCmOnR}BnFqB|Gu@|AgBrCoNfMgJpH{BxAwCnC}SxPqFdFwXxUyQnVMD{HxKmKxK[j@cCtBqErCmAj@W?iFnAZa@~E_Ds@k@c@q@uAiEm@sC";
+
+ @Test public void testAnotherRoute(){
+ line = decoder.decode( meylan_saint_egreve);
+ assertTrue( line.size() > 0);
+ Point p = line.get(0);
+ System.out.println("p : " + p);
+ assertTrue(p.equals(orange));
+ System.out.println( PolylineUtils.toMarkers(line));
+ System.out.println( "nb of points " + line.size());
+ }
+
+ String meylan_grenoble_gare = "y||rGuxjb@KdDh@jEZnESRE`@Rd@\\CXjAjF~Kf@nDrAdN@dAQt@kBnCQf@G|@XbBjEsAlACd@FnB`Av@t@nAvBv@hCxA|LhI~gAhCnZbAtKhBhOMh@@XvC~F~i@h|@rKlQ|GtLpB~DhGhSnNlf@_CnQOb@o`@bd@vAvRtBhV?PqAf@";
+
+ @Test public void testDirectionInTown(){
+ line = decoder.decode( meylan_grenoble_gare);
+ assertTrue( line.size() > 0);
+ Point p = line.get(0);
+ System.out.println("p : " + p);
+ assertTrue(p.equals(orange));
+ System.out.println( PolylineUtils.toMarkers(line));
+ System.out.println( "nb of points " + line.size());
+ }
+
+ String concorde_trocadero = "isfiH{t}L@aBf@{@eHma@i@uFw@o_@LmAx@aDRqCMyE}@}|ABa@Vw@@_DMm@H[?mCCi@e@MqA{@";
+
+ @Test public void testParis(){
+ line = decoder.decode( concorde_trocadero);
+ assertTrue( line.size() > 0);
+ Point p = line.get(0);
+ System.out.println("p : " + p);
+ System.out.println( PolylineUtils.toMarkers(line));
+ System.out.println( "nb of points " + line.size());
+ }
+
+
+}

0 comments on commit 76406ba

Please sign in to comment.
Something went wrong with that request. Please try again.