AbstractHafasClientInterfaceProvider: Parse 'polyG' for the exact path of a trip.

This commit is contained in:
Andreas Schildbach 2019-01-09 17:08:52 +01:00
parent 979a5c95a4
commit 2550c68771
4 changed files with 156 additions and 2 deletions

View file

@ -78,6 +78,7 @@ import de.schildbach.pte.dto.Trip;
import de.schildbach.pte.dto.TripOptions;
import de.schildbach.pte.exception.ParserException;
import de.schildbach.pte.util.ParserUtils;
import de.schildbach.pte.util.PolylineFormat;
import okhttp3.HttpUrl;
@ -552,7 +553,7 @@ public abstract class AbstractHafasClientInterfaceProvider extends AbstractHafas
? "\"jnyFltrL\":[{\"value\":\"" + jnyFltr + "\",\"mode\":\"BIT\",\"type\":\"PROD\"}]," : "") //
+ "\"gisFltrL\":[{\"mode\":\"FB\",\"profile\":{\"type\":\"F\",\"linDistRouting\":false,\"maxdist\":2000},\"type\":\"M\",\"meta\":\""
+ meta + "\"}]," //
+ "\"getPolyline\":false,\"getPasslist\":true,\"getIST\":false,\"getEco\":false,\"extChgTime\":-1}", //
+ "\"getPolyline\":true,\"getPasslist\":true,\"getIST\":false,\"getEco\":false,\"extChgTime\":-1}", //
false);
final HttpUrl url = requestUrl(request);
@ -620,6 +621,7 @@ public abstract class AbstractHafasClientInterfaceProvider extends AbstractHafas
final JSONArray locList = common.getJSONArray("locL");
final List<String> operators = parseOpList(common.getJSONArray("opL"));
final List<Line> lines = parseProdList(common.getJSONArray("prodL"), operators, styles);
final List<String> encodedPolylines = parsePolyList(common.getJSONArray("polyL"));
final JSONArray outConList = res.optJSONArray("outConL");
final List<Trip> trips = new ArrayList<>(outConList.length());
@ -673,6 +675,27 @@ public abstract class AbstractHafasClientInterfaceProvider extends AbstractHafas
intermediateStops = null;
}
final List<Point> path;
final JSONObject polyG = jny.optJSONObject("polyG");
if (polyG != null) {
final int crdSysX = polyG.optInt("crdSysX", -1);
if (crdSysX != -1) {
final String crdSysType = crdSysList.getJSONObject(crdSysX).getString("type");
if (!"WGS84".equals(crdSysType))
throw new RuntimeException("unknown type: " + crdSysType);
}
final JSONArray polyXList = polyG.getJSONArray("polyXL");
path = new LinkedList<>();
final int polyXListLen = polyXList.length();
checkState(polyXListLen <= 1);
for (int i = 0; i < polyXListLen; i++) {
final String encodedPolyline = encodedPolylines.get(polyXList.getInt(i));
path.addAll(PolylineFormat.decode(encodedPolyline));
}
} else {
path = null;
}
final JSONArray remList = jny.optJSONArray("remL");
String message = null;
if (remList != null) {
@ -684,7 +707,7 @@ public abstract class AbstractHafasClientInterfaceProvider extends AbstractHafas
}
}
leg = new Trip.Public(line, destination, departureStop, arrivalStop, intermediateStops, null,
leg = new Trip.Public(line, destination, departureStop, arrivalStop, intermediateStops, path,
message);
} else if ("DEVI".equals(secType)) {
leg = new Trip.Individual(Trip.Individual.Type.TRANSFER, departureStop.location,
@ -1036,6 +1059,18 @@ public abstract class AbstractHafasClientInterfaceProvider extends AbstractHafas
return lines;
}
private List<String> parsePolyList(final JSONArray polyList) throws JSONException {
final int len = polyList.length();
final List<String> polylines = new ArrayList<>(len);
for (int i = 0; i < len; i++) {
final JSONObject poly = polyList.getJSONObject(i);
checkState(poly.getBoolean("delta"));
polylines.add(poly.getString("crdEncYX"));
}
return polylines;
}
protected Line newLine(final String id, final String operator, final Product product, final @Nullable String name,
final @Nullable String shortName, final @Nullable String number, final Style style) {
final String longName;

View file

@ -43,6 +43,10 @@ public final class Point implements Serializable {
return new Point(lat / 1E6, lon / 1E6);
}
public static Point from1E5(final int lat, final int lon) {
return new Point(lat / 1E5, lon / 1E5);
}
public double getLatAsDouble() {
return lat;
}
@ -59,6 +63,14 @@ public final class Point implements Serializable {
return (int) Math.round(lon * 1E6);
}
public int getLatAs1E5() {
return (int) Math.round(lat * 1E5);
}
public int getLonAs1E5() {
return (int) Math.round(lon * 1E5);
}
@Override
public boolean equals(final Object o) {
if (o == this)

View file

@ -0,0 +1,67 @@
/*
* Copyright the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 <https://www.gnu.org/licenses/>.
*/
package de.schildbach.pte.util;
import java.util.ArrayList;
import java.util.List;
import de.schildbach.pte.dto.Point;
/**
* <p>
* Implementation of the
* <a href="https://developers.google.com/maps/documentation/utilities/polylinealgorithm">Encoded Polyline
* Algorithm Format</a>.
* </p>
*
* @author Andreas Schildbach
*/
public final class PolylineFormat {
public static List<Point> decode(final String encodedPolyline) {
final int len = encodedPolyline.length();
final List<Point> path = new ArrayList<>(len / 2);
int lat = 0;
int lon = 0;
int index = 0;
while (index < len) {
int latResult = 1;
int latShift = 0;
int latB;
do {
latB = encodedPolyline.charAt(index++) - 63 - 1;
latResult += latB << latShift;
latShift += 5;
} while (latB >= 0x1f);
lat += (latResult & 1) != 0 ? ~(latResult >> 1) : (latResult >> 1);
int lonResult = 1;
int lonShift = 0;
int lonB;
do {
lonB = encodedPolyline.charAt(index++) - 63 - 1;
lonResult += lonB << lonShift;
lonShift += 5;
} while (lonB >= 0x1f);
lon += (lonResult & 1) != 0 ? ~(lonResult >> 1) : (lonResult >> 1);
path.add(Point.from1E5(lat, lon));
}
return path;
}
}

View file

@ -0,0 +1,40 @@
/*
* Copyright the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 <https://www.gnu.org/licenses/>.
*/
package de.schildbach.pte.util;
import static org.junit.Assert.assertEquals;
import java.util.List;
import org.junit.Test;
import de.schildbach.pte.dto.Point;
/**
* @author Andreas Schildbach
*/
public class PolylineFormatTest {
@Test
public void test() {
final List<Point> polyline = PolylineFormat.decode(
"}qfeHyn|bBnBdA\\R]xBzA|@r@f@u@hCWS{@bCe@t@e@v@h@vCIFu@`@MPDJ@L?NAPIZXf@|@`Br@pAHLZp@~@jBbArBbBjDLTTd@fAzBcFnH[d@Vf@iA`BWb@t@zAb@~@LTNNdCzE~A{BAA??");
assertEquals(44, polyline.size());
assertEquals(Point.fromDouble(48.2078300, 16.3711700), polyline.get(0));
assertEquals(Point.fromDouble(48.2051400, 16.3579600), polyline.get(43));
}
}