diff --git a/OsmAnd-java/src/main/java/net/osmand/GPXUtilities.java b/OsmAnd-java/src/main/java/net/osmand/GPXUtilities.java index 23afd7dd2a..18ebc9b688 100644 --- a/OsmAnd-java/src/main/java/net/osmand/GPXUtilities.java +++ b/OsmAnd-java/src/main/java/net/osmand/GPXUtilities.java @@ -52,6 +52,7 @@ public class GPXUtilities { private static final String DEFAULT_ICON_NAME = "special_star"; private static final String BACKGROUND_TYPE_EXTENSION = "background"; private static final String PROFILE_TYPE_EXTENSION = "profile"; + private static final String GAP_PROFILE_TYPE = "gap"; private static final String TRKPT_INDEX_EXTENSION = "trkpt_idx"; private final static String GPX_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'"; //$NON-NLS-1$ @@ -324,6 +325,20 @@ public class GPXUtilities { getExtensionsToWrite().put(PROFILE_TYPE_EXTENSION, profileType); } + public boolean hasProfile() { + String profileType = getProfileType(); + return profileType != null && !GAP_PROFILE_TYPE.equals(profileType); + } + + public boolean isGap() { + String profileType = getProfileType(); + return GAP_PROFILE_TYPE.equals(profileType); + } + + public void setGap() { + setProfileType(GAP_PROFILE_TYPE); + } + public void removeProfileType() { getExtensionsToWrite().remove(PROFILE_TYPE_EXTENSION); } @@ -374,11 +389,16 @@ public class GPXUtilities { public static class TrkSegment extends GPXExtensions { public boolean generalSegment = false; - public List points = new ArrayList<>(); public Object renderer; + public List routeSegments = new ArrayList<>(); + public List routeTypes = new ArrayList<>(); + + public boolean hasRoute() { + return !routeSegments.isEmpty() && !routeTypes.isEmpty(); + } public List splitByDistance(double meters, boolean joinSegments) { return split(getDistanceMetric(), getTimeSplit(), meters, joinSegments); @@ -393,7 +413,6 @@ public class GPXUtilities { splitSegment(metric, secondaryMetric, metricLimit, splitSegments, this, joinSegments); return convert(splitSegments); } - } public static class Track extends GPXExtensions { @@ -1078,9 +1097,6 @@ public class GPXUtilities { private List points = new ArrayList<>(); public List routes = new ArrayList<>(); - public List routeSegments = new ArrayList<>(); - public List routeTypes = new ArrayList<>(); - public Exception error = null; public String path = ""; public boolean showCurrentTrack; @@ -1108,7 +1124,7 @@ public class GPXUtilities { } public boolean hasRoute() { - return !routeSegments.isEmpty() && !routeTypes.isEmpty(); + return getNonEmptyTrkSegments(true).size() > 0; } public List getPoints() { @@ -1218,7 +1234,7 @@ public class GPXUtilities { GPXTrackAnalysis g = new GPXTrackAnalysis(); g.wptPoints = points.size(); g.wptCategoryNames = getWaypointCategories(true); - List splitSegments = new ArrayList(); + List splitSegments = new ArrayList<>(); for (int i = 0; i < tracks.size(); i++) { Track subtrack = tracks.get(i); for (TrkSegment segment : subtrack.segments) { @@ -1243,6 +1259,15 @@ public class GPXUtilities { return points; } + public List getRoutePoints(int routeIndex) { + List points = new ArrayList<>(); + if (routes.size() > routeIndex) { + Route rt = routes.get(routeIndex); + points.addAll(rt.points); + } + return points; + } + public boolean hasRtePt() { for (Route r : routes) { if (r.points.size() > 0) { @@ -1318,15 +1343,16 @@ public class GPXUtilities { return pt; } - public TrkSegment getNonEmptyTrkSegment() { - for (GPXUtilities.Track t : tracks) { + public List getNonEmptyTrkSegments(boolean routesOnly) { + List segments = new ArrayList<>(); + for (Track t : tracks) { for (TrkSegment s : t.segments) { - if (s.points.size() > 0) { - return s; + if (!s.generalSegment && s.points.size() > 0 && (!routesOnly || s.hasRoute())) { + segments.add(s); } } } - return null; + return segments; } public void addTrkSegment(List points) { @@ -1365,8 +1391,8 @@ public class GPXUtilities { return false; } - public void addRoutePoints(List points) { - if (routes.size() == 0) { + public void addRoutePoints(List points, boolean addRoute) { + if (routes.size() == 0 || addRoute) { Route route = new Route(); routes.add(route); } @@ -1608,7 +1634,7 @@ public class GPXUtilities { bottom = Math.min(bottom, p.getLatitude()); } } - for (GPXUtilities.Route route : routes) { + for (Route route : routes) { for (WptPt p : route.points) { if (left == 0 && right == 0) { left = p.getLongitude(); @@ -1720,7 +1746,7 @@ public class GPXUtilities { public static String asString(GPXFile file) { final Writer writer = new StringWriter(); - GPXUtilities.writeGpx(writer, file); + writeGpx(writer, file); return writer.toString(); } @@ -1807,6 +1833,8 @@ public class GPXUtilities { writeWpt(format, serializer, p); serializer.endTag(null, "trkpt"); //$NON-NLS-1$ } + assignRouteExtensionWriter(segment); + writeExtensions(serializer, segment); serializer.endTag(null, "trkseg"); //$NON-NLS-1$ } writeExtensions(serializer, track); @@ -1834,7 +1862,6 @@ public class GPXUtilities { serializer.endTag(null, "wpt"); //$NON-NLS-1$ } - assignRouteExtensionWriter(file); writeExtensions(serializer, file); serializer.endTag(null, "gpx"); //$NON-NLS-1$ @@ -1847,19 +1874,19 @@ public class GPXUtilities { return null; } - private static void assignRouteExtensionWriter(final GPXFile gpxFile) { - if (gpxFile.hasRoute() && gpxFile.getExtensionsWriter() == null) { - gpxFile.setExtensionsWriter(new GPXExtensionsWriter() { + private static void assignRouteExtensionWriter(final TrkSegment segment) { + if (segment.hasRoute() && segment.getExtensionsWriter() == null) { + segment.setExtensionsWriter(new GPXExtensionsWriter() { @Override public void writeExtensions(XmlSerializer serializer) { StringBundle bundle = new StringBundle(); List segmentsBundle = new ArrayList<>(); - for (RouteSegment segment : gpxFile.routeSegments) { + for (RouteSegment segment : segment.routeSegments) { segmentsBundle.add(segment.toStringBundle()); } bundle.putBundleList("route", "segment", segmentsBundle); List typesBundle = new ArrayList<>(); - for (RouteType routeType : gpxFile.routeTypes) { + for (RouteType routeType : segment.routeTypes) { typesBundle.add(routeType.toStringBundle()); } bundle.putBundleList("types", "type", typesBundle); @@ -1901,12 +1928,15 @@ public class GPXUtilities { } private static void writeExtensions(XmlSerializer serializer, GPXExtensions p) throws IOException { - Map extensionsToRead = p.getExtensionsToRead(); + writeExtensions(serializer, p.getExtensionsToRead(), p); + } + + private static void writeExtensions(XmlSerializer serializer, Map extensions, GPXExtensions p) throws IOException { GPXExtensionsWriter extensionsWriter = p.getExtensionsWriter(); - if (!extensionsToRead.isEmpty() || extensionsWriter != null) { + if (!extensions.isEmpty() || extensionsWriter != null) { serializer.startTag(null, "extensions"); - if (!extensionsToRead.isEmpty()) { - for (Entry s : extensionsToRead.entrySet()) { + if (!extensions.isEmpty()) { + for (Entry s : extensions.entrySet()) { writeNotNullText(serializer, s.getKey(), s.getValue()); } } @@ -1943,7 +1973,20 @@ public class GPXUtilities { if (!Float.isNaN(p.heading)) { p.getExtensionsToWrite().put("heading", String.valueOf(Math.round(p.heading))); } - writeExtensions(serializer, p); + Map extensions = p.getExtensionsToRead(); + if (!"rtept".equals(serializer.getName())) { + // Leave "profile" and "trkpt" tags for rtept only + extensions.remove(PROFILE_TYPE_EXTENSION); + extensions.remove(TRKPT_INDEX_EXTENSION); + writeExtensions(serializer, extensions, p); + } else { + // Remove "gap" profile + String profile = extensions.get(PROFILE_TYPE_EXTENSION); + if (GAP_PROFILE_TYPE.equals(profile)) { + extensions.remove(PROFILE_TYPE_EXTENSION); + } + writeExtensions(serializer, p); + } } private static void writeAuthor(XmlSerializer serializer, Author author) throws IOException { @@ -2099,10 +2142,11 @@ public class GPXUtilities { TrkSegment routeTrackSegment = new TrkSegment(); routeTrack.segments.add(routeTrackSegment); Stack parserState = new Stack<>(); + TrkSegment firstSegment = null; boolean extensionReadMode = false; boolean routePointExtension = false; - List routeSegments = gpxFile.routeSegments; - List routeTypes = gpxFile.routeTypes; + List routeSegments = new ArrayList<>(); + List routeTypes = new ArrayList<>(); boolean routeExtension = false; boolean typesExtension = false; parserState.push(gpxFile); @@ -2403,6 +2447,16 @@ public class GPXUtilities { assert pop instanceof Route; } else if (tag.equals("trkseg")) { Object pop = parserState.pop(); + if (pop instanceof TrkSegment) { + TrkSegment segment = (TrkSegment) pop; + segment.routeSegments = routeSegments; + segment.routeTypes = routeTypes; + routeSegments = new ArrayList<>(); + routeTypes = new ArrayList<>(); + if (firstSegment == null) { + firstSegment = segment; + } + } assert pop instanceof TrkSegment; } else if (tag.equals("rpt")) { Object pop = parserState.pop(); @@ -2413,6 +2467,10 @@ public class GPXUtilities { if (!routeTrackSegment.points.isEmpty()) { gpxFile.tracks.add(routeTrack); } + if (!routeSegments.isEmpty() && !routeTypes.isEmpty() && firstSegment != null) { + firstSegment.routeSegments = routeSegments; + firstSegment.routeTypes = routeTypes; + } } catch (Exception e) { gpxFile.error = e; log.error("Error reading gpx", e); //$NON-NLS-1$ diff --git a/OsmAnd-java/src/main/java/net/osmand/router/RouteExporter.java b/OsmAnd-java/src/main/java/net/osmand/router/RouteExporter.java index 7ae47d4098..6add39fdcc 100644 --- a/OsmAnd-java/src/main/java/net/osmand/router/RouteExporter.java +++ b/OsmAnd-java/src/main/java/net/osmand/router/RouteExporter.java @@ -20,10 +20,10 @@ public class RouteExporter { public static final String OSMAND_ROUTER_V2 = "OsmAndRouterV2"; - private String name; - private List route; - private List locations; - private List points; + private final String name; + private final List route; + private final List locations; + private final List points; public RouteExporter(String name, List route, List locations, List points) { this.name = name; @@ -33,6 +33,34 @@ public class RouteExporter { } public GPXFile exportRoute() { + GPXFile gpx = new GPXFile(OSMAND_ROUTER_V2); + Track track = new Track(); + track.name = name; + gpx.tracks.add(track); + track.segments.add(generateRouteSegment()); + if (points != null) { + for (WptPt pt : points) { + gpx.addPoint(pt); + } + } + return gpx; + } + + public static GPXFile exportRoute(String name, List trkSegments, List points) { + GPXFile gpx = new GPXFile(OSMAND_ROUTER_V2); + Track track = new Track(); + track.name = name; + gpx.tracks.add(track); + track.segments.addAll(trkSegments); + if (points != null) { + for (WptPt pt : points) { + gpx.addPoint(pt); + } + } + return gpx; + } + + public TrkSegment generateRouteSegment() { RouteDataResources resources = new RouteDataResources(locations); List routeItems = new ArrayList<>(); if (!Algorithms.isEmpty(route)) { @@ -57,15 +85,9 @@ public class RouteExporter { typeList.add(typeBundle); } - GPXFile gpx = new GPXFile(OSMAND_ROUTER_V2); - Track track = new Track(); - track.name = name; - gpx.tracks.add(track); TrkSegment trkSegment = new TrkSegment(); - track.segments.add(trkSegment); - if (locations == null || locations.isEmpty()) { - return gpx; + return trkSegment; } for (int i = 0; i < locations.size(); i++) { Location loc = locations.get(i); @@ -83,23 +105,17 @@ public class RouteExporter { } trkSegment.points.add(pt); } - if (points != null) { - for (WptPt pt : points) { - gpx.addPoint(pt); - } - } List routeSegments = new ArrayList<>(); for (StringBundle item : routeItems) { routeSegments.add(RouteSegment.fromStringBundle(item)); } - gpx.routeSegments = routeSegments; + trkSegment.routeSegments = routeSegments; List routeTypes = new ArrayList<>(); for (StringBundle item : typeList) { routeTypes.add(RouteType.fromStringBundle(item)); } - gpx.routeTypes = routeTypes; - - return gpx; + trkSegment.routeTypes = routeTypes; + return trkSegment; } } diff --git a/OsmAnd-java/src/main/java/net/osmand/router/RouteImporter.java b/OsmAnd-java/src/main/java/net/osmand/router/RouteImporter.java index e2be849dcb..418ca2db6c 100644 --- a/OsmAnd-java/src/main/java/net/osmand/router/RouteImporter.java +++ b/OsmAnd-java/src/main/java/net/osmand/router/RouteImporter.java @@ -4,6 +4,7 @@ import net.osmand.GPXUtilities; import net.osmand.GPXUtilities.GPXFile; import net.osmand.GPXUtilities.RouteSegment; import net.osmand.GPXUtilities.RouteType; +import net.osmand.GPXUtilities.TrkSegment; import net.osmand.GPXUtilities.WptPt; import net.osmand.Location; import net.osmand.PlatformUtil; @@ -28,10 +29,9 @@ public class RouteImporter { private File file; private GPXFile gpxFile; + private TrkSegment segment; - private List route = new ArrayList<>(); - private RouteRegion region = new RouteRegion(); - private RouteDataResources resources = new RouteDataResources(); + private final List route = new ArrayList<>(); public RouteImporter(File file) { this.file = file; @@ -41,8 +41,12 @@ public class RouteImporter { this.gpxFile = gpxFile; } + public RouteImporter(TrkSegment segment) { + this.segment = segment; + } + public List importRoute() { - if (gpxFile != null) { + if (gpxFile != null || segment != null) { parseRoute(); } else if (file != null) { FileInputStream fis = null; @@ -69,19 +73,34 @@ public class RouteImporter { } private void parseRoute() { - collectLocations(); - collectSegments(); - collectTypes(); - for (RouteSegmentResult segment : route) { - segment.fillNames(resources); + if (segment != null) { + parseRoute(segment); + } else if (gpxFile != null) { + List segments = gpxFile.getNonEmptyTrkSegments(true); + for (TrkSegment s : segments) { + parseRoute(s); + } } } - private void collectLocations() { + private void parseRoute(TrkSegment segment) { + RouteRegion region = new RouteRegion(); + RouteDataResources resources = new RouteDataResources(); + + collectLocations(resources, segment); + List route = collectRouteSegments(region, resources, segment); + collectRouteTypes(region, segment); + for (RouteSegmentResult routeSegment : route) { + routeSegment.fillNames(resources); + } + this.route.addAll(route); + } + + private void collectLocations(RouteDataResources resources, TrkSegment segment) { List locations = resources.getLocations(); double lastElevation = HEIGHT_UNDEFINED; - if (gpxFile.tracks.size() > 0 && gpxFile.tracks.get(0).segments.size() > 0 && gpxFile.tracks.get(0).segments.get(0).points.size() > 0) { - for (WptPt point : gpxFile.tracks.get(0).segments.get(0).points) { + if (segment.hasRoute()) { + for (WptPt point : segment.points) { Location loc = new Location("", point.getLatitude(), point.getLongitude()); if (!Double.isNaN(point.ele)) { loc.setAltitude(point.ele); @@ -94,18 +113,20 @@ public class RouteImporter { } } - private void collectSegments() { - for (RouteSegment segment : gpxFile.routeSegments) { + private List collectRouteSegments(RouteRegion region, RouteDataResources resources, TrkSegment segment) { + List route = new ArrayList<>(); + for (RouteSegment routeSegment : segment.routeSegments) { RouteDataObject object = new RouteDataObject(region); RouteSegmentResult segmentResult = new RouteSegmentResult(object); - segmentResult.readFromBundle(new RouteDataBundle(resources, segment.toStringBundle())); + segmentResult.readFromBundle(new RouteDataBundle(resources, routeSegment.toStringBundle())); route.add(segmentResult); } + return route; } - private void collectTypes() { + private void collectRouteTypes(RouteRegion region, TrkSegment segment) { int i = 0; - for (RouteType routeType : gpxFile.routeTypes) { + for (RouteType routeType : segment.routeTypes) { StringBundle bundle = routeType.toStringBundle(); String t = bundle.getString("t", null); String v = bundle.getString("v", null); 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 bff7db3a6d..17eb567813 100644 --- a/OsmAnd-java/src/main/java/net/osmand/router/RoutePlannerFrontEnd.java +++ b/OsmAnd-java/src/main/java/net/osmand/router/RoutePlannerFrontEnd.java @@ -243,9 +243,6 @@ public class RoutePlannerFrontEnd { start = gpxPoints.get(0); } while (start != null && !gctx.ctx.calculationProgress.isCancelled) { - if (Thread.currentThread().isInterrupted()) { - return null; - } double routeDist = gctx.MAXIMUM_STEP_APPROXIMATION; GpxPoint next = findNextGpxPointWithin(gctx, gpxPoints, start, routeDist); boolean routeFound = false; diff --git a/OsmAnd-java/src/main/java/net/osmand/router/RouteSegmentResult.java b/OsmAnd-java/src/main/java/net/osmand/router/RouteSegmentResult.java index e31f8ef03b..6f8de67353 100644 --- a/OsmAnd-java/src/main/java/net/osmand/router/RouteSegmentResult.java +++ b/OsmAnd-java/src/main/java/net/osmand/router/RouteSegmentResult.java @@ -255,7 +255,8 @@ public class RouteSegmentResult implements StringExternalizable @Override public void writeToBundle(RouteDataBundle bundle) { Map rules = bundle.getResources().getRules(); - bundle.putInt("length", (Math.abs(endPointIndex - startPointIndex) + 1) * (endPointIndex >= startPointIndex ? 1 : -1)); + boolean reversed = endPointIndex < startPointIndex; + bundle.putInt("length", Math.abs(endPointIndex - startPointIndex) + 1); bundle.putFloat("segmentTime", segmentTime, 2); bundle.putFloat("speed", speed, 2); if (turnType != null) { @@ -278,17 +279,22 @@ public class RouteSegmentResult implements StringExternalizable int end = Math.max(startPointIndex, endPointIndex) + 1; if (object.pointTypes != null && start < object.pointTypes.length) { int[][] types = Arrays.copyOfRange(object.pointTypes, start, Math.min(end, object.pointTypes.length)); + if (reversed) { + Algorithms.reverseArray(types); + } bundle.putArray("pointTypes", convertTypes(types, rules)); } if (object.nameIds != null) { bundle.putArray("names", convertNameIds(object.nameIds, rules)); } - if (object.pointNameTypes != null && start < object.pointNameTypes.length) { + if (object.pointNameTypes != null && start < object.pointNameTypes.length && object.pointNames != null) { int[][] types = Arrays.copyOfRange(object.pointNameTypes, start, Math.min(end, object.pointNameTypes.length)); - if (object.pointNames != null) { - String[][] names = Arrays.copyOfRange(object.pointNames, start, Math.min(end, object.pointNames.length)); - bundle.putArray("pointNames", convertPointNames(types, names, rules)); + String[][] names = Arrays.copyOfRange(object.pointNames, start, Math.min(end, object.pointNames.length)); + if (reversed) { + Algorithms.reverseArray(types); + Algorithms.reverseArray(names); } + bundle.putArray("pointNames", convertPointNames(types, names, rules)); } } diff --git a/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java b/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java index 915a463182..2c0c056ab3 100644 --- a/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java +++ b/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java @@ -886,6 +886,14 @@ public class Algorithms { return map; } + public static void reverseArray(T[] array) { + for (int i = 0; i < array.length / 2; i++) { + T temp = array[i]; + array[i] = array[array.length - i - 1]; + array[array.length - i - 1] = temp; + } + } + public static boolean containsInArrayL(long[] array, long value) { return Arrays.binarySearch(array, value) >= 0; } diff --git a/OsmAnd/res/drawable/shadow.xml b/OsmAnd/res/drawable/shadow.xml new file mode 100644 index 0000000000..25b8ac43b3 --- /dev/null +++ b/OsmAnd/res/drawable/shadow.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/OsmAnd/res/layout/bottom_sheet_behaviour_base.xml b/OsmAnd/res/layout/bottom_sheet_behaviour_base.xml index 1f54a2b8d1..af79d3e289 100644 --- a/OsmAnd/res/layout/bottom_sheet_behaviour_base.xml +++ b/OsmAnd/res/layout/bottom_sheet_behaviour_base.xml @@ -38,9 +38,9 @@ diff --git a/OsmAnd/res/layout/bottom_sheet_menu_base.xml b/OsmAnd/res/layout/bottom_sheet_menu_base.xml index d265ba938c..cb4716cf00 100644 --- a/OsmAnd/res/layout/bottom_sheet_menu_base.xml +++ b/OsmAnd/res/layout/bottom_sheet_menu_base.xml @@ -33,9 +33,9 @@ diff --git a/OsmAnd/res/layout/edit_arrangement_list_fragment.xml b/OsmAnd/res/layout/edit_arrangement_list_fragment.xml index f0003875a2..2cc1e020cb 100644 --- a/OsmAnd/res/layout/edit_arrangement_list_fragment.xml +++ b/OsmAnd/res/layout/edit_arrangement_list_fragment.xml @@ -32,8 +32,8 @@ + android:layout_height="8dp" + android:background="@drawable/shadow" /> + android:background="@drawable/shadow" /> + android:background="@drawable/shadow" /> + android:background="@drawable/shadow" /> + android:background="@drawable/shadow" /> + Gap + %1$s — %2$s Wait for the route recalculation.\nGraph will be available after recalculation. %1$s data available only on the roads, you need to calculate a route using “Route between points” to get it. Graph diff --git a/OsmAnd/src/net/osmand/plus/FavouritesDbHelper.java b/OsmAnd/src/net/osmand/plus/FavouritesDbHelper.java index 6ebdaea6b4..4aaca14bb3 100644 --- a/OsmAnd/src/net/osmand/plus/FavouritesDbHelper.java +++ b/OsmAnd/src/net/osmand/plus/FavouritesDbHelper.java @@ -428,7 +428,7 @@ public class FavouritesDbHelper { while (fl) { fl = false; for (FavouritePoint fp : fdb.getFavouritePoints()) { - if (fp.getName().equals(name) && p.getLatitude() != fp.getLatitude() && p.getLongitude() != fp.getLongitude()) { + if (fp.getName().equals(name) && p.getLatitude() != fp.getLatitude() && p.getLongitude() != fp.getLongitude() && fp.getCategory().equals(p.getCategory())) { number++; index = " (" + number + ")"; name = p.getName() + index; diff --git a/OsmAnd/src/net/osmand/plus/activities/TrackActivity.java b/OsmAnd/src/net/osmand/plus/activities/TrackActivity.java index 0de2d3972f..12e5edf12a 100644 --- a/OsmAnd/src/net/osmand/plus/activities/TrackActivity.java +++ b/OsmAnd/src/net/osmand/plus/activities/TrackActivity.java @@ -21,7 +21,6 @@ import com.google.android.material.bottomnavigation.BottomNavigationView; import net.osmand.AndroidUtils; import net.osmand.GPXUtilities; import net.osmand.GPXUtilities.GPXFile; -import net.osmand.GPXUtilities.TrkSegment; import net.osmand.GPXUtilities.WptPt; import net.osmand.IndexConstants; import net.osmand.data.LatLon; @@ -32,9 +31,7 @@ import net.osmand.plus.GpxSelectionHelper; import net.osmand.plus.GpxSelectionHelper.GpxDisplayGroup; import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile; import net.osmand.plus.LockableViewPager; -import net.osmand.plus.settings.backend.OsmAndAppCustomization; import net.osmand.plus.OsmandApplication; -import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.R; import net.osmand.plus.mapmarkers.CoordinateInputDialogFragment; import net.osmand.plus.measurementtool.GpxData; @@ -44,6 +41,8 @@ import net.osmand.plus.myplaces.TrackBitmapDrawer; import net.osmand.plus.myplaces.TrackBitmapDrawer.TrackBitmapDrawerListener; import net.osmand.plus.myplaces.TrackPointFragment; import net.osmand.plus.myplaces.TrackSegmentFragment; +import net.osmand.plus.settings.backend.OsmAndAppCustomization; +import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.views.AddGpxPointBottomSheetHelper.NewGpxPoint; import java.io.File; @@ -136,14 +135,9 @@ public class TrackActivity extends TabActivity { } } - public void addNewGpxData(GpxData.ActionType actionType) { - addNewGpxData(actionType, null); - } - - public void addNewGpxData(GpxData.ActionType actionType, TrkSegment segment) { + public void addNewGpxData() { GPXFile gpxFile = getGpx(); - QuadRect rect = getRect(); - GpxData gpxData = new GpxData(gpxFile, rect, actionType, segment); + GpxData gpxData = new GpxData(gpxFile); WptPt pointToShow = gpxFile != null ? gpxFile.findPointToShow() : null; if (pointToShow != null) { LatLon location = new LatLon(pointToShow.getLatitude(), pointToShow.getLongitude()); @@ -154,7 +148,6 @@ public class TrackActivity extends TabActivity { false, gpxData ); - MapActivity.launchMapActivityMoveToTop(this); } } diff --git a/OsmAnd/src/net/osmand/plus/base/MenuBottomSheetDialogFragment.java b/OsmAnd/src/net/osmand/plus/base/MenuBottomSheetDialogFragment.java index 307cfb3bbe..f073e18076 100644 --- a/OsmAnd/src/net/osmand/plus/base/MenuBottomSheetDialogFragment.java +++ b/OsmAnd/src/net/osmand/plus/base/MenuBottomSheetDialogFragment.java @@ -423,7 +423,7 @@ public abstract class MenuBottomSheetDialogFragment extends BottomSheetDialogFra private LayerDrawable createBackgroundDrawable(@NonNull Context ctx, @DrawableRes int shadowDrawableResId) { Drawable shadowDrawable = ContextCompat.getDrawable(ctx, shadowDrawableResId); - Drawable[] layers = new Drawable[] {shadowDrawable, getColoredBg(ctx)}; + Drawable[] layers = new Drawable[]{shadowDrawable, getColoredBg(ctx)}; return new LayerDrawable(layers); } @@ -434,6 +434,21 @@ public abstract class MenuBottomSheetDialogFragment extends BottomSheetDialogFra return !app.getSettings().isLightContent(); } + private void showShadowButton() { + buttonsShadow.setVisibility(View.VISIBLE); + buttonsShadow.animate() + .alpha(0.8f) + .setDuration(200) + .setListener(null); + } + + private void hideShadowButton() { + buttonsShadow.animate() + .alpha(0f) + .setDuration(200); + + } + private void setupScrollShadow(View view) { final View scrollView; if (useScrollableItemsContainer()) { @@ -446,7 +461,11 @@ public abstract class MenuBottomSheetDialogFragment extends BottomSheetDialogFra @Override public void onScrollChanged() { boolean scrollToBottomAvailable = scrollView.canScrollVertically(1); - AndroidUiHelper.updateVisibility(buttonsShadow, scrollToBottomAvailable); + if (scrollToBottomAvailable) { + showShadowButton(); + } else { + hideShadowButton(); + } } }); } diff --git a/OsmAnd/src/net/osmand/plus/importfiles/ImportHelper.java b/OsmAnd/src/net/osmand/plus/importfiles/ImportHelper.java index 1416e29e31..541300a7ec 100644 --- a/OsmAnd/src/net/osmand/plus/importfiles/ImportHelper.java +++ b/OsmAnd/src/net/osmand/plus/importfiles/ImportHelper.java @@ -670,7 +670,10 @@ public class ImportHelper { } fp.setAddress(p.getExtensionsToRead().get("address")); fp.setColor(p.getColor(0)); - fp.setIconIdFromName(app, p.getIconName()); + String iconName = p.getIconName(); + if (iconName != null) { + fp.setIconIdFromName(app, iconName); + } fp.setBackgroundType(BackgroundType.getByTypeName(p.getBackgroundType(), DEFAULT_BACKGROUND_TYPE)); favourites.add(fp); } diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/GpxApproximationFragment.java b/OsmAnd/src/net/osmand/plus/measurementtool/GpxApproximationFragment.java index 924cea3ab0..132f48b6a5 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/GpxApproximationFragment.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/GpxApproximationFragment.java @@ -17,6 +17,7 @@ import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import net.osmand.AndroidUtils; +import net.osmand.GPXUtilities.WptPt; import net.osmand.LocationsHolder; import net.osmand.PlatformUtil; import net.osmand.ResultMatcher; @@ -27,11 +28,18 @@ 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.routing.GpxApproximator.GpxApproximationProgressCallback; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.router.RoutePlannerFrontEnd.GpxRouteApproximation; import org.apache.commons.logging.Log; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import static net.osmand.plus.measurementtool.ProfileCard.ProfileCardListener; import static net.osmand.plus.measurementtool.SliderCard.SliderCardListener; @@ -49,8 +57,11 @@ public class GpxApproximationFragment extends ContextMenuScrollFragment private ApplicationMode snapToRoadAppMode = ApplicationMode.CAR; private int distanceThreshold = 50; private boolean applyApproximation; + private GpxApproximationProgressCallback approximationProgress; + + private List locationsHolders; + private final Map resultMap = new HashMap<>(); - private LocationsHolder locationsHolder; @Nullable private GpxApproximator gpxApproximator; private ProgressBar progressBar; @@ -119,44 +130,26 @@ 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); - } } + approximationProgress = new GpxApproximationProgressCallback() { - if (gpxApproximator != null) { - gpxApproximator.setApproximationProgress(new GpxApproximator.GpxApproximationProgressCallback() { + @Override + public void start(GpxApproximator approximator) { + } - @Override - public void start() { - if (isResumed()) { - startProgress(); - } + @Override + public void updateProgress(GpxApproximator approximator, int progress) { + if (isResumed() && approximator == GpxApproximationFragment.this.gpxApproximator) { + float partSize = 100f / locationsHolders.size(); + float p = resultMap.size() * partSize + (progress / 100f) * partSize; + GpxApproximationFragment.this.updateProgress((int) p); } + } - @Override - public void updateProgress(int progress) { - if (isResumed()) { - GpxApproximationFragment.this.updateProgress(progress); - } - } - - @Override - public void finish() { - if (isResumed()) { - finishProgress(); - } - } - }); - } + @Override + public void finish(GpxApproximator approximator) { + } + }; applyButton = mainView.findViewById(R.id.right_bottom_button); cancelButton = mainView.findViewById(R.id.dismiss_button); @@ -180,7 +173,7 @@ public class GpxApproximationFragment extends ContextMenuScrollFragment } runLayoutListener(); - calculateGpxApproximation(); + calculateGpxApproximation(true); return mainView; } @@ -219,6 +212,20 @@ public class GpxApproximationFragment extends ContextMenuScrollFragment } } + private GpxApproximator getNewGpxApproximator(@NonNull LocationsHolder locationsHolder) { + GpxApproximator gpxApproximator = null; + try { + OsmandApplication app = getMyApplication(); + if (app != null) { + gpxApproximator = new GpxApproximator(app, snapToRoadAppMode, distanceThreshold, locationsHolder); + gpxApproximator.setApproximationProgress(approximationProgress); + } + } catch (IOException e) { + LOG.error(e.getMessage(), e); + } + return gpxApproximator; + } + private void updateCardsLayout() { View mainView = getMainView(); if (mainView != null) { @@ -299,13 +306,17 @@ public class GpxApproximationFragment extends ContextMenuScrollFragment } public static void showInstance(@NonNull FragmentManager fm, @Nullable Fragment targetFragment, - @NonNull LocationsHolder locationsHolder, @Nullable ApplicationMode appMode) { + @NonNull List> pointsList, @Nullable ApplicationMode appMode) { try { if (!fm.isStateSaved()) { GpxApproximationFragment fragment = new GpxApproximationFragment(); fragment.setRetainInstance(true); fragment.setTargetFragment(targetFragment, REQUEST_CODE); - fragment.setLocationsHolder(locationsHolder); + List locationsHolders = new ArrayList<>(); + for (List points : pointsList) { + locationsHolders.add(new LocationsHolder(points)); + } + fragment.setLocationsHolders(locationsHolders); fragment.setSnapToRoadAppMode(appMode); fm.beginTransaction() .replace(R.id.fragmentContainer, fragment, TAG) @@ -328,30 +339,48 @@ public class GpxApproximationFragment extends ContextMenuScrollFragment } } - public void calculateGpxApproximation() { + public boolean calculateGpxApproximation(boolean newCalculation) { + if (newCalculation) { + if (gpxApproximator != null) { + gpxApproximator.cancelApproximation(); + gpxApproximator = null; + } + resultMap.clear(); + startProgress(); + } + GpxApproximator gpxApproximator = null; + for (LocationsHolder locationsHolder : locationsHolders) { + if (!resultMap.containsKey(locationsHolder)) { + gpxApproximator = getNewGpxApproximator(locationsHolder); + break; + } + } if (gpxApproximator != null) { try { + this.gpxApproximator = gpxApproximator; gpxApproximator.setMode(snapToRoadAppMode); gpxApproximator.setPointApproximation(distanceThreshold); - approximateGpx(); + approximateGpx(gpxApproximator); + return true; } catch (Exception e) { LOG.error(e.getMessage(), e); } } + return false; } @Override public void onSliderChange(int sliderValue) { if (distanceThreshold != sliderValue) { distanceThreshold = sliderValue; - calculateGpxApproximation(); + calculateGpxApproximation(true); } } @Override public void onProfileSelect(ApplicationMode applicationMode) { if (setSnapToRoadAppMode(applicationMode)) { - calculateGpxApproximation(); + calculateGpxApproximation(true); } } @@ -363,12 +392,12 @@ public class GpxApproximationFragment extends ContextMenuScrollFragment return false; } - public LocationsHolder getLocationsHolder() { - return locationsHolder; + public List getLocationsHolders() { + return locationsHolders; } - public void setLocationsHolder(LocationsHolder locationsHolder) { - this.locationsHolder = locationsHolder; + public void setLocationsHolders(List locationsHolders) { + this.locationsHolders = locationsHolders; } public void startProgress() { @@ -393,35 +422,58 @@ public class GpxApproximationFragment extends ContextMenuScrollFragment } } - private void approximateGpx() { - if (gpxApproximator != null) { - setApplyButtonEnabled(false); - 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, gpxApproximator.getMode()); + private void approximateGpx(@NonNull final GpxApproximator gpxApproximator) { + onApproximationStarted(); + 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() { + if (!gpxApproximator.isCancelled()) { + if (gpxApproximation != null) { + resultMap.put(gpxApproximator.getLocationsHolder(), gpxApproximation); + } + if (!calculateGpxApproximation(false)) { + onApproximationFinished(); } - setApplyButtonEnabled(gpxApproximation != null); } - }); - return true; - } - return false; + } + }); } + return true; + } - @Override - public boolean isCancelled() { - return false; - } - }); + @Override + public boolean isCancelled() { + return false; + } + }); + } + + private void onApproximationStarted() { + setApplyButtonEnabled(false); + } + + private void onApproximationFinished() { + finishProgress(); + Fragment fragment = getTargetFragment(); + List approximations = new ArrayList<>(); + List> points = new ArrayList<>(); + for (LocationsHolder locationsHolder : locationsHolders) { + GpxRouteApproximation approximation = resultMap.get(locationsHolder); + if (approximation != null) { + approximations.add(approximation); + points.add(locationsHolder.getWptPtList()); + } } + if (fragment instanceof GpxApproximationFragmentListener) { + ((GpxApproximationFragmentListener) fragment).onGpxApproximationDone( + approximations, points, snapToRoadAppMode); + } + setApplyButtonEnabled(!approximations.isEmpty()); } @Override @@ -431,7 +483,7 @@ public class GpxApproximationFragment extends ContextMenuScrollFragment public interface GpxApproximationFragmentListener { - void onGpxApproximationDone(GpxRouteApproximation gpxApproximation, ApplicationMode mode); + void onGpxApproximationDone(List gpxApproximations, List> pointsList, ApplicationMode mode); void onApplyGpxApproximation(); diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/GpxData.java b/OsmAnd/src/net/osmand/plus/measurementtool/GpxData.java index a59efe63dc..89044cdfd5 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/GpxData.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/GpxData.java @@ -1,35 +1,20 @@ package net.osmand.plus.measurementtool; import net.osmand.GPXUtilities.GPXFile; -import net.osmand.GPXUtilities.TrkSegment; import net.osmand.data.QuadRect; public class GpxData { - public enum ActionType { - ADD_SEGMENT, - ADD_ROUTE_POINTS, - EDIT_SEGMENT, - OVERWRITE_SEGMENT - } + private final GPXFile gpxFile; + private final QuadRect rect; - private GPXFile gpxFile; - private TrkSegment trkSegment; - private QuadRect rect; - private ActionType actionType; - - public GpxData(GPXFile gpxFile, QuadRect rect, ActionType actionType, TrkSegment trkSegment) { + public GpxData(GPXFile gpxFile) { this.gpxFile = gpxFile; - this.rect = rect; - this.actionType = actionType; - this.trkSegment = trkSegment; - } - - public GpxData(GPXFile gpxFile, GpxData gpxData) { - this.gpxFile = gpxFile; - this.rect = gpxData.rect; - this.actionType = gpxData.actionType; - this.trkSegment = gpxData.trkSegment; + if (gpxFile != null) { + this.rect = gpxFile.getRect(); + } else { + this.rect = new QuadRect(0, 0, 0, 0); + } } public GPXFile getGpxFile() { @@ -39,12 +24,4 @@ public class GpxData { public QuadRect getRect() { return rect; } - - public ActionType getActionType() { - return actionType; - } - - public TrkSegment getTrkSegment() { - return trkSegment; - } } diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java b/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java index 9a5cbeffba..242a8f25e4 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java @@ -341,7 +341,7 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen if (editingCtx.getGpxData() != null) { gpx = editingCtx.getGpxData().getGpxFile(); } else { - gpx = editingCtx.exportRouteAsGpx(GRAPH_DATA_GPX_FILE_NAME); + gpx = editingCtx.exportGpx(GRAPH_DATA_GPX_FILE_NAME); } return gpx != null ? gpx.getAnalysis(0) : null; } diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementEditingContext.java b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementEditingContext.java index 307d89d501..91a1d6e163 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementEditingContext.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementEditingContext.java @@ -53,9 +53,11 @@ public class MeasurementEditingContext { private final MeasurementCommandManager commandManager = new MeasurementCommandManager(); private final TrkSegment before = new TrkSegment(); - private TrkSegment beforeCacheForSnap; + private List beforeSegments = new ArrayList<>(); + private List beforeSegmentsForSnap; private final TrkSegment after = new TrkSegment(); - private TrkSegment afterCacheForSnap; + private List afterSegments = new ArrayList<>(); + private List afterSegmentsForSnap; private GpxData gpxData; @@ -63,6 +65,7 @@ public class MeasurementEditingContext { private WptPt originalPointToMove; private boolean inAddPointMode; + private boolean inAddPointBeforeMode; private boolean inApproximationMode; private int calculatedPairs; private int pointsToCalculateSize; @@ -72,18 +75,23 @@ public class MeasurementEditingContext { private RouteCalculationProgress calculationProgress; private Map, RoadSegmentData> roadSegmentData = new ConcurrentHashMap<>(); - public enum CalculationMode { NEXT_SEGMENT, WHOLE_TRACK } + public enum AdditionMode { + UNDEFINED, + ADD_AFTER, + ADD_BEFORE, + } + public static class RoadSegmentData { - private ApplicationMode appMode; - private WptPt start; - private WptPt end; - private List points; - private List segments; + private final ApplicationMode appMode; + private final WptPt start; + private final WptPt end; + private final List points; + private final List segments; private double distance; public RoadSegmentData(@NonNull ApplicationMode appMode, @NonNull WptPt start, @NonNull WptPt end, @@ -156,8 +164,12 @@ public class MeasurementEditingContext { return inAddPointMode; } - public void updateCacheForSnap() { - updateCacheForSnap(true); + public boolean isInAddPointBeforeMode() { + return inAddPointBeforeMode; + } + + public void updateSegmentsForSnap() { + updateSegmentsForSnap(true); } public int getSelectedPointPosition() { @@ -176,8 +188,9 @@ public class MeasurementEditingContext { this.originalPointToMove = originalPointToMove; } - void setInAddPointMode(boolean inAddPointMode) { + void setInAddPointMode(boolean inAddPointMode, boolean inAddPointAfterMode) { this.inAddPointMode = inAddPointMode; + this.inAddPointBeforeMode = inAddPointAfterMode; } public boolean isInApproximationMode() { @@ -188,10 +201,10 @@ public class MeasurementEditingContext { this.inApproximationMode = inApproximationMode; } - public List getOriginalTrackPointList() { + public List> getOriginalSegmentPointsList() { MeasurementModeCommand command = commandManager.getLastCommand(); if (command.getType() == APPROXIMATE_POINTS) { - return ((ApplyGpxApproximationCommand) command).getPoints(); + return ((ApplyGpxApproximationCommand) command).getOriginalSegmentPointsList(); } return null; } @@ -213,10 +226,6 @@ public class MeasurementEditingContext { return gpxData != null && gpxData.getGpxFile() != null && gpxData.getGpxFile().hasRtePt(); } - public boolean hasSavedRoute() { - return gpxData != null && gpxData.getGpxFile() != null && gpxData.getGpxFile().hasRoute(); - } - public CalculationMode getLastCalculationMode() { return lastCalculationMode; } @@ -252,7 +261,7 @@ public class MeasurementEditingContext { if (appMode != MeasurementEditingContext.DEFAULT_APP_MODE || !pair.first.lastPoint || !pair.second.firstPoint) { double localDist = MapUtils.getDistance(pair.first.getLatitude(), pair.first.getLongitude(), pair.second.getLatitude(), pair.second.getLongitude()); - if(!Double.isNaN(pair.first.ele) && !Double.isNaN(pair.second.ele) && + if (!Double.isNaN(pair.first.ele) && !Double.isNaN(pair.second.ele) && pair.first.ele != 0 && pair.second.ele != 0) { double h = Math.abs(pair.first.ele - pair.second.ele); localDist = Math.sqrt(localDist * localDist + h * h); @@ -279,28 +288,104 @@ public class MeasurementEditingContext { return !roadSegmentData.isEmpty(); } + public boolean isApproximationNeeded() { + boolean hasDefaultPoints = false; + boolean newData = isNewData(); + if (!newData) { + List points = getPoints(); + WptPt prevPoint = null; + for (WptPt point : points) { + if (!point.hasProfile() && (prevPoint == null || !prevPoint.hasProfile())) { + hasDefaultPoints = true; + break; + } + prevPoint = point; + } + } + return !newData && hasDefaultPoints && getPoints().size() > 2; + } + + public boolean isSelectionNeedApproximation() { + boolean hasDefaultPoints = false; + boolean newData = isNewData(); + if (!newData && selectedPointPosition != -1) { + WptPt selectedPoint = getPoints().get(selectedPointPosition); + List segments = getBeforeSegments(); + List points = null; + for (TrkSegment segment : segments) { + if (segment.points.contains(selectedPoint)) { + points = segment.points; + } + } + WptPt prevPoint = null; + if (points != null) { + for (WptPt point : points) { + if (!point.hasProfile() && (prevPoint == null || !prevPoint.hasProfile())) { + hasDefaultPoints = true; + break; + } + prevPoint = point; + } + } + } + return !newData && hasDefaultPoints && getPoints().size() > 2; + } + public void clearSnappedToRoadPoints() { roadSegmentData.clear(); } - TrkSegment getBeforeTrkSegmentLine() { - if (beforeCacheForSnap != null) { - return beforeCacheForSnap; + List getBeforeTrkSegmentLine() { + if (beforeSegmentsForSnap != null) { + return beforeSegmentsForSnap; } - return before; + return beforeSegments; } - TrkSegment getAfterTrkSegmentLine() { - if (afterCacheForSnap != null) { - return afterCacheForSnap; + List getAfterTrkSegmentLine() { + if (afterSegmentsForSnap != null) { + return afterSegmentsForSnap; } - return after; + return afterSegments; + } + + public List getBeforeSegments() { + return beforeSegments; + } + + public List getAfterSegments() { + return afterSegments; } public List getPoints() { return getBeforePoints(); } + public List> getPointsSegments(boolean plain, boolean route) { + List> res = new ArrayList<>(); + List allPoints = getPoints(); + List segment = new ArrayList<>(); + String prevProfileType = null; + for (WptPt point : allPoints) { + String profileType = point.getProfileType(); + boolean isGap = point.isGap(); + boolean plainPoint = Algorithms.isEmpty(profileType) || (isGap && Algorithms.isEmpty(prevProfileType)); + boolean routePoint = !plainPoint; + if (plain && plainPoint || route && routePoint) { + segment.add(point); + if (isGap) { + res.add(segment); + segment = new ArrayList<>(); + } + } + prevProfileType = profileType; + } + if (!segment.isEmpty()) { + res.add(segment); + } + return res; + } + List getBeforePoints() { return before.points; } @@ -335,31 +420,118 @@ public class MeasurementEditingContext { after.points.clear(); before.points.addAll(points.subList(0, position)); after.points.addAll(points.subList(position, points.size())); - updateCacheForSnap(true); + updateSegmentsForSnap(true); + } + + private void preAddPoint(int position, AdditionMode additionMode, WptPt point) { + switch (additionMode) { + case UNDEFINED: { + if (appMode != MeasurementEditingContext.DEFAULT_APP_MODE) { + point.setProfileType(appMode.getStringKey()); + } + break; + } + case ADD_AFTER: { + List points = getBeforePoints(); + if (position > 0 && position <= points.size()) { + WptPt prevPt = points.get(position - 1); + if (prevPt.isGap()) { + point.setGap(); + if (position > 1) { + WptPt pt = points.get(position - 2); + if (pt.hasProfile()) { + prevPt.setProfileType(pt.getProfileType()); + } else { + prevPt.removeProfileType(); + } + } + } else if (prevPt.hasProfile()) { + point.setProfileType(prevPt.getProfileType()); + } + } else if (appMode != MeasurementEditingContext.DEFAULT_APP_MODE) { + point.setProfileType(appMode.getStringKey()); + } + break; + } + case ADD_BEFORE: { + List points = getAfterPoints(); + if (position >= -1 && position + 1 < points.size()) { + WptPt nextPt = points.get(position + 1); + if (nextPt.hasProfile()) { + point.setProfileType(nextPt.getProfileType()); + } + } else if (appMode != MeasurementEditingContext.DEFAULT_APP_MODE) { + point.setProfileType(appMode.getStringKey()); + } + break; + } + } } public void addPoint(WptPt pt) { + addPoint(pt, AdditionMode.UNDEFINED); + } + + public void addPoint(WptPt pt, AdditionMode additionMode) { + if (additionMode == AdditionMode.ADD_AFTER || additionMode == AdditionMode.ADD_BEFORE) { + preAddPoint(additionMode == AdditionMode.ADD_BEFORE ? -1 : getBeforePoints().size(), additionMode, pt); + } before.points.add(pt); - updateCacheForSnap(false); + updateSegmentsForSnap(false); } public void addPoint(int position, WptPt pt) { + addPoint(position, pt, AdditionMode.UNDEFINED); + } + + public void addPoint(int position, WptPt pt, AdditionMode additionMode) { + if (additionMode == AdditionMode.ADD_AFTER || additionMode == AdditionMode.ADD_BEFORE) { + preAddPoint(position, additionMode, pt); + } before.points.add(position, pt); - updateCacheForSnap(false); + updateSegmentsForSnap(false); } public void addPoints(List points) { before.points.addAll(points); - updateCacheForSnap(false); + updateSegmentsForSnap(false); + } + + public void replacePoints(List originalPoints, List points) { + if (originalPoints.size() > 1) { + int firstPointIndex = before.points.indexOf(originalPoints.get(0)); + int lastPointIndex = before.points.indexOf(originalPoints.get(originalPoints.size() - 1)); + List newPoints = new ArrayList<>(); + if (firstPointIndex != -1 && lastPointIndex != -1) { + newPoints.addAll(before.points.subList(0, firstPointIndex)); + newPoints.addAll(points); + if (before.points.size() > lastPointIndex + 1) { + newPoints.addAll(before.points.subList(lastPointIndex + 1, before.points.size())); + } + } else { + newPoints.addAll(points); + } + before.points = newPoints; + } else { + before.points = points; + } + updateSegmentsForSnap(false); } public WptPt removePoint(int position, boolean updateSnapToRoad) { if (position < 0 || position >= before.points.size()) { return new WptPt(); } - WptPt pt = before.points.remove(position); + WptPt pt = before.points.get(position); + if (position > 0 && pt.isGap()) { + WptPt prevPt = before.points.get(position - 1); + if (!prevPt.isGap()) { + prevPt.setGap(); + } + } + before.points.remove(position); if (updateSnapToRoad) { - updateCacheForSnap(false); + updateSegmentsForSnap(false); } return pt; } @@ -382,24 +554,40 @@ public class MeasurementEditingContext { public void clearBeforeSegments() { before.points.clear(); - if (beforeCacheForSnap != null) { - beforeCacheForSnap.points.clear(); + if (beforeSegmentsForSnap != null) { + beforeSegmentsForSnap.clear(); } } public void clearAfterSegments() { after.points.clear(); - if (afterCacheForSnap != null) { - afterCacheForSnap.points.clear(); + if (afterSegmentsForSnap != null) { + afterSegmentsForSnap.clear(); } } public boolean isFirstPointSelected() { - return selectedPointPosition == 0; + return isBorderPointSelected(true); } public boolean isLastPointSelected() { - return selectedPointPosition == getPoints().size() - 1; + return isBorderPointSelected(false); + } + + private boolean isBorderPointSelected(boolean first) { + WptPt selectedPoint = getPoints().get(selectedPointPosition); + List segments = getBeforeSegments(); + int count = 0; + for (TrkSegment segment : segments) { + int i = segment.points.indexOf(selectedPoint); + if (i != -1) { + int segmentPosition = selectedPointPosition - count; + return first ? segmentPosition == 0 : segmentPosition == segment.points.size() - 1; + } else { + count += segment.points.size(); + } + } + return false; } public ApplicationMode getSelectedPointAppMode() { @@ -438,8 +626,10 @@ public class MeasurementEditingContext { List> res = new ArrayList<>(); for (List points : Arrays.asList(before.points, after.points)) { for (int i = 0; i < points.size() - 1; i++) { - Pair pair = new Pair<>(points.get(i), points.get(i + 1)); - if (roadSegmentData.get(pair) == null) { + WptPt startPoint = points.get(i); + WptPt endPoint = points.get(i + 1); + Pair pair = new Pair<>(startPoint, endPoint); + if (roadSegmentData.get(pair) == null && startPoint.hasProfile()) { res.add(pair); } } @@ -447,7 +637,7 @@ public class MeasurementEditingContext { return res; } - private List> getOrderedRoadSegmentDataKeys() { + private List> getOrderedRoadSegmentDataKeys() { List> keys = new ArrayList<>(); for (List points : Arrays.asList(before.points, after.points)) { for (int i = 0; i < points.size() - 1; i++) { @@ -456,99 +646,141 @@ public class MeasurementEditingContext { } return keys; } - - private void recreateCacheForSnap(TrkSegment cache, TrkSegment original, boolean calculateIfNeeded) { - boolean hasDefaultModeOnly = true; - if (original.points.size() > 1) { - for (int i = 0; i < original.points.size(); i++) { - String profileType = original.points.get(i).getProfileType(); - if (profileType != null && !profileType.equals(DEFAULT_APP_MODE.getStringKey())) { - hasDefaultModeOnly = false; - break; - } - } - } - if (original.points.size() > 1) { - for (int i = 0; i < original.points.size() - 1; i++) { - Pair pair = new Pair<>(original.points.get(i), original.points.get(i + 1)); - RoadSegmentData data = this.roadSegmentData.get(pair); - List pts = data != null ? data.getPoints() : null; - if (pts != null) { - cache.points.addAll(pts); - } else { - if (calculateIfNeeded && !hasDefaultModeOnly) { - scheduleRouteCalculateIfNotEmpty(); + + private void recreateSegments(List segments, List segmentsForSnap, List points, boolean calculateIfNeeded) { + List roadSegmentIndexes = new ArrayList<>(); + TrkSegment s = new TrkSegment(); + segments.add(s); + boolean defaultMode = true; + if (points.size() > 1) { + for (int i = 0; i < points.size(); i++) { + WptPt point = points.get(i); + s.points.add(point); + String profileType = point.getProfileType(); + if (profileType != null) { + boolean isDefault = profileType.equals(DEFAULT_APP_MODE.getStringKey()); + boolean isGap = point.isGap(); + if (defaultMode && !isDefault && !isGap) { + roadSegmentIndexes.add(segments.size() - 1); + defaultMode = false; + } + if (isGap) { + if (!s.points.isEmpty()) { + s = new TrkSegment(); + segments.add(s); + defaultMode = true; + } } - cache.points.addAll(Arrays.asList(pair.first, pair.second)); } } } else { - cache.points.addAll(original.points); + s.points.addAll(points); + } + if (s.points.isEmpty()) { + segments.remove(s); + } + if (!segments.isEmpty()) { + for (TrkSegment segment : segments) { + TrkSegment segmentForSnap = new TrkSegment(); + for (int i = 0; i < segment.points.size() - 1; i++) { + Pair pair = new Pair<>(segment.points.get(i), segment.points.get(i + 1)); + RoadSegmentData data = this.roadSegmentData.get(pair); + List pts = data != null ? data.getPoints() : null; + if (pts != null) { + segmentForSnap.points.addAll(pts); + } else { + if (calculateIfNeeded && roadSegmentIndexes.contains(segmentsForSnap.size())) { + scheduleRouteCalculateIfNotEmpty(); + } + segmentForSnap.points.addAll(Arrays.asList(pair.first, pair.second)); + } + } + if (segmentForSnap.points.isEmpty()) { + segmentForSnap.points.addAll(segment.points); + } + segmentsForSnap.add(segmentForSnap); + } + } else if (!points.isEmpty()) { + TrkSegment segmentForSnap = new TrkSegment(); + segmentForSnap.points.addAll(points); + segmentsForSnap.add(segmentForSnap); } } void addPoints() { GpxData gpxData = getGpxData(); - if (gpxData == null || gpxData.getTrkSegment() == null || Algorithms.isEmpty(gpxData.getTrkSegment().points)) { + if (gpxData == null || gpxData.getGpxFile() == null) { return; } - List points = gpxData.getTrkSegment().points; - if (isTrackSnappedToRoad()) { - RouteImporter routeImporter = new RouteImporter(gpxData.getGpxFile()); - List segments = routeImporter.importRoute(); - List routePoints = gpxData.getGpxFile().getRoutePoints(); - int prevPointIndex = 0; - if (routePoints.isEmpty() && points.size() > 1) { - routePoints.add(points.get(0)); - routePoints.add(points.get(points.size() - 1)); - } - for (int i = 0; i < routePoints.size() - 1; i++) { - Pair pair = new Pair<>(routePoints.get(i), routePoints.get(i + 1)); - int startIndex = pair.first.getTrkPtIndex(); - if (startIndex < 0 || startIndex < prevPointIndex || startIndex >= points.size()) { - startIndex = findPointIndex(pair.first, points, prevPointIndex); + List segments = gpxData.getGpxFile().getNonEmptyTrkSegments(false); + if (Algorithms.isEmpty(segments)) { + return; + } + for (int si = 0; si < segments.size(); si++) { + TrkSegment segment = segments.get(si); + List points = segment.points; + if (segment.hasRoute()) { + RouteImporter routeImporter = new RouteImporter(segment); + List routeSegments = routeImporter.importRoute(); + List routePoints = gpxData.getGpxFile().getRoutePoints(si); + int prevPointIndex = 0; + if (routePoints.isEmpty() && points.size() > 1) { + routePoints.add(points.get(0)); + routePoints.add(points.get(points.size() - 1)); } - int endIndex = pair.second.getTrkPtIndex(); - if (endIndex < 0 || endIndex < startIndex || endIndex >= points.size()) { - endIndex = findPointIndex(pair.second, points, startIndex); - } - if (startIndex >= 0 && endIndex >= 0) { - List pairPoints = new ArrayList<>(); - for (int j = startIndex; j < endIndex && j < points.size(); j++) { - pairPoints.add(points.get(j)); - prevPointIndex = j; + for (int i = 0; i < routePoints.size() - 1; i++) { + Pair pair = new Pair<>(routePoints.get(i), routePoints.get(i + 1)); + int startIndex = pair.first.getTrkPtIndex(); + if (startIndex < 0 || startIndex < prevPointIndex || startIndex >= points.size()) { + startIndex = findPointIndex(pair.first, points, prevPointIndex); } - if (points.size() > prevPointIndex + 1) { - pairPoints.add(points.get(prevPointIndex + 1)); + int endIndex = pair.second.getTrkPtIndex(); + if (endIndex < 0 || endIndex < startIndex || endIndex >= points.size()) { + endIndex = findPointIndex(pair.second, points, startIndex); } - Iterator it = segments.iterator(); - int k = endIndex - startIndex - 1; - List pairSegments = new ArrayList<>(); - if (k == 0 && !segments.isEmpty()) { - pairSegments.add(segments.remove(0)); - } else { - while (it.hasNext() && k > 0) { - RouteSegmentResult s = it.next(); - pairSegments.add(s); - it.remove(); - k -= Math.abs(s.getEndPointIndex() - s.getStartPointIndex()); + if (startIndex >= 0 && endIndex >= 0) { + List pairPoints = new ArrayList<>(); + for (int j = startIndex; j < endIndex && j < points.size(); j++) { + pairPoints.add(points.get(j)); + prevPointIndex = j; } + if (points.size() > prevPointIndex + 1) { + pairPoints.add(points.get(prevPointIndex + 1)); + } + Iterator it = routeSegments.iterator(); + int k = endIndex - startIndex - 1; + List pairSegments = new ArrayList<>(); + if (k == 0 && !routeSegments.isEmpty()) { + pairSegments.add(routeSegments.remove(0)); + } else { + while (it.hasNext() && k > 0) { + RouteSegmentResult s = it.next(); + pairSegments.add(s); + it.remove(); + k -= Math.abs(s.getEndPointIndex() - s.getStartPointIndex()); + } + } + ApplicationMode appMode = ApplicationMode.valueOfStringKey(pair.first.getProfileType(), DEFAULT_APP_MODE); + roadSegmentData.put(pair, new RoadSegmentData(appMode, pair.first, pair.second, pairPoints, pairSegments)); } - ApplicationMode appMode = ApplicationMode.valueOfStringKey(pair.first.getProfileType(), DEFAULT_APP_MODE); - roadSegmentData.put(pair, new RoadSegmentData(appMode, pair.first, pair.second, pairPoints, pairSegments)); + } + if (!routePoints.isEmpty() && si < segments.size() - 1) { + routePoints.get(routePoints.size() - 1).setGap(); + } + addPoints(routePoints); + } else { + addPoints(points); + if (!points.isEmpty() && si < segments.size() - 1) { + points.get(points.size() - 1).setGap(); } } - addPoints(routePoints); - } else { - addPoints(points); } } - public void setPoints(GpxRouteApproximation gpxApproximation, ApplicationMode mode) { + public List setPoints(GpxRouteApproximation gpxApproximation, List originalPoints, ApplicationMode mode) { if (gpxApproximation == null || Algorithms.isEmpty(gpxApproximation.finalPoints) || Algorithms.isEmpty(gpxApproximation.result)) { - return; + return null; } - roadSegmentData.clear(); List routePoints = new ArrayList<>(); List gpxPoints = gpxApproximation.finalPoints; for (int i = 0; i < gpxPoints.size(); i++) { @@ -590,7 +822,13 @@ public class MeasurementEditingContext { break; } } - addPoints(routePoints); + WptPt lastOriginalPoint = originalPoints.get(originalPoints.size() - 1); + WptPt lastRoutePoint = routePoints.get(routePoints.size() - 1); + if (lastOriginalPoint.isGap()) { + lastRoutePoint.setGap(); + } + replacePoints(originalPoints, routePoints); + return routePoints; } private boolean isLastGpxPoint(List gpxPoints, int index) { @@ -648,24 +886,21 @@ public class MeasurementEditingContext { return index; } - boolean isTrackSnappedToRoad() { - GpxData gpxData = getGpxData(); - return gpxData != null && gpxData.getTrkSegment() != null - && !gpxData.getTrkSegment().points.isEmpty() - && gpxData.getGpxFile().hasRoute(); - } - - private void updateCacheForSnap(boolean both) { - recreateCacheForSnap(beforeCacheForSnap = new TrkSegment(), before, true); + private void updateSegmentsForSnap(boolean both) { + recreateSegments(beforeSegments = new ArrayList<>(), + beforeSegmentsForSnap = new ArrayList<>(), before.points, true); if (both) { - recreateCacheForSnap(afterCacheForSnap = new TrkSegment(), after, true); + recreateSegments(afterSegments = new ArrayList<>(), + afterSegmentsForSnap = new ArrayList<>(), after.points, true); } } - private void updateCacheForSnap(boolean both, boolean calculateIfNeeded) { - recreateCacheForSnap(beforeCacheForSnap = new TrkSegment(), before, calculateIfNeeded); + private void updateSegmentsForSnap(boolean both, boolean calculateIfNeeded) { + recreateSegments(beforeSegments = new ArrayList<>(), + beforeSegmentsForSnap = new ArrayList<>(), before.points, calculateIfNeeded); if (both) { - recreateCacheForSnap(afterCacheForSnap = new TrkSegment(), after, calculateIfNeeded); + recreateSegments(afterSegments = new ArrayList<>(), + afterSegmentsForSnap = new ArrayList<>(), after.points, calculateIfNeeded); } } @@ -718,7 +953,7 @@ public class MeasurementEditingContext { int pairs = pointsToCalculateSize; if (pairs != 0) { float pairProgress = 100f / pairs; - progress = (int)(calculatedPairs * pairProgress + (float) progress / pairs); + progress = (int) (calculatedPairs * pairProgress + (float) progress / pairs); } progressListener.updateProgress(progress); } @@ -762,7 +997,7 @@ public class MeasurementEditingContext { application.runInUIThread(new Runnable() { @Override public void run() { - updateCacheForSnap(true, false); + updateSegmentsForSnap(true, false); progressListener.refresh(); RouteCalculationParams params = getParams(false); if (params != null) { @@ -777,34 +1012,41 @@ public class MeasurementEditingContext { return params; } - public List getRoutePoints() { - List res = new ArrayList<>(); - List points = new ArrayList<>(before.points); - points.addAll(after.points); - int size = points.size(); - for (int i = 0; i < size - 1; i++) { - Pair pair = new Pair<>(points.get(i), points.get(i + 1)); - RoadSegmentData data = this.roadSegmentData.get(pair); - if (data != null) { - res.addAll(data.points); + public List> getRoutePoints() { + List> res = new ArrayList<>(); + List plainPoints = new ArrayList<>(before.points); + plainPoints.addAll(after.points); + List points = new ArrayList<>(); + for (WptPt point : plainPoints) { + if (point.getTrkPtIndex() != -1) { + points.add(point); + if (point.isGap()) { + res.add(points); + points = new ArrayList<>(); + } } } + if (!points.isEmpty()) { + res.add(points); + } return res; } @Nullable - public GPXFile exportRouteAsGpx(@NonNull String gpxName) { - if (application == null || before.points.isEmpty() || !hasRoute()) { + public GPXFile exportGpx(@NonNull String gpxName) { + if (application == null || before.points.isEmpty()) { return null; } + return RouteExporter.exportRoute(gpxName, getRouteSegments(), null); + } + + private TrkSegment getRouteSegment(int startPointIndex, int endPointIndex) { List route = new ArrayList<>(); List locations = new ArrayList<>(); - before.points.get(0).setTrkPtIndex(0); - int size = before.points.size(); - for (int i = 0; i < size - 1; i++) { + for (int i = startPointIndex; i < endPointIndex; i++) { Pair pair = new Pair<>(before.points.get(i), before.points.get(i + 1)); RoadSegmentData data = this.roadSegmentData.get(pair); - if (data != null) { + if (data != null && data.points != null && data.segments != null) { for (WptPt pt : data.points) { Location l = new Location(""); l.setLatitude(pt.getLatitude()); @@ -814,11 +1056,42 @@ public class MeasurementEditingContext { } locations.add(l); } - pair.second.setTrkPtIndex(i < size - 1 ? locations.size() : locations.size() - 1); + pair.second.setTrkPtIndex(i + 1 < before.points.size() - 1 ? locations.size() : locations.size() - 1); route.addAll(data.segments); } } - return new RouteExporter(gpxName, route, locations, null).exportRoute(); + if (!locations.isEmpty() && !route.isEmpty()) { + before.points.get(startPointIndex).setTrkPtIndex(0); + return new RouteExporter("", route, locations, null).generateRouteSegment(); + } else if (endPointIndex - startPointIndex >= 0) { + TrkSegment segment = new TrkSegment(); + segment.points = before.points.subList(startPointIndex, endPointIndex + 1); + return segment; + } + return null; + } + + private List getRouteSegments() { + List res = new ArrayList<>(); + List lastPointIndexes = new ArrayList<>(); + for (int i = 0; i < before.points.size(); i++) { + WptPt pt = before.points.get(i); + if (pt.isGap()) { + lastPointIndexes.add(i); + } + } + if (lastPointIndexes.isEmpty() || lastPointIndexes.get(lastPointIndexes.size() - 1) < before.points.size() - 1) { + lastPointIndexes.add(before.points.size() - 1); + } + int firstPointIndex = 0; + for (Integer lastPointIndex : lastPointIndexes) { + TrkSegment segment = getRouteSegment(firstPointIndex, lastPointIndex); + if (segment != null) { + res.add(segment); + } + firstPointIndex = lastPointIndex + 1; + } + return res; } interface SnapToRoadProgressListener { diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolFragment.java b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolFragment.java index c40e7b70ca..3212ef60b8 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolFragment.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolFragment.java @@ -34,9 +34,7 @@ import net.osmand.AndroidUtils; import net.osmand.FileUtils; import net.osmand.GPXUtilities; import net.osmand.GPXUtilities.GPXFile; -import net.osmand.GPXUtilities.TrkSegment; import net.osmand.GPXUtilities.WptPt; -import net.osmand.LocationsHolder; import net.osmand.data.LatLon; import net.osmand.data.QuadRect; import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile; @@ -53,7 +51,6 @@ import net.osmand.plus.base.BaseOsmAndFragment; import net.osmand.plus.base.ContextMenuFragment.MenuState; import net.osmand.plus.helpers.AndroidUiHelper; import net.osmand.plus.measurementtool.GpxApproximationFragment.GpxApproximationFragmentListener; -import net.osmand.plus.measurementtool.GpxData.ActionType; import net.osmand.plus.measurementtool.OptionsBottomSheetDialogFragment.OptionsFragmentListener; import net.osmand.plus.measurementtool.RouteBetweenPointsBottomSheetDialogFragment.RouteBetweenPointsDialogMode; import net.osmand.plus.measurementtool.RouteBetweenPointsBottomSheetDialogFragment.RouteBetweenPointsDialogType; @@ -139,7 +136,6 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route private static final int UNDO_MODE = 0x8; private int modes = 0x0; - private boolean approximationApplied = false; private boolean portrait; private boolean nightMode; private int cachedMapPosition; @@ -149,7 +145,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route private LatLon initialPoint; enum SaveType { - ROUTE_POINT, + ROUTE, LINE } @@ -355,7 +351,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route mainView.findViewById(R.id.options_button).setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { - boolean trackSnappedToRoad = editingCtx.isTrackSnappedToRoad() || editingCtx.isNewData() || approximationApplied; + boolean trackSnappedToRoad = !editingCtx.isApproximationNeeded(); OptionsBottomSheetDialogFragment.showInstance(mapActivity.getSupportFragmentManager(), MeasurementToolFragment.this, trackSnappedToRoad, @@ -503,7 +499,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route if (savedInstanceState == null) { if (fileName != null) { addNewGpxData(getGpxFile(fileName)); - } else if (!editingCtx.isNewData() && !editingCtx.hasRoutePoints() && !editingCtx.hasRoute() && editingCtx.getPointsCount() > 1) { + } else if (editingCtx.isApproximationNeeded()) { enterApproximationMode(mapActivity); } } else { @@ -570,7 +566,6 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route if (mapActivity != null) { editingCtx.getCommandManager().setMeasurementLayer(mapActivity.getMapLayers().getMeasurementToolLayer()); enterMeasurementMode(); - updateSnapToRoadControls(); if (gpxData != null && addPoints) { if (!isUndoMode()) { List points = gpxData.getGpxFile().getRoutePoints(); @@ -581,13 +576,9 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route } } } - ActionType actionType = gpxData.getActionType(); - if (actionType == ActionType.ADD_ROUTE_POINTS) { - displayRoutePoints(); - } else if (actionType == ActionType.EDIT_SEGMENT) { - displaySegmentPoints(); - } + collectPoints(); } + updateSnapToRoadControls(); setMode(UNDO_MODE, false); } } @@ -675,16 +666,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route private void updateMainIcon() { GpxData gpxData = editingCtx.getGpxData(); - if (gpxData != null) { - ActionType actionType = gpxData.getActionType(); - if (actionType == ActionType.ADD_SEGMENT || actionType == ActionType.EDIT_SEGMENT) { - mainIcon.setImageDrawable(getActiveIcon(R.drawable.ic_action_polygom_dark)); - } else { - mainIcon.setImageDrawable(getActiveIcon(R.drawable.ic_action_markers_dark)); - } - } else { - mainIcon.setImageDrawable(getActiveIcon(R.drawable.ic_action_ruler)); - } + mainIcon.setImageDrawable(getActiveIcon(gpxData != null ? R.drawable.ic_action_polygom_dark : R.drawable.ic_action_ruler)); } private void startSnapToRoad(boolean rememberPreviousTitle) { @@ -696,15 +678,15 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route toolBarController.setTitle(getString(R.string.route_between_points)); mapActivity.refreshMap(); - if (editingCtx.isNewData() || editingCtx.hasRoutePoints() || editingCtx.hasRoute() || editingCtx.getPointsCount() <= 2) { + if (editingCtx.isApproximationNeeded()) { + enterApproximationMode(mapActivity); + } else { RouteBetweenPointsBottomSheetDialogFragment.showInstance(mapActivity.getSupportFragmentManager(), this, RouteBetweenPointsDialogType.WHOLE_ROUTE_CALCULATION, editingCtx.getLastCalculationMode() == CalculationMode.NEXT_SEGMENT ? RouteBetweenPointsDialogMode.SINGLE : RouteBetweenPointsDialogMode.ALL, editingCtx.getAppMode()); - } else { - enterApproximationMode(mapActivity); } } } @@ -713,12 +695,11 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route MapActivity mapActivity = getMapActivity(); if (mapActivity != null) { if (editingCtx.getPointsCount() > 0) { - GpxData gpxData = editingCtx.getGpxData(); - if (editingCtx.isNewData() || (isInEditMode() && gpxData.getActionType() == ActionType.EDIT_SEGMENT)) { + if (editingCtx.isNewData() || isInEditMode()) { if (showDialog) { openSaveAsNewTrackMenu(mapActivity); } else { - saveNewGpx(null, getSuggestedFileName(), true, false, finalSaveAction); + saveNewGpx("", getSuggestedFileName(), true, false, finalSaveAction); } } else { addToGpx(mapActivity, finalSaveAction); @@ -732,6 +713,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route @Override public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); + MapActivity mapActivity = getMapActivity(); switch (requestCode) { case SnapTrackWarningFragment.REQUEST_CODE: switch (resultCode) { @@ -742,14 +724,16 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route updateToolbar(); break; case SnapTrackWarningFragment.CONTINUE_RESULT_CODE: - MapActivity mapActivity = getMapActivity(); if (mapActivity != null) { ApplicationMode mode = editingCtx.getAppMode(); if (mode == ApplicationMode.DEFAULT || "public_transport".equals(mode.getRoutingProfile())) { mode = null; } - GpxApproximationFragment.showInstance(mapActivity.getSupportFragmentManager(), - this, new LocationsHolder(editingCtx.getPoints()), mode); + List> pointsSegments = editingCtx.getPointsSegments(true, false); + if (!pointsSegments.isEmpty()) { + GpxApproximationFragment.showInstance( + mapActivity.getSupportFragmentManager(), this, pointsSegments, mode); + } } break; } @@ -757,10 +741,14 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route case ExitBottomSheetDialogFragment.REQUEST_CODE: switch (resultCode) { case ExitBottomSheetDialogFragment.EXIT_RESULT_CODE: - dismiss(getMapActivity()); + if (mapActivity != null) { + dismiss(getMapActivity()); + } break; case ExitBottomSheetDialogFragment.SAVE_RESULT_CODE: - openSaveAsNewTrackMenu(getMapActivity()); + if (mapActivity != null) { + openSaveAsNewTrackMenu(getMapActivity()); + } break; } } @@ -792,7 +780,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route } else { String trackName = getSuggestedFileName(); if (editingCtx.hasRoute()) { - GPXFile gpx = editingCtx.exportRouteAsGpx(trackName); + GPXFile gpx = editingCtx.exportGpx(trackName); if (gpx != null) { dismiss(mapActivity); runNavigation(gpx, appMode); @@ -800,15 +788,15 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route Toast.makeText(mapActivity, getString(R.string.error_occurred_saving_gpx), Toast.LENGTH_SHORT).show(); } } else { - if (editingCtx.isNewData() || editingCtx.hasRoutePoints()) { + if (editingCtx.isApproximationNeeded()) { + setMode(DIRECTION_MODE, true); + enterApproximationMode(mapActivity); + } else { GPXFile gpx = new GPXFile(Version.getFullVersion(requireMyApplication())); - gpx.addRoutePoints(points); + gpx.addRoutePoints(points, true); dismiss(mapActivity); targetPointsHelper.clearAllPoints(false); mapActions.enterRoutePlanningModeGivenGpx(gpx, appMode, null, null, true, true, MenuState.HEADER_ONLY); - } else { - setMode(DIRECTION_MODE, true); - enterApproximationMode(mapActivity); } } } @@ -860,7 +848,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route } @Override - public void addToTheTrackOnClick() { + public void addToTrackOnClick() { MapActivity mapActivity = getMapActivity(); if (mapActivity != null) { if (editingCtx.getPointsCount() > 0) { @@ -927,7 +915,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route MeasurementToolLayer measurementLayer = getMeasurementLayer(); if (measurementLayer != null) { measurementLayer.moveMapToPoint(editingCtx.getSelectedPointPosition()); - editingCtx.setInAddPointMode(true); + editingCtx.setInAddPointMode(true, false); editingCtx.splitSegments(editingCtx.getSelectedPointPosition() + 1); } ((TextView) mainView.findViewById(R.id.add_point_before_after_text)).setText(mainView.getResources().getString(R.string.add_point_after)); @@ -940,7 +928,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route MeasurementToolLayer measurementLayer = getMeasurementLayer(); if (measurementLayer != null) { measurementLayer.moveMapToPoint(editingCtx.getSelectedPointPosition()); - editingCtx.setInAddPointMode(true); + editingCtx.setInAddPointMode(true, true); editingCtx.splitSegments(editingCtx.getSelectedPointPosition()); } ((TextView) mainView.findViewById(R.id.add_point_before_after_text)).setText(mainView.getResources().getString(R.string.add_point_before)); @@ -1081,8 +1069,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route SelectedGpxFile selectedGpxFile = mapActivity.getMyApplication().getSelectedGpxHelper() .getSelectedFileByPath(gpxFile.path); boolean showOnMap = selectedGpxFile != null; - saveExistingGpx(gpxFile, showOnMap, ActionType.ADD_SEGMENT, - editingCtx.hasRoute() ? SaveType.ROUTE_POINT : SaveType.LINE, FinalSaveAction.SHOW_TOAST); + saveExistingGpx(gpxFile, showOnMap, false, true, FinalSaveAction.SHOW_TOAST); } } @@ -1107,10 +1094,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route private GpxData setupGpxData(@Nullable GPXFile gpxFile) { GpxData gpxData = null; if (gpxFile != null) { - QuadRect rect = gpxFile.getRect(); - TrkSegment segment = gpxFile.getNonEmptyTrkSegment(); - ActionType actionType = segment == null ? ActionType.ADD_ROUTE_POINTS : ActionType.EDIT_SEGMENT; - gpxData = new GpxData(gpxFile, rect, actionType, segment); + gpxData = new GpxData(gpxFile); } editingCtx.setGpxData(gpxData); return gpxData; @@ -1128,22 +1112,8 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route } @Override - public void onSaveAsNewTrack(String folderName, String fileName, boolean showOnMap, boolean simplifiedTrack) { - saveNewGpx(folderName, fileName, showOnMap, simplifiedTrack, FinalSaveAction.SHOW_IS_SAVED_FRAGMENT); - } - - private void saveNewGpx(String folderName, String fileName, boolean showOnMap, boolean simplifiedTrack, - FinalSaveAction finalSaveAction) { - OsmandApplication app = getMyApplication(); - if (app != null) { - File dir = getMyApplication().getAppPath(GPX_INDEX_DIR); - if (folderName != null && !dir.getName().equals(folderName)) { - dir = new File(dir, folderName); - } - fileName += GPX_FILE_EXT; - SaveType saveType = simplifiedTrack ? SaveType.LINE : SaveType.ROUTE_POINT; - saveNewGpx(dir, fileName, showOnMap, saveType, finalSaveAction); - } + public void onSaveAsNewTrack(String folderName, String fileName, boolean showOnMap, boolean simplified) { + saveNewGpx(folderName, fileName, showOnMap, simplified, FinalSaveAction.SHOW_IS_SAVED_FRAGMENT); } MeasurementAdapterListener createMeasurementAdapterListener(final ItemTouchHelper touchHelper) { @@ -1219,7 +1189,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route final ApplicationMode appMode = editingCtx.getAppMode(); if (mapActivity != null) { Drawable icon; - if (editingCtx.isTrackSnappedToRoad() || editingCtx.isNewData() || approximationApplied) { + if (!editingCtx.isApproximationNeeded() || editingCtx.isNewData()) { if (appMode == MeasurementEditingContext.DEFAULT_APP_MODE) { icon = getActiveIcon(R.drawable.ic_action_split_interval); } else { @@ -1241,23 +1211,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route } } - private void displayRoutePoints() { - MeasurementToolLayer measurementLayer = getMeasurementLayer(); - GpxData gpxData = editingCtx.getGpxData(); - GPXFile gpx = gpxData != null ? gpxData.getGpxFile() : null; - if (gpx != null) { - List points = gpx.getRoutePoints(); - if (measurementLayer != null) { - if (!isUndoMode()) { - editingCtx.addPoints(points); - } - updateAdditionalInfoView(); - updateDistancePointsText(); - } - } - } - - private void displaySegmentPoints() { + private void collectPoints() { MeasurementToolLayer measurementLayer = getMeasurementLayer(); if (measurementLayer != null) { if (!isUndoMode()) { @@ -1354,7 +1308,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route switchAddPointBeforeAfterMode(false); editingCtx.splitSegments(editingCtx.getBeforePoints().size() + editingCtx.getAfterPoints().size()); editingCtx.setSelectedPointPosition(-1); - editingCtx.setInAddPointMode(false); + editingCtx.setInAddPointMode(false, false); MeasurementToolLayer measurementLayer = getMeasurementLayer(); if (measurementLayer != null) { measurementLayer.refreshMap(); @@ -1366,7 +1320,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route switchAddPointBeforeAfterMode(false); editingCtx.splitSegments(editingCtx.getBeforePoints().size() + editingCtx.getAfterPoints().size()); editingCtx.setSelectedPointPosition(-1); - editingCtx.setInAddPointMode(false); + editingCtx.setInAddPointMode(false, false); MeasurementToolLayer measurementToolLayer = getMeasurementLayer(); if (measurementToolLayer != null) { measurementToolLayer.refreshMap(); @@ -1520,8 +1474,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route SelectedGpxFile selectedGpxFile = mapActivity.getMyApplication().getSelectedGpxHelper().getSelectedFileByPath(gpx.path); boolean showOnMap = selectedGpxFile != null; - saveExistingGpx(gpx, showOnMap, gpxData.getActionType(), - editingCtx.hasRoute() ? SaveType.ROUTE_POINT : SaveType.LINE, finalSaveAction); + saveExistingGpx(gpx, showOnMap, false, false, finalSaveAction); } } @@ -1555,30 +1508,45 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route return displayedName; } - private void saveNewGpx(@NonNull File dir, @NonNull String fileName, boolean showOnMap, SaveType saveType, FinalSaveAction finalSaveAction) { - saveGpx(new File(dir, fileName), null, null, saveType, finalSaveAction, showOnMap); + private void saveNewGpx(String folderName, String fileName, boolean showOnMap, + boolean simplified, FinalSaveAction finalSaveAction) { + OsmandApplication app = getMyApplication(); + if (app != null) { + File dir = getMyApplication().getAppPath(GPX_INDEX_DIR); + if (!Algorithms.isEmpty(folderName) && !dir.getName().equals(folderName)) { + dir = new File(dir, folderName); + } + fileName += GPX_FILE_EXT; + saveNewGpx(dir, fileName, showOnMap, simplified, finalSaveAction); + } } - private void saveExistingGpx(@NonNull GPXFile gpx, boolean showOnMap, ActionType actionType, - SaveType saveType, FinalSaveAction finalSaveAction) { - saveGpx(new File(gpx.path), gpx, actionType, saveType, finalSaveAction, showOnMap); + private void saveNewGpx(@NonNull File dir, @NonNull String fileName, boolean showOnMap, + boolean simplified, FinalSaveAction finalSaveAction) { + saveGpx(new File(dir, fileName), null, simplified, false, finalSaveAction, showOnMap); } - private void saveGpx(@NonNull final File outFile, @Nullable GPXFile gpxFile, final ActionType actionType, - SaveType saveType, final FinalSaveAction finalSaveAction, final boolean showOnMap) { + private void saveExistingGpx(@NonNull GPXFile gpx, boolean showOnMap, + boolean simplified, boolean addToTrack, FinalSaveAction finalSaveAction) { + saveGpx(new File(gpx.path), gpx, simplified, addToTrack, finalSaveAction, showOnMap); + } + + private void saveGpx(@NonNull final File outFile, @Nullable GPXFile gpxFile, boolean simplified, + boolean addToTrack, final FinalSaveAction finalSaveAction, final boolean showOnMap) { SaveGpxRouteListener saveGpxRouteListener = new SaveGpxRouteListener() { @Override public void gpxSavingFinished(Exception warning, GPXFile savedGpxFile, File backupFile) { - onGpxSaved(warning, savedGpxFile, outFile, backupFile, actionType, finalSaveAction, showOnMap); + onGpxSaved(warning, savedGpxFile, outFile, backupFile, finalSaveAction, showOnMap); } }; - SaveGpxRouteAsyncTask saveTask = new SaveGpxRouteAsyncTask(this, outFile, gpxFile, actionType, saveType, showOnMap, saveGpxRouteListener); + SaveGpxRouteAsyncTask saveTask = new SaveGpxRouteAsyncTask(this, outFile, gpxFile, simplified, + addToTrack, showOnMap, saveGpxRouteListener); saveTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } private void onGpxSaved(Exception warning, GPXFile savedGpxFile, final File outFile, final File backupFile, - final ActionType actionType, FinalSaveAction finalSaveAction, final boolean showOnMap) { + FinalSaveAction finalSaveAction, final boolean showOnMap) { MapActivity mapActivity = getMapActivity(); if (mapActivity == null) { return; @@ -1586,9 +1554,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route mapActivity.refreshMap(); if (warning == null) { if (editingCtx.isNewData() && savedGpxFile != null) { - QuadRect rect = savedGpxFile.getRect(); - TrkSegment segment = savedGpxFile.getNonEmptyTrkSegment(); - GpxData gpxData = new GpxData(savedGpxFile, rect, ActionType.EDIT_SEGMENT, segment); + GpxData gpxData = new GpxData(savedGpxFile); editingCtx.setGpxData(gpxData); updateToolbar(); } @@ -1614,7 +1580,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route GPXFile gpx = GPXUtilities.loadGPXFile(outFile); setupGpxData(gpx); if (showOnMap) { - showGpxOnMap(app, gpx, actionType, false); + showGpxOnMap(app, gpx, false); } } else { setupGpxData(null); @@ -1660,12 +1626,10 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route } } - protected static void showGpxOnMap(OsmandApplication app, GPXFile gpx, ActionType actionType, boolean isNewGpx) { + protected static void showGpxOnMap(OsmandApplication app, GPXFile gpx, boolean isNewGpx) { SelectedGpxFile sf = app.getSelectedGpxHelper().selectGpxFile(gpx, true, false); if (sf != null && !isNewGpx) { - if (actionType == ActionType.ADD_SEGMENT || actionType == ActionType.EDIT_SEGMENT) { - sf.processPoints(app); - } + sf.processPoints(app); } } @@ -1704,25 +1668,9 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route if (mapActivity == null) { return; } - final GpxData gpxData = editingCtx.getGpxData(); String fileName = getSuggestedFileName(); - String actionStr = getString(R.string.plan_route); boolean editMode = isInEditMode(); - if (editMode) { - ActionType actionType = gpxData.getActionType(); - switch (actionType) { - case ADD_ROUTE_POINTS: - actionStr = getString(R.string.add_route_points); - break; - case ADD_SEGMENT: - actionStr = getString(R.string.add_line); - break; - case EDIT_SEGMENT: - case OVERWRITE_SEGMENT: - actionStr = getString(R.string.edit_line); - break; - } - } + String actionStr = getString(editMode ? R.string.edit_line : R.string.plan_route); if (!editMode && editingCtx.getPointsCount() > 1) { toolBarController.setTitle(fileName.replace('_', ' ')); toolBarController.setDescription(actionStr); @@ -1969,12 +1917,13 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route } @Override - public void onGpxApproximationDone(GpxRouteApproximation gpxApproximation, ApplicationMode mode) { + public void onGpxApproximationDone(List gpxApproximations, List> pointsList, ApplicationMode mode) { MeasurementToolLayer measurementLayer = getMeasurementLayer(); if (measurementLayer != null) { + boolean approximationMode = editingCtx.isInApproximationMode(); editingCtx.setInApproximationMode(true); - ApplyGpxApproximationCommand command = new ApplyGpxApproximationCommand(measurementLayer, gpxApproximation, mode); - if (!editingCtx.getCommandManager().update(command)) { + ApplyGpxApproximationCommand command = new ApplyGpxApproximationCommand(measurementLayer, gpxApproximations, pointsList, mode); + if (!approximationMode || !editingCtx.getCommandManager().update(command)) { editingCtx.getCommandManager().execute(command); } if (additionalInfoExpanded) { @@ -1986,7 +1935,6 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route @Override public void onApplyGpxApproximation() { - approximationApplied = true; exitApproximationMode(); doAddOrMovePointCommonStuff(); updateSnapToRoadControls(); @@ -2001,7 +1949,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route if (mapActivity != null) { if (editingCtx.hasRoute()) { String trackName = getSuggestedFileName(); - GPXFile gpx = editingCtx.exportRouteAsGpx(trackName); + GPXFile gpx = editingCtx.exportGpx(trackName); if (gpx != null) { ApplicationMode appMode = editingCtx.getAppMode(); dismiss(mapActivity); diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolLayer.java b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolLayer.java index 23a69002f8..cad4985d38 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolLayer.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolLayer.java @@ -17,7 +17,7 @@ import net.osmand.data.PointDescription; import net.osmand.data.QuadRect; import net.osmand.data.RotatedTileBox; import net.osmand.plus.R; -import net.osmand.plus.settings.backend.ApplicationMode; +import net.osmand.plus.measurementtool.MeasurementEditingContext.AdditionMode; import net.osmand.plus.views.OsmandMapLayer; import net.osmand.plus.views.OsmandMapTileView; import net.osmand.plus.views.Renderable; @@ -183,22 +183,27 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL lineAttrs.updatePaints(view.getApplication(), settings, tb); if (editingCtx.isInApproximationMode()) { - List originalTrackPointList = editingCtx.getOriginalTrackPointList(); - if (originalTrackPointList != null) { + List> originalPointsList = editingCtx.getOriginalSegmentPointsList(); + if (originalPointsList != null) { lineAttrs.customColorPaint.setColor(ContextCompat.getColor(view.getContext(), R.color.activity_background_transparent_color_dark)); - new Renderable.StandardTrack(new ArrayList<>(originalTrackPointList), 17.2). - drawSegment(view.getZoom(), lineAttrs.customColorPaint, canvas, tb); + for (List points : originalPointsList) { + new Renderable.StandardTrack(new ArrayList<>(points), 17.2). + drawSegment(view.getZoom(), lineAttrs.customColorPaint, canvas, tb); + } } } - TrkSegment before = editingCtx.getBeforeTrkSegmentLine(); - new Renderable.StandardTrack(new ArrayList<>(before.points), 17.2). - drawSegment(view.getZoom(), lineAttrs.paint, canvas, tb); - - TrkSegment after = editingCtx.getAfterTrkSegmentLine(); - new Renderable.StandardTrack(new ArrayList<>(after.points), 17.2). - drawSegment(view.getZoom(), lineAttrs.paint, canvas, tb); + List before = editingCtx.getBeforeTrkSegmentLine(); + for (TrkSegment segment : before) { + new Renderable.StandardTrack(new ArrayList<>(segment.points), 17.2). + drawSegment(view.getZoom(), lineAttrs.paint, canvas, tb); + } + List after = editingCtx.getAfterTrkSegmentLine(); + for (TrkSegment segment : after) { + new Renderable.StandardTrack(new ArrayList<>(segment.points), 17.2). + drawSegment(view.getZoom(), lineAttrs.paint, canvas, tb); + } drawPoints(canvas, tb); } @@ -308,36 +313,52 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL } private void drawBeforeAfterPath(Canvas canvas, RotatedTileBox tb) { - TrkSegment before = editingCtx.getBeforeTrkSegmentLine(); - TrkSegment after = editingCtx.getAfterTrkSegmentLine(); - if (before.points.size() > 0 || after.points.size() > 0) { + List before = editingCtx.getBeforeSegments(); + List after = editingCtx.getAfterSegments(); + if (before.size() > 0 || after.size() > 0) { path.reset(); tx.clear(); ty.clear(); - if (before.points.size() > 0) { - WptPt pt = before.points.get(before.points.size() - 1); - float locX = tb.getPixXFromLatLon(pt.lat, pt.lon); - float locY = tb.getPixYFromLatLon(pt.lat, pt.lon); - tx.add(locX); - ty.add(locY); - tx.add((float) tb.getCenterPixelX()); - ty.add((float) tb.getCenterPixelY()); - } - if (after.points.size() > 0) { - if (before.points.size() == 0) { + boolean hasPointsBefore = false; + boolean hasGapBefore = false; + if (before.size() > 0) { + TrkSegment segment = before.get(before.size() - 1); + if (segment.points.size() > 0) { + hasPointsBefore = true; + WptPt pt = segment.points.get(segment.points.size() - 1); + hasGapBefore = pt.isGap(); + if (!pt.isGap() || !editingCtx.isInAddPointBeforeMode()) { + float locX = tb.getPixXFromLatLon(pt.lat, pt.lon); + float locY = tb.getPixYFromLatLon(pt.lat, pt.lon); + tx.add(locX); + ty.add(locY); + } tx.add((float) tb.getCenterPixelX()); ty.add((float) tb.getCenterPixelY()); } - WptPt pt = after.points.get(0); - float locX = tb.getPixXFromLatLon(pt.lat, pt.lon); - float locY = tb.getPixYFromLatLon(pt.lat, pt.lon); - tx.add(locX); - ty.add(locY); + } + if (after.size() > 0) { + TrkSegment segment = after.get(0); + if (segment.points.size() > 0) { + if (!hasPointsBefore) { + tx.add((float) tb.getCenterPixelX()); + ty.add((float) tb.getCenterPixelY()); + } + if (!hasGapBefore || editingCtx.isInAddPointBeforeMode()) { + WptPt pt = segment.points.get(0); + float locX = tb.getPixXFromLatLon(pt.lat, pt.lon); + float locY = tb.getPixYFromLatLon(pt.lat, pt.lon); + tx.add(locX); + ty.add(locY); + } + } } - GeometryWay.calculatePath(tb, tx, ty, path); - canvas.drawPath(path, lineAttrs.paint); + if (!tx.isEmpty() && !ty.isEmpty()) { + GeometryWay.calculatePath(tb, tx, ty, path); + canvas.drawPath(path, lineAttrs.paint); + } } } @@ -359,7 +380,7 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL canvas.rotate(tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY()); } - public WptPt addCenterPoint() { + public WptPt addCenterPoint(boolean addPointBefore) { RotatedTileBox tb = view.getCurrentRotatedTileBox(); LatLon l = tb.getCenterLatLon(); WptPt pt = new WptPt(); @@ -367,18 +388,13 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL pt.lon = l.getLongitude(); boolean allowed = editingCtx.getPointsCount() == 0 || !editingCtx.getPoints().get(editingCtx.getPointsCount() - 1).equals(pt); if (allowed) { - - ApplicationMode applicationMode = editingCtx.getAppMode(); - if (applicationMode != MeasurementEditingContext.DEFAULT_APP_MODE) { - pt.setProfileType(applicationMode.getStringKey()); - } - editingCtx.addPoint(pt); + editingCtx.addPoint(pt, addPointBefore ? AdditionMode.ADD_BEFORE : AdditionMode.ADD_AFTER); return pt; } return null; } - public WptPt addPoint() { + public WptPt addPoint(boolean addPointBefore) { if (pressedPointLatLon != null) { WptPt pt = new WptPt(); double lat = pressedPointLatLon.getLatitude(); @@ -388,11 +404,7 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL pressedPointLatLon = null; boolean allowed = editingCtx.getPointsCount() == 0 || !editingCtx.getPoints().get(editingCtx.getPointsCount() - 1).equals(pt); if (allowed) { - ApplicationMode applicationMode = editingCtx.getAppMode(); - if (applicationMode != MeasurementEditingContext.DEFAULT_APP_MODE) { - pt.setProfileType(applicationMode.getStringKey()); - } - editingCtx.addPoint(pt); + editingCtx.addPoint(pt, addPointBefore ? AdditionMode.ADD_BEFORE : AdditionMode.ADD_AFTER); moveMapToLatLon(lat, lon); return pt; } diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/OptionsBottomSheetDialogFragment.java b/OsmAnd/src/net/osmand/plus/measurementtool/OptionsBottomSheetDialogFragment.java index 6cfbcf8f3f..0a9c690a1e 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/OptionsBottomSheetDialogFragment.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/OptionsBottomSheetDialogFragment.java @@ -108,7 +108,7 @@ public class OptionsBottomSheetDialogFragment extends MenuBottomSheetDialogFragm public void onClick(View v) { Fragment fragment = getTargetFragment(); if (fragment instanceof OptionsFragmentListener) { - ((OptionsFragmentListener) fragment).addToTheTrackOnClick(); + ((OptionsFragmentListener) fragment).addToTrackOnClick(); } dismiss(); } @@ -229,7 +229,7 @@ public class OptionsBottomSheetDialogFragment extends MenuBottomSheetDialogFragm void saveAsNewTrackOnClick(); - void addToTheTrackOnClick(); + void addToTrackOnClick(); void directionsOnClick(); diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/PointsCard.java b/OsmAnd/src/net/osmand/plus/measurementtool/PointsCard.java index 4b0117bd42..9d14598856 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/PointsCard.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/PointsCard.java @@ -35,9 +35,7 @@ public class PointsCard extends BaseCard implements OnUpdateAdditionalInfoListen @Override protected void updateContent() { MeasurementEditingContext editingCtx = fragment.getEditingCtx(); - final GpxData gpxData = editingCtx.getGpxData(); - adapter = new MeasurementToolAdapter(mapActivity, editingCtx.getPoints(), - gpxData != null ? gpxData.getActionType() : null); + adapter = new MeasurementToolAdapter(mapActivity, editingCtx.getPoints()); RecyclerView pointsRv = view.findViewById(R.id.measure_points_recycler_view); ItemTouchHelper touchHelper = new ItemTouchHelper(new ReorderItemTouchHelperCallback(adapter)); touchHelper.attachToRecyclerView(pointsRv); diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/SaveGpxRouteAsyncTask.java b/OsmAnd/src/net/osmand/plus/measurementtool/SaveGpxRouteAsyncTask.java index ddae8ed26d..a73d8667cc 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/SaveGpxRouteAsyncTask.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/SaveGpxRouteAsyncTask.java @@ -4,10 +4,13 @@ import android.app.ProgressDialog; import android.content.Context; import android.os.AsyncTask; +import androidx.annotation.NonNull; + import net.osmand.AndroidUtils; import net.osmand.FileUtils; import net.osmand.GPXUtilities; import net.osmand.GPXUtilities.GPXFile; +import net.osmand.GPXUtilities.Route; import net.osmand.GPXUtilities.Track; import net.osmand.GPXUtilities.TrkSegment; import net.osmand.GPXUtilities.WptPt; @@ -15,42 +18,38 @@ import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.Version; import net.osmand.plus.activities.MapActivity; -import net.osmand.plus.measurementtool.GpxData.ActionType; -import net.osmand.plus.measurementtool.MeasurementToolFragment.SaveType; import net.osmand.util.Algorithms; import java.io.File; import java.lang.ref.WeakReference; -import java.util.ArrayList; import java.util.List; import static net.osmand.IndexConstants.GPX_FILE_EXT; class SaveGpxRouteAsyncTask extends AsyncTask { - private WeakReference fragmentRef; + private final WeakReference fragmentRef; private ProgressDialog progressDialog; - private SaveType saveType; - private ActionType actionType; - - private File outFile; + private final File outFile; private File backupFile; - private GPXFile gpxFile; + private final GPXFile gpxFile; private GPXFile savedGpxFile; - private boolean showOnMap; - - private SaveGpxRouteListener saveGpxRouteListener; + private final boolean simplified; + private final boolean addToTrack; + private final boolean showOnMap; + private final SaveGpxRouteListener saveGpxRouteListener; public SaveGpxRouteAsyncTask(MeasurementToolFragment fragment, File outFile, GPXFile gpxFile, - ActionType actionType, SaveType saveType, boolean showOnMap, SaveGpxRouteListener saveGpxRouteListener) { + boolean simplified, boolean addToTrack, boolean showOnMap, + SaveGpxRouteListener saveGpxRouteListener) { fragmentRef = new WeakReference<>(fragment); this.outFile = outFile; this.showOnMap = showOnMap; this.gpxFile = gpxFile; - this.actionType = actionType; - this.saveType = saveType; + this.simplified = simplified; + this.addToTrack = addToTrack; this.saveGpxRouteListener = saveGpxRouteListener; } @@ -77,119 +76,73 @@ class SaveGpxRouteAsyncTask extends AsyncTask { OsmandApplication app = mapActivity.getMyApplication(); MeasurementToolLayer measurementLayer = mapActivity.getMapLayers().getMeasurementToolLayer(); MeasurementEditingContext editingCtx = fragment.getEditingCtx(); - - List points = editingCtx.getPoints(); - TrkSegment before = editingCtx.getBeforeTrkSegmentLine(); - TrkSegment after = editingCtx.getAfterTrkSegmentLine(); + Exception res = null; if (gpxFile == null) { String fileName = outFile.getName(); String trackName = fileName.substring(0, fileName.length() - GPX_FILE_EXT.length()); - GPXFile gpx = new GPXFile(Version.getFullVersion(app)); - if (measurementLayer != null) { - if (saveType == MeasurementToolFragment.SaveType.LINE) { - TrkSegment segment = new TrkSegment(); - if (editingCtx.hasRoute()) { - segment.points.addAll(editingCtx.getRoutePoints()); - } else { - segment.points.addAll(before.points); - segment.points.addAll(after.points); - } - Track track = new Track(); - track.name = trackName; - track.segments.add(segment); - gpx.tracks.add(track); - } else if (saveType == MeasurementToolFragment.SaveType.ROUTE_POINT) { - if (editingCtx.hasRoute()) { - GPXFile newGpx = editingCtx.exportRouteAsGpx(trackName); - if (newGpx != null) { - gpx = newGpx; - } - } - gpx.addRoutePoints(points); - } - } - Exception res = GPXUtilities.writeGpxFile(outFile, gpx); + GPXFile gpx = generateGpxFile(measurementLayer, editingCtx, trackName, new GPXFile(Version.getFullVersion(app))); + res = GPXUtilities.writeGpxFile(outFile, gpx); gpx.path = outFile.getAbsolutePath(); savedGpxFile = gpx; if (showOnMap) { - MeasurementToolFragment.showGpxOnMap(app, gpx, actionType, true); + MeasurementToolFragment.showGpxOnMap(app, gpx, true); } - return res; } else { - GPXFile gpx = gpxFile; backupFile = FileUtils.backupFile(app, outFile); String trackName = Algorithms.getFileNameWithoutExtension(outFile); - if (measurementLayer != null) { - if (fragment.isPlanRouteMode()) { - if (saveType == MeasurementToolFragment.SaveType.LINE) { - TrkSegment segment = new TrkSegment(); - if (editingCtx.hasRoute()) { - segment.points.addAll(editingCtx.getRoutePoints()); - } else { - segment.points.addAll(before.points); - segment.points.addAll(after.points); - } - Track track = new Track(); - track.name = trackName; - track.segments.add(segment); - gpx.tracks.add(track); - } else if (saveType == MeasurementToolFragment.SaveType.ROUTE_POINT) { - if (editingCtx.hasRoute()) { - GPXFile newGpx = editingCtx.exportRouteAsGpx(trackName); - if (newGpx != null) { - gpx = newGpx; - } - } - gpx.addRoutePoints(points); - } - } else if (actionType != null) { - GpxData gpxData = editingCtx.getGpxData(); - switch (actionType) { - case ADD_SEGMENT: { - List snappedPoints = new ArrayList<>(); - snappedPoints.addAll(before.points); - snappedPoints.addAll(after.points); - gpx.addTrkSegment(snappedPoints); - break; - } - case ADD_ROUTE_POINTS: { - gpx.replaceRoutePoints(points); - break; - } - case EDIT_SEGMENT: { - if (gpxData != null) { - TrkSegment segment = new TrkSegment(); - segment.points.addAll(points); - gpx.replaceSegment(gpxData.getTrkSegment(), segment); - } - break; - } - case OVERWRITE_SEGMENT: { - if (gpxData != null) { - List snappedPoints = new ArrayList<>(); - snappedPoints.addAll(before.points); - snappedPoints.addAll(after.points); - TrkSegment segment = new TrkSegment(); - segment.points.addAll(snappedPoints); - gpx.replaceSegment(gpxData.getTrkSegment(), segment); - } - break; - } - } - } else { - gpx.addRoutePoints(points); - } - } - Exception res = null; + GPXFile gpx = generateGpxFile(measurementLayer, editingCtx, trackName, gpxFile); if (!gpx.showCurrentTrack) { res = GPXUtilities.writeGpxFile(outFile, gpx); } savedGpxFile = gpx; if (showOnMap) { - MeasurementToolFragment.showGpxOnMap(app, gpx, actionType, false); + MeasurementToolFragment.showGpxOnMap(app, gpx, false); } - return res; } + return res; + } + + private GPXFile generateGpxFile(MeasurementToolLayer measurementLayer, MeasurementEditingContext editingCtx, + String trackName, @NonNull GPXFile gpx) { + if (measurementLayer != null) { + List before = editingCtx.getBeforeTrkSegmentLine(); + List after = editingCtx.getAfterTrkSegmentLine(); + if (simplified) { + Track track = new Track(); + track.name = trackName; + gpx.tracks.add(track); + for (TrkSegment s : before) { + TrkSegment segment = new TrkSegment(); + segment.points.addAll(s.points); + track.segments.add(segment); + } + for (TrkSegment s : after) { + TrkSegment segment = new TrkSegment(); + segment.points.addAll(s.points); + track.segments.add(segment); + } + } else { + GPXFile newGpx = editingCtx.exportGpx(trackName); + if (newGpx != null) { + List gpxTracks = gpx.tracks; + List gpxPoints = gpx.getPoints(); + List gpxRoutes = gpx.routes; + gpx = newGpx; + List> routePoints = editingCtx.getRoutePoints(); + for (List points : routePoints) { + gpx.addRoutePoints(points, true); + } + if (!Algorithms.isEmpty(gpxPoints)) { + gpx.addPoints(gpxPoints); + } + if (addToTrack) { + gpx.tracks.addAll(gpxTracks); + gpx.routes.addAll(gpxRoutes); + } + } + } + } + return gpx; } @Override diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/SelectedPointBottomSheetDialogFragment.java b/OsmAnd/src/net/osmand/plus/measurementtool/SelectedPointBottomSheetDialogFragment.java index 9fac103fc5..39ff57b20c 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/SelectedPointBottomSheetDialogFragment.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/SelectedPointBottomSheetDialogFragment.java @@ -1,5 +1,6 @@ package net.osmand.plus.measurementtool; +import android.annotation.SuppressLint; import android.app.Activity; import android.content.DialogInterface; import android.graphics.drawable.Drawable; @@ -25,7 +26,6 @@ import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription; import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem; import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleDividerItem; import net.osmand.plus.helpers.FontCache; -import net.osmand.plus.measurementtool.GpxData.ActionType; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.util.MapUtils; @@ -39,6 +39,7 @@ public class SelectedPointBottomSheetDialogFragment extends MenuBottomSheetDialo private static final Log LOG = PlatformUtil.getLog(SelectedPointBottomSheetDialogFragment.class); private MeasurementEditingContext editingCtx; + @SuppressLint("InflateParams") @Override public void createMenuItems(Bundle savedInstanceState) { MapActivity mapActivity = getMapActivity(); @@ -172,7 +173,7 @@ public class SelectedPointBottomSheetDialogFragment extends MenuBottomSheetDialo dismiss(); } }) - .setDisabled(editingCtx.isFirstPointSelected()) + .setDisabled(editingCtx.isFirstPointSelected() || editingCtx.isSelectionNeedApproximation()) .create(); items.add(changeRouteTypeBefore); @@ -191,7 +192,7 @@ public class SelectedPointBottomSheetDialogFragment extends MenuBottomSheetDialo dismiss(); } }) - .setDisabled(editingCtx.isLastPointSelected()) + .setDisabled(editingCtx.isLastPointSelected() || editingCtx.isSelectionNeedApproximation()) .create(); items.add(changeRouteTypeAfter); @@ -264,11 +265,7 @@ public class SelectedPointBottomSheetDialogFragment extends MenuBottomSheetDialo if (!TextUtils.isEmpty(pointName)) { return pointName; } - GpxData gpxData = editingCtx.getGpxData(); - if (gpxData != null && gpxData.getActionType() == ActionType.ADD_ROUTE_POINTS) { - return getString(R.string.route_point) + " - " + (pos + 1); - } - return getString(R.string.plugin_distance_point) + " - " + (pos + 1); + return getString(R.string.ltr_or_rtl_combine_via_dash, getString(R.string.plugin_distance_point), String.valueOf(pos + 1)); } @NonNull @@ -305,18 +302,15 @@ public class SelectedPointBottomSheetDialogFragment extends MenuBottomSheetDialo } description.append(OsmAndFormatter.getFormattedDistance(dist, mapActivity.getMyApplication())); } - GpxData gpxData = editingCtx.getGpxData(); - if (gpxData != null && gpxData.getActionType() == ActionType.EDIT_SEGMENT) { - double elevation = pt.ele; - if (!Double.isNaN(elevation)) { - description.append(" ").append((getString(R.string.altitude)).substring(0, 1)).append(": "); - description.append(OsmAndFormatter.getFormattedAlt(elevation, mapActivity.getMyApplication())); - } - float speed = (float) pt.speed; - if (speed != 0) { - description.append(" ").append((getString(R.string.map_widget_speed)).substring(0, 1)).append(": "); - description.append(OsmAndFormatter.getFormattedSpeed(speed, mapActivity.getMyApplication())); - } + double elevation = pt.ele; + if (!Double.isNaN(elevation)) { + description.append(" ").append((getString(R.string.altitude)).substring(0, 1)).append(": "); + description.append(OsmAndFormatter.getFormattedAlt(elevation, mapActivity.getMyApplication())); + } + float speed = (float) pt.speed; + if (speed != 0) { + description.append(" ").append((getString(R.string.map_widget_speed)).substring(0, 1)).append(": "); + description.append(OsmAndFormatter.getFormattedSpeed(speed, mapActivity.getMyApplication())); } return description.toString(); } diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/adapter/MeasurementToolAdapter.java b/OsmAnd/src/net/osmand/plus/measurementtool/adapter/MeasurementToolAdapter.java index bc9a2f1651..2411a58c61 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/adapter/MeasurementToolAdapter.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/adapter/MeasurementToolAdapter.java @@ -19,7 +19,6 @@ import net.osmand.plus.OsmAndFormatter; import net.osmand.plus.R; import net.osmand.plus.UiUtilities; import net.osmand.plus.activities.MapActivity; -import net.osmand.plus.measurementtool.GpxData.ActionType; import net.osmand.plus.views.controls.ReorderItemTouchHelperCallback; import java.util.Collections; @@ -32,13 +31,11 @@ public class MeasurementToolAdapter extends RecyclerView.Adapter points; private MeasurementAdapterListener listener; private boolean nightMode; - private final ActionType actionType; private final static String BULLET = " • "; - public MeasurementToolAdapter(MapActivity mapActivity, List points, ActionType actionType) { + public MeasurementToolAdapter(MapActivity mapActivity, List points) { this.mapActivity = mapActivity; this.points = points; - this.actionType = actionType; } public void setAdapterListener(MeasurementAdapterListener listener) { @@ -79,11 +76,7 @@ public class MeasurementToolAdapter extends RecyclerView.Adapter points = ctx.getPoints(); + if (points.size() > 0) { + WptPt prevPt = points.get(points.size() - 1); + prevPointProfile = prevPt.getProfileType(); + } if (point != null) { - getEditingCtx().addPoint(point); + ctx.addPoint(point, addPointBefore ? AdditionMode.ADD_BEFORE : AdditionMode.ADD_AFTER); measurementLayer.moveMapToPoint(position); } else if (center) { - point = measurementLayer.addCenterPoint(); + point = measurementLayer.addCenterPoint(addPointBefore); } else { - point = measurementLayer.addPoint(); + point = measurementLayer.addPoint(addPointBefore); } refreshMap(); return point != null; @@ -52,13 +61,22 @@ public class AddPointCommand extends MeasurementModeCommand { @Override public void undo() { - getEditingCtx().removePoint(position, true); + MeasurementEditingContext ctx = getEditingCtx(); + if (position > 0) { + WptPt prevPt = ctx.getPoints().get(position - 1); + if (prevPointProfile != null) { + prevPt.setProfileType(prevPointProfile); + } else { + prevPt.removeProfileType(); + } + } + ctx.removePoint(position, true); refreshMap(); } @Override public void redo() { - getEditingCtx().addPoint(position, point); + getEditingCtx().addPoint(position, point, addPointBefore ? AdditionMode.ADD_BEFORE : AdditionMode.ADD_AFTER); refreshMap(); measurementLayer.moveMapToPoint(position); } diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/command/ApplyGpxApproximationCommand.java b/OsmAnd/src/net/osmand/plus/measurementtool/command/ApplyGpxApproximationCommand.java index 5198faedc3..8685e475ac 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/command/ApplyGpxApproximationCommand.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/command/ApplyGpxApproximationCommand.java @@ -1,24 +1,36 @@ package net.osmand.plus.measurementtool.command; +import android.util.Pair; + import androidx.annotation.NonNull; import net.osmand.GPXUtilities.WptPt; +import net.osmand.plus.measurementtool.MeasurementEditingContext; +import net.osmand.plus.measurementtool.MeasurementEditingContext.RoadSegmentData; import net.osmand.plus.measurementtool.MeasurementToolLayer; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.router.RoutePlannerFrontEnd.GpxRouteApproximation; import java.util.ArrayList; import java.util.List; +import java.util.Map; public class ApplyGpxApproximationCommand extends MeasurementModeCommand { private ApplicationMode mode; - private GpxRouteApproximation approximation; private List points; + private Map, RoadSegmentData> roadSegmentData; + private List approximations; + private List> segmentPointsList; + private final List> originalSegmentPointsList; - public ApplyGpxApproximationCommand(MeasurementToolLayer measurementLayer, GpxRouteApproximation approximation, ApplicationMode mode) { + public ApplyGpxApproximationCommand(MeasurementToolLayer measurementLayer, + List approximations, + List> segmentPointsList, ApplicationMode mode) { super(measurementLayer); - this.approximation = approximation; + this.approximations = approximations; + this.segmentPointsList = segmentPointsList; + this.originalSegmentPointsList = new ArrayList<>(segmentPointsList); this.mode = mode; } @@ -26,6 +38,10 @@ public class ApplyGpxApproximationCommand extends MeasurementModeCommand { return points; } + public List> getOriginalSegmentPointsList() { + return originalSegmentPointsList; + } + @Override public MeasurementCommandType getType() { return MeasurementCommandType.APPROXIMATE_POINTS; @@ -33,8 +49,9 @@ public class ApplyGpxApproximationCommand extends MeasurementModeCommand { @Override public boolean execute() { - List pts = getEditingCtx().getPoints(); - points = new ArrayList<>(pts); + MeasurementEditingContext ctx = getEditingCtx(); + points = new ArrayList<>(ctx.getPoints()); + roadSegmentData = ctx.getRoadSegmentData(); applyApproximation(); refreshMap(); return true; @@ -44,7 +61,7 @@ public class ApplyGpxApproximationCommand extends MeasurementModeCommand { public boolean update(@NonNull Command command) { if (command instanceof ApplyGpxApproximationCommand) { ApplyGpxApproximationCommand approxCommand = (ApplyGpxApproximationCommand) command; - approximation = approxCommand.approximation; + approximations = approxCommand.approximations; mode = approxCommand.mode; applyApproximation(); refreshMap(); @@ -55,10 +72,12 @@ public class ApplyGpxApproximationCommand extends MeasurementModeCommand { @Override public void undo() { - getEditingCtx().resetAppMode(); - getEditingCtx().clearSegments(); - getEditingCtx().addPoints(points); - getEditingCtx().updateCacheForSnap(); + MeasurementEditingContext ctx = getEditingCtx(); + ctx.resetAppMode(); + ctx.clearSegments(); + ctx.setRoadSegmentData(roadSegmentData); + ctx.addPoints(points); + segmentPointsList = new ArrayList<>(originalSegmentPointsList); refreshMap(); } @@ -69,8 +88,15 @@ public class ApplyGpxApproximationCommand extends MeasurementModeCommand { } public void applyApproximation() { - getEditingCtx().setAppMode(mode); - getEditingCtx().clearSegments(); - getEditingCtx().setPoints(approximation, mode); + MeasurementEditingContext ctx = getEditingCtx(); + ctx.setAppMode(mode); + for (int i = 0; i < approximations.size(); i++) { + GpxRouteApproximation approximation = approximations.get(i); + List segmentPoints = segmentPointsList.get(i); + List newSegmentPoints = ctx.setPoints(approximation, segmentPoints, mode); + if (newSegmentPoints != null) { + segmentPointsList.set(i, newSegmentPoints); + } + } } } diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/command/ChangeRouteModeCommand.java b/OsmAnd/src/net/osmand/plus/measurementtool/command/ChangeRouteModeCommand.java index 383431bd65..a9cfa2bb1e 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/command/ChangeRouteModeCommand.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/command/ChangeRouteModeCommand.java @@ -114,7 +114,7 @@ public class ChangeRouteModeCommand extends MeasurementModeCommand { editingCtx.addPoints(oldPoints); editingCtx.setAppMode(oldMode); editingCtx.setRoadSegmentData(oldRoadSegmentData); - editingCtx.updateCacheForSnap(); + editingCtx.updateSegmentsForSnap(); } @Override @@ -146,14 +146,16 @@ public class ChangeRouteModeCommand extends MeasurementModeCommand { if (newRoadSegmentData != null) { editingCtx.setRoadSegmentData(newRoadSegmentData); } - editingCtx.updateCacheForSnap(); + editingCtx.updateSegmentsForSnap(); } private void updateProfileType(WptPt pt) { - if (newMode != null && newMode != DEFAULT_APP_MODE) { - pt.setProfileType(newMode.getStringKey()); - } else { - pt.removeProfileType(); + if (!pt.isGap()) { + if (newMode != null && newMode != DEFAULT_APP_MODE) { + pt.setProfileType(newMode.getStringKey()); + } else { + pt.removeProfileType(); + } } } } diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/command/ClearPointsCommand.java b/OsmAnd/src/net/osmand/plus/measurementtool/command/ClearPointsCommand.java index 2e5b9aaf85..14533a150d 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/command/ClearPointsCommand.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/command/ClearPointsCommand.java @@ -1,14 +1,20 @@ package net.osmand.plus.measurementtool.command; +import android.util.Pair; + import net.osmand.GPXUtilities.WptPt; +import net.osmand.plus.measurementtool.MeasurementEditingContext; +import net.osmand.plus.measurementtool.MeasurementEditingContext.RoadSegmentData; import net.osmand.plus.measurementtool.MeasurementToolLayer; import java.util.ArrayList; import java.util.List; +import java.util.Map; public class ClearPointsCommand extends MeasurementModeCommand { private List points; + private Map, RoadSegmentData> roadSegmentData; private ClearCommandMode clearMode; private int pointPosition; @@ -31,27 +37,30 @@ public class ClearPointsCommand extends MeasurementModeCommand { } private void executeCommand() { - List pts = getEditingCtx().getPoints(); + MeasurementEditingContext ctx = getEditingCtx(); + List pts = ctx.getPoints(); points = new ArrayList<>(pts); + roadSegmentData = ctx.getRoadSegmentData(); switch (clearMode) { case ALL: pts.clear(); - getEditingCtx().clearSegments(); + ctx.clearSegments(); break; case BEFORE: - getEditingCtx().trimBefore(pointPosition); + ctx.trimBefore(pointPosition); break; case AFTER: - getEditingCtx().trimAfter(pointPosition); + ctx.trimAfter(pointPosition); } refreshMap(); } @Override public void undo() { - getEditingCtx().clearSegments(); - getEditingCtx().addPoints(points); - getEditingCtx().updateCacheForSnap(); + MeasurementEditingContext ctx = getEditingCtx(); + ctx.clearSegments(); + ctx.setRoadSegmentData(roadSegmentData); + ctx.addPoints(points); refreshMap(); } diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/command/MeasurementCommandManager.java b/OsmAnd/src/net/osmand/plus/measurementtool/command/MeasurementCommandManager.java index a1b5cad3ef..4d1cddfc56 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/command/MeasurementCommandManager.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/command/MeasurementCommandManager.java @@ -80,6 +80,6 @@ public class MeasurementCommandManager { } public MeasurementModeCommand getLastCommand() { - return undoCommands.getLast(); + return undoCommands.getFirst(); } } diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/command/RemovePointCommand.java b/OsmAnd/src/net/osmand/plus/measurementtool/command/RemovePointCommand.java index c420d1c42e..383da291a4 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/command/RemovePointCommand.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/command/RemovePointCommand.java @@ -7,6 +7,7 @@ public class RemovePointCommand extends MeasurementModeCommand { private final int position; private WptPt point; + private String prevPointProfile; public RemovePointCommand(MeasurementToolLayer measurementLayer, int position) { super(measurementLayer); @@ -15,6 +16,9 @@ public class RemovePointCommand extends MeasurementModeCommand { @Override public boolean execute() { + if (position > 0) { + prevPointProfile = getEditingCtx().getPoints().get(position - 1).getProfileType(); + } point = getEditingCtx().removePoint(position, true); refreshMap(); return true; @@ -22,6 +26,14 @@ public class RemovePointCommand extends MeasurementModeCommand { @Override public void undo() { + if (position > 0) { + WptPt prevPt = getEditingCtx().getPoints().get(position - 1); + if (prevPointProfile != null) { + prevPt.setProfileType(prevPointProfile); + } else { + prevPt.removeProfileType(); + } + } getEditingCtx().addPoint(position, point); refreshMap(); measurementLayer.moveMapToPoint(position); diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/command/ReorderPointCommand.java b/OsmAnd/src/net/osmand/plus/measurementtool/command/ReorderPointCommand.java index 302371e490..81976b7763 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/command/ReorderPointCommand.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/command/ReorderPointCommand.java @@ -18,7 +18,7 @@ public class ReorderPointCommand extends MeasurementModeCommand { @Override public boolean execute() { - getEditingCtx().updateCacheForSnap(); + getEditingCtx().updateSegmentsForSnap(); refreshMap(); return true; } @@ -36,7 +36,7 @@ public class ReorderPointCommand extends MeasurementModeCommand { private void reorder(int addTo, int removeFrom) { List points = getEditingCtx().getPoints(); points.add(addTo, points.remove(removeFrom)); - getEditingCtx().updateCacheForSnap(); + getEditingCtx().updateSegmentsForSnap(); refreshMap(); } diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/command/ReversePointsCommand.java b/OsmAnd/src/net/osmand/plus/measurementtool/command/ReversePointsCommand.java index eeadcc1ceb..364556635c 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/command/ReversePointsCommand.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/command/ReversePointsCommand.java @@ -47,7 +47,7 @@ public class ReversePointsCommand extends MeasurementModeCommand { WptPt lastPoint = newPoints.get(newPoints.size() - 1); editingCtx.setAppMode(ApplicationMode.valueOfStringKey(lastPoint.getProfileType(), DEFAULT_APP_MODE)); } - editingCtx.updateCacheForSnap(); + editingCtx.updateSegmentsForSnap(); } @Override @@ -57,7 +57,7 @@ public class ReversePointsCommand extends MeasurementModeCommand { editingCtx.addPoints(oldPoints); editingCtx.setAppMode(oldMode); editingCtx.setRoadSegmentData(oldRoadSegmentData); - editingCtx.updateCacheForSnap(); + editingCtx.updateSegmentsForSnap(); } diff --git a/OsmAnd/src/net/osmand/plus/myplaces/TrackActivityFragmentAdapter.java b/OsmAnd/src/net/osmand/plus/myplaces/TrackActivityFragmentAdapter.java index 4451354fc8..7612583067 100644 --- a/OsmAnd/src/net/osmand/plus/myplaces/TrackActivityFragmentAdapter.java +++ b/OsmAnd/src/net/osmand/plus/myplaces/TrackActivityFragmentAdapter.java @@ -50,14 +50,13 @@ import net.osmand.plus.GpxSelectionHelper.GpxDisplayItemType; import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile; import net.osmand.plus.OsmAndFormatter; import net.osmand.plus.OsmandApplication; -import net.osmand.plus.settings.backend.CommonPreference; -import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.activities.TrackActivity; import net.osmand.plus.dialogs.GpxAppearanceAdapter; -import net.osmand.plus.measurementtool.GpxData; import net.osmand.plus.myplaces.TrackBitmapDrawer.TrackBitmapDrawerListener; +import net.osmand.plus.settings.backend.CommonPreference; +import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.track.GpxSplitType; import net.osmand.plus.track.SplitTrackAsyncTask; import net.osmand.plus.track.SplitTrackAsyncTask.SplitTrackListener; @@ -918,17 +917,10 @@ public class TrackActivityFragmentAdapter implements TrackBitmapDrawerListener { } } - public void addNewGpxData(GpxData.ActionType actionType) { + public void addNewGpxData() { TrackActivity activity = getTrackActivity(); if (activity != null) { - activity.addNewGpxData(actionType); - } - } - - public void addNewGpxData(GpxData.ActionType actionType, GPXUtilities.TrkSegment segment) { - TrackActivity activity = getTrackActivity(); - if (activity != null) { - activity.addNewGpxData(actionType, segment); + activity.addNewGpxData(); } } @@ -951,10 +943,8 @@ public class TrackActivityFragmentAdapter implements TrackBitmapDrawerListener { PointDescription pointWptDescription = new PointDescription(PointDescription.POINT_TYPE_WPT, app.getString(R.string.add_waypoint)); addPoint(pointWptDescription); - } else if (i == R.id.route_text_layout || i == R.id.route_fab) { - addNewGpxData(GpxData.ActionType.ADD_ROUTE_POINTS); - } else if (i == R.id.line_text_layout || i == R.id.line_fab) { - addNewGpxData(GpxData.ActionType.ADD_SEGMENT); + } else if (i == R.id.route_text_layout || i == R.id.route_fab || i == R.id.line_fab) { + addNewGpxData(); } } }; diff --git a/OsmAnd/src/net/osmand/plus/myplaces/TrackSegmentFragment.java b/OsmAnd/src/net/osmand/plus/myplaces/TrackSegmentFragment.java index 94b3f9bfa3..ce3151920d 100644 --- a/OsmAnd/src/net/osmand/plus/myplaces/TrackSegmentFragment.java +++ b/OsmAnd/src/net/osmand/plus/myplaces/TrackSegmentFragment.java @@ -65,11 +65,10 @@ import net.osmand.plus.helpers.GpxUiHelper; import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetAxisType; import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetType; import net.osmand.plus.helpers.GpxUiHelper.OrderedLineDataSet; -import net.osmand.plus.measurementtool.GpxData; -import net.osmand.plus.track.SaveGpxAsyncTask; -import net.osmand.plus.track.SaveGpxAsyncTask.SaveGpxListener; import net.osmand.plus.myplaces.TrackBitmapDrawer.TrackBitmapDrawerListener; import net.osmand.plus.settings.backend.OsmandSettings; +import net.osmand.plus.track.SaveGpxAsyncTask; +import net.osmand.plus.track.SaveGpxAsyncTask.SaveGpxListener; import net.osmand.plus.views.controls.PagerSlidingTabStrip; import net.osmand.plus.views.controls.PagerSlidingTabStrip.CustomTabProvider; import net.osmand.plus.views.controls.WrapContentHeightViewPager; @@ -1026,7 +1025,7 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit private void editSegment() { TrkSegment segment = getTrkSegment(); if (segment != null && fragmentAdapter != null) { - fragmentAdapter.addNewGpxData(GpxData.ActionType.EDIT_SEGMENT, segment); + fragmentAdapter.addNewGpxData(); } } diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/FollowTrackFragment.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/FollowTrackFragment.java index ec180a97e3..8537c8df7a 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/FollowTrackFragment.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/FollowTrackFragment.java @@ -1,8 +1,11 @@ package net.osmand.plus.routepreparationmenu; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.Intent; +import android.graphics.drawable.AnimationDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; @@ -16,6 +19,7 @@ import android.view.ViewGroup.MarginLayoutParams; import android.view.ViewTreeObserver.OnScrollChangedListener; import android.widget.FrameLayout; import android.widget.ImageButton; +import android.widget.ImageView; import android.widget.LinearLayout; import androidx.annotation.NonNull; @@ -24,7 +28,6 @@ import androidx.fragment.app.FragmentManager; import net.osmand.AndroidUtils; import net.osmand.CallbackWithObject; import net.osmand.GPXUtilities.GPXFile; -import net.osmand.GPXUtilities.TrkSegment; import net.osmand.GPXUtilities.WptPt; import net.osmand.IndexConstants; import net.osmand.PlatformUtil; @@ -44,7 +47,6 @@ import net.osmand.plus.helpers.GpxUiHelper.GPXInfo; import net.osmand.plus.importfiles.ImportHelper; import net.osmand.plus.importfiles.ImportHelper.OnGpxImportCompleteListener; import net.osmand.plus.measurementtool.GpxData; -import net.osmand.plus.measurementtool.GpxData.ActionType; import net.osmand.plus.measurementtool.MeasurementEditingContext; import net.osmand.plus.measurementtool.MeasurementToolFragment; import net.osmand.plus.routepreparationmenu.RoutingOptionsHelper.LocalRoutingParameter; @@ -86,6 +88,8 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca private GPXFile gpxFile; + private View buttonsShadow; + private boolean editingTrack; private boolean selectingTrack; private int menuTitleHeight; @@ -148,6 +152,7 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca View view = super.onCreateView(inflater, container, savedInstanceState); if (view != null) { ImageButton closeButton = view.findViewById(R.id.close_button); + buttonsShadow = view.findViewById(R.id.buttons_shadow); closeButton.setImageDrawable(getContentIcon(AndroidUtils.getNavigationIconResId(app))); closeButton.setOnClickListener(new View.OnClickListener() { @Override @@ -174,6 +179,22 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca return view; } + private void showShadowButton() { + buttonsShadow.setVisibility(View.VISIBLE); + buttonsShadow.animate() + .alpha(0.8f) + .setDuration(200) + .setListener(null); + } + + private void hideShadowButton() { + buttonsShadow.animate() + .alpha(0f) + .setDuration(200); + + } + + private void setupCards() { MapActivity mapActivity = getMapActivity(); if (mapActivity != null) { @@ -554,10 +575,7 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca MapActivity mapActivity = getMapActivity(); if (mapActivity != null && gpxFile != null) { editingTrack = true; - QuadRect rect = gpxFile.getRect(); - TrkSegment segment = gpxFile.getNonEmptyTrkSegment(); - ActionType actionType = segment == null ? ActionType.ADD_ROUTE_POINTS : ActionType.EDIT_SEGMENT; - GpxData gpxData = new GpxData(gpxFile, rect, actionType, segment); + GpxData gpxData = new GpxData(gpxFile); MeasurementEditingContext editingContext = new MeasurementEditingContext(); editingContext.setGpxData(gpxData); editingContext.setAppMode(app.getRoutingHelper().getAppMode()); @@ -598,20 +616,16 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca } private void setupScrollShadow() { - int shadowIconId = isNightMode() ? R.drawable.bg_contextmenu_shadow : R.drawable.bg_contextmenu_shadow; - final Drawable shadowIcon = app.getUIUtilities().getIcon(shadowIconId); - final View scrollView = getBottomScrollView(); - final FrameLayout bottomContainer = getBottomContainer(); scrollView.getViewTreeObserver().addOnScrollChangedListener(new OnScrollChangedListener() { @Override public void onScrollChanged() { - int scrollY = scrollView.getScrollY(); - if (scrollY <= 0 && bottomContainer.getForeground() != null) { - bottomContainer.setForeground(null); - } else if (scrollY > 0 && bottomContainer.getForeground() == null) { - bottomContainer.setForeground(shadowIcon); + boolean scrollToBottomAvailable = scrollView.canScrollVertically(1); + if (scrollToBottomAvailable) { + showShadowButton(); + } else { + hideShadowButton(); } } }); diff --git a/OsmAnd/src/net/osmand/plus/routing/GpxApproximator.java b/OsmAnd/src/net/osmand/plus/routing/GpxApproximator.java index 4650d527ae..65e683a734 100644 --- a/OsmAnd/src/net/osmand/plus/routing/GpxApproximator.java +++ b/OsmAnd/src/net/osmand/plus/routing/GpxApproximator.java @@ -1,28 +1,23 @@ 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.Future; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -31,29 +26,31 @@ public class GpxApproximator { protected static final Log log = PlatformUtil.getLog(GpxApproximator.class); - private OsmandApplication ctx; - private RoutingHelper routingHelper; + private final OsmandApplication ctx; + private final RoutingHelper routingHelper; private RoutingEnvironment env; private GpxRouteApproximation gctx; private ApplicationMode mode; - private LocationsHolder locationsHolder; + private final LocationsHolder locationsHolder; private List points; private LatLon start; private LatLon end; private double pointApproximation = 50; + private Runnable approximationTask; + + private static final ThreadPoolExecutor SINGLE_THREAD_EXECUTOR + = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());; - private ThreadPoolExecutor singleThreadedExecutor; private GpxApproximationProgressCallback approximationProgress; - private Future currentApproximationTask; public interface GpxApproximationProgressCallback { - void start(); + void start(GpxApproximator approximator); - void updateProgress(int progress); + void updateProgress(GpxApproximator approximator, int progress); - void finish(); + void finish(GpxApproximator approximator); } public GpxApproximator(@NonNull OsmandApplication ctx, @NonNull LocationsHolder locationsHolder) throws IOException { @@ -61,12 +58,7 @@ public class GpxApproximator { this.locationsHolder = locationsHolder; this.routingHelper = ctx.getRoutingHelper(); this.mode = ApplicationMode.CAR; - if (locationsHolder.getSize() > 1) { - start = locationsHolder.getLatLon(0); - end = locationsHolder.getLatLon(locationsHolder.getSize() - 1); - prepareEnvironment(ctx, mode); - } - init(); + initEnvironment(mode, locationsHolder); } public GpxApproximator(@NonNull OsmandApplication ctx, @NonNull ApplicationMode mode, double pointApproximation, @NonNull LocationsHolder locationsHolder) throws IOException { @@ -75,16 +67,15 @@ public class GpxApproximator { this.pointApproximation = pointApproximation; this.routingHelper = ctx.getRoutingHelper(); this.mode = mode; + initEnvironment(mode, locationsHolder); + } + + private void initEnvironment(@NonNull ApplicationMode mode, @NonNull LocationsHolder locationsHolder) throws IOException { if (locationsHolder.getSize() > 1) { start = locationsHolder.getLatLon(0); end = locationsHolder.getLatLon(locationsHolder.getSize() - 1); prepareEnvironment(ctx, mode); } - init(); - } - - private void init() { - singleThreadedExecutor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()); } private void prepareEnvironment(@NonNull OsmandApplication ctx, @NonNull ApplicationMode mode) throws IOException { @@ -140,6 +131,10 @@ public class GpxApproximator { this.approximationProgress = approximationProgress; } + public boolean isCancelled() { + return gctx != null && gctx.ctx.calculationProgress.isCancelled; + } + public void cancelApproximation() { if (gctx != null) { gctx.ctx.calculationProgress.isCancelled = true; @@ -154,10 +149,7 @@ public class GpxApproximator { this.gctx = gctx; startProgress(); updateProgress(gctx); - if (currentApproximationTask != null) { - currentApproximationTask.cancel(true); - } - currentApproximationTask = singleThreadedExecutor.submit(new Runnable() { + approximationTask = new Runnable() { @Override public void run() { try { @@ -166,21 +158,23 @@ public class GpxApproximator { resultMatcher.publish(null); log.error(e.getMessage(), e); } + approximationTask = null; } - }); + }; + SINGLE_THREAD_EXECUTOR.submit(approximationTask); } private void startProgress() { final GpxApproximationProgressCallback approximationProgress = this.approximationProgress; if (approximationProgress != null) { - approximationProgress.start(); + approximationProgress.start(this); } } private void finishProgress() { final GpxApproximationProgressCallback approximationProgress = this.approximationProgress; if (approximationProgress != null) { - approximationProgress.finish(); + approximationProgress.finish(this); } } @@ -192,15 +186,13 @@ public class GpxApproximator { @Override public void run() { RouteCalculationProgress calculationProgress = gctx.ctx.calculationProgress; - if (!gctx.result.isEmpty() && GpxApproximator.this.gctx == gctx) { + if (approximationTask == null && GpxApproximator.this.gctx == gctx) { finishProgress(); } - if (gctx.result.isEmpty() && calculationProgress != null && !calculationProgress.isCancelled) { + if (approximationTask != null && calculationProgress != null && !calculationProgress.isCancelled) { float pr = calculationProgress.getLinearProgress(); - approximationProgress.updateProgress((int) pr); - if (GpxApproximator.this.gctx != gctx) { - // different calculation started - } else { + approximationProgress.updateProgress(GpxApproximator.this, (int) pr); + if (GpxApproximator.this.gctx == gctx) { updateProgress(gctx); } } diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/ApplicationMode.java b/OsmAnd/src/net/osmand/plus/settings/backend/ApplicationMode.java index 894a4a7492..8c64654b41 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/ApplicationMode.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/ApplicationMode.java @@ -78,6 +78,7 @@ public class ApplicationMode { public static final ApplicationMode DEFAULT = createBase(R.string.app_mode_default, "default") .icon(R.drawable.ic_world_globe_dark).reg(); + public static final ApplicationMode GAP = new ApplicationMode(R.string.app_mode_gap, "gap"); public static final ApplicationMode CAR = createBase(R.string.app_mode_car, "car") .icon(R.drawable.ic_action_car_dark) diff --git a/OsmAnd/src/net/osmand/plus/track/TrackAppearanceFragment.java b/OsmAnd/src/net/osmand/plus/track/TrackAppearanceFragment.java index 2276d57cd2..0c7cfce551 100644 --- a/OsmAnd/src/net/osmand/plus/track/TrackAppearanceFragment.java +++ b/OsmAnd/src/net/osmand/plus/track/TrackAppearanceFragment.java @@ -475,24 +475,33 @@ public class TrackAppearanceFragment extends ContextMenuScrollFragment implement AndroidUiHelper.updateVisibility(saveButton, true); AndroidUiHelper.updateVisibility(view.findViewById(R.id.buttons_divider), true); } + private void showShadowButton() { + buttonsShadow.setVisibility(View.VISIBLE); + buttonsShadow.animate() + .alpha(0.8f) + .setDuration(200) + .setListener(null); + } + + private void hideShadowButton() { + buttonsShadow.animate() + .alpha(0f) + .setDuration(200); + + } private void setupScrollShadow() { - int shadowIconId = isNightMode() ? R.drawable.bg_contextmenu_shadow : R.drawable.bg_contextmenu_shadow; - final Drawable shadowIcon = app.getUIUtilities().getIcon(shadowIconId); - final View scrollView = getBottomScrollView(); - final FrameLayout bottomContainer = getBottomContainer(); scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() { @Override public void onScrollChanged() { - int scrollY = scrollView.getScrollY(); - if (scrollY <= 0 && bottomContainer.getForeground() != null) { - bottomContainer.setForeground(null); - } else if (scrollY > 0 && bottomContainer.getForeground() == null) { - bottomContainer.setForeground(shadowIcon); + boolean scrollToBottomAvailable = scrollView.canScrollVertically(1); + if (scrollToBottomAvailable) { + showShadowButton(); + } else { + hideShadowButton(); } - updateButtonsShadow(); } }); }