Compare commits
10 commits
master
...
avoid_road
Author | SHA1 | Date | |
---|---|---|---|
|
ff03c5db19 | ||
|
3193c249ac | ||
|
a21d25d5e6 | ||
|
7839cb2c32 | ||
|
d464ea2182 | ||
|
547117f2ae | ||
|
a12812b564 | ||
|
53268f462a | ||
|
41b4e81fa0 | ||
|
bf7b067e8f |
20 changed files with 828 additions and 12 deletions
|
@ -20,6 +20,7 @@ public interface OsmAndCustomizationConstants {
|
||||||
String DRAWER_HELP_ID = DRAWER_ITEM_ID_SCHEME + "help";
|
String DRAWER_HELP_ID = DRAWER_ITEM_ID_SCHEME + "help";
|
||||||
String DRAWER_BUILDS_ID = DRAWER_ITEM_ID_SCHEME + "builds";
|
String DRAWER_BUILDS_ID = DRAWER_ITEM_ID_SCHEME + "builds";
|
||||||
String DRAWER_DIVIDER_ID = DRAWER_ITEM_ID_SCHEME + "divider";
|
String DRAWER_DIVIDER_ID = DRAWER_ITEM_ID_SCHEME + "divider";
|
||||||
|
String DRAWER_AVOID_ID = DRAWER_ITEM_ID_SCHEME + "avoid_roads";
|
||||||
|
|
||||||
// Configure Map:
|
// Configure Map:
|
||||||
String CONFIGURE_MAP_ITEM_ID_SCHEME = "map.configure.";
|
String CONFIGURE_MAP_ITEM_ID_SCHEME = "map.configure.";
|
||||||
|
|
|
@ -71,4 +71,5 @@ public class IndexConstants {
|
||||||
public static final String SETTINGS_DIR = "settings/"; //$NON-NLS-1$
|
public static final String SETTINGS_DIR = "settings/"; //$NON-NLS-1$
|
||||||
public static final String TEMP_DIR = "temp/";
|
public static final String TEMP_DIR = "temp/";
|
||||||
public static final String ROUTING_PROFILES_DIR = "routing/";
|
public static final String ROUTING_PROFILES_DIR = "routing/";
|
||||||
|
public static final String AVOID_ROADS_DIR = "avoidRoads/";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package net.osmand.binary;
|
package net.osmand.binary;
|
||||||
|
|
||||||
|
import net.osmand.Location;
|
||||||
import net.osmand.PlatformUtil;
|
import net.osmand.PlatformUtil;
|
||||||
import net.osmand.ResultMatcher;
|
import net.osmand.ResultMatcher;
|
||||||
import net.osmand.CollatorStringMatcher.StringMatcherMode;
|
import net.osmand.CollatorStringMatcher.StringMatcherMode;
|
||||||
|
@ -20,14 +21,17 @@ import net.osmand.util.MapUtils;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.text.Collator;
|
import java.text.Collator;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
@ -140,6 +144,73 @@ public class GeocodingUtilities {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface RouteSearchProgressCallback {
|
||||||
|
void onRouteFoundProgress(int percent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<RouteDataObject, Location> multipleReverseGeocodingSearch(RoutingContext ctx, List<Location> points, boolean allowEmptyNames, WeakReference<RouteSearchProgressCallback> progressCallbackWeakRef) throws IOException {
|
||||||
|
RoutePlannerFrontEnd rp = new RoutePlannerFrontEnd();
|
||||||
|
Map<RouteDataObject, Location> result = new HashMap<>();
|
||||||
|
int prevProgress = 0;
|
||||||
|
int batchSize = points.size();
|
||||||
|
for (int i = 0; i < batchSize; i++) {
|
||||||
|
Location point = points.get(i);
|
||||||
|
List<GeocodingResult> lst = new ArrayList<>();
|
||||||
|
List<RouteSegmentPoint> listR = new ArrayList<>();
|
||||||
|
rp.findRouteSegment(point.getLatitude(), point.getLongitude(), ctx, listR);
|
||||||
|
double distSquare = 0;
|
||||||
|
TLongHashSet set = new TLongHashSet();
|
||||||
|
Set<String> streetNames = new HashSet<String>();
|
||||||
|
for (RouteSegmentPoint p : listR) {
|
||||||
|
RouteDataObject road = p.getRoad();
|
||||||
|
if (!set.add(road.getId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String name = Algorithms.isEmpty(road.getName()) ? road.getRef("", false, true) : road.getName();
|
||||||
|
if (allowEmptyNames || !Algorithms.isEmpty(name)) {
|
||||||
|
if (distSquare == 0 || distSquare > p.distSquare) {
|
||||||
|
distSquare = p.distSquare;
|
||||||
|
}
|
||||||
|
GeocodingResult sr = new GeocodingResult();
|
||||||
|
sr.searchPoint = new LatLon(point.getLatitude(), point.getLongitude());
|
||||||
|
sr.streetName = name == null ? "" : name;
|
||||||
|
sr.point = p;
|
||||||
|
sr.connectionPoint = new LatLon(MapUtils.get31LatitudeY(p.preciseY), MapUtils.get31LongitudeX(p.preciseX));
|
||||||
|
sr.regionFP = road.region.getFilePointer();
|
||||||
|
sr.regionLen = road.region.getLength();
|
||||||
|
if (streetNames.add(sr.streetName)) {
|
||||||
|
lst.add(sr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (p.distSquare > STOP_SEARCHING_STREET_WITH_MULTIPLIER_RADIUS * STOP_SEARCHING_STREET_WITH_MULTIPLIER_RADIUS &&
|
||||||
|
distSquare != 0 && p.distSquare > THRESHOLD_MULTIPLIER_SKIP_STREETS_AFTER * distSquare) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (p.distSquare > STOP_SEARCHING_STREET_WITHOUT_MULTIPLIER_RADIUS * STOP_SEARCHING_STREET_WITHOUT_MULTIPLIER_RADIUS) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Collections.sort(lst, GeocodingUtilities.DISTANCE_COMPARATOR);
|
||||||
|
if (lst.size() > 0) {
|
||||||
|
Location ll = new Location("");
|
||||||
|
ll.setLatitude(lst.get(0).connectionPoint.getLatitude());
|
||||||
|
ll.setLongitude(lst.get(0).connectionPoint.getLongitude());
|
||||||
|
result.put(lst.get(0).point.getRoad(), ll);
|
||||||
|
// result.put(lst.get(0).point.getRoad(), point);
|
||||||
|
if (progressCallbackWeakRef.get() != null) {
|
||||||
|
int progress = (int) (i * 100.0/batchSize);
|
||||||
|
if (progress > prevProgress) {
|
||||||
|
progressCallbackWeakRef.get().onRouteFoundProgress(progress);
|
||||||
|
prevProgress = progress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// log.debug(String.format("Road %s", lst.get(0).point.getRoad()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.debug(String.format("Time to load %.3f s, time to findInitialSegment %.3f s, timeToLoadHeaders %.3f s, tiles loaded %d",
|
||||||
|
ctx.timeToLoad/1000000000.0f, ctx.timeToFindInitialSegments/1000000000.0f, ctx.timeToLoadHeaders/1000000000.0f, ctx.loadedTiles));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public List<GeocodingResult> reverseGeocodingSearch(RoutingContext ctx, double lat, double lon, boolean allowEmptyNames) throws IOException {
|
public List<GeocodingResult> reverseGeocodingSearch(RoutingContext ctx, double lat, double lon, boolean allowEmptyNames) throws IOException {
|
||||||
RoutePlannerFrontEnd rp = new RoutePlannerFrontEnd();
|
RoutePlannerFrontEnd rp = new RoutePlannerFrontEnd();
|
||||||
|
|
|
@ -9,6 +9,7 @@ import java.util.Comparator;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.osmand.Location;
|
||||||
import net.osmand.NativeLibrary;
|
import net.osmand.NativeLibrary;
|
||||||
import net.osmand.PlatformUtil;
|
import net.osmand.PlatformUtil;
|
||||||
import net.osmand.binary.BinaryMapIndexReader;
|
import net.osmand.binary.BinaryMapIndexReader;
|
||||||
|
|
|
@ -56,6 +56,7 @@ public class RoutingConfiguration {
|
||||||
private Map<String, GeneralRouter> routers = new LinkedHashMap<>();
|
private Map<String, GeneralRouter> routers = new LinkedHashMap<>();
|
||||||
private Map<String, String> attributes = new LinkedHashMap<>();
|
private Map<String, String> attributes = new LinkedHashMap<>();
|
||||||
private HashMap<Long, Location> impassableRoadLocations = new HashMap<>();
|
private HashMap<Long, Location> impassableRoadLocations = new HashMap<>();
|
||||||
|
private HashMap<Long, Location> roadsToAvoid = new HashMap<>();
|
||||||
|
|
||||||
// Example
|
// Example
|
||||||
// {
|
// {
|
||||||
|
@ -88,6 +89,7 @@ public class RoutingConfiguration {
|
||||||
i.recalculateDistance = parseSilentFloat(getAttribute(i.router, "recalculateDistanceHelp"), i.recalculateDistance) ;
|
i.recalculateDistance = parseSilentFloat(getAttribute(i.router, "recalculateDistanceHelp"), i.recalculateDistance) ;
|
||||||
i.heuristicCoefficient = parseSilentFloat(getAttribute(i.router, "heuristicCoefficient"), i.heuristicCoefficient);
|
i.heuristicCoefficient = parseSilentFloat(getAttribute(i.router, "heuristicCoefficient"), i.heuristicCoefficient);
|
||||||
i.router.addImpassableRoads(impassableRoadLocations.keySet());
|
i.router.addImpassableRoads(impassableRoadLocations.keySet());
|
||||||
|
i.router.addImpassableRoads(roadsToAvoid.keySet());
|
||||||
i.ZOOM_TO_LOAD_TILES = parseSilentInt(getAttribute(i.router, "zoomToLoadTiles"), i.ZOOM_TO_LOAD_TILES);
|
i.ZOOM_TO_LOAD_TILES = parseSilentInt(getAttribute(i.router, "zoomToLoadTiles"), i.ZOOM_TO_LOAD_TILES);
|
||||||
int desirable = parseSilentInt(getAttribute(i.router, "memoryLimitInMB"), 0);
|
int desirable = parseSilentInt(getAttribute(i.router, "memoryLimitInMB"), 0);
|
||||||
if(desirable != 0) {
|
if(desirable != 0) {
|
||||||
|
@ -114,7 +116,14 @@ public class RoutingConfiguration {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addMultipleImpassableRoads(Map<RouteDataObject, Location> ir) {
|
||||||
|
for (Map.Entry<RouteDataObject, Location> r : ir.entrySet()) {
|
||||||
|
if (!impassableRoadLocations.containsKey(r.getKey().id)){
|
||||||
|
impassableRoadLocations.put(r.getKey().id, r.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private String getAttribute(VehicleRouter router, String propertyName) {
|
private String getAttribute(VehicleRouter router, String propertyName) {
|
||||||
if (router.containsAttribute(propertyName)) {
|
if (router.containsAttribute(propertyName)) {
|
||||||
|
@ -140,6 +149,10 @@ public class RoutingConfiguration {
|
||||||
public void removeImpassableRoad(RouteDataObject obj) {
|
public void removeImpassableRoad(RouteDataObject obj) {
|
||||||
impassableRoadLocations.remove(obj.id);
|
impassableRoadLocations.remove(obj.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void clearImpassableRoads() {
|
||||||
|
impassableRoadLocations.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int parseSilentInt(String t, int v) {
|
public static int parseSilentInt(String t, int v) {
|
||||||
|
|
|
@ -92,10 +92,10 @@ public class RoutingContext {
|
||||||
public int memoryOverhead = 0;
|
public int memoryOverhead = 0;
|
||||||
|
|
||||||
|
|
||||||
long timeNanoToCalcDeviation = 0;
|
public long timeNanoToCalcDeviation = 0;
|
||||||
long timeToLoad = 0;
|
public long timeToLoad = 0;
|
||||||
long timeToLoadHeaders = 0;
|
public long timeToLoadHeaders = 0;
|
||||||
long timeToFindInitialSegments = 0;
|
public long timeToFindInitialSegments = 0;
|
||||||
public long timeToCalculate = 0;
|
public long timeToCalculate = 0;
|
||||||
|
|
||||||
int distinctLoadedTiles = 0;
|
int distinctLoadedTiles = 0;
|
||||||
|
@ -289,6 +289,7 @@ public class RoutingContext {
|
||||||
public void loadSubregionTile(final RoutingSubregionTile ts, boolean loadObjectsInMemory, List<RouteDataObject> toLoad, TLongHashSet excludeNotAllowed) {
|
public void loadSubregionTile(final RoutingSubregionTile ts, boolean loadObjectsInMemory, List<RouteDataObject> toLoad, TLongHashSet excludeNotAllowed) {
|
||||||
boolean wasUnloaded = ts.isUnloaded();
|
boolean wasUnloaded = ts.isUnloaded();
|
||||||
int ucount = ts.getUnloadCont();
|
int ucount = ts.getUnloadCont();
|
||||||
|
|
||||||
if (nativeLib == null) {
|
if (nativeLib == null) {
|
||||||
long now = System.nanoTime();
|
long now = System.nanoTime();
|
||||||
try {
|
try {
|
||||||
|
@ -321,7 +322,7 @@ public class RoutingContext {
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException("Loading data exception", e);
|
throw new RuntimeException("Loading data exception", e);
|
||||||
}
|
}
|
||||||
|
// log.debug(String.format("Load subregion: %s", ts.subregion.filePointer));
|
||||||
timeToLoad += (System.nanoTime() - now);
|
timeToLoad += (System.nanoTime() - now);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -438,7 +439,7 @@ public class RoutingContext {
|
||||||
long now = System.nanoTime();
|
long now = System.nanoTime();
|
||||||
for(int i = -t; i <= t; i++) {
|
for(int i = -t; i <= t; i++) {
|
||||||
for(int j = -t; j <= t; j++) {
|
for(int j = -t; j <= t; j++) {
|
||||||
ts.add(getRoutingTile(x31 +i*coordinatesShift, y31 + j*coordinatesShift, 0, OPTION_IN_MEMORY_LOAD));
|
ts.add(getRoutingTile(x31 +i*coordinatesShift, y31 + j*coordinatesShift, 0, OPTION_IN_MEMORY_LOAD));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TLongIterator it = ts.iterator();
|
TLongIterator it = ts.iterator();
|
||||||
|
|
|
@ -109,7 +109,7 @@ public class RouteResultPreparationTest {
|
||||||
String expectedResult = expectedResults.get(segmentId);
|
String expectedResult = expectedResults.get(segmentId);
|
||||||
if (expectedResult != null) {
|
if (expectedResult != null) {
|
||||||
if(!Algorithms.objectEquals(expectedResult, turnLanes) &&
|
if(!Algorithms.objectEquals(expectedResult, turnLanes) &&
|
||||||
!Algorithms.objectEquals(expectedResult, lanes) &&
|
!Algorithms.objectEquals(expectedResult, lanes) &&
|
||||||
!Algorithms.objectEquals(expectedResult, turn)) {
|
!Algorithms.objectEquals(expectedResult, turn)) {
|
||||||
Assert.assertEquals("Segment " + segmentId, expectedResult, turnLanes);
|
Assert.assertEquals("Segment " + segmentId, expectedResult, turnLanes);
|
||||||
}
|
}
|
||||||
|
|
13
OsmAnd/res/layout/avoid_roads_progress_dialog.xml
Normal file
13
OsmAnd/res/layout/avoid_roads_progress_dialog.xml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical" android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/avoid_route_pb"
|
||||||
|
style="?android:attr/progressBarStyleHorizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="@dimen/list_content_padding"
|
||||||
|
/>
|
||||||
|
</LinearLayout>
|
65
OsmAnd/res/layout/load_avoid_roads_dialog.xml
Normal file
65
OsmAnd/res/layout/load_avoid_roads_dialog.xml
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical" android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/message"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:padding="@dimen/list_content_padding"
|
||||||
|
android:textSize="@dimen/default_list_text_size"
|
||||||
|
android:textColor="?attr/textColorAlertDialogListItem"
|
||||||
|
android:text="Select how many Points you want to process from demo JSON or enter valid URL to custom JSON file with point in geoJSON format" />
|
||||||
|
|
||||||
|
<RadioGroup
|
||||||
|
android:id="@+id/point_quantity_selector"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingLeft="@dimen/list_content_padding"
|
||||||
|
android:paddingRight="@dimen/list_content_padding"
|
||||||
|
android:paddingBottom="@dimen/list_content_padding"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
|
<RadioButton
|
||||||
|
android:id="@+id/rb_select10"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="@dimen/list_content_padding"
|
||||||
|
android:text="10" />
|
||||||
|
|
||||||
|
<RadioButton
|
||||||
|
android:id="@+id/rb_select100"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="@dimen/list_content_padding"
|
||||||
|
android:text="100" />
|
||||||
|
|
||||||
|
<RadioButton
|
||||||
|
android:id="@+id/rb_select500"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="@dimen/list_content_padding"
|
||||||
|
android:text="500" />
|
||||||
|
|
||||||
|
</RadioGroup>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/json_url_et"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="@dimen/list_content_padding"
|
||||||
|
android:ems="10"
|
||||||
|
android:hint="URL to GeoJSON file"
|
||||||
|
android:text="" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progress_bar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -15,6 +15,7 @@
|
||||||
<string name="distance_and_address">%1$s • %2$s</string>
|
<string name="distance_and_address">%1$s • %2$s</string>
|
||||||
<string name="street_city">%1$s, %2$s</string>
|
<string name="street_city">%1$s, %2$s</string>
|
||||||
<string name="personal_category_name">Personal</string>
|
<string name="personal_category_name">Personal</string>
|
||||||
|
<string name="test_avoid_roads_menu_item">Avoid roads [test]</string>
|
||||||
<string name="add_new_profile_q">Add new profile \'%1$s\'?</string>
|
<string name="add_new_profile_q">Add new profile \'%1$s\'?</string>
|
||||||
<string name="save_heading">Include heading</string>
|
<string name="save_heading">Include heading</string>
|
||||||
<string name="save_heading_descr">Save heading to each trackpoint while recording.</string>
|
<string name="save_heading_descr">Save heading to each trackpoint while recording.</string>
|
||||||
|
|
|
@ -28,6 +28,7 @@ import net.osmand.plus.activities.DayNightHelper;
|
||||||
import net.osmand.plus.activities.LocalIndexHelper;
|
import net.osmand.plus.activities.LocalIndexHelper;
|
||||||
import net.osmand.plus.activities.LocalIndexInfo;
|
import net.osmand.plus.activities.LocalIndexInfo;
|
||||||
import net.osmand.plus.activities.SavingTrackHelper;
|
import net.osmand.plus.activities.SavingTrackHelper;
|
||||||
|
import net.osmand.plus.avoidroads.AvoidRoadsHelper;
|
||||||
import net.osmand.plus.base.MapViewTrackingUtilities;
|
import net.osmand.plus.base.MapViewTrackingUtilities;
|
||||||
import net.osmand.plus.download.DownloadActivity;
|
import net.osmand.plus.download.DownloadActivity;
|
||||||
import net.osmand.plus.download.ui.AbstractLoadLocalIndexTask;
|
import net.osmand.plus.download.ui.AbstractLoadLocalIndexTask;
|
||||||
|
@ -489,6 +490,7 @@ public class AppInitializer implements IProgress {
|
||||||
app.daynightHelper = startupInit(new DayNightHelper(app), DayNightHelper.class);
|
app.daynightHelper = startupInit(new DayNightHelper(app), DayNightHelper.class);
|
||||||
app.locationProvider = startupInit(new OsmAndLocationProvider(app), OsmAndLocationProvider.class);
|
app.locationProvider = startupInit(new OsmAndLocationProvider(app), OsmAndLocationProvider.class);
|
||||||
app.avoidSpecificRoads = startupInit(new AvoidSpecificRoads(app), AvoidSpecificRoads.class);
|
app.avoidSpecificRoads = startupInit(new AvoidSpecificRoads(app), AvoidSpecificRoads.class);
|
||||||
|
app.avoidRoadsHelper = startupInit(new AvoidRoadsHelper(app), AvoidRoadsHelper.class);
|
||||||
app.savingTrackHelper = startupInit(new SavingTrackHelper(app), SavingTrackHelper.class);
|
app.savingTrackHelper = startupInit(new SavingTrackHelper(app), SavingTrackHelper.class);
|
||||||
app.analyticsHelper = startupInit(new AnalyticsHelper(app), AnalyticsHelper.class);
|
app.analyticsHelper = startupInit(new AnalyticsHelper(app), AnalyticsHelper.class);
|
||||||
app.notificationHelper = startupInit(new NotificationHelper(app), NotificationHelper.class);
|
app.notificationHelper = startupInit(new NotificationHelper(app), NotificationHelper.class);
|
||||||
|
|
|
@ -23,10 +23,12 @@ import net.osmand.util.MapUtils;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
@ -56,6 +58,15 @@ public class CurrentPositionHelper {
|
||||||
return scheduleRouteSegmentFind(loc, false, true, cancelPreviousSearch, null, result, appMode);
|
return scheduleRouteSegmentFind(loc, false, true, cancelPreviousSearch, null, result, appMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean getMultipleRouteSegmentsIds(List<Location> points,
|
||||||
|
@Nullable ApplicationMode appMode,
|
||||||
|
boolean cancelPreviousSearch,
|
||||||
|
ResultMatcher<Map<RouteDataObject, Location>> result,
|
||||||
|
final WeakReference<GeocodingUtilities.RouteSearchProgressCallback> progressCallbackWeakRef) {
|
||||||
|
return scheduleMultipleRouteSegmentFind(points, false, true, cancelPreviousSearch, null, result, appMode, progressCallbackWeakRef);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public boolean getGeocodingResult(Location loc, ResultMatcher<GeocodingResult> result) {
|
public boolean getGeocodingResult(Location loc, ResultMatcher<GeocodingResult> result) {
|
||||||
return scheduleRouteSegmentFind(loc, false, false, true, result, null, null);
|
return scheduleRouteSegmentFind(loc, false, false, true, result, null, null);
|
||||||
}
|
}
|
||||||
|
@ -116,6 +127,93 @@ public class CurrentPositionHelper {
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean scheduleMultipleRouteSegmentFind(final List<Location> points,
|
||||||
|
final boolean storeFound,
|
||||||
|
final boolean allowEmptyNames,
|
||||||
|
final boolean cancelPreviousSearch,
|
||||||
|
@Nullable final ResultMatcher<GeocodingResult> geoCoding,
|
||||||
|
@Nullable final ResultMatcher<Map<RouteDataObject, Location>> result,
|
||||||
|
@Nullable final ApplicationMode appMode,
|
||||||
|
final WeakReference<GeocodingUtilities.RouteSearchProgressCallback> progressCallbackWeakRef) {
|
||||||
|
boolean res = false;
|
||||||
|
if (points.get(0) != null) {
|
||||||
|
long requestKey = getRequestNumberKey(storeFound, allowEmptyNames);
|
||||||
|
AtomicInteger requestNumber = requestNumbersMap.get(requestKey);
|
||||||
|
if (requestNumber == null) {
|
||||||
|
requestNumber = new AtomicInteger();
|
||||||
|
requestNumbersMap.put(requestKey, requestNumber);
|
||||||
|
}
|
||||||
|
final int request = requestNumber.incrementAndGet();
|
||||||
|
final AtomicInteger finalRequestNumber = requestNumber;
|
||||||
|
singleThreadExecutor.submit(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
processMultipleGeocoding(points, geoCoding, storeFound, allowEmptyNames, result, appMode, request, finalRequestNumber, cancelPreviousSearch, progressCallbackWeakRef);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
res = true;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void processMultipleGeocoding(@NonNull List<Location> points,
|
||||||
|
@Nullable ResultMatcher<GeocodingResult> geoCoding,
|
||||||
|
boolean storeFound,
|
||||||
|
boolean allowEmptyNames,
|
||||||
|
@Nullable final ResultMatcher<Map<RouteDataObject, Location>> result,
|
||||||
|
@Nullable ApplicationMode appMode,
|
||||||
|
int request,
|
||||||
|
@NonNull AtomicInteger requestNumber,
|
||||||
|
boolean cancelPreviousSearch,
|
||||||
|
WeakReference<GeocodingUtilities.RouteSearchProgressCallback> progressCallbackWeakRef) {
|
||||||
|
|
||||||
|
if (cancelPreviousSearch && request != requestNumber.get()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Map<RouteDataObject, Location> gr = runUpdateInThreadBatch(points,
|
||||||
|
geoCoding != null, allowEmptyNames, appMode, progressCallbackWeakRef);
|
||||||
|
|
||||||
|
if(result != null) {
|
||||||
|
app.runInUIThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
result.publish(gr == null || gr.isEmpty() ? null : gr);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private Map<RouteDataObject, Location> runUpdateInThreadBatch(List<Location> points,
|
||||||
|
boolean geocoding,
|
||||||
|
boolean allowEmptyNames,
|
||||||
|
@Nullable ApplicationMode appMode,
|
||||||
|
WeakReference<GeocodingUtilities.RouteSearchProgressCallback> progressCallbackWeakRef) {
|
||||||
|
|
||||||
|
List<BinaryMapReaderResource> checkReaders = usedReaders;
|
||||||
|
for (Location loc : points) {
|
||||||
|
checkReaders = checkReaders(loc.getLatitude(), loc.getLongitude(), checkReaders);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (appMode == null) {
|
||||||
|
appMode = app.getSettings().getApplicationMode();
|
||||||
|
}
|
||||||
|
if (ctx == null || am != appMode || checkReaders != usedReaders) {
|
||||||
|
initCtx(app, checkReaders, appMode);
|
||||||
|
if (ctx == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return new GeocodingUtilities().multipleReverseGeocodingSearch(geocoding ? defCtx : ctx, points, allowEmptyNames,progressCallbackWeakRef);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Exception happened during runUpdateInThread", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void initCtx(OsmandApplication app, List<BinaryMapReaderResource> checkReaders,
|
private void initCtx(OsmandApplication app, List<BinaryMapReaderResource> checkReaders,
|
||||||
@NonNull ApplicationMode appMode) {
|
@NonNull ApplicationMode appMode) {
|
||||||
|
@ -137,11 +235,11 @@ public class CurrentPositionHelper {
|
||||||
for (BinaryMapReaderResource rep : checkReaders) {
|
for (BinaryMapReaderResource rep : checkReaders) {
|
||||||
rs[i++] = rep.getReader(BinaryMapReaderResourceType.STREET_LOOKUP);
|
rs[i++] = rep.getReader(BinaryMapReaderResourceType.STREET_LOOKUP);
|
||||||
}
|
}
|
||||||
RoutingConfiguration cfg = app.getRoutingConfig().build(p, 10,
|
RoutingConfiguration cfg = app.getRoutingConfig().build(p, 100,
|
||||||
new HashMap<String, String>());
|
new HashMap<String, String>());
|
||||||
cfg.routeCalculationTime = System.currentTimeMillis();
|
cfg.routeCalculationTime = System.currentTimeMillis();
|
||||||
ctx = new RoutePlannerFrontEnd().buildRoutingContext(cfg, null, rs);
|
ctx = new RoutePlannerFrontEnd().buildRoutingContext(cfg, null, rs);
|
||||||
RoutingConfiguration defCfg = app.getRoutingConfig().build("geocoding", 10,
|
RoutingConfiguration defCfg = app.getRoutingConfig().build("geocoding", 100,
|
||||||
new HashMap<String, String>());
|
new HashMap<String, String>());
|
||||||
defCtx = new RoutePlannerFrontEnd().buildRoutingContext(defCfg, null, rs);
|
defCtx = new RoutePlannerFrontEnd().buildRoutingContext(defCfg, null, rs);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -2,17 +2,21 @@ package net.osmand.plus;
|
||||||
|
|
||||||
import android.os.Build.VERSION;
|
import android.os.Build.VERSION;
|
||||||
import android.os.Build.VERSION_CODES;
|
import android.os.Build.VERSION_CODES;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import net.osmand.GeoidAltitudeCorrection;
|
import net.osmand.GeoidAltitudeCorrection;
|
||||||
import net.osmand.PlatformUtil;
|
import net.osmand.PlatformUtil;
|
||||||
import net.osmand.ResultMatcher;
|
import net.osmand.ResultMatcher;
|
||||||
import net.osmand.access.NavigationInfo;
|
import net.osmand.access.NavigationInfo;
|
||||||
|
import net.osmand.binary.GeocodingUtilities;
|
||||||
import net.osmand.binary.GeocodingUtilities.GeocodingResult;
|
import net.osmand.binary.GeocodingUtilities.GeocodingResult;
|
||||||
import net.osmand.binary.RouteDataObject;
|
import net.osmand.binary.RouteDataObject;
|
||||||
import net.osmand.data.LatLon;
|
import net.osmand.data.LatLon;
|
||||||
|
@ -879,7 +883,15 @@ public class OsmAndLocationProvider implements SensorEventListener {
|
||||||
ResultMatcher<RouteDataObject> result) {
|
ResultMatcher<RouteDataObject> result) {
|
||||||
return currentPositionHelper.getRouteSegment(loc, appMode, cancelPreviousSearch, result);
|
return currentPositionHelper.getRouteSegment(loc, appMode, cancelPreviousSearch, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean getMultipleRouteSegmentsIds(List<net.osmand.Location> points,
|
||||||
|
@Nullable ApplicationMode appMode,
|
||||||
|
boolean cancelPreviousSearch,
|
||||||
|
ResultMatcher<Map<RouteDataObject, net.osmand.Location>> result,
|
||||||
|
final WeakReference<GeocodingUtilities.RouteSearchProgressCallback> progressCallbackWeakRef) {
|
||||||
|
return currentPositionHelper.getMultipleRouteSegmentsIds(points, appMode, cancelPreviousSearch, result, progressCallbackWeakRef);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean getGeocodingResult(net.osmand.Location loc, ResultMatcher<GeocodingResult> result) {
|
public boolean getGeocodingResult(net.osmand.Location loc, ResultMatcher<GeocodingResult> result) {
|
||||||
return currentPositionHelper.getGeocodingResult(loc, result);
|
return currentPositionHelper.getGeocodingResult(loc, result);
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ import net.osmand.plus.activities.MapActivity;
|
||||||
import net.osmand.plus.activities.SavingTrackHelper;
|
import net.osmand.plus.activities.SavingTrackHelper;
|
||||||
import net.osmand.plus.api.SQLiteAPI;
|
import net.osmand.plus.api.SQLiteAPI;
|
||||||
import net.osmand.plus.api.SQLiteAPIImpl;
|
import net.osmand.plus.api.SQLiteAPIImpl;
|
||||||
|
import net.osmand.plus.avoidroads.AvoidRoadsHelper;
|
||||||
import net.osmand.plus.base.MapViewTrackingUtilities;
|
import net.osmand.plus.base.MapViewTrackingUtilities;
|
||||||
import net.osmand.plus.dialogs.CrashBottomSheetDialogFragment;
|
import net.osmand.plus.dialogs.CrashBottomSheetDialogFragment;
|
||||||
import net.osmand.plus.dialogs.RateUsBottomSheetDialog;
|
import net.osmand.plus.dialogs.RateUsBottomSheetDialog;
|
||||||
|
@ -137,6 +138,7 @@ public class OsmandApplication extends MultiDexApplication {
|
||||||
LockHelper lockHelper;
|
LockHelper lockHelper;
|
||||||
SettingsHelper settingsHelper;
|
SettingsHelper settingsHelper;
|
||||||
GpxDbHelper gpxDbHelper;
|
GpxDbHelper gpxDbHelper;
|
||||||
|
AvoidRoadsHelper avoidRoadsHelper;
|
||||||
|
|
||||||
private RoutingConfiguration.Builder routingConfig;
|
private RoutingConfiguration.Builder routingConfig;
|
||||||
private Locale preferredLocale = null;
|
private Locale preferredLocale = null;
|
||||||
|
@ -340,6 +342,10 @@ public class OsmandApplication extends MultiDexApplication {
|
||||||
return settingsHelper;
|
return settingsHelper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AvoidRoadsHelper getAvoidRoadsHelper() {
|
||||||
|
return avoidRoadsHelper;
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized DownloadIndexesThread getDownloadThread() {
|
public synchronized DownloadIndexesThread getDownloadThread() {
|
||||||
if(downloadIndexesThread == null) {
|
if(downloadIndexesThread == null) {
|
||||||
downloadIndexesThread = new DownloadIndexesThread(this);
|
downloadIndexesThread = new DownloadIndexesThread(this);
|
||||||
|
|
|
@ -2593,6 +2593,7 @@ public class OsmandSettings {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private abstract class MapPointsStorage {
|
private abstract class MapPointsStorage {
|
||||||
|
|
||||||
protected String pointsKey;
|
protected String pointsKey;
|
||||||
|
@ -2787,6 +2788,7 @@ public class OsmandSettings {
|
||||||
return mImpassableRoadsStorage.insertPoint(latitude, longitude, null, 0);
|
return mImpassableRoadsStorage.insertPoint(latitude, longitude, null, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean removeImpassableRoad(int index) {
|
public boolean removeImpassableRoad(int index) {
|
||||||
return mImpassableRoadsStorage.deletePoint(index);
|
return mImpassableRoadsStorage.deletePoint(index);
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_AVOID_ID;
|
||||||
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_CONFIGURE_MAP_ID;
|
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_CONFIGURE_MAP_ID;
|
||||||
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_CONFIGURE_SCREEN_ID;
|
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_CONFIGURE_SCREEN_ID;
|
||||||
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_DASHBOARD_ID;
|
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_DASHBOARD_ID;
|
||||||
|
@ -971,6 +972,19 @@ public class MapActivityActions implements DialogProvider {
|
||||||
}
|
}
|
||||||
}).createItem());
|
}).createItem());
|
||||||
|
|
||||||
|
optionsMenuHelper.addItem(new ItemBuilder().setTitleId(R.string.test_avoid_roads_menu_item, mapActivity)
|
||||||
|
.setId(DRAWER_AVOID_ID)
|
||||||
|
.setIcon(R.drawable.ic_action_road_works_dark)
|
||||||
|
.setListener(new ItemClickListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onContextMenuClick(ArrayAdapter<ContextMenuItem> adapter, int itemId, int pos, boolean isChecked, int[] viewCoordinates) {
|
||||||
|
app.logEvent("drawer_import_avoid_roads");
|
||||||
|
app.getAvoidRoadsHelper().showUrlDialog(mapActivity);
|
||||||
|
// app.getAvoidRoadsHelper().testRunDownload();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}).createItem());
|
||||||
|
|
||||||
//////////// Others
|
//////////// Others
|
||||||
OsmandPlugin.registerOptionsMenu(mapActivity, optionsMenuHelper);
|
OsmandPlugin.registerOptionsMenu(mapActivity, optionsMenuHelper);
|
||||||
|
|
||||||
|
|
474
OsmAnd/src/net/osmand/plus/avoidroads/AvoidRoadsHelper.java
Normal file
474
OsmAnd/src/net/osmand/plus/avoidroads/AvoidRoadsHelper.java
Normal file
|
@ -0,0 +1,474 @@
|
||||||
|
package net.osmand.plus.avoidroads;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
|
import android.widget.RadioButton;
|
||||||
|
import android.widget.RadioGroup;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.annotations.Expose;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
import net.osmand.IndexConstants;
|
||||||
|
import net.osmand.Location;
|
||||||
|
import net.osmand.PlatformUtil;
|
||||||
|
import net.osmand.ResultMatcher;
|
||||||
|
import net.osmand.binary.GeocodingUtilities;
|
||||||
|
import net.osmand.binary.RouteDataObject;
|
||||||
|
import net.osmand.data.QuadRect;
|
||||||
|
import net.osmand.data.QuadTree;
|
||||||
|
import net.osmand.osm.io.NetworkUtils;
|
||||||
|
import net.osmand.plus.ApplicationMode;
|
||||||
|
import net.osmand.plus.OsmandApplication;
|
||||||
|
import net.osmand.plus.R;
|
||||||
|
import net.osmand.plus.activities.MapActivity;
|
||||||
|
import net.osmand.util.Algorithms;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
public class AvoidRoadsHelper {
|
||||||
|
|
||||||
|
private static final Log LOG = PlatformUtil.getLog(AvoidRoadsHelper.class);
|
||||||
|
|
||||||
|
private static final int FROM_URL = 101;
|
||||||
|
private static final int FROM_STORAGE = 100;
|
||||||
|
private static final int SOURCE = FROM_STORAGE;
|
||||||
|
|
||||||
|
|
||||||
|
private final Map<RouteDataObject, Location> roadsToAvoid;
|
||||||
|
private final List<Location> parsedPoints;
|
||||||
|
private final OsmandApplication app;
|
||||||
|
private final ApplicationMode appMode;
|
||||||
|
private GeocodingUtilities.RouteSearchProgressCallback ppc;
|
||||||
|
private ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
|
||||||
|
|
||||||
|
private CompletionCallback completionCallback;
|
||||||
|
private UpdateProgressCallback progressDialogCallback;
|
||||||
|
private WeakReference<MapActivity> mapActivityWeakReference = null;
|
||||||
|
|
||||||
|
private static boolean saveResultToFile = false;
|
||||||
|
|
||||||
|
private long timeStart;
|
||||||
|
private long timeDownload;
|
||||||
|
private long timeParsePoints;
|
||||||
|
private long timeFindSegments;
|
||||||
|
|
||||||
|
private AlertDialog pDialog;
|
||||||
|
|
||||||
|
private final int[] pointsToProcess = {-1};
|
||||||
|
// private String inputFileName = "points_500.json";
|
||||||
|
// private String inputFileName = "point_100.json";
|
||||||
|
private String inputFileName = "points_10.json";
|
||||||
|
// private String testurl = "https://gist.githubusercontent.com/MadWasp79/1238d8878792572e343eb2e296c3c7f5/raw/494f872425993797c3a3bc79a4ec82039db6ee46/point_100.json";
|
||||||
|
private String testurl = "https://gist.githubusercontent.com/MadWasp79/45f362ea48e9e8edd1593113593993c5/raw/6e817fb3bc7eaeaa3eda24847fde4855eb22485d/points_500.json";
|
||||||
|
|
||||||
|
|
||||||
|
public AvoidRoadsHelper(final OsmandApplication app) {
|
||||||
|
this.app = app;
|
||||||
|
this.appMode = app.getSettings().getApplicationMode();
|
||||||
|
this.roadsToAvoid = new LinkedHashMap<>();
|
||||||
|
this.parsedPoints = new ArrayList<>();
|
||||||
|
|
||||||
|
completionCallback = new CompletionCallback() {
|
||||||
|
@Override
|
||||||
|
public void onRDOSearchComplete() {
|
||||||
|
timeFindSegments = System.currentTimeMillis();
|
||||||
|
if (pDialog.isShowing()) {
|
||||||
|
pDialog.dismiss();
|
||||||
|
}
|
||||||
|
pDialog = null;
|
||||||
|
if (saveResultToFile) {
|
||||||
|
File out = new File (app.getAppPath(IndexConstants.AVOID_ROADS_DIR).getAbsolutePath() + "/processed_ids.json");
|
||||||
|
saveRoadsToJson(roadsToAvoid, out);
|
||||||
|
}
|
||||||
|
app.getAvoidRoadsHelper().addResultToImpassibleRoads(roadsToAvoid);
|
||||||
|
MapActivity mapActivity = mapActivityWeakReference.get();
|
||||||
|
if (mapActivity != null) {
|
||||||
|
app.getAvoidRoadsHelper().showParsingCompleteDialog(mapActivity);
|
||||||
|
} else {
|
||||||
|
app.showToastMessage("Successfully processed roads to avoid. Applying result to routing parameters");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPointsParsed(List<Location> result) {
|
||||||
|
app.getRoutingConfig().clearImpassableRoads();
|
||||||
|
parsedPoints.clear();
|
||||||
|
parsedPoints.addAll(result);
|
||||||
|
final MapActivity mapActivity = mapActivityWeakReference.get();
|
||||||
|
if (mapActivity != null) {
|
||||||
|
if (pDialog == null) {
|
||||||
|
pDialog = buildProgressDialog(mapActivity).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
convertPointsToRDO(parsedPoints);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ppc = new GeocodingUtilities.RouteSearchProgressCallback() {
|
||||||
|
@Override
|
||||||
|
public void onRouteFoundProgress(int percent) {
|
||||||
|
LOG.debug("Progress: " + percent);
|
||||||
|
final MapActivity mapActivity = mapActivityWeakReference.get();
|
||||||
|
if (mapActivity != null) {
|
||||||
|
// if (!pDialog.isShowing()) {
|
||||||
|
// pDialog.show();
|
||||||
|
// }
|
||||||
|
final ProgressBar pb = (ProgressBar) ((AlertDialog) pDialog).findViewById(R.id.avoid_route_pb);
|
||||||
|
pb.setProgress(percent);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testRun() {
|
||||||
|
String in = "";
|
||||||
|
switch (SOURCE) {
|
||||||
|
case FROM_STORAGE:
|
||||||
|
in = app.getAppPath(IndexConstants.AVOID_ROADS_DIR).getAbsolutePath() + "/" + inputFileName;
|
||||||
|
LOG.debug(String.format("Input json from file: %s", in));
|
||||||
|
break;
|
||||||
|
case FROM_URL:
|
||||||
|
LOG.debug(String.format("Loading json from url: %s", in));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadJson(in, SOURCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Map<RouteDataObject, Location> getRoadsToAvoid() {
|
||||||
|
return roadsToAvoid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addResultToImpassibleRoads(Map<RouteDataObject, Location> result) {
|
||||||
|
app.getRoutingConfig().addMultipleImpassableRoads(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AlertDialog.Builder buildProgressDialog(final MapActivity activity) {
|
||||||
|
|
||||||
|
AlertDialog.Builder adb = new AlertDialog.Builder(activity);
|
||||||
|
adb.setMessage("Determining Roads to Avoid...");
|
||||||
|
final View dialogProgressView = activity.getLayoutInflater().inflate(R.layout.avoid_roads_progress_dialog, null);
|
||||||
|
adb.setView(dialogProgressView);
|
||||||
|
return adb;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showUrlDialog(final MapActivity activity) {
|
||||||
|
mapActivityWeakReference = new WeakReference<MapActivity>(activity);
|
||||||
|
pointsToProcess[0] = -1;
|
||||||
|
final AlertDialog.Builder db = new AlertDialog.Builder(activity);
|
||||||
|
final View dialogView = activity.getLayoutInflater().inflate(R.layout.load_avoid_roads_dialog, null);
|
||||||
|
final RadioGroup rg = (RadioGroup) dialogView.findViewById(R.id.point_quantity_selector);
|
||||||
|
final EditText urlEt = (EditText) dialogView.findViewById(R.id.json_url_et);
|
||||||
|
db.setTitle("Process Avoid Roads");
|
||||||
|
db.setView(dialogView);
|
||||||
|
db.setIcon(R.drawable.map_pin_avoid_road);
|
||||||
|
db.setPositiveButton("Parse", new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
boolean isValidJsonUrl = false;
|
||||||
|
int selectedId = rg.getCheckedRadioButtonId();
|
||||||
|
RadioButton rb = (RadioButton) dialogView.findViewById(selectedId);
|
||||||
|
if (rb != null) {
|
||||||
|
switch (rb.getText().toString()) {
|
||||||
|
case "10":
|
||||||
|
pointsToProcess[0] = 10;
|
||||||
|
break;
|
||||||
|
case "100":
|
||||||
|
pointsToProcess[0] = 100;
|
||||||
|
break;
|
||||||
|
case "500":
|
||||||
|
pointsToProcess[0] = 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String urlFromEt = urlEt.getText().toString();
|
||||||
|
if (Algorithms.isEmpty(urlFromEt)) {
|
||||||
|
urlFromEt = testurl;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
URL test = new URL(urlFromEt);
|
||||||
|
if (urlFromEt.endsWith(".json")) {
|
||||||
|
isValidJsonUrl = true;
|
||||||
|
}
|
||||||
|
} catch (MalformedURLException e){
|
||||||
|
isValidJsonUrl = false;
|
||||||
|
app.showShortToastMessage("Enter valid JSON url!");
|
||||||
|
}
|
||||||
|
if (isValidJsonUrl) {
|
||||||
|
timeStart = System.currentTimeMillis();
|
||||||
|
app.showShortToastMessage("Downloading JSON");
|
||||||
|
loadJson(urlFromEt, FROM_URL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
db.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
pointsToProcess[0] = -1;
|
||||||
|
dialog.dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
db.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showParsingCompleteDialog(final MapActivity activity) {
|
||||||
|
final AlertDialog.Builder db = new AlertDialog.Builder(activity);
|
||||||
|
db.setTitle("Processing complete!");
|
||||||
|
db.setMessage(String.format("Found %d unique roads to avoid.\n" +
|
||||||
|
"Time to download: %.3fs\n" +
|
||||||
|
"Time to parse JSON: %.3fs\n" +
|
||||||
|
"Time to find roads: %.3fs\n",
|
||||||
|
roadsToAvoid.size(),
|
||||||
|
(timeDownload-timeStart)/1000.0f,
|
||||||
|
(timeParsePoints-timeDownload)/1000.0f,
|
||||||
|
(timeFindSegments-timeParsePoints)/1000.0f));
|
||||||
|
db.setIcon(R.drawable.map_pin_avoid_road);
|
||||||
|
db.setPositiveButton("OK", new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
dialog.dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
db.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void convertPointsToRDO(final List<Location> parsedPoints) {
|
||||||
|
this.roadsToAvoid.clear();
|
||||||
|
app.getLocationProvider().getMultipleRouteSegmentsIds(parsedPoints, appMode, false,
|
||||||
|
new ResultMatcher<Map<RouteDataObject, Location>>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean publish(Map<RouteDataObject, Location> result) {
|
||||||
|
if (result == null || result.isEmpty()) {
|
||||||
|
LOG.error("Error! No valid result");
|
||||||
|
} else {
|
||||||
|
roadsToAvoid.putAll(result);
|
||||||
|
LOG.debug(String.format("Found %d road ids", result.size()));
|
||||||
|
app.getAvoidRoadsHelper().completionCallback.onRDOSearchComplete();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}, new WeakReference<GeocodingUtilities.RouteSearchProgressCallback>(ppc));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("StaticFieldLeak")
|
||||||
|
public void loadJson(final String path, final int source) {
|
||||||
|
new AsyncTask<Void, Void, List<Location>>() {
|
||||||
|
@Override
|
||||||
|
protected List<Location> doInBackground(Void... voids) {
|
||||||
|
InputStream is = null;
|
||||||
|
try {
|
||||||
|
switch(source) {
|
||||||
|
case FROM_STORAGE:
|
||||||
|
is = new FileInputStream(path);
|
||||||
|
break;
|
||||||
|
case FROM_URL:
|
||||||
|
URLConnection connection = NetworkUtils.getHttpURLConnection(path);
|
||||||
|
is = connection.getInputStream();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Location> result = new ArrayList<>();
|
||||||
|
timeDownload = System.currentTimeMillis();
|
||||||
|
parseJson(is, result);
|
||||||
|
if (is != null) {
|
||||||
|
is.close();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error("Error reading json!");
|
||||||
|
} finally {
|
||||||
|
if (is != null) {
|
||||||
|
try {
|
||||||
|
is.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(List<Location> result) {
|
||||||
|
if (!Algorithms.isEmpty(result)) {
|
||||||
|
app.getAvoidRoadsHelper().completionCallback.onPointsParsed(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.executeOnExecutor(singleThreadExecutor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseJson(InputStream is, List<Location> result) {
|
||||||
|
Gson gson = new Gson();
|
||||||
|
GeoJSON geoJSON = gson.fromJson(new BufferedReader(new InputStreamReader(is)), GeoJSON.class);
|
||||||
|
double minlat = 0 , maxlat = 0, minlon = 0, maxlon= 0;
|
||||||
|
boolean first = true;
|
||||||
|
int limit = pointsToProcess[0];
|
||||||
|
if (limit == -1 || limit > geoJSON.points.size()) {
|
||||||
|
limit = geoJSON.points.size();
|
||||||
|
}
|
||||||
|
for (int i = 0; i < limit; i++) {
|
||||||
|
Point o = geoJSON.points.get(i);
|
||||||
|
Location ll = new Location("geoJSON");
|
||||||
|
double lat = o.geo.coordinates.get(1);
|
||||||
|
double lon = o.geo.coordinates.get(0);
|
||||||
|
if(first) {
|
||||||
|
minlat = maxlat = lat;
|
||||||
|
minlon = maxlon = lon;
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
minlat = Math.min(minlat, lat);
|
||||||
|
minlon = Math.min(minlon, lon);
|
||||||
|
maxlat = Math.max(maxlat, lat);
|
||||||
|
maxlon = Math.max(maxlon, lon);
|
||||||
|
}
|
||||||
|
ll.setLatitude(lat);
|
||||||
|
ll.setLongitude(lon);
|
||||||
|
result.add(ll);
|
||||||
|
}
|
||||||
|
QuadRect qr = new QuadRect(minlon, minlat, maxlon, maxlat);
|
||||||
|
QuadTree<Location> qt = new QuadTree<Location>(qr, 8, 0.55f);
|
||||||
|
for(Location l : result) {
|
||||||
|
qt.insert(l, (float)l.getLongitude(), (float) l.getLatitude());
|
||||||
|
}
|
||||||
|
qt.queryInBox(qr, result);
|
||||||
|
timeParsePoints = System.currentTimeMillis();
|
||||||
|
app.showShortToastMessage(String.format("Loaded and parsed %d points from JSON. Starting segment search.", result.size()));
|
||||||
|
LOG.debug(String.format("Points parsed: %d", result.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("StaticFieldLeak")
|
||||||
|
private void saveRoadsToJson(final Map<RouteDataObject, Location> roadsToAvoid, final File out) {
|
||||||
|
new AsyncTask<Void, Void, Void>() {
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground(Void... voids) {
|
||||||
|
FileWriter fileWriter = null;
|
||||||
|
if (out.exists()) {
|
||||||
|
out.delete();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Gson gson = new Gson();
|
||||||
|
fileWriter = new FileWriter(out, true);
|
||||||
|
gson.toJson(new RoadsToAvoid (roadsToAvoid), fileWriter);
|
||||||
|
fileWriter.close();
|
||||||
|
LOG.info(String.format("File saved: %s ", out.getAbsolutePath()));
|
||||||
|
} catch (Exception e) {
|
||||||
|
//inform user about error
|
||||||
|
LOG.error("Error writing file");
|
||||||
|
} finally {
|
||||||
|
if (fileWriter != null) {
|
||||||
|
try {
|
||||||
|
fileWriter.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}.executeOnExecutor(singleThreadExecutor);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CompletionCallback {
|
||||||
|
void onRDOSearchComplete();
|
||||||
|
void onPointsParsed(List<Location> result);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateProgressCallback {
|
||||||
|
void onProgressUpdate(int progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class GeoJSON {
|
||||||
|
@SerializedName("type")
|
||||||
|
@Expose
|
||||||
|
String type;
|
||||||
|
@SerializedName("features")
|
||||||
|
@Expose
|
||||||
|
List<Point> points = null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class Point {
|
||||||
|
@SerializedName("type")
|
||||||
|
@Expose
|
||||||
|
String type;
|
||||||
|
@SerializedName("geometry")
|
||||||
|
@Expose
|
||||||
|
Geometry geo;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Geometry {
|
||||||
|
@SerializedName("type")
|
||||||
|
@Expose
|
||||||
|
String type;
|
||||||
|
@SerializedName("coordinates")
|
||||||
|
@Expose
|
||||||
|
List<Double> coordinates = null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class RoadsToAvoid {
|
||||||
|
@SerializedName("avoid_roads")
|
||||||
|
@Expose
|
||||||
|
List<RoadToAvoid> roadsToAvoid;
|
||||||
|
|
||||||
|
public RoadsToAvoid(Map<RouteDataObject, Location> roads) {
|
||||||
|
this.roadsToAvoid = new ArrayList<>();
|
||||||
|
for (Map.Entry<RouteDataObject, Location> road : roads.entrySet()) {
|
||||||
|
roadsToAvoid.add(new RoadToAvoid (road.getKey().id >> 6, road.getValue().getLatitude(), road.getValue().getLongitude()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RoadToAvoid {
|
||||||
|
@SerializedName("road_id")
|
||||||
|
@Expose
|
||||||
|
long roadId;
|
||||||
|
@SerializedName("lat")
|
||||||
|
@Expose
|
||||||
|
double lat;
|
||||||
|
@SerializedName("lon")
|
||||||
|
@Expose
|
||||||
|
double lon;
|
||||||
|
|
||||||
|
RoadToAvoid(long roadId, double lat, double lon) {
|
||||||
|
this.roadId = roadId;
|
||||||
|
this.lat = lat;
|
||||||
|
this.lon = lon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -19,6 +19,7 @@ import android.widget.Toast;
|
||||||
|
|
||||||
import net.osmand.CallbackWithObject;
|
import net.osmand.CallbackWithObject;
|
||||||
import net.osmand.Location;
|
import net.osmand.Location;
|
||||||
|
import net.osmand.PlatformUtil;
|
||||||
import net.osmand.ResultMatcher;
|
import net.osmand.ResultMatcher;
|
||||||
import net.osmand.binary.RouteDataObject;
|
import net.osmand.binary.RouteDataObject;
|
||||||
import net.osmand.data.LatLon;
|
import net.osmand.data.LatLon;
|
||||||
|
@ -34,12 +35,14 @@ import net.osmand.plus.routing.RoutingHelper;
|
||||||
import net.osmand.plus.views.ContextMenuLayer;
|
import net.osmand.plus.views.ContextMenuLayer;
|
||||||
import net.osmand.util.MapUtils;
|
import net.osmand.util.MapUtils;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class AvoidSpecificRoads {
|
public class AvoidSpecificRoads {
|
||||||
|
private static final Log LOG = PlatformUtil.getLog(AvoidSpecificRoads.class);
|
||||||
private OsmandApplication app;
|
private OsmandApplication app;
|
||||||
|
|
||||||
private Map<LatLon, RouteDataObject> impassableRoads = new LinkedHashMap<>();
|
private Map<LatLon, RouteDataObject> impassableRoads = new LinkedHashMap<>();
|
||||||
|
|
|
@ -253,6 +253,10 @@ public class ResourceManager {
|
||||||
if (!path.exists()) {
|
if (!path.exists()) {
|
||||||
path.mkdir();
|
path.mkdir();
|
||||||
}
|
}
|
||||||
|
path = context.getAppPath(IndexConstants.AVOID_ROADS_DIR);
|
||||||
|
if (!path.exists()) {
|
||||||
|
path.mkdir();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public BitmapTilesCache getBitmapTilesCache() {
|
public BitmapTilesCache getBitmapTilesCache() {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import android.graphics.PointF;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
|
import net.osmand.Location;
|
||||||
import net.osmand.binary.RouteDataObject;
|
import net.osmand.binary.RouteDataObject;
|
||||||
import net.osmand.data.LatLon;
|
import net.osmand.data.LatLon;
|
||||||
import net.osmand.data.PointDescription;
|
import net.osmand.data.PointDescription;
|
||||||
|
@ -17,6 +18,7 @@ import net.osmand.data.RotatedTileBox;
|
||||||
import net.osmand.plus.OsmandApplication;
|
import net.osmand.plus.OsmandApplication;
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
import net.osmand.plus.activities.MapActivity;
|
import net.osmand.plus.activities.MapActivity;
|
||||||
|
import net.osmand.plus.avoidroads.AvoidRoadsHelper;
|
||||||
import net.osmand.plus.helpers.AvoidSpecificRoads;
|
import net.osmand.plus.helpers.AvoidSpecificRoads;
|
||||||
import net.osmand.plus.helpers.AvoidSpecificRoads.AvoidSpecificRoadsCallback;
|
import net.osmand.plus.helpers.AvoidSpecificRoads.AvoidSpecificRoadsCallback;
|
||||||
import net.osmand.plus.views.ContextMenuLayer.ApplyMovedObjectCallback;
|
import net.osmand.plus.views.ContextMenuLayer.ApplyMovedObjectCallback;
|
||||||
|
@ -31,6 +33,7 @@ public class ImpassableRoadsLayer extends OsmandMapLayer implements
|
||||||
|
|
||||||
private final MapActivity activity;
|
private final MapActivity activity;
|
||||||
private AvoidSpecificRoads avoidSpecificRoads;
|
private AvoidSpecificRoads avoidSpecificRoads;
|
||||||
|
private AvoidRoadsHelper avoidRoadsHelper;
|
||||||
private ContextMenuLayer contextMenuLayer;
|
private ContextMenuLayer contextMenuLayer;
|
||||||
|
|
||||||
private Bitmap roadWorkIcon;
|
private Bitmap roadWorkIcon;
|
||||||
|
@ -44,6 +47,7 @@ public class ImpassableRoadsLayer extends OsmandMapLayer implements
|
||||||
@Override
|
@Override
|
||||||
public void initLayer(OsmandMapTileView view) {
|
public void initLayer(OsmandMapTileView view) {
|
||||||
avoidSpecificRoads = activity.getMyApplication().getAvoidSpecificRoads();
|
avoidSpecificRoads = activity.getMyApplication().getAvoidSpecificRoads();
|
||||||
|
avoidRoadsHelper = activity.getMyApplication().getAvoidRoadsHelper();
|
||||||
contextMenuLayer = view.getLayerByClass(ContextMenuLayer.class);
|
contextMenuLayer = view.getLayerByClass(ContextMenuLayer.class);
|
||||||
roadWorkIcon = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_pin_avoid_road);
|
roadWorkIcon = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_pin_avoid_road);
|
||||||
activePaint = new Paint();
|
activePaint = new Paint();
|
||||||
|
@ -80,6 +84,23 @@ public class ImpassableRoadsLayer extends OsmandMapLayer implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tileBox.getZoom() > START_ZOOM + 1) {
|
||||||
|
for (Map.Entry<RouteDataObject, Location> entry : avoidRoadsHelper.getRoadsToAvoid().entrySet()) {
|
||||||
|
RouteDataObject rdo = entry.getKey();
|
||||||
|
if (rdo != null && contextMenuLayer.getMoveableObject() instanceof RouteDataObject) {
|
||||||
|
RouteDataObject object = (RouteDataObject) contextMenuLayer.getMoveableObject();
|
||||||
|
if (object.id == rdo.id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final double lat = entry.getValue().getLatitude();
|
||||||
|
final double lon = entry.getValue().getLongitude();
|
||||||
|
if (tileBox.containsLatLon(lat, lon)) {
|
||||||
|
drawPoint(canvas, tileBox, lat, lon, rdo != null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawPoint(Canvas canvas, RotatedTileBox tileBox, double latitude, double longitude, boolean active) {
|
private void drawPoint(Canvas canvas, RotatedTileBox tileBox, double latitude, double longitude, boolean active) {
|
||||||
|
@ -158,6 +179,19 @@ public class ImpassableRoadsLayer extends OsmandMapLayer implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (Map.Entry<RouteDataObject, Location> entry : avoidRoadsHelper.getRoadsToAvoid().entrySet()) {
|
||||||
|
LatLon location = new LatLon(entry.getValue().getLatitude(), entry.getValue().getLongitude());
|
||||||
|
RouteDataObject road = entry.getKey();
|
||||||
|
if (location != null && road != null) {
|
||||||
|
int x = (int) tileBox.getPixXFromLatLon(location.getLatitude(), location.getLongitude());
|
||||||
|
int y = (int) tileBox.getPixYFromLatLon(location.getLatitude(), location.getLongitude());
|
||||||
|
if (calculateBelongs(ex, ey, x, y, compare)) {
|
||||||
|
compare = radius;
|
||||||
|
o.add(road);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue