Update binary router

This commit is contained in:
Victor Shcherb 2012-06-10 12:52:08 +02:00
parent 4a8ff5ba10
commit 399378b585
22 changed files with 583 additions and 385 deletions

View file

@ -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) {

View file

@ -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<points.length; k++) {
ROUTE_COORDINATES_COUNT++;
int tx = (points[k].x >> 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 ;

View file

@ -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<Entity> 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<Long> 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<Long> 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);
}
}

View file

@ -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);

View file

@ -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

View file

@ -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<EntityId> fromL = ((Relation) e).getMemberIds("from"); //$NON-NLS-1$
Collection<EntityId> toL = ((Relation) e).getMemberIds("to"); //$NON-NLS-1$
if (!fromL.isEmpty() && !toL.isEmpty()) {

View file

@ -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);

View file

@ -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<Entity, String> 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);

View file

@ -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();

View file

@ -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;
}

View file

@ -65,10 +65,7 @@ public class MapRoutingTypes {
}
public boolean encodeEntity(Entity et, TIntArrayList outTypes, TLongObjectHashMap<TIntArrayList> pointTypes, Map<MapRouteType, String> names){
if (!(et instanceof Way)) {
return false;
}
public boolean encodeEntity(Way et, TIntArrayList outTypes, Map<MapRouteType, String> 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<String, String> 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<String, String> 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<TIntArrayList> pointTypes){
pointTypes.clear();
for(Node nd : e.getNodes() ) {
if (nd != null) {
for (Entry<String, String> 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);
}

View file

@ -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<RouteDataObject> 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<RouteSegment> graphSegments, TLongObjectHashMap<RouteSegment> visitedSegments, int targetEndX, int targetEndY,
RouteSegment segment, TLongObjectHashMap<RouteSegment> 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<RouteSegment> graphSegments,
TLongObjectHashMap<RouteSegment> visitedSegments, TLongObjectHashMap<RouteSegment> 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<RouteSegment> segmentsToVisitPrescripted = new ArrayList<RouteSegment>(5);
ArrayList<RouteSegment> segmentsToVisitNotForbidden = new ArrayList<RouteSegment>(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<BinaryRoutePlanner.RouteSegment>() {
@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<RouteSegment> graphSegments,
TLongObjectHashMap<RouteSegment> visitedSegments, TLongObjectHashMap<RouteSegment> oppositeSegments,
double distFromStart, double distToFinalPoint,
RouteSegment segment, int segmentEnd, RouteSegment inputNext,
boolean reverseWay) {
boolean thereAreRestrictions = proccessRestrictions(ctx, segment.road, inputNext, reverseWay);
Iterator<RouteSegment> 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<RouteSegmentResult> prepareResult(RoutingContext ctx, RouteSegment start, RouteSegment end, long startNanoTime,
RouteSegment finalDirectRoute, RouteSegment finalReverseRoute) {
List<RouteSegmentResult> result = new ArrayList<RouteSegmentResult>();
@ -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;
}
}
}

View file

@ -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<RouteSegment> routes = new TLongObjectHashMap<RouteSegment>();
TIntSet loadedTiles = new TIntHashSet();
// TODO delete this object ?
TLongObjectHashMap<RouteDataObject> idObjects = new TLongObjectHashMap<RouteDataObject>();
// 4. Warm object caches
TLongSet nonRestrictedIds = new TLongHashSet();
RouteSegment finalDirectRoute = null;
RouteSegment finalReverseRoute = null;
ArrayList<RouteSegment> segmentsToVisitPrescripted = new ArrayList<BinaryRoutePlanner.RouteSegment>(5);
ArrayList<RouteSegment> segmentsToVisitNotForbidden = new ArrayList<BinaryRoutePlanner.RouteSegment>(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<RouteDataObject> idObjects = new TLongObjectHashMap<RouteDataObject>();
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);

View file

@ -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", "улица", "ул."};

View file

@ -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<RouteSegment> cache = new ArrayList<RouteSegment>();
@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) {
}

View file

@ -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);

View file

@ -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()){

View file

@ -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);
}

View file

@ -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<Point, String> pointsToDraw = new LinkedHashMap<Point, String>();
private List<Line2D> linesToDraw = new ArrayList<Line2D>();
private List<LineObject> linesToDraw = new ArrayList<LineObject>();
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;

View file

@ -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<RouteSegment> cache = new ArrayList<RouteSegment>();
private List<RouteSegment> pollCache = new ArrayList<RouteSegment>();
@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<Way> points, boolean white,
List<RouteSegment> 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<RouteSegmentResult> 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());

View file

@ -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());
}

View file

@ -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);