Update binary router
This commit is contained in:
parent
4a8ff5ba10
commit
399378b585
22 changed files with 583 additions and 385 deletions
|
@ -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) {
|
||||
|
|
|
@ -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 ;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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", "улица", "ул."};
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()){
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue