diff --git a/OsmAnd-java/src/main/java/net/osmand/LocationsHolder.java b/OsmAnd-java/src/main/java/net/osmand/LocationsHolder.java index 875f481644..5cecf9b8e6 100644 --- a/OsmAnd-java/src/main/java/net/osmand/LocationsHolder.java +++ b/OsmAnd-java/src/main/java/net/osmand/LocationsHolder.java @@ -25,15 +25,15 @@ public class LocationsHolder { this.locationType = resolveLocationType(locations); switch (locationType) { case LOCATION_TYPE_LATLON: - latLonList = (List) locations; + latLonList = new ArrayList<>((List) locations); size = locations.size(); break; case LOCATION_TYPE_LOCATION: - locationList = (List) locations; + locationList = new ArrayList<>((List) locations); size = locations.size(); break; case LOCATION_TYPE_WPTPT: - wptPtList = (List) locations; + wptPtList = new ArrayList<>((List) locations); size = locations.size(); break; } diff --git a/OsmAnd-java/src/main/java/net/osmand/router/RoutePlannerFrontEnd.java b/OsmAnd-java/src/main/java/net/osmand/router/RoutePlannerFrontEnd.java index 22cf7b434d..c6f18ab427 100644 --- a/OsmAnd-java/src/main/java/net/osmand/router/RoutePlannerFrontEnd.java +++ b/OsmAnd-java/src/main/java/net/osmand/router/RoutePlannerFrontEnd.java @@ -4,6 +4,7 @@ package net.osmand.router; import net.osmand.LocationsHolder; import net.osmand.NativeLibrary; import net.osmand.PlatformUtil; +import net.osmand.ResultMatcher; import net.osmand.binary.BinaryMapIndexReader; import net.osmand.binary.BinaryMapRouteReaderAdapter; import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion; @@ -62,17 +63,29 @@ public class RoutePlannerFrontEnd { public int routeDistance; public int routeGapDistance; public int routeDistanceUnmatched; - + + public boolean calculationCancelled; + private boolean calculationDone; + public GpxRouteApproximation(RoutingContext ctx) { this.ctx = ctx; } + public GpxRouteApproximation(GpxRouteApproximation gctx) { + this.ctx = gctx.ctx; + this.routeDistance = gctx.routeDistance; + } + @Override public String toString() { return String.format(">> GPX approximation (%d of %d m route calcs, %d route points searched) for %d m: %d m umatched", routeCalculations, routeDistCalculations, routePointsSearched, routeDistance, routeDistanceUnmatched); } + public boolean isCalculationDone() { + return calculationDone; + } + public double distFromLastPoint(LatLon startPoint) { if (result.size() > 0) { return MapUtils.getDistance(getLastPoint(), startPoint); @@ -87,7 +100,7 @@ public class RoutePlannerFrontEnd { return null; } } - + public static class GpxPoint { public int ind; public LatLon loc; @@ -97,6 +110,15 @@ public class RoutePlannerFrontEnd { public List stepBackRoute; public int targetInd = -1; public boolean straightLine = false; + + public GpxPoint() { + } + + public GpxPoint(GpxPoint point) { + this.ind = point.ind; + this.loc = point.loc; + this.cumDist = point.cumDist; + } } public RoutingContext buildRoutingContext(RoutingConfiguration config, NativeLibrary nativeLibrary, BinaryMapIndexReader[] map, RouteCalculationMode rm) { @@ -206,7 +228,6 @@ public class RoutePlannerFrontEnd { return null; } - public List searchRoute(final RoutingContext ctx, LatLon start, LatLon end, List intermediates) throws IOException, InterruptedException { return searchRoute(ctx, start, end, intermediates, null); } @@ -215,19 +236,16 @@ public class RoutePlannerFrontEnd { useSmartRouteRecalculation = use; } - public GpxRouteApproximation searchGpxRoute(GpxRouteApproximation gctx, List gpxPoints) throws IOException, InterruptedException { + public GpxRouteApproximation searchGpxRoute(GpxRouteApproximation gctx, List gpxPoints, ResultMatcher resultMatcher) throws IOException, InterruptedException { long timeToCalculate = System.nanoTime(); - if (gctx.ctx.calculationProgress == null) { - gctx.ctx.calculationProgress = new RouteCalculationProgress(); - } gctx.ctx.keepNativeRoutingContext = true; GpxPoint start = null; GpxPoint prev = null; - if(gpxPoints.size() > 0) { + if (gpxPoints.size() > 0) { gctx.ctx.calculationProgress.totalIterations = (int) (gpxPoints.get(gpxPoints.size() - 1).cumDist / gctx.MAXIMUM_STEP_APPROXIMATION + 1); start = gpxPoints.get(0); } - while (start != null) { + while (start != null && !gctx.calculationCancelled) { double routeDist = gctx.MAXIMUM_STEP_APPROXIMATION; GpxPoint next = findNextGpxPointWithin(gctx, gpxPoints, start, routeDist); boolean routeFound = false; @@ -287,10 +305,14 @@ public class RoutePlannerFrontEnd { gctx.ctx.deleteNativeRoutingContext(); BinaryRoutePlanner.printDebugMemoryInformation(gctx.ctx); calculateGpxRoute(gctx, gpxPoints); - if (!gctx.result.isEmpty()) { + if (!gctx.result.isEmpty() && !gctx.calculationCancelled) { new RouteResultPreparation().printResults(gctx.ctx, gpxPoints.get(0).loc, gpxPoints.get(gpxPoints.size() - 1).loc, gctx.result); System.out.println(gctx); } + if (resultMatcher != null) { + resultMatcher.publish(gctx); + } + gctx.calculationDone = true; return gctx; } @@ -343,7 +365,7 @@ public class RoutePlannerFrontEnd { reg.initRouteEncodingRule(0, "highway", RouteResultPreparation.UNMATCHED_HIGHWAY_TYPE); List lastStraightLine = null; GpxPoint straightPointStart = null; - for (int i = 0; i < gpxPoints.size(); ) { + for (int i = 0; i < gpxPoints.size() && !gctx.calculationCancelled; ) { GpxPoint pnt = gpxPoints.get(i); if (pnt.routeToTarget != null && !pnt.routeToTarget.isEmpty()) { LatLon startPoint = pnt.routeToTarget.get(0).getStartPoint(); @@ -402,7 +424,7 @@ public class RoutePlannerFrontEnd { private void cleanupResultAndAddTurns(GpxRouteApproximation gctx) { // cleanup double joints int LOOK_AHEAD = 4; - for(int i = 0; i < gctx.result.size(); i++) { + for(int i = 0; i < gctx.result.size() && !gctx.calculationCancelled; i++) { RouteSegmentResult s = gctx.result.get(i); for(int j = i + 2; j <= i + LOOK_AHEAD && j < gctx.result.size(); j++) { RouteSegmentResult e = gctx.result.get(j); @@ -419,7 +441,9 @@ public class RoutePlannerFrontEnd { r.setTurnType(null); r.setDescription(""); } - preparation.prepareTurnResults(gctx.ctx, gctx.result); + if (!gctx.calculationCancelled) { + preparation.prepareTurnResults(gctx.ctx, gctx.result); + } } private void addStraightLine(GpxRouteApproximation gctx, List lastStraightLine, GpxPoint strPnt, RouteRegion reg) { diff --git a/OsmAnd/res/layout/fragment_gpx_approximation_bottom_sheet_dialog.xml b/OsmAnd/res/layout/fragment_gpx_approximation_bottom_sheet_dialog.xml index 2699fa722f..086fb5a66f 100644 --- a/OsmAnd/res/layout/fragment_gpx_approximation_bottom_sheet_dialog.xml +++ b/OsmAnd/res/layout/fragment_gpx_approximation_bottom_sheet_dialog.xml @@ -18,8 +18,6 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - + + + diff --git a/OsmAnd/src/net/osmand/AndroidUtils.java b/OsmAnd/src/net/osmand/AndroidUtils.java index a38825956c..63956aa36b 100644 --- a/OsmAnd/src/net/osmand/AndroidUtils.java +++ b/OsmAnd/src/net/osmand/AndroidUtils.java @@ -54,6 +54,7 @@ import androidx.annotation.ColorInt; import androidx.annotation.ColorRes; import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.appcompat.content.res.AppCompatResources; import androidx.core.content.ContextCompat; import androidx.core.content.FileProvider; @@ -169,11 +170,11 @@ public class AndroidUtils { return intent.resolveActivity(context.getPackageManager()) != null; } - public static boolean isActivityNotDestroyed(Activity activity) { + public static boolean isActivityNotDestroyed(@Nullable Activity activity) { if (Build.VERSION.SDK_INT >= 17) { - return !activity.isFinishing() && !activity.isDestroyed(); + return activity != null && !activity.isFinishing() && !activity.isDestroyed(); } - return !activity.isFinishing(); + return activity != null && !activity.isFinishing(); } public static Spannable replaceCharsWithIcon(String text, Drawable icon, String[] chars) { diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/GpxApproximationFragment.java b/OsmAnd/src/net/osmand/plus/measurementtool/GpxApproximationFragment.java index 3aade669ef..3873ad22b7 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/GpxApproximationFragment.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/GpxApproximationFragment.java @@ -7,6 +7,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.LinearLayout; +import android.widget.ProgressBar; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -15,18 +16,25 @@ import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import net.osmand.AndroidUtils; +import net.osmand.LocationsHolder; import net.osmand.PlatformUtil; +import net.osmand.ResultMatcher; +import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.UiUtilities; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.base.ContextMenuScrollFragment; import net.osmand.plus.helpers.AndroidUiHelper; +import net.osmand.plus.routing.GpxApproximator; import net.osmand.plus.settings.backend.ApplicationMode; +import net.osmand.router.RoutePlannerFrontEnd.GpxRouteApproximation; import org.apache.commons.logging.Log; -import static net.osmand.plus.measurementtool.ProfileCard.*; -import static net.osmand.plus.measurementtool.SliderCard.*; +import java.io.IOException; + +import static net.osmand.plus.measurementtool.ProfileCard.ProfileCardListener; +import static net.osmand.plus.measurementtool.SliderCard.SliderCardListener; public class GpxApproximationFragment extends ContextMenuScrollFragment implements SliderCardListener, ProfileCardListener { @@ -36,9 +44,16 @@ public class GpxApproximationFragment extends ContextMenuScrollFragment public static final String DISTANCE_THRESHOLD_KEY = "distance_threshold"; public static final String SNAP_TO_ROAD_APP_MODE_STRING_KEY = "snap_to_road_app_mode"; + public static final int REQUEST_CODE = 1100; + private int menuTitleHeight; private ApplicationMode snapToRoadAppMode = ApplicationMode.CAR; - private int distanceThreshold = 30; + private int distanceThreshold = 50; + + private LocationsHolder locationsHolder; + @Nullable + private GpxApproximator gpxApproximator; + private ProgressBar progressBar; @Override public int getMainLayoutId() { @@ -85,6 +100,43 @@ public class GpxApproximationFragment extends ContextMenuScrollFragment distanceThreshold = savedInstanceState.getInt(DISTANCE_THRESHOLD_KEY); snapToRoadAppMode = ApplicationMode.valueOfStringKey( savedInstanceState.getString(SNAP_TO_ROAD_APP_MODE_STRING_KEY), ApplicationMode.CAR); + try { + gpxApproximator = new GpxApproximator(requireMyApplication(), snapToRoadAppMode, distanceThreshold, locationsHolder); + } catch (Exception e) { + LOG.error(e.getMessage(), e); + } + } else { + try { + gpxApproximator = new GpxApproximator(requireMyApplication(), locationsHolder); + } catch (Exception e) { + LOG.error(e.getMessage(), e); + } + } + + if (gpxApproximator != null) { + gpxApproximator.setApproximationProgress(new GpxApproximator.GpxApproximationProgressCallback() { + + @Override + public void start() { + if (isResumed()) { + startProgress(); + } + } + + @Override + public void updateProgress(int progress) { + if (isResumed()) { + GpxApproximationFragment.this.updateProgress(progress); + } + } + + @Override + public void finish() { + if (isResumed()) { + finishProgress(); + } + } + }); } if (isPortrait()) { @@ -93,6 +145,12 @@ public class GpxApproximationFragment extends ContextMenuScrollFragment updateCards(); updateButtons(mainView); + progressBar = mainView.findViewById(R.id.progress_bar); + if (progressBar != null) { + requireMapActivity().setupRouteCalculationProgressBar(progressBar); + progressBar.setIndeterminate(false); + } + if (!isPortrait()) { int widthNoShadow = getLandscapeNoShadowWidth(); FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(widthNoShadow, ViewGroup.LayoutParams.WRAP_CONTENT); @@ -102,6 +160,8 @@ public class GpxApproximationFragment extends ContextMenuScrollFragment enterGpxApproximationMode(); runLayoutListener(); + calculateGpxApproximation(); + return mainView; } @@ -159,7 +219,7 @@ public class GpxApproximationFragment extends ContextMenuScrollFragment public void onClick(View v) { Fragment fragment = getTargetFragment(); if (fragment instanceof GpxApproximationFragmentListener) { - ((GpxApproximationFragmentListener) fragment).onApplyGpxApproximation(snapToRoadAppMode, distanceThreshold); + ((GpxApproximationFragmentListener) fragment).onApplyGpxApproximation(); } dismiss(); } @@ -226,13 +286,13 @@ public class GpxApproximationFragment extends ContextMenuScrollFragment return (menuState & (MenuState.HEADER_ONLY | MenuState.HALF_SCREEN)) != 0; } - public static void showInstance(@NonNull FragmentManager fm, @Nullable Fragment targetFragment, @NonNull ApplicationMode initialAppMode, int initialDistanceThreshold) { + public static void showInstance(@NonNull FragmentManager fm, @Nullable Fragment targetFragment, @NonNull LocationsHolder locationsHolder) { try { if (!fm.isStateSaved()) { GpxApproximationFragment fragment = new GpxApproximationFragment(); - fragment.setTargetFragment(targetFragment, 0); - fragment.snapToRoadAppMode = initialAppMode; - fragment.distanceThreshold = initialDistanceThreshold; + fragment.setRetainInstance(true); + fragment.setTargetFragment(targetFragment, REQUEST_CODE); + fragment.setLocationsHolder(locationsHolder); fm.beginTransaction() .replace(R.id.fragmentContainer, fragment, TAG) .addToBackStack(TAG) @@ -254,29 +314,94 @@ public class GpxApproximationFragment extends ContextMenuScrollFragment } } - @Override - public void onSliderChange(int sliderValue) { - Fragment fragment = getTargetFragment(); - if (fragment instanceof GpxApproximationFragmentListener) { - ((GpxApproximationFragmentListener) fragment).onChangeGpxApproxDistanceThreshold(snapToRoadAppMode, sliderValue); - distanceThreshold = sliderValue; + public void calculateGpxApproximation() { + if (gpxApproximator != null) { + try { + gpxApproximator.setMode(snapToRoadAppMode); + gpxApproximator.setPointApproximation(distanceThreshold); + approximateGpx(); + } catch (Exception e) { + LOG.error(e.getMessage(), e); + } } } + @Override + public void onSliderChange(int sliderValue) { + distanceThreshold = sliderValue; + calculateGpxApproximation(); + } + @Override public void onProfileSelect(ApplicationMode applicationMode) { - Fragment fragment = getTargetFragment(); - if (fragment instanceof GpxApproximationFragmentListener) { - ((GpxApproximationFragmentListener) fragment).onChangeGpxApproxDistanceThreshold(applicationMode, distanceThreshold); - snapToRoadAppMode = applicationMode; + snapToRoadAppMode = applicationMode; + calculateGpxApproximation(); + } + + public LocationsHolder getLocationsHolder() { + return locationsHolder; + } + + public void setLocationsHolder(LocationsHolder locationsHolder) { + this.locationsHolder = locationsHolder; + } + + public void startProgress() { + if (progressBar != null) { + progressBar.setProgress(0); + progressBar.setVisibility(View.VISIBLE); + } + } + + public void finishProgress() { + if (progressBar != null) { + progressBar.setVisibility(View.GONE); + } + } + + public void updateProgress(int progress) { + if (progressBar != null) { + if (progressBar.getVisibility() != View.VISIBLE) { + progressBar.setVisibility(View.VISIBLE); + } + progressBar.setProgress(progress); + } + } + + private void approximateGpx() { + if (gpxApproximator != null) { + gpxApproximator.calculateGpxApproximation(new ResultMatcher() { + @Override + public boolean publish(final GpxRouteApproximation gpxApproximation) { + OsmandApplication app = getMyApplication(); + if (app != null) { + app.runInUIThread(new Runnable() { + @Override + public void run() { + Fragment fragment = getTargetFragment(); + if (fragment instanceof GpxApproximationFragmentListener) { + ((GpxApproximationFragmentListener) fragment).onGpxApproximationDone(gpxApproximation); + } + } + }); + return true; + } + return false; + } + + @Override + public boolean isCancelled() { + return false; + } + }); } } public interface GpxApproximationFragmentListener { - void onChangeGpxApproxDistanceThreshold(ApplicationMode mode, int distanceThreshold); + void onGpxApproximationDone(GpxRouteApproximation gpxApproximation); - void onApplyGpxApproximation(ApplicationMode mode, int distanceThreshold); + void onApplyGpxApproximation(); void onCancelGpxApproximation(); } diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolFragment.java b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolFragment.java index a0590f77f7..1b289e0149 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolFragment.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolFragment.java @@ -61,6 +61,7 @@ import net.osmand.plus.activities.MapActivity; import net.osmand.plus.activities.TrackActivity; import net.osmand.plus.base.BaseOsmAndFragment; import net.osmand.plus.helpers.AndroidUiHelper; +import net.osmand.plus.measurementtool.GpxApproximationFragment.GpxApproximationFragmentListener; import net.osmand.plus.measurementtool.NewGpxData.ActionType; import net.osmand.plus.measurementtool.OptionsBottomSheetDialogFragment.OptionsFragmentListener; import net.osmand.plus.measurementtool.RouteBetweenPointsBottomSheetDialogFragment.RouteBetweenPointsFragmentListener; @@ -73,7 +74,6 @@ import net.osmand.plus.measurementtool.command.ClearPointsCommand; import net.osmand.plus.measurementtool.command.MovePointCommand; import net.osmand.plus.measurementtool.command.RemovePointCommand; import net.osmand.plus.measurementtool.command.ReorderPointCommand; -import net.osmand.plus.routing.GpxApproximator; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.views.controls.ReorderItemTouchHelperCallback; @@ -84,7 +84,6 @@ import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopToolbarView; import net.osmand.router.RoutePlannerFrontEnd.GpxRouteApproximation; import java.io.File; -import java.io.IOException; import java.lang.ref.WeakReference; import java.text.MessageFormat; import java.text.SimpleDateFormat; @@ -94,7 +93,6 @@ import java.util.List; import java.util.Locale; import static net.osmand.IndexConstants.GPX_FILE_EXT; -import static net.osmand.plus.measurementtool.GpxApproximationFragment.GpxApproximationFragmentListener; import static net.osmand.plus.measurementtool.MeasurementEditingContext.CalculationType; import static net.osmand.plus.measurementtool.MeasurementEditingContext.ExportAsGpxListener; import static net.osmand.plus.measurementtool.MeasurementEditingContext.SnapToRoadProgressListener; @@ -104,7 +102,7 @@ import static net.osmand.plus.measurementtool.SelectFileBottomSheet.SelectFileLi import static net.osmand.plus.measurementtool.StartPlanRouteBottomSheet.StartPlanRouteListener; public class MeasurementToolFragment extends BaseOsmAndFragment implements RouteBetweenPointsFragmentListener, - GpxApproximationFragmentListener, OptionsFragmentListener { + OptionsFragmentListener, GpxApproximationFragmentListener { public static final String TAG = MeasurementToolFragment.class.getSimpleName(); @@ -138,7 +136,6 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route private boolean gpxPointsAdded; private MeasurementEditingContext editingCtx = new MeasurementEditingContext(); - private GpxApproximator gpxApproximator; private LatLon initialPoint; @@ -547,39 +544,6 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route return R.color.status_bar_transparent_gradient; } - private void approximateGpx() { - if (gpxApproximator != null) { - try { - GpxRouteApproximation gpxApproximation = gpxApproximator.calculateGpxApproximation(); - displayApproximatedPoints(gpxApproximation); - } catch (IOException e) { - } catch (InterruptedException e) { - } - } - } - - @Override - public void onChangeGpxApproxDistanceThreshold(ApplicationMode mode, int distanceThreshold) { - if (gpxApproximator != null) { - try { - gpxApproximator.setMode(mode); - gpxApproximator.setPointApproximation(distanceThreshold); - approximateGpx(); - } catch (IOException e) { - } - } - } - - @Override - public void onApplyGpxApproximation(ApplicationMode mode, int distanceThreshold) { - - } - - @Override - public void onCancelGpxApproximation() { - - } - @Nullable private MapActivity getMapActivity() { Activity activity = getActivity(); @@ -659,13 +623,8 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route case SnapTrackWarningBottomSheet.CONTINUE_REQUEST_CODE: MapActivity mapActivity = getMapActivity(); if (mapActivity != null) { - try { - gpxApproximator = new GpxApproximator(requireMyApplication(), new LocationsHolder(editingCtx.getPoints())); - GpxApproximationFragment.showInstance(mapActivity.getSupportFragmentManager(), - this, gpxApproximator.getMode(), (int) gpxApproximator.getPointApproximation()); - } catch (IOException e) { - - } + GpxApproximationFragment.showInstance(mapActivity.getSupportFragmentManager(), + this, new LocationsHolder(editingCtx.getPoints())); } break; } @@ -1098,7 +1057,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route } } - private void displayApproximatedPoints(GpxRouteApproximation gpxApproximation) { + public void displayApproximatedPoints(GpxRouteApproximation gpxApproximation) { MeasurementToolLayer measurementLayer = getMeasurementLayer(); if (measurementLayer != null) { editingCtx.setPoints(gpxApproximation); @@ -1968,4 +1927,19 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route return NO_COLOR; } } + + @Override + public void onGpxApproximationDone(GpxRouteApproximation gpxApproximation) { + displayApproximatedPoints(gpxApproximation); + } + + @Override + public void onApplyGpxApproximation() { + + } + + @Override + public void onCancelGpxApproximation() { + + } } diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/SliderCard.java b/OsmAnd/src/net/osmand/plus/measurementtool/SliderCard.java index ce4e098716..b496c935fb 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/SliderCard.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/SliderCard.java @@ -46,9 +46,19 @@ public class SliderCard extends BaseCard { if (fromUser) { String valueStr = getStringValueWithMetric((int) value); thresholdDistanceValue.setText(valueStr); - if (listener != null) { - listener.onSliderChange((int) value); - } + } + } + }); + slider.addOnSliderTouchListener(new Slider.OnSliderTouchListener() { + @Override + public void onStartTrackingTouch(@NonNull Slider slider) { + + } + + @Override + public void onStopTrackingTouch(@NonNull Slider slider) { + if (listener != null) { + listener.onSliderChange((int) slider.getValue()); } } }); diff --git a/OsmAnd/src/net/osmand/plus/routing/GpxApproximator.java b/OsmAnd/src/net/osmand/plus/routing/GpxApproximator.java index 318fbd63e9..60f43050b8 100644 --- a/OsmAnd/src/net/osmand/plus/routing/GpxApproximator.java +++ b/OsmAnd/src/net/osmand/plus/routing/GpxApproximator.java @@ -1,18 +1,35 @@ package net.osmand.plus.routing; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import net.osmand.LocationsHolder; +import net.osmand.PlatformUtil; +import net.osmand.ResultMatcher; import net.osmand.data.LatLon; import net.osmand.plus.OsmandApplication; +import net.osmand.plus.measurementtool.GpxApproximationFragment; import net.osmand.plus.routing.RouteProvider.RoutingEnvironment; import net.osmand.plus.settings.backend.ApplicationMode; +import net.osmand.router.RouteCalculationProgress; +import net.osmand.router.RoutePlannerFrontEnd; import net.osmand.router.RoutePlannerFrontEnd.GpxPoint; import net.osmand.router.RoutePlannerFrontEnd.GpxRouteApproximation; +import net.osmand.search.core.SearchResult; + +import org.apache.commons.logging.Log; import java.io.IOException; +import java.util.ArrayList; import java.util.List; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; public class GpxApproximator { + protected static final Log log = PlatformUtil.getLog(GpxApproximator.class); + private OsmandApplication ctx; private RoutingHelper routingHelper; @@ -23,8 +40,21 @@ public class GpxApproximator { private List points; private LatLon start; private LatLon end; + private double pointApproximation = 50; - public GpxApproximator(OsmandApplication ctx, LocationsHolder locationsHolder) throws IOException { + private ThreadPoolExecutor singleThreadedExecutor; + private GpxApproximationProgressCallback approximationProgress; + + public interface GpxApproximationProgressCallback { + + void start(); + + void updateProgress(int progress); + + void finish(); + } + + public GpxApproximator(@NonNull OsmandApplication ctx, @NonNull LocationsHolder locationsHolder) throws IOException { this.ctx = ctx; this.locationsHolder = locationsHolder; this.routingHelper = ctx.getRoutingHelper(); @@ -33,26 +63,48 @@ public class GpxApproximator { start = locationsHolder.getLatLon(0); end = locationsHolder.getLatLon(locationsHolder.getSize() - 1); prepareEnvironment(ctx, mode); - this.points = routingHelper.generateGpxPoints(env, gctx, locationsHolder); } + init(); } - public GpxApproximator(OsmandApplication ctx, ApplicationMode mode, double pointApproximation, LocationsHolder locationsHolder) throws IOException { + public GpxApproximator(@NonNull OsmandApplication ctx, @NonNull ApplicationMode mode, double pointApproximation, @NonNull LocationsHolder locationsHolder) throws IOException { this.ctx = ctx; + this.locationsHolder = locationsHolder; + this.pointApproximation = pointApproximation; this.routingHelper = ctx.getRoutingHelper(); this.mode = mode; if (locationsHolder.getSize() > 1) { start = locationsHolder.getLatLon(0); end = locationsHolder.getLatLon(locationsHolder.getSize() - 1); prepareEnvironment(ctx, mode); - gctx.MINIMUM_POINT_APPROXIMATION = pointApproximation; - this.points = routingHelper.generateGpxPoints(env, gctx, locationsHolder); } + init(); } - private void prepareEnvironment(OsmandApplication ctx, ApplicationMode mode) throws IOException { + private void init() { + singleThreadedExecutor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()); + } + + private void prepareEnvironment(@NonNull OsmandApplication ctx, @NonNull ApplicationMode mode) throws IOException { this.env = routingHelper.getRoutingEnvironment(ctx, mode, start, end); - this.gctx = new GpxRouteApproximation(env.getCtx()); + } + + private GpxRouteApproximation getNewGpxApproximationContext(@Nullable GpxRouteApproximation gctx) { + GpxRouteApproximation newContext = gctx != null ? new GpxRouteApproximation(gctx) : new GpxRouteApproximation(env.getCtx()); + newContext.ctx.calculationProgress = new RouteCalculationProgress(); + newContext.MINIMUM_POINT_APPROXIMATION = pointApproximation; + return newContext; + } + + private List getPoints() { + if (points == null) { + points = routingHelper.generateGpxPoints(env, getNewGpxApproximationContext(null), locationsHolder); + } + List points = new ArrayList<>(this.points.size()); + for (GpxPoint p : this.points) { + points.add(new GpxPoint(p)); + } + return points; } public ApplicationMode getMode() { @@ -68,18 +120,82 @@ public class GpxApproximator { } public double getPointApproximation() { - return gctx.MINIMUM_POINT_APPROXIMATION; + return pointApproximation; } public void setPointApproximation(double pointApproximation) { - gctx.MINIMUM_POINT_APPROXIMATION = pointApproximation; + this.pointApproximation = pointApproximation; } public LocationsHolder getLocationsHolder() { return locationsHolder; } - public GpxRouteApproximation calculateGpxApproximation() throws IOException, InterruptedException { - return routingHelper.calculateGpxApproximation(env, gctx, points); + public GpxApproximationProgressCallback getApproximationProgress() { + return approximationProgress; + } + + public void setApproximationProgress(GpxApproximationProgressCallback approximationProgress) { + this.approximationProgress = approximationProgress; + } + + public void calculateGpxApproximation(@NonNull final ResultMatcher resultMatcher) { + if (gctx != null) { + gctx.calculationCancelled = true; + } + final GpxRouteApproximation gctx = getNewGpxApproximationContext(this.gctx); + this.gctx = gctx; + startProgress(); + updateProgress(gctx); + singleThreadedExecutor.submit(new Runnable() { + @Override + public void run() { + try { + routingHelper.calculateGpxApproximation(env, gctx, getPoints(), resultMatcher); + } catch (Exception e) { + resultMatcher.publish(null); + log.error(e.getMessage(), e); + } + } + }); + } + + private void startProgress() { + final GpxApproximationProgressCallback approximationProgress = this.approximationProgress; + if (approximationProgress != null) { + approximationProgress.start(); + } + } + + private void finishProgress() { + final GpxApproximationProgressCallback approximationProgress = this.approximationProgress; + if (approximationProgress != null) { + approximationProgress.finish(); + } + } + + private void updateProgress(@NonNull final GpxRouteApproximation gctx) { + final GpxApproximationProgressCallback approximationProgress = this.approximationProgress; + if (approximationProgress != null) { + ctx.runInUIThread(new Runnable() { + + @Override + public void run() { + RouteCalculationProgress calculationProgress = gctx.ctx.calculationProgress; + if (gctx.isCalculationDone() && GpxApproximator.this.gctx == gctx) { + finishProgress(); + } + if (!gctx.isCalculationDone() && calculationProgress != null && !calculationProgress.isCancelled) { + float pr = calculationProgress.getLinearProgress(); + approximationProgress.updateProgress((int) pr); + if (GpxApproximator.this.gctx != gctx) { + // different calculation started + } else { + updateProgress(gctx); + } + } + } + }, 300); + } } } diff --git a/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java b/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java index 6aaac45c1d..9433e325f6 100644 --- a/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java +++ b/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java @@ -15,6 +15,7 @@ import net.osmand.GPXUtilities.WptPt; import net.osmand.Location; import net.osmand.LocationsHolder; import net.osmand.PlatformUtil; +import net.osmand.ResultMatcher; import net.osmand.binary.BinaryMapIndexReader; import net.osmand.data.LatLon; import net.osmand.data.LocationPoint; @@ -716,13 +717,8 @@ public class RouteProvider { return env.router.generateGpxPoints(gctx, locationsHolder); } - public GpxRouteApproximation calculateGpxPointsApproximation(RoutingEnvironment env, GpxRouteApproximation gctx, List points) throws IOException, InterruptedException { - if (points != null && points.size() > 1) { - if (!Algorithms.isEmpty(points)) { - return env.router.searchGpxRoute(gctx, points); - } - } - return null; + public GpxRouteApproximation calculateGpxPointsApproximation(RoutingEnvironment env, GpxRouteApproximation gctx, List points, ResultMatcher resultMatcher) throws IOException, InterruptedException { + return env.router.searchGpxRoute(gctx, points, resultMatcher); } protected RoutingEnvironment calculateRoutingEnvironment(RouteCalculationParams params, boolean calcGPXRoute, boolean skipComplex) throws IOException { diff --git a/OsmAnd/src/net/osmand/plus/routing/RoutingHelper.java b/OsmAnd/src/net/osmand/plus/routing/RoutingHelper.java index 0899b586a9..25727f86ea 100644 --- a/OsmAnd/src/net/osmand/plus/routing/RoutingHelper.java +++ b/OsmAnd/src/net/osmand/plus/routing/RoutingHelper.java @@ -7,6 +7,7 @@ import net.osmand.GPXUtilities.WptPt; import net.osmand.Location; import net.osmand.LocationsHolder; import net.osmand.PlatformUtil; +import net.osmand.ResultMatcher; import net.osmand.ValueHolder; import net.osmand.binary.RouteDataObject; import net.osmand.data.LatLon; @@ -1364,8 +1365,8 @@ public class RoutingHelper { return provider.generateGpxPoints(env, gctx, locationsHolder); } - public GpxRouteApproximation calculateGpxApproximation(RoutingEnvironment env, GpxRouteApproximation gctx, List points) throws IOException, InterruptedException { - return provider.calculateGpxPointsApproximation(env, gctx, points); + public GpxRouteApproximation calculateGpxApproximation(RoutingEnvironment env, GpxRouteApproximation gctx, List points, ResultMatcher resultMatcher) throws IOException, InterruptedException { + return provider.calculateGpxPointsApproximation(env, gctx, points, resultMatcher); } public void notifyIfRouteIsCalculated() {