diff --git a/DataExtractionOSM/src/net/osmand/binary/BinaryMapRouteReaderAdapter.java b/DataExtractionOSM/src/net/osmand/binary/BinaryMapRouteReaderAdapter.java index 4b3503eaef..fe2e61405a 100644 --- a/DataExtractionOSM/src/net/osmand/binary/BinaryMapRouteReaderAdapter.java +++ b/DataExtractionOSM/src/net/osmand/binary/BinaryMapRouteReaderAdapter.java @@ -25,7 +25,7 @@ import com.google.protobuf.WireFormat; public class BinaryMapRouteReaderAdapter { protected static final Log LOG = LogUtil.getLog(BinaryMapRouteReaderAdapter.class); - private static final int SHIFT_COORDINATES = 5; + private static final int SHIFT_COORDINATES = 4; public static class RouteTypeRule { private final static int ACCESS = 1; @@ -377,10 +377,10 @@ public class BinaryMapRouteReaderAdapter { long r = restrictions.get(k); int from = (int) (r >> (RESTRICTION_SHIFT+RESTRICTION_SHIFT)); int to = (int) ((r >> RESTRICTION_SHIFT) & RESTRICTION_MASK); - int type = (int) (r & RESTRICTION_SHIFT); - RouteDataObject i = routeTree.dataObjects.get(from); - long val = (idTables.get(to) << 3) | ((long)type); - i.restrictions.add(val); + int type = (int) (r & RESTRICTION_MASK); + long valto = (idTables.get(to) << 3) | ((long)type); + RouteDataObject fromr = routeTree.dataObjects.get(from); + fromr.restrictions.add(valto); } for (RouteDataObject o : routeTree.dataObjects) { if (o != null) { diff --git a/DataExtractionOSM/src/net/osmand/data/preparation/BinaryMapIndexWriter.java b/DataExtractionOSM/src/net/osmand/data/preparation/BinaryMapIndexWriter.java index bb9f467274..f21a5ef54e 100644 --- a/DataExtractionOSM/src/net/osmand/data/preparation/BinaryMapIndexWriter.java +++ b/DataExtractionOSM/src/net/osmand/data/preparation/BinaryMapIndexWriter.java @@ -78,6 +78,7 @@ public class BinaryMapIndexWriter { private RandomAccessFile raf; private CodedOutputStream codedOutStream; protected static final int SHIFT_COORDINATES = BinaryMapIndexReader.SHIFT_COORDINATES; + private static final int ROUTE_SHIFT_COORDINATES = 4; private static Log log = LogFactory.getLog(BinaryMapIndexWriter.class); private static class Bounds { @@ -465,15 +466,15 @@ public class BinaryMapIndexWriter { ROUTE_TYPES_SIZE += CodedOutputStream.computeTagSize(RouteData.TYPES_FIELD_NUMBER) + CodedOutputStream.computeRawVarint32Size(mapDataBuf.size()) + mapDataBuf.size(); // coordinates and point types - int pcalcx = pleft >> SHIFT_COORDINATES; - int pcalcy = ptop >> SHIFT_COORDINATES; + int pcalcx = pleft >> ROUTE_SHIFT_COORDINATES; + int pcalcy = ptop >> ROUTE_SHIFT_COORDINATES; mapDataBuf.clear(); typesDataBuf.clear(); for(int k=0; k> SHIFT_COORDINATES) - pcalcx; - int ty = (points[k].y >> SHIFT_COORDINATES) - pcalcy; + int tx = (points[k].x >> ROUTE_SHIFT_COORDINATES) - pcalcx; + int ty = (points[k].y >> ROUTE_SHIFT_COORDINATES) - pcalcy; writeRawVarint32(mapDataBuf, CodedOutputStream.encodeZigZag32(tx)); writeRawVarint32(mapDataBuf, CodedOutputStream.encodeZigZag32(ty)); pcalcx = pcalcx + tx ; diff --git a/DataExtractionOSM/src/net/osmand/data/preparation/IndexAddressCreator.java b/DataExtractionOSM/src/net/osmand/data/preparation/IndexAddressCreator.java index 98d30c7905..1fba67107f 100644 --- a/DataExtractionOSM/src/net/osmand/data/preparation/IndexAddressCreator.java +++ b/DataExtractionOSM/src/net/osmand/data/preparation/IndexAddressCreator.java @@ -284,7 +284,7 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{ Boundary boundary = null; if (e instanceof Relation) { Relation aRelation = (Relation) e; - ctx.loadEntityData(aRelation); + ctx.loadEntityRelation(aRelation); boundary = new Boundary(true); //is computed later boundary.setName(aRelation.getTag(OSMTagKey.NAME)); boundary.setBoundaryId(aRelation.getId()); @@ -334,7 +334,7 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{ // try to find appropriate city/street City c = null; // load with member ways with their nodes and tags ! - ctx.loadEntityData(i); + ctx.loadEntityRelation(i); Collection members = i.getMembers("is_in"); //$NON-NLS-1$ Relation a3 = null; @@ -344,16 +344,16 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{ a6 = i; } Entity in = members.iterator().next(); - ctx.loadEntityData(in); if (in instanceof Relation) { + ctx.loadEntityRelation((Relation) in); // go one level up for house if (house) { a6 = (Relation) in; members = ((Relation) in).getMembers("is_in"); //$NON-NLS-1$ if (!members.isEmpty()) { in = members.iterator().next(); - ctx.loadEntityData(in); if (in instanceof Relation) { + ctx.loadEntityRelation((Relation) in); a3 = (Relation) in; } } @@ -698,7 +698,6 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{ if (e.getTag(OSMTagKey.ADDR_HOUSE_NUMBER) != null && e.getTag(OSMTagKey.ADDR_STREET) != null) { boolean exist = streetDAO.findBuilding(e); if (!exist) { - ctx.loadEntityData(e); LatLon l = e.getLatLon(); Set idsOfStreet = getStreetInCity(e.getIsInNames(), e.getTag(OSMTagKey.ADDR_STREET), null, l); if (!idsOfStreet.isEmpty()) { @@ -738,7 +737,6 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{ // check that street way is not registered already if (!exist) { - ctx.loadEntityData(e); LatLon l = e.getLatLon(); Set idsOfStreet = getStreetInCity(e.getIsInNames(), e.getTag(OSMTagKey.NAME), e.getTag(OSMTagKey.NAME_EN), l); if (!idsOfStreet.isEmpty()) { @@ -748,7 +746,7 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{ } if (e instanceof Relation) { if (e.getTag(OSMTagKey.POSTAL_CODE) != null) { - ctx.loadEntityData(e); + ctx.loadEntityRelation((Relation) e); postalCodeRelations.add((Relation) e); } } diff --git a/DataExtractionOSM/src/net/osmand/data/preparation/IndexCreator.java b/DataExtractionOSM/src/net/osmand/data/preparation/IndexCreator.java index 8cd590f5db..24470c404c 100644 --- a/DataExtractionOSM/src/net/osmand/data/preparation/IndexCreator.java +++ b/DataExtractionOSM/src/net/osmand/data/preparation/IndexCreator.java @@ -386,7 +386,6 @@ public class IndexCreator { accessor.iterateOverEntities(progress, EntityType.NODE, new OsmDbVisitor() { @Override public void iterateEntity(Entity e, OsmDbAccessorContext ctx) throws SQLException { - ctx.loadEntityData(e); processor.processEntity(e); } }); @@ -395,7 +394,6 @@ public class IndexCreator { accessor.iterateOverEntities(progress, EntityType.WAY, new OsmDbVisitor() { @Override public void iterateEntity(Entity e, OsmDbAccessorContext ctx) throws SQLException { - ctx.loadEntityData(e); processor.processEntity(e); } }); @@ -748,7 +746,7 @@ public class IndexCreator { MapRenderingTypes rt = MapRenderingTypes.getDefault(); MapZooms zooms = MapZooms.getDefault(); // MapZooms.parseZooms("15-"); creator.setNodesDBFile(new File("/home/victor/projects/OsmAnd/data/osm-gen/nodes.tmp.odb")); - creator.generateIndexes(new File("/home/victor/projects/OsmAnd/data/osm-maps/RU-SPE.osm.pbf"), + creator.generateIndexes(new File("/home/victor/projects/OsmAnd/data/osm-maps/RU-SPE.osm.bz2"), new ConsoleProgressImplementation(1), null, zooms, rt, log); diff --git a/DataExtractionOSM/src/net/osmand/data/preparation/IndexPoiCreator.java b/DataExtractionOSM/src/net/osmand/data/preparation/IndexPoiCreator.java index f428bfeff7..73e7e37e1f 100644 --- a/DataExtractionOSM/src/net/osmand/data/preparation/IndexPoiCreator.java +++ b/DataExtractionOSM/src/net/osmand/data/preparation/IndexPoiCreator.java @@ -63,8 +63,6 @@ public class IndexPoiCreator extends AbstractIndexPartCreator { tempAmenityList.clear(); tempAmenityList = Amenity.parseAmenities(renderingTypes, e, tempAmenityList); if (!tempAmenityList.isEmpty() && poiPreparedStatement != null) { - // load data for way (location etc...) - ctx.loadEntityData(e); for (Amenity a : tempAmenityList) { // do not add that check because it is too much printing for batch creation // by statistic < 1% creates maps manually diff --git a/DataExtractionOSM/src/net/osmand/data/preparation/IndexRouteCreator.java b/DataExtractionOSM/src/net/osmand/data/preparation/IndexRouteCreator.java index a6ee7778ae..8aaa2f5fb5 100644 --- a/DataExtractionOSM/src/net/osmand/data/preparation/IndexRouteCreator.java +++ b/DataExtractionOSM/src/net/osmand/data/preparation/IndexRouteCreator.java @@ -79,9 +79,11 @@ public class IndexRouteCreator extends AbstractIndexPartCreator { public void iterateMainEntity(Entity es, OsmDbAccessorContext ctx) throws SQLException { if (es instanceof Way) { Way e = (Way) es; - ctx.loadEntityData(e); - boolean encoded = routeTypes.encodeEntity(e, outTypes, pointTypes, names); + boolean encoded = routeTypes.encodeEntity(e, outTypes, names); if (encoded) { + // Load point with tags! + ctx.loadEntityWay(e); + routeTypes.encodePointTypes(e, pointTypes); boolean init = false; int minX = Integer.MAX_VALUE; int maxX = 0; @@ -268,7 +270,7 @@ public class IndexRouteCreator extends AbstractIndexPartCreator { type = MapRenderingTypes.RESTRICTION_ONLY_STRAIGHT_ON; } if (type != -1) { - ctx.loadEntityData(e); + ctx.loadEntityRelation((Relation) e); Collection fromL = ((Relation) e).getMemberIds("from"); //$NON-NLS-1$ Collection toL = ((Relation) e).getMemberIds("to"); //$NON-NLS-1$ if (!fromL.isEmpty() && !toL.isEmpty()) { diff --git a/DataExtractionOSM/src/net/osmand/data/preparation/IndexTransportCreator.java b/DataExtractionOSM/src/net/osmand/data/preparation/IndexTransportCreator.java index ec2945b30f..3ef3549c46 100644 --- a/DataExtractionOSM/src/net/osmand/data/preparation/IndexTransportCreator.java +++ b/DataExtractionOSM/src/net/osmand/data/preparation/IndexTransportCreator.java @@ -129,7 +129,7 @@ public class IndexTransportCreator extends AbstractIndexPartCreator { public void visitEntityMainStep(Entity e, OsmDbAccessorContext ctx) throws SQLException { if (e instanceof Relation && e.getTag(OSMTagKey.ROUTE) != null) { - ctx.loadEntityData(e); + ctx.loadEntityRelation((Relation) e); TransportRoute route = indexTransportRoute((Relation) e); if (route != null) { insertTransportIntoIndex(route); diff --git a/DataExtractionOSM/src/net/osmand/data/preparation/IndexVectorMapCreator.java b/DataExtractionOSM/src/net/osmand/data/preparation/IndexVectorMapCreator.java index fbf1a05ad3..ac5aa03a13 100644 --- a/DataExtractionOSM/src/net/osmand/data/preparation/IndexVectorMapCreator.java +++ b/DataExtractionOSM/src/net/osmand/data/preparation/IndexVectorMapCreator.java @@ -88,7 +88,7 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator { private void indexMultiPolygon(Entity e, OsmDbAccessorContext ctx) throws SQLException { if (e instanceof Relation && "multipolygon".equals(e.getTag(OSMTagKey.TYPE))) { //$NON-NLS-1$ - ctx.loadEntityData(e); + ctx.loadEntityRelation((Relation) e); Map entities = ((Relation) e).getMemberEntities(); boolean outerFound = false; @@ -510,7 +510,6 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator { public void iterateMainEntity(Entity e, OsmDbAccessorContext ctx) throws SQLException { if (e instanceof Way || e instanceof Node) { // manipulate what kind of way to load - ctx.loadEntityData(e); for (int level = 0; level < mapZooms.size(); level++) { boolean area = renderingTypes.encodeEntityWithType(e, mapZooms.getLevel(level).getMaxZoom(), typeUse, addtypeUse, namesUse, tempNameUse); diff --git a/DataExtractionOSM/src/net/osmand/data/preparation/OsmDbAccessor.java b/DataExtractionOSM/src/net/osmand/data/preparation/OsmDbAccessor.java index 5ab80f802e..7dd4bbb72d 100644 --- a/DataExtractionOSM/src/net/osmand/data/preparation/OsmDbAccessor.java +++ b/DataExtractionOSM/src/net/osmand/data/preparation/OsmDbAccessor.java @@ -112,14 +112,19 @@ public class OsmDbAccessor implements OsmDbAccessorContext { } @Override + public void loadEntityRelation(Relation e) throws SQLException { + loadEntityData(e); + } + + @Override + public void loadEntityWay(Way e) throws SQLException { + loadEntityData(e); + } + public void loadEntityData(Entity e) throws SQLException { if (e.isDataLoaded()) { //data was already loaded, nothing to do return; } - if (e instanceof Node || (e instanceof Way && !((Way) e).getNodes().isEmpty())) { - // do not load tags for nodes inside way - return; - } if(dialect == DBDialect.NOSQL){ loadEntityDataNoSQL(e); e.entityDataLoaded(); diff --git a/DataExtractionOSM/src/net/osmand/data/preparation/OsmDbAccessorContext.java b/DataExtractionOSM/src/net/osmand/data/preparation/OsmDbAccessorContext.java index f956412b83..b8789d5644 100644 --- a/DataExtractionOSM/src/net/osmand/data/preparation/OsmDbAccessorContext.java +++ b/DataExtractionOSM/src/net/osmand/data/preparation/OsmDbAccessorContext.java @@ -2,9 +2,19 @@ package net.osmand.data.preparation; import java.sql.SQLException; -import net.osmand.osm.Entity; +import net.osmand.osm.Relation; +import net.osmand.osm.Way; public interface OsmDbAccessorContext { - public void loadEntityData(Entity e) throws SQLException; + /** + * Load way with points (with tags) and tags + */ + public void loadEntityWay(Way e) throws SQLException; + + /** + * Load one level relation members : + * ways - loaded with tags and points, nodes with tags, relations with members and tags + */ + public void loadEntityRelation(Relation e) throws SQLException; } \ No newline at end of file diff --git a/DataExtractionOSM/src/net/osmand/osm/MapRoutingTypes.java b/DataExtractionOSM/src/net/osmand/osm/MapRoutingTypes.java index 52915a7a1c..9b5ed91a2e 100644 --- a/DataExtractionOSM/src/net/osmand/osm/MapRoutingTypes.java +++ b/DataExtractionOSM/src/net/osmand/osm/MapRoutingTypes.java @@ -65,10 +65,7 @@ public class MapRoutingTypes { } - public boolean encodeEntity(Entity et, TIntArrayList outTypes, TLongObjectHashMap pointTypes, Map names){ - if (!(et instanceof Way)) { - return false; - } + public boolean encodeEntity(Way et, TIntArrayList outTypes, Map names){ Way e = (Way) et; boolean init = false; for(String tg : e.getTagKeySet()) { @@ -81,7 +78,6 @@ public class MapRoutingTypes { return false; } outTypes.clear(); - pointTypes.clear(); for(Entry es : e.getTags().entrySet()) { String tag = es.getKey(); String value = es.getValue(); @@ -89,21 +85,27 @@ public class MapRoutingTypes { outTypes.add(registerRule(tag, value).id); } } - for(Node nd : e.getNodes() ) { - for(Entry es : nd.getTags().entrySet()) { - String tag = es.getKey(); - String value = es.getValue(); - if(TAGS_TO_ACCEPT.contains(tag) || TAGS_TO_SAVE.contains(tag) || tag.startsWith("access")) { - if(!pointTypes.containsKey(nd.getId())) { - pointTypes.put(nd.getId(), new TIntArrayList()); - } - pointTypes.get(nd.getId()).add(registerRule(tag, value).id); - } - } - } return true; } + public void encodePointTypes(Way e, TLongObjectHashMap pointTypes){ + pointTypes.clear(); + for(Node nd : e.getNodes() ) { + if (nd != null) { + for (Entry es : nd.getTags().entrySet()) { + String tag = es.getKey(); + String value = es.getValue(); + if (TAGS_TO_ACCEPT.contains(tag) || TAGS_TO_SAVE.contains(tag) || tag.startsWith("access")) { + if (!pointTypes.containsKey(nd.getId())) { + pointTypes.put(nd.getId(), new TIntArrayList()); + } + pointTypes.get(nd.getId()).add(registerRule(tag, value).id); + } + } + } + } + } + public MapRouteType getTypeByInternalId(int id) { return listTypes.get(id - 1); } diff --git a/DataExtractionOSM/src/net/osmand/router/BinaryRoutePlanner.java b/DataExtractionOSM/src/net/osmand/router/BinaryRoutePlanner.java index af6ffde052..0acfa29139 100644 --- a/DataExtractionOSM/src/net/osmand/router/BinaryRoutePlanner.java +++ b/DataExtractionOSM/src/net/osmand/router/BinaryRoutePlanner.java @@ -1,13 +1,13 @@ package net.osmand.router; import gnu.trove.map.hash.TLongObjectHashMap; -import gnu.trove.procedure.TObjectProcedure; import java.io.IOException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -125,9 +125,8 @@ public class BinaryRoutePlanner { } if (road == null || currentsDist < sdist) { - road = new RouteSegment(); - road.road = r; - road.segmentStart = j - 1;//TODO: first 2 and last 2 segments should be based on projection. my start/finish point S/F, fake point P between j-1 & j -> SP, PJ; should end at finish point: JP,PF + road = new RouteSegment(r, j-1); +//TODO: first 2 and last 2 segments should be based on projection. my start/finish point S/F, fake point P between j-1 & j -> SP, PJ; should end at finish point: JP,PF road.segmentEnd = j; sdist = currentsDist; @@ -140,11 +139,12 @@ public class BinaryRoutePlanner { + // TODO TO-DO U-TURN + // TODO TO-DO ADD-INFO // TODO write unit tests // TODO add information about turns (?) - probably calculate additional information to show on map - // TODO think about u-turn // TODO fix roundabout (?) - probably calculate additional information to show on map // TODO access // TODO fastest/shortest way @@ -195,10 +195,6 @@ public class BinaryRoutePlanner { visitAllStartSegments(ctx, start, graphDirectSegments, visitedDirectSegments, startX, startY); visitAllStartSegments(ctx, end, graphReverseSegments, visitedOppositeSegments, targetEndX, targetEndY); - // final segment before end - RouteSegment finalDirectRoute = null; - RouteSegment finalReverseRoute = null; - // Extract & analyze segment with min(f(x)) from queue while final segment is not found boolean inverse = false; @@ -209,26 +205,17 @@ public class BinaryRoutePlanner { ctx.visitedSegments ++; // for debug purposes if (ctx.visitor != null) { - ctx.visitor.visitSegment(segment); + ctx.visitor.visitSegment(segment, true); } + boolean routeFound = false; if (!inverse) { - RoutePair pair = processRouteSegment(ctx, end, false, graphDirectSegments, visitedDirectSegments, targetEndX, + routeFound = processRouteSegment(ctx, end, false, graphDirectSegments, visitedDirectSegments, targetEndX, targetEndY, segment, visitedOppositeSegments); - if (pair != null) { - finalDirectRoute = pair.a; - finalReverseRoute = pair.b; - break; - } } else { - RoutePair pair = processRouteSegment(ctx, start, true, graphReverseSegments, visitedOppositeSegments, startX, + routeFound = processRouteSegment(ctx, start, true, graphReverseSegments, visitedOppositeSegments, startX, startY, segment, visitedDirectSegments); - if (pair != null) { - finalReverseRoute = pair.a; - finalDirectRoute = pair.b; - break; - } } - if(graphReverseSegments.isEmpty() || graphDirectSegments.isEmpty()){ + if(graphReverseSegments.isEmpty() || graphDirectSegments.isEmpty() || routeFound){ break; } if(ctx.planRouteIn2Directions()){ @@ -238,8 +225,6 @@ public class BinaryRoutePlanner { } else if (graphDirectSegments.size() < 1.3 * graphReverseSegments.size()) { inverse = false; } - // make it more simmetrical with dynamic prioritizing it makes big sense -// inverse = !inverse; } else { // different strategy : use onedirectional graph inverse = !ctx.getPlanRoadDirection().booleanValue(); @@ -249,7 +234,7 @@ public class BinaryRoutePlanner { // 4. Route is found : collect all segments and prepare result - return prepareResult(ctx, start, end, startNanoTime, finalDirectRoute, finalReverseRoute); + return prepareResult(ctx, start, end, startNanoTime, ctx.finalDirectRoute, ctx.finalReverseRoute); } @@ -257,30 +242,19 @@ public class BinaryRoutePlanner { private double h(final RoutingContext ctx, int targetEndX, int targetEndY, int startX, int startY) { double distance = squareRootDist(startX, startY, targetEndX, targetEndY); - //TODO add possible turn time and barrier according the distance return distance / ctx.getRouter().getMaxDefaultSpeed(); } - protected static double h(RoutingContext ctx, double distToFinalPoint, RouteSegment actual, RouteSegment next) { + protected static double h(RoutingContext ctx, double distToFinalPoint, RouteSegment next) { double result = distToFinalPoint / ctx.getRouter().getMaxDefaultSpeed(); if(ctx.isUseDynamicRoadPrioritising() && next != null){ double priority = ctx.getRouter().getRoadPriorityToCalculateRoute(next.road); result /= priority; } - //TODO add possible turn time and barrier according the distance return result; } - private double g(RoutingContext ctx, double distOnRoadToPass, - RouteSegment segment, int segmentEnd, double obstaclesTime, - RouteSegment next, double speed) { - double result = segment.distanceFromStart + distOnRoadToPass / speed; - // calculate turn time - result += ctx.getRouter().calculateTurnTime(segment, next, segmentEnd); - // add obstacles time - result += obstaclesTime; - return result; - } + public void loadRoutes(final RoutingContext ctx, int tile31X, int tile31Y, final List toFillIn) { int zoomToLoad = 31 - ctx.getZoomToLoadTileWithRoads(); @@ -307,9 +281,8 @@ public class BinaryRoutePlanner { ctx.idObjects.put(o.id, o); for (int j = 0; j < o.pointsX.size(); j++) { long l = (((long) o.pointsX.getQuick(j)) << 31) + (long) o.pointsY.getQuick(j); - RouteSegment segment = new RouteSegment(); - segment.road = o; - segment.segmentEnd = segment.segmentStart = j; + RouteSegment segment = new RouteSegment(o , j); + segment.segmentEnd = j; if (ctx.routes.get(l) != null) { segment.next = ctx.routes.get(l); } @@ -361,7 +334,8 @@ public class BinaryRoutePlanner { } } - private RoutePair processRouteSegment(final RoutingContext ctx, RouteSegment end, boolean reverseWaySearch, + + private boolean processRouteSegment(final RoutingContext ctx, RouteSegment end, boolean reverseWaySearch, PriorityQueue graphSegments, TLongObjectHashMap visitedSegments, int targetEndX, int targetEndY, RouteSegment segment, TLongObjectHashMap oppositeSegments) throws IOException { // Always start from segmentStart (!), not from segmentEnd @@ -371,6 +345,8 @@ public class BinaryRoutePlanner { final int middle = segment.segmentStart; int middlex = road.getPoint31XTile(middle); int middley = road.getPoint31YTile(middle); + double obstaclePlusTime = 0; + double obstacleMinusTime = 0; // 0. mark route segment as visited long nt = (road.getId() << 8l) + middle; @@ -380,7 +356,7 @@ public class BinaryRoutePlanner { segment.segmentEnd = middle; RouteSegment opposite = oppositeSegments.get(nt); opposite.segmentEnd = middle; - return new RoutePair(segment, opposite); + return true; } int oneway = ctx.getRouter().isOneWay(road); @@ -428,7 +404,8 @@ public class BinaryRoutePlanner { segment.segmentEnd = segmentEnd; RouteSegment opposite = oppositeSegments.get(nts); opposite.segmentEnd = segmentEnd; - return new RoutePair(segment, opposite); + ctx.finalDirectRoute = segment; + ctx.finalReverseRoute = opposite; } visitedSegments.put(nts, segment); @@ -436,207 +413,250 @@ public class BinaryRoutePlanner { int x = road.getPoint31XTile(segmentEnd); int y = road.getPoint31YTile(segmentEnd); loadRoutes(ctx, x, y, null); + + // TO-DO ADD-INFO attach add information about speed cameras here + // 2.1 calculate possible obstacle plus time + if(d > 0){ + obstaclePlusTime += ctx.getRouter().defineObstacle(road, segmentEnd); + } else if(d < 0) { + obstacleMinusTime += ctx.getRouter().defineObstacle(road, segmentEnd); + } + + long l = (((long) x) << 31) + (long) y; RouteSegment next = ctx.routes.get(l); - // 3. get intersected ways if (next != null) { - double distOnRoadToPass = squareRootDist(x, y, middlex, middley); - double distToFinalPoint = squareRootDist(x, y, targetEndX, targetEndY); - RouteSegment foundIntersection = processIntersectionsWithWays(ctx, graphSegments, visitedSegments, oppositeSegments, - distOnRoadToPass, distToFinalPoint, segment, road, - d == 0, segmentEnd, next, reverseWaySearch); - if(foundIntersection != null){ - segment.segmentEnd = segmentEnd; - return new RoutePair(segment, foundIntersection); + // TO-DO U-Turn + if(next == segment && next.next == null) { + // simplification if there is no real intersection + continue; } + // Using A* routing algorithm + // g(x) - calculate distance to that point and calculate time + double distOnRoadToPass = squareRootDist(x, y, middlex, middley); + double speed = ctx.getRouter().defineSpeed(road); + if (speed == 0) { + speed = ctx.getRouter().getMinDefaultSpeed(); + } + double distanceFromStart = segment.distanceFromStart + distOnRoadToPass / speed; + distanceFromStart += d > 0? obstaclePlusTime : obstacleMinusTime; + + double distToFinalPoint = squareRootDist(x, y, targetEndX, targetEndY); + + boolean routeFound = processIntersections(ctx, graphSegments, visitedSegments, oppositeSegments, + distanceFromStart, distToFinalPoint, segment, segmentEnd, next, reverseWaySearch); + if(routeFound){ + return routeFound; + } + } } - return null; + return false; } - - - - private RouteSegment processIntersectionsWithWays(RoutingContext ctx, PriorityQueue graphSegments, - TLongObjectHashMap visitedSegments, TLongObjectHashMap oppositeSegments, - double distOnRoadToPass, double distToFinalPoint, - RouteSegment segment, RouteDataObject road, boolean firstOfSegment, int segmentEnd, RouteSegment inputNext, - boolean reverseWay) { - - // This variables can be in routing context - // initialize temporary lists to calculate not forbidden ways at way intersections - ArrayList segmentsToVisitPrescripted = new ArrayList(5); - ArrayList segmentsToVisitNotForbidden = new ArrayList(5); - // collect time for obstacles - double obstaclesTime = 0; + private boolean proccessRestrictions(RoutingContext ctx, RouteDataObject road, RouteSegment inputNext, boolean reverseWay) { + ctx.segmentsToVisitPrescripted.clear(); + ctx.segmentsToVisitNotForbidden.clear(); boolean exclusiveRestriction = false; - - // 3.1 calculate time for obstacles (bumps, traffic_signals, level_crossing) - if (firstOfSegment) { - RouteSegment possibleObstacle = inputNext; - while (possibleObstacle != null) { - obstaclesTime += ctx.getRouter().defineObstacle(possibleObstacle.road, possibleObstacle.segmentStart); - possibleObstacle = possibleObstacle.next; - } - } - - // 3.2 calculate possible ways to put into priority queue - // for debug next.road.getId() >> 1 == 33911427 && road.getId() >> 1 == 33911442 RouteSegment next = inputNext; + if (!reverseWay && road.restrictions.isEmpty()) { + return false; + } while (next != null) { - long nts = (next.road.getId() << 8l) + next.segmentStart; - boolean oppositeConnectionFound = oppositeSegments.containsKey(nts) && oppositeSegments.get(nts) != null; - - boolean processRoad = true; - if (ctx.isUseStrategyOfIncreasingRoadPriorities()) { - double roadPriority = ctx.getRouter().getRoadPriorityHeuristicToIncrease(segment.road); - double nextRoadPriority = ctx.getRouter().getRoadPriorityHeuristicToIncrease(segment.road); - if (nextRoadPriority < roadPriority) { - processRoad = false; + int type = -1; + if (!reverseWay) { + for (int i = 0; i < road.restrictions.size(); i++) { + if (road.restrictions.getQuick(i) >> 3 == next.road.id) { + type = (int) (road.restrictions.getQuick(i) & 7); + break; + } } - } - - /* next.road.getId() >> 1 (3) != road.getId() >> 1 (3) - used that line for debug with osm map */ - // road.id could be equal on roundabout, but we should accept them - boolean alreadyVisited = visitedSegments.contains(nts); - if ((!alreadyVisited && processRoad) || oppositeConnectionFound) { - int type = -1; + } else { + for (int i = 0; i < next.road.restrictions.size(); i++) { + int rt = (int) (next.road.restrictions.getQuick(i) & 7); + long restrictedTo = next.road.restrictions.getQuick(i) >> 3; + if (restrictedTo == road.id) { + type = rt; + break; + } + + // Check if there is restriction only to the other than current road + if (rt == MapRenderingTypes.RESTRICTION_ONLY_RIGHT_TURN || rt == MapRenderingTypes.RESTRICTION_ONLY_LEFT_TURN + || rt == MapRenderingTypes.RESTRICTION_ONLY_STRAIGHT_ON) { + // check if that restriction applies to considered junk + RouteSegment foundNext = inputNext; + while (foundNext != null) { + if (foundNext.getRoad().id == restrictedTo) { + break; + } + foundNext = foundNext.next; + } + if (foundNext != null) { + type = REVERSE_WAY_RESTRICTION_ONLY; // special constant + } + } + } + } + if (type == REVERSE_WAY_RESTRICTION_ONLY) { + // next = next.next; continue; + } else if (type == -1 && exclusiveRestriction) { + // next = next.next; continue; + } else if (type == MapRenderingTypes.RESTRICTION_NO_LEFT_TURN || type == MapRenderingTypes.RESTRICTION_NO_RIGHT_TURN + || type == MapRenderingTypes.RESTRICTION_NO_STRAIGHT_ON || type == MapRenderingTypes.RESTRICTION_NO_U_TURN) { + // next = next.next; continue; + } else if (type == -1) { + // case no restriction + ctx.segmentsToVisitNotForbidden.add(next); + } else { + // case exclusive restriction (only_right, only_straight, ...) + // 1. in case we are going backward we should not consider only_restriction + // as exclusive because we have many "in" roads and one "out" + // 2. in case we are going forward we have one "in" and many "out" if (!reverseWay) { - for (int i = 0; i < road.restrictions.size(); i++) { - if (road.restrictions.getQuick(i) >> 3 == next.road.id) { - type = (int) (road.restrictions.getQuick(i) & 7); - break; - } - } + exclusiveRestriction = true; + ctx.segmentsToVisitNotForbidden.clear(); + ctx.segmentsToVisitPrescripted.add(next); } else { - for (int i = 0; i < next.road.restrictions.size(); i++) { - int rt = (int) (next.road.restrictions.getQuick(i) & 7); - if (next.road.restrictions.getQuick(i) >> 3 == road.id) { - type = rt; - break; - } - - // Check if there is restriction only to the current road - if (rt == MapRenderingTypes.RESTRICTION_ONLY_RIGHT_TURN - || rt == MapRenderingTypes.RESTRICTION_ONLY_LEFT_TURN - || rt == MapRenderingTypes.RESTRICTION_ONLY_STRAIGHT_ON) { - // check if that restriction applies to considered junk - RouteSegment foundNext = inputNext; - while(foundNext != null && foundNext.getRoad().id != rt){ - foundNext = foundNext.next; - } - if(foundNext != null) { - type = REVERSE_WAY_RESTRICTION_ONLY; // special constant - } - } - } - } - if(type == REVERSE_WAY_RESTRICTION_ONLY){ - // next = next.next; continue; - } else if (type == -1 && exclusiveRestriction) { - // next = next.next; continue; - } else if (type == MapRenderingTypes.RESTRICTION_NO_LEFT_TURN || type == MapRenderingTypes.RESTRICTION_NO_RIGHT_TURN - || type == MapRenderingTypes.RESTRICTION_NO_STRAIGHT_ON || type == MapRenderingTypes.RESTRICTION_NO_U_TURN) { - // next = next.next; continue; - } else { - // no restriction can go out - if(oppositeConnectionFound){ - RouteSegment oppSegment = oppositeSegments.get(nts); - oppSegment.segmentEnd = next.segmentStart; - return oppSegment; - } - - double distanceToEnd = h(ctx, distToFinalPoint, segment, next); - - // Using A* routing algorithm - // g(x) - calculate distance to that point and calculate time - double speed = ctx.getRouter().defineSpeed(road); - if (speed == 0) { - speed = ctx.getRouter().getMinDefaultSpeed(); - } - - double distanceFromStart = g(ctx, distOnRoadToPass, segment, segmentEnd, obstaclesTime, next, speed); - - // segment.getRoad().getId() >> 1 - if (next.parentRoute == null - || ctx.roadPriorityComparator(next.distanceFromStart, next.distanceToEnd, distanceFromStart, distanceToEnd) > 0) { - next.distanceFromStart = distanceFromStart; - next.distanceToEnd = distanceToEnd; - if (next.parentRoute != null) { - // already in queue remove it - graphSegments.remove(next); - } - // put additional information to recover whole route after - next.parentRoute = segment; - next.parentSegmentEnd = segmentEnd; - if (type == -1) { - // case no restriction - segmentsToVisitNotForbidden.add(next); - } else { - // case exclusive restriction (only_right, only_straight, ...) - // 1. in case we are going backward we should not consider only_restriction - // as exclusive because we have main "in" roads and one "out" - // 2. in case we are going forward we have one "in" and many "out" - if (!reverseWay) { - exclusiveRestriction = true; - segmentsToVisitNotForbidden.clear(); - segmentsToVisitPrescripted.add(next); - } else { - segmentsToVisitNotForbidden.add(next); - } - } - } - - } - } else if (alreadyVisited) { - //the segment was already visited! We need to follow better route. - if (segment.distanceFromStart < next.distanceFromStart) { - // Using A* routing algorithm - // g(x) - calculate distance to that point and calculate time - double speed = ctx.getRouter().defineSpeed(road); - if (speed == 0) { - speed = ctx.getRouter().getMinDefaultSpeed(); - } - next.distanceFromStart = g(ctx, distOnRoadToPass, segment, segmentEnd, obstaclesTime, next, speed); - //TODO calculate also the H heuristic, if this segment is in priority queue - final RouteSegment findAndReplace = next.parentRoute; - final RouteSegment actual = segment; - final int theend = next.parentSegmentEnd; - next.parentRoute = segment; - next.parentSegmentEnd = segment.road.getPointsLength()-1; //TODO I don't understand yet the segments correctly, this might be not correct - //REPLACE all that are branches of the next.parentRoute, because better way was found. - //TODO check which segments are in priority queue and update it. Probably, it can currently confuse the queue implementation! - //TODO all leaves of branches that exists from the updateSegment should be updated and leaves also updated in the priority queue - // --- this will speed up a little because the branches should be 'faster' - visitedSegments.forEachValue(new TObjectProcedure() { - @Override - public boolean execute(RouteSegment updateSegment) { - if (updateSegment != null && updateSegment.parentRoute == findAndReplace && updateSegment.parentSegmentEnd == theend && updateSegment != actual) { - updateSegment.parentRoute = actual; - updateSegment.parentSegmentEnd = actual.road.getPointsLength()-1; //TODO I don't understand yet the segments correctly, this might be not correct - } - return false; - } - }); + ctx.segmentsToVisitNotForbidden.add(next); } } next = next.next; } - - // add all allowed route segments to priority queue - for (RouteSegment s : segmentsToVisitNotForbidden) { - graphSegments.add(s); - } - for (RouteSegment s : segmentsToVisitPrescripted) { - graphSegments.add(s); - } - return null; + ctx.segmentsToVisitPrescripted.addAll(ctx.segmentsToVisitNotForbidden); + return true; } - - + + + private boolean processIntersections(RoutingContext ctx, PriorityQueue graphSegments, + TLongObjectHashMap visitedSegments, TLongObjectHashMap oppositeSegments, + double distFromStart, double distToFinalPoint, + RouteSegment segment, int segmentEnd, RouteSegment inputNext, + boolean reverseWay) { + + boolean thereAreRestrictions = proccessRestrictions(ctx, segment.road, inputNext, reverseWay); + Iterator nextIterator = null; + if (thereAreRestrictions) { + nextIterator = ctx.segmentsToVisitPrescripted.iterator(); + } + // Calculate possible ways to put into priority queue + // for debug next.road.getId() >> 1 == 33911427 && road.getId() >> 1 == 33911442 + RouteSegment next = inputNext; + boolean hasNext = nextIterator == null || nextIterator.hasNext(); + while (hasNext) { + if(nextIterator != null) { + next = nextIterator.next(); + } + long nts = (next.road.getId() << 8l) + next.segmentStart; + + // 1. Check if opposite segment found so we can stop calculations + boolean oppositeConnectionFound = oppositeSegments.containsKey(nts) && oppositeSegments.get(nts) != null; + if (oppositeConnectionFound) { + RouteSegment oppSegment = oppositeSegments.get(nts); + oppSegment.segmentEnd = next.segmentStart; + segment.segmentEnd = segmentEnd; + ctx.finalDirectRoute = segment; + ctx.finalReverseRoute = oppSegment; + return true; + } + + // Calculate complete distance from start + double gDistFromStart = distFromStart + ctx.getRouter().calculateTurnTime(segment, next, segmentEnd); + + /* next.road.getId() >> 1 (3) != road.getId() >> 1 (3) - used that line for debug with osm map */ + // road.id could be equal on roundabout, but we should accept them + boolean alreadyVisited = visitedSegments.contains(nts); + if (!alreadyVisited) { + double distanceToEnd = h(ctx, distToFinalPoint, next); + if (next.parentRoute == null + || ctx.roadPriorityComparator(next.distanceFromStart, next.distanceToEnd, gDistFromStart, distanceToEnd) > 0) { + next.distanceFromStart = gDistFromStart; + next.distanceToEnd = distanceToEnd; + if (next.parentRoute != null) { + // already in queue remove it + graphSegments.remove(next); + } + // put additional information to recover whole route after + next.parentRoute = segment; + next.parentSegmentEnd = segmentEnd; + } + graphSegments.add(next); + if (ctx.visitor != null) { + ctx.visitor.visitSegment(next, false); + } + } else { + // the segment was already visited! We need to follow better route if it exists + // that is very strange situation and almost exception (it can happen when we underestimate distnceToEnd) + if (gDistFromStart < next.distanceFromStart) { + // That code is incorrect (when segment is processed itself, + // then it tries to make wrong u-turn) - + // this situation should be very carefully checked in future +// next.distanceFromStart = gDistFromStart; +// next.parentRoute = segment; +// next.parentSegmentEnd = segmentEnd; +// +// if (ctx.visitor != null) { +// ctx.visitor.visitSegment(next, false); +// } + } + } + + // iterate to next road + if(nextIterator == null) { + next = next.next; + hasNext = next != null; + } else { + hasNext = nextIterator.hasNext(); + } + } + return false; + } + + public static class RouteSegment { + final int segmentStart; + final RouteDataObject road; + // needed to store intersection of routes + RouteSegment next = null; + + // search context (needed for searching route) + // Initially it should be null (!) because it checks was it segment visited before + RouteSegment parentRoute = null; + int parentSegmentEnd = 0; + + // distance measured in time (seconds) + double distanceFromStart = 0; + double distanceToEnd = 0; + + // used only to round up route (TODO remove?) + int segmentEnd = 0; + + public RouteSegment(RouteDataObject road, int segmentStart) { + this.road = road; + this.segmentStart = segmentStart; + } + + public RouteSegment getNext() { + return next; + } + + public int getSegmentStart() { + return segmentStart; + } + + public RouteDataObject getRoad() { + return road; + } + + public String getTestName(){ + return String.format("s%.2f e%.2f", ((float)distanceFromStart), ((float)distanceToEnd)); + } + } + + /** + * Helper method to prepare final result + */ private List prepareResult(RoutingContext ctx, RouteSegment start, RouteSegment end, long startNanoTime, RouteSegment finalDirectRoute, RouteSegment finalReverseRoute) { List result = new ArrayList(); @@ -725,7 +745,7 @@ public class BinaryRoutePlanner { public interface RouteSegmentVisitor { - public void visitSegment(RouteSegment segment); + public void visitSegment(RouteSegment segment, boolean poll); } @@ -738,46 +758,6 @@ public class BinaryRoutePlanner { o2DistanceFromStart + heuristicCoefficient * o2DistanceToEnd); } - public static class RouteSegment { - int segmentStart = 0; - int segmentEnd = 0; - RouteDataObject road; - // needed to store intersection of routes - RouteSegment next = null; - - // search context (needed for searching route) - // Initially it should be null (!) because it checks was it segment visited before - RouteSegment parentRoute = null; - int parentSegmentEnd = 0; - - // distance measured in time (seconds) - double distanceFromStart = 0; - double distanceToEnd = 0; - - public RouteSegment getNext() { - return next; - } - - public int getSegmentStart() { - return segmentStart; - } - - public RouteDataObject getRoad() { - return road; - } - } - - private static class RoutePair { - RouteSegment a; - RouteSegment b; - public RoutePair(RouteSegment a, RouteSegment b) { - super(); - this.a = a; - this.b = b; - } - - - } } diff --git a/DataExtractionOSM/src/net/osmand/router/RoutingContext.java b/DataExtractionOSM/src/net/osmand/router/RoutingContext.java index c99f326b12..36c86697c8 100644 --- a/DataExtractionOSM/src/net/osmand/router/RoutingContext.java +++ b/DataExtractionOSM/src/net/osmand/router/RoutingContext.java @@ -1,9 +1,13 @@ package net.osmand.router; +import java.util.ArrayList; + import gnu.trove.map.TLongObjectMap; import gnu.trove.map.hash.TLongObjectHashMap; import gnu.trove.set.TIntSet; +import gnu.trove.set.TLongSet; import gnu.trove.set.hash.TIntHashSet; +import gnu.trove.set.hash.TLongHashSet; import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteDataObject; import net.osmand.router.BinaryRoutePlanner.RouteSegment; @@ -18,7 +22,6 @@ public class RoutingContext { // 1. parameters of routing and different tweaks private int heuristicCoefficient = DEFAULT_HEURISTIC_COEFFICIENT; private int zoomToLoadTileWithRoads = ZOOM_TO_LOAD_TILES; - private boolean useStrategyOfIncreasingRoadPriorities = true; // null - 2 ways, true - direct way, false - reverse way private Boolean planRoadDirection = null; private VehicleRouter router = new CarRouter(); @@ -30,6 +33,17 @@ public class RoutingContext { // 2. Routing memory cache TLongObjectMap routes = new TLongObjectHashMap(); TIntSet loadedTiles = new TIntHashSet(); + // TODO delete this object ? + TLongObjectHashMap idObjects = new TLongObjectHashMap(); + + // 4. Warm object caches + TLongSet nonRestrictedIds = new TLongHashSet(); + RouteSegment finalDirectRoute = null; + RouteSegment finalReverseRoute = null; + ArrayList segmentsToVisitPrescripted = new ArrayList(5); + ArrayList segmentsToVisitNotForbidden = new ArrayList(5); + + // 3. debug information (package accessor) long timeToLoad = 0; @@ -37,8 +51,8 @@ public class RoutingContext { int visitedSegments = 0; // callback of processing segments RouteSegmentVisitor visitor = null; - // TODO delete this object ? - TLongObjectHashMap idObjects = new TLongObjectHashMap(); + + public RouteSegmentVisitor getVisitor() { @@ -61,10 +75,6 @@ public class RoutingContext { return zoomToLoadTileWithRoads; } - public boolean isUseStrategyOfIncreasingRoadPriorities() { - return useStrategyOfIncreasingRoadPriorities && planRoadDirection == null; - } - public void setUseDynamicRoadPrioritising(boolean useDynamicRoadPrioritising) { this.useDynamicRoadPrioritising = useDynamicRoadPrioritising; } @@ -101,14 +111,6 @@ public class RoutingContext { this.planRoadDirection = planRoadDirection; } - public boolean useStrategyOfIncreasingRoadPriorities() { - return planRouteIn2Directions() && useStrategyOfIncreasingRoadPriorities; - } - - public void setUseStrategyOfIncreasingRoadPriorities(boolean useStrategyOfIncreasingRoadPriorities) { - this.useStrategyOfIncreasingRoadPriorities = useStrategyOfIncreasingRoadPriorities; - } - public int roadPriorityComparator(double o1DistanceFromStart, double o1DistanceToEnd, double o2DistanceFromStart, double o2DistanceToEnd) { return BinaryRoutePlanner.roadPriorityComparator(o1DistanceFromStart, o1DistanceToEnd, o2DistanceFromStart, o2DistanceToEnd, heuristicCoefficient); diff --git a/DataExtractionOSM/src/net/osmand/swing/DataExtractionSettings.java b/DataExtractionOSM/src/net/osmand/swing/DataExtractionSettings.java index 0cbfdec3af..7376fd238a 100644 --- a/DataExtractionOSM/src/net/osmand/swing/DataExtractionSettings.java +++ b/DataExtractionOSM/src/net/osmand/swing/DataExtractionSettings.java @@ -209,6 +209,15 @@ public class DataExtractionSettings { preferences.putBoolean("supress_duplicated_id", b); } + public boolean isAnimateRouting(){ + return preferences.getBoolean("animate_routing", true); + } + + public void setAnimateRouting(boolean b){ + preferences.putBoolean("animate_routing", b); + } + + String[] SUFFIXES = new String[] {"av.", "avenue", "просп.", "пер.", "пр.","заул.", "проспект", "переул.", "бул.", "бульвар", "тракт"}; String[] DEFAUTL_SUFFIXES = new String[] {"str.", "street", "улица", "ул."}; diff --git a/DataExtractionOSM/src/net/osmand/swing/MapClusterLayer.java b/DataExtractionOSM/src/net/osmand/swing/MapClusterLayer.java index baa1168ea1..ce404ae1c0 100644 --- a/DataExtractionOSM/src/net/osmand/swing/MapClusterLayer.java +++ b/DataExtractionOSM/src/net/osmand/swing/MapClusterLayer.java @@ -3,6 +3,7 @@ package net.osmand.swing; import gnu.trove.set.hash.TLongHashSet; import java.awt.Graphics; +import java.awt.Graphics2D; import java.awt.Point; import java.awt.event.ActionEvent; import java.io.File; @@ -154,7 +155,7 @@ public class MapClusterLayer implements MapPanelLayer { private List cache = new ArrayList(); @Override - public void visitSegment(RouteSegment s) { + public void visitSegment(RouteSegment s, boolean poll) { if(!ANIMATE_CLUSTERING){ return; } @@ -186,6 +187,7 @@ public class MapClusterLayer implements MapPanelLayer { e.printStackTrace(); } } + }); searchCluster(ctx, st, router, res, roads); if (ANIMATE_CLUSTERING) { @@ -223,7 +225,7 @@ public class MapClusterLayer implements MapPanelLayer { nextSegment : while(!queue.isEmpty()){ RouteSegment segment = queue.poll(); RouteDataObject road = segment.getRoad(); - ctx.getVisitor().visitSegment(segment); + ctx.getVisitor().visitSegment(segment, true); if(visitedIds.contains(calculateId(segment, segment.getSegmentStart()))){ continue; } @@ -319,8 +321,7 @@ public class MapClusterLayer implements MapPanelLayer { } @Override - public void paintLayer(Graphics g) { - + public void paintLayer(Graphics2D g) { } diff --git a/DataExtractionOSM/src/net/osmand/swing/MapInformationLayer.java b/DataExtractionOSM/src/net/osmand/swing/MapInformationLayer.java index 54998b1b45..477a888bba 100644 --- a/DataExtractionOSM/src/net/osmand/swing/MapInformationLayer.java +++ b/DataExtractionOSM/src/net/osmand/swing/MapInformationLayer.java @@ -3,6 +3,7 @@ package net.osmand.swing; import java.awt.Color; import java.awt.Component; import java.awt.Graphics; +import java.awt.Graphics2D; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.text.MessageFormat; @@ -119,7 +120,7 @@ public class MapInformationLayer implements MapPanelLayer { } @Override - public void paintLayer(Graphics g) { + public void paintLayer(Graphics2D g) { g.setColor(Color.black); g.fillOval((int)map.getCenterPointX() - 2,(int) map.getCenterPointY() - 2, 4, 4); g.drawOval((int)map.getCenterPointX() - 2,(int) map.getCenterPointY() - 2, 4, 4); diff --git a/DataExtractionOSM/src/net/osmand/swing/MapPanel.java b/DataExtractionOSM/src/net/osmand/swing/MapPanel.java index b2cf729a90..82bf86f5ef 100644 --- a/DataExtractionOSM/src/net/osmand/swing/MapPanel.java +++ b/DataExtractionOSM/src/net/osmand/swing/MapPanel.java @@ -4,6 +4,7 @@ import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import java.awt.Graphics; +import java.awt.Graphics2D; import java.awt.Image; import java.awt.Point; import java.awt.Rectangle; @@ -407,7 +408,7 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback { } } for(MapPanelLayer l : layers){ - l.paintLayer(g); + l.paintLayer((Graphics2D) g); } if(selectionArea.isVisible()){ diff --git a/DataExtractionOSM/src/net/osmand/swing/MapPanelLayer.java b/DataExtractionOSM/src/net/osmand/swing/MapPanelLayer.java index 1a41f57f39..d0c74109c5 100644 --- a/DataExtractionOSM/src/net/osmand/swing/MapPanelLayer.java +++ b/DataExtractionOSM/src/net/osmand/swing/MapPanelLayer.java @@ -1,6 +1,6 @@ package net.osmand.swing; -import java.awt.Graphics; +import java.awt.Graphics2D; public interface MapPanelLayer { @@ -10,6 +10,6 @@ public interface MapPanelLayer { public void prepareToDraw(); - public void paintLayer(Graphics g); + public void paintLayer(Graphics2D g); } diff --git a/DataExtractionOSM/src/net/osmand/swing/MapPointsLayer.java b/DataExtractionOSM/src/net/osmand/swing/MapPointsLayer.java index 07f715fac7..d0453fb578 100644 --- a/DataExtractionOSM/src/net/osmand/swing/MapPointsLayer.java +++ b/DataExtractionOSM/src/net/osmand/swing/MapPointsLayer.java @@ -1,8 +1,10 @@ package net.osmand.swing; import java.awt.Color; -import java.awt.Graphics; +import java.awt.Font; +import java.awt.Graphics2D; import java.awt.Point; +import java.awt.RenderingHints; import java.awt.geom.AffineTransform; import java.awt.geom.Line2D; import java.awt.geom.Point2D; @@ -10,11 +12,14 @@ import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; import net.osmand.data.DataTileManager; import net.osmand.osm.Entity; import net.osmand.osm.MapUtils; import net.osmand.osm.Node; +import net.osmand.osm.OSMSettings.OSMTagKey; import net.osmand.osm.Way; @@ -31,7 +36,22 @@ public class MapPointsLayer implements MapPanelLayer { private String tagToShow = null; private Map pointsToDraw = new LinkedHashMap(); - private List linesToDraw = new ArrayList(); + private List linesToDraw = new ArrayList(); + + private Font whiteFont; + + private static class LineObject { + Way w; + Line2D line; + boolean middle; + public LineObject(Way w, Line2D line, boolean middle) { + super(); + this.w = w; + this.line = line; + this.middle = middle; + } + + } @Override public void destroyLayer() { @@ -57,8 +77,13 @@ public class MapPointsLayer implements MapPanelLayer { @Override - public void paintLayer(Graphics g) { + public void paintLayer(Graphics2D g) { g.setColor(color); + if (whiteFont == null) { + whiteFont = g.getFont().deriveFont(15).deriveFont(Font.BOLD); + } + g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); // draw user points for (Point p : pointsToDraw.keySet()) { g.drawOval(p.x, p.y, size, size); @@ -68,11 +93,24 @@ public class MapPointsLayer implements MapPanelLayer { } } - g.setColor(color); // draw user points int[] xPoints = new int[4]; int[] yPoints = new int[4]; - for (Line2D p : linesToDraw) { + for (LineObject e : linesToDraw) { + Line2D p = e.line; + Way w = e.w; + g.setColor(color); + String name = null; + boolean white = false; + if(w != null) { + if (e.middle) { + name = w.getTag("name"); + } + white = "white".equalsIgnoreCase(w.getTag("color")); + if(white){ + g.setColor(Color.gray); + } + } AffineTransform transform = new AffineTransform(); transform.translate(p.getX1(), p.getY1()); transform.rotate(p.getX2() - p.getX1(), p.getY2() - p.getY1()); @@ -88,6 +126,40 @@ public class MapPointsLayer implements MapPanelLayer { } g.drawPolygon(xPoints, yPoints, 4); g.fillPolygon(xPoints, yPoints, 4); + if(name != null && map.getZoom() > 16) { + Font prevFont = g.getFont(); + Color prevColor = g.getColor(); + AffineTransform prev = g.getTransform(); + + double flt = Math.atan2(p.getX2() - p.getX1(), p.getY2() - p.getY1()); + + AffineTransform ps = new AffineTransform(prev); + ps.translate((p.getX2() + p.getX1()) / 2, (int)(p.getY2() + p.getY1()) / 2); + if(flt < Math.PI && flt > 0) { + ps.rotate(p.getX2() - p.getX1(), p.getY2() - p.getY1()); + } else { + ps.rotate(-(p.getX2() - p.getX1()), -(p.getY2() - p.getY1())); + } + g.setTransform(ps); + + g.setFont(whiteFont); + g.setColor(Color.white); + float c = 1.3f; + g.scale(c, c); + g.drawString(name, (int)(-15), (int) (-10/c)); + g.scale(1/c, 1/c); + + if(white) { + g.setColor(Color.lightGray); + } else { + g.setColor(Color.DARK_GRAY); + } + g.drawString(name, -15, -10); + + g.setColor(prevColor); + g.setTransform(prev); + g.setFont(prevFont); + } } } @@ -117,7 +189,7 @@ public class MapPointsLayer implements MapPanelLayer { int pixX = (int) (MapUtils.getPixelShiftX(map.getZoom(), n.getLongitude(), map.getLongitude(), map.getTileSize()) + map.getCenterPointX()); int pixY = (int) (MapUtils.getPixelShiftY(map.getZoom(), n.getLatitude(), map.getLatitude(), map.getTileSize()) + map.getCenterPointY()); if (i > 0) { - linesToDraw.add(new Line2D.Float(pixX, pixY, prevPixX, prevPixY)); + linesToDraw.add(new LineObject((Way) e, new Line2D.Float(pixX, pixY, prevPixX, prevPixY), i == nodes.size() / 2)); } prevPixX = pixX; prevPixY = pixY; diff --git a/DataExtractionOSM/src/net/osmand/swing/MapRouterLayer.java b/DataExtractionOSM/src/net/osmand/swing/MapRouterLayer.java index 13e3f544c6..edb19fc94c 100644 --- a/DataExtractionOSM/src/net/osmand/swing/MapRouterLayer.java +++ b/DataExtractionOSM/src/net/osmand/swing/MapRouterLayer.java @@ -1,9 +1,11 @@ package net.osmand.swing; import java.awt.Color; -import java.awt.Graphics; +import java.awt.Component; +import java.awt.Graphics2D; import java.awt.Point; import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.File; import java.io.IOException; @@ -18,6 +20,7 @@ import java.util.List; import javax.swing.AbstractAction; import javax.swing.Action; +import javax.swing.JButton; import javax.swing.JOptionPane; import javax.swing.JPopupMenu; import javax.swing.SwingUtilities; @@ -30,6 +33,7 @@ import net.osmand.data.DataTileManager; import net.osmand.osm.LatLon; import net.osmand.osm.MapUtils; import net.osmand.osm.Way; +import net.osmand.osm.OSMSettings.OSMTagKey; import net.osmand.router.BinaryRoutePlanner; import net.osmand.router.CarRouter; import net.osmand.router.RouteSegmentResult; @@ -52,14 +56,17 @@ import org.json.JSONTokener; public class MapRouterLayer implements MapPanelLayer { - private /*final */ static boolean ANIMATE_CALCULATING_ROUTE = true; - private /*final */ static int SIZE_OF_ROUTES_TO_ANIMATE = 10; - - private MapPanel map; private LatLon startRoute ; private LatLon endRoute ; private VehicleRouter routerMode = new CarRouter(); + private boolean nextAvailable = true; + private boolean pause = true; + private boolean stop = false; + private int steps = 1; + private JButton nextTurn; + private JButton playPauseButton; + private JButton stopButton; @Override @@ -73,6 +80,49 @@ public class MapRouterLayer implements MapPanelLayer { fillPopupMenuWithActions(map.getPopupMenu()); startRoute = DataExtractionSettings.getSettings().getStartLocation(); endRoute = DataExtractionSettings.getSettings().getEndLocation(); + + nextTurn = new JButton(">>"); //$NON-NLS-1$ + nextTurn.addActionListener(new ActionListener(){ + @Override + public void actionPerformed(ActionEvent e) { + nextAvailable = true; + synchronized (MapRouterLayer.this) { + MapRouterLayer.this.notify(); + } + } + }); + nextTurn.setVisible(false); + nextTurn.setAlignmentY(Component.TOP_ALIGNMENT); + map.add(nextTurn, 0); + playPauseButton = new JButton("Play"); //$NON-NLS-1$ + playPauseButton.addActionListener(new ActionListener(){ + @Override + public void actionPerformed(ActionEvent e) { + pause = !pause; + playPauseButton.setText(pause ? "Play" : "Pause"); + nextAvailable = true; + synchronized (MapRouterLayer.this) { + MapRouterLayer.this.notify(); + } + } + }); + playPauseButton.setVisible(false); + playPauseButton.setAlignmentY(Component.TOP_ALIGNMENT); + map.add(playPauseButton, 0); + stopButton = new JButton("Stop"); //$NON-NLS-1$ + stopButton.addActionListener(new ActionListener(){ + @Override + public void actionPerformed(ActionEvent e) { + stop = true; + nextAvailable = true; + synchronized (MapRouterLayer.this) { + MapRouterLayer.this.notify(); + } + } + }); + stopButton.setVisible(false); + stopButton.setAlignmentY(Component.TOP_ALIGNMENT); + map.add(stopButton); } public void fillPopupMenuWithActions(JPopupMenu menu) { @@ -481,7 +531,15 @@ public class MapRouterLayer implements MapPanelLayer { files.add(f); } } - + final boolean animateRoutingCalculation = DataExtractionSettings.getSettings().isAnimateRouting(); + if(animateRoutingCalculation) { + nextTurn.setVisible(true); + playPauseButton.setVisible(true); + stopButton.setVisible(true); + pause = true; + playPauseButton.setText("Play"); + } + stop = false; if(files == null){ JOptionPane.showMessageDialog(OsmExtractionUI.MAIN_APP.getFrame(), "Please specify obf file in settings", "Obf file not found", JOptionPane.ERROR_MESSAGE); @@ -521,30 +579,40 @@ public class MapRouterLayer implements MapPanelLayer { ctx.setVisitor(new RouteSegmentVisitor() { private List cache = new ArrayList(); + private List pollCache = new ArrayList(); @Override - public void visitSegment(RouteSegment s) { - if(!ANIMATE_CALCULATING_ROUTE){ + public void visitSegment(RouteSegment s, boolean poll) { + if(stop) { + throw new RuntimeException("Interrupted"); + } + if (!animateRoutingCalculation) { return; } + if (!poll && pause) { + pollCache.add(s); + return; + } + cache.add(s); - if(cache.size() < SIZE_OF_ROUTES_TO_ANIMATE){ + if (cache.size() < steps) { return; } - for (RouteSegment segment : cache) { - Way way = new Way(-1); - for (int i = 0; i < segment.getRoad().getPointsLength(); i++) { - net.osmand.osm.Node n = new net.osmand.osm.Node(MapUtils.get31LatitudeY(segment.getRoad() - .getPoint31YTile(i)), MapUtils.get31LongitudeX(segment.getRoad().getPoint31XTile(i)), -1); - way.addNode(n); - } - LatLon n = way.getLatLon(); - points.registerObject(n.getLatitude(), n.getLongitude(), way); + if(pause) { + registerObjects(points, poll, pollCache); + pollCache.clear(); } + registerObjects(points, !poll, cache); cache.clear(); + redraw(); + if (pause) { + waitNextPress(); + } + } + + private void redraw() { try { SwingUtilities.invokeAndWait(new Runnable() { - @Override public void run() { map.prepareImage(); @@ -555,15 +623,32 @@ public class MapRouterLayer implements MapPanelLayer { e.printStackTrace(); } } + + private void registerObjects(final DataTileManager points, boolean white, + List registerCache) { + for (RouteSegment segment : registerCache) { + Way way = new Way(-1); + way.putTag(OSMTagKey.NAME.getValue(), segment.getTestName()); + if(white) { + way.putTag("color", "white"); + } + for (int i = 0; i < segment.getRoad().getPointsLength(); i++) { + net.osmand.osm.Node n = new net.osmand.osm.Node(MapUtils.get31LatitudeY(segment.getRoad() + .getPoint31YTile(i)), MapUtils.get31LongitudeX(segment.getRoad().getPoint31XTile(i)), -1); + way.addNode(n); + } + LatLon n = way.getLatLon(); + points.registerObject(n.getLatitude(), n.getLongitude(), way); + } + } + }); List searchRoute = router.searchRoute(ctx, st, e); - if (ANIMATE_CALCULATING_ROUTE) { - try { - Thread.sleep(2000); - } catch (InterruptedException e1) { - } + if (pause) { + nextTurn.setText("FINISH"); + waitNextPress(); + nextTurn.setText(">>"); } - net.osmand.osm.Node prevWayNode = null; for (RouteSegmentResult s : searchRoute) { // double dist = MapUtils.getDistance(s.startPoint, s.endPoint); @@ -597,19 +682,39 @@ public class MapRouterLayer implements MapPanelLayer { } } catch (IOException e) { ExceptionHandler.handle(e); + } finally { + playPauseButton.setVisible(false); + nextTurn.setVisible(false); + stopButton.setVisible(false); + map.getPoints().clear(); } System.out.println("Finding self routes " + res.size() + " " + (System.currentTimeMillis() - time) + " ms"); } return res; } + private void waitNextPress() { + nextTurn.setVisible(true); + while (!nextAvailable) { + try { + synchronized (MapRouterLayer.this) { + MapRouterLayer.this.wait(); + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + nextTurn.setVisible(false); + nextAvailable = false; + } + @Override public void prepareToDraw() { } @Override - public void paintLayer(Graphics g) { + public void paintLayer(Graphics2D g) { g.setColor(Color.green); if(startRoute != null){ int x = map.getMapXForPoint(startRoute.getLongitude()); diff --git a/DataExtractionOSM/src/net/osmand/swing/OsmExtractionPreferencesDialog.java b/DataExtractionOSM/src/net/osmand/swing/OsmExtractionPreferencesDialog.java index 6dcad52cae..e28f6ddbfd 100644 --- a/DataExtractionOSM/src/net/osmand/swing/OsmExtractionPreferencesDialog.java +++ b/DataExtractionOSM/src/net/osmand/swing/OsmExtractionPreferencesDialog.java @@ -40,6 +40,7 @@ public class OsmExtractionPreferencesDialog extends JDialog { private JTextField renderingStyleFile; private JCheckBox useInternet; + private JCheckBox animateRouting; // private JCheckBox supressWarning; @@ -86,6 +87,7 @@ public class OsmExtractionPreferencesDialog extends JDialog { private void createGeneralSection(JPanel root) { JPanel panel = new JPanel(); + int gridY = 0; // panel.setLayout(new GridLayout(3, 1, 5, 5)); GridBagLayout l = new GridBagLayout(); panel.setLayout(l); @@ -99,17 +101,29 @@ public class OsmExtractionPreferencesDialog extends JDialog { GridBagConstraints constr = new GridBagConstraints(); constr.ipadx = 5; constr.gridx = 0; - constr.gridy = 0; + constr.gridy = gridY++; constr.gridwidth = 2; constr.anchor = GridBagConstraints.WEST; l.setConstraints(useInternet, constr); + animateRouting = new JCheckBox(); + animateRouting.setText("Animate routing"); //$NON-NLS-1$ + animateRouting.setSelected(DataExtractionSettings.getSettings().isAnimateRouting()); + panel.add(animateRouting); + constr = new GridBagConstraints(); + constr.ipadx = 5; + constr.gridx = 0; + constr.gridy = gridY++; + constr.gridwidth = 2; + constr.anchor = GridBagConstraints.WEST; + l.setConstraints(animateRouting, constr); + JLabel label = new JLabel("Directory with obf binary files (routing, rendering): "); panel.add(label); constr = new GridBagConstraints(); constr.ipadx = 5; constr.gridx = 0; - constr.gridy = 1; + constr.gridy = gridY; constr.anchor = GridBagConstraints.WEST; l.setConstraints(label, constr); @@ -122,7 +136,7 @@ public class OsmExtractionPreferencesDialog extends JDialog { constr.fill = GridBagConstraints.HORIZONTAL; constr.ipadx = 5; constr.gridx = 1; - constr.gridy = 1; + constr.gridy = gridY++; l.setConstraints(nativeFilesDirectory, constr); @@ -131,7 +145,7 @@ public class OsmExtractionPreferencesDialog extends JDialog { constr = new GridBagConstraints(); constr.ipadx = 5; constr.gridx = 0; - constr.gridy = 2; + constr.gridy = gridY; constr.anchor = GridBagConstraints.WEST; l.setConstraints(label, constr); @@ -144,7 +158,7 @@ public class OsmExtractionPreferencesDialog extends JDialog { constr.fill = GridBagConstraints.HORIZONTAL; constr.ipadx = 5; constr.gridx = 1; - constr.gridy = 2; + constr.gridy = gridY++; l.setConstraints(cityAdminLevel, constr); label = new JLabel(Messages.getString("OsmExtractionPreferencesDialog.OSRM.SERVER.ADDRESS")); @@ -152,7 +166,7 @@ public class OsmExtractionPreferencesDialog extends JDialog { constr = new GridBagConstraints(); constr.ipadx = 5; constr.gridx = 0; - constr.gridy = 3; + constr.gridy = gridY; constr.anchor = GridBagConstraints.WEST; l.setConstraints(label, constr); @@ -165,7 +179,7 @@ public class OsmExtractionPreferencesDialog extends JDialog { constr.fill = GridBagConstraints.HORIZONTAL; constr.ipadx = 5; constr.gridx = 1; - constr.gridy = 3; + constr.gridy = gridY++; l.setConstraints(osrmServerAddress, constr); label = new JLabel("Rendering style file : "); @@ -173,7 +187,7 @@ public class OsmExtractionPreferencesDialog extends JDialog { constr = new GridBagConstraints(); constr.ipadx = 5; constr.gridx = 0; - constr.gridy = 4; + constr.gridy = gridY; constr.anchor = GridBagConstraints.WEST; l.setConstraints(label, constr); @@ -185,7 +199,7 @@ public class OsmExtractionPreferencesDialog extends JDialog { constr.fill = GridBagConstraints.HORIZONTAL; constr.ipadx = 5; constr.gridx = 1; - constr.gridy = 4; + constr.gridy = gridY++; l.setConstraints(renderingStyleFile, constr); label = new JLabel("Native lib file (osmand.lib): "); @@ -193,7 +207,7 @@ public class OsmExtractionPreferencesDialog extends JDialog { constr = new GridBagConstraints(); constr.ipadx = 5; constr.gridx = 0; - constr.gridy = 5; + constr.gridy = gridY; constr.anchor = GridBagConstraints.WEST; l.setConstraints(label, constr); @@ -205,7 +219,7 @@ public class OsmExtractionPreferencesDialog extends JDialog { constr.fill = GridBagConstraints.HORIZONTAL; constr.ipadx = 5; constr.gridx = 1; - constr.gridy = 5; + constr.gridy = gridY++; l.setConstraints(nativeLibFile, constr); // supressWarning = new JCheckBox(); @@ -268,7 +282,7 @@ public class OsmExtractionPreferencesDialog extends JDialog { constr.gridy = 1; l.setConstraints(streetDefaultSuffixes, constr); - label = new JLabel("Map zooms (specify zoom levels in binary map) example - " + MapZooms.MAP_ZOOMS_DEFAULT); + label = new JLabel("Map zooms (specify zoom levels in binary map) "); panel.add(label); constr = new GridBagConstraints(); constr.ipadx = 5; @@ -362,6 +376,9 @@ public class OsmExtractionPreferencesDialog extends JDialog { if(settings.useInternetToLoadImages() != useInternet.isSelected()){ settings.setUseInterentToLoadImages(useInternet.isSelected()); } + if(settings.isAnimateRouting() != animateRouting.isSelected()){ + settings.setAnimateRouting(animateRouting.isSelected()); + } if(!settings.getNativeLibFile().equals(nativeLibFile.getText())){ settings.setNativeLibFile(nativeLibFile.getText()); } diff --git a/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java b/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java index e80b55b5f7..44a2c4f6fa 100644 --- a/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java +++ b/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java @@ -620,16 +620,13 @@ public class RouteProvider { ctx.setUsingShortestWay(!fast); if(mode == ApplicationMode.BICYCLE){ ctx.setRouter(new BicycleRouter()); - ctx.setUseStrategyOfIncreasingRoadPriorities(false); ctx.setUseDynamicRoadPrioritising(true); } else if(mode == ApplicationMode.PEDESTRIAN){ ctx.setRouter(new PedestrianRouter()); - ctx.setUseStrategyOfIncreasingRoadPriorities(false); ctx.setUseDynamicRoadPrioritising(false); ctx.setHeuristicCoefficient(2); } else { ctx.setRouter(new CarRouter()); - ctx.setUseStrategyOfIncreasingRoadPriorities(true); ctx.setUseDynamicRoadPrioritising(true); } RouteSegment st= router.findRouteSegment(start.getLatitude(), start.getLongitude(), ctx);