Merge branch 'master' into imp_exp_osm_note

# Conflicts:
#	OsmAnd/res/values/strings.xml
This commit is contained in:
Dima-1 2020-10-28 09:34:40 +02:00
commit 6112b20a6d
81 changed files with 1607 additions and 957 deletions

View file

@ -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<WptPt> points = new ArrayList<>();
public Object renderer;
public List<RouteSegment> routeSegments = new ArrayList<>();
public List<RouteType> routeTypes = new ArrayList<>();
public boolean hasRoute() {
return !routeSegments.isEmpty() && !routeTypes.isEmpty();
}
public List<GPXTrackAnalysis> 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<WptPt> points = new ArrayList<>();
public List<Route> routes = new ArrayList<>();
public List<RouteSegment> routeSegments = new ArrayList<>();
public List<RouteType> 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<WptPt> getPoints() {
@ -1218,7 +1234,7 @@ public class GPXUtilities {
GPXTrackAnalysis g = new GPXTrackAnalysis();
g.wptPoints = points.size();
g.wptCategoryNames = getWaypointCategories(true);
List<SplitSegment> splitSegments = new ArrayList<GPXUtilities.SplitSegment>();
List<SplitSegment> 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<WptPt> getRoutePoints(int routeIndex) {
List<WptPt> 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<TrkSegment> getNonEmptyTrkSegments(boolean routesOnly) {
List<TrkSegment> 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<WptPt> points) {
@ -1365,8 +1391,8 @@ public class GPXUtilities {
return false;
}
public void addRoutePoints(List<WptPt> points) {
if (routes.size() == 0) {
public void addRoutePoints(List<WptPt> 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<StringBundle> segmentsBundle = new ArrayList<>();
for (RouteSegment segment : gpxFile.routeSegments) {
for (RouteSegment segment : segment.routeSegments) {
segmentsBundle.add(segment.toStringBundle());
}
bundle.putBundleList("route", "segment", segmentsBundle);
List<StringBundle> 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<String, String> extensionsToRead = p.getExtensionsToRead();
writeExtensions(serializer, p.getExtensionsToRead(), p);
}
private static void writeExtensions(XmlSerializer serializer, Map<String, String> 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<String, String> s : extensionsToRead.entrySet()) {
if (!extensions.isEmpty()) {
for (Entry<String, String> s : extensions.entrySet()) {
writeNotNullText(serializer, s.getKey(), s.getValue());
}
}
@ -1943,8 +1973,21 @@ public class GPXUtilities {
if (!Float.isNaN(p.heading)) {
p.getExtensionsToWrite().put("heading", String.valueOf(Math.round(p.heading)));
}
Map<String, String> 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 {
writeNotNullText(serializer, "name", author.name);
@ -2099,10 +2142,11 @@ public class GPXUtilities {
TrkSegment routeTrackSegment = new TrkSegment();
routeTrack.segments.add(routeTrackSegment);
Stack<GPXExtensions> parserState = new Stack<>();
TrkSegment firstSegment = null;
boolean extensionReadMode = false;
boolean routePointExtension = false;
List<RouteSegment> routeSegments = gpxFile.routeSegments;
List<RouteType> routeTypes = gpxFile.routeTypes;
List<RouteSegment> routeSegments = new ArrayList<>();
List<RouteType> 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$

View file

@ -20,10 +20,10 @@ public class RouteExporter {
public static final String OSMAND_ROUTER_V2 = "OsmAndRouterV2";
private String name;
private List<RouteSegmentResult> route;
private List<Location> locations;
private List<WptPt> points;
private final String name;
private final List<RouteSegmentResult> route;
private final List<Location> locations;
private final List<WptPt> points;
public RouteExporter(String name, List<RouteSegmentResult> route, List<Location> locations, List<WptPt> 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<TrkSegment> trkSegments, List<WptPt> 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<StringBundle> 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<RouteSegment> routeSegments = new ArrayList<>();
for (StringBundle item : routeItems) {
routeSegments.add(RouteSegment.fromStringBundle(item));
}
gpx.routeSegments = routeSegments;
trkSegment.routeSegments = routeSegments;
List<RouteType> routeTypes = new ArrayList<>();
for (StringBundle item : typeList) {
routeTypes.add(RouteType.fromStringBundle(item));
}
gpx.routeTypes = routeTypes;
return gpx;
trkSegment.routeTypes = routeTypes;
return trkSegment;
}
}

View file

@ -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<RouteSegmentResult> route = new ArrayList<>();
private RouteRegion region = new RouteRegion();
private RouteDataResources resources = new RouteDataResources();
private final List<RouteSegmentResult> 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<RouteSegmentResult> 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<TrkSegment> 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<RouteSegmentResult> 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<Location> 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<RouteSegmentResult> collectRouteSegments(RouteRegion region, RouteDataResources resources, TrkSegment segment) {
List<RouteSegmentResult> 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);

View file

@ -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;

View file

@ -255,7 +255,8 @@ public class RouteSegmentResult implements StringExternalizable<RouteDataBundle>
@Override
public void writeToBundle(RouteDataBundle bundle) {
Map<RouteTypeRule, Integer> 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<RouteDataBundle>
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));
if (reversed) {
Algorithms.reverseArray(types);
Algorithms.reverseArray(names);
}
bundle.putArray("pointNames", convertPointNames(types, names, rules));
}
}

View file

@ -886,6 +886,14 @@ public class Algorithms {
return map;
}
public static <T> 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;
}

View file

@ -179,7 +179,7 @@
<string name="monitoring_is_enabled">Oppsyn er påskrudd</string>
<string name="monitoring_is_disabled">Oppsyn er ikke aktivert</string>
<string name="time_on_the_move">Tid i bevegelse</string>
<string name="average_altitude">Gjennomsnittlig høyde</string>
<string name="average_altitude">Gjennomsnittshøyde</string>
<string name="average_speed">Gjennomsnittsfart</string>
<string name="open_in_osmand">Vis i OsmAnd</string>
<string name="end_date">Sluttdato</string>

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape
android:dither="true"
android:shape="rectangle">
<gradient
android:angle="90"
android:startColor="#1A000000"
android:centerColor="#00FFFFFF"
android:endColor="#00FFFFFF" />
</shape>
</item>
<item>
<shape
android:dither="true"
android:shape="rectangle">
<gradient
android:angle="90"
android:startColor="#0D000000"
android:centerColor="#00FFFFFF"
android:endColor="#00FFFFFF" />
</shape>
</item>
</layer-list>

View file

@ -38,9 +38,9 @@
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/buttons_shadow"
android:layout_width="match_parent"
android:layout_height="10dp"
android:layout_height="8dp"
android:layout_gravity="bottom"
android:background="@drawable/bg_contextmenu_shadow_top_light"
android:background="@drawable/shadow"
android:visibility="gone" />
<include layout="@layout/bottom_buttons" />

View file

@ -33,9 +33,9 @@
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/buttons_shadow"
android:layout_width="match_parent"
android:layout_height="10dp"
android:layout_height="8dp"
android:layout_gravity="bottom"
android:background="@drawable/bg_contextmenu_shadow_top_light"
android:background="@drawable/shadow"
android:visibility="gone" />
</FrameLayout>

View file

@ -32,8 +32,8 @@
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/buttons_shadow"
android:layout_width="match_parent"
android:layout_height="10dp"
android:background="@drawable/bg_contextmenu_shadow_top_light" />
android:layout_height="8dp"
android:background="@drawable/shadow" />
<LinearLayout
android:layout_width="match_parent"

View file

@ -128,9 +128,9 @@
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/buttons_shadow"
android:layout_width="match_parent"
android:layout_height="10dp"
android:layout_height="8dp"
android:layout_gravity="bottom"
android:background="@drawable/bg_contextmenu_shadow_top_light" />
android:background="@drawable/shadow" />
<include
layout="@layout/bottom_buttons"

View file

@ -98,9 +98,9 @@
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/buttons_shadow"
android:layout_width="match_parent"
android:layout_height="10dp"
android:layout_height="8dp"
android:layout_gravity="bottom"
android:background="@drawable/bg_contextmenu_shadow_top_light" />
android:background="@drawable/shadow" />
<include
layout="@layout/bottom_buttons"

View file

@ -591,9 +591,9 @@
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/buttons_shadow"
android:layout_width="match_parent"
android:layout_height="10dp"
android:layout_height="8dp"
android:layout_gravity="bottom"
android:background="@drawable/bg_contextmenu_shadow_top_light" />
android:background="@drawable/shadow" />
<include
layout="@layout/route_info_menu_control_buttons"

View file

@ -129,9 +129,9 @@
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/buttons_shadow"
android:layout_width="match_parent"
android:layout_height="10dp"
android:layout_height="8dp"
android:layout_gravity="bottom"
android:background="@drawable/bg_contextmenu_shadow_top_light" />
android:background="@drawable/shadow" />
<include
layout="@layout/bottom_buttons"

View file

@ -904,7 +904,7 @@
<string name="rendering_attr_OSMMapperAssistant_name">مساعد تخطيط OSM</string>
<string name="agps_info">معلومات A-GPS</string>
<string name="shared_string_manage">إدارة</string>
<string name="shared_string_edit">تعديل/حذف</string>
<string name="shared_string_edit">تعديل</string>
<string name="shared_string_places">أماكن</string>
<string name="shared_string_search">بحث</string>
<string name="shared_string_show_description">عرض الوصف.</string>
@ -1076,8 +1076,8 @@
<string name="rendering_category_others">سمات أخرى للخريطة</string>
<string name="map_widget_appearance_rem">العناصر الأخرى</string>
<string name="map_widget_top">شريط المعلومات</string>
<string name="map_widget_right">العدادات على اليمين</string>
<string name="map_widget_left">العدادات على اليسار</string>
<string name="map_widget_right">العدادات على اليسار</string>
<string name="map_widget_left">العدادات على اليمين</string>
<string name="search_radius_proximity">ضمن</string>
<string name="anonymous_user">مستخدم مجهول</string>
<string name="logged_as">سجل الدخول ب %1$s</string>
@ -1153,7 +1153,7 @@
<string name="action_delete">حذف إجراء</string>
<string name="osm_edits">التعديلات</string>
<string name="parking_place_limited">وقت وقوف السيارات يقتصر على</string>
<string name="shared_string_collapse">تدلي</string>
<string name="shared_string_collapse">أقل</string>
<string name="drawer">قائمة منبسطة</string>
<string name="osm_settings">تعديل OSM</string>
<string name="free">فارغ %1$s</string>
@ -1483,7 +1483,7 @@
<string name="access_smart_autoannounce">التنبيه الآلي الذكي</string>
<string name="access_smart_autoannounce_descr">الإشعار فقط عند تغير الوجهة نحو نقطة الهدف.</string>
<string name="access_autoannounce_period">مهلة التنبيه الآلي</string>
<string name="access_autoannounce_period_descr">أقل مهلة بين الاخطارات.</string>
<string name="access_autoannounce_period_descr">أقل مهلة بين الإشعارات.</string>
<string name="access_map_linked_to_location">الخريطة مرتبطة بالموقع</string>
<string name="rendering_value_bold_name">عريض</string>
<string name="anonymous_user_hint">المستخدم المجهول لا يمكنه :
@ -1658,7 +1658,7 @@
<string name="no_location_permission">منح الوصول إلى بيانات الموقع.</string>
<string name="rendering_attr_horseRoutes_name">مسارات الخيول</string>
<string name="shared_string_hide">إخفاء</string>
<string name="av_video_quality_low">أقل جودة</string>
<string name="av_video_quality_low">جودة أقل</string>
<string name="av_video_quality_high">أعلى جودة</string>
<string name="copied_to_clipboard">تم النسخ في الحافظة</string>
<string name="context_menu_item_open_note">فتح ملاحظة OSM</string>
@ -1838,7 +1838,7 @@
<string name="osb_comment_dialog_error">لا يمكن إضافة تعليق.</string>
<string name="shared_string_commit">تقديم</string>
<string name="context_menu_item_delete_waypoint">حذف إحداثية GPX ؟</string>
<string name="context_menu_item_edit_waypoint">تعديل/حذف</string>
<string name="context_menu_item_edit_waypoint">تعديل</string>
<string name="lang_nds">ألمانية منخفضة</string>
<string name="lang_fy">اللغة الفريزية</string>
<string name="rendering_attr_hideProposed_name">الأشياء المقترحة</string>
@ -1996,7 +1996,7 @@
<string name="rendering_attr_hideOverground_name">أشياء فوق سطح الأرض</string>
<string name="shared_string_change">تغيير</string>
<string name="get_started">ابدأ</string>
<string name="routing_attr_short_way_name">طريق أقل استهلاكا للوقود</string>
<string name="routing_attr_short_way_name">طريق أقل استهلاكاً للوقود</string>
<string name="routing_attr_short_way_description">استخدم طريق أقل استهلاكا للوقود (عادة أقصر).</string>
<string name="replace_favorite_confirmation">هل تريد استبدال المفضلة %1$s؟</string>
<string name="clear_tile_data">حذف جميع الطبقات</string>
@ -2249,7 +2249,7 @@
<string name="quick_action_auto_zoom_on">قم بتشغيل التكبير التلقائي</string>
<string name="quick_action_auto_zoom_off">إيقاف التكبير التلقائي</string>
<string name="quick_action_add_first_intermediate">إضافة وجهة وسطى</string>
<string name="analyze_on_map">تحليل على الخريطة</string>
<string name="analyze_on_map">تحليل</string>
<string name="shared_string_visible">المعروضة على الخريطة</string>
<string name="restore_purchases">استرجاع الشراء</string>
<string name="do_not_send_anonymous_app_usage">لا ترسل إحصاءات مجهولة عن استخدام التطبيق</string>
@ -2302,7 +2302,7 @@
<string name="download_depth_countours">محيطات الأعماق البحرية</string>
<string name="do_not_send_anonymous_app_usage_desc">أوسماند يقوم بجمع معلومات حول أجزاء من التطبيقات التي تفتحها. الموقع الخاص بك لا يرسل ابدأ، ولا أي شيء تقوم بإدخاله في التطبيق أو أي تفاصيل لمناطق رأيتها ، بحثت عنها أو نزلتها.</string>
<string name="do_not_show_startup_messages_desc">عرض خصومات التطبيق ورسائل الأحداث المحلية الخاصة.</string>
<string name="routing_attr_relief_smoothness_factor_plains_name">أقل تضاريس</string>
<string name="routing_attr_relief_smoothness_factor_plains_name">تضاريس أقل</string>
<string name="routing_attr_relief_smoothness_factor_more_plains_name">مسطح</string>
<string name="routing_attr_driving_style_balance_name">متوازن</string>
<string name="relief_smoothness_factor_descr">التضاريس المفضلة : مسطحة أو تلال.</string>
@ -2730,7 +2730,7 @@
<string name="coord_input_add_point">إضافة نقطة</string>
<string name="coord_input_save_as_track">حفظ كمسار</string>
<string name="coord_input_save_as_track_descr">أنت بحاجة %1$s نقاط. اكتب اسم ملف واضغط \"حفظ\".</string>
<string name="error_notification_desc">يرجى إرسال لقطة شاشة من هذا الإخطار إلى support@osmand.net</string>
<string name="error_notification_desc">يرجى إرسال لقطة شاشة من هذا الإشعار إلى support@osmand.net</string>
<string name="quick_action_edit_actions">تعديل الإجراء</string>
<string name="get_osmand_live">احصل على أوسماند لايف لإلغاء قفل جميع الميزات: تحديثات الخرائط اليومية مع تنزيلات غير محدودة، وجميع الإضافات المدفوعة والمجانية ، ويكيبيديا، ويكي الرحلات وأكثر.</string>
<string name="osm_live_subscriptions">الاشتراكات</string>
@ -3101,7 +3101,7 @@
<string name="rendering_attr_tracktype_grade5_name">لينة</string>
<string name="routeInfo_tracktype_name">متانة السطح</string>
<string name="shared_string_file_is_saved">%s تم الحفظ</string>
<string name="shared_string_open_track">مسار مفتوح</string>
<string name="shared_string_open_track">فتح المسار</string>
<string name="shared_string_track_is_saved">المسار %s تم حفظ</string>
<string name="gpx_join_gaps">ربط الأجزاء</string>
<string name="app_mode_camper">العربه</string>
@ -3223,7 +3223,7 @@
<string name="app_mode_offroad">الطرق الوعره</string>
<string name="edit_profile_setup_title">إعداد الوضع</string>
<string name="edit_profile_setup_subtitle">يحتفظ الوضع بإعداداتك</string>
<string name="edit_profile_setup_map_subtitle">حدد خيارات الخريطة للملف الشخصي</string>
<string name="edit_profile_setup_map_subtitle">حدد خيارات الخريطة للوضع</string>
<string name="edit_profile_screen_options_subtitle">حدد خيارات الشاشة للوضع</string>
<string name="edit_profile_nav_settings_subtitle">حدد إعدادات الملاحة للوضع</string>
<string name="routing_attr_max_num_changes_description">حدد الحد الأعلى للتغييرات</string>
@ -3387,7 +3387,7 @@
<string name="selected_profile">الوضع المحدد</string>
<string name="reset_confirmation_descr">بالضغط على %1$s، ستفقد كل تغييراتك.</string>
<string name="reset_all_profile_settings_descr">سيتم إعادة ضبط جميع إعدادات الوضع إلى الحالة الافتراضية بعد التثبيت.</string>
<string name="reset_all_profile_settings">استعادة الضبط الافتراضي؟</string>
<string name="reset_all_profile_settings">استعادة الضبط الافتراضي لكل الأوضاع؟</string>
<string name="ltr_or_rtl_combine_via_space">%2$s %1$s</string>
<string name="ltr_or_rtl_combine_via_colon">%2$s :%1$s</string>
<string name="file_does_not_contain_routing_rules">\'%1$s\' لا يحتوي الملف على قواعد توجيه ،يرجى اختيار ملف آخر.</string>
@ -3489,7 +3489,7 @@
<string name="copy_coordinates">نسخ الإحداثيات</string>
<string name="routing_profile_direct_to">مباشر إلى نقطة</string>
<string name="sort_by_category">الفرز حسب الفئة</string>
<string name="please_provide_profile_name_message">يرجى اعطاء اسم للملف الشخصي</string>
<string name="please_provide_profile_name_message">يرجى إدخال اسم للوضع</string>
<string name="open_settings">افتح الإعدادات</string>
<string name="plugin_disabled">الملحق مُعطل</string>
<string name="shared_string_menu">القائمة</string>
@ -3732,7 +3732,7 @@
\nشهر واحد هو 43 829 دقيقة.</string>
<string name="tiles_storage_descr">اختر كيفية تخزين الطبقات المنزلة.</string>
<string name="default_screen_timeout">مهلة الشاشة الافتراضية</string>
<string name="export_import_quick_actions_with_profiles_promo">يمكنك تصدير أو استيراد إجراءات سريعة باستخدام ملفات بروفايل التطبيق .</string>
<string name="export_import_quick_actions_with_profiles_promo">يمكنك تصدير أو استيراد إجراءات سريعة باستخدام أوضاع التطبيق .</string>
<string name="shared_string_delete_all_q">حذف الكل؟</string>
<string name="delete_all_actions_message_q">هل أنت متأكد من رغبتك في حذف الاختصارات السريعة %d نهائيًا؟</string>
<string name="screen_timeout">مهلة الشاشة</string>
@ -3771,7 +3771,7 @@
\n
\nحدد %1$s وستتلقى تنبيهات وتحذيرات حول كاميرات السرعة.
\n
\nحدد %2$s. جميع البيانات المتعلقة كاميرات السرعة: التنبيهات، والإخطارات، سيتم حذف نقاط الاهتمام حتى يتم إعادة تثبيت أوسماند تماما.</string>
\nحدد %2$s. جميع البيانات المتعلقة كاميرات السرعة: التنبيهات، والإشعارات، سيتم حذف نقاط الاهتمام حتى يتم إعادة تثبيت أوسماند تماما.</string>
<string name="routing_attr_length_description">تحديد الارتفاع الأعلى المسموح به على الطرق.</string>
<string name="routing_attr_length_name">حد الطول</string>
<string name="speed_cameras_removed_descr">هذا الجهاز لا يملك كاميرات السرعة.</string>
@ -3909,7 +3909,7 @@
<string name="complex_routing_descr">التوجيه على مرحلتين لملاحة السيارة.</string>
<string name="use_native_pt">تطوير النقل العام المحلي</string>
<string name="use_native_pt_desc">قم بالتبديل إلى Java (الآمن) حساب توجيه النقل العام</string>
<string name="perform_oauth_authorization_description">قم بإجراء تسجيل دخول إلى OAuth لاستخدام ميزات osmedit</string>
<string name="perform_oauth_authorization_description">قم بتسجيل الدخول إلى OAuth لاستخدام ميزات osmedit</string>
<string name="perform_oauth_authorization">تسجيل الدخول عبر OAuth</string>
<string name="clear_osm_token">مسح رمز OpenStreetMap OAuth</string>
<string name="osm_edit_logout_success">تسجيل الخروج بنجاح</string>
@ -3920,4 +3920,6 @@
\nسيتوفر الرسم البياني بعد إعادة الحساب.</string>
<string name="snowmobile_render_descr">للقيادة على الجليد مع طرق ومسارات مخصصة.</string>
<string name="shared_string_graph">رسم بياني</string>
<string name="ltr_or_rtl_combine_via_dash">%2$s — %1$s</string>
<string name="app_mode_gap">فجوة</string>
</resources>

View file

@ -1553,7 +1553,7 @@ Per retornar a l\'estil habitual dels mapes d\'OsmAnd, només cal desactivar aqu
<string name="routing_attr_height_name">Límit d\'alçada</string>
<string name="routing_attr_height_description">Indiqueu l\'alçada del vehicle que les rutes han d\'admetre.</string>
<string name="use_fast_recalculation">Recàlcul intel·ligent de la ruta</string>
<string name="use_fast_recalculation_desc">En viatges llargs, només actualitzis la part inicial de la ruta.</string>
<string name="use_fast_recalculation_desc">Actualitza només la part inicial de la ruta. Pot ser usat per a viatges llargs.</string>
<string name="shared_string_logoff">Surt</string>
<string name="rendering_value_disabled_name">Desactivat</string>
<string name="rendering_value_walkingRoutesScopeOSMC_name">Acoloreix segons el tipus de xarxa</string>
@ -3589,10 +3589,10 @@ Abasta l\'àrea: %1$s x %2$s</string>
<string name="slope_description">Les pistes es mostren sobre el terreny i amb colors.</string>
<string name="download_slope_maps">Pistes</string>
<string name="custom_osmand_plugin">Connector d\'OsmAnd adaptat</string>
<string name="replace_point_descr">Substitueix un altre punt per aquest</string>
<string name="replace_point_descr">Substitueix un altre punt per aquest.</string>
<string name="changes_applied_to_profile">S\'han fet els canvis al perfil \'%1$s\'.</string>
<string name="settings_item_read_error">No s\'ha pogut llegir des de \'%1$s\'.</string>
<string name="settings_item_write_error">No s\'ha pogut escriure %1$s.</string>
<string name="settings_item_write_error">No s\'ha pogut escriure a \'%1$s\'.</string>
<string name="settings_item_import_error">No s\'ha pogut importar des de \'%1$s\'.</string>
<string name="select_track_file">Seleccioneu fitxer de la traça</string>
<string name="shared_string_languages">Idiomes</string>
@ -3619,7 +3619,7 @@ Abasta l\'àrea: %1$s x %2$s</string>
<string name="lang_an">Aragonès</string>
<string name="lang_lmo">Llombard</string>
<string name="custom_color">Color personalitzat</string>
<string name="select_wikipedia_article_langs">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.</string>
<string name="select_wikipedia_article_langs">Seleccioneu els idiomes per als articles de Viquipèdia al mapa. Canvieu la llengua entre les disponibles mentre llegiu un article.</string>
<string name="some_articles_may_not_available_in_lang">Alguns articles de la Viquipèdia podrien no estar disponibles en el vostre idioma.</string>
<string name="lang_zhyue">Cantonès</string>
<string name="lang_zhminnan">Min nan</string>
@ -3672,11 +3672,11 @@ Abasta l\'àrea: %1$s x %2$s</string>
<string name="routing_attr_length_name">Llargada màxima</string>
<string name="shared_string_bearing">Trajectòria</string>
<string name="item_deleted">S\'ha esborrat %1$s</string>
<string name="speed_cameras_restart_descr">Cal reiniciar per esborrar totalment les dades de les càmeres de radar.</string>
<string name="speed_cameras_restart_descr">Reinicia l\'aplicació per esborrar totes les dades de les càmeres de radar.</string>
<string name="shared_string_uninstall_and_restart">Desinstal·la i Reinicia</string>
<string name="speed_cameras_removed_descr">Aquest dispositiu no inclou les càmeres de radar.</string>
<string name="app_mode_inline_skates">Patins en línia</string>
<string name="use_volume_buttons_as_zoom_descr">Activeu per controlar el nivell d\'ampliació del mapa amb els botons del volum del dispositiu.</string>
<string name="use_volume_buttons_as_zoom_descr">Controla el nivell d\'ampliació del mapa fent servir els botons del volum del dispositiu.</string>
<string name="use_volume_buttons_as_zoom">Botons de volum pel zoom</string>
<string name="delete_all_actions_message_q">Esteu segur que voleu suprimir definitivament %d dreceres\?</string>
<string name="export_import_quick_actions_with_profiles_promo">Podeu exportar o importar les dreceres amb els perfils de les aplicacions.</string>
@ -3686,7 +3686,7 @@ Abasta l\'àrea: %1$s x %2$s</string>
<string name="screen_timeout_descr">Si està activat \"%1$s\" el temps d\'activitat quedarà afectat.</string>
<string name="shared_string_tones">tones</string>
<string name="shared_string_meters">metres</string>
<string name="quick_action_remove_next_destination">Suprimeix la propera fita</string>
<string name="quick_action_remove_next_destination">Suprimeix la fita més propera</string>
<string name="please_provide_point_name_error">Proporcioneu un nom per al punt</string>
<string name="quick_action_remove_next_destination_descr">La propera fita de la ruta s\'esborrarà. Si es tractés de la Destinació final, la navegació s\'aturaria.</string>
<string name="search_download_wikipedia_maps">Baixa mapes de la Viquipèdia</string>
@ -3850,4 +3850,13 @@ Abasta l\'àrea: %1$s x %2$s</string>
\n • S\'han corregit problemes en la importació/exportació de la configuració dels perfils
\n
\n</string>
<string name="quick_action_transport_show">Mostra el transport públic</string>
<string name="shared_string_add_profile">Afegeix un perfil</string>
<string name="change_application_profile">Canvia el perfil de l\'aplicació</string>
<string name="index_item_world_basemap_detailed">Mapa general del món (detallat)</string>
<string name="unsupported_type_error">Tipus no suportat</string>
<string name="shared_string_always">Sempre</string>
<string name="screen_control">Control de pantalla</string>
<string name="development">Desenvolupament</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
</resources>

View file

@ -3588,20 +3588,20 @@
<string name="poi_substation_compensation">Kompenzační</string>
<string name="poi_substation_compression">Kompresní</string>
<string name="poi_substation_measurement">Měřicí</string>
<string name="poi_rtsa_scale_nc">н/к</string>
<string name="poi_rtsa_scale_nc_asterisk">н/к*</string>
<string name="poi_rtsa_scale_nc">n/c</string>
<string name="poi_rtsa_scale_nc_asterisk">n/c*</string>
<string name="poi_rtsa_scale_1a">1А</string>
<string name="poi_rtsa_scale_1a_asterisk">1А*</string>
<string name="poi_rtsa_scale_1b">1Б</string>
<string name="poi_rtsa_scale_1b_asterisk">1Б*</string>
<string name="poi_rtsa_scale_2a">2А</string>
<string name="poi_rtsa_scale_2a_asterisk">2А*</string>
<string name="poi_rtsa_scale_2b">2Б</string>
<string name="poi_rtsa_scale_2b_asterisk">2Б*</string>
<string name="poi_rtsa_scale_3a">3А</string>
<string name="poi_rtsa_scale_3a_asterisk">3А*</string>
<string name="poi_rtsa_scale_3b">3Б</string>
<string name="poi_rtsa_scale_3b_asterisk">3Б*</string>
<string name="poi_rtsa_scale_1b">1B</string>
<string name="poi_rtsa_scale_1b_asterisk">1B*</string>
<string name="poi_rtsa_scale_2a">2A</string>
<string name="poi_rtsa_scale_2a_asterisk">2A*</string>
<string name="poi_rtsa_scale_2b">2B</string>
<string name="poi_rtsa_scale_2b_asterisk">2B*</string>
<string name="poi_rtsa_scale_3a">3A</string>
<string name="poi_rtsa_scale_3a_asterisk">3A*</string>
<string name="poi_rtsa_scale_3b">3B</string>
<string name="poi_rtsa_scale_3b_asterisk">3B*</string>
<string name="poi_snowmobile_filter">Přístup sněžným skútrům</string>
<string name="poi_access_bus">Přístup autobusům</string>
<string name="poi_access_caravan">Přístup karavanům</string>
@ -3827,7 +3827,7 @@
<string name="poi_osmand_fire_hydrant_pressure_pressurized">Pod tlakem</string>
<string name="poi_fire_hydrant_style_water_source_groundwater">Podzemní voda</string>
<string name="poi_fire_hydrant_type_pipe">Roura</string>
<string name="poi_internet_access_fee_customers">Internetový přístup: zdarma pro zákazníky</string>
<string name="poi_internet_access_fee_customers">Internetový přístup: zákazníci</string>
<string name="poi_monastery_type_clerks_regular">Typ klášteru: řeholnický</string>
<string name="poi_monastery_type_hermitage">Typ klášteru: poustevnický</string>
<string name="poi_monastery_type_canonry">Typ klášteru: kanovnický</string>
@ -3845,4 +3845,8 @@
<string name="poi_traffic_signals_vibration">Vibrace</string>
<string name="poi_fire_hydrant_pressure_filter">Tlak</string>
<string name="poi_fuel_lng">Zkapalněný zemní plyn</string>
<string name="poi_parking_layby">Podél silnice</string>
<string name="poi_parking_sheds">Přístřešky</string>
<string name="poi_parking_rooftop">Střešní</string>
<string name="poi_gpx_point">Bod GPX</string>
</resources>

View file

@ -3578,4 +3578,15 @@ Zobrazená oblast: %1$s x %2$s</string>
<string name="sort_name_ascending">Název: A Z</string>
<string name="start_finish_icons">Ikony startu/cíle</string>
<string name="contour_lines_thanks">Děkujeme za zakoupení modulu \'Vrstevnice\'</string>
<string name="perform_oauth_authorization_description">Přihlásit se pomocí OAuth pro použití funkcí editace OSM</string>
<string name="perform_oauth_authorization">Přihlásit pomocí OAuth</string>
<string name="clear_osm_token">Vymazat OpenStreetMap OAuth token</string>
<string name="osm_edit_logout_success">Odhlášení úspěšné</string>
<string name="file_already_imported">Soubor je již importovaný v OsmAnd</string>
<string name="use_two_phase_routing">Použít dvoufázový algoritmus A* pro výpočet trasy</string>
<string name="shared_string_graph">Graf</string>
<string name="message_need_calculate_route_before_show_graph">Údaje %1$s jsou dostupné pouze na cestách, pro jejich získání musíte vypočítat trasu pomocí “Trasa medzi body”.</string>
<string name="message_graph_will_be_available_after_recalculation">Počkejte na přepočet trasy.
\nGraf bude dostupný po přepočtu.</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
</resources>

View file

@ -3788,4 +3788,6 @@
<string name="all_next_segments_will_be_recalc">Alle efterfølgende segmenter genberegnes ved hjælp af den valgte profil.</string>
<string name="all_previous_segments_will_be_recalc">Alle tidligere segmenter genberegnes ved hjælp af den valgte profil.</string>
<string name="start_finish_icons">Start-/slutikoner</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
<string name="app_mode_gap">Hul</string>
</resources>

View file

@ -3848,4 +3848,8 @@
<string name="poi_recycling_small_electrical_appliances">Kleine Elektrogeräte</string>
<string name="poi_nuts">Nussladen</string>
<string name="poi_fuel_lng">Flüssigerdgas</string>
<string name="poi_parking_layby">Parken in Parallelstraße</string>
<string name="poi_parking_sheds">Überdachter Parkplatz</string>
<string name="poi_parking_rooftop">Dachparkplätze</string>
<string name="poi_gpx_point">GPX-Wegpunkt</string>
</resources>

View file

@ -3652,9 +3652,9 @@
<string name="ltr_or_rtl_combine_via_slash_with_space">%1$s / %2$s</string>
<string name="osm_live_payment_subscription_management">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.</string>
\nSie können Ihre Abonnements verwalten und kündigen, indem Sie zu Ihren Google Play-Einstellungen gehen.</string>
<string name="search_poi_types">Suche nach POI-Typen</string>
<string name="search_poi_types_descr">Kombinieren Sie POI-Typen aus verschiedenen Kategorien. Tippen Sie auf den Schalter, um alle auszuwählen, tippen Sie auf die linke Seite zur Kategorieauswahl.</string>
<string name="shared_string_divider">Trenner</string>
@ -3913,9 +3913,9 @@
<string name="osm_live_payment_desc_hw">Das Abonnement wird pro ausgewähltem Zeitraum berechnet. Sie können das Abonnement jederzeit über die AppGallery kündigen.</string>
<string name="osm_live_payment_subscription_management_hw">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.</string>
\nSie können Ihre Abonnements verwalten und kündigen, indem Sie zu Ihren AppGallery-Einstellungen gehen.</string>
<string name="routing_attr_avoid_footways_description">Vermeidet Fußwege</string>
<string name="routing_attr_avoid_footways_name">Keine Fußwege</string>
<string name="development">Entwicklung</string>
@ -3929,4 +3929,8 @@
<string name="file_already_imported">Datei wurde bereits in OsmAnd importiert</string>
<string name="perform_oauth_authorization">Anmelden über OAuth</string>
<string name="clear_osm_token">OpenStreetMap OAuth-Token löschen</string>
<string name="what_is_new">Was ist neu</string>
<string name="snowmobile_render_descr">Für das Schneemobilfahren mit speziellen Straßen und Tracks.</string>
<string name="perform_oauth_authorization_description">Durchführen eines OAuth-Logins zur Nutzung der osmedit-Funktionen</string>
<string name="use_two_phase_routing">2-Phasen-A*-Routing-Algorithmus verwenden</string>
</resources>

View file

@ -3838,4 +3838,8 @@
<string name="poi_departures_board">Tabulo de forveturoj</string>
<string name="poi_drinking_water_refill">Plenigi per trinkebla akvo</string>
<string name="poi_fuel_lng">tergaso likva (LNG)</string>
<string name="poi_parking_layby">laŭlonge de strato</string>
<string name="poi_parking_sheds">privataj garaĝ-budoj</string>
<string name="poi_parking_rooftop">tegmento</string>
<string name="poi_gpx_point">GPX-punkto</string>
</resources>

View file

@ -3931,9 +3931,10 @@
<string name="osm_edit_logout_success">Sesión finalizada</string>
<string name="snowmobile_render_descr">Para caminos y senderos exclusivos de motos de nieve.</string>
<string name="file_already_imported">El archivo ya fue importado en OsmAnd</string>
<string name="use_two_phase_routing">Usar el algoritmo de enrutamiento A* de 2 fases</string>
<string name="use_two_phase_routing">Usar el algoritmo de navegación A* bifásica</string>
<string name="shared_string_graph">Gráfico</string>
<string name="message_need_calculate_route_before_show_graph">%1$s datos disponibles sólo en los caminos, necesitas calcular una ruta usando «Ruta entre puntos» para obtenerla.</string>
<string name="message_graph_will_be_available_after_recalculation">Espera el recálculo de la ruta.
\nEl gráfico estará disponible después del recálculo.</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
</resources>

View file

@ -3774,7 +3774,7 @@
<string name="poi_tactile_paving_incorrect">Ebaõige</string>
<string name="poi_tactile_paving_contrasted">Kontrastne</string>
<string name="poi_traffic_signals_sound_locate">Ainult kui jalakäijatele lubatud</string>
<string name="poi_internet_access_fee_customers">Tasuline internetipunkt</string>
<string name="poi_internet_access_fee_customers">Tasuline internetipunkt klientidele</string>
<string name="poi_video_no">Ei</string>
<string name="poi_video_yes">Jah</string>
<string name="poi_booth">Kioski tüüp</string>
@ -3827,4 +3827,8 @@
<string name="poi_beehive">Mesitaru</string>
<string name="poi_nuts">Pähklipood</string>
<string name="poi_fuel_lng">Veeldatud maagaas</string>
<string name="poi_gpx_point">GPX sõlm</string>
<string name="poi_parking_layby">Parkla kiirtee ääres</string>
<string name="poi_parking_sheds">Parkimine varjualustes</string>
<string name="poi_parking_rooftop">Parkla katusel</string>
</resources>

View file

@ -3782,4 +3782,8 @@
<string name="what_is_new">Meie uudised</string>
<string name="use_two_phase_routing">Kasuta kahefaasilist A-klassi teekonna koostamise algoritmi</string>
<string name="file_already_imported">See fail on juba OsmAnd\'i imporditud</string>
<string name="use_live_routing">OsmAnd andmed reaalajas</string>
<string name="use_live_public_transport">OsmAnd andmed reaalajas</string>
<string name="snowmobile_render_descr">Mootorsaanide sõitmine eraldi määratud teedel ja radadel.</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
</resources>

View file

@ -1050,7 +1050,7 @@
<string name="poi_nudism_no">Interdit</string>
<string name="poi_nudism_obligatory">Obligatoire</string>
<string name="poi_population">Population</string>
<string name="poi_parking_underground">Parking : sous-terrain</string>
<string name="poi_parking_underground">Parking : souterrain</string>
<string name="poi_trees_olive">Olivier</string>
<string name="poi_trees_apple">Pommier</string>
<string name="poi_trees_oil">Palmier</string>

View file

@ -3845,7 +3845,7 @@
<string name="simplified_track">Trace simplifiée</string>
<string name="shared_string_file_name">Nom de fichier</string>
<string name="system_default_theme">Par défaut</string>
<string name="open_saved_track">Ouvrir une trace enregistrée</string>
<string name="open_saved_track">Ouvrir la trace enregistrée</string>
<string name="shared_string_is_saved">a été enregistré</string>
<string name="one_point_error">Veuillez ajouter au moins deux points.</string>
<string name="import_track_descr">Sélectionnez le fichier de trace à suivre ou importez-le depuis votre appareil.</string>
@ -3912,4 +3912,6 @@
\nLe graphique sera disponible à l\'issue du calcul.</string>
<string name="snowmobile_render_descr">Pour la conduite en motoneige avec des routes et des pistes dédiées.</string>
<string name="shared_string_graph">Graphique</string>
<string name="app_mode_gap">Écart</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s - %2$s</string>
</resources>

View file

@ -3950,4 +3950,9 @@ Lon %2$s</string>
<string name="perform_oauth_authorization">Entrar polo OAuth</string>
<string name="clear_osm_token">Limpar token do OpenStreetMap OAuth</string>
<string name="osm_edit_logout_success">Sesión rematada</string>
<string name="snowmobile_render_descr">Para estradas e pistas exclusivas de motos de neve.</string>
<string name="file_already_imported">O ficheiro xa foi importado no OsmAnd</string>
<string name="use_two_phase_routing">Usar algoritmo de enrutamento A* de 2 fases</string>
<string name="shared_string_graph">Gráfica</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
</resources>

View file

@ -454,7 +454,7 @@
<string name="poi_attraction_train">Vonat (látványosság)</string>
<string name="poi_attraction_water_slide">Vízi csúszda</string>
<string name="poi_hunting_lodge">Vadászház</string>
<string name="poi_internet_access_wlan">Internetcsatlakozás: WLAN</string>
<string name="poi_internet_access_wlan">Internetcsatlakozás: WLAN (wifi)</string>
<string name="poi_internet_access_terminal">Internetcsatlakozás: munkaállomás</string>
<string name="poi_internet_access_wired">Internetcsatlakozás: kábel</string>
<string name="poi_internet_access_public">Internetcsatlakozás: nyilvános</string>
@ -836,7 +836,7 @@
<string name="poi_denomination_georgian_orthodox">Grúz ortodox</string>
<string name="poi_denomination_romanian_orthodox">Román ortodox</string>
<string name="poi_denomination_coptic_orthodox">Kopt ortodox</string>
<string name="poi_internet_access_yes">Internetcsatlakozás</string>
<string name="poi_internet_access_yes">Internetcsatlakozás van</string>
<string name="poi_internet_access_no">Internetcsatlakozás nincs</string>
<string name="poi_dance_floor">Tánctér</string>
<string name="poi_nightclub">Night club; Diszkó</string>
@ -1547,7 +1547,7 @@
<string name="poi_internet_access_type_wlan">Wi-Fi</string>
<string name="poi_internet_access_type_terminal">Munkaállomás</string>
<string name="poi_internet_access_type_wired">Vezetékes</string>
<string name="poi_internet_access_type_public">Nyilvános</string>
<string name="poi_internet_access_type_public">Internetcsatlakozás: nyilvános</string>
<string name="poi_internet_access_type_service">Segítenek</string>
<string name="poi_internet_access_type_no">Internetcsatlakozás nincs</string>
<string name="poi_internet_access_type_yes">Internetcsatlakozás van</string>
@ -3836,4 +3836,8 @@
<string name="poi_nuts">Mag- és aszaltgyümölcsbolt</string>
<string name="poi_beehive">Méhkaptár</string>
<string name="poi_fuel_lng">LNG (cseppfolyósított földgáz)</string>
<string name="poi_parking_layby">Út mellett parkolósáv (UK)</string>
<string name="poi_parking_sheds">Fedett parkolóhely</string>
<string name="poi_parking_rooftop">Tető</string>
<string name="poi_internet_access_fee_customers">Internetcsatlakozás: ügyfeleknek</string>
</resources>

View file

@ -3509,7 +3509,7 @@
<string name="clear_recorded_data">Rögzített adatok törlése</string>
<string name="terrain_empty_state_text">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.</string>
<string name="app_mode_ski_touring">Túrasízés</string>
<string name="app_mode_ski_snowmobile">Motoros szán</string>
<string name="app_mode_ski_snowmobile">Motoros szán</string>
<string name="custom_osmand_plugin">Egyéni OsmAnd bővítmény</string>
<string name="settings_item_read_error">Sikertelen olvasás innen: \'%1$s\'.</string>
<string name="settings_item_write_error">Sikertelen írás ide: \'%1$s\'.</string>
@ -3920,4 +3920,10 @@
<string name="osm_edit_logout_success">Sikeresen kijelentkezett</string>
<string name="use_two_phase_routing">Kétszakaszos A* útvonaltervezési algoritmus használata</string>
<string name="file_already_imported">A fájl már importálva van az OsmAndba</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s - %2$s</string>
<string name="snowmobile_render_descr">Motorosszánutakhoz kifejezetten motoros szán számára kijelölt utakon.</string>
<string name="shared_string_graph">Grafikon</string>
<string name="message_need_calculate_route_before_show_graph">%1$s adatok csak az utakról állnak rendelkezésre. Használja az „Útvonal tervezése pontok között” funkciót.</string>
<string name="message_graph_will_be_available_after_recalculation">Várja meg az útvonal újraszámítását.
\nAz ábra az újraszámítás után lesz látható.</string>
</resources>

View file

@ -3905,4 +3905,32 @@
<string name="sort_name_ascending">Nome: A Z</string>
<string name="start_finish_icons">Icona Partenza/Arrivo</string>
<string name="contour_lines_thanks">Grazie per l\'acquisto del \'Plugin delle curve di livello\'</string>
<string name="what_is_new">Novità</string>
<string name="snowmobile_render_descr">Per slitte a motore con strade e sentieri dedicati.</string>
<string name="osm_live_payment_desc_hw">Sottoscrizione addebitata per il periodo selezionato. Cancellala nell\'AppGallery in ogni momento.</string>
<string name="osm_live_payment_subscription_management_hw">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.</string>
<string name="routing_attr_avoid_footways_description">Evita i marciapiedi</string>
<string name="routing_attr_avoid_footways_name">Evita i marciapiedi</string>
<string name="development">Sviluppo</string>
<string name="use_live_public_transport">Dati OsmAnd Live</string>
<string name="use_live_routing">Dati OsmAnd Live</string>
<string name="complex_routing_descr">Calcolo del percorso in due fasi per la navigazione in auto.</string>
<string name="use_native_pt">Sviluppo Trasporto Pubblico nativo</string>
<string name="use_native_pt_desc">Cambia a Java (safe) calcolo del percorso su Trasporto Pubblico</string>
<string name="perform_oauth_authorization_description">Effettua una connessione OAuth per usare le funzionalità osmedit</string>
<string name="perform_oauth_authorization">Connettiti via OAuth</string>
<string name="clear_osm_token">Cancella il token OAuth OpenStreetMap</string>
<string name="osm_edit_logout_success">Disconnessione effettuata</string>
<string name="file_already_imported">Il file è già importato in OsmAnd</string>
<string name="use_two_phase_routing">Utilizza l\'algoritmo di calcolo a 2-fasi A*</string>
<string name="shared_string_graph">Grafico</string>
<string name="message_need_calculate_route_before_show_graph">%1$s dati disponibili solo per le strade, necessiti di calcolare un percorso utilizzando \"Percorso fra punti\" per ottenerlo.</string>
<string name="message_graph_will_be_available_after_recalculation">Attendi per il ricalcolo del percorso.
\nIl grafico sarà disponibile dopo il ricalcolo.</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
<string name="app_mode_gap">Buco</string>
</resources>

View file

@ -3938,4 +3938,5 @@
<string name="shared_string_graph">תרשים</string>
<string name="message_graph_will_be_available_after_recalculation">נא להמתין לחישוב המסלול מחדש.
\nהתרשים יהיה זמין לאחר החישוב מחדש.</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s ‏— %2$s</string>
</resources>

View file

@ -17,10 +17,10 @@
<string name="new_destination_point_dialog">Du har allerede angitt et reisemål:</string>
<string name="shared_string_target_points">Reisemål</string>
<string name="intermediate_point_too_far">Mellomliggende reisemål %1$s er for langt fra den nærmeste veien.</string>
<string name="arrived_at_intermediate_point">Ankommet mellomliggende reisemål</string>
<string name="arrived_at_intermediate_point">Mellomliggende reisemål er nådd</string>
<string name="context_menu_item_intermediate_point">Legg til som mellomliggende reisemål</string>
<string name="map_widget_intermediate_distance">Mellomliggende reisemål</string>
<string name="ending_point_too_far">Sluttpunkt for langt fra nærmeste vei.</string>
<string name="ending_point_too_far">Endepunkt for langt fra nærmeste vei.</string>
<string name="add_tag">Legg til merke</string>
<string name="btn_advanced_mode">Avansert modus…</string>
<string name="poi_filter_parking">Parkering</string>
@ -259,7 +259,7 @@
<string name="local_indexes_cat_poi">Interessepunkt-data</string>
<string name="ttsvoice">TTS-tale</string>
<string name="search_offline_clear_search">Nytt søk</string>
<string name="map_text_size_descr">Navnetekststørrelse på kartet:</string>
<string name="map_text_size_descr">Tekststørrelse for navn på kartet:</string>
<string name="map_text_size">Skriftstørrelse for kart</string>
<string name="internet_connection_required_for_online_route">Nettbasert navigering fungerer ikke frakoblet.</string>
<string name="tts_language_not_supported_title">Språk ikke støttet</string>
@ -406,7 +406,7 @@
<string name="route_general_information">Total distanse %1$s, reisetid %2$d t %3$d min.</string>
<string name="router_service_descr">Nettbasert eller frakoblet navigeringstjeneste.</string>
<string name="router_service">Navigeringstjeneste</string>
<string name="sd_dir_not_accessible">Datalagringsmappen på minnekortet er ikke tilgjengelig!</string>
<string name="sd_dir_not_accessible">Lagringsmappen på minnekortet er ikke tilgjengelig!</string>
<string name="download_question">Laste ned {0} - {1} \?</string>
<string name="download_question_exist">Nettfrakoblede data for {0} finnes allerede ({1}). Oppdater ({2})\?</string>
<string name="address">Adresse</string>
@ -456,7 +456,7 @@
<string name="search_button">Søk</string>
<string name="search_activity">Søk</string>
<string name="searchpoi_activity">Velg interessepunkt</string>
<string name="search_POI_level_btn">Finn mer</string>
<string name="search_POI_level_btn">Finn flere</string>
<string name="incremental_search_city">Søk etter by trinnvis</string>
<string name="incremental_search_street">Søk etter gate trinnvis</string>
<string name="incremental_search_building">Søk etter bygning trinnvis</string>
@ -472,8 +472,8 @@
<string name="navigate_point_top_text">Angi bredde- og lengdegrad i det valgte formatet (G - grader, M - minutter, S - sekunder)</string>
<string name="navigate_point_latitude">Breddegrad</string>
<string name="navigate_point_longitude">Lengdegrad</string>
<string name="navigate_point_format_D">DDD.DDDDD</string>
<string name="navigate_point_format_DM">DDD MM,MMM</string>
<string name="navigate_point_format_D">GGG.GGGGG</string>
<string name="navigate_point_format_DM">GGG MM,MMM</string>
<string name="navigate_point_format_DMS">GGG MM SS,S</string>
<string name="search_address_top_text">Adresse</string>
<string name="search_address_region">Region</string>
@ -522,7 +522,7 @@
<string name="choose_osmand_theme_descr">Tilpass programutseende.</string>
<string name="driving_region_us">USA</string>
<string name="driving_region_canada">Canada</string>
<string name="driving_region_europe_asia">Europa, Asia, Latin-Amerika &amp; lignende</string>
<string name="driving_region_europe_asia">Europa, Asia, Latin-Amerika og lignende</string>
<string name="driving_region_uk">Storbritannia, India og lignende</string>
<string name="driving_region_descr">Velg bilkjøringssted: USA, Europa, Storbritannia, Asia og andre.</string>
<string name="driving_region_japan">Japan</string>
@ -603,7 +603,7 @@
<string name="lang_lv">Latvisk</string>
<string name="lang_lt">Litauisk</string>
<string name="lang_mr">Marathi</string>
<string name="lang_no">Norsk Bokmål</string>
<string name="lang_no">Norsk bokmål</string>
<string name="lang_pl">Polsk</string>
<string name="lang_pt">Portugisisk</string>
<string name="lang_ro">Rumensk</string>
@ -637,7 +637,7 @@
<string name="rendering_attr_showCycleRoutes_name">Vis sykkelruter</string>
<string name="show_zoom_buttons_navigation_descr">Vis zoom-knapper under navigering.</string>
<string name="show_zoom_buttons_navigation">Vis zoom-knapper</string>
<string name="map_widget_plain_time">tid</string>
<string name="map_widget_plain_time">Gjeldende tid</string>
<string name="osmo_edit_color">Visningsfarge</string>
<string name="always_center_position_on_map">Sentrer posisjon på kart</string>
<string name="guidance_preferences_descr">Navigeringsinnstillinger</string>
@ -675,7 +675,7 @@
<string name="rendering_category_others">Andre kartattributter</string>
<string name="rendering_attr_publicTransportMode_name">Buss-, trolleybuss-, skyttelbussruter</string>
<string name="rendering_attr_tramTrainRoutes_name">Trikk- og togruter</string>
<string name="rendering_attr_subwayMode_name">Undergrunnsruter</string>
<string name="rendering_attr_subwayMode_name">T-bane-ruter</string>
<string name="rendering_attr_trainLightrailRoutes_name">Togruter</string>
<string name="rendering_attr_tramRoutes_name">Trikkeruter</string>
<string name="rendering_attr_trolleybusRoutes_name">Trolleybussruter</string>
@ -721,7 +721,7 @@
<string name="lang_al">Albansk</string>
<string name="lang_ar">Arabisk</string>
<string name="lang_fa">Persisk</string>
<string name="lang_sc">Sardinsk</string>
<string name="lang_sc">Sardisk</string>
<string name="route_descr_select_destination">Velg reisemål</string>
<string name="routing_attr_prefer_motorway_name">Foretrekk motorveier</string>
<string name="routing_attr_prefer_motorway_description">Foretrekk motorveier</string>
@ -1103,7 +1103,7 @@
<string name="mark_to_delete">Merk for å slette</string>
<string name="agps_info">A-GPS-info</string>
<string name="shared_string_message">Melding</string>
<string name="agps_data_last_downloaded">A-GPS-data sist nedlastet: %1$s</string>
<string name="agps_data_last_downloaded">A-GPS-data nedlastet: %1$s</string>
<string name="welcome_text">OsmAnd tilbyr global nettfrakoblet kartlesing og navigering.</string>
<string name="current_route">Gjeldende rute</string>
<string name="shared_string_go">Start</string>
@ -1257,7 +1257,7 @@
<string name="favorite_category_name">Kategorinavn</string>
<string name="favorite_category_add_new_title">Legg til ny kategori</string>
<string name="regions">Regioner</string>
<string name="region_maps">Regionkart</string>
<string name="region_maps">Regionale kart</string>
<string name="world_maps">Verdenskart</string>
<string name="hillshade_layer_disabled">Relieffskyggelag deaktivert</string>
<string name="share_menu_location">Del posisjon</string>
@ -1271,7 +1271,7 @@
<string name="update_all">Oppdater alle (%1$s MB)</string>
<string name="free_downloads_used">Gratis nedlastinger brukt</string>
<string name="application_dir_description">Velg hvor du vil lagre kart og andre datafiler.</string>
<string name="enter_country_name">Oppgi navn på land</string>
<string name="enter_country_name">Angi navn på land</string>
<string name="world_map_download_descr">Basiskart verden (som dekker hele verden ved lavt zoomnivå) mangler eller er utdatert. Vurder å laste det ned for en global oversikt.</string>
<string name="shared_string_qr_code">QR-kode</string>
<string name="basemap_was_selected_to_download">Basiskart velges for nedlasting slik at programmet fungerer.</string>
@ -1455,7 +1455,7 @@
<string name="poi_action_delete">slett</string>
<string name="poi_error_io_error_template">I/O-feil under utførelse av handlingen {0}.</string>
<string name="user_hates_app_get_feedback">Fortell oss hvorfor.</string>
<string name="failed_to_upload">Klarte ikke å laste opp</string>
<string name="failed_to_upload">Kunne ikke laste opp</string>
<string name="buy">Kjøp</string>
<string name="faq_item">Ofte stilte spørsmål</string>
<string name="number_of_edits">Antall redigeringer</string>
@ -1482,7 +1482,7 @@
<string name="use_osm_live_routing">OsmAnd Live-navigering</string>
<string name="access_no_destination">Reisemål er ikke angitt</string>
<string name="access_shared_string_navigate_up">Naviger opp</string>
<string name="open_street_map_login_and_pass">OpenStreetMap-brukernavn og passord</string>
<string name="open_street_map_login_and_pass">OSM-brukernavn og passord</string>
<string name="osm_live_subscription">OsmAnd Live-abonnement</string>
<string name="osm_live_hide_user_name">Ikke vis mitt navn i rapporter</string>
<string name="osm_live_ask_for_purchase">Kjøp først et OsmAnd Live-abonnement</string>
@ -1564,7 +1564,7 @@
<string name="current_track">Aktuelle spor</string>
<string name="show_current_gpx_title">Vis aktuelle spor</string>
<string name="rendering_attr_currentTrackWidth_description">GPX-bredde</string>
<string name="storage_place_description">OsmAnds datalagring (for kart, GPX-filer, osv.): %1$s.</string>
<string name="storage_place_description">OsmAnds datalagring (for kart, sporfiler, etc.): %1$s.</string>
<string name="first_usage_greeting">Få anvisninger og oppdag nye steder uten å ha internettforbindelse</string>
<string name="update_all_maps_now">Oppdater alle kart nå\?</string>
<string name="osm_live_payment_desc">Abonnementsavgift belastes månedsvis. Avbryt det på Google Play når som helst.</string>
@ -1694,7 +1694,7 @@
<string name="upload_osm_note_description">Last opp ditt OSM-notat anonymt eller ved å bruke din profil hos OpenStreetMap.org.</string>
<string name="gpx_no_tracks_title">Du har ingen GPX-filer enda</string>
<string name="gpx_no_tracks_title_folder">Du kan også legge til GPX-filer i mappen</string>
<string name="gpx_add_track">Legg til mer</string>
<string name="gpx_add_track">Legg til flere</string>
<string name="trip_rec_notification_settings">Skru på hurtigopptak</string>
<string name="trip_rec_notification_settings_desc">Vis et systemvarsel som kan starte turopptak.</string>
<string name="save_track_min_speed">Minimumshastighet for logging</string>
@ -1801,7 +1801,7 @@
<string name="osmo_connect_menu">Koble til</string>
<string name="routing_attr_avoid_stairs_name">Ingen trapper</string>
<string name="routing_attr_avoid_stairs_description">Unngår trapper</string>
<string name="speech_rate_descr">Angi talehastigheten for TTS.</string>
<string name="speech_rate_descr">Angi talehastigheten for tekst-til-tale.</string>
<string name="speech_rate">Talehastighet</string>
<string name="complex_route_calculation_failed">Rask ruteberegning mislyktes (%s), faller tilbake på treg beregning.</string>
<string name="disable_complex_routing_descr">Slå av to-fase ruteplanlegging for bilnavigering.</string>
@ -1856,7 +1856,7 @@
<string name="lang_new">Nepal bhasa</string>
<string name="lang_ceb">Cebuano</string>
<string name="lang_ast">Asturiansk</string>
<string name="lang_hsb">Øvervendisk</string>
<string name="lang_hsb">Oversorbisk</string>
<string name="lang_kab">Kabylsk</string>
<string name="lang_zh_hk">Kinesisk (Hongkong)</string>
<string name="use_displayed_track_for_navigation">Bruk vist spor for navigering\?</string>
@ -1932,7 +1932,7 @@
<string name="quick_action_map_overlay_action">Legg til overlegg</string>
<string name="quick_action_map_overlay_switch">Kartoverlegg er endret til \"%s\".</string>
<string name="points_delete_multiple_succesful">Punkt(er) slettet.</string>
<string name="points_delete_multiple">ER du sikker på at du vil slette %1$d punkt(er)\?</string>
<string name="points_delete_multiple">Er du sikker på at du vil slette %1$d punkt(er)\?</string>
<string name="average_speed">Gjennomsnittsfart</string>
<string name="select_gpx_folder">Velg mappe for GPX-fil</string>
<string name="osmand_extended_description_part1">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 @@
<string name="altitude_descent">Fall</string>
<string name="altitude_ascent">Stigning</string>
<string name="altitude_range">Høydeintervall</string>
<string name="average_altitude">Gjennomsnittlig høyde</string>
<string name="average_altitude">Gjennomsnittshøyde</string>
<string name="route_head">Følg</string>
<string name="shared_string_action_name">Handlingsnavn</string>
<string name="display_zoom_level">Visningszoomnivå: %1$s</string>
@ -2025,7 +2025,7 @@
<string name="routing_attr_height_obstacles_description">Ta hensyn til terrenghøyde (data fra SRTM, ASTER og EU-DEM).</string>
<string name="quick_action_bug_message">Melding</string>
<string name="shared_string_permissions">Tillatelser</string>
<string name="import_gpx_failed_descr">Kunne ikke importere filen. Kontroller at OsmAnd kan lese den.</string>
<string name="import_gpx_failed_descr">Kunne ikke importere filen. Kontroller at OsmAnd har tillatelse til å lese den.</string>
<string name="distance_moving">Korrigert avstand</string>
<string name="shared_string_reload">Last på nytt</string>
<string name="wrong_user_name">Feil brukernavn</string>
@ -2053,7 +2053,7 @@
<string name="quick_action_resume_pause_navigation">Navigering: sett på pause/gjenoppta</string>
<string name="quick_action_resume_pause_navigation_descr">Knapp for å ta en pause i eller gjenoppta navigeringen.</string>
<string name="right_side_navigation">Høyrekjøring</string>
<string name="quick_action_start_stop_navigation_descr">Trykk på denne knappen for å starte eller avslutte navigeringen.</string>
<string name="quick_action_start_stop_navigation_descr">Knapp for å starte eller avslutte navigering.</string>
<string name="store_tracks_in_monthly_directories">Lagre spor som er tatt opp i månedlige mapper</string>
<string name="store_tracks_in_monthly_directories_descrp">Lagre spor som er tatt opp, i undermapper per opptaksmåned (f.eks. 2018-01).</string>
<string name="mapillary_menu_descr_tile_cache">Last kartfliser på nytt for å se oppdaterte data.</string>
@ -2085,7 +2085,7 @@
<string name="mapillary_image">Mapillary-bilde</string>
<string name="open_mapillary">Åpne Mapillary</string>
<string name="shared_string_install">Installer</string>
<string name="improve_coverage_mapillary">Forbedre billeddekningen med Mapillary</string>
<string name="improve_coverage_mapillary">Forbedre bildedekningen med Mapillary</string>
<string name="online_photos">Nettbaserte bilder</string>
<string name="shared_string_add_photos">Legg til bilder</string>
<string name="no_photos_descr">Ingen bilder her.</string>
@ -2097,7 +2097,7 @@
<string name="nautical_maps">Sjøkart</string>
<string name="restore_purchases">Gjenopprett kjøp</string>
<string name="do_not_send_anonymous_app_usage">Ikke send anonym bruksstatistikk</string>
<string name="parking_options">Parkeringsalternativer</string>
<string name="parking_options">Parkeringsmuligheter</string>
<string name="full_version_thanks">Takk for at du kjøpte betalingsversjonen av OsmAnd.</string>
<string name="routing_attr_driving_style_speed_name">Kortere ruter</string>
<string name="routing_attr_driving_style_balance_name">Balansert</string>
@ -2137,7 +2137,7 @@
<string name="shared_string_list">Liste</string>
<string name="passed">Sist brukt: %1$s</string>
<string name="mapillary_menu_filter_description">Filtrer bilder etter innsender, dato eller type. Kun aktivt på nærgående forstørrelsesnivå.</string>
<string name="improve_coverage_install_mapillary_desc">Installer Mapillary for å legge til et eller flere bilder til denne kartposisjonen.</string>
<string name="improve_coverage_install_mapillary_desc">Installer Mapillary for å legge til bilder i denne kartposisjonen.</string>
<string name="plugin_mapillary_descr">Foto på gatenivå for alle. Oppdag plasser, samarbeid, fang inn verden.</string>
<string name="quick_action_showhide_osmbugs_title">Vis/skjul OSM-notater</string>
<string name="quick_action_osmbugs_show">Vis OSM-notater</string>
@ -2147,7 +2147,7 @@
<string name="index_item_depth_contours_osmand_ext">Havdybdekonturer</string>
<string name="download_depth_countours">Havdybdekonturer</string>
<string name="route_points_category_name">Svinger å passere langs ruten</string>
<string name="rendering_attr_depthContours_description">Vis havdybdekonturer og punkter.</string>
<string name="rendering_attr_depthContours_description">Vis dybdekonturer og punkter.</string>
<string name="rendering_attr_depthContours_name">Havdybdekonturer</string>
<string name="auto_split_recording_title">Del opp opptak automatisk etter avbrudd</string>
<string name="auto_split_recording_descr">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.</string>
@ -2156,7 +2156,7 @@
\n- Synkronisere grupper og enheter med tjeneren;
\n- Behandle grupper og enheter i et personlig dashbord på nettstedet.</string>
<string name="simulate_initial_startup">Simuler første programstart</string>
<string name="audionotes_plugin_description">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.</string>
<string name="audionotes_plugin_description">Lag audio/foto/video-notater på en tur, enten ved bruk av en knapp på kartet eller posisjon-kontekstmeny.</string>
<string name="average">Gjennomsnitt</string>
<string name="of">%1$d av %2$d</string>
<string name="ascent_descent">Stigning/fall</string>
@ -2177,7 +2177,7 @@
<string name="order_by">Sorter etter:</string>
<string name="map_orientation_change_in_accordance_with_speed">Kartorienteringsterskel</string>
<string name="map_orientation_change_in_accordance_with_speed_descr">Velg hastighet for skifte av kartorientering fra \'Bevegelsesretning\' til \'Kompassretning\' nedenfor.</string>
<string name="srtm_purchase_header">Kjøp og installer \"Koter\"-programtillegget for å vise loddrett skyggelegging.</string>
<string name="srtm_purchase_header">Kjøp og installer \"Koter\"-tillegget for å vise graderte vertikale områder.</string>
<string name="native_app_allocated_memory">Totalt innebygget minne</string>
<string name="starting_point_too_far">Startpunkt for langt fra nærmeste vei.</string>
<string name="shared_location">Delt posisjon</string>
@ -2213,7 +2213,7 @@
<string name="rendering_exception">Kunne ikke tegne valgt område.</string>
<string name="renderer_load_sucess">Kartgenerator lastet</string>
<string name="error_reading_gpx">Kunne ikke lese GPX-data.</string>
<string name="any_poi">Hvilke som helst</string>
<string name="any_poi">Alle</string>
<string name="thanks_yandex_traffic">Takk til Yandex for trafikkinfo.</string>
<string name="layer_yandex_traffic">Yandex-trafikk</string>
<string name="background_service_provider">Stedsbestemmelsestjeneste</string>
@ -2238,7 +2238,7 @@
<string name="use_fast_recalculation">Smart omberegning av rute</string>
<string name="rate_this_app">Vurder dette programmet</string>
<string name="rate_this_app_long">Gi OsmAnd en poengsum på Google Play</string>
<string name="user_hates_app_get_feedback_long">Fortell oss hva du ønsker å endre i dette programmet.</string>
<string name="user_hates_app_get_feedback_long">Gi oss beskjed om forslag.</string>
<string name="shared_string_card_was_hidden">Kortet ble skjult</string>
<string name="count_of_lines">Antall linjer</string>
<string name="poi_context_menu_modify_osm_change">Modifiser OSM-endring</string>
@ -2370,7 +2370,7 @@
<string name="poi_namefinder_query_empty">Skriv for å finne interessepunkt</string>
<string name="background_service_wait_int_descr">Setter høyeste tillatte ventetid for hver bakgrunns-posisjonsbestemmelse.</string>
<string name="background_service_wait_int">Maksimal ventetid for posisjonsbestemmelse</string>
<string name="background_service_int_descr">Vekkingsintervall brukt av bakgrunnstjeneste:</string>
<string name="background_service_int_descr">Vekkingsintervall brukt av bakgrunnstjenesten:</string>
<string name="background_service_provider_descr">Stedsbestemmelsesmetode brukt av bakgrunnstjeneste:</string>
<string name="transport_search_after">Etterfølgende rute</string>
<string name="transport_search_before">Tidligere rute</string>
@ -2437,8 +2437,8 @@
<string name="audionotes_location_not_defined">Sted å assosiere med notatet er ikke definert ennå. \"Bruk posisjon…\" for å tilordne et notat til det angitte stedet.</string>
<string name="add_waypoint_dialog_title">Legg til rutepunkt i innspilt GPX-spor</string>
<string name="voice_is_not_available_msg">Taleveiledning er ikke tilgjengelig, gå til \'Innstillinger\' → \'Navigeringsinnstillinger\' , velg profilen → \'Taleveiledning\' og velg eller last ned en talemeldingspakke.</string>
<string name="use_fast_recalculation_desc">For lange turer, beregn på nytt bare den første delen av ruten.</string>
<string name="nautical_renderer">Nautisk</string>
<string name="use_fast_recalculation_desc">Beregner på nytt bare den første delen av ruten. Kan brukes for lange turer.</string>
<string name="nautical_renderer">Maritimt</string>
<string name="day_off_label">stengt (fridag)</string>
<string name="copy_location_name">Kopier sted/interessepunkt-navn</string>
<string name="toast_empty_name_error">Sted uten navn</string>
@ -3679,7 +3679,7 @@
<string name="quick_action_remove_next_destination_descr">Nåværende målpunkt på ruten vil slettes. Hvis det er målet, vil navigasjonen stoppe.</string>
<string name="app_mode_wheelchair">Rullestol</string>
<string name="app_mode_go_cart">Gokart</string>
<string name="plan_a_route">Planlegg en rute</string>
<string name="plan_a_route">Ruteplanlegging</string>
<string name="additional_actions_descr">Du får tilgang til disse handlingene ved å trykke på knappen “%1$s”.</string>
<string name="use_volume_buttons_as_zoom_descr">Styr zoomnivået på kartet med enhetens volumknapper.</string>
<string name="add_hidden_group_info">Det tillagte punktet vil ikke være synlig på kartet, siden den valgte gruppen er skjult, du kan finne det i \"%s\".</string>
@ -3823,7 +3823,7 @@
<string name="simplified_track_description">Kun rutelinjen vil lagres, rutepunktene vil slettes.</string>
<string name="context_menu_item_add_waypoint">Legg til spor-rutepunkt</string>
<string name="quick_action_add_gpx">Legg til spor-rutepunkt</string>
<string name="complex_routing_descr">To-delt ruting for bilkjøring.</string>
<string name="complex_routing_descr">To-fase-ruting for bilnavigering.</string>
<string name="osm_live_payment_desc_hw">Abonnement påløper per valgte periode. Avbryt det når som helst fra programgalleriet.</string>
<string name="attach_to_the_roads">Følg veier</string>
<string name="monitoring_min_distance">Minimumsforskyvning</string>
@ -3868,4 +3868,8 @@
<string name="osm_edit_logout_success">Utlogget</string>
<string name="use_two_phase_routing">Bruk 2-stegs A*-rutingsalgoritme</string>
<string name="file_already_imported">Filen er allerede importert i OsmAnd</string>
<string name="message_graph_will_be_available_after_recalculation">Vent på omberegning av ruten.
\nGraf vil være tilgjengelig etter omberegning.</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
<string name="shared_string_graph">Graf</string>
</resources>

View file

@ -30,7 +30,7 @@
<string name="back_to_location">Terug naar locatie</string>
<string name="accessibility_mode">Toegankelijkheidsmodus</string>
<string name="accessibility_mode_descr">Zet toegankelijkheidsmodus aan.</string>
<string name="accessibility_default">Gelijk aan systeeminstelling</string>
<string name="accessibility_default">Gelijk aan de Android systeeminstelling</string>
<string name="backToMenu">Terug naar menu</string>
<string name="zoomOut">Zoom uit</string>
<string name="zoomIn">Zoom in</string>
@ -251,8 +251,8 @@
<string name="error_doing_search">Fout bij offline zoeken.</string>
<string name="search_osm_offline">Zoek adres in de offline kaarten</string>
<string name="system_locale">Systeem</string>
<string name="preferred_locale_descr">App menu-taal (OsmAnd dient opnieuw gestart).</string>
<string name="preferred_locale">Taal</string>
<string name="preferred_locale_descr">App toon talen (OsmAnd dient opnieuw gestart).</string>
<string name="preferred_locale">Toon talen</string>
<string name="unit_of_length_descr">Wijzig de eenheid van afstand voor metingen.</string>
<string name="unit_of_length">Afstand eenheden</string>
<string name="si_mi_feet">Mijlen/voeten</string>
@ -824,7 +824,7 @@
<string name="intermediate_point">Tussenpunt %1$s</string>
<string name="gps_not_available">Schakel GPS in via de instellingen</string>
<string name="map_widget_show_destination_arrow">Richting van de bestemming tonen</string>
<string name="enable_plugin_monitoring_services">Activeer de GPX-Track opnemen- Plugin om de afgelegde weg vast te leggen (GPX-track, online tracking)</string>
<string name="enable_plugin_monitoring_services">Activeer de \"GPX-Track opnemen\" Plug-in om de afgelegde weg vast te leggen (GPX-track, online tracking)</string>
<string name="non_optimal_route_calculation">Bereken mogelijk niet-optimale route voor lange afstanden</string>
<string name="rendering_attr_roadColors_description">Kies kleurschema voor wegen:</string>
<string name="rendering_attr_roadColors_name">Kleurschema voor wegen</string>
@ -921,7 +921,7 @@
<string name="osmand_play_title_30_chars">OsmAnd Kaarten &amp; Navigatie</string>
<string name="osmand_plus_play_title_30_chars">OsmAnd+ Kaarten &amp; Navigatie</string>
<string name="hno">Huisnummer</string>
<string name="monitoring_settings">GPX-track</string>
<string name="monitoring_settings">Track opnemen</string>
<string name="monitoring_settings_descr">Stel in hoe uw trips op te nemen.</string>
<string name="street_name">Straatnaam</string>
<string name="choose_osmand_theme_descr">Aanpassen van app uitzicht aan uw wensen.</string>
@ -952,8 +952,8 @@
<string name="plugin_distance_point">Punt</string>
<string name="gpx_file_name">GPX-bestandsnaam</string>
<string name="gpx_saved_sucessfully">GPX-bestand succesvol opgeslagen als {0}</string>
<string name="osmand_distance_planning_plugin_description">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.</string>
<string name="osmand_distance_planning_plugin_name">Afstand meten en Route plannen</string>
<string name="osmand_distance_planning_plugin_description">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.</string>
<string name="osmand_distance_planning_plugin_name">Afstandscalculator en planningstool</string>
<string name="use_distance_measurement_help">* 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 @@
<string name="speak_poi">Dichtbij POI</string>
<string name="shared_string_all">Alles</string>
<string name="index_tours">Reizen</string>
<string name="record_plugin_name">GPX-track opnemen</string>
<string name="record_plugin_name">Track opnemen</string>
<string name="int_hour">u.</string>
<string name="duration">Duur</string>
<string name="distance">Afstand</string>
@ -1462,7 +1462,7 @@
<string name="shared_string_audio">Geluid</string>
<string name="shared_string_video">Video</string>
<string name="shared_string_photo">Foto</string>
<string name="delay_to_start_navigation_descr">Kies de wachttijd in om op het route-planning scherm te blijven.</string>
<string name="delay_to_start_navigation_descr">Geef de wachttijd op om op het route-planning scherm te blijven.</string>
<string name="delay_to_start_navigation">Start begeleiding na…</string>
<string name="shared_string_go">Start</string>
<string name="action_create">Actietoets aanmaken</string>
@ -1639,7 +1639,7 @@
<string name="min_mile">min/m</string>
<string name="min_km">min/km</string>
<string name="m_s">m/s</string>
<string name="shared_string_trip_recording">GPX-Track opnemen</string>
<string name="shared_string_trip_recording">Track opnemen</string>
<string name="shared_string_navigation">Navigatie</string>
<string name="favourites_edit_dialog_title">Informatie over favoriet</string>
<string name="simulate_your_location_stop_descr">Positiesimulatie beëindigen.</string>
@ -2058,7 +2058,7 @@
<string name="gpx_add_track">Meer toevoegen…</string>
<string name="shared_string_appearance">Weergave</string>
<string name="trip_rec_notification_settings">Snelle opname activeren</string>
<string name="trip_rec_notification_settings_desc">Toon systeemmelding waarmee ritopname toegestaan wordt.</string>
<string name="trip_rec_notification_settings_desc">Toon systeemmelding waarmee track opname toegestaan wordt.</string>
<string name="shared_string_notifications">Meldingen</string>
<string name="route_calculation">Route berekening</string>
<string name="rendering_value_fine_name">Fijn</string>
@ -2359,10 +2359,10 @@
<string name="shared_string_install">Installeer</string>
<string name="improve_coverage_mapillary">Verbeter de fotocollectie van Mapillary</string>
<string name="improve_coverage_install_mapillary_desc">Installeer Mapillary om foto\'s aan deze kaartlocatie toe te voegen.</string>
<string name="mapillary_action_descr">Deel uw straatniveau uitzicht via Mapillary.</string>
<string name="mapillary_action_descr">Deel uw weergave op straatniveau via Mapillary.</string>
<string name="mapillary_widget_descr">Snel bijdragen aan Mapillary.</string>
<string name="mapillary_descr">Foto\'s van buiten voor iedereen. Ondek plaatsen, werk samen, en leg de wereld vast.</string>
<string name="plugin_mapillary_descr">Foto\'s van buiten voor iedereen. Ondek plaatsen, werk samen, en leg de wereld vast.</string>
<string name="mapillary_descr">Online foto\'s op straatniveau voor iedereen. Ontdek plaatsen, werk samen, leg de wereld vast.</string>
<string name="plugin_mapillary_descr">Foto\'s op straatniveau voor iedereen. Ontdek plaatsen, werk samen, leg de wereld vast.</string>
<string name="shared_string_permissions">Rechten</string>
<string name="import_gpx_failed_descr">Kan bestand niet importeren. Controleer of OsmAnd rechten heeft om het bestand te lezen.</string>
<string name="distance_moving">Gecorrigeerde afstand</string>
@ -3297,7 +3297,7 @@
<string name="added_profiles_descr">Door plug-in toegevoegde profielen</string>
<string name="shared_string_turn_off">Uitschakelen</string>
<string name="new_plugin_added">Nieuwe plug-in toegevoegd</string>
<string name="join_segments">verbind segmenten</string>
<string name="join_segments">Segmenten samenvoegen</string>
<string name="release_3_4">• 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 @@
<string name="multimedia_notes_prefs_descr">Afbeeldingsgrootte, geluids- en videokwaliteit</string>
<string name="osm_editing_prefs_descr">Login, wachtwoord, offline bewerken</string>
<string name="accessibility_prefs_descr">Kies icoon, kleur en naam</string>
<string name="live_monitoring_descr">Laat u toe uw positie te delen dankzij reisopname.</string>
<string name="live_monitoring_descr">Laat u toe uw positie te delen dankzij track opname.</string>
<string name="live_monitoring">Online volgen</string>
<string name="save_track_logging_accuracy">Opnamenauwkeurigheid</string>
<string name="tracks_view_descr">De opgenomen tracks zijn opgeslagen in %1$s, of in de OsmAnd-map.</string>
@ -3530,7 +3530,7 @@
<string name="shared_string_terrain">Terrein</string>
<string name="slope_description">Helling gebruikt kleuren om de steilheid van het terrein te visualiseren.</string>
<string name="terrain_slider_description">Stel de minimale en maximale zoomniveaus in waarbij de laag wordt weergegeven.</string>
<string name="slope_download_description">Om Hellingen te tonen zijn extra kaarten nodig.</string>
<string name="slope_download_description">Om hellingen te tonen zijn extra kaarten nodig.</string>
<string name="slope_read_more">Meer over Hellingen in %1$s.</string>
<string name="shared_string_transparency">Transparantie</string>
<string name="shared_string_zoom_levels">Zoomniveaus</string>
@ -3666,7 +3666,7 @@
<string name="shared_string_legal">Legaal</string>
<string name="speed_camera_pois">Snelheidscameras als POIs</string>
<string name="hillshade_description">De reliëfschaduwkaart maakt gebruik van donkere schaduwen om hellingen, bergtoppen en valleien te visualiseren.</string>
<string name="hillshade_download_description">Om Reliëfschaduw te tonen zijn extra kaarten nodig.</string>
<string name="hillshade_download_description">Om reliëfschaduw te tonen zijn extra kaarten nodig.</string>
<string name="shared_string_hillshade">Reliëfschaduw</string>
<string name="terrain_empty_state_text">Selecteer deze optie om een reliëfschaduw- of hellingskaart te tonen. Op onze site staat meer informatie over deze kaarttypes.</string>
<string name="map_source_zoom_levels_descr">Heeft invloed op de weergave bij gebruik als kaart of als extra kaartlaag/achtergrondlaag.
@ -3696,4 +3696,79 @@
<string name="app_mode_wheelchair_forward">Rolstoel vooraanzicht</string>
<string name="osm_edit_closed_note">Opgeloste OSM-opmerking</string>
<string name="app_mode_go_cart">Kart</string>
<string name="map_widget_monitoring">Track opnemen</string>
<string name="save_global_track_interval_descr">Specificeer het registratie-interval voor de algemene trackregistratie (ingeschakeld via de track-widget op de kaart).</string>
<string name="gpx_monitoring_stop">Pauzeer track opname</string>
<string name="gpx_monitoring_start">Hervat track opnemen</string>
<string name="street_level_imagery">Beelden op srraatniveau</string>
<string name="select_track_width">Selecteer dikte</string>
<string name="track_show_start_finish_icons">Toon start en aankomst pictogrammen</string>
<string name="gpx_direction_arrows">Richtingaanwijzers</string>
<string name="add_hidden_group_info">Het toegevoegde punt zal niet zichtbaar zijn op de kaart, aangezien de geselecteerde groep verborgen is, je kan het vinden in \"%s\".</string>
<string name="system_default_theme">Standaard</string>
<string name="route_between_points">Route tussen punten</string>
<string name="route_between_points_warning_desc">"Vervolgens, zet uw track vast op de dichtstbijzijnde toegestane weg met een van uw navigatieprofielen om deze optie te gebruiken."</string>
<string name="message_need_calculate_route_before_show_graph">%1$s gegevens alleen beschikbaar op de wegen, u moet een route berekenen met behulp van \"Route tussen punten\" om deze te krijgen.</string>
<string name="route_between_points_desc">Selecteer hoe de punten verbonden worden, via een rechte lijn, of een route berekenen tussen de punten zoals hieronder aangegeven.</string>
<string name="route_between_points_next_segment_button_desc">Alleen het volgende segment wordt opnieuw berekend met het geselecteerde profiel.</string>
<string name="next_segment">Volgende segment</string>
<string name="all_next_segments">Alle volgende segmenten</string>
<string name="all_next_segments_will_be_recalc">Alle volgende segmenten worden opnieuw berekend met het geselecteerde profiel.</string>
<string name="whole_track">De ganse track</string>
<string name="route_between_points_whole_track_button_desc">De ganse track wordt herberekend volgens het geselecteerde profiel.</string>
<string name="pass_whole_track_descr">Punt van de track om te navigeren</string>
<string name="shared_string_save_as_gpx">Bewaar als nieuw trackbestand</string>
<string name="save_as_new_track">Bewaar als nieuwe track</string>
<string name="release_3_7">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</string>
<string name="add_to_a_track">Voeg toe aan een track</string>
<string name="add_segment_to_the_track">Voeg toe aan een trackbestand</string>
<string name="simplified_track">Vereenvoudigde track</string>
<string name="simplified_track_description">Alleen de routelijn wordt opgeslagen, de waypoints worden verwijderd.</string>
<string name="shared_string_done">Bewaar</string>
<string name="reverse_route">Route omkeren</string>
<string name="route_between_points_add_track_desc">"Selecteer een track waaraan je een nieuw segment wil toevoegen."</string>
<string name="plan_route_select_track_file_for_open">Selecteer een trackbestand om te openen.</string>
<string name="plan_route_exit_dialog_descr">Weet u zeker dat u alle wijzigingen in de geplande route wilt annuleren door deze te sluiten\?</string>
<string name="plan_route_trim_before">Opsmukken voor</string>
<string name="plan_route_trim_after">Opsmukken na</string>
<string name="plan_route_change_route_type_before">Wijzig het routetype voor</string>
<string name="plan_route_change_route_type_after">Wijzig het routetype na</string>
<string name="release_3_8">• 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</string>
<string name="plan_route_import_track">Importeer track</string>
<string name="plan_route_last_edited">Laatst bewerkt</string>
<string name="plan_route_create_new_route">Maak een nieuwe route</string>
<string name="plan_route_open_existing_track">Open een bestaande track</string>
<string name="plan_a_route">Plan een route</string>
</resources>

View file

@ -3265,7 +3265,7 @@
<string name="language_and_output">Język i wyjście</string>
<string name="plugins_settings">Ustawienia wtyczki</string>
<string name="shared_string_by_default">Domyślnie</string>
<string name="download_detailed_map">Pobierz szczegółową mapę %S, aby zobaczyć ten obszar.</string>
<string name="download_detailed_map">Pobierz szczegółową mapę %s, aby zobaczyć ten obszar.</string>
<string name="change_data_storage_full_description">Przenieść pliki danych OsmAnd do nowego położenia\?
\n%1$s &gt; %2$s</string>
<string name="enter_path_to_folder">Proszę wprowadzić ścieżkę do katalogu</string>
@ -3769,11 +3769,11 @@
<string name="uninstall_speed_cameras">Odinstaluj fotoradary</string>
<string name="shared_string_legal">Prawny</string>
<string name="speed_camera_pois">Punkty fotoradarów</string>
<string name="speed_cameras_legal_descr">W niektórych krajachi regionach uzywanie aplikacji ostrzegających o fotoradarach jest zabronione przez prawo.
<string name="speed_cameras_legal_descr">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.
\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.</string>
<string name="keep_active">Nie wyłączaj</string>
@ -3814,7 +3814,7 @@
<string name="gpx_split_interval_none_descr">Wybierz żądaną opcję podziału: według czasu lub odległości.</string>
<string name="track_coloring_solid">Stałe</string>
<string name="gpx_parse_error">OsmAnd GPX nie jest dobrze uformowany, prosimy o kontakt z zespołem wsparcia technicznego w celu dalszego zbadania sprawy.</string>
<string name="turn_screen_on_wake_time_descr">Wybierz limit czasu ekranu po przebudzeniu. (\"%1$s\" nie powoduje przekroczenia limitu czasu).</string>
<string name="turn_screen_on_wake_time_descr">Wybierz limit czasu ekranu po przebudzeniu. (\"%1$s\" nie powoduje przekroczenia limitu czasu.)</string>
<string name="track_show_start_finish_icons">Pokaż ikony początku i końca</string>
<string name="gpx_split_interval_descr">Wybierz przedział czasowy, w którym będą wyświetlane znaki z odległością lub czasem na torze.</string>
<string name="shared_string_custom">Dostosowany</string>
@ -3891,7 +3891,7 @@
<string name="open_saved_track">Otwórz zapisaną ścieżkę</string>
<string name="shared_string_is_saved">jest zapisywany</string>
<string name="one_point_error">Należy dodać co najmniej dwa punkty.</string>
<string name="disable_recording_once_app_killed_descrp">Wstrzyma rejestrowanie ścieżki, gdy aplikacja zostanie zabita (za pośrednictwem ostatnich aplikacji). (Wskazanie tła OsmAnd znika z paska powiadomień Androida).</string>
<string name="disable_recording_once_app_killed_descrp">Wstrzyma rejestrowanie ścieżki, gdy aplikacja zostanie zabita (za pośrednictwem ostatnich aplikacji). (Wskazanie tła OsmAnd znika z paska powiadomień Androida.)</string>
<string name="shared_string_redo">Ponów</string>
<string name="release_3_8">• 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 @@
<string name="perform_oauth_authorization">Zaloguj się przez OAuth</string>
<string name="clear_osm_token">Wyczyść token OpenStreetMap OAuth</string>
<string name="osm_edit_logout_success">Wylogowanie powiodło się</string>
<string name="file_already_imported">Plik jest już zaimportowany do OsmAnd</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
</resources>

View file

@ -3800,7 +3800,7 @@
<string name="poi_booth">Tipo de cabine</string>
<string name="poi_video_yes">Sim</string>
<string name="poi_video_no">Não</string>
<string name="poi_internet_access_fee_customers">Sinal para encontrar o poste</string>
<string name="poi_internet_access_fee_customers">Acesso à Internet: clientes</string>
<string name="poi_traffic_signals_sound_locate">Somente quando andar é permitido</string>
<string name="poi_tactile_paving_contrasted">Contrastado</string>
<string name="poi_tactile_paving_primitive">Primitivo</string>
@ -3845,4 +3845,6 @@
<string name="poi_beehive">Colmeia</string>
<string name="poi_nuts">Loja de nozes</string>
<string name="poi_fuel_lng">GNL</string>
<string name="poi_parking_sheds">Galpões</string>
<string name="poi_gpx_point">Ponto GPX</string>
</resources>

View file

@ -3928,4 +3928,5 @@
<string name="message_need_calculate_route_before_show_graph">Dados de %1$s disponíveis apenas nas estradas, você precisa calcular uma rota usando “Rota entre pontos” para obtê-la.</string>
<string name="message_graph_will_be_available_after_recalculation">Aguarde o recálculo da rota.
\nO gráfico estará disponível após o recálculo.</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
</resources>

View file

@ -3935,4 +3935,6 @@
<string name="message_need_calculate_route_before_show_graph">%1$s dados disponíveis apenas nas estradas, precisa calcular uma rota a usar \"Rota entre pontos\" para obtê-la.</string>
<string name="message_graph_will_be_available_after_recalculation">Espere pelo recalculo da rota.
\nO gráfico estará disponível após o recalculo.</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
<string name="app_mode_gap">Lacuna</string>
</resources>

View file

@ -1974,7 +1974,7 @@
<string name="downloads">Загрузки</string>
<string name="show_free_version_banner">Показывать баннер бесплатной версии</string>
<string name="show_free_version_banner_description">Показывать баннер бесплатной версии даже в платной версии.</string>
<string name="confirm_download_roadmaps">В карте дорог не необходимости, так как у вас уже есть стандартная (полная) карта. Загрузить в любом случае?</string>
<string name="confirm_download_roadmaps">В карте дорог нет необходимости, так как у вас уже есть стандартная (полная) карта. Загрузить в любом случае?</string>
<string name="value_downloaded_of_max">%1$.1f из %2$.1f МБ</string>
<string name="file_size_in_mb">%.1f МБ</string>
<string name="update_all">Обновить все (%1$s МБ)</string>

View file

@ -3796,7 +3796,7 @@
<string name="poi_booth">Casta de cabina</string>
<string name="poi_video_yes">Eja</string>
<string name="poi_video_no">Nono</string>
<string name="poi_internet_access_fee_customers">Sinnale pro agatare su palu</string>
<string name="poi_internet_access_fee_customers">Atzessu a ìnternet: clientes</string>
<string name="poi_traffic_signals_sound_locate">Petzi cando si podet camminare</string>
<string name="poi_tactile_paving_contrasted">Cuntrastadu</string>
<string name="poi_tactile_paving_primitive">Primitivu</string>
@ -3841,4 +3841,8 @@
<string name="poi_departures_board">Tabellone de sas tzucadas</string>
<string name="poi_drinking_water_refill">Ricàrriga de abba potàbile</string>
<string name="poi_fuel_lng">GNL (LNG)</string>
<string name="poi_parking_layby">Ispiatzu (layby)</string>
<string name="poi_parking_sheds">Cabannas</string>
<string name="poi_parking_rooftop">Cobertura</string>
<string name="poi_gpx_point">Puntu GPX</string>
</resources>

View file

@ -3931,4 +3931,5 @@
<string name="shared_string_graph">Gràficu</string>
<string name="message_graph_will_be_available_after_recalculation">Iseta su càrculu nou de s\'àndala.
\nSu gràficu at a èssere a disponimentu a pustis de su càrculu.</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
</resources>

View file

@ -3933,4 +3933,6 @@
<string name="message_need_calculate_route_before_show_graph">Údaje %1$s sú dostupné len na cestách, pre ich získanie musíte vypočítať trasu pomocou “Trasa medzi bodmi”.</string>
<string name="message_graph_will_be_available_after_recalculation">Počkajte na prepočet trasy.
\nGraf bude dostupný po prepočte.</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
<string name="app_mode_gap">Medzera</string>
</resources>

View file

@ -3788,7 +3788,7 @@
<string name="poi_booth">Вид стенда</string>
<string name="poi_video_yes">Так</string>
<string name="poi_video_no">Ні</string>
<string name="poi_internet_access_fee_customers">Сигнал, щоб знайти полюс</string>
<string name="poi_internet_access_fee_customers">Доступ до Інтернету: клієнти</string>
<string name="poi_traffic_signals_sound_locate">Допускається лише при ходінні</string>
<string name="poi_tactile_paving_contrasted">Контрастний</string>
<string name="poi_tactile_paving_primitive">Примітивний</string>
@ -3833,4 +3833,8 @@
<string name="poi_beehive">Вулик</string>
<string name="poi_nuts">Насіннєвий магазин</string>
<string name="poi_fuel_lng">СПГ</string>
<string name="poi_parking_layby">Придорожня стоянка</string>
<string name="poi_parking_sheds">Навіси</string>
<string name="poi_parking_rooftop">Дах</string>
<string name="poi_gpx_point">Точка GPX</string>
</resources>

View file

@ -3929,4 +3929,6 @@
<string name="message_need_calculate_route_before_show_graph">%1$s дані доступні лише для доріг, вам потрібно обчислити маршрут за допомогою «Маршрут між точками», щоб отримати його.</string>
<string name="message_graph_will_be_available_after_recalculation">Дочекайтеся переобчислення маршруту.
\nГрафік буде доступний після переобчислення.</string>
<string name="app_mode_gap">Розрив</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
</resources>

View file

@ -3799,7 +3799,7 @@
<string name="poi_booth">亭類型</string>
<string name="poi_video_yes"></string>
<string name="poi_video_no"></string>
<string name="poi_internet_access_fee_customers">找到極點的訊號</string>
<string name="poi_internet_access_fee_customers">網際網路存取:顧客</string>
<string name="poi_traffic_signals_sound_locate">僅在步行時允許</string>
<string name="poi_tactile_paving_contrasted">對比</string>
<string name="poi_tactile_paving_primitive">粗糙</string>
@ -3844,4 +3844,8 @@
<string name="poi_beehive">蜂箱</string>
<string name="poi_nuts">堅果店</string>
<string name="poi_fuel_lng">LNG</string>
<string name="poi_parking_layby">停車區</string>
<string name="poi_parking_sheds">車棚</string>
<string name="poi_parking_rooftop">屋頂</string>
<string name="poi_gpx_point">GPX 點</string>
</resources>

View file

@ -3928,4 +3928,6 @@
<string name="message_need_calculate_route_before_show_graph">%1$s 資料僅供道路使用,您需要使用「兩點間的路線」來計算路線。</string>
<string name="message_graph_will_be_available_after_recalculation">等待路線重新計算。
\n重新計算後即可使用圖表。</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
<string name="app_mode_gap">分隔</string>
</resources>

View file

@ -11,6 +11,16 @@
Thx - Hardy
-->
<string name="icon_group_travel">Travel</string>
<string name="icon_group_emergency">Emergency</string>
<string name="icon_group_sport">Sport</string>
<string name="icon_group_symbols">Symbols</string>
<string name="icon_group_service">Service</string>
<string name="icon_group_transport">Transport</string>
<string name="icon_group_special">Special</string>
<string name="icon_group_amenity">Amenity</string>
<string name="app_mode_gap">Gap</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
<string name="shared_string_local_maps">Local maps</string>
<string name="message_graph_will_be_available_after_recalculation">Wait for the route recalculation.\nGraph will be available after recalculation.</string>
<string name="message_need_calculate_route_before_show_graph">%1$s data available only on the roads, you need to calculate a route using “Route between points” to get it.</string>
@ -104,7 +114,7 @@
<string name="route_between_points_warning_desc">Next, snap your track to the nearest allowed road with one of your navigation profiles to use this option.</string>
<string name="next_segment">Next segment</string>
<string name="whole_track">Whole track</string>
<string name="route_between_points_desc">Select how to connect points, by a straight line, or calculate a route between them as specified below.</string>
<string name="route_between_points_desc">Choose how to connect the points, by a straight line, or calculate a route between them as specified below.</string>
<string name="route_between_points_next_segment_button_desc">Only the next segment will be recalculated using the selected profile.</string>
<string name="route_between_points_whole_track_button_desc">The whole track will be recalculated using the selected profile.</string>
<string name="reverse_route">Reverse route</string>

View file

@ -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" />
<Preference

View file

@ -428,7 +428,7 @@ public class FavouritesDbHelper {
while (fl) {
fl = false;
for (FavouritePoint fp : fdb.getFavouritePoints()) {
if (fp.getName().equals(name) && p.getLatitude() != fp.getLatitude() && p.getLongitude() != fp.getLongitude()) {
if (fp.getName().equals(name) && p.getLatitude() != fp.getLatitude() && p.getLongitude() != fp.getLongitude() && fp.getCategory().equals(p.getCategory())) {
number++;
index = " (" + number + ")";
name = p.getName() + index;

View file

@ -114,6 +114,19 @@ public abstract class SettingsBaseActivity extends ActionBarPreferenceActivity
return p;
}
public static String getIconStringPropertyName(Context ctx, String propertyName, String defValue) {
try {
Field f = R.string.class.getField("icon_group_" + propertyName);
if (f != null) {
Integer in = (Integer) f.get(null);
return ctx.getString(in);
}
} catch (Exception e) {
System.err.println(e.getMessage());
}
return defValue;
}
public static String getRoutingStringPropertyName(Context ctx, String propertyName, String defValue) {
try {
Field f = R.string.class.getField("routing_attr_" + propertyName + "_name");

View file

@ -21,7 +21,6 @@ import com.google.android.material.bottomnavigation.BottomNavigationView;
import net.osmand.AndroidUtils;
import net.osmand.GPXUtilities;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.TrkSegment;
import net.osmand.GPXUtilities.WptPt;
import net.osmand.IndexConstants;
import net.osmand.data.LatLon;
@ -32,9 +31,7 @@ import net.osmand.plus.GpxSelectionHelper;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayGroup;
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
import net.osmand.plus.LockableViewPager;
import net.osmand.plus.settings.backend.OsmAndAppCustomization;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.mapmarkers.CoordinateInputDialogFragment;
import net.osmand.plus.measurementtool.GpxData;
@ -44,6 +41,8 @@ import net.osmand.plus.myplaces.TrackBitmapDrawer;
import net.osmand.plus.myplaces.TrackBitmapDrawer.TrackBitmapDrawerListener;
import net.osmand.plus.myplaces.TrackPointFragment;
import net.osmand.plus.myplaces.TrackSegmentFragment;
import net.osmand.plus.settings.backend.OsmAndAppCustomization;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.views.AddGpxPointBottomSheetHelper.NewGpxPoint;
import java.io.File;
@ -136,14 +135,9 @@ public class TrackActivity extends TabActivity {
}
}
public void addNewGpxData(GpxData.ActionType actionType) {
addNewGpxData(actionType, null);
}
public void addNewGpxData(GpxData.ActionType actionType, TrkSegment segment) {
public void addNewGpxData() {
GPXFile gpxFile = getGpx();
QuadRect rect = getRect();
GpxData gpxData = new GpxData(gpxFile, rect, actionType, segment);
GpxData gpxData = new GpxData(gpxFile);
WptPt pointToShow = gpxFile != null ? gpxFile.findPointToShow() : null;
if (pointToShow != null) {
LatLon location = new LatLon(pointToShow.getLatitude(), pointToShow.getLongitude());
@ -154,7 +148,6 @@ public class TrackActivity extends TabActivity {
false,
gpxData
);
MapActivity.launchMapActivityMoveToTop(this);
}
}

View file

@ -423,7 +423,7 @@ public abstract class MenuBottomSheetDialogFragment extends BottomSheetDialogFra
private LayerDrawable createBackgroundDrawable(@NonNull Context ctx, @DrawableRes int shadowDrawableResId) {
Drawable shadowDrawable = ContextCompat.getDrawable(ctx, shadowDrawableResId);
Drawable[] layers = new Drawable[] {shadowDrawable, getColoredBg(ctx)};
Drawable[] layers = new Drawable[]{shadowDrawable, getColoredBg(ctx)};
return new LayerDrawable(layers);
}
@ -434,6 +434,21 @@ public abstract class MenuBottomSheetDialogFragment extends BottomSheetDialogFra
return !app.getSettings().isLightContent();
}
private void showShadowButton() {
buttonsShadow.setVisibility(View.VISIBLE);
buttonsShadow.animate()
.alpha(0.8f)
.setDuration(200)
.setListener(null);
}
private void hideShadowButton() {
buttonsShadow.animate()
.alpha(0f)
.setDuration(200);
}
private void setupScrollShadow(View view) {
final View scrollView;
if (useScrollableItemsContainer()) {
@ -446,7 +461,11 @@ public abstract class MenuBottomSheetDialogFragment extends BottomSheetDialogFra
@Override
public void onScrollChanged() {
boolean scrollToBottomAvailable = scrollView.canScrollVertically(1);
AndroidUiHelper.updateVisibility(buttonsShadow, scrollToBottomAvailable);
if (scrollToBottomAvailable) {
showShadowButton();
} else {
hideShadowButton();
}
}
});
}

View file

@ -670,7 +670,10 @@ public class ImportHelper {
}
fp.setAddress(p.getExtensionsToRead().get("address"));
fp.setColor(p.getColor(0));
fp.setIconIdFromName(app, p.getIconName());
String iconName = p.getIconName();
if (iconName != null) {
fp.setIconIdFromName(app, iconName);
}
fp.setBackgroundType(BackgroundType.getByTypeName(p.getBackgroundType(), DEFAULT_BACKGROUND_TYPE));
favourites.add(fp);
}

View file

@ -47,6 +47,7 @@ import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.activities.SettingsBaseActivity;
import net.osmand.plus.base.BaseOsmAndFragment;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.helpers.ColorDialogs;
@ -567,23 +568,6 @@ public abstract class PointEditorFragmentNew extends BaseOsmAndFragment {
: R.color.inactive_buttons_and_links_bg_light)));
}
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());
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();

View file

@ -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<LocationsHolder> locationsHolders;
private final Map<LocationsHolder, GpxRouteApproximation> 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);
}
}
if (gpxApproximator != null) {
gpxApproximator.setApproximationProgress(new GpxApproximator.GpxApproximationProgressCallback() {
approximationProgress = new GpxApproximationProgressCallback() {
@Override
public void start() {
if (isResumed()) {
startProgress();
public void start(GpxApproximator approximator) {
}
@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();
}
}
});
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<List<WptPt>> pointsList, @Nullable ApplicationMode appMode) {
try {
if (!fm.isStateSaved()) {
GpxApproximationFragment fragment = new GpxApproximationFragment();
fragment.setRetainInstance(true);
fragment.setTargetFragment(targetFragment, REQUEST_CODE);
fragment.setLocationsHolder(locationsHolder);
List<LocationsHolder> locationsHolders = new ArrayList<>();
for (List<WptPt> 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<LocationsHolder> getLocationsHolders() {
return locationsHolders;
}
public void setLocationsHolder(LocationsHolder locationsHolder) {
this.locationsHolder = locationsHolder;
public void setLocationsHolders(List<LocationsHolder> locationsHolders) {
this.locationsHolders = locationsHolders;
}
public void startProgress() {
@ -393,9 +422,8 @@ public class GpxApproximationFragment extends ContextMenuScrollFragment
}
}
private void approximateGpx() {
if (gpxApproximator != null) {
setApplyButtonEnabled(false);
private void approximateGpx(@NonNull final GpxApproximator gpxApproximator) {
onApproximationStarted();
gpxApproximator.calculateGpxApproximation(new ResultMatcher<GpxRouteApproximation>() {
@Override
public boolean publish(final GpxRouteApproximation gpxApproximation) {
@ -404,16 +432,18 @@ public class GpxApproximationFragment extends ContextMenuScrollFragment
app.runInUIThread(new Runnable() {
@Override
public void run() {
Fragment fragment = getTargetFragment();
if (fragment instanceof GpxApproximationFragmentListener) {
((GpxApproximationFragmentListener) fragment).onGpxApproximationDone(gpxApproximation, gpxApproximator.getMode());
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
@ -422,6 +452,28 @@ public class GpxApproximationFragment extends ContextMenuScrollFragment
}
});
}
private void onApproximationStarted() {
setApplyButtonEnabled(false);
}
private void onApproximationFinished() {
finishProgress();
Fragment fragment = getTargetFragment();
List<GpxRouteApproximation> approximations = new ArrayList<>();
List<List<WptPt>> 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<GpxRouteApproximation> gpxApproximations, List<List<WptPt>> pointsList, ApplicationMode mode);
void onApplyGpxApproximation();

View file

@ -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;
if (gpxFile != null) {
this.rect = gpxFile.getRect();
} else {
this.rect = new QuadRect(0, 0, 0, 0);
}
public GpxData(GPXFile gpxFile, GpxData gpxData) {
this.gpxFile = gpxFile;
this.rect = gpxData.rect;
this.actionType = gpxData.actionType;
this.trkSegment = gpxData.trkSegment;
}
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;
}
}

View file

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

View file

@ -53,9 +53,11 @@ public class MeasurementEditingContext {
private final MeasurementCommandManager commandManager = new MeasurementCommandManager();
private final TrkSegment before = new TrkSegment();
private TrkSegment beforeCacheForSnap;
private List<TrkSegment> beforeSegments = new ArrayList<>();
private List<TrkSegment> beforeSegmentsForSnap;
private final TrkSegment after = new TrkSegment();
private TrkSegment afterCacheForSnap;
private List<TrkSegment> afterSegments = new ArrayList<>();
private List<TrkSegment> 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<Pair<WptPt, WptPt>, 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<WptPt> points;
private List<RouteSegmentResult> segments;
private final ApplicationMode appMode;
private final WptPt start;
private final WptPt end;
private final List<WptPt> points;
private final List<RouteSegmentResult> 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<WptPt> getOriginalTrackPointList() {
public List<List<WptPt>> 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<WptPt> 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<TrkSegment> segments = getBeforeSegments();
List<WptPt> 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<TrkSegment> getBeforeTrkSegmentLine() {
if (beforeSegmentsForSnap != null) {
return beforeSegmentsForSnap;
}
return before;
return beforeSegments;
}
TrkSegment getAfterTrkSegmentLine() {
if (afterCacheForSnap != null) {
return afterCacheForSnap;
List<TrkSegment> getAfterTrkSegmentLine() {
if (afterSegmentsForSnap != null) {
return afterSegmentsForSnap;
}
return after;
return afterSegments;
}
public List<TrkSegment> getBeforeSegments() {
return beforeSegments;
}
public List<TrkSegment> getAfterSegments() {
return afterSegments;
}
public List<WptPt> getPoints() {
return getBeforePoints();
}
public List<List<WptPt>> getPointsSegments(boolean plain, boolean route) {
List<List<WptPt>> res = new ArrayList<>();
List<WptPt> allPoints = getPoints();
List<WptPt> 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<WptPt> 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<WptPt> 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<WptPt> 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<WptPt> points) {
before.points.addAll(points);
updateCacheForSnap(false);
updateSegmentsForSnap(false);
}
public void replacePoints(List<WptPt> originalPoints, List<WptPt> points) {
if (originalPoints.size() > 1) {
int firstPointIndex = before.points.indexOf(originalPoints.get(0));
int lastPointIndex = before.points.indexOf(originalPoints.get(originalPoints.size() - 1));
List<WptPt> 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<TrkSegment> 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<Pair<WptPt, WptPt>> res = new ArrayList<>();
for (List<WptPt> points : Arrays.asList(before.points, after.points)) {
for (int i = 0; i < points.size() - 1; i++) {
Pair<WptPt, WptPt> 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<WptPt, WptPt> pair = new Pair<>(startPoint, endPoint);
if (roadSegmentData.get(pair) == null && startPoint.hasProfile()) {
res.add(pair);
}
}
@ -457,46 +647,82 @@ 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;
private void recreateSegments(List<TrkSegment> segments, List<TrkSegment> segmentsForSnap, List<WptPt> points, boolean calculateIfNeeded) {
List<Integer> 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;
}
}
}
if (original.points.size() > 1) {
for (int i = 0; i < original.points.size() - 1; i++) {
Pair<WptPt, WptPt> pair = new Pair<>(original.points.get(i), original.points.get(i + 1));
}
} else {
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<WptPt, WptPt> pair = new Pair<>(segment.points.get(i), segment.points.get(i + 1));
RoadSegmentData data = this.roadSegmentData.get(pair);
List<WptPt> pts = data != null ? data.getPoints() : null;
if (pts != null) {
cache.points.addAll(pts);
segmentForSnap.points.addAll(pts);
} else {
if (calculateIfNeeded && !hasDefaultModeOnly) {
if (calculateIfNeeded && roadSegmentIndexes.contains(segmentsForSnap.size())) {
scheduleRouteCalculateIfNotEmpty();
}
cache.points.addAll(Arrays.asList(pair.first, pair.second));
segmentForSnap.points.addAll(Arrays.asList(pair.first, pair.second));
}
}
} else {
cache.points.addAll(original.points);
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<WptPt> points = gpxData.getTrkSegment().points;
if (isTrackSnappedToRoad()) {
RouteImporter routeImporter = new RouteImporter(gpxData.getGpxFile());
List<RouteSegmentResult> segments = routeImporter.importRoute();
List<WptPt> routePoints = gpxData.getGpxFile().getRoutePoints();
List<TrkSegment> segments = gpxData.getGpxFile().getNonEmptyTrkSegments(false);
if (Algorithms.isEmpty(segments)) {
return;
}
for (int si = 0; si < segments.size(); si++) {
TrkSegment segment = segments.get(si);
List<WptPt> points = segment.points;
if (segment.hasRoute()) {
RouteImporter routeImporter = new RouteImporter(segment);
List<RouteSegmentResult> routeSegments = routeImporter.importRoute();
List<WptPt> routePoints = gpxData.getGpxFile().getRoutePoints(si);
int prevPointIndex = 0;
if (routePoints.isEmpty() && points.size() > 1) {
routePoints.add(points.get(0));
@ -521,11 +747,11 @@ public class MeasurementEditingContext {
if (points.size() > prevPointIndex + 1) {
pairPoints.add(points.get(prevPointIndex + 1));
}
Iterator<RouteSegmentResult> it = segments.iterator();
Iterator<RouteSegmentResult> it = routeSegments.iterator();
int k = endIndex - startIndex - 1;
List<RouteSegmentResult> pairSegments = new ArrayList<>();
if (k == 0 && !segments.isEmpty()) {
pairSegments.add(segments.remove(0));
if (k == 0 && !routeSegments.isEmpty()) {
pairSegments.add(routeSegments.remove(0));
} else {
while (it.hasNext() && k > 0) {
RouteSegmentResult s = it.next();
@ -538,17 +764,23 @@ public class MeasurementEditingContext {
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();
}
}
}
}
public void setPoints(GpxRouteApproximation gpxApproximation, ApplicationMode mode) {
public List<WptPt> setPoints(GpxRouteApproximation gpxApproximation, List<WptPt> originalPoints, ApplicationMode mode) {
if (gpxApproximation == null || Algorithms.isEmpty(gpxApproximation.finalPoints) || Algorithms.isEmpty(gpxApproximation.result)) {
return;
return null;
}
roadSegmentData.clear();
List<WptPt> routePoints = new ArrayList<>();
List<GpxPoint> 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<GpxPoint> 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<WptPt> getRoutePoints() {
List<WptPt> res = new ArrayList<>();
List<WptPt> points = new ArrayList<>(before.points);
points.addAll(after.points);
int size = points.size();
for (int i = 0; i < size - 1; i++) {
Pair<WptPt, WptPt> 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<List<WptPt>> getRoutePoints() {
List<List<WptPt>> res = new ArrayList<>();
List<WptPt> plainPoints = new ArrayList<>(before.points);
plainPoints.addAll(after.points);
List<WptPt> 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<RouteSegmentResult> route = new ArrayList<>();
List<Location> 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<WptPt, WptPt> 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<TrkSegment> getRouteSegments() {
List<TrkSegment> res = new ArrayList<>();
List<Integer> 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 {

View file

@ -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<WptPt> 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<List<WptPt>> 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:
if (mapActivity != null) {
dismiss(getMapActivity());
}
break;
case ExitBottomSheetDialogFragment.SAVE_RESULT_CODE:
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<WptPt> 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,14 +1626,12 @@ 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);
}
}
}
private void updateUndoRedoButton(boolean enable, View view) {
view.setEnabled(enable);
@ -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<GpxRouteApproximation> gpxApproximations, List<List<WptPt>> 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);

View file

@ -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<WptPt> originalTrackPointList = editingCtx.getOriginalTrackPointList();
if (originalTrackPointList != null) {
List<List<WptPt>> 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).
for (List<WptPt> 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).
List<TrkSegment> before = editingCtx.getBeforeTrkSegmentLine();
for (TrkSegment segment : before) {
new Renderable.StandardTrack(new ArrayList<>(segment.points), 17.2).
drawSegment(view.getZoom(), lineAttrs.paint, canvas, tb);
TrkSegment after = editingCtx.getAfterTrkSegmentLine();
new Renderable.StandardTrack(new ArrayList<>(after.points), 17.2).
}
List<TrkSegment> 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,38 +313,54 @@ 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<TrkSegment> before = editingCtx.getBeforeSegments();
List<TrkSegment> 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);
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());
}
if (after.points.size() > 0) {
if (before.points.size() == 0) {
}
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());
}
WptPt pt = after.points.get(0);
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);
}
}
}
if (!tx.isEmpty() && !ty.isEmpty()) {
GeometryWay.calculatePath(tb, tx, ty, path);
canvas.drawPath(path, lineAttrs.paint);
}
}
}
private void drawCenterIcon(Canvas canvas, RotatedTileBox tb, boolean nightMode) {
canvas.rotate(-tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY());
@ -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;
}

View file

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

View file

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

View file

@ -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<Void, Void, Exception> {
private WeakReference<MeasurementToolFragment> fragmentRef;
private final WeakReference<MeasurementToolFragment> 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<Void, Void, Exception> {
OsmandApplication app = mapActivity.getMyApplication();
MeasurementToolLayer measurementLayer = mapActivity.getMapLayers().getMeasurementToolLayer();
MeasurementEditingContext editingCtx = fragment.getEditingCtx();
List<WptPt> 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<WptPt> 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<WptPt> 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;
}
private GPXFile generateGpxFile(MeasurementToolLayer measurementLayer, MeasurementEditingContext editingCtx,
String trackName, @NonNull GPXFile gpx) {
if (measurementLayer != null) {
List<TrkSegment> before = editingCtx.getBeforeTrkSegmentLine();
List<TrkSegment> 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<Track> gpxTracks = gpx.tracks;
List<WptPt> gpxPoints = gpx.getPoints();
List<Route> gpxRoutes = gpx.routes;
gpx = newGpx;
List<List<WptPt>> routePoints = editingCtx.getRoutePoints();
for (List<WptPt> 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

View file

@ -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,8 +302,6 @@ 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(": ");
@ -317,7 +312,6 @@ public class SelectedPointBottomSheetDialogFragment extends MenuBottomSheetDialo
description.append(" ").append((getString(R.string.map_widget_speed)).substring(0, 1)).append(": ");
description.append(OsmAndFormatter.getFormattedSpeed(speed, mapActivity.getMyApplication()));
}
}
return description.toString();
}

View file

@ -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<MeasurementTool
private final List<WptPt> points;
private MeasurementAdapterListener listener;
private boolean nightMode;
private final ActionType actionType;
private final static String BULLET = "";
public MeasurementToolAdapter(MapActivity mapActivity, List<WptPt> points, ActionType actionType) {
public MeasurementToolAdapter(MapActivity mapActivity, List<WptPt> 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<MeasurementTool
if (!TextUtils.isEmpty(pointTitle)) {
holder.title.setText(pointTitle);
} else {
if (actionType == ActionType.ADD_ROUTE_POINTS) {
holder.title.setText(mapActivity.getString(R.string.route_point) + " - " + (pos + 1));
} else {
holder.title.setText(mapActivity.getString(R.string.plugin_distance_point) + " - " + (pos + 1));
}
holder.title.setText(mapActivity.getString(R.string.ltr_or_rtl_combine_via_dash, mapActivity.getString(R.string.plugin_distance_point), String.valueOf(pos + 1)));
}
String pointDesc = pt.desc;
if (!TextUtils.isEmpty(pointDesc)) {
@ -114,11 +107,11 @@ public class MeasurementToolAdapter extends RecyclerView.Adapter<MeasurementTool
holder.descr.setText(text);
}
}
if (actionType == ActionType.EDIT_SEGMENT) {
double elevation = pt.ele;
if (!Double.isNaN(elevation)) {
String eleStr = (mapActivity.getString(R.string.altitude)).substring(0, 1);
holder.elevation.setText(eleStr + ": " + OsmAndFormatter.getFormattedAlt(elevation, mapActivity.getMyApplication()));
holder.elevation.setText(mapActivity.getString(R.string.ltr_or_rtl_combine_via_colon,
eleStr, OsmAndFormatter.getFormattedAlt(elevation, mapActivity.getMyApplication())));
} else {
holder.elevation.setText("");
}
@ -129,7 +122,6 @@ public class MeasurementToolAdapter extends RecyclerView.Adapter<MeasurementTool
} else {
holder.speed.setText("");
}
}
holder.deleteBtn.setImageDrawable(iconsCache.getIcon(R.drawable.ic_action_remove_dark,
nightMode ? R.color.icon_color_default_dark : R.color.icon_color_default_light));
holder.deleteBtn.setOnClickListener(new View.OnClickListener() {

View file

@ -3,48 +3,57 @@ package net.osmand.plus.measurementtool.command;
import net.osmand.data.LatLon;
import net.osmand.GPXUtilities.WptPt;
import net.osmand.plus.measurementtool.MeasurementEditingContext;
import net.osmand.plus.measurementtool.MeasurementEditingContext.AdditionMode;
import net.osmand.plus.measurementtool.MeasurementToolLayer;
import net.osmand.plus.settings.backend.ApplicationMode;
import java.util.List;
public class AddPointCommand extends MeasurementModeCommand {
private int position;
private WptPt point;
private String prevPointProfile;
private boolean center;
private boolean addPointBefore;
public AddPointCommand(MeasurementToolLayer measurementLayer, boolean center) {
super(measurementLayer);
init(measurementLayer, null, center);
init(null, center);
}
public AddPointCommand(MeasurementToolLayer measurementLayer, LatLon latLon) {
super(measurementLayer);
init(measurementLayer, latLon, false);
init(latLon, false);
}
private void init(MeasurementToolLayer measurementLayer, LatLon latLon, boolean center) {
private void init(LatLon latLon, boolean center) {
MeasurementEditingContext ctx = getEditingCtx();
if (latLon != null) {
point = new WptPt();
point.lat = latLon.getLatitude();
point.lon = latLon.getLongitude();
ApplicationMode appMode = measurementLayer.getEditingCtx().getAppMode();
if (appMode != MeasurementEditingContext.DEFAULT_APP_MODE) {
point.setProfileType(appMode.getStringKey());
}
}
this.center = center;
position = measurementLayer.getEditingCtx().getPointsCount();
position = ctx.getPointsCount();
}
@Override
public boolean execute() {
MeasurementEditingContext ctx = getEditingCtx();
addPointBefore = ctx.isInAddPointBeforeMode();
List<WptPt> 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);
}

View file

@ -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<WptPt> points;
private Map<Pair<WptPt, WptPt>, RoadSegmentData> roadSegmentData;
private List<GpxRouteApproximation> approximations;
private List<List<WptPt>> segmentPointsList;
private final List<List<WptPt>> originalSegmentPointsList;
public ApplyGpxApproximationCommand(MeasurementToolLayer measurementLayer, GpxRouteApproximation approximation, ApplicationMode mode) {
public ApplyGpxApproximationCommand(MeasurementToolLayer measurementLayer,
List<GpxRouteApproximation> approximations,
List<List<WptPt>> 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<List<WptPt>> 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<WptPt> 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<WptPt> segmentPoints = segmentPointsList.get(i);
List<WptPt> newSegmentPoints = ctx.setPoints(approximation, segmentPoints, mode);
if (newSegmentPoints != null) {
segmentPointsList.set(i, newSegmentPoints);
}
}
}
}

View file

@ -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 (!pt.isGap()) {
if (newMode != null && newMode != DEFAULT_APP_MODE) {
pt.setProfileType(newMode.getStringKey());
} else {
pt.removeProfileType();
}
}
}
}

View file

@ -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<WptPt> points;
private Map<Pair<WptPt, WptPt>, RoadSegmentData> roadSegmentData;
private ClearCommandMode clearMode;
private int pointPosition;
@ -31,27 +37,30 @@ public class ClearPointsCommand extends MeasurementModeCommand {
}
private void executeCommand() {
List<WptPt> pts = getEditingCtx().getPoints();
MeasurementEditingContext ctx = getEditingCtx();
List<WptPt> 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();
}

View file

@ -80,6 +80,6 @@ public class MeasurementCommandManager {
}
public MeasurementModeCommand getLastCommand() {
return undoCommands.getLast();
return undoCommands.getFirst();
}
}

View file

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

View file

@ -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<WptPt> points = getEditingCtx().getPoints();
points.add(addTo, points.remove(removeFrom));
getEditingCtx().updateCacheForSnap();
getEditingCtx().updateSegmentsForSnap();
refreshMap();
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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,

View file

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