From 22e9fe318a3fa0c1fa81f0d99dee58329cedbf40 Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Wed, 25 Jul 2018 22:48:43 +0200 Subject: [PATCH] Support via restriction properly #5709 --- .../binary/BinaryMapRouteReaderAdapter.java | 49 +++++++++------ .../net/osmand/binary/RouteDataObject.java | 60 +++++++++++++++++-- .../net/osmand/router/BinaryRoutePlanner.java | 19 +++--- 3 files changed, 99 insertions(+), 29 deletions(-) diff --git a/OsmAnd-java/src/main/java/net/osmand/binary/BinaryMapRouteReaderAdapter.java b/OsmAnd-java/src/main/java/net/osmand/binary/BinaryMapRouteReaderAdapter.java index f4c5323ec0..b047b34629 100644 --- a/OsmAnd-java/src/main/java/net/osmand/binary/BinaryMapRouteReaderAdapter.java +++ b/OsmAnd-java/src/main/java/net/osmand/binary/BinaryMapRouteReaderAdapter.java @@ -24,6 +24,7 @@ import net.osmand.binary.OsmandOdb.OsmAndRoutingIndex.RouteDataBox; 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.util.MapUtils; import net.osmand.util.OpeningHoursParser; @@ -329,6 +330,7 @@ public class BinaryMapRouteReaderAdapter { rdo.pointsY = o.pointsY; rdo.id = o.id; rdo.restrictions = o.restrictions; + rdo.restrictionsVia = o.restrictionsVia; if (o.types != null) { rdo.types = new int[o.types.length]; @@ -649,7 +651,7 @@ public class BinaryMapRouteReaderAdapter { } } private void readRouteTreeData(RouteSubregion routeTree, TLongArrayList idTables, - TLongObjectHashMap restrictions) throws IOException { + TLongObjectHashMap restrictions) throws IOException { routeTree.dataObjects = new ArrayList(); idTables.clear(); restrictions.clear(); @@ -659,17 +661,24 @@ public class BinaryMapRouteReaderAdapter { int tag = WireFormat.getTagFieldNumber(t); switch (tag) { case 0: - TLongObjectIterator it = restrictions.iterator(); + TLongObjectIterator it = restrictions.iterator(); while (it.hasNext()) { it.advance(); int from = (int) it.key(); RouteDataObject fromr = routeTree.dataObjects.get(from); - fromr.restrictions = new long[it.value().size()]; + fromr.restrictions = new long[it.value().length()]; + RestrictionInfo val = it.value(); for (int k = 0; k < fromr.restrictions.length; k++) { - int to = (int) (it.value().get(k) >> RouteDataObject.RESTRICTION_SHIFT); - long valto = (idTables.get(to) << RouteDataObject.RESTRICTION_SHIFT) | ((long) it.value().get(k) & RouteDataObject.RESTRICTION_MASK); - fromr.restrictions[k] = valto; + if(val != null) { + long via = 0; + if(val.viaWay != 0) { + via = idTables.get((int)val.viaWay); + } + fromr.setRestriction(k, idTables.get((int)val.toWay), val.type, via); + } + val = val.next; } +// fromr.restrictionsVia = new } for (RouteDataObject o : routeTree.dataObjects) { if (o != null) { @@ -728,33 +737,37 @@ public class BinaryMapRouteReaderAdapter { case RouteDataBlock.RESTRICTIONS_FIELD_NUMBER : length = codedIS.readRawVarint32(); oldLimit = codedIS.pushLimit(length); + RestrictionInfo ri = new RestrictionInfo(); long from = 0; - long to = 0; - long type = 0; idLoop : while(true){ int ts = codedIS.readTag(); int tags = WireFormat.getTagFieldNumber(ts); switch (tags) { case 0: break idLoop; - case RestrictionData.FROM_FIELD_NUMBER : + case RestrictionData.FROM_FIELD_NUMBER: from = codedIS.readInt32(); break; - case RestrictionData.TO_FIELD_NUMBER : - to = codedIS.readInt32(); + case RestrictionData.TO_FIELD_NUMBER: + ri.toWay = codedIS.readInt32(); break; - case RestrictionData.TYPE_FIELD_NUMBER : - type = codedIS.readInt32(); + case RestrictionData.TYPE_FIELD_NUMBER: + ri.type = codedIS.readInt32(); + break; + case RestrictionData.VIA_FIELD_NUMBER: + ri.viaWay = codedIS.readInt32(); break; default: skipUnknownField(ts); break; } } - if(!restrictions.containsKey(from)) { - restrictions.put(from, new TLongArrayList()); + RestrictionInfo prev = restrictions.get(from); + if(prev != null) { + prev.next = ri; + } else { + restrictions.put(from, ri); } - restrictions.get(from).add((to << RouteDataObject.RESTRICTION_SHIFT) + type); codedIS.popLimit(oldLimit); break; case RouteDataBlock.STRINGTABLE_FIELD_NUMBER : @@ -886,7 +899,7 @@ public class BinaryMapRouteReaderAdapter { public List loadRouteRegionData(RouteSubregion rs) throws IOException { TLongArrayList idMap = new TLongArrayList(); - TLongObjectHashMap restrictionMap = new TLongObjectHashMap(); + TLongObjectHashMap restrictionMap = new TLongObjectHashMap(); if (rs.dataObjects == null) { codedIS.seek(rs.filePointer + rs.shiftToData); int limit = codedIS.readRawVarint32(); @@ -909,7 +922,7 @@ public class BinaryMapRouteReaderAdapter { } }); TLongArrayList idMap = new TLongArrayList(); - TLongObjectHashMap restrictionMap = new TLongObjectHashMap(); + TLongObjectHashMap restrictionMap = new TLongObjectHashMap(); for (RouteSubregion rs : toLoad) { if (rs.dataObjects == null) { codedIS.seek(rs.filePointer + rs.shiftToData); diff --git a/OsmAnd-java/src/main/java/net/osmand/binary/RouteDataObject.java b/OsmAnd-java/src/main/java/net/osmand/binary/RouteDataObject.java index c599e471fe..0e0e402274 100644 --- a/OsmAnd-java/src/main/java/net/osmand/binary/RouteDataObject.java +++ b/OsmAnd-java/src/main/java/net/osmand/binary/RouteDataObject.java @@ -6,11 +6,11 @@ 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; import net.osmand.util.Algorithms; import net.osmand.util.MapUtils; -import net.osmand.Location; import net.sf.junidecode.Junidecode; @@ -26,6 +26,7 @@ public class RouteDataObject { public int[] pointsX; public int[] pointsY; public long[] restrictions; + public long[] restrictionsVia; public int[][] pointTypes; public String[][] pointNames; public int[][] pointNameTypes; @@ -58,6 +59,7 @@ public class RouteDataObject { this.types = copy.types; this.names = copy.names; this.restrictions = copy.restrictions; + this.restrictionsVia = copy.restrictionsVia; this.pointTypes = copy.pointTypes; this.pointNames = copy.pointNames; this.pointNameTypes = copy.pointNameTypes; @@ -77,6 +79,7 @@ public class RouteDataObject { 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) { @@ -395,10 +398,23 @@ public class RouteDataObject { return (int) (restrictions[i] & RESTRICTION_MASK); } - public long getRawRestriction(int i) { - return restrictions[i]; + public RestrictionInfo getRestrictionInfo(int k) { + RestrictionInfo ri = new RestrictionInfo(); + ri.toWay = getRestrictionId(k); + ri.type = getRestrictionType(k); + if(restrictionsVia != null && k < restrictionsVia.length) { + ri.viaWay = restrictionsVia[k]; + } + return null; } - + + 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; } @@ -832,4 +848,40 @@ 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; + } + } + + public void setRestriction(int k, long to, int type, long viaWay) { + long valto = (to << RouteDataObject.RESTRICTION_SHIFT) | ((long) type & RouteDataObject.RESTRICTION_MASK); + restrictions[k] = valto; + if(viaWay != 0) { + setRestrictionVia(k, viaWay); + } + } + + public void setRestrictionVia(int k, long viaWay) { + if(restrictionsVia != null) { + long[] nrestrictionsVia = new long[Math.max(k + 1, restrictions.length)]; + System.arraycopy(restrictions, 0, nrestrictionsVia, 0, restrictions.length); + restrictionsVia = nrestrictionsVia; + } else { + restrictionsVia = new long[k + 1]; + } + restrictionsVia[k] = viaWay; + } + + } diff --git a/OsmAnd-java/src/main/java/net/osmand/router/BinaryRoutePlanner.java b/OsmAnd-java/src/main/java/net/osmand/router/BinaryRoutePlanner.java index 7df1a8cf73..fb154ae378 100644 --- a/OsmAnd-java/src/main/java/net/osmand/router/BinaryRoutePlanner.java +++ b/OsmAnd-java/src/main/java/net/osmand/router/BinaryRoutePlanner.java @@ -623,16 +623,17 @@ public class BinaryRoutePlanner { } ctx.segmentsToVisitPrescripted.clear(); ctx.segmentsToVisitNotForbidden.clear(); - processRestriction(ctx, inputNext, reverseWay, false, road); + processRestriction(ctx, inputNext, reverseWay, 0, road); if (parent != null) { - processRestriction(ctx, inputNext, reverseWay, true, parent.getRoad()); + processRestriction(ctx, inputNext, reverseWay, road.id, parent.getRoad()); } return true; } - protected void processRestriction(RoutingContext ctx, RouteSegment inputNext, boolean reverseWay, boolean via, + protected void processRestriction(RoutingContext ctx, RouteSegment inputNext, boolean reverseWay, long viaId, RouteDataObject road) { + boolean via = viaId != 0; RouteSegment next = inputNext; boolean exclusiveRestriction = false; while (next != null) { @@ -640,8 +641,10 @@ public class BinaryRoutePlanner { if (!reverseWay) { for (int i = 0; i < road.getRestrictionLength(); i++) { if (road.getRestrictionId(i) == next.road.id) { - type = road.getRestrictionType(i); - break; + if(!via || road.getRestrictionVia(i) == viaId) { + type = road.getRestrictionType(i); + break; + } } } } else { @@ -649,8 +652,10 @@ public class BinaryRoutePlanner { int rt = next.road.getRestrictionType(i); long restrictedTo = next.road.getRestrictionId(i); if (restrictedTo == road.id) { - type = rt; - break; + if(!via || next.road.getRestrictionVia(i) == viaId) { + type = rt; + break; + } } // Check if there is restriction only to the other than current road