Gpx approximation in progress

This commit is contained in:
max-klaus 2020-08-11 23:03:13 +03:00
parent 44b84bf65d
commit 2ab38a54b5
10 changed files with 358 additions and 110 deletions

View file

@ -25,15 +25,15 @@ public class LocationsHolder {
this.locationType = resolveLocationType(locations);
switch (locationType) {
case LOCATION_TYPE_LATLON:
latLonList = (List<LatLon>) locations;
latLonList = new ArrayList<>((List<LatLon>) locations);
size = locations.size();
break;
case LOCATION_TYPE_LOCATION:
locationList = (List<Location>) locations;
locationList = new ArrayList<>((List<Location>) locations);
size = locations.size();
break;
case LOCATION_TYPE_WPTPT:
wptPtList = (List<WptPt>) locations;
wptPtList = new ArrayList<>((List<WptPt>) locations);
size = locations.size();
break;
}

View file

@ -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<RouteSegmentResult> 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<RouteSegmentResult> searchRoute(final RoutingContext ctx, LatLon start, LatLon end, List<LatLon> 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<GpxPoint> gpxPoints) throws IOException, InterruptedException {
public GpxRouteApproximation searchGpxRoute(GpxRouteApproximation gctx, List<GpxPoint> gpxPoints, ResultMatcher<GpxRouteApproximation> 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<LatLon> 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<LatLon> lastStraightLine, GpxPoint strPnt, RouteRegion reg) {

View file

@ -18,8 +18,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/plan_route_progress_bar"/>
<net.osmand.plus.LockableScrollView
android:id="@+id/route_menu_bottom_scroll"
android:layout_width="match_parent"
@ -37,6 +35,9 @@
</LinearLayout>
</net.osmand.plus.LockableScrollView>
<include layout="@layout/plan_route_progress_bar"/>
</FrameLayout>
</LinearLayout>

View file

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

View file

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

View file

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

View file

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

View file

@ -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<GpxPoint> 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<Runnable>());
}
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<GpxPoint> getPoints() {
if (points == null) {
points = routingHelper.generateGpxPoints(env, getNewGpxApproximationContext(null), locationsHolder);
}
List<GpxPoint> 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<GpxRouteApproximation> 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);
}
}
}

View file

@ -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<GpxPoint> 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<GpxPoint> points, ResultMatcher<GpxRouteApproximation> resultMatcher) throws IOException, InterruptedException {
return env.router.searchGpxRoute(gctx, points, resultMatcher);
}
protected RoutingEnvironment calculateRoutingEnvironment(RouteCalculationParams params, boolean calcGPXRoute, boolean skipComplex) throws IOException {

View file

@ -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<GpxPoint> points) throws IOException, InterruptedException {
return provider.calculateGpxPointsApproximation(env, gctx, points);
public GpxRouteApproximation calculateGpxApproximation(RoutingEnvironment env, GpxRouteApproximation gctx, List<GpxPoint> points, ResultMatcher<GpxRouteApproximation> resultMatcher) throws IOException, InterruptedException {
return provider.calculateGpxPointsApproximation(env, gctx, points, resultMatcher);
}
public void notifyIfRouteIsCalculated() {