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-telegram/res/values-nb/strings.xml b/OsmAnd-telegram/res/values-nb/strings.xml index 8fd7b0eb17..5b6d88b4af 100644 --- a/OsmAnd-telegram/res/values-nb/strings.xml +++ b/OsmAnd-telegram/res/values-nb/strings.xml @@ -179,7 +179,7 @@ Oppsyn er påskrudd Oppsyn er ikke aktivert Tid i bevegelse - Gjennomsnittlig høyde + Gjennomsnittshøyde Gjennomsnittsfart Vis i OsmAnd Sluttdato 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" /> مساعد تخطيط OSM معلومات A-GPS إدارة - تعديل/حذف + تعديل أماكن بحث عرض الوصف. @@ -1076,8 +1076,8 @@ سمات أخرى للخريطة العناصر الأخرى شريط المعلومات - العدادات على اليمين - العدادات على اليسار + العدادات على اليسار + العدادات على اليمين ضمن مستخدم مجهول سجل الدخول ب %1$s @@ -1153,7 +1153,7 @@ حذف إجراء التعديلات وقت وقوف السيارات يقتصر على - تدلي + أقل قائمة منبسطة تعديل OSM فارغ %1$s @@ -1483,7 +1483,7 @@ التنبيه الآلي الذكي الإشعار فقط عند تغير الوجهة نحو نقطة الهدف. مهلة التنبيه الآلي - أقل مهلة بين الاخطارات. + أقل مهلة بين الإشعارات. الخريطة مرتبطة بالموقع عريض المستخدم المجهول لا يمكنه : @@ -1658,7 +1658,7 @@ منح الوصول إلى بيانات الموقع. مسارات الخيول إخفاء - أقل جودة + جودة أقل أعلى جودة تم النسخ في الحافظة فتح ملاحظة OSM @@ -1838,7 +1838,7 @@ لا يمكن إضافة تعليق. تقديم حذف إحداثية GPX ؟ - تعديل/حذف + تعديل ألمانية منخفضة اللغة الفريزية الأشياء المقترحة @@ -1996,7 +1996,7 @@ أشياء فوق سطح الأرض تغيير ابدأ - طريق أقل استهلاكا للوقود + طريق أقل استهلاكاً للوقود استخدم طريق أقل استهلاكا للوقود (عادة أقصر). هل تريد استبدال المفضلة %1$s؟ حذف جميع الطبقات @@ -2249,7 +2249,7 @@ قم بتشغيل التكبير التلقائي إيقاف التكبير التلقائي إضافة وجهة وسطى - تحليل على الخريطة + تحليل المعروضة على الخريطة استرجاع الشراء لا ترسل إحصاءات مجهولة عن استخدام التطبيق @@ -2302,7 +2302,7 @@ محيطات الأعماق البحرية أوسماند يقوم بجمع معلومات حول أجزاء من التطبيقات التي تفتحها. الموقع الخاص بك لا يرسل ابدأ، ولا أي شيء تقوم بإدخاله في التطبيق أو أي تفاصيل لمناطق رأيتها ، بحثت عنها أو نزلتها. عرض خصومات التطبيق ورسائل الأحداث المحلية الخاصة. - أقل تضاريس + تضاريس أقل مسطح متوازن التضاريس المفضلة : مسطحة أو تلال. @@ -2730,7 +2730,7 @@ إضافة نقطة حفظ كمسار أنت بحاجة %1$s نقاط. اكتب اسم ملف واضغط \"حفظ\". - يرجى إرسال لقطة شاشة من هذا الإخطار إلى support@osmand.net + يرجى إرسال لقطة شاشة من هذا الإشعار إلى support@osmand.net تعديل الإجراء احصل على أوسماند لايف لإلغاء قفل جميع الميزات: تحديثات الخرائط اليومية مع تنزيلات غير محدودة، وجميع الإضافات المدفوعة والمجانية ، ويكيبيديا، ويكي الرحلات وأكثر. الاشتراكات @@ -3101,7 +3101,7 @@ لينة متانة السطح %s تم الحفظ - مسار مفتوح + فتح المسار المسار %s تم حفظ ربط الأجزاء العربه @@ -3223,7 +3223,7 @@ الطرق الوعره إعداد الوضع يحتفظ الوضع بإعداداتك - حدد خيارات الخريطة للملف الشخصي + حدد خيارات الخريطة للوضع حدد خيارات الشاشة للوضع حدد إعدادات الملاحة للوضع حدد الحد الأعلى للتغييرات @@ -3387,7 +3387,7 @@ الوضع المحدد بالضغط على %1$s، ستفقد كل تغييراتك. سيتم إعادة ضبط جميع إعدادات الوضع إلى الحالة الافتراضية بعد التثبيت. - استعادة الضبط الافتراضي؟ + استعادة الضبط الافتراضي لكل الأوضاع؟ %2$s %1$s %2$s :%1$s \'%1$s\' لا يحتوي الملف على قواعد توجيه ،يرجى اختيار ملف آخر. @@ -3489,7 +3489,7 @@ نسخ الإحداثيات مباشر إلى نقطة الفرز حسب الفئة - يرجى اعطاء اسم للملف الشخصي + يرجى إدخال اسم للوضع افتح الإعدادات الملحق مُعطل القائمة @@ -3732,7 +3732,7 @@ \nشهر واحد هو 43 829 دقيقة. اختر كيفية تخزين الطبقات المنزلة. مهلة الشاشة الافتراضية - يمكنك تصدير أو استيراد إجراءات سريعة باستخدام ملفات بروفايل التطبيق . + يمكنك تصدير أو استيراد إجراءات سريعة باستخدام أوضاع التطبيق . حذف الكل؟ هل أنت متأكد من رغبتك في حذف الاختصارات السريعة %d نهائيًا؟ مهلة الشاشة @@ -3765,13 +3765,13 @@ %1$s محذوفة إعادة التشغيل مطلوبة لحذف بيانات كاميرا السرعة بالكامل. إلغاء التثبيت وإعادة التشغيل - في بعض البلدان أو المناطق، يحظر القانون استخدام تطبيقات التحذير من كاميرا السرعة. + في بعض البلدان أو المناطق، يحظر القانون استخدام تطبيقات التحذير من كاميرا السرعة. \n -\nعليك أن تختار اعتمادا على قانون بلدك. +\nعليك أن تختار اعتمادا على قانون بلدك. \n -\nحدد %1$s وستتلقى تنبيهات وتحذيرات حول كاميرات السرعة. +\nحدد %1$s وستتلقى تنبيهات وتحذيرات حول كاميرات السرعة. \n -\nحدد %2$s. جميع البيانات المتعلقة كاميرات السرعة: التنبيهات، والإخطارات، سيتم حذف نقاط الاهتمام حتى يتم إعادة تثبيت أوسماند تماما. +\nحدد %2$s. جميع البيانات المتعلقة كاميرات السرعة: التنبيهات، والإشعارات، سيتم حذف نقاط الاهتمام حتى يتم إعادة تثبيت أوسماند تماما. تحديد الارتفاع الأعلى المسموح به على الطرق. حد الطول هذا الجهاز لا يملك كاميرات السرعة. @@ -3909,7 +3909,7 @@ التوجيه على مرحلتين لملاحة السيارة. تطوير النقل العام المحلي قم بالتبديل إلى Java (الآمن) حساب توجيه النقل العام - قم بإجراء تسجيل دخول إلى OAuth لاستخدام ميزات osmedit + قم بتسجيل الدخول إلى OAuth لاستخدام ميزات osmedit تسجيل الدخول عبر OAuth مسح رمز OpenStreetMap OAuth تسجيل الخروج بنجاح @@ -3920,4 +3920,6 @@ \nسيتوفر الرسم البياني بعد إعادة الحساب. للقيادة على الجليد مع طرق ومسارات مخصصة. رسم بياني + %2$s — %1$s + فجوة \ No newline at end of file diff --git a/OsmAnd/res/values-ca/strings.xml b/OsmAnd/res/values-ca/strings.xml index 79432f1703..eb412908d1 100644 --- a/OsmAnd/res/values-ca/strings.xml +++ b/OsmAnd/res/values-ca/strings.xml @@ -1553,7 +1553,7 @@ Per retornar a l\'estil habitual dels mapes d\'OsmAnd, només cal desactivar aqu Límit d\'alçada Indiqueu l\'alçada del vehicle que les rutes han d\'admetre. Recàlcul intel·ligent de la ruta - En viatges llargs, només actualitzis la part inicial de la ruta. + Actualitza només la part inicial de la ruta. Pot ser usat per a viatges llargs. Surt Desactivat Acoloreix segons el tipus de xarxa @@ -3589,10 +3589,10 @@ Abasta l\'àrea: %1$s x %2$s Les pistes es mostren sobre el terreny i amb colors. Pistes Connector d\'OsmAnd adaptat - Substitueix un altre punt per aquest + Substitueix un altre punt per aquest. S\'han fet els canvis al perfil \'%1$s\'. No s\'ha pogut llegir des de \'%1$s\'. - No s\'ha pogut escriure %1$s. + No s\'ha pogut escriure a \'%1$s\'. No s\'ha pogut importar des de \'%1$s\'. Seleccioneu fitxer de la traça Idiomes @@ -3619,7 +3619,7 @@ Abasta l\'àrea: %1$s x %2$s Aragonès Llombard Color personalitzat - Seleccioneu els idiomes de la Viquipèdia en que es veuran els articles al mapa. Mentre llegiu un article podeu modificar la llengua entre les disponibles. + Seleccioneu els idiomes per als articles de Viquipèdia al mapa. Canvieu la llengua entre les disponibles mentre llegiu un article. Alguns articles de la Viquipèdia podrien no estar disponibles en el vostre idioma. Cantonès Min nan @@ -3672,11 +3672,11 @@ Abasta l\'àrea: %1$s x %2$s Llargada màxima Trajectòria S\'ha esborrat %1$s - Cal reiniciar per esborrar totalment les dades de les càmeres de radar. + Reinicia l\'aplicació per esborrar totes les dades de les càmeres de radar. Desinstal·la i Reinicia Aquest dispositiu no inclou les càmeres de radar. Patins en línia - Activeu per controlar el nivell d\'ampliació del mapa amb els botons del volum del dispositiu. + Controla el nivell d\'ampliació del mapa fent servir els botons del volum del dispositiu. Botons de volum pel zoom Esteu segur que voleu suprimir definitivament %d dreceres\? Podeu exportar o importar les dreceres amb els perfils de les aplicacions. @@ -3686,7 +3686,7 @@ Abasta l\'àrea: %1$s x %2$s Si està activat \"%1$s\" el temps d\'activitat quedarà afectat. tones metres - Suprimeix la propera fita + Suprimeix la fita més propera Proporcioneu un nom per al punt La propera fita de la ruta s\'esborrarà. Si es tractés de la Destinació final, la navegació s\'aturaria. Baixa mapes de la Viquipèdia @@ -3850,4 +3850,13 @@ Abasta l\'àrea: %1$s x %2$s \n • S\'han corregit problemes en la importació/exportació de la configuració dels perfils \n \n + Mostra el transport públic + Afegeix un perfil + Canvia el perfil de l\'aplicació + Mapa general del món (detallat) + Tipus no suportat + Sempre + Control de pantalla + Desenvolupament + %1$s — %2$s \ No newline at end of file diff --git a/OsmAnd/res/values-cs/phrases.xml b/OsmAnd/res/values-cs/phrases.xml index 8d64234b3a..b64efe0702 100644 --- a/OsmAnd/res/values-cs/phrases.xml +++ b/OsmAnd/res/values-cs/phrases.xml @@ -3588,20 +3588,20 @@ Kompenzační Kompresní Měřicí - н/к - н/к* + n/c + n/c* 1А* - - 1Б* - - 2А* - - 2Б* - - 3А* - - 3Б* + 1B + 1B* + 2A + 2A* + 2B + 2B* + 3A + 3A* + 3B + 3B* Přístup sněžným skútrům Přístup autobusům Přístup karavanům @@ -3827,7 +3827,7 @@ Pod tlakem Podzemní voda Roura - Internetový přístup: zdarma pro zákazníky + Internetový přístup: zákazníci Typ klášteru: řeholnický Typ klášteru: poustevnický Typ klášteru: kanovnický @@ -3845,4 +3845,8 @@ Vibrace Tlak Zkapalněný zemní plyn + Podél silnice + Přístřešky + Střešní + Bod GPX \ No newline at end of file diff --git a/OsmAnd/res/values-cs/strings.xml b/OsmAnd/res/values-cs/strings.xml index 59b0baf68d..67044dc34e 100644 --- a/OsmAnd/res/values-cs/strings.xml +++ b/OsmAnd/res/values-cs/strings.xml @@ -3578,4 +3578,15 @@ Zobrazená oblast: %1$s x %2$s Název: A – Z Ikony startu/cíle Děkujeme za zakoupení modulu \'Vrstevnice\' + Přihlásit se pomocí OAuth pro použití funkcí editace OSM + Přihlásit pomocí OAuth + Vymazat OpenStreetMap OAuth token + Odhlášení úspěšné + Soubor je již importovaný v OsmAnd + Použít dvoufázový algoritmus A* pro výpočet trasy + Graf + Údaje %1$s jsou dostupné pouze na cestách, pro jejich získání musíte vypočítat trasu pomocí “Trasa medzi body”. + Počkejte na přepočet trasy. +\nGraf bude dostupný po přepočtu. + %1$s — %2$s \ No newline at end of file diff --git a/OsmAnd/res/values-da/strings.xml b/OsmAnd/res/values-da/strings.xml index 0e05949cf0..3943611228 100644 --- a/OsmAnd/res/values-da/strings.xml +++ b/OsmAnd/res/values-da/strings.xml @@ -3788,4 +3788,6 @@ Alle efterfølgende segmenter genberegnes ved hjælp af den valgte profil. Alle tidligere segmenter genberegnes ved hjælp af den valgte profil. Start-/slutikoner + %1$s — %2$s + Hul \ No newline at end of file diff --git a/OsmAnd/res/values-de/phrases.xml b/OsmAnd/res/values-de/phrases.xml index d40597ca63..011706fbf0 100644 --- a/OsmAnd/res/values-de/phrases.xml +++ b/OsmAnd/res/values-de/phrases.xml @@ -3848,4 +3848,8 @@ Kleine Elektrogeräte Nussladen Flüssigerdgas + Parken in Parallelstraße + Überdachter Parkplatz + Dachparkplätze + GPX-Wegpunkt \ No newline at end of file diff --git a/OsmAnd/res/values-de/strings.xml b/OsmAnd/res/values-de/strings.xml index dec24d8f5d..697326c31c 100644 --- a/OsmAnd/res/values-de/strings.xml +++ b/OsmAnd/res/values-de/strings.xml @@ -3652,9 +3652,9 @@ %1$s / %2$s Die Bezahlung wird Ihrem Google Play-Konto bei der Bestätigung des Kaufs belastet. \n -\n Das Abonnement verlängert sich automatisch, sofern es nicht vor dem Verlängerungsdatum gekündigt wird. Ihr Konto wird für den Verlängerungszeitraum (Monat / drei Monate / Jahr) nur am Verlängerungsdatum belastet. +\nDas Abonnement verlängert sich automatisch, sofern es nicht vor dem Verlängerungsdatum gekündigt wird. Ihr Konto wird für den Verlängerungszeitraum (Monat / drei Monate / Jahr) nur am Verlängerungsdatum belastet. \n -\n Sie können Ihre Abonnements verwalten und kündigen, indem Sie zu Ihren Google Play-Einstellungen gehen. +\nSie können Ihre Abonnements verwalten und kündigen, indem Sie zu Ihren Google Play-Einstellungen gehen. Suche nach POI-Typen Kombinieren Sie POI-Typen aus verschiedenen Kategorien. Tippen Sie auf den Schalter, um alle auszuwählen, tippen Sie auf die linke Seite zur Kategorieauswahl. Trenner @@ -3913,9 +3913,9 @@ Das Abonnement wird pro ausgewähltem Zeitraum berechnet. Sie können das Abonnement jederzeit über die AppGallery kündigen. Die Bezahlung wird Ihrem AppGallery-Konto bei der Bestätigung des Kaufs belastet. \n -\n Das Abonnement verlängert sich automatisch, sofern es nicht vor dem Verlängerungsdatum gekündigt wird. Ihr Konto wird für den Verlängerungszeitraum (Monat / drei Monate / Jahr) nur am Verlängerungsdatum belastet. +\nDas Abonnement verlängert sich automatisch, sofern es nicht vor dem Verlängerungsdatum gekündigt wird. Ihr Konto wird für den Verlängerungszeitraum (Monat / drei Monate / Jahr) nur am Verlängerungsdatum belastet. \n -\n Sie können Ihre Abonnements verwalten und kündigen, indem Sie zu Ihren AppGallery-Einstellungen gehen. +\nSie können Ihre Abonnements verwalten und kündigen, indem Sie zu Ihren AppGallery-Einstellungen gehen. Vermeidet Fußwege Keine Fußwege Entwicklung @@ -3929,4 +3929,8 @@ Datei wurde bereits in OsmAnd importiert Anmelden über OAuth OpenStreetMap OAuth-Token löschen + Was ist neu + Für das Schneemobilfahren mit speziellen Straßen und Tracks. + Durchführen eines OAuth-Logins zur Nutzung der osmedit-Funktionen + 2-Phasen-A*-Routing-Algorithmus verwenden \ No newline at end of file diff --git a/OsmAnd/res/values-eo/phrases.xml b/OsmAnd/res/values-eo/phrases.xml index df01830535..2eae52044b 100644 --- a/OsmAnd/res/values-eo/phrases.xml +++ b/OsmAnd/res/values-eo/phrases.xml @@ -3838,4 +3838,8 @@ Tabulo de forveturoj Plenigi per trinkebla akvo tergaso likva (LNG) + laŭlonge de strato + privataj garaĝ-budoj + tegmento + GPX-punkto \ No newline at end of file diff --git a/OsmAnd/res/values-es-rAR/strings.xml b/OsmAnd/res/values-es-rAR/strings.xml index b68eaba5e1..4da8d4966b 100644 --- a/OsmAnd/res/values-es-rAR/strings.xml +++ b/OsmAnd/res/values-es-rAR/strings.xml @@ -3931,9 +3931,10 @@ Sesión finalizada Para caminos y senderos exclusivos de motos de nieve. El archivo ya fue importado en OsmAnd - Usar el algoritmo de enrutamiento A* de 2 fases + Usar el algoritmo de navegación A* bifásica Gráfico %1$s datos disponibles sólo en los caminos, necesitas calcular una ruta usando «Ruta entre puntos» para obtenerla. Espera el recálculo de la ruta. \nEl gráfico estará disponible después del recálculo. + %1$s — %2$s \ No newline at end of file diff --git a/OsmAnd/res/values-et/phrases.xml b/OsmAnd/res/values-et/phrases.xml index daafc22ac5..4e06dceeb0 100644 --- a/OsmAnd/res/values-et/phrases.xml +++ b/OsmAnd/res/values-et/phrases.xml @@ -3774,7 +3774,7 @@ Ebaõige Kontrastne Ainult kui jalakäijatele lubatud - Tasuline internetipunkt + Tasuline internetipunkt klientidele Ei Jah Kioski tüüp @@ -3827,4 +3827,8 @@ Mesitaru Pähklipood Veeldatud maagaas + GPX sõlm + Parkla kiirtee ääres + Parkimine varjualustes + Parkla katusel \ No newline at end of file diff --git a/OsmAnd/res/values-et/strings.xml b/OsmAnd/res/values-et/strings.xml index 8ccdb58038..3930c5b18f 100644 --- a/OsmAnd/res/values-et/strings.xml +++ b/OsmAnd/res/values-et/strings.xml @@ -3782,4 +3782,8 @@ Meie uudised Kasuta kahefaasilist A-klassi teekonna koostamise algoritmi See fail on juba OsmAnd\'i imporditud + OsmAnd andmed reaalajas + OsmAnd andmed reaalajas + Mootorsaanide sõitmine eraldi määratud teedel ja radadel. + %1$s — %2$s \ No newline at end of file diff --git a/OsmAnd/res/values-fr/phrases.xml b/OsmAnd/res/values-fr/phrases.xml index 1196bb8b8b..2141c47b39 100644 --- a/OsmAnd/res/values-fr/phrases.xml +++ b/OsmAnd/res/values-fr/phrases.xml @@ -1050,7 +1050,7 @@ Interdit Obligatoire Population - Parking : sous-terrain + Parking : souterrain Olivier Pommier Palmier diff --git a/OsmAnd/res/values-fr/strings.xml b/OsmAnd/res/values-fr/strings.xml index 04e329659a..2a4458f148 100644 --- a/OsmAnd/res/values-fr/strings.xml +++ b/OsmAnd/res/values-fr/strings.xml @@ -3845,7 +3845,7 @@ Trace simplifiée Nom de fichier Par défaut - Ouvrir une trace enregistrée + Ouvrir la trace enregistrée a été enregistré Veuillez ajouter au moins deux points. Sélectionnez le fichier de trace à suivre ou importez-le depuis votre appareil. @@ -3912,4 +3912,6 @@ \nLe graphique sera disponible à l\'issue du calcul. Pour la conduite en motoneige avec des routes et des pistes dédiées. Graphique + Écart + %1$s - %2$s \ No newline at end of file diff --git a/OsmAnd/res/values-gl/strings.xml b/OsmAnd/res/values-gl/strings.xml index 0a65bf9b5a..447bdc7bbf 100644 --- a/OsmAnd/res/values-gl/strings.xml +++ b/OsmAnd/res/values-gl/strings.xml @@ -3950,4 +3950,9 @@ Lon %2$s Entrar polo OAuth Limpar token do OpenStreetMap OAuth Sesión rematada + Para estradas e pistas exclusivas de motos de neve. + O ficheiro xa foi importado no OsmAnd + Usar algoritmo de enrutamento A* de 2 fases + Gráfica + %1$s — %2$s \ No newline at end of file diff --git a/OsmAnd/res/values-hu/phrases.xml b/OsmAnd/res/values-hu/phrases.xml index eb5f1ef453..99f11bb034 100644 --- a/OsmAnd/res/values-hu/phrases.xml +++ b/OsmAnd/res/values-hu/phrases.xml @@ -454,7 +454,7 @@ Vonat (látványosság) Vízi csúszda Vadászház - Internetcsatlakozás: WLAN + Internetcsatlakozás: WLAN (wifi) Internetcsatlakozás: munkaállomás Internetcsatlakozás: kábel Internetcsatlakozás: nyilvános @@ -836,7 +836,7 @@ Grúz ortodox Román ortodox Kopt ortodox - Internetcsatlakozás + Internetcsatlakozás van Internetcsatlakozás nincs Tánctér Night club; Diszkó @@ -1547,7 +1547,7 @@ Wi-Fi Munkaállomás Vezetékes - Nyilvános + Internetcsatlakozás: nyilvános Segítenek Internetcsatlakozás nincs Internetcsatlakozás van @@ -3836,4 +3836,8 @@ Mag- és aszaltgyümölcsbolt Méhkaptár LNG (cseppfolyósított földgáz) + Út mellett parkolósáv (UK) + Fedett parkolóhely + Tető + Internetcsatlakozás: ügyfeleknek \ No newline at end of file diff --git a/OsmAnd/res/values-hu/strings.xml b/OsmAnd/res/values-hu/strings.xml index ac040cd72f..9ae52a9644 100644 --- a/OsmAnd/res/values-hu/strings.xml +++ b/OsmAnd/res/values-hu/strings.xml @@ -3509,7 +3509,7 @@ Rögzített adatok törlése Engedélyezésével domborzatárnyékolás vagy lejtőtérkép jeleníthető meg. Ezekről a térképfajtákról többet olvashat a honlapunkon. Túrasízés - Motoros hószán + Motoros szán Egyéni OsmAnd bővítmény Sikertelen olvasás innen: \'%1$s\'. Sikertelen írás ide: \'%1$s\'. @@ -3920,4 +3920,10 @@ Sikeresen kijelentkezett Kétszakaszos A* útvonaltervezési algoritmus használata A fájl már importálva van az OsmAndba + %1$s - %2$s + Motorosszánutakhoz kifejezetten motoros szán számára kijelölt utakon. + Grafikon + %1$s adatok csak az utakról állnak rendelkezésre. Használja az „Útvonal tervezése pontok között” funkciót. + Várja meg az útvonal újraszámítását. +\nAz ábra az újraszámítás után lesz látható. \ No newline at end of file diff --git a/OsmAnd/res/values-it/strings.xml b/OsmAnd/res/values-it/strings.xml index 86af4a4f07..7b4c8ad764 100644 --- a/OsmAnd/res/values-it/strings.xml +++ b/OsmAnd/res/values-it/strings.xml @@ -3905,4 +3905,32 @@ Nome: A – Z Icona Partenza/Arrivo Grazie per l\'acquisto del \'Plugin delle curve di livello\' + Novità + Per slitte a motore con strade e sentieri dedicati. + Sottoscrizione addebitata per il periodo selezionato. Cancellala nell\'AppGallery in ogni momento. + Il pagamento sarà addebitato nella tuo account AppGallery alla conferma dell\'acquisto. +\n +\nLe sottoscrizioni si rinnovano automaticamente finché non vengono cancellate prima della date del rinnovo. Il tuo account sarà addebitato per i rinnovi periodici solo (mensile/trimestrale/annuale) solo alla data di rinnovo. +\n +\nPuoi gestire le tue sottoscrizioni nelle impostazioni della tua AppGallery. + Evita i marciapiedi + Evita i marciapiedi + Sviluppo + Dati OsmAnd Live + Dati OsmAnd Live + Calcolo del percorso in due fasi per la navigazione in auto. + Sviluppo Trasporto Pubblico nativo + Cambia a Java (safe) calcolo del percorso su Trasporto Pubblico + Effettua una connessione OAuth per usare le funzionalità osmedit + Connettiti via OAuth + Cancella il token OAuth OpenStreetMap + Disconnessione effettuata + Il file è già importato in OsmAnd + Utilizza l\'algoritmo di calcolo a 2-fasi A* + Grafico + %1$s dati disponibili solo per le strade, necessiti di calcolare un percorso utilizzando \"Percorso fra punti\" per ottenerlo. + Attendi per il ricalcolo del percorso. +\nIl grafico sarà disponibile dopo il ricalcolo. + %1$s — %2$s + Buco \ No newline at end of file diff --git a/OsmAnd/res/values-iw/strings.xml b/OsmAnd/res/values-iw/strings.xml index efe9cb3b27..7334c5dbb9 100644 --- a/OsmAnd/res/values-iw/strings.xml +++ b/OsmAnd/res/values-iw/strings.xml @@ -3938,4 +3938,5 @@ תרשים נא להמתין לחישוב המסלול מחדש. \nהתרשים יהיה זמין לאחר החישוב מחדש. + %1$s ‏— %2$s \ No newline at end of file diff --git a/OsmAnd/res/values-nb/strings.xml b/OsmAnd/res/values-nb/strings.xml index 85bfc9b423..85f13702a1 100644 --- a/OsmAnd/res/values-nb/strings.xml +++ b/OsmAnd/res/values-nb/strings.xml @@ -17,10 +17,10 @@ Du har allerede angitt et reisemål: Reisemål Mellomliggende reisemål %1$s er for langt fra den nærmeste veien. - Ankommet mellomliggende reisemål + Mellomliggende reisemål er nådd Legg til som mellomliggende reisemål Mellomliggende reisemål - Sluttpunkt for langt fra nærmeste vei. + Endepunkt for langt fra nærmeste vei. Legg til merke Avansert modus… Parkering @@ -259,7 +259,7 @@ Interessepunkt-data TTS-tale Nytt søk - Navnetekststørrelse på kartet: + Tekststørrelse for navn på kartet: Skriftstørrelse for kart Nettbasert navigering fungerer ikke frakoblet. Språk ikke støttet @@ -406,7 +406,7 @@ Total distanse %1$s, reisetid %2$d t %3$d min. Nettbasert eller frakoblet navigeringstjeneste. Navigeringstjeneste - Datalagringsmappen på minnekortet er ikke tilgjengelig! + Lagringsmappen på minnekortet er ikke tilgjengelig! Laste ned {0} - {1} \? Nettfrakoblede data for {0} finnes allerede ({1}). Oppdater ({2})\? Adresse @@ -456,7 +456,7 @@ Søk Søk Velg interessepunkt - Finn mer + Finn flere Søk etter by trinnvis Søk etter gate trinnvis Søk etter bygning trinnvis @@ -472,8 +472,8 @@ Angi bredde- og lengdegrad i det valgte formatet (G - grader, M - minutter, S - sekunder) Breddegrad Lengdegrad - DDD.DDDDD - DDD MM,MMM + GGG.GGGGG + GGG MM,MMM GGG MM SS,S Adresse Region @@ -522,7 +522,7 @@ Tilpass programutseende. USA Canada - Europa, Asia, Latin-Amerika & lignende + Europa, Asia, Latin-Amerika og lignende Storbritannia, India og lignende Velg bilkjøringssted: USA, Europa, Storbritannia, Asia og andre. Japan @@ -603,7 +603,7 @@ Latvisk Litauisk Marathi - Norsk Bokmål + Norsk bokmål Polsk Portugisisk Rumensk @@ -637,7 +637,7 @@ Vis sykkelruter Vis zoom-knapper under navigering. Vis zoom-knapper - Nåtid + Gjeldende tid Visningsfarge Sentrer posisjon på kart Navigeringsinnstillinger @@ -675,7 +675,7 @@ Andre kartattributter Buss-, trolleybuss-, skyttelbussruter Trikk- og togruter - Undergrunnsruter + T-bane-ruter Togruter Trikkeruter Trolleybussruter @@ -721,7 +721,7 @@ Albansk Arabisk Persisk - Sardinsk + Sardisk Velg reisemål Foretrekk motorveier Foretrekk motorveier @@ -1103,7 +1103,7 @@ Merk for å slette A-GPS-info Melding - A-GPS-data sist nedlastet: %1$s + A-GPS-data nedlastet: %1$s OsmAnd tilbyr global nettfrakoblet kartlesing og navigering. Gjeldende rute Start @@ -1257,7 +1257,7 @@ Kategorinavn Legg til ny kategori Regioner - Regionkart + Regionale kart Verdenskart Relieffskyggelag deaktivert Del posisjon @@ -1271,7 +1271,7 @@ Oppdater alle (%1$s MB) Gratis nedlastinger brukt Velg hvor du vil lagre kart og andre datafiler. - Oppgi navn på land + Angi navn på land Basiskart verden (som dekker hele verden ved lavt zoomnivå) mangler eller er utdatert. Vurder å laste det ned for en global oversikt. QR-kode Basiskart velges for nedlasting slik at programmet fungerer. @@ -1455,7 +1455,7 @@ slett I/O-feil under utførelse av handlingen {0}. Fortell oss hvorfor. - Klarte ikke å laste opp + Kunne ikke laste opp Kjøp Ofte stilte spørsmål Antall redigeringer @@ -1482,7 +1482,7 @@ OsmAnd Live-navigering Reisemål er ikke angitt Naviger opp - OpenStreetMap-brukernavn og passord + OSM-brukernavn og passord OsmAnd Live-abonnement Ikke vis mitt navn i rapporter Kjøp først et OsmAnd Live-abonnement @@ -1564,7 +1564,7 @@ Aktuelle spor Vis aktuelle spor GPX-bredde - OsmAnds datalagring (for kart, GPX-filer, osv.): %1$s. + OsmAnds datalagring (for kart, sporfiler, etc.): %1$s. Få anvisninger og oppdag nye steder uten å ha internettforbindelse Oppdater alle kart nå\? Abonnementsavgift belastes månedsvis. Avbryt det på Google Play når som helst. @@ -1694,7 +1694,7 @@ Last opp ditt OSM-notat anonymt eller ved å bruke din profil hos OpenStreetMap.org. Du har ingen GPX-filer enda Du kan også legge til GPX-filer i mappen - Legg til mer… + Legg til flere… Skru på hurtigopptak Vis et systemvarsel som kan starte turopptak. Minimumshastighet for logging @@ -1801,7 +1801,7 @@ Koble til Ingen trapper Unngår trapper - Angi talehastigheten for TTS. + Angi talehastigheten for tekst-til-tale. Talehastighet Rask ruteberegning mislyktes (%s), faller tilbake på treg beregning. Slå av to-fase ruteplanlegging for bilnavigering. @@ -1856,7 +1856,7 @@ Nepal bhasa Cebuano Asturiansk - Øvervendisk + Oversorbisk Kabylsk Kinesisk (Hongkong) Bruk vist spor for navigering\? @@ -1932,7 +1932,7 @@ Legg til overlegg Kartoverlegg er endret til \"%s\". Punkt(er) slettet. - ER du sikker på at du vil slette %1$d punkt(er)\? + Er du sikker på at du vil slette %1$d punkt(er)\? Gjennomsnittsfart Velg mappe for GPX-fil OsmAnd (OSM Automated Navigation Directions) er et kart- og navigeringsprogram med tilgang til gratis, verdensomspennende og høykvalitets data fra OpenStreetMap (OSM). @@ -2003,7 +2003,7 @@ Fall Stigning Høydeintervall - Gjennomsnittlig høyde + Gjennomsnittshøyde Følg Handlingsnavn Visningszoomnivå: %1$s @@ -2025,7 +2025,7 @@ Ta hensyn til terrenghøyde (data fra SRTM, ASTER og EU-DEM). Melding Tillatelser - Kunne ikke importere filen. Kontroller at OsmAnd kan lese den. + Kunne ikke importere filen. Kontroller at OsmAnd har tillatelse til å lese den. Korrigert avstand Last på nytt Feil brukernavn @@ -2053,7 +2053,7 @@ Navigering: sett på pause/gjenoppta Knapp for å ta en pause i eller gjenoppta navigeringen. Høyrekjøring - Trykk på denne knappen for å starte eller avslutte navigeringen. + Knapp for å starte eller avslutte navigering. Lagre spor som er tatt opp i månedlige mapper Lagre spor som er tatt opp, i undermapper per opptaksmåned (f.eks. 2018-01). Last kartfliser på nytt for å se oppdaterte data. @@ -2085,7 +2085,7 @@ Mapillary-bilde Åpne Mapillary Installer - Forbedre billeddekningen med Mapillary + Forbedre bildedekningen med Mapillary Nettbaserte bilder Legg til bilder Ingen bilder her. @@ -2097,7 +2097,7 @@ Sjøkart Gjenopprett kjøp Ikke send anonym bruksstatistikk - Parkeringsalternativer + Parkeringsmuligheter Takk for at du kjøpte betalingsversjonen av OsmAnd. Kortere ruter Balansert @@ -2137,7 +2137,7 @@ Liste Sist brukt: %1$s Filtrer bilder etter innsender, dato eller type. Kun aktivt på nærgående forstørrelsesnivå. - Installer Mapillary for å legge til et eller flere bilder til denne kartposisjonen. + Installer Mapillary for å legge til bilder i denne kartposisjonen. Foto på gatenivå for alle. Oppdag plasser, samarbeid, fang inn verden. Vis/skjul OSM-notater Vis OSM-notater @@ -2147,7 +2147,7 @@ Havdybdekonturer Havdybdekonturer Svinger å passere langs ruten - Vis havdybdekonturer og punkter. + Vis dybdekonturer og punkter. Havdybdekonturer Del opp opptak automatisk etter avbrudd Start nytt segment etter et avbrudd på 6 min., nytt spor etter avbrudd på 2 timer, eller ny fil etter et lengre avbrudd hvis datoen er endret. @@ -2156,7 +2156,7 @@ \n- Synkronisere grupper og enheter med tjeneren; \n- Behandle grupper og enheter i et personlig dashbord på nettstedet. Simuler første programstart - Programtillegget for Audio/video-notater tilbyr funksjoner for å ta lyd/video/bilde-notater på en tur, enten ved bruk av en knapp på kartet, eller direkte i kontekstmenyen for enhver posisjon på kartet. + Lag audio/foto/video-notater på en tur, enten ved bruk av en knapp på kartet eller posisjon-kontekstmeny. Gjennomsnitt %1$d av %2$d Stigning/fall @@ -2177,7 +2177,7 @@ Sorter etter: Kartorienteringsterskel Velg hastighet for skifte av kartorientering fra \'Bevegelsesretning\' til \'Kompassretning\' nedenfor. - Kjøp og installer \"Koter\"-programtillegget for å vise loddrett skyggelegging. + Kjøp og installer \"Koter\"-tillegget for å vise graderte vertikale områder. Totalt innebygget minne Startpunkt for langt fra nærmeste vei. Delt posisjon @@ -2213,7 +2213,7 @@ Kunne ikke tegne valgt område. Kartgenerator lastet Kunne ikke lese GPX-data. - Hvilke som helst + Alle Takk til Yandex for trafikkinfo. Yandex-trafikk Stedsbestemmelsestjeneste @@ -2238,7 +2238,7 @@ Smart omberegning av rute Vurder dette programmet Gi OsmAnd en poengsum på Google Play - Fortell oss hva du ønsker å endre i dette programmet. + Gi oss beskjed om forslag. Kortet ble skjult Antall linjer Modifiser OSM-endring @@ -2370,7 +2370,7 @@ Skriv for å finne interessepunkt Setter høyeste tillatte ventetid for hver bakgrunns-posisjonsbestemmelse. Maksimal ventetid for posisjonsbestemmelse - Vekkingsintervall brukt av bakgrunnstjeneste: + Vekkingsintervall brukt av bakgrunnstjenesten: Stedsbestemmelsesmetode brukt av bakgrunnstjeneste: Etterfølgende rute Tidligere rute @@ -2437,8 +2437,8 @@ Sted å assosiere med notatet er ikke definert ennå. \"Bruk posisjon…\" for å tilordne et notat til det angitte stedet. Legg til rutepunkt i innspilt GPX-spor Taleveiledning er ikke tilgjengelig, gå til \'Innstillinger\' → \'Navigeringsinnstillinger\' , velg profilen → \'Taleveiledning\' og velg eller last ned en talemeldingspakke. - For lange turer, beregn på nytt bare den første delen av ruten. - Nautisk + Beregner på nytt bare den første delen av ruten. Kan brukes for lange turer. + Maritimt stengt (fridag) Kopier sted/interessepunkt-navn Sted uten navn @@ -3679,7 +3679,7 @@ Nåværende målpunkt på ruten vil slettes. Hvis det er målet, vil navigasjonen stoppe. Rullestol Gokart - Planlegg en rute + Ruteplanlegging Du får tilgang til disse handlingene ved å trykke på knappen “%1$s”. Styr zoomnivået på kartet med enhetens volumknapper. Det tillagte punktet vil ikke være synlig på kartet, siden den valgte gruppen er skjult, du kan finne det i \"%s\". @@ -3823,7 +3823,7 @@ Kun rutelinjen vil lagres, rutepunktene vil slettes. Legg til spor-rutepunkt Legg til spor-rutepunkt - To-delt ruting for bilkjøring. + To-fase-ruting for bilnavigering. Abonnement påløper per valgte periode. Avbryt det når som helst fra programgalleriet. Følg veier Minimumsforskyvning @@ -3868,4 +3868,8 @@ Utlogget Bruk 2-stegs A*-rutingsalgoritme Filen er allerede importert i OsmAnd + Vent på omberegning av ruten. +\nGraf vil være tilgjengelig etter omberegning. + %1$s — %2$s + Graf \ No newline at end of file diff --git a/OsmAnd/res/values-nl/strings.xml b/OsmAnd/res/values-nl/strings.xml index 575016f2f6..54c11b5a67 100644 --- a/OsmAnd/res/values-nl/strings.xml +++ b/OsmAnd/res/values-nl/strings.xml @@ -30,7 +30,7 @@ Terug naar locatie Toegankelijkheidsmodus Zet toegankelijkheidsmodus aan. - Gelijk aan systeeminstelling + Gelijk aan de Android systeeminstelling Terug naar menu Zoom uit Zoom in @@ -251,8 +251,8 @@ Fout bij offline zoeken. Zoek adres in de offline kaarten Systeem - App menu-taal (OsmAnd dient opnieuw gestart). - Taal + App toon talen (OsmAnd dient opnieuw gestart). + Toon talen Wijzig de eenheid van afstand voor metingen. Afstand eenheden Mijlen/voeten @@ -636,10 +636,10 @@ Gebruik online kaarten (download en bewaar deze op SD-kaart). Online kaarten Configureer online of bewaarde kaarttegels. - Geeft toegang tot vele soorten online (zogenaamde tile of raster) kaarten, van vooraf gedefinieerde OSM tiles (zoals Mapnik) tot satellietbeelden en lagen voor speciale doeleinden zoals weerkaarten, klimaatkaarten, geologische kaarten, reliëfschaduwlagen, enz. -\n -\nAl deze kaarten kunnen worden gebruikt als de hoofd(basis)kaart, of als een extra laag of een achtergrondlaag bij een andere basiskaart (zoals de normale offline kaarten van OsmAnd). Om een achtergrondlaag beter te kunnen zien, kunt u elementen van de OsmAnd vectorkaarten eenvoudig verbergen via het menu \'Kaart instellen\'. -\n + Geeft toegang tot vele soorten online (zogenaamde tile of raster) kaarten, van vooraf gedefinieerde OSM tiles (zoals Mapnik) tot satellietbeelden en lagen voor speciale doeleinden zoals weerkaarten, klimaatkaarten, geologische kaarten, reliëfschaduwlagen, enz. +\n +\nAl deze kaarten kunnen worden gebruikt als de hoofd(basis)kaart, of als een extra laag of een achtergrondlaag bij een andere basiskaart (zoals de normale offline kaarten van OsmAnd). Om een achtergrondlaag beter te kunnen zien, kunt u elementen van de OsmAnd vectorkaarten eenvoudig verbergen via het menu \'Kaart instellen\'. +\n \nRasterkaarten zijn direct via online bronnen verkrijgbaar of kunnen voor offline gebruik gereedgemaakt worden (en handmatig gekopieerd naar de OsmAnd gegevensmap) als SQLite database door diverse hulpprogramma\'s van derden. Instellingen om tracking en navigatie te kunnen gebruiken met het scherm uit (schakelt de GPS periodiek in). "Maakt de toegankelijkheidsopties van het toestel rechtstreeks beschikbaar in OsmAnd. Hiermee kan o.a. de spreeksnelheid van tekst-naar-spraak-stemmen aangepast worden, D-pad schermnavigatie geconfigureerd worden, een trackball gebruikt worden voor de zoomregeling, of het gebruiken van meldingen via tekst-naar-spraak, bijvoorbeeld het automatisch melden van de positie." @@ -824,7 +824,7 @@ Tussenpunt %1$s Schakel GPS in via de instellingen Richting van de bestemming tonen - Activeer de GPX-Track opnemen- Plugin om de afgelegde weg vast te leggen (GPX-track, online tracking) + Activeer de \"GPX-Track opnemen\" Plug-in om de afgelegde weg vast te leggen (GPX-track, online tracking) Bereken mogelijk niet-optimale route voor lange afstanden Kies kleurschema voor wegen: Kleurschema voor wegen @@ -921,7 +921,7 @@ OsmAnd Kaarten & Navigatie OsmAnd+ Kaarten & Navigatie Huisnummer - GPX-track + Track opnemen Stel in hoe uw trips op te nemen. Straatnaam Aanpassen van app uitzicht aan uw wensen. @@ -952,8 +952,8 @@ Punt GPX-bestandsnaam GPX-bestand succesvol opgeslagen als {0} - Deze plug-in voorziet een kaart-widget waarmee u een route kan ontwerpen door op de kaart te tikken, of gebruik te maken (of wijzigen) van bestaande GPX-bestanden. Plan zo een reis en bereken de afstand tussen punten. Het resultaat kan worden bewaard als GPX-bestand, om later te gebruiken als navigatieroute. - Afstand meten en Route plannen + Maak paden door op de kaart te tikken of door bestaande GPX-bestanden te gebruiken of te wijzigen om een reis te plannen en de afstand tussen punten te meten. Het resultaat kan worden opgeslagen als een GPX-bestand om later als richtlijn te gebruiken. + Afstandscalculator en planningstool * Tik om een punt te markeren. \n* Druk lang op de kaart om het vorige punt te verwijderen. \n* Druk lang en houd vast op een punt om de beschrijving te zien en toe te voegen. @@ -1247,7 +1247,7 @@ Dichtbij POI Alles Reizen - GPX-track opnemen + Track opnemen u. Duur Afstand @@ -1462,7 +1462,7 @@ Geluid Video Foto - Kies de wachttijd in om op het route-planning scherm te blijven. + Geef de wachttijd op om op het route-planning scherm te blijven. Start begeleiding na… Start Actietoets aanmaken @@ -1639,7 +1639,7 @@ min/m min/km m/s - GPX-Track opnemen + Track opnemen Navigatie Informatie over favoriet Positiesimulatie beëindigen. @@ -2058,7 +2058,7 @@ Meer toevoegen… Weergave Snelle opname activeren - Toon systeemmelding waarmee ritopname toegestaan wordt. + Toon systeemmelding waarmee track opname toegestaan wordt. Meldingen Route berekening Fijn @@ -2359,10 +2359,10 @@ Installeer Verbeter de fotocollectie van Mapillary Installeer Mapillary om foto\'s aan deze kaartlocatie toe te voegen. - Deel uw straatniveau uitzicht via Mapillary. + Deel uw weergave op straatniveau via Mapillary. Snel bijdragen aan Mapillary. - Foto\'s van buiten voor iedereen. Ondek plaatsen, werk samen, en leg de wereld vast. - Foto\'s van buiten voor iedereen. Ondek plaatsen, werk samen, en leg de wereld vast. + Online foto\'s op straatniveau voor iedereen. Ontdek plaatsen, werk samen, leg de wereld vast. + Foto\'s op straatniveau voor iedereen. Ontdek plaatsen, werk samen, leg de wereld vast. Rechten Kan bestand niet importeren. Controleer of OsmAnd rechten heeft om het bestand te lezen. Gecorrigeerde afstand @@ -3297,7 +3297,7 @@ Door plug-in toegevoegde profielen Uitschakelen Nieuwe plug-in toegevoegd - verbind segmenten + Segmenten samenvoegen • App profiles: Create a custom profile for your own needs, with a custom icon and color \n \n • Nu aan te passen standaard en min / max snelheden voor elk profiel @@ -3356,7 +3356,7 @@ Afbeeldingsgrootte, geluids- en videokwaliteit Login, wachtwoord, offline bewerken Kies icoon, kleur en naam - Laat u toe uw positie te delen dankzij reisopname. + Laat u toe uw positie te delen dankzij track opname. Online volgen Opnamenauwkeurigheid De opgenomen tracks zijn opgeslagen in %1$s, of in de OsmAnd-map. @@ -3406,8 +3406,8 @@ Zonsopkomst om %1$s Toegankelijkheidsmodus is uitgeschakeld in de Android systeeminstellingen. Gebruik de scherm time-out van het systeem - Standaard niet actief: Wanneer OsmAnd in de voorgrond actief is zal het scherm niet uitschakelen. -\n + Standaard niet actief: Wanneer OsmAnd in de voorgrond actief is zal het scherm niet uitschakelen. +\n \nBij activatie zal OsmAnd de time-out instellingen van het systeem volgen. Verwijder opgenomen gegevens Kopieer coördinaten @@ -3530,7 +3530,7 @@ Terrein Helling gebruikt kleuren om de steilheid van het terrein te visualiseren. Stel de minimale en maximale zoomniveaus in waarbij de laag wordt weergegeven. - Om Hellingen te tonen zijn extra kaarten nodig. + Om hellingen te tonen zijn extra kaarten nodig. Meer over Hellingen in %1$s. Transparantie Zoomniveaus @@ -3666,7 +3666,7 @@ Legaal Snelheidscamera’s als POI’s De reliëfschaduwkaart maakt gebruik van donkere schaduwen om hellingen, bergtoppen en valleien te visualiseren. - Om Reliëfschaduw te tonen zijn extra kaarten nodig. + Om reliëfschaduw te tonen zijn extra kaarten nodig. Reliëfschaduw Selecteer deze optie om een reliëfschaduw- of hellingskaart te tonen. Op onze site staat meer informatie over deze kaarttypes. Heeft invloed op de weergave bij gebruik als kaart of als extra kaartlaag/achtergrondlaag. @@ -3696,4 +3696,79 @@ Rolstoel vooraanzicht Opgeloste OSM-opmerking Kart + Track opnemen + Specificeer het registratie-interval voor de algemene trackregistratie (ingeschakeld via de track-widget op de kaart). + Pauzeer track opname + Hervat track opnemen + Beelden op srraatniveau + Selecteer dikte + Toon start en aankomst pictogrammen + Richtingaanwijzers + Het toegevoegde punt zal niet zichtbaar zijn op de kaart, aangezien de geselecteerde groep verborgen is, je kan het vinden in \"%s\". + Standaard + Route tussen punten + "Vervolgens, zet uw track vast op de dichtstbijzijnde toegestane weg met een van uw navigatieprofielen om deze optie te gebruiken." + %1$s gegevens alleen beschikbaar op de wegen, u moet een route berekenen met behulp van \"Route tussen punten\" om deze te krijgen. + Selecteer hoe de punten verbonden worden, via een rechte lijn, of een route berekenen tussen de punten zoals hieronder aangegeven. + Alleen het volgende segment wordt opnieuw berekend met het geselecteerde profiel. + Volgende segment + Alle volgende segmenten + Alle volgende segmenten worden opnieuw berekend met het geselecteerde profiel. + De ganse track + De ganse track wordt herberekend volgens het geselecteerde profiel. + Punt van de track om te navigeren + Bewaar als nieuw trackbestand + Bewaar als nieuwe track + Nieuwe offline pistekaarten +\n +\n • Volledige aanpassing van favorieten en GPX-waypoints - aangepaste kleuren, pictogrammen, vormen +\n +\n • Pas de volgorde van items aan in \"Contextmenu\", \"Configureer kaart\" en \"........\" +\n +\n •Wikipedia als een afzonderlijke laag in Kaart configureren, selecteer alleen de benodigde talen +\n +\n • Creëer uw eigen POI-filter / kaarten met totale flexibiliteit +\n +\n • Opties toegevoegd om instellingen voor aangepaste profielen te herstellen +\n +\n • Volledige GPX-routes van navigatieondersteunende rijstroken en volledige afslaginstructies +\n +\n •Verbeterde UI-formaten op tablets +\n +\n •Herstel bugs met RTL +\n +\n + Voeg toe aan een track + Voeg toe aan een trackbestand + Vereenvoudigde track + Alleen de routelijn wordt opgeslagen, de waypoints worden verwijderd. + Bewaar + Route omkeren + "Selecteer een track waaraan je een nieuw segment wil toevoegen." + Selecteer een trackbestand om te openen. + Weet u zeker dat u alle wijzigingen in de geplande route wilt annuleren door deze te sluiten\? + Opsmukken voor + Opsmukken na + Wijzig het routetype voor + Wijzig het routetype na + • Bijgewerkt Plan een route functie: maakt het mogelijk om verschillende navigatietypes per segment te gebruiken en tracks op te nemen +\n +\n • Nieuw menu voor tracks: selecteer kleur, dikte, weergeven van richtingspijlen, start / finish-pictogrammen. +\n +\n • Verbeterde zichtbaarheid van fietsknooppunten. +\n +\n • Tracks kun je nu aantikken en hebben een contextmenu met basisinformatie. +\n +\n • Verbeterde zoekalgoritmen. +\n +\n • Verbeterde volg track-opties bij navigatie +\n +\n • Problemen opgelost met het importeren / exporteren van profielinstellingen +\n +\n + Importeer track + Laatst bewerkt + Maak een nieuwe route + Open een bestaande track + Plan een route \ No newline at end of file diff --git a/OsmAnd/res/values-pl/strings.xml b/OsmAnd/res/values-pl/strings.xml index c94fb854dc..13ddd2c001 100644 --- a/OsmAnd/res/values-pl/strings.xml +++ b/OsmAnd/res/values-pl/strings.xml @@ -3265,7 +3265,7 @@ Język i wyjście Ustawienia wtyczki Domyślnie - Pobierz szczegółową mapę %S, aby zobaczyć ten obszar. + Pobierz szczegółową mapę %s, aby zobaczyć ten obszar. Przenieść pliki danych OsmAnd do nowego położenia\? \n%1$s > %2$s Proszę wprowadzić ścieżkę do katalogu @@ -3769,11 +3769,11 @@ Odinstaluj fotoradary Prawny Punkty fotoradarów - W niektórych krajachi regionach uzywanie aplikacji ostrzegających o fotoradarach jest zabronione przez prawo. + W niektórych krajach i regionach używanie aplikacji ostrzegających o fotoradarach jest zabronione przez prawo. \n -\nMusisz dokonać wyboru w zależności od prawa danego kraju. +\nMusisz dokonać wyboru w zależności od prawa danego kraju. \n -\nWybierz %1$S i będziesz otrzymywać powiadomienia i ostrzeżenia o fotoradarach. +\nWybierz %1$s i będziesz otrzymywać powiadomienia i ostrzeżenia o fotoradarach. \n \nWybierz %2$s. Wszystkie dane o fotoradarach: ostrzeżenia, powiadomienia, miejsca użyteczne zostaną usunięte, aż OsmAnd zostanie zainstalowany ponownie. Nie wyłączaj @@ -3814,7 +3814,7 @@ Wybierz żądaną opcję podziału: według czasu lub odległości. Stałe OsmAnd GPX nie jest dobrze uformowany, prosimy o kontakt z zespołem wsparcia technicznego w celu dalszego zbadania sprawy. - Wybierz limit czasu ekranu po przebudzeniu. (\"%1$s\" nie powoduje przekroczenia limitu czasu). + Wybierz limit czasu ekranu po przebudzeniu. (\"%1$s\" nie powoduje przekroczenia limitu czasu.) Pokaż ikony początku i końca Wybierz przedział czasowy, w którym będą wyświetlane znaki z odległością lub czasem na torze. Dostosowany @@ -3891,7 +3891,7 @@ Otwórz zapisaną ścieżkę jest zapisywany Należy dodać co najmniej dwa punkty. - Wstrzyma rejestrowanie ścieżki, gdy aplikacja zostanie zabita (za pośrednictwem ostatnich aplikacji). (Wskazanie tła OsmAnd znika z paska powiadomień Androida). + Wstrzyma rejestrowanie ścieżki, gdy aplikacja zostanie zabita (za pośrednictwem ostatnich aplikacji). (Wskazanie tła OsmAnd znika z paska powiadomień Androida.) Ponów • Zaktualizowana funkcja planu trasy: umożliwia korzystanie z różnych typów nawigacji na segment i dołączanie ścieżek \n @@ -3933,4 +3933,6 @@ Zaloguj się przez OAuth Wyczyść token OpenStreetMap OAuth Wylogowanie powiodło się + Plik jest już zaimportowany do OsmAnd + %1$s — %2$s \ No newline at end of file diff --git a/OsmAnd/res/values-pt-rBR/phrases.xml b/OsmAnd/res/values-pt-rBR/phrases.xml index bcb7d4a63f..068381b014 100644 --- a/OsmAnd/res/values-pt-rBR/phrases.xml +++ b/OsmAnd/res/values-pt-rBR/phrases.xml @@ -3800,7 +3800,7 @@ Tipo de cabine Sim Não - Sinal para encontrar o poste + Acesso à Internet: clientes Somente quando andar é permitido Contrastado Primitivo @@ -3845,4 +3845,6 @@ Colmeia Loja de nozes GNL + Galpões + Ponto GPX \ No newline at end of file diff --git a/OsmAnd/res/values-pt-rBR/strings.xml b/OsmAnd/res/values-pt-rBR/strings.xml index 1ea7427da0..43ef613eb1 100644 --- a/OsmAnd/res/values-pt-rBR/strings.xml +++ b/OsmAnd/res/values-pt-rBR/strings.xml @@ -3928,4 +3928,5 @@ Dados de %1$s disponíveis apenas nas estradas, você precisa calcular uma rota usando “Rota entre pontos” para obtê-la. Aguarde o recálculo da rota. \nO gráfico estará disponível após o recálculo. + %1$s — %2$s \ No newline at end of file diff --git a/OsmAnd/res/values-pt/strings.xml b/OsmAnd/res/values-pt/strings.xml index 8179f41893..23fbc0cbcc 100644 --- a/OsmAnd/res/values-pt/strings.xml +++ b/OsmAnd/res/values-pt/strings.xml @@ -3935,4 +3935,6 @@ %1$s dados disponíveis apenas nas estradas, precisa calcular uma rota a usar \"Rota entre pontos\" para obtê-la. Espere pelo recalculo da rota. \nO gráfico estará disponível após o recalculo. + %1$s — %2$s + Lacuna \ No newline at end of file diff --git a/OsmAnd/res/values-ru/strings.xml b/OsmAnd/res/values-ru/strings.xml index 1e5b9b274d..145cd10775 100644 --- a/OsmAnd/res/values-ru/strings.xml +++ b/OsmAnd/res/values-ru/strings.xml @@ -1974,7 +1974,7 @@ Загрузки Показывать баннер бесплатной версии Показывать баннер бесплатной версии даже в платной версии. - В карте дорог не необходимости, так как у вас уже есть стандартная (полная) карта. Загрузить в любом случае? + В карте дорог нет необходимости, так как у вас уже есть стандартная (полная) карта. Загрузить в любом случае? %1$.1f из %2$.1f МБ %.1f МБ Обновить все (%1$s МБ) diff --git a/OsmAnd/res/values-sc/phrases.xml b/OsmAnd/res/values-sc/phrases.xml index e0a15ffcdb..2c62c095ff 100644 --- a/OsmAnd/res/values-sc/phrases.xml +++ b/OsmAnd/res/values-sc/phrases.xml @@ -3796,7 +3796,7 @@ Casta de cabina Eja Nono - Sinnale pro agatare su palu + Atzessu a ìnternet: clientes Petzi cando si podet camminare Cuntrastadu Primitivu @@ -3841,4 +3841,8 @@ Tabellone de sas tzucadas Ricàrriga de abba potàbile GNL (LNG) + Ispiatzu (layby) + Cabannas + Cobertura + Puntu GPX \ No newline at end of file diff --git a/OsmAnd/res/values-sc/strings.xml b/OsmAnd/res/values-sc/strings.xml index 4a3d545b47..8c9aa3a3ec 100644 --- a/OsmAnd/res/values-sc/strings.xml +++ b/OsmAnd/res/values-sc/strings.xml @@ -3931,4 +3931,5 @@ Gràficu Iseta su càrculu nou de s\'àndala. \nSu gràficu at a èssere a disponimentu a pustis de su càrculu. + %1$s — %2$s \ No newline at end of file diff --git a/OsmAnd/res/values-sk/strings.xml b/OsmAnd/res/values-sk/strings.xml index 6575698d3a..9f57bcf8fd 100644 --- a/OsmAnd/res/values-sk/strings.xml +++ b/OsmAnd/res/values-sk/strings.xml @@ -3933,4 +3933,6 @@ Údaje %1$s sú dostupné len na cestách, pre ich získanie musíte vypočítať trasu pomocou “Trasa medzi bodmi”. Počkajte na prepočet trasy. \nGraf bude dostupný po prepočte. + %1$s — %2$s + Medzera \ No newline at end of file diff --git a/OsmAnd/res/values-uk/phrases.xml b/OsmAnd/res/values-uk/phrases.xml index 493e631c02..0faed8c3ad 100644 --- a/OsmAnd/res/values-uk/phrases.xml +++ b/OsmAnd/res/values-uk/phrases.xml @@ -3788,7 +3788,7 @@ Вид стенда Так Ні - Сигнал, щоб знайти полюс + Доступ до Інтернету: клієнти Допускається лише при ходінні Контрастний Примітивний @@ -3833,4 +3833,8 @@ Вулик Насіннєвий магазин СПГ + Придорожня стоянка + Навіси + Дах + Точка GPX \ No newline at end of file diff --git a/OsmAnd/res/values-uk/strings.xml b/OsmAnd/res/values-uk/strings.xml index f93a7c0156..aec06b50db 100644 --- a/OsmAnd/res/values-uk/strings.xml +++ b/OsmAnd/res/values-uk/strings.xml @@ -3929,4 +3929,6 @@ %1$s дані доступні лише для доріг, вам потрібно обчислити маршрут за допомогою «Маршрут між точками», щоб отримати його. Дочекайтеся переобчислення маршруту. \nГрафік буде доступний після переобчислення. + Розрив + %1$s — %2$s \ No newline at end of file diff --git a/OsmAnd/res/values-zh-rTW/phrases.xml b/OsmAnd/res/values-zh-rTW/phrases.xml index add05fe4a7..10415b42a8 100644 --- a/OsmAnd/res/values-zh-rTW/phrases.xml +++ b/OsmAnd/res/values-zh-rTW/phrases.xml @@ -3799,7 +3799,7 @@ 亭類型 - 找到極點的訊號 + 網際網路存取:顧客 僅在步行時允許 對比 粗糙 @@ -3844,4 +3844,8 @@ 蜂箱 堅果店 LNG + 停車區 + 車棚 + 屋頂 + GPX 點 \ No newline at end of file diff --git a/OsmAnd/res/values-zh-rTW/strings.xml b/OsmAnd/res/values-zh-rTW/strings.xml index d84b6fcd82..e01741d9c3 100644 --- a/OsmAnd/res/values-zh-rTW/strings.xml +++ b/OsmAnd/res/values-zh-rTW/strings.xml @@ -3928,4 +3928,6 @@ %1$s 資料僅供道路使用,您需要使用「兩點間的路線」來計算路線。 等待路線重新計算。 \n重新計算後即可使用圖表。 + %1$s — %2$s + 分隔 \ No newline at end of file diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index cd0d9dd2b0..d5287d60bb 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -11,6 +11,16 @@ Thx - Hardy --> + Travel + Emergency + Sport + Symbols + Service + Transport + Special + Amenity + Gap + %1$s — %2$s Local maps 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. @@ -104,7 +114,7 @@ Next, snap your track to the nearest allowed road with one of your navigation profiles to use this option. Next segment Whole track - Select how to connect points, by a straight line, or calculate a route between them as specified below. + Choose how to connect the points, by a straight line, or calculate a route between them as specified below. Only the next segment will be recalculated using the selected profile. The whole track will be recalculated using the selected profile. Reverse route diff --git a/OsmAnd/res/xml/settings_main_screen.xml b/OsmAnd/res/xml/settings_main_screen.xml index 888a082ec2..e2a2a5be80 100644 --- a/OsmAnd/res/xml/settings_main_screen.xml +++ b/OsmAnd/res/xml/settings_main_screen.xml @@ -58,7 +58,7 @@ android:layout="@layout/preference_button" android:persistent="false" android:title="@string/reorder_profiles" - app:fragment="net.osmand.plus.profiles.fragments.EditProfilesFragment" + app:fragment="net.osmand.plus.profiles.EditProfilesFragment" tools:icon="@drawable/ic_action_edit_dark" /> (); - try { - JSONObject obj = new JSONObject(loadJSONFromAsset()); - JSONObject categories = obj.getJSONObject("categories"); - for (int i = 0; i < categories.length(); i++) { - JSONArray names = categories.names(); - JSONObject icons = categories.getJSONObject(names.get(i).toString()); - iconCategories.put(names.get(i).toString(), icons.getJSONArray("icons")); - } - } catch (JSONException e) { - e.printStackTrace(); - } - selectedIconCategory = getInitCategory(); - createIconForCategory(); - } - private String getInitCategory() { for (int j = 0; j < iconCategories.values().size(); j++) { JSONArray iconJsonArray = (JSONArray) iconCategories.values().toArray()[j]; @@ -604,6 +588,25 @@ public abstract class PointEditorFragmentNew extends BaseOsmAndFragment { return app.getResources().getResourceEntryName(iconId).replaceFirst("mx_", ""); } + private void createIconSelector() { + iconCategories = new LinkedHashMap<>(); + try { + JSONObject obj = new JSONObject(loadJSONFromAsset()); + JSONObject categories = obj.getJSONObject("categories"); + for (int i = 0; i < categories.length(); i++) { + JSONArray names = categories.names(); + JSONObject icons = categories.getJSONObject(names.get(i).toString()); + String name = names.get(i).toString(); + String translatedName = SettingsBaseActivity.getIconStringPropertyName(app, name, name); + iconCategories.put(translatedName, icons.getJSONArray("icons")); + } + } catch (JSONException e) { + e.printStackTrace(); + } + selectedIconCategory = getInitCategory(); + createIconForCategory(); + } + private void createIconForCategory() { FlowLayout selectIcon = view.findViewById(R.id.select_icon); selectIcon.removeAllViews(); 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/settings/fragments/BaseSettingsFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/BaseSettingsFragment.java index db12e7d781..3763987e38 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/BaseSettingsFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/BaseSettingsFragment.java @@ -899,7 +899,7 @@ public abstract class BaseSettingsFragment extends PreferenceFragmentCompat impl } public static boolean showInstance(FragmentActivity activity, SettingsScreenType screenType, @Nullable ApplicationMode appMode) { - return showInstance(activity, screenType, null, new Bundle()); + return showInstance(activity, screenType, appMode, new Bundle()); } public static boolean showInstance(FragmentActivity activity, SettingsScreenType screenType, 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(); } }); }