Added lanes to gpx export. Write route segments to gpx.

This commit is contained in:
max-klaus 2020-03-07 23:34:18 +03:00
parent b192fc7cd9
commit 0fb78ed4f6
15 changed files with 1107 additions and 102 deletions

View file

@ -94,8 +94,13 @@ public class GPXUtilities {
}
}
public interface GPXExtensionsWriter {
public void writeExtensions(XmlSerializer serializer);
}
public static class GPXExtensions {
Map<String, String> extensions = null;
GPXExtensionsWriter extensionsWriter = null;
public Map<String, String> getExtensionsToRead() {
if (extensions == null) {
@ -104,6 +109,14 @@ public class GPXUtilities {
return extensions;
}
public GPXExtensionsWriter getExtensionsWriter() {
return extensionsWriter;
}
public void setExtensionsWriter(GPXExtensionsWriter extensionsWriter) {
this.extensionsWriter = extensionsWriter;
}
public int getColor(int defColor) {
String clrValue = null;
if (extensions != null) {
@ -1600,10 +1613,17 @@ public class GPXUtilities {
}
private static void writeExtensions(XmlSerializer serializer, GPXExtensions p) throws IOException {
if (!p.getExtensionsToRead().isEmpty()) {
Map<String, String> extensionsToRead = p.getExtensionsToRead();
GPXExtensionsWriter extensionsWriter = p.getExtensionsWriter();
if (!extensionsToRead.isEmpty() || extensionsWriter != null) {
serializer.startTag(null, "extensions");
for (Entry<String, String> s : p.getExtensionsToRead().entrySet()) {
writeNotNullText(serializer, s.getKey(), s.getValue());
if (!extensionsToRead.isEmpty()) {
for (Entry<String, String> s : extensionsToRead.entrySet()) {
writeNotNullText(serializer, s.getKey(), s.getValue());
}
}
if (extensionsWriter != null) {
extensionsWriter.writeExtensions(serializer);
}
serializer.endTag(null, "extensions");
}

View file

@ -1,19 +1,8 @@
package net.osmand.binary;
import gnu.trove.iterator.TLongObjectIterator;
import gnu.trove.list.array.TIntArrayList;
import gnu.trove.list.array.TLongArrayList;
import gnu.trove.map.hash.TIntObjectHashMap;
import gnu.trove.map.hash.TLongObjectHashMap;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.google.protobuf.CodedInputStream;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.WireFormat;
import net.osmand.PlatformUtil;
import net.osmand.ResultMatcher;
@ -25,27 +14,51 @@ import net.osmand.binary.OsmandOdb.OsmAndRoutingIndex.RouteEncodingRule;
import net.osmand.binary.OsmandOdb.RestrictionData;
import net.osmand.binary.OsmandOdb.RouteData;
import net.osmand.binary.RouteDataObject.RestrictionInfo;
import net.osmand.router.RouteDataResources;
import net.osmand.util.MapUtils;
import net.osmand.util.OpeningHoursParser;
import org.apache.commons.logging.Log;
import com.google.protobuf.CodedInputStream;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.WireFormat;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import gnu.trove.iterator.TLongObjectIterator;
import gnu.trove.list.array.TIntArrayList;
import gnu.trove.list.array.TLongArrayList;
import gnu.trove.map.hash.TIntObjectHashMap;
import gnu.trove.map.hash.TLongObjectHashMap;
public class BinaryMapRouteReaderAdapter {
protected static final Log LOG = PlatformUtil.getLog(BinaryMapRouteReaderAdapter.class);
private static final int SHIFT_COORDINATES = 4;
private static class RouteTypeCondition {
private static class RouteTypeCondition implements StringExternalizable<RouteDataBundle> {
String condition = "";
OpeningHoursParser.OpeningHours hours = null;
String value;
int ruleid;
@Override
public void writeToBundle(RouteDataBundle bundle) {
bundle.putString("condition", condition);
bundle.putString("value", value);
bundle.putInt("ruleid", ruleid);
}
@Override
public void readFromBundle(RouteDataBundle bundle) {
}
}
public static class RouteTypeRule {
public static class RouteTypeRule implements StringExternalizable<RouteDataBundle> {
private final static int ACCESS = 1;
private final static int ONEWAY = 2;
private final static int HIGHWAY_TYPE = 3;
@ -79,6 +92,22 @@ public class BinaryMapRouteReaderAdapter {
}
}
@Override
public void writeToBundle(RouteDataBundle bundle) {
bundle.putString("t", t);
bundle.putString("v", v);
bundle.putInt("intValue", intValue);
bundle.putFloat("floatValue", floatValue);
bundle.putInt("type", type);
bundle.putList("conditions", "condition", conditions);
bundle.putInt("forward", forward);
}
@Override
public void readFromBundle(RouteDataBundle bundle) {
}
public int isForward() {
return forward;
}
@ -228,7 +257,7 @@ public class BinaryMapRouteReaderAdapter {
}
}
public static class RouteRegion extends BinaryIndexPart {
public static class RouteRegion extends BinaryIndexPart implements StringExternalizable<RouteDataBundle> {
public int regionsRead;
public List<RouteTypeRule> routeEncodingRules = new ArrayList<BinaryMapRouteReaderAdapter.RouteTypeRule>();
public Map<String, Integer> decodingRules = null;
@ -240,11 +269,36 @@ public class BinaryMapRouteReaderAdapter {
int destinationTypeRule = -1;
int destinationRefTypeRule = -1;
private RouteRegion referenceRouteRegion;
@Override
public void writeToBundle(RouteDataBundle bundle) {
bundle.putInt("regionsRead", regionsRead);
bundle.putList("routeEncodingRules", "rule", routeEncodingRules);
bundle.putMap("decodingRules", decodingRules);
bundle.putList("subregions", "subregion", subregions);
bundle.putList("basesubregions", "subregion", basesubregions);
bundle.putInt("nameTypeRule", nameTypeRule);
bundle.putInt("refTypeRule", refTypeRule);
bundle.putInt("destinationTypeRule", destinationTypeRule);
bundle.putInt("destinationRefTypeRule", destinationRefTypeRule);
if (referenceRouteRegion != null) {
List<RouteRegion> regions = bundle.getResources().getRouteRegions();
int regionIndex = regions.indexOf(referenceRouteRegion);
assert regionIndex != -1;
bundle.putInt("referenceRouteRegionIndex", regionIndex);
}
}
@Override
public void readFromBundle(RouteDataBundle bundle) {
}
public String getPartName() {
return "Routing";
}
public int getFieldNumber() {
return OsmandOdb.OsmAndStructure.ROUTINGINDEX_FIELD_NUMBER;
@ -452,7 +506,7 @@ public class BinaryMapRouteReaderAdapter {
}
// Used in C++
public static class RouteSubregion {
public static class RouteSubregion implements StringExternalizable<RouteDataBundle> {
private final static int INT_SIZE = 4;
public final RouteRegion routeReg;
public RouteSubregion(RouteSubregion copy) {
@ -477,7 +531,52 @@ public class BinaryMapRouteReaderAdapter {
public int shiftToData;
public List<RouteSubregion> subregions = null;
public List<RouteDataObject> dataObjects = null;
public void collectResources(RouteDataResources resources) {
List<RouteDataObject> dataObjects = resources.getRouteDataObjects();
List<RouteRegion> regions = resources.getRouteRegions();
if (this.dataObjects != null) {
for (RouteDataObject dataObject : this.dataObjects) {
if (!dataObjects.contains(dataObject)) {
dataObjects.add(dataObject);
}
}
}
if (routeReg != null && !regions.contains(routeReg)) {
regions.add(routeReg);
}
if (subregions != null) {
for (RouteSubregion subregion : subregions) {
RouteRegion routeReg = subregion.routeReg;
if (routeReg != null && !regions.contains(routeReg)) {
regions.add(routeReg);
}
subregion.collectResources(resources);
}
}
}
@Override
public void writeToBundle(RouteDataBundle bundle) {
List<RouteRegion> regions = bundle.getResources().getRouteRegions();
int regionIndex = regions.indexOf(routeReg);
assert regionIndex == -1;
bundle.putInt("routeRegIndex", regionIndex);
bundle.putInt("left", left);
bundle.putInt("right", right);
bundle.putInt("top", top);
bundle.putInt("bottom", bottom);
bundle.putList("subregions", "subregion", subregions);
bundle.putList("dataObjects", "object", dataObjects);
}
@Override
public void readFromBundle(RouteDataBundle bundle) {
}
public int getEstimatedSize(){
int shallow = 7 * INT_SIZE + 4*3;
if (subregions != null) {

View file

@ -0,0 +1,21 @@
package net.osmand.binary;
import net.osmand.router.RouteDataResources;
public class RouteDataBundle extends StringBundle {
private RouteDataResources resources;
public RouteDataBundle(RouteDataResources resources) {
this.resources = resources;
}
@Override
public StringBundle newInstance() {
return new RouteDataBundle(resources);
}
public RouteDataResources getResources() {
return resources;
}
}

View file

@ -1,11 +1,6 @@
package net.osmand.binary;
import gnu.trove.map.hash.TIntObjectHashMap;
import java.text.MessageFormat;
import java.util.Arrays;
import net.osmand.Location;
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion;
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteTypeRule;
@ -13,12 +8,18 @@ import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
import net.osmand.util.TransliterationHelper;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.List;
public class RouteDataObject {
import gnu.trove.map.hash.TIntObjectHashMap;
public class RouteDataObject implements StringExternalizable<RouteDataBundle> {
/*private */static final int RESTRICTION_SHIFT = 3;
/*private */static final int RESTRICTION_MASK = 7;
public static int HEIGHT_UNDEFINED = -80000;
public final RouteRegion region;
// all these arrays supposed to be immutable!
// These fields accessible from C++
@ -36,11 +37,36 @@ public class RouteDataObject {
public int[] nameIds;
// mixed array [0, height, cumulative_distance height, cumulative_distance, height, ...] - length is length(points)*2
public float[] heightDistanceArray = null;
@Override
public void writeToBundle(RouteDataBundle bundle) {
List<RouteRegion> regions = bundle.getResources().getRouteRegions();
int regionIndex = regions.indexOf(region);
assert regionIndex != -1;
bundle.putInt("regionIndex", regionIndex);
bundle.putArray("types", types);
bundle.putArray("pointsX", pointsX);
bundle.putArray("pointsY", pointsY);
bundle.putArray("restrictions", restrictions);
bundle.putArray("pointTypes", pointTypes);
bundle.putArray("pointNames", pointNames);
bundle.putArray("pointNameTypes", pointNameTypes);
bundle.putLong("id", id);
bundle.putMap("names", names);
bundle.putArray("nameIds", nameIds);
bundle.putArray("heightDistanceArray", heightDistanceArray);
}
@Override
public void readFromBundle(RouteDataBundle bundle) {
}
public RouteDataObject(RouteRegion region) {
this.region = region;
}
public RouteDataObject(RouteRegion region, int[] nameIds, String[] nameValues) {
this.region = region;
this.nameIds = nameIds;
@ -65,7 +91,7 @@ public class RouteDataObject {
this.pointNameTypes = copy.pointNameTypes;
this.id = copy.id;
}
public boolean compareRoute(RouteDataObject thatObj) {
if (this.id == thatObj.id
&& Arrays.equals(this.pointsX, thatObj.pointsX)
@ -76,11 +102,11 @@ public class RouteDataObject {
if (thatObj.region == null) {
throw new IllegalStateException("Illegal routing object: " + thatObj.id);
}
boolean equals = true;
equals = equals && Arrays.equals(this.restrictions, thatObj.restrictions);
equals = equals && Arrays.equals(this.restrictionsVia, thatObj.restrictionsVia);
if (equals) {
if (this.types == null || thatObj.types == null) {
equals = this.types == thatObj.types;
@ -161,7 +187,7 @@ public class RouteDataObject {
}
return false;
}
public float[] calculateHeightArray() {
if(heightDistanceArray != null) {
return heightDistanceArray;
@ -172,8 +198,8 @@ public class RouteDataObject {
heightDistanceArray = new float[0];
return heightDistanceArray;
}
heightDistanceArray = new float[2*getPointsLength()];
heightDistanceArray = new float[2*getPointsLength()];
double plon = 0;
double plat = 0;
float prevHeight = startHeight;
@ -214,7 +240,7 @@ public class RouteDataObject {
}
prevHeight = height;
}
} else {
heightDistanceArray[0] = 0;
heightDistanceArray[1] = startHeight;
@ -228,19 +254,19 @@ public class RouteDataObject {
public long getId() {
return id;
}
public String getName(){
if(names != null ) {
return names.get(region.nameTypeRule);
}
return null;
}
public String getName(String lang){
return getName(lang, false);
}
public String getName(String lang, boolean transliterate){
if(names != null ) {
if(Algorithms.isEmpty(lang)) {
@ -263,11 +289,11 @@ public class RouteDataObject {
}
return null;
}
public int[] getNameIds() {
return nameIds;
}
public TIntObjectHashMap<String> getNames() {
return names;
}
@ -393,7 +419,7 @@ public class RouteDataObject {
public int getRestrictionType(int i) {
return (int) (restrictions[i] & RESTRICTION_MASK);
}
public RestrictionInfo getRestrictionInfo(int k) {
RestrictionInfo ri = new RestrictionInfo();
ri.toWay = getRestrictionId(k);
@ -403,26 +429,26 @@ public class RouteDataObject {
}
return ri;
}
public long getRestrictionVia(int i) {
if(restrictionsVia != null && restrictionsVia.length > i) {
return restrictionsVia[i];
}
return 0;
}
public long getRestrictionId(int i) {
return restrictions[i] >> RESTRICTION_SHIFT;
}
public boolean hasPointTypes() {
return pointTypes != null;
}
public boolean hasPointNames() {
return pointNames != null;
}
public void insert(int pos, int x31, int y31) {
int[] opointsX = pointsX;
@ -455,14 +481,14 @@ public class RouteDataObject {
}
}
}
public String[] getPointNames(int ind) {
if (pointNames == null || ind >= pointNames.length) {
return null;
}
return pointNames[ind];
}
public int[] getPointNameTypes(int ind) {
if (pointNameTypes == null || ind >= pointNameTypes.length) {
return null;
@ -476,11 +502,11 @@ public class RouteDataObject {
}
return pointTypes[ind];
}
public int[] getTypes() {
return types;
}
public void processConditionalTags(long conditionalTime) {
int sz = types.length;
for (int i = 0; i < sz; i++) {
@ -582,7 +608,7 @@ public class RouteDataObject {
}
return def;
}
public static float parseLength(String v, float def) {
float f = 0;
// 14'10" 14 - inches, 10 feet
@ -602,10 +628,10 @@ public class RouteDataObject {
}
}
if(pref.contains("km")) {
f *= 1000;
f *= 1000;
}
if(pref.contains("\"") || pref.contains("in")) {
f *= 0.0254;
f *= 0.0254;
} else if (pref.contains("\'") || pref.contains("ft") || pref.contains("feet")) {
// foot to meters
f *= 0.3048;
@ -618,7 +644,7 @@ public class RouteDataObject {
}
return def;
}
public static float parseWeightInTon(String v, float def) {
int i = Algorithms.findFirstNumberEndIndex(v);
if (i > 0) {
@ -631,7 +657,7 @@ public class RouteDataObject {
}
return def;
}
public boolean loop() {
return pointsX[0] == pointsX[pointsX.length - 1] && pointsY[0] == pointsY[pointsY.length - 1];
}
@ -662,7 +688,7 @@ public class RouteDataObject {
}
return false;
}
public boolean tunnel(){
int sz = types.length;
for(int i=0; i<sz; i++) {
@ -754,7 +780,7 @@ public class RouteDataObject {
}
return 0;
}
public String getRoute() {
int sz = types.length;
for (int i = 0; i < sz; i++) {
@ -803,7 +829,7 @@ public class RouteDataObject {
}
return null;
}
public String getValue(int pnt, String tag) {
if (pointTypes != null && pnt < pointTypes.length && pointTypes[pnt] != null) {
for (int i = 0; i < pointTypes[pnt].length; i++) {
@ -823,7 +849,7 @@ public class RouteDataObject {
}
return null;
}
public static String getHighway(int[] types, RouteRegion region) {
String highway = null;
int sz = types.length;
@ -836,7 +862,7 @@ public class RouteDataObject {
}
return highway;
}
public int getLanes() {
int sz = types.length;
for (int i = 0; i < sz; i++) {
@ -848,7 +874,7 @@ public class RouteDataObject {
}
return -1;
}
public double directionRoute(int startPoint, boolean plus) {
// same goes to C++
// Victor : the problem to put more than 5 meters that BinaryRoutePlanner will treat
@ -865,7 +891,7 @@ public class RouteDataObject {
}
return direction;
}
public boolean isRoadDeleted() {
int[] pt = getTypes();
int sz = pt.length;
@ -921,7 +947,7 @@ public class RouteDataObject {
int kx = getPoint31XTile(k + 1);
int ky = getPoint31YTile(k + 1);
d += simplifyDistance(kx, ky, x, y);
}
return d;
}
@ -957,7 +983,7 @@ public class RouteDataObject {
private double simplifyDistance(int x, int y, int px, int py) {
return Math.abs(px - x) * 0.011d + Math.abs(py - y) * 0.01863d;
}
private static void assertTrueLength(String vl, float exp){
float dest = parseLength(vl, 0);
if(exp != dest) {
@ -966,7 +992,7 @@ public class RouteDataObject {
System.out.println("OK " + vl);
}
}
public static void main(String[] args) {
assertTrueLength("10 km", 10000);
assertTrueLength("0.01 km", 10);
@ -987,7 +1013,7 @@ public class RouteDataObject {
assertTrueLength("14 feet", 4.2672f);
assertTrueLength("14 mile", 22530.76f);
assertTrueLength("14 cm", 0.14f);
// float badValue = -1;
// assertTrueLength("none", badValue);
// assertTrueLength("m 4.1", badValue);
@ -1012,18 +1038,18 @@ public class RouteDataObject {
return MessageFormat.format("Road id {0} name {1} ref {2}", (getId() / 64) + "", name == null ? "" : name,
rf == null ? "" : rf);
}
public static class RestrictionInfo {
public int type;
public long toWay;
public long viaWay;
public RestrictionInfo next; // optional to simulate linked list
public int length() {
if(next == null) {
return 1;
}
}
return next.length() + 1;
}
}
@ -1047,5 +1073,5 @@ public class RouteDataObject {
restrictionsVia[k] = viaWay;
}
}

View file

@ -0,0 +1,365 @@
package net.osmand.binary;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import gnu.trove.iterator.TIntObjectIterator;
import gnu.trove.map.hash.TIntObjectHashMap;
public class StringBundle {
private Map<String, Item> map = new LinkedHashMap<>();
public enum ItemType {
STRING,
LIST,
MAP
}
public StringBundle newInstance() {
return new StringBundle();
}
public static abstract class Item<T> {
private String name;
private ItemType type;
private T value;
private Item(String name, ItemType type, T value) {
this.name = name;
this.type = type;
this.value = value;
}
public String getName() {
return name;
}
public ItemType getType() {
return type;
}
public T getValue() {
return value;
}
}
public static class StringItem extends Item<String> {
private StringItem(String name, String value) {
super(name, ItemType.STRING, value);
}
private StringItem(String name, int value) {
super(name, ItemType.STRING, String.valueOf(value));
}
private StringItem(String name, long value) {
super(name, ItemType.STRING, String.valueOf(value));
}
private StringItem(String name, float value) {
super(name, ItemType.STRING, String.valueOf(value));
}
private StringItem(String name, boolean value) {
super(name, ItemType.STRING, String.valueOf(value));
}
public int asInt() throws NumberFormatException {
return Integer.parseInt(getValue());
}
}
public static class StringListItem extends Item<List<Item>> {
private StringListItem(String name, List<Item> list) {
super(name, ItemType.LIST, list);
}
}
public static class StringMapItem extends Item<Map<String, Item>> {
private StringMapItem(String name, Map<String, Item> map) {
super(name, ItemType.MAP, map);
}
}
public static class StringBundleItem extends StringMapItem {
private StringBundleItem(String name, StringBundle bundle) {
super(name, bundle.map);
}
}
public Map<String, Item> getMap() {
return Collections.unmodifiableMap(map);
}
public void putInt(String key, int value) {
map.put(key, new StringItem(key, value));
}
public int getInt(String key) throws IllegalArgumentException {
Item item = map.get(key);
if (item instanceof StringItem) {
return ((StringItem) item).asInt();
} else {
throw new IllegalArgumentException("The item is " + item.getClass().getSimpleName() + " but must be StringItem");
}
}
public void putLong(String key, long value) {
map.put(key, new StringItem(key, value));
}
public void putFloat(String key, float value) {
map.put(key, new StringItem(key, value));
}
public void putBoolean(String key, boolean value) {
map.put(key, new StringItem(key, value));
}
public void putString(String key, String value) {
if (value != null) {
map.put(key, new StringItem(key, value));
}
}
public void putObject(String key, StringExternalizable object) {
if (object != null) {
StringBundle bundle = newInstance();
object.writeToBundle(bundle);
map.put(key, new StringBundleItem(key, bundle));
}
}
public void putList(String key, String itemName, List<? extends StringExternalizable> list) {
if (list != null) {
List<Item> itemList = new ArrayList<>();
for (StringExternalizable ex : list) {
if (ex != null) {
StringBundle bundle = newInstance();
ex.writeToBundle(bundle);
itemList.add(new StringBundleItem(itemName, bundle));
}
}
map.put(key, new StringListItem(key, itemList));
}
}
public void putBundleList(String key, String itemName, List<StringBundle> list) {
if (list != null) {
List<Item> itemList = new ArrayList<>();
for (StringBundle bundle : list) {
itemList.add(new StringBundleItem(itemName, bundle));
}
map.put(key, new StringListItem(key, itemList));
}
}
public void putBundle(String key, StringBundle bundle) {
map.put(key, new StringBundleItem(key, bundle));
}
public void putArray(String key, int[] array) {
if (array != null) {
map.put(key, new StringItem(key, intArrayToString(array)));
}
}
public void putArray(String key, int[][] array) {
if (array != null) {
map.put(key, new StringItem(key, intIntArrayToString(array)));
}
}
public void putArray(String key, long[] array) {
if (array != null) {
map.put(key, new StringItem(key, longArrayToString(array)));
}
}
public void putArray(String key, float[] array) {
if (array != null) {
map.put(key, new StringItem(key, floatArrayToString(array)));
}
}
public void putArray(String key, String[] array) {
if (array != null) {
map.put(key, new StringItem(key, strArrayToString(array)));
}
}
public void putArray(String key, String[][] array) {
if (array != null) {
map.put(key, new StringItem(key, strStrArrayToString(array)));
}
}
public <T> void putMap(String key, TIntObjectHashMap<T> map) {
if (map != null) {
StringBundle bundle = newInstance();
TIntObjectIterator<T> it = map.iterator();
while (it.hasNext()) {
it.advance();
int k = it.key();
T v = it.value();
bundle.putString(String.valueOf(k), String.valueOf(v));
}
this.map.put(key, new StringBundleItem(key, bundle));
}
}
public <K, V> void putMap(String key, Map<K, V> map) {
if (map != null) {
StringBundle bundle = newInstance();
for (Map.Entry<K, V> entry : map.entrySet()) {
bundle.putString(String.valueOf(entry.getKey()), String.valueOf(entry.getValue()));
}
this.map.put(key, new StringBundleItem(key, bundle));
}
}
private String intArrayToString(int[] a) {
if (a == null) {
return null;
}
StringBuilder b = new StringBuilder();
for (int value : a) {
if (b.length() > 0) {
b.append(",");
}
b.append(value);
}
return b.toString();
}
private int[] stringToIntArray(String a) throws NumberFormatException {
if (a == null) {
return null;
}
String[] items = a.split(",");
int[] res = new int[items.length];
for (int i = 0; i < items.length; i++) {
res[i] = Integer.parseInt(items[i]);
}
return res;
}
private String longArrayToString(long[] a) {
if (a == null) {
return null;
}
StringBuilder b = new StringBuilder();
for (long value : a) {
if (b.length() > 0) {
b.append(",");
}
b.append(value);
}
return b.toString();
}
private long[] stringToLongArray(String a) throws NumberFormatException {
if (a == null) {
return null;
}
String[] items = a.split(",");
long[] res = new long[items.length];
for (int i = 0; i < items.length; i++) {
res[i] = Integer.parseInt(items[i]);
}
return res;
}
private String floatArrayToString(float[] a) {
if (a == null) {
return null;
}
StringBuilder b = new StringBuilder();
for (float value : a) {
if (b.length() > 0) {
b.append(",");
}
b.append(value);
}
return b.toString();
}
private float[] stringToFloatArray(String a) throws NumberFormatException {
if (a == null) {
return null;
}
String[] items = a.split(",");
float[] res = new float[items.length];
for (int i = 0; i < items.length; i++) {
res[i] = Float.parseFloat(items[i]);
}
return res;
}
private String intIntArrayToString(int[][] a) {
if (a == null) {
return null;
}
StringBuilder b = new StringBuilder();
for (int[] value : a) {
if (b.length() > 0) {
b.append(";");
}
b.append(intArrayToString(value));
}
return b.toString();
}
private int[][] stringToIntIntArray(String a) throws NumberFormatException {
if (a == null) {
return null;
}
String[] items = a.split(";");
int[][] res = new int[items.length][];
for (int i = 0; i < items.length; i++) {
String[] subItems = a.split(",");
res[i] = new int[subItems.length];
for (int k = 0; k < subItems.length; k++) {
res[i][k] = Integer.parseInt(subItems[k]);
}
}
return res;
}
private String strArrayToString(String[] a) {
if (a == null) {
return null;
}
StringBuilder b = new StringBuilder();
for (String value : a) {
if (b.length() > 0) {
b.append(0x1E);
}
b.append(value);
}
return b.toString();
}
private String strStrArrayToString(String[][] a) {
if (a == null) {
return null;
}
StringBuilder b = new StringBuilder();
for (String[] value : a) {
if (b.length() > 0) {
b.append(0x1F);
}
b.append(strArrayToString(value));
}
return b.toString();
}
}

View file

@ -0,0 +1,33 @@
package net.osmand.binary;
import net.osmand.binary.StringBundle.Item;
import java.io.IOException;
import java.util.Map;
import java.util.Map.Entry;
public abstract class StringBundleWriter {
private StringBundle bundle;
protected String result;
public StringBundleWriter(StringBundle bundle) {
this.bundle = bundle;
}
protected StringBundle getBundle() {
return bundle;
}
public String getResult() {
return result;
}
protected abstract void writeItem(String name, Item item);
public void writeBundle() {
for (Entry<String, Item> entry : bundle.getMap().entrySet()) {
writeItem(entry.getKey(), entry.getValue());
}
}
}

View file

@ -0,0 +1,100 @@
package net.osmand.binary;
import net.osmand.PlatformUtil;
import net.osmand.binary.StringBundle.Item;
import net.osmand.binary.StringBundle.StringItem;
import net.osmand.binary.StringBundle.StringListItem;
import net.osmand.binary.StringBundle.StringMapItem;
import org.apache.commons.logging.Log;
import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Map.Entry;
public class StringBundleXmlWriter extends StringBundleWriter {
public final static Log log = PlatformUtil.getLog(StringBundleXmlWriter.class);
private StringWriter writer;
private XmlSerializer serializer;
public StringBundleXmlWriter(StringBundle bundle) {
super(bundle);
writer = new StringWriter();
serializer = PlatformUtil.newSerializer();
try {
serializer.setOutput(writer);
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startDocument("UTF-8", true);
} catch (IOException e) {
serializer = null;
}
}
public StringBundleXmlWriter(StringBundle bundle, XmlSerializer serializer) {
super(bundle);
this.serializer = serializer;
}
@Override
protected void writeItem(String name, Item item) {
if (serializer != null) {
try {
writeItemImpl(name, item);
} catch (Exception e) {
log.error("Error writing string bundle as xml", e);
}
}
}
@Override
public void writeBundle() {
if (serializer != null) {
super.writeBundle();
try {
serializer.flush();
if (writer != null) {
result = writer.toString();
}
} catch (Exception e) {
log.error("Error writing string bundle as xml", e);
}
}
}
private void writeItemImpl(String name, Item item) throws IOException {
if (serializer != null && item != null) {
switch (item.getType()) {
case STRING: {
StringItem stringItem = (StringItem) item;
serializer.startTag(null, "s");
serializer.attribute(null, "n", name);
serializer.text(stringItem.getValue());
serializer.endTag(null, "s");
break;
}
case LIST: {
StringListItem listItem = (StringListItem) item;
serializer.startTag(null, name);
for (Item i : listItem.getValue()) {
writeItemImpl(i.getName(), i);
}
serializer.endTag(null, name);
break;
}
case MAP: {
StringMapItem mapItem = (StringMapItem) item;
serializer.startTag(null, name);
for (Entry<String, Item> entry : mapItem.getValue().entrySet()) {
writeItemImpl(entry.getKey(), entry.getValue());
}
serializer.endTag(null, name);
break;
}
}
}
}
}

View file

@ -0,0 +1,9 @@
package net.osmand.binary;
public interface StringExternalizable<T extends StringBundle> {
public void writeToBundle(T bundle);
public void readFromBundle(T bundle);
}

View file

@ -0,0 +1,28 @@
package net.osmand.router;
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion;
import net.osmand.binary.RouteDataObject;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
public class RouteDataResources {
private List<RouteSegmentResult> routeSegments = new LinkedList<>();
private List<RouteDataObject> routeDataObjects = new LinkedList<>();
private List<RouteRegion> routeRegions = new LinkedList<>();
public List<RouteSegmentResult> getRouteSegments() {
return routeSegments;
}
public List<RouteDataObject> getRouteDataObjects() {
return routeDataObjects;
}
public List<RouteRegion> getRouteRegions() {
return routeRegions;
}
}

View file

@ -0,0 +1,118 @@
package net.osmand.router;
import net.osmand.GPXUtilities;
import net.osmand.GPXUtilities.GPXExtensionsWriter;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.Track;
import net.osmand.GPXUtilities.TrkSegment;
import net.osmand.GPXUtilities.WptPt;
import net.osmand.Location;
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion;
import net.osmand.binary.RouteDataBundle;
import net.osmand.binary.RouteDataObject;
import net.osmand.binary.StringBundle;
import net.osmand.binary.StringBundleWriter;
import net.osmand.binary.StringBundleXmlWriter;
import net.osmand.util.Algorithms;
import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class RouteExporter {
private static final String OSMAND_ROUTER = "OsmAndRouter";
private File file;
private List<RouteSegmentResult> route;
private List<Location> locations;
public RouteExporter(File file, List<RouteSegmentResult> route, List<Location> locations) {
this.file = file;
this.route = route;
this.locations = locations;
}
public Exception export() {
RouteDataResources resources = new RouteDataResources();
final RouteDataBundle bundle = new RouteDataBundle(resources);
for (RouteSegmentResult sr : route) {
sr.collectResources(resources);
}
List<StringBundle> routeItems = new ArrayList<>();
for (RouteSegmentResult sr : route) {
RouteDataBundle itemBundle = new RouteDataBundle(resources);
sr.writeToBundle(itemBundle);
routeItems.add(itemBundle);
}
bundle.putBundleList("route", "segment", routeItems);
List<StringBundle> segments = new ArrayList<>();
for (RouteSegmentResult segment : resources.getRouteSegments()) {
RouteDataBundle segmentBundle = new RouteDataBundle(resources);
segment.writeToBundle(segmentBundle);
segments.add(segmentBundle);
}
bundle.putBundleList("segments", "segment", segments);
List<StringBundle> dataObjects = new ArrayList<>();
for (RouteDataObject dataObject : resources.getRouteDataObjects()) {
RouteDataBundle objectBundle = new RouteDataBundle(resources);
dataObject.writeToBundle(objectBundle);
dataObjects.add(objectBundle);
}
bundle.putBundleList("objects", "object", dataObjects);
List<StringBundle> regions = new ArrayList<>();
for (RouteRegion routeRegion : resources.getRouteRegions()) {
RouteDataBundle regionBundle = new RouteDataBundle(resources);
routeRegion.writeToBundle(regionBundle);
regions.add(regionBundle);
}
bundle.putBundleList("regions", "region", regions);
GPXFile gpx = new GPXFile("OsmAnd");
gpx.author = OSMAND_ROUTER;
Track track = new Track();
track.name = new SimpleDateFormat("yyyy-MM-dd_HH-mm_EEE", Locale.US).format(new Date());
gpx.tracks.add(track);
TrkSegment trkSegment = new TrkSegment();
track.segments.add(trkSegment);
for (int i = 0; i< locations.size(); i++) {
Location loc = locations.get(i);
WptPt pt = new WptPt();
pt.lat = loc.getLatitude();
pt.lon = loc.getLongitude();
if (loc.hasSpeed()) {
pt.speed = loc.getSpeed();
}
if (loc.hasAltitude()) {
pt.ele = loc.getAltitude();
}
if (loc.hasAccuracy()) {
pt.hdop = loc.getAccuracy();
}
trkSegment.points.add(pt);
}
GPXExtensionsWriter extensionsWriter = new GPXExtensionsWriter() {
@Override
public void writeExtensions(XmlSerializer serializer) {
StringBundleWriter bundleWriter = new StringBundleXmlWriter(bundle, serializer);
bundleWriter.writeBundle();
}
};
gpx.setExtensionsWriter(extensionsWriter);
Exception result = GPXUtilities.writeGpxFile(file, gpx);
return result;
}
}

View file

@ -1,19 +1,23 @@
package net.osmand.router;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteTypeRule;
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion;
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteSubregion;
import net.osmand.binary.RouteDataBundle;
import net.osmand.binary.RouteDataObject;
import net.osmand.binary.StringExternalizable;
import net.osmand.data.LatLon;
import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
public class RouteSegmentResult {
public class RouteSegmentResult implements StringExternalizable<RouteDataBundle> {
private final RouteDataObject object;
private int startPointIndex;
private int endPointIndex;
@ -34,7 +38,123 @@ public class RouteSegmentResult {
this.endPointIndex = endPointIndex;
updateCapacity();
}
void collectResources(RouteDataResources resources) {
List<RouteSegmentResult> segments = resources.getRouteSegments();
List<RouteDataObject> dataObjects = resources.getRouteDataObjects();
List<RouteRegion> regions = resources.getRouteRegions();
if (!segments.contains(this)) {
segments.add(this);
}
if (attachedRoutes != null) {
for (List<RouteSegmentResult> routes : attachedRoutes) {
if (routes != null) {
for (RouteSegmentResult route : routes) {
if (!segments.contains(route)) {
segments.add(route);
}
}
}
}
}
if (preAttachedRoutes != null) {
for (RouteSegmentResult[] routes : preAttachedRoutes) {
if (routes != null) {
for (RouteSegmentResult route : routes) {
if (!segments.contains(route)) {
segments.add(route);
}
}
}
}
}
if (!dataObjects.contains(object)) {
dataObjects.add(object);
}
RouteRegion region = object.region;
if (!regions.contains(region)) {
regions.add(region);
}
List<RouteSubregion> baseSubregions = region.getBaseSubregions();
if (baseSubregions != null) {
for (RouteSubregion subregion : baseSubregions) {
subregion.collectResources(resources);
}
}
List<RouteSubregion> subregions = region.getSubregions();
if (subregions != null) {
for (RouteSubregion subregion : subregions) {
subregion.collectResources(resources);
}
}
}
@Override
public void writeToBundle(RouteDataBundle bundle) {
List<RouteDataObject> dataObjects = bundle.getResources().getRouteDataObjects();
int dataObjectIndex = dataObjects.indexOf(object);
assert dataObjectIndex != -1;
bundle.putInt("objectIndex", dataObjectIndex);
bundle.putInt("startPointIndex", startPointIndex);
bundle.putInt("endPointIndex", endPointIndex);
List<RouteSegmentResult> segments = bundle.getResources().getRouteSegments();
if (attachedRoutes != null) {
Set<Integer> attachedRoutesIndexes = new HashSet<>();
for (List<RouteSegmentResult> routes : attachedRoutes) {
if (routes != null) {
for (RouteSegmentResult route : routes) {
int segmentIndex = segments.indexOf(route);
assert segmentIndex != -1;
attachedRoutesIndexes.add(segmentIndex);
}
}
}
int[] attachedRoutesIndexesArray = new int[attachedRoutesIndexes.size()];
Iterator<Integer> it = attachedRoutesIndexes.iterator();
int i = 0;
while (it.hasNext()) {
int index = it.next();
attachedRoutesIndexesArray[i++] = index;
}
bundle.putArray("attachedRoutes", attachedRoutesIndexesArray);
}
if (preAttachedRoutes != null) {
Set<Integer> preAttachedRoutesIndexes = new HashSet<>();
for (RouteSegmentResult[] routes : preAttachedRoutes) {
if (routes != null) {
for (RouteSegmentResult route : routes) {
int segmentIndex = segments.indexOf(route);
assert segmentIndex != -1;
preAttachedRoutesIndexes.add(segmentIndex);
}
}
}
int[] preAttachedRoutesIndexesArray = new int[preAttachedRoutesIndexes.size()];
Iterator<Integer> it = preAttachedRoutesIndexes.iterator();
int i = 0;
while (it.hasNext()) {
int index = it.next();
preAttachedRoutesIndexesArray[i++] = index;
}
bundle.putArray("preAttachedRoutes", preAttachedRoutesIndexesArray);
}
bundle.putFloat("segmentTime", segmentTime);
bundle.putFloat("routingTime", routingTime);
bundle.putFloat("speed", speed);
bundle.putFloat("distance", distance);
bundle.putString("description", description);
bundle.putObject("turnType", turnType);
}
@Override
public void readFromBundle(RouteDataBundle bundle) {
}
public float[] getHeightValues() {
float[] pf = object.calculateHeightArray();
if(pf == null || pf.length == 0) {

View file

@ -1,9 +1,13 @@
package net.osmand.router;
import net.osmand.binary.RouteDataBundle;
import net.osmand.binary.StringBundle;
import net.osmand.binary.StringExternalizable;
import gnu.trove.list.array.TIntArrayList;
import gnu.trove.set.hash.TIntHashSet;
public class TurnType {
public class TurnType implements StringExternalizable<RouteDataBundle> {
public static final int C = 1;//"C"; // continue (go straight) //$NON-NLS-1$
public static final int TL = 2; // turn left //$NON-NLS-1$
public static final int TSLL = 3; // turn slightly left //$NON-NLS-1$
@ -18,7 +22,23 @@ public class TurnType {
public static final int OFFR = 12; // Off route //$NON-NLS-1$
public static final int RNDB = 13; // Roundabout
public static final int RNLB = 14; // Roundabout left
@Override
public void writeToBundle(RouteDataBundle bundle) {
bundle.putInt("value", value);
bundle.putInt("exitOut", exitOut);
bundle.putFloat("turnAngle", turnAngle);
bundle.putBoolean("skipToSpeak", skipToSpeak);
bundle.putArray("lanes", lanes);
bundle.putBoolean("possiblyLeftTurn", possiblyLeftTurn);
bundle.putBoolean("possiblyRightTurn", possiblyRightTurn);
}
@Override
public void readFromBundle(RouteDataBundle bundle) {
}
public static TurnType straight() {
return valueOf(C, false);
}

View file

@ -817,4 +817,30 @@ public class Algorithms {
return array;
}
}
public static String arrayToString(int[] a) {
if (a == null || a.length == 0) {
return null;
}
StringBuilder b = new StringBuilder();
for (int value : a) {
if (b.length() > 0) {
b.append(",");
}
b.append(value);
}
return b.toString();
}
public static int[] stringToArray(String array) throws NumberFormatException {
if (array == null || array.length() == 0) {
return null;
}
String[] items = array.split(",");
int[] res = new int[items.length];
for (int i = 0; i < items.length; i++) {
res[i] = Integer.parseInt(items[i]);
}
return res;
}
}

View file

@ -4,6 +4,7 @@ import android.content.Context;
import android.support.annotation.Nullable;
import android.system.Os;
import net.osmand.IndexConstants;
import net.osmand.Location;
import net.osmand.PlatformUtil;
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion;
@ -12,11 +13,13 @@ import net.osmand.binary.RouteDataObject;
import net.osmand.data.LatLon;
import net.osmand.data.LocationPoint;
import net.osmand.data.QuadRect;
import net.osmand.plus.AppInitializer;
import net.osmand.plus.ApplicationMode;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.routing.AlarmInfo.AlarmInfoType;
import net.osmand.router.ExitInfo;
import net.osmand.router.RouteExporter;
import net.osmand.router.RouteSegmentResult;
import net.osmand.router.RoutingContext;
import net.osmand.router.TurnType;
@ -25,6 +28,7 @@ import net.osmand.util.MapUtils;
import org.apache.commons.logging.Log;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -168,8 +172,12 @@ public class RouteCalculationResult {
this.routeRecalcDistance = ctx.getSettings().ROUTE_RECALCULATION_DISTANCE.getModeValue(mode);
this.routeVisibleAngle = routeService == RouteProvider.RouteService.STRAIGHT ?
ctx.getSettings().ROUTE_STRAIGHT_ANGLE.getModeValue(mode) : 0;
RouteExporter exporter = new RouteExporter(new File(ctx.getAppPath(IndexConstants.GPX_INDEX_DIR), "test.gpx"), list, locations);
exporter.export();
}
public ApplicationMode getAppMode() {
return appMode;
}

View file

@ -6,23 +6,20 @@ import android.os.Build;
import android.os.Bundle;
import android.util.Base64;
import net.osmand.Location;
import net.osmand.PlatformUtil;
import net.osmand.binary.BinaryMapIndexReader;
import net.osmand.data.DataTileManager;
import net.osmand.data.LatLon;
import net.osmand.data.LocationPoint;
import net.osmand.data.WptLocationPoint;
import net.osmand.osm.edit.Node;
import net.osmand.osm.edit.Way;
import net.osmand.osm.io.NetworkUtils;
import net.osmand.plus.ApplicationMode;
import net.osmand.GPXUtilities;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.Route;
import net.osmand.GPXUtilities.Track;
import net.osmand.GPXUtilities.TrkSegment;
import net.osmand.GPXUtilities.WptPt;
import net.osmand.Location;
import net.osmand.PlatformUtil;
import net.osmand.binary.BinaryMapIndexReader;
import net.osmand.data.LatLon;
import net.osmand.data.LocationPoint;
import net.osmand.data.WptLocationPoint;
import net.osmand.osm.io.NetworkUtils;
import net.osmand.plus.ApplicationMode;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.OsmandSettings.CommonPreference;
@ -902,6 +899,17 @@ public class RouteProvider {
if (sturn != null) {
turnType.setTurnAngle((float) Double.parseDouble(sturn));
}
String slanes = item.getExtensionsToRead().get("lanes");
if (slanes != null) {
try {
int[] lanes = Algorithms.stringToArray(slanes);
if (lanes != null && lanes.length > 0) {
turnType.setLanes(lanes);
}
} catch (NumberFormatException e) {
// ignore
}
}
RouteDirectionInfo dirInfo = new RouteDirectionInfo(avgSpeed, turnType);
dirInfo.setDescriptionRoute(item.desc); //$NON-NLS-1$
dirInfo.routePointOffset = offset;
@ -1058,6 +1066,10 @@ public class RouteProvider {
extensions.put("turn", dirInfo.getTurnType().toXmlString());
extensions.put("turn-angle", dirInfo.getTurnType().getTurnAngle() + "");
}
int[] lanes = dirInfo.getTurnType().getLanes();
if (lanes != null && lanes.length > 0) {
extensions.put("lanes", Algorithms.arrayToString(lanes));
}
extensions.put("offset", (dirInfo.routePointOffset - currentRoute) + "");
// Issue #2894