Add snap to road

This commit is contained in:
Alexander Sytnyk 2017-10-04 15:05:01 +03:00
parent 880ac5c5d7
commit b76ed9e0a7
3 changed files with 255 additions and 74 deletions

View file

@ -788,9 +788,9 @@ public class DashboardOnMap implements ObservableScrollViewCallbacks, DynamicLis
mapActivity.enableDrawer();
getMyApplication().getMapMarkersHelper().removeListener(this);
if (mapActivity.getMapLayers().getMapMarkersLayer().clearRoute()) {
mapActivity.refreshMap();
}
// if (mapActivity.getMapLayers().getMapMarkersLayer().clearRoute()) {
// mapActivity.refreshMap();
// }
if (swipeDismissListener != null) {
swipeDismissListener.discardUndo();
}
@ -1691,7 +1691,7 @@ public class DashboardOnMap implements ObservableScrollViewCallbacks, DynamicLis
public void showMarkersRouteOnMap() {
MapMarkersHelper helper = getMyApplication().getMapMarkersHelper();
List<LatLon> points = helper.getSelectedMarkersLatLon();
mapActivity.getMapLayers().getMapMarkersLayer().setRoute(points);
// mapActivity.getMapLayers().getMapMarkersLayer().setRoute(points);
showRouteOnMap(points);
}

View file

@ -13,6 +13,7 @@ import android.support.v4.content.ContextCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.util.Pair;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
@ -20,6 +21,7 @@ import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
@ -29,6 +31,8 @@ import net.osmand.TspAnt;
import net.osmand.data.LatLon;
import net.osmand.data.RotatedTileBox;
import net.osmand.plus.ApplicationMode;
import net.osmand.plus.GPXUtilities.TrkSegment;
import net.osmand.plus.GPXUtilities.WptPt;
import net.osmand.plus.IconsCache;
import net.osmand.plus.MapMarkersHelper;
import net.osmand.plus.MapMarkersHelper.MapMarker;
@ -44,14 +48,23 @@ import net.osmand.plus.mapmarkers.adapters.MapMarkersListAdapter;
import net.osmand.plus.measurementtool.RecyclerViewFragment;
import net.osmand.plus.measurementtool.SnapToRoadBottomSheetDialogFragment;
import net.osmand.plus.measurementtool.SnapToRoadBottomSheetDialogFragment.SnapToRoadFragmentListener;
import net.osmand.plus.routing.RouteCalculationParams;
import net.osmand.plus.routing.RoutingHelper;
import net.osmand.plus.views.MapMarkersLayer;
import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory;
import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopToolbarController;
import net.osmand.router.RouteCalculationProgress;
import net.osmand.util.MapUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import static net.osmand.plus.OsmandSettings.LANDSCAPE_MIDDLE_RIGHT_CONSTANT;
@ -81,6 +94,13 @@ public class PlanRouteFragment extends Fragment {
private TextView timeTv;
private TextView countTv;
private final Queue<Pair<WptPt, WptPt>> snapToRoadPairsToCalculate = new ConcurrentLinkedQueue<>();
private final Map<Pair<WptPt, WptPt>, List<WptPt>> snappedToRoadPoints = new ConcurrentHashMap<>();
private TrkSegment snapTrkSegment = new TrkSegment();
private RouteCalculationProgress calculationProgress;
private int calculatedPairs;
private boolean progressBarVisible;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
@ -158,9 +178,8 @@ public class PlanRouteFragment extends Fragment {
}
adapter.calculateStartAndFinishPos();
adapter.notifyDataSetChanged();
updateText();
updateSelectButton();
showMarkersRouteOnMap();
recreateSnapTrkSegment();
mapActivity.refreshMap();
}
});
@ -227,8 +246,7 @@ public class PlanRouteFragment extends Fragment {
adapter.calculateStartAndFinishPos();
adapter.notifyDataSetChanged();
updateSelectButton();
updateText();
showMarkersRouteOnMap();
recreateSnapTrkSegment();
}
@Override
@ -251,8 +269,7 @@ public class PlanRouteFragment extends Fragment {
// to avoid crash because of:
// java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling
}
updateText();
showMarkersRouteOnMap();
recreateSnapTrkSegment();
}
}
});
@ -296,6 +313,10 @@ public class PlanRouteFragment extends Fragment {
}
});
if (progressBarVisible) {
showProgressBar();
}
return view;
}
@ -337,9 +358,12 @@ public class PlanRouteFragment extends Fragment {
@Override
public void onApplicationModeItemClick(ApplicationMode mode) {
appMode = mode;
setupAppModesBtn();
updateText();
if (appMode != null && !appMode.getStringKey().equals(mode.getStringKey())) {
appMode = mode;
snappedToRoadPoints.clear();
recreateSnapTrkSegment();
setupAppModesBtn();
}
}
};
}
@ -367,6 +391,7 @@ public class PlanRouteFragment extends Fragment {
markersHelper.reverseActiveMarkersOrder();
adapter.calculateStartAndFinishPos();
adapter.notifyDataSetChanged();
recreateSnapTrkSegment();
}
}
};
@ -405,9 +430,8 @@ public class PlanRouteFragment extends Fragment {
setupAppModesBtn();
selectedCount = mapActivity.getMyApplication().getMapMarkersHelper().getSelectedMarkersCount();
showMarkersRouteOnMap();
recreateSnapTrkSegment();
mapActivity.refreshMap();
updateText();
updateSelectButton();
}
}
@ -460,7 +484,8 @@ public class PlanRouteFragment extends Fragment {
mapActivity.findViewById(R.id.snap_to_road_image_button).setVisibility(View.GONE);
mainView.findViewById(R.id.snap_to_road_progress_bar).setVisibility(View.GONE);
markersLayer.clearRoute();
cancelSnapToRoad();
markersLayer.setRoute(null);
mapActivity.refreshMap();
}
}
@ -471,17 +496,10 @@ public class PlanRouteFragment extends Fragment {
boolean defaultMode = appMode.getStringKey().equals(ApplicationMode.DEFAULT.getStringKey());
float dist = 0;
Location myLoc = mapActivity.getMyApplication().getLocationProvider().getLastStaleKnownLocation();
boolean useLocation = myLoc != null && mapActivity.getMyApplication().getSettings().ROUTE_MAP_MARKERS_START_MY_LOC.get();
List<LatLon> markers = markersHelper.getSelectedMarkersLatLon();
if (useLocation ? markers.size() > 0 : markers.size() > 1) {
if (useLocation) {
dist += MapUtils.getDistance(myLoc.getLatitude(), myLoc.getLongitude(),
markers.get(0).getLatitude(), markers.get(0).getLongitude());
}
for (int i = 1; i < markers.size(); i++) {
dist += MapUtils.getDistance(markers.get(i - 1), markers.get(i));
}
for (int i = 1; i < snapTrkSegment.points.size(); i++) {
WptPt pt1 = snapTrkSegment.points.get(i - 1);
WptPt pt2 = snapTrkSegment.points.get(i);
dist += MapUtils.getDistance(pt1.lat, pt1.lon, pt2.lat, pt2.lon);
}
distanceTv.setText(OsmAndFormatter.getFormattedDistance(dist, mapActivity.getMyApplication()) + (defaultMode ? "" : ","));
@ -587,13 +605,12 @@ public class PlanRouteFragment extends Fragment {
private void showMarkersRouteOnMap() {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
List<LatLon> points = markersHelper.getSelectedMarkersLatLon();
mapActivity.getMapLayers().getMapMarkersLayer().setRoute(points);
showRouteOnMap(points);
mapActivity.getMapLayers().getMapMarkersLayer().setRoute(snapTrkSegment);
showRouteOnMap(snapTrkSegment.points);
}
}
private void showRouteOnMap(List<LatLon> points) {
private void showRouteOnMap(List<WptPt> points) {
MapActivity mapActivity = getMapActivity();
if (points.size() > 0 && mapActivity != null) {
OsmandMapTileView mapView = mapActivity.getMapView();
@ -606,17 +623,17 @@ public class PlanRouteFragment extends Fragment {
top = myLocation.getLatitude();
bottom = myLocation.getLatitude();
}
for (LatLon l : points) {
for (WptPt pt : points) {
if (left == 0) {
left = l.getLongitude();
right = l.getLongitude();
top = l.getLatitude();
bottom = l.getLatitude();
left = pt.getLongitude();
right = pt.getLongitude();
top = pt.getLatitude();
bottom = pt.getLatitude();
} else {
left = Math.min(left, l.getLongitude());
right = Math.max(right, l.getLongitude());
top = Math.max(top, l.getLatitude());
bottom = Math.min(bottom, l.getLatitude());
left = Math.min(left, pt.getLongitude());
right = Math.max(right, pt.getLongitude());
top = Math.max(top, pt.getLatitude());
bottom = Math.min(bottom, pt.getLatitude());
}
}
@ -721,12 +738,200 @@ public class PlanRouteFragment extends Fragment {
mapActivity.getMyApplication().getMapMarkersHelper().addSelectedMarkersToTop(res);
adapter.calculateStartAndFinishPos();
adapter.notifyDataSetChanged();
updateText();
showMarkersRouteOnMap();
recreateSnapTrkSegment();
}
}.execute();
}
private void cancelSnapToRoad() {
hideProgressBar();
snapToRoadPairsToCalculate.clear();
if (calculationProgress != null) {
calculationProgress.isCancelled = true;
}
}
private void scheduleRouteCalculateIfNotEmpty(List<WptPt> points) {
MapActivity mapActivity = getMapActivity();
if (mapActivity == null || points.isEmpty()) {
return;
}
findPairsToCalculate(points);
OsmandApplication app = mapActivity.getMyApplication();
RoutingHelper routingHelper = app.getRoutingHelper();
if (!snapToRoadPairsToCalculate.isEmpty() && !routingHelper.isRouteBeingCalculated()) {
routingHelper.startRouteCalculationThread(getParams(app), true, true);
app.runInUIThread(new Runnable() {
@Override
public void run() {
showProgressBar();
}
});
}
}
private void findPairsToCalculate(List<WptPt> points) {
snapToRoadPairsToCalculate.clear();
for (int i = 0; i < points.size() - 1; i++) {
Pair<WptPt, WptPt> pair = new Pair<>(points.get(i), points.get(i + 1));
if (snappedToRoadPoints.get(pair) == null) {
snapToRoadPairsToCalculate.add(pair);
}
}
}
private void recreateSnapTrkSegment() {
snapTrkSegment.points.clear();
List<WptPt> points = getPointsToCalculate();
if (appMode.getStringKey().equals(ApplicationMode.DEFAULT.getStringKey())) {
snapTrkSegment.points.addAll(points);
} else if (points.size() > 1) {
for (int i = 0; i < points.size() - 1; i++) {
Pair<WptPt, WptPt> pair = new Pair<>(points.get(i), points.get(i + 1));
List<WptPt> pts = snappedToRoadPoints.get(pair);
if (pts != null) {
snapTrkSegment.points.addAll(pts);
} else {
scheduleRouteCalculateIfNotEmpty(points);
snapTrkSegment.points.addAll(Arrays.asList(pair.first, pair.second));
}
}
}
showMarkersRouteOnMap();
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
mapActivity.getMyApplication().runInUIThread(new Runnable() {
@Override
public void run() {
updateText();
}
});
}
}
private List<WptPt> getPointsToCalculate() {
List<WptPt> points = new LinkedList<>();
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
Location myLoc = mapActivity.getMyApplication().getLocationProvider().getLastStaleKnownLocation();
if (markersHelper.isStartFromMyLocation() && myLoc != null) {
addWptPt(points, myLoc.getLatitude(), myLoc.getLongitude());
}
for (LatLon l : markersHelper.getSelectedMarkersLatLon()) {
addWptPt(points, l.getLatitude(), l.getLongitude());
}
}
return points;
}
private void addWptPt(List<WptPt> points, double lat, double lon) {
WptPt pt = new WptPt();
pt.lat = lat;
pt.lon = lon;
points.add(pt);
}
private void showProgressBar() {
ProgressBar progressBar = (ProgressBar) mainView.findViewById(R.id.snap_to_road_progress_bar);
progressBar.setVisibility(View.VISIBLE);
progressBar.setMinimumHeight(0);
progressBar.setProgress(0);
progressBarVisible = true;
}
private void updateProgress(int progress) {
((ProgressBar) mainView.findViewById(R.id.snap_to_road_progress_bar)).setProgress(progress);
}
private void refresh() {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
mapActivity.refreshMap();
}
}
private void hideProgressBar() {
mainView.findViewById(R.id.snap_to_road_progress_bar).setVisibility(View.GONE);
progressBarVisible = false;
}
private RouteCalculationParams getParams(final OsmandApplication app) {
OsmandSettings settings = app.getSettings();
final Pair<WptPt, WptPt> currentPair = snapToRoadPairsToCalculate.poll();
Location start = new Location("");
start.setLatitude(currentPair.first.getLatitude());
start.setLongitude(currentPair.first.getLongitude());
LatLon end = new LatLon(currentPair.second.getLatitude(), currentPair.second.getLongitude());
final RouteCalculationParams params = new RouteCalculationParams();
params.inSnapToRoadMode = true;
params.start = start;
params.end = end;
params.leftSide = settings.DRIVING_REGION.get().leftHandDriving;
params.fast = settings.FAST_ROUTE_MODE.getModeValue(appMode);
params.type = settings.ROUTER_SERVICE.getModeValue(appMode);
params.mode = appMode;
params.ctx = app;
params.calculationProgress = calculationProgress = new RouteCalculationProgress();
params.calculationProgressCallback = new RoutingHelper.RouteCalculationProgressCallback() {
@Override
public void updateProgress(int progress) {
int pairs = calculatedPairs + snapToRoadPairsToCalculate.size();
if (pairs != 0) {
int pairProgress = 100 / pairs;
progress = calculatedPairs * pairProgress + progress / pairs;
}
PlanRouteFragment.this.updateProgress(progress);
}
@Override
public void requestPrivateAccessRouting() {
}
@Override
public void finish() {
calculatedPairs = 0;
}
};
params.resultListener = new RouteCalculationParams.RouteCalculationResultListener() {
@Override
public void onRouteCalculated(List<Location> locations) {
ArrayList<WptPt> pts = new ArrayList<>(locations.size());
for (Location loc : locations) {
WptPt pt = new WptPt();
pt.lat = loc.getLatitude();
pt.lon = loc.getLongitude();
pts.add(pt);
}
calculatedPairs++;
snappedToRoadPoints.put(currentPair, pts);
recreateSnapTrkSegment();
app.runInUIThread(new Runnable() {
@Override
public void run() {
refresh();
}
});
if (!snapToRoadPairsToCalculate.isEmpty()) {
app.getRoutingHelper().startRouteCalculationThread(getParams(app), true, true);
} else {
app.runInUIThread(new Runnable() {
@Override
public void run() {
hideProgressBar();
}
});
}
}
};
return params;
}
private class PlanRouteToolbarController extends TopToolbarController {
PlanRouteToolbarController() {

View file

@ -19,6 +19,7 @@ import net.osmand.data.LatLon;
import net.osmand.data.PointDescription;
import net.osmand.data.QuadPoint;
import net.osmand.data.RotatedTileBox;
import net.osmand.plus.GPXUtilities.TrkSegment;
import net.osmand.plus.MapMarkersHelper;
import net.osmand.plus.MapMarkersHelper.MapMarker;
import net.osmand.plus.OsmAndFormatter;
@ -71,8 +72,7 @@ public class MapMarkersLayer extends OsmandMapLayer implements IContextMenuProvi
private final RenderingLineAttributes lineAttrs = new RenderingLineAttributes("measureDistanceLine");
private final RenderingLineAttributes textAttrs = new RenderingLineAttributes("rulerLineFont");
private Paint paint;
private Path path;
private List<LatLon> route = new ArrayList<>();
private TrkSegment route;
private TIntArrayList tx = new TIntArrayList();
private TIntArrayList ty = new TIntArrayList();
@ -120,7 +120,6 @@ public class MapMarkersLayer extends OsmandMapLayer implements IContextMenuProvi
bitmapPaintDestTeal = createPaintDest(R.color.marker_teal);
bitmapPaintDestPurple = createPaintDest(R.color.marker_purple);
path = new Path();
paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(7 * view.getDensity());
@ -191,15 +190,8 @@ public class MapMarkersLayer extends OsmandMapLayer implements IContextMenuProvi
}
}
public void setRoute(List<LatLon> points) {
route.clear();
route.addAll(points);
}
public boolean clearRoute() {
boolean res = route.size() > 0;
route.clear();
return res;
public void setRoute(TrkSegment route) {
this.route = route;
}
@Override
@ -214,26 +206,10 @@ public class MapMarkersLayer extends OsmandMapLayer implements IContextMenuProvi
MapMarkersHelper markersHelper = map.getMyApplication().getMapMarkersHelper();
List<MapMarker> activeMapMarkers = markersHelper.getMapMarkers();
if (route.size() > 0) {
path.reset();
boolean first = true;
if (markersHelper.isStartFromMyLocation() && myLoc != null) {
int locationX = tileBox.getPixXFromLonNoRot(myLoc.getLongitude());
int locationY = tileBox.getPixYFromLatNoRot(myLoc.getLatitude());
path.moveTo(locationX, locationY);
first = false;
}
for (LatLon point : route) {
int locationX = tileBox.getPixXFromLonNoRot(point.getLongitude());
int locationY = tileBox.getPixYFromLatNoRot(point.getLatitude());
if (first) {
path.moveTo(locationX, locationY);
first = false;
} else {
path.lineTo(locationX, locationY);
}
}
canvas.drawPath(path, paint);
if (route != null && route.points.size() > 0) {
route.renders.clear();
route.renders.add(new Renderable.StandardTrack(new ArrayList<>(route.points), 17.2));
route.drawRenderers(view.getZoom(), paint, canvas, tileBox);
}
if (markersHelper.isStartFromMyLocation() && myLoc != null) {