Gpx approx refactor (first stage)
This commit is contained in:
parent
267d1374b5
commit
b1d714a62c
27 changed files with 889 additions and 715 deletions
|
@ -52,6 +52,7 @@ public class GPXUtilities {
|
||||||
private static final String DEFAULT_ICON_NAME = "special_star";
|
private static final String DEFAULT_ICON_NAME = "special_star";
|
||||||
private static final String BACKGROUND_TYPE_EXTENSION = "background";
|
private static final String BACKGROUND_TYPE_EXTENSION = "background";
|
||||||
private static final String PROFILE_TYPE_EXTENSION = "profile";
|
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 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$
|
private final static String GPX_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'"; //$NON-NLS-1$
|
||||||
|
@ -324,6 +325,11 @@ public class GPXUtilities {
|
||||||
getExtensionsToWrite().put(PROFILE_TYPE_EXTENSION, profileType);
|
getExtensionsToWrite().put(PROFILE_TYPE_EXTENSION, profileType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasProfile() {
|
||||||
|
String profileType = getProfileType();
|
||||||
|
return profileType != null && !GAP_PROFILE_TYPE.equals(profileType);
|
||||||
|
}
|
||||||
|
|
||||||
public void removeProfileType() {
|
public void removeProfileType() {
|
||||||
getExtensionsToWrite().remove(PROFILE_TYPE_EXTENSION);
|
getExtensionsToWrite().remove(PROFILE_TYPE_EXTENSION);
|
||||||
}
|
}
|
||||||
|
@ -374,11 +380,16 @@ public class GPXUtilities {
|
||||||
|
|
||||||
public static class TrkSegment extends GPXExtensions {
|
public static class TrkSegment extends GPXExtensions {
|
||||||
public boolean generalSegment = false;
|
public boolean generalSegment = false;
|
||||||
|
|
||||||
public List<WptPt> points = new ArrayList<>();
|
public List<WptPt> points = new ArrayList<>();
|
||||||
|
|
||||||
public Object renderer;
|
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) {
|
public List<GPXTrackAnalysis> splitByDistance(double meters, boolean joinSegments) {
|
||||||
return split(getDistanceMetric(), getTimeSplit(), meters, joinSegments);
|
return split(getDistanceMetric(), getTimeSplit(), meters, joinSegments);
|
||||||
|
@ -393,7 +404,6 @@ public class GPXUtilities {
|
||||||
splitSegment(metric, secondaryMetric, metricLimit, splitSegments, this, joinSegments);
|
splitSegment(metric, secondaryMetric, metricLimit, splitSegments, this, joinSegments);
|
||||||
return convert(splitSegments);
|
return convert(splitSegments);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Track extends GPXExtensions {
|
public static class Track extends GPXExtensions {
|
||||||
|
@ -1078,9 +1088,6 @@ public class GPXUtilities {
|
||||||
private List<WptPt> points = new ArrayList<>();
|
private List<WptPt> points = new ArrayList<>();
|
||||||
public List<Route> routes = 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 Exception error = null;
|
||||||
public String path = "";
|
public String path = "";
|
||||||
public boolean showCurrentTrack;
|
public boolean showCurrentTrack;
|
||||||
|
@ -1108,7 +1115,7 @@ public class GPXUtilities {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasRoute() {
|
public boolean hasRoute() {
|
||||||
return !routeSegments.isEmpty() && !routeTypes.isEmpty();
|
return getNonEmptyTrkSegments(true).size() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<WptPt> getPoints() {
|
public List<WptPt> getPoints() {
|
||||||
|
@ -1218,7 +1225,7 @@ public class GPXUtilities {
|
||||||
GPXTrackAnalysis g = new GPXTrackAnalysis();
|
GPXTrackAnalysis g = new GPXTrackAnalysis();
|
||||||
g.wptPoints = points.size();
|
g.wptPoints = points.size();
|
||||||
g.wptCategoryNames = getWaypointCategories(true);
|
g.wptCategoryNames = getWaypointCategories(true);
|
||||||
List<SplitSegment> splitSegments = new ArrayList<GPXUtilities.SplitSegment>();
|
List<SplitSegment> splitSegments = new ArrayList<>();
|
||||||
for (int i = 0; i < tracks.size(); i++) {
|
for (int i = 0; i < tracks.size(); i++) {
|
||||||
Track subtrack = tracks.get(i);
|
Track subtrack = tracks.get(i);
|
||||||
for (TrkSegment segment : subtrack.segments) {
|
for (TrkSegment segment : subtrack.segments) {
|
||||||
|
@ -1243,6 +1250,15 @@ public class GPXUtilities {
|
||||||
return points;
|
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() {
|
public boolean hasRtePt() {
|
||||||
for (Route r : routes) {
|
for (Route r : routes) {
|
||||||
if (r.points.size() > 0) {
|
if (r.points.size() > 0) {
|
||||||
|
@ -1318,15 +1334,16 @@ public class GPXUtilities {
|
||||||
return pt;
|
return pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TrkSegment getNonEmptyTrkSegment() {
|
public List<TrkSegment> getNonEmptyTrkSegments(boolean routesOnly) {
|
||||||
for (GPXUtilities.Track t : tracks) {
|
List<TrkSegment> segments = new ArrayList<>();
|
||||||
|
for (Track t : tracks) {
|
||||||
for (TrkSegment s : t.segments) {
|
for (TrkSegment s : t.segments) {
|
||||||
if (s.points.size() > 0) {
|
if (!s.generalSegment && s.points.size() > 0 && (!routesOnly || s.hasRoute())) {
|
||||||
return s;
|
segments.add(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return segments;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addTrkSegment(List<WptPt> points) {
|
public void addTrkSegment(List<WptPt> points) {
|
||||||
|
@ -1365,8 +1382,8 @@ public class GPXUtilities {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addRoutePoints(List<WptPt> points) {
|
public void addRoutePoints(List<WptPt> points, boolean addRoute) {
|
||||||
if (routes.size() == 0) {
|
if (routes.size() == 0 || addRoute) {
|
||||||
Route route = new Route();
|
Route route = new Route();
|
||||||
routes.add(route);
|
routes.add(route);
|
||||||
}
|
}
|
||||||
|
@ -1608,7 +1625,7 @@ public class GPXUtilities {
|
||||||
bottom = Math.min(bottom, p.getLatitude());
|
bottom = Math.min(bottom, p.getLatitude());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (GPXUtilities.Route route : routes) {
|
for (Route route : routes) {
|
||||||
for (WptPt p : route.points) {
|
for (WptPt p : route.points) {
|
||||||
if (left == 0 && right == 0) {
|
if (left == 0 && right == 0) {
|
||||||
left = p.getLongitude();
|
left = p.getLongitude();
|
||||||
|
@ -1720,7 +1737,7 @@ public class GPXUtilities {
|
||||||
|
|
||||||
public static String asString(GPXFile file) {
|
public static String asString(GPXFile file) {
|
||||||
final Writer writer = new StringWriter();
|
final Writer writer = new StringWriter();
|
||||||
GPXUtilities.writeGpx(writer, file);
|
writeGpx(writer, file);
|
||||||
return writer.toString();
|
return writer.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1807,6 +1824,8 @@ public class GPXUtilities {
|
||||||
writeWpt(format, serializer, p);
|
writeWpt(format, serializer, p);
|
||||||
serializer.endTag(null, "trkpt"); //$NON-NLS-1$
|
serializer.endTag(null, "trkpt"); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
assignRouteExtensionWriter(segment);
|
||||||
|
writeExtensions(serializer, segment);
|
||||||
serializer.endTag(null, "trkseg"); //$NON-NLS-1$
|
serializer.endTag(null, "trkseg"); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
writeExtensions(serializer, track);
|
writeExtensions(serializer, track);
|
||||||
|
@ -1834,7 +1853,6 @@ public class GPXUtilities {
|
||||||
serializer.endTag(null, "wpt"); //$NON-NLS-1$
|
serializer.endTag(null, "wpt"); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
||||||
assignRouteExtensionWriter(file);
|
|
||||||
writeExtensions(serializer, file);
|
writeExtensions(serializer, file);
|
||||||
|
|
||||||
serializer.endTag(null, "gpx"); //$NON-NLS-1$
|
serializer.endTag(null, "gpx"); //$NON-NLS-1$
|
||||||
|
@ -1847,19 +1865,19 @@ public class GPXUtilities {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void assignRouteExtensionWriter(final GPXFile gpxFile) {
|
private static void assignRouteExtensionWriter(final TrkSegment segment) {
|
||||||
if (gpxFile.hasRoute() && gpxFile.getExtensionsWriter() == null) {
|
if (segment.hasRoute() && segment.getExtensionsWriter() == null) {
|
||||||
gpxFile.setExtensionsWriter(new GPXExtensionsWriter() {
|
segment.setExtensionsWriter(new GPXExtensionsWriter() {
|
||||||
@Override
|
@Override
|
||||||
public void writeExtensions(XmlSerializer serializer) {
|
public void writeExtensions(XmlSerializer serializer) {
|
||||||
StringBundle bundle = new StringBundle();
|
StringBundle bundle = new StringBundle();
|
||||||
List<StringBundle> segmentsBundle = new ArrayList<>();
|
List<StringBundle> segmentsBundle = new ArrayList<>();
|
||||||
for (RouteSegment segment : gpxFile.routeSegments) {
|
for (RouteSegment segment : segment.routeSegments) {
|
||||||
segmentsBundle.add(segment.toStringBundle());
|
segmentsBundle.add(segment.toStringBundle());
|
||||||
}
|
}
|
||||||
bundle.putBundleList("route", "segment", segmentsBundle);
|
bundle.putBundleList("route", "segment", segmentsBundle);
|
||||||
List<StringBundle> typesBundle = new ArrayList<>();
|
List<StringBundle> typesBundle = new ArrayList<>();
|
||||||
for (RouteType routeType : gpxFile.routeTypes) {
|
for (RouteType routeType : segment.routeTypes) {
|
||||||
typesBundle.add(routeType.toStringBundle());
|
typesBundle.add(routeType.toStringBundle());
|
||||||
}
|
}
|
||||||
bundle.putBundleList("types", "type", typesBundle);
|
bundle.putBundleList("types", "type", typesBundle);
|
||||||
|
@ -1901,12 +1919,15 @@ public class GPXUtilities {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void writeExtensions(XmlSerializer serializer, GPXExtensions p) throws IOException {
|
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();
|
GPXExtensionsWriter extensionsWriter = p.getExtensionsWriter();
|
||||||
if (!extensionsToRead.isEmpty() || extensionsWriter != null) {
|
if (!extensions.isEmpty() || extensionsWriter != null) {
|
||||||
serializer.startTag(null, "extensions");
|
serializer.startTag(null, "extensions");
|
||||||
if (!extensionsToRead.isEmpty()) {
|
if (!extensions.isEmpty()) {
|
||||||
for (Entry<String, String> s : extensionsToRead.entrySet()) {
|
for (Entry<String, String> s : extensions.entrySet()) {
|
||||||
writeNotNullText(serializer, s.getKey(), s.getValue());
|
writeNotNullText(serializer, s.getKey(), s.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1943,7 +1964,20 @@ public class GPXUtilities {
|
||||||
if (!Float.isNaN(p.heading)) {
|
if (!Float.isNaN(p.heading)) {
|
||||||
p.getExtensionsToWrite().put("heading", String.valueOf(Math.round(p.heading)));
|
p.getExtensionsToWrite().put("heading", String.valueOf(Math.round(p.heading)));
|
||||||
}
|
}
|
||||||
writeExtensions(serializer, p);
|
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 {
|
private static void writeAuthor(XmlSerializer serializer, Author author) throws IOException {
|
||||||
|
@ -2099,10 +2133,11 @@ public class GPXUtilities {
|
||||||
TrkSegment routeTrackSegment = new TrkSegment();
|
TrkSegment routeTrackSegment = new TrkSegment();
|
||||||
routeTrack.segments.add(routeTrackSegment);
|
routeTrack.segments.add(routeTrackSegment);
|
||||||
Stack<GPXExtensions> parserState = new Stack<>();
|
Stack<GPXExtensions> parserState = new Stack<>();
|
||||||
|
TrkSegment firstSegment = null;
|
||||||
boolean extensionReadMode = false;
|
boolean extensionReadMode = false;
|
||||||
boolean routePointExtension = false;
|
boolean routePointExtension = false;
|
||||||
List<RouteSegment> routeSegments = gpxFile.routeSegments;
|
List<RouteSegment> routeSegments = new ArrayList<>();
|
||||||
List<RouteType> routeTypes = gpxFile.routeTypes;
|
List<RouteType> routeTypes = new ArrayList<>();
|
||||||
boolean routeExtension = false;
|
boolean routeExtension = false;
|
||||||
boolean typesExtension = false;
|
boolean typesExtension = false;
|
||||||
parserState.push(gpxFile);
|
parserState.push(gpxFile);
|
||||||
|
@ -2403,6 +2438,16 @@ public class GPXUtilities {
|
||||||
assert pop instanceof Route;
|
assert pop instanceof Route;
|
||||||
} else if (tag.equals("trkseg")) {
|
} else if (tag.equals("trkseg")) {
|
||||||
Object pop = parserState.pop();
|
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;
|
assert pop instanceof TrkSegment;
|
||||||
} else if (tag.equals("rpt")) {
|
} else if (tag.equals("rpt")) {
|
||||||
Object pop = parserState.pop();
|
Object pop = parserState.pop();
|
||||||
|
@ -2413,6 +2458,10 @@ public class GPXUtilities {
|
||||||
if (!routeTrackSegment.points.isEmpty()) {
|
if (!routeTrackSegment.points.isEmpty()) {
|
||||||
gpxFile.tracks.add(routeTrack);
|
gpxFile.tracks.add(routeTrack);
|
||||||
}
|
}
|
||||||
|
if (!routeSegments.isEmpty() && !routeTypes.isEmpty() && firstSegment != null) {
|
||||||
|
firstSegment.routeSegments = routeSegments;
|
||||||
|
firstSegment.routeTypes = routeTypes;
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
gpxFile.error = e;
|
gpxFile.error = e;
|
||||||
log.error("Error reading gpx", e); //$NON-NLS-1$
|
log.error("Error reading gpx", e); //$NON-NLS-1$
|
||||||
|
|
|
@ -20,10 +20,10 @@ public class RouteExporter {
|
||||||
|
|
||||||
public static final String OSMAND_ROUTER_V2 = "OsmAndRouterV2";
|
public static final String OSMAND_ROUTER_V2 = "OsmAndRouterV2";
|
||||||
|
|
||||||
private String name;
|
private final String name;
|
||||||
private List<RouteSegmentResult> route;
|
private final List<RouteSegmentResult> route;
|
||||||
private List<Location> locations;
|
private final List<Location> locations;
|
||||||
private List<WptPt> points;
|
private final List<WptPt> points;
|
||||||
|
|
||||||
public RouteExporter(String name, List<RouteSegmentResult> route, List<Location> locations, List<WptPt> points) {
|
public RouteExporter(String name, List<RouteSegmentResult> route, List<Location> locations, List<WptPt> points) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
@ -33,6 +33,34 @@ public class RouteExporter {
|
||||||
}
|
}
|
||||||
|
|
||||||
public GPXFile exportRoute() {
|
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);
|
RouteDataResources resources = new RouteDataResources(locations);
|
||||||
List<StringBundle> routeItems = new ArrayList<>();
|
List<StringBundle> routeItems = new ArrayList<>();
|
||||||
if (!Algorithms.isEmpty(route)) {
|
if (!Algorithms.isEmpty(route)) {
|
||||||
|
@ -57,15 +85,9 @@ public class RouteExporter {
|
||||||
typeList.add(typeBundle);
|
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();
|
TrkSegment trkSegment = new TrkSegment();
|
||||||
track.segments.add(trkSegment);
|
|
||||||
|
|
||||||
if (locations == null || locations.isEmpty()) {
|
if (locations == null || locations.isEmpty()) {
|
||||||
return gpx;
|
return trkSegment;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < locations.size(); i++) {
|
for (int i = 0; i < locations.size(); i++) {
|
||||||
Location loc = locations.get(i);
|
Location loc = locations.get(i);
|
||||||
|
@ -83,23 +105,17 @@ public class RouteExporter {
|
||||||
}
|
}
|
||||||
trkSegment.points.add(pt);
|
trkSegment.points.add(pt);
|
||||||
}
|
}
|
||||||
if (points != null) {
|
|
||||||
for (WptPt pt : points) {
|
|
||||||
gpx.addPoint(pt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<RouteSegment> routeSegments = new ArrayList<>();
|
List<RouteSegment> routeSegments = new ArrayList<>();
|
||||||
for (StringBundle item : routeItems) {
|
for (StringBundle item : routeItems) {
|
||||||
routeSegments.add(RouteSegment.fromStringBundle(item));
|
routeSegments.add(RouteSegment.fromStringBundle(item));
|
||||||
}
|
}
|
||||||
gpx.routeSegments = routeSegments;
|
trkSegment.routeSegments = routeSegments;
|
||||||
List<RouteType> routeTypes = new ArrayList<>();
|
List<RouteType> routeTypes = new ArrayList<>();
|
||||||
for (StringBundle item : typeList) {
|
for (StringBundle item : typeList) {
|
||||||
routeTypes.add(RouteType.fromStringBundle(item));
|
routeTypes.add(RouteType.fromStringBundle(item));
|
||||||
}
|
}
|
||||||
gpx.routeTypes = routeTypes;
|
trkSegment.routeTypes = routeTypes;
|
||||||
|
return trkSegment;
|
||||||
return gpx;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import net.osmand.GPXUtilities;
|
||||||
import net.osmand.GPXUtilities.GPXFile;
|
import net.osmand.GPXUtilities.GPXFile;
|
||||||
import net.osmand.GPXUtilities.RouteSegment;
|
import net.osmand.GPXUtilities.RouteSegment;
|
||||||
import net.osmand.GPXUtilities.RouteType;
|
import net.osmand.GPXUtilities.RouteType;
|
||||||
|
import net.osmand.GPXUtilities.TrkSegment;
|
||||||
import net.osmand.GPXUtilities.WptPt;
|
import net.osmand.GPXUtilities.WptPt;
|
||||||
import net.osmand.Location;
|
import net.osmand.Location;
|
||||||
import net.osmand.PlatformUtil;
|
import net.osmand.PlatformUtil;
|
||||||
|
@ -28,10 +29,9 @@ public class RouteImporter {
|
||||||
|
|
||||||
private File file;
|
private File file;
|
||||||
private GPXFile gpxFile;
|
private GPXFile gpxFile;
|
||||||
|
private TrkSegment segment;
|
||||||
|
|
||||||
private List<RouteSegmentResult> route = new ArrayList<>();
|
private final List<RouteSegmentResult> route = new ArrayList<>();
|
||||||
private RouteRegion region = new RouteRegion();
|
|
||||||
private RouteDataResources resources = new RouteDataResources();
|
|
||||||
|
|
||||||
public RouteImporter(File file) {
|
public RouteImporter(File file) {
|
||||||
this.file = file;
|
this.file = file;
|
||||||
|
@ -41,8 +41,12 @@ public class RouteImporter {
|
||||||
this.gpxFile = gpxFile;
|
this.gpxFile = gpxFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RouteImporter(TrkSegment segment) {
|
||||||
|
this.segment = segment;
|
||||||
|
}
|
||||||
|
|
||||||
public List<RouteSegmentResult> importRoute() {
|
public List<RouteSegmentResult> importRoute() {
|
||||||
if (gpxFile != null) {
|
if (gpxFile != null || segment != null) {
|
||||||
parseRoute();
|
parseRoute();
|
||||||
} else if (file != null) {
|
} else if (file != null) {
|
||||||
FileInputStream fis = null;
|
FileInputStream fis = null;
|
||||||
|
@ -69,19 +73,34 @@ public class RouteImporter {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseRoute() {
|
private void parseRoute() {
|
||||||
collectLocations();
|
if (segment != null) {
|
||||||
collectSegments();
|
parseRoute(segment);
|
||||||
collectTypes();
|
} else if (gpxFile != null) {
|
||||||
for (RouteSegmentResult segment : route) {
|
List<TrkSegment> segments = gpxFile.getNonEmptyTrkSegments(true);
|
||||||
segment.fillNames(resources);
|
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();
|
List<Location> locations = resources.getLocations();
|
||||||
double lastElevation = HEIGHT_UNDEFINED;
|
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) {
|
if (segment.hasRoute()) {
|
||||||
for (WptPt point : gpxFile.tracks.get(0).segments.get(0).points) {
|
for (WptPt point : segment.points) {
|
||||||
Location loc = new Location("", point.getLatitude(), point.getLongitude());
|
Location loc = new Location("", point.getLatitude(), point.getLongitude());
|
||||||
if (!Double.isNaN(point.ele)) {
|
if (!Double.isNaN(point.ele)) {
|
||||||
loc.setAltitude(point.ele);
|
loc.setAltitude(point.ele);
|
||||||
|
@ -94,18 +113,20 @@ public class RouteImporter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void collectSegments() {
|
private List<RouteSegmentResult> collectRouteSegments(RouteRegion region, RouteDataResources resources, TrkSegment segment) {
|
||||||
for (RouteSegment segment : gpxFile.routeSegments) {
|
List<RouteSegmentResult> route = new ArrayList<>();
|
||||||
|
for (RouteSegment routeSegment : segment.routeSegments) {
|
||||||
RouteDataObject object = new RouteDataObject(region);
|
RouteDataObject object = new RouteDataObject(region);
|
||||||
RouteSegmentResult segmentResult = new RouteSegmentResult(object);
|
RouteSegmentResult segmentResult = new RouteSegmentResult(object);
|
||||||
segmentResult.readFromBundle(new RouteDataBundle(resources, segment.toStringBundle()));
|
segmentResult.readFromBundle(new RouteDataBundle(resources, routeSegment.toStringBundle()));
|
||||||
route.add(segmentResult);
|
route.add(segmentResult);
|
||||||
}
|
}
|
||||||
|
return route;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void collectTypes() {
|
private void collectRouteTypes(RouteRegion region, TrkSegment segment) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (RouteType routeType : gpxFile.routeTypes) {
|
for (RouteType routeType : segment.routeTypes) {
|
||||||
StringBundle bundle = routeType.toStringBundle();
|
StringBundle bundle = routeType.toStringBundle();
|
||||||
String t = bundle.getString("t", null);
|
String t = bundle.getString("t", null);
|
||||||
String v = bundle.getString("v", null);
|
String v = bundle.getString("v", null);
|
||||||
|
|
|
@ -243,9 +243,6 @@ public class RoutePlannerFrontEnd {
|
||||||
start = gpxPoints.get(0);
|
start = gpxPoints.get(0);
|
||||||
}
|
}
|
||||||
while (start != null && !gctx.ctx.calculationProgress.isCancelled) {
|
while (start != null && !gctx.ctx.calculationProgress.isCancelled) {
|
||||||
if (Thread.currentThread().isInterrupted()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
double routeDist = gctx.MAXIMUM_STEP_APPROXIMATION;
|
double routeDist = gctx.MAXIMUM_STEP_APPROXIMATION;
|
||||||
GpxPoint next = findNextGpxPointWithin(gctx, gpxPoints, start, routeDist);
|
GpxPoint next = findNextGpxPointWithin(gctx, gpxPoints, start, routeDist);
|
||||||
boolean routeFound = false;
|
boolean routeFound = false;
|
||||||
|
|
|
@ -255,7 +255,8 @@ public class RouteSegmentResult implements StringExternalizable<RouteDataBundle>
|
||||||
@Override
|
@Override
|
||||||
public void writeToBundle(RouteDataBundle bundle) {
|
public void writeToBundle(RouteDataBundle bundle) {
|
||||||
Map<RouteTypeRule, Integer> rules = bundle.getResources().getRules();
|
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("segmentTime", segmentTime, 2);
|
||||||
bundle.putFloat("speed", speed, 2);
|
bundle.putFloat("speed", speed, 2);
|
||||||
if (turnType != null) {
|
if (turnType != null) {
|
||||||
|
@ -278,17 +279,22 @@ public class RouteSegmentResult implements StringExternalizable<RouteDataBundle>
|
||||||
int end = Math.max(startPointIndex, endPointIndex) + 1;
|
int end = Math.max(startPointIndex, endPointIndex) + 1;
|
||||||
if (object.pointTypes != null && start < object.pointTypes.length) {
|
if (object.pointTypes != null && start < object.pointTypes.length) {
|
||||||
int[][] types = Arrays.copyOfRange(object.pointTypes, start, Math.min(end, 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));
|
bundle.putArray("pointTypes", convertTypes(types, rules));
|
||||||
}
|
}
|
||||||
if (object.nameIds != null) {
|
if (object.nameIds != null) {
|
||||||
bundle.putArray("names", convertNameIds(object.nameIds, rules));
|
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));
|
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));
|
||||||
String[][] names = Arrays.copyOfRange(object.pointNames, start, Math.min(end, object.pointNames.length));
|
if (reversed) {
|
||||||
bundle.putArray("pointNames", convertPointNames(types, names, rules));
|
Algorithms.reverseArray(types);
|
||||||
|
Algorithms.reverseArray(names);
|
||||||
}
|
}
|
||||||
|
bundle.putArray("pointNames", convertPointNames(types, names, rules));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -886,6 +886,14 @@ public class Algorithms {
|
||||||
return map;
|
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) {
|
public static boolean containsInArrayL(long[] array, long value) {
|
||||||
return Arrays.binarySearch(array, value) >= 0;
|
return Arrays.binarySearch(array, value) >= 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
Thx - Hardy
|
Thx - Hardy
|
||||||
|
|
||||||
-->
|
-->
|
||||||
|
<string name="app_mode_gap">Gap</string>
|
||||||
|
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
|
||||||
<string name="file_already_imported">File is already imported in OsmAnd</string>
|
<string name="file_already_imported">File is already imported in OsmAnd</string>
|
||||||
<string name="osm_edit_logout_success">Logout successful</string>
|
<string name="osm_edit_logout_success">Logout successful</string>
|
||||||
<string name="clear_osm_token">Clear OpenStreetMap OAuth token</string>
|
<string name="clear_osm_token">Clear OpenStreetMap OAuth token</string>
|
||||||
|
|
|
@ -21,7 +21,6 @@ import com.google.android.material.bottomnavigation.BottomNavigationView;
|
||||||
import net.osmand.AndroidUtils;
|
import net.osmand.AndroidUtils;
|
||||||
import net.osmand.GPXUtilities;
|
import net.osmand.GPXUtilities;
|
||||||
import net.osmand.GPXUtilities.GPXFile;
|
import net.osmand.GPXUtilities.GPXFile;
|
||||||
import net.osmand.GPXUtilities.TrkSegment;
|
|
||||||
import net.osmand.GPXUtilities.WptPt;
|
import net.osmand.GPXUtilities.WptPt;
|
||||||
import net.osmand.IndexConstants;
|
import net.osmand.IndexConstants;
|
||||||
import net.osmand.data.LatLon;
|
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.GpxDisplayGroup;
|
||||||
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
|
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
|
||||||
import net.osmand.plus.LockableViewPager;
|
import net.osmand.plus.LockableViewPager;
|
||||||
import net.osmand.plus.settings.backend.OsmAndAppCustomization;
|
|
||||||
import net.osmand.plus.OsmandApplication;
|
import net.osmand.plus.OsmandApplication;
|
||||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
import net.osmand.plus.mapmarkers.CoordinateInputDialogFragment;
|
import net.osmand.plus.mapmarkers.CoordinateInputDialogFragment;
|
||||||
import net.osmand.plus.measurementtool.GpxData;
|
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.TrackBitmapDrawer.TrackBitmapDrawerListener;
|
||||||
import net.osmand.plus.myplaces.TrackPointFragment;
|
import net.osmand.plus.myplaces.TrackPointFragment;
|
||||||
import net.osmand.plus.myplaces.TrackSegmentFragment;
|
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 net.osmand.plus.views.AddGpxPointBottomSheetHelper.NewGpxPoint;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -136,14 +135,9 @@ public class TrackActivity extends TabActivity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addNewGpxData(GpxData.ActionType actionType) {
|
public void addNewGpxData() {
|
||||||
addNewGpxData(actionType, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addNewGpxData(GpxData.ActionType actionType, TrkSegment segment) {
|
|
||||||
GPXFile gpxFile = getGpx();
|
GPXFile gpxFile = getGpx();
|
||||||
QuadRect rect = getRect();
|
GpxData gpxData = new GpxData(gpxFile);
|
||||||
GpxData gpxData = new GpxData(gpxFile, rect, actionType, segment);
|
|
||||||
WptPt pointToShow = gpxFile != null ? gpxFile.findPointToShow() : null;
|
WptPt pointToShow = gpxFile != null ? gpxFile.findPointToShow() : null;
|
||||||
if (pointToShow != null) {
|
if (pointToShow != null) {
|
||||||
LatLon location = new LatLon(pointToShow.getLatitude(), pointToShow.getLongitude());
|
LatLon location = new LatLon(pointToShow.getLatitude(), pointToShow.getLongitude());
|
||||||
|
@ -154,7 +148,6 @@ public class TrackActivity extends TabActivity {
|
||||||
false,
|
false,
|
||||||
gpxData
|
gpxData
|
||||||
);
|
);
|
||||||
|
|
||||||
MapActivity.launchMapActivityMoveToTop(this);
|
MapActivity.launchMapActivityMoveToTop(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import androidx.fragment.app.FragmentActivity;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
|
||||||
import net.osmand.AndroidUtils;
|
import net.osmand.AndroidUtils;
|
||||||
|
import net.osmand.GPXUtilities.WptPt;
|
||||||
import net.osmand.LocationsHolder;
|
import net.osmand.LocationsHolder;
|
||||||
import net.osmand.PlatformUtil;
|
import net.osmand.PlatformUtil;
|
||||||
import net.osmand.ResultMatcher;
|
import net.osmand.ResultMatcher;
|
||||||
|
@ -27,11 +28,18 @@ import net.osmand.plus.activities.MapActivity;
|
||||||
import net.osmand.plus.base.ContextMenuScrollFragment;
|
import net.osmand.plus.base.ContextMenuScrollFragment;
|
||||||
import net.osmand.plus.helpers.AndroidUiHelper;
|
import net.osmand.plus.helpers.AndroidUiHelper;
|
||||||
import net.osmand.plus.routing.GpxApproximator;
|
import net.osmand.plus.routing.GpxApproximator;
|
||||||
|
import net.osmand.plus.routing.GpxApproximator.GpxApproximationProgressCallback;
|
||||||
import net.osmand.plus.settings.backend.ApplicationMode;
|
import net.osmand.plus.settings.backend.ApplicationMode;
|
||||||
import net.osmand.router.RoutePlannerFrontEnd.GpxRouteApproximation;
|
import net.osmand.router.RoutePlannerFrontEnd.GpxRouteApproximation;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
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.ProfileCard.ProfileCardListener;
|
||||||
import static net.osmand.plus.measurementtool.SliderCard.SliderCardListener;
|
import static net.osmand.plus.measurementtool.SliderCard.SliderCardListener;
|
||||||
|
|
||||||
|
@ -49,8 +57,11 @@ public class GpxApproximationFragment extends ContextMenuScrollFragment
|
||||||
private ApplicationMode snapToRoadAppMode = ApplicationMode.CAR;
|
private ApplicationMode snapToRoadAppMode = ApplicationMode.CAR;
|
||||||
private int distanceThreshold = 50;
|
private int distanceThreshold = 50;
|
||||||
private boolean applyApproximation;
|
private boolean applyApproximation;
|
||||||
|
private GpxApproximationProgressCallback approximationProgress;
|
||||||
|
|
||||||
|
private List<LocationsHolder> locationsHolders;
|
||||||
|
private final Map<LocationsHolder, GpxRouteApproximation> resultMap = new HashMap<>();
|
||||||
|
|
||||||
private LocationsHolder locationsHolder;
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private GpxApproximator gpxApproximator;
|
private GpxApproximator gpxApproximator;
|
||||||
private ProgressBar progressBar;
|
private ProgressBar progressBar;
|
||||||
|
@ -119,44 +130,26 @@ public class GpxApproximationFragment extends ContextMenuScrollFragment
|
||||||
distanceThreshold = savedInstanceState.getInt(DISTANCE_THRESHOLD_KEY);
|
distanceThreshold = savedInstanceState.getInt(DISTANCE_THRESHOLD_KEY);
|
||||||
snapToRoadAppMode = ApplicationMode.valueOfStringKey(
|
snapToRoadAppMode = ApplicationMode.valueOfStringKey(
|
||||||
savedInstanceState.getString(SNAP_TO_ROAD_APP_MODE_STRING_KEY), ApplicationMode.CAR);
|
savedInstanceState.getString(SNAP_TO_ROAD_APP_MODE_STRING_KEY), ApplicationMode.CAR);
|
||||||
try {
|
|
||||||
gpxApproximator = new GpxApproximator(requireMyApplication(), snapToRoadAppMode, distanceThreshold, locationsHolder);
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.error(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
gpxApproximator = new GpxApproximator(requireMyApplication(), locationsHolder);
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.error(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
approximationProgress = new GpxApproximationProgressCallback() {
|
||||||
|
|
||||||
if (gpxApproximator != null) {
|
@Override
|
||||||
gpxApproximator.setApproximationProgress(new GpxApproximator.GpxApproximationProgressCallback() {
|
public void start(GpxApproximator approximator) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start() {
|
public void updateProgress(GpxApproximator approximator, int progress) {
|
||||||
if (isResumed()) {
|
if (isResumed() && approximator == GpxApproximationFragment.this.gpxApproximator) {
|
||||||
startProgress();
|
float partSize = 100f / locationsHolders.size();
|
||||||
}
|
float p = resultMap.size() * partSize + (progress / 100f) * partSize;
|
||||||
|
GpxApproximationFragment.this.updateProgress((int) p);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateProgress(int progress) {
|
public void finish(GpxApproximator approximator) {
|
||||||
if (isResumed()) {
|
}
|
||||||
GpxApproximationFragment.this.updateProgress(progress);
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void finish() {
|
|
||||||
if (isResumed()) {
|
|
||||||
finishProgress();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
applyButton = mainView.findViewById(R.id.right_bottom_button);
|
applyButton = mainView.findViewById(R.id.right_bottom_button);
|
||||||
cancelButton = mainView.findViewById(R.id.dismiss_button);
|
cancelButton = mainView.findViewById(R.id.dismiss_button);
|
||||||
|
@ -180,7 +173,7 @@ public class GpxApproximationFragment extends ContextMenuScrollFragment
|
||||||
}
|
}
|
||||||
runLayoutListener();
|
runLayoutListener();
|
||||||
|
|
||||||
calculateGpxApproximation();
|
calculateGpxApproximation(true);
|
||||||
|
|
||||||
return mainView;
|
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() {
|
private void updateCardsLayout() {
|
||||||
View mainView = getMainView();
|
View mainView = getMainView();
|
||||||
if (mainView != null) {
|
if (mainView != null) {
|
||||||
|
@ -299,13 +306,17 @@ public class GpxApproximationFragment extends ContextMenuScrollFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void showInstance(@NonNull FragmentManager fm, @Nullable Fragment targetFragment,
|
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 {
|
try {
|
||||||
if (!fm.isStateSaved()) {
|
if (!fm.isStateSaved()) {
|
||||||
GpxApproximationFragment fragment = new GpxApproximationFragment();
|
GpxApproximationFragment fragment = new GpxApproximationFragment();
|
||||||
fragment.setRetainInstance(true);
|
fragment.setRetainInstance(true);
|
||||||
fragment.setTargetFragment(targetFragment, REQUEST_CODE);
|
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);
|
fragment.setSnapToRoadAppMode(appMode);
|
||||||
fm.beginTransaction()
|
fm.beginTransaction()
|
||||||
.replace(R.id.fragmentContainer, fragment, TAG)
|
.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) {
|
if (gpxApproximator != null) {
|
||||||
try {
|
try {
|
||||||
|
this.gpxApproximator = gpxApproximator;
|
||||||
gpxApproximator.setMode(snapToRoadAppMode);
|
gpxApproximator.setMode(snapToRoadAppMode);
|
||||||
gpxApproximator.setPointApproximation(distanceThreshold);
|
gpxApproximator.setPointApproximation(distanceThreshold);
|
||||||
approximateGpx();
|
approximateGpx(gpxApproximator);
|
||||||
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error(e.getMessage(), e);
|
LOG.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSliderChange(int sliderValue) {
|
public void onSliderChange(int sliderValue) {
|
||||||
if (distanceThreshold != sliderValue) {
|
if (distanceThreshold != sliderValue) {
|
||||||
distanceThreshold = sliderValue;
|
distanceThreshold = sliderValue;
|
||||||
calculateGpxApproximation();
|
calculateGpxApproximation(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onProfileSelect(ApplicationMode applicationMode) {
|
public void onProfileSelect(ApplicationMode applicationMode) {
|
||||||
if (setSnapToRoadAppMode(applicationMode)) {
|
if (setSnapToRoadAppMode(applicationMode)) {
|
||||||
calculateGpxApproximation();
|
calculateGpxApproximation(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,12 +392,12 @@ public class GpxApproximationFragment extends ContextMenuScrollFragment
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LocationsHolder getLocationsHolder() {
|
public List<LocationsHolder> getLocationsHolders() {
|
||||||
return locationsHolder;
|
return locationsHolders;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLocationsHolder(LocationsHolder locationsHolder) {
|
public void setLocationsHolders(List<LocationsHolder> locationsHolders) {
|
||||||
this.locationsHolder = locationsHolder;
|
this.locationsHolders = locationsHolders;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startProgress() {
|
public void startProgress() {
|
||||||
|
@ -393,35 +422,58 @@ public class GpxApproximationFragment extends ContextMenuScrollFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void approximateGpx() {
|
private void approximateGpx(@NonNull final GpxApproximator gpxApproximator) {
|
||||||
if (gpxApproximator != null) {
|
onApproximationStarted();
|
||||||
setApplyButtonEnabled(false);
|
gpxApproximator.calculateGpxApproximation(new ResultMatcher<GpxRouteApproximation>() {
|
||||||
gpxApproximator.calculateGpxApproximation(new ResultMatcher<GpxRouteApproximation>() {
|
@Override
|
||||||
@Override
|
public boolean publish(final GpxRouteApproximation gpxApproximation) {
|
||||||
public boolean publish(final GpxRouteApproximation gpxApproximation) {
|
OsmandApplication app = getMyApplication();
|
||||||
OsmandApplication app = getMyApplication();
|
if (app != null) {
|
||||||
if (app != null) {
|
app.runInUIThread(new Runnable() {
|
||||||
app.runInUIThread(new Runnable() {
|
@Override
|
||||||
@Override
|
public void run() {
|
||||||
public void run() {
|
if (!gpxApproximator.isCancelled()) {
|
||||||
Fragment fragment = getTargetFragment();
|
if (gpxApproximation != null) {
|
||||||
if (fragment instanceof GpxApproximationFragmentListener) {
|
resultMap.put(gpxApproximator.getLocationsHolder(), gpxApproximation);
|
||||||
((GpxApproximationFragmentListener) fragment).onGpxApproximationDone(gpxApproximation, gpxApproximator.getMode());
|
}
|
||||||
|
if (!calculateGpxApproximation(false)) {
|
||||||
|
onApproximationFinished();
|
||||||
}
|
}
|
||||||
setApplyButtonEnabled(gpxApproximation != null);
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
return true;
|
});
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isCancelled() {
|
public boolean isCancelled() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
@Override
|
||||||
|
@ -431,7 +483,7 @@ public class GpxApproximationFragment extends ContextMenuScrollFragment
|
||||||
|
|
||||||
public interface GpxApproximationFragmentListener {
|
public interface GpxApproximationFragmentListener {
|
||||||
|
|
||||||
void onGpxApproximationDone(GpxRouteApproximation gpxApproximation, ApplicationMode mode);
|
void onGpxApproximationDone(List<GpxRouteApproximation> gpxApproximations, List<List<WptPt>> pointsList, ApplicationMode mode);
|
||||||
|
|
||||||
void onApplyGpxApproximation();
|
void onApplyGpxApproximation();
|
||||||
|
|
||||||
|
|
|
@ -1,35 +1,20 @@
|
||||||
package net.osmand.plus.measurementtool;
|
package net.osmand.plus.measurementtool;
|
||||||
|
|
||||||
import net.osmand.GPXUtilities.GPXFile;
|
import net.osmand.GPXUtilities.GPXFile;
|
||||||
import net.osmand.GPXUtilities.TrkSegment;
|
|
||||||
import net.osmand.data.QuadRect;
|
import net.osmand.data.QuadRect;
|
||||||
|
|
||||||
public class GpxData {
|
public class GpxData {
|
||||||
|
|
||||||
public enum ActionType {
|
private final GPXFile gpxFile;
|
||||||
ADD_SEGMENT,
|
private final QuadRect rect;
|
||||||
ADD_ROUTE_POINTS,
|
|
||||||
EDIT_SEGMENT,
|
|
||||||
OVERWRITE_SEGMENT
|
|
||||||
}
|
|
||||||
|
|
||||||
private GPXFile gpxFile;
|
public GpxData(GPXFile gpxFile) {
|
||||||
private TrkSegment trkSegment;
|
|
||||||
private QuadRect rect;
|
|
||||||
private ActionType actionType;
|
|
||||||
|
|
||||||
public GpxData(GPXFile gpxFile, QuadRect rect, ActionType actionType, TrkSegment trkSegment) {
|
|
||||||
this.gpxFile = gpxFile;
|
this.gpxFile = gpxFile;
|
||||||
this.rect = rect;
|
if (gpxFile != null) {
|
||||||
this.actionType = actionType;
|
this.rect = gpxFile.getRect();
|
||||||
this.trkSegment = trkSegment;
|
} 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() {
|
public GPXFile getGpxFile() {
|
||||||
|
@ -39,12 +24,4 @@ public class GpxData {
|
||||||
public QuadRect getRect() {
|
public QuadRect getRect() {
|
||||||
return rect;
|
return rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActionType getActionType() {
|
|
||||||
return actionType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TrkSegment getTrkSegment() {
|
|
||||||
return trkSegment;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,9 +53,11 @@ public class MeasurementEditingContext {
|
||||||
private final MeasurementCommandManager commandManager = new MeasurementCommandManager();
|
private final MeasurementCommandManager commandManager = new MeasurementCommandManager();
|
||||||
|
|
||||||
private final TrkSegment before = new TrkSegment();
|
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 final TrkSegment after = new TrkSegment();
|
||||||
private TrkSegment afterCacheForSnap;
|
private List<TrkSegment> afterSegments = new ArrayList<>();
|
||||||
|
private List<TrkSegment> afterSegmentsForSnap;
|
||||||
|
|
||||||
private GpxData gpxData;
|
private GpxData gpxData;
|
||||||
|
|
||||||
|
@ -79,11 +81,11 @@ public class MeasurementEditingContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class RoadSegmentData {
|
public static class RoadSegmentData {
|
||||||
private ApplicationMode appMode;
|
private final ApplicationMode appMode;
|
||||||
private WptPt start;
|
private final WptPt start;
|
||||||
private WptPt end;
|
private final WptPt end;
|
||||||
private List<WptPt> points;
|
private final List<WptPt> points;
|
||||||
private List<RouteSegmentResult> segments;
|
private final List<RouteSegmentResult> segments;
|
||||||
private double distance;
|
private double distance;
|
||||||
|
|
||||||
public RoadSegmentData(@NonNull ApplicationMode appMode, @NonNull WptPt start, @NonNull WptPt end,
|
public RoadSegmentData(@NonNull ApplicationMode appMode, @NonNull WptPt start, @NonNull WptPt end,
|
||||||
|
@ -156,8 +158,8 @@ public class MeasurementEditingContext {
|
||||||
return inAddPointMode;
|
return inAddPointMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateCacheForSnap() {
|
public void updateSegmentsForSnap() {
|
||||||
updateCacheForSnap(true);
|
updateSegmentsForSnap(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSelectedPointPosition() {
|
public int getSelectedPointPosition() {
|
||||||
|
@ -188,10 +190,10 @@ public class MeasurementEditingContext {
|
||||||
this.inApproximationMode = inApproximationMode;
|
this.inApproximationMode = inApproximationMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<WptPt> getOriginalTrackPointList() {
|
public List<List<WptPt>> getOriginalSegmentPointsList() {
|
||||||
MeasurementModeCommand command = commandManager.getLastCommand();
|
MeasurementModeCommand command = commandManager.getLastCommand();
|
||||||
if (command.getType() == APPROXIMATE_POINTS) {
|
if (command.getType() == APPROXIMATE_POINTS) {
|
||||||
return ((ApplyGpxApproximationCommand) command).getPoints();
|
return ((ApplyGpxApproximationCommand) command).getOriginalSegmentPointsList();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -213,10 +215,6 @@ public class MeasurementEditingContext {
|
||||||
return gpxData != null && gpxData.getGpxFile() != null && gpxData.getGpxFile().hasRtePt();
|
return gpxData != null && gpxData.getGpxFile() != null && gpxData.getGpxFile().hasRtePt();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasSavedRoute() {
|
|
||||||
return gpxData != null && gpxData.getGpxFile() != null && gpxData.getGpxFile().hasRoute();
|
|
||||||
}
|
|
||||||
|
|
||||||
public CalculationMode getLastCalculationMode() {
|
public CalculationMode getLastCalculationMode() {
|
||||||
return lastCalculationMode;
|
return lastCalculationMode;
|
||||||
}
|
}
|
||||||
|
@ -252,7 +250,7 @@ public class MeasurementEditingContext {
|
||||||
if (appMode != MeasurementEditingContext.DEFAULT_APP_MODE || !pair.first.lastPoint || !pair.second.firstPoint) {
|
if (appMode != MeasurementEditingContext.DEFAULT_APP_MODE || !pair.first.lastPoint || !pair.second.firstPoint) {
|
||||||
double localDist = MapUtils.getDistance(pair.first.getLatitude(), pair.first.getLongitude(),
|
double localDist = MapUtils.getDistance(pair.first.getLatitude(), pair.first.getLongitude(),
|
||||||
pair.second.getLatitude(), pair.second.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) {
|
pair.first.ele != 0 && pair.second.ele != 0) {
|
||||||
double h = Math.abs(pair.first.ele - pair.second.ele);
|
double h = Math.abs(pair.first.ele - pair.second.ele);
|
||||||
localDist = Math.sqrt(localDist * localDist + h * h);
|
localDist = Math.sqrt(localDist * localDist + h * h);
|
||||||
|
@ -279,28 +277,70 @@ public class MeasurementEditingContext {
|
||||||
return !roadSegmentData.isEmpty();
|
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 void clearSnappedToRoadPoints() {
|
public void clearSnappedToRoadPoints() {
|
||||||
roadSegmentData.clear();
|
roadSegmentData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
TrkSegment getBeforeTrkSegmentLine() {
|
List<TrkSegment> getBeforeTrkSegmentLine() {
|
||||||
if (beforeCacheForSnap != null) {
|
if (beforeSegmentsForSnap != null) {
|
||||||
return beforeCacheForSnap;
|
return beforeSegmentsForSnap;
|
||||||
}
|
}
|
||||||
return before;
|
return beforeSegments;
|
||||||
}
|
}
|
||||||
|
|
||||||
TrkSegment getAfterTrkSegmentLine() {
|
List<TrkSegment> getAfterTrkSegmentLine() {
|
||||||
if (afterCacheForSnap != null) {
|
if (afterSegmentsForSnap != null) {
|
||||||
return afterCacheForSnap;
|
return afterSegmentsForSnap;
|
||||||
}
|
}
|
||||||
return after;
|
return afterSegments;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<WptPt> getPoints() {
|
public List<WptPt> getPoints() {
|
||||||
return getBeforePoints();
|
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 = ApplicationMode.GAP.getStringKey().equals(profileType);
|
||||||
|
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() {
|
List<WptPt> getBeforePoints() {
|
||||||
return before.points;
|
return before.points;
|
||||||
}
|
}
|
||||||
|
@ -321,22 +361,43 @@ public class MeasurementEditingContext {
|
||||||
after.points.clear();
|
after.points.clear();
|
||||||
before.points.addAll(points.subList(0, position));
|
before.points.addAll(points.subList(0, position));
|
||||||
after.points.addAll(points.subList(position, points.size()));
|
after.points.addAll(points.subList(position, points.size()));
|
||||||
updateCacheForSnap(true);
|
updateSegmentsForSnap(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addPoint(WptPt pt) {
|
public void addPoint(WptPt pt) {
|
||||||
before.points.add(pt);
|
before.points.add(pt);
|
||||||
updateCacheForSnap(false);
|
updateSegmentsForSnap(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addPoint(int position, WptPt pt) {
|
public void addPoint(int position, WptPt pt) {
|
||||||
before.points.add(position, pt);
|
before.points.add(position, pt);
|
||||||
updateCacheForSnap(false);
|
updateSegmentsForSnap(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addPoints(List<WptPt> points) {
|
public void addPoints(List<WptPt> points) {
|
||||||
before.points.addAll(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) {
|
public WptPt removePoint(int position, boolean updateSnapToRoad) {
|
||||||
|
@ -345,7 +406,7 @@ public class MeasurementEditingContext {
|
||||||
}
|
}
|
||||||
WptPt pt = before.points.remove(position);
|
WptPt pt = before.points.remove(position);
|
||||||
if (updateSnapToRoad) {
|
if (updateSnapToRoad) {
|
||||||
updateCacheForSnap(false);
|
updateSegmentsForSnap(false);
|
||||||
}
|
}
|
||||||
return pt;
|
return pt;
|
||||||
}
|
}
|
||||||
|
@ -368,15 +429,15 @@ public class MeasurementEditingContext {
|
||||||
|
|
||||||
public void clearBeforeSegments() {
|
public void clearBeforeSegments() {
|
||||||
before.points.clear();
|
before.points.clear();
|
||||||
if (beforeCacheForSnap != null) {
|
if (beforeSegmentsForSnap != null) {
|
||||||
beforeCacheForSnap.points.clear();
|
beforeSegmentsForSnap.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearAfterSegments() {
|
public void clearAfterSegments() {
|
||||||
after.points.clear();
|
after.points.clear();
|
||||||
if (afterCacheForSnap != null) {
|
if (afterSegmentsForSnap != null) {
|
||||||
afterCacheForSnap.points.clear();
|
afterSegmentsForSnap.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,8 +485,10 @@ public class MeasurementEditingContext {
|
||||||
List<Pair<WptPt, WptPt>> res = new ArrayList<>();
|
List<Pair<WptPt, WptPt>> res = new ArrayList<>();
|
||||||
for (List<WptPt> points : Arrays.asList(before.points, after.points)) {
|
for (List<WptPt> points : Arrays.asList(before.points, after.points)) {
|
||||||
for (int i = 0; i < points.size() - 1; i++) {
|
for (int i = 0; i < points.size() - 1; i++) {
|
||||||
Pair<WptPt, WptPt> pair = new Pair<>(points.get(i), points.get(i + 1));
|
WptPt startPoint = points.get(i);
|
||||||
if (roadSegmentData.get(pair) == null) {
|
WptPt endPoint = points.get(i + 1);
|
||||||
|
Pair<WptPt, WptPt> pair = new Pair<>(startPoint, endPoint);
|
||||||
|
if (roadSegmentData.get(pair) == null && startPoint.hasProfile()) {
|
||||||
res.add(pair);
|
res.add(pair);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -433,98 +496,135 @@ public class MeasurementEditingContext {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void recreateCacheForSnap(TrkSegment cache, TrkSegment original, boolean calculateIfNeeded) {
|
private void recreateSegments(List<TrkSegment> segments, List<TrkSegment> segmentsForSnap, List<WptPt> points, boolean calculateIfNeeded) {
|
||||||
boolean hasDefaultModeOnly = true;
|
List<Integer> roadSegmentIndexes = new ArrayList<>();
|
||||||
if (original.points.size() > 1) {
|
TrkSegment s = new TrkSegment();
|
||||||
for (int i = 0; i < original.points.size(); i++) {
|
segments.add(s);
|
||||||
String profileType = original.points.get(i).getProfileType();
|
boolean defaultMode = true;
|
||||||
if (profileType != null && !profileType.equals(DEFAULT_APP_MODE.getStringKey())) {
|
if (points.size() > 1) {
|
||||||
hasDefaultModeOnly = false;
|
for (int i = 0; i < points.size(); i++) {
|
||||||
break;
|
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 = profileType.equals(ApplicationMode.GAP.getStringKey());
|
||||||
|
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) {
|
if (s.points.isEmpty()) {
|
||||||
for (int i = 0; i < original.points.size() - 1; i++) {
|
segments.remove(s);
|
||||||
Pair<WptPt, WptPt> pair = new Pair<>(original.points.get(i), original.points.get(i + 1));
|
}
|
||||||
RoadSegmentData data = this.roadSegmentData.get(pair);
|
if (!segments.isEmpty()) {
|
||||||
List<WptPt> pts = data != null ? data.getPoints() : null;
|
for (TrkSegment segment : segments) {
|
||||||
if (pts != null) {
|
TrkSegment segmentForSnap = new TrkSegment();
|
||||||
cache.points.addAll(pts);
|
for (int i = 0; i < segment.points.size() - 1; i++) {
|
||||||
} else {
|
Pair<WptPt, WptPt> pair = new Pair<>(segment.points.get(i), segment.points.get(i + 1));
|
||||||
if (calculateIfNeeded && !hasDefaultModeOnly) {
|
RoadSegmentData data = this.roadSegmentData.get(pair);
|
||||||
scheduleRouteCalculateIfNotEmpty();
|
List<WptPt> pts = data != null ? data.getPoints() : null;
|
||||||
|
if (pts != null) {
|
||||||
|
segmentForSnap.points.addAll(pts);
|
||||||
|
} else {
|
||||||
|
if (calculateIfNeeded && roadSegmentIndexes.contains(segmentsForSnap.size())) {
|
||||||
|
scheduleRouteCalculateIfNotEmpty();
|
||||||
|
}
|
||||||
|
segmentForSnap.points.addAll(Arrays.asList(pair.first, pair.second));
|
||||||
}
|
}
|
||||||
cache.points.addAll(Arrays.asList(pair.first, pair.second));
|
|
||||||
}
|
}
|
||||||
|
segmentsForSnap.add(segmentForSnap);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (!points.isEmpty()) {
|
||||||
cache.points.addAll(original.points);
|
TrkSegment segmentForSnap = new TrkSegment();
|
||||||
|
segmentForSnap.points.addAll(points);
|
||||||
|
segmentsForSnap.add(segmentForSnap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addPoints() {
|
void addPoints() {
|
||||||
GpxData gpxData = getGpxData();
|
GpxData gpxData = getGpxData();
|
||||||
if (gpxData == null || gpxData.getTrkSegment() == null || Algorithms.isEmpty(gpxData.getTrkSegment().points)) {
|
if (gpxData == null || gpxData.getGpxFile() == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List<WptPt> points = gpxData.getTrkSegment().points;
|
List<TrkSegment> segments = gpxData.getGpxFile().getNonEmptyTrkSegments(false);
|
||||||
if (isTrackSnappedToRoad()) {
|
if (Algorithms.isEmpty(segments)) {
|
||||||
RouteImporter routeImporter = new RouteImporter(gpxData.getGpxFile());
|
return;
|
||||||
List<RouteSegmentResult> segments = routeImporter.importRoute();
|
}
|
||||||
List<WptPt> routePoints = gpxData.getGpxFile().getRoutePoints();
|
for (int si = 0; si < segments.size(); si++) {
|
||||||
int prevPointIndex = 0;
|
TrkSegment segment = segments.get(si);
|
||||||
if (routePoints.isEmpty() && points.size() > 1) {
|
List<WptPt> points = segment.points;
|
||||||
routePoints.add(points.get(0));
|
if (segment.hasRoute()) {
|
||||||
routePoints.add(points.get(points.size() - 1));
|
RouteImporter routeImporter = new RouteImporter(segment);
|
||||||
}
|
List<RouteSegmentResult> routeSegments = routeImporter.importRoute();
|
||||||
for (int i = 0; i < routePoints.size() - 1; i++) {
|
List<WptPt> routePoints = gpxData.getGpxFile().getRoutePoints(si);
|
||||||
Pair<WptPt, WptPt> pair = new Pair<>(routePoints.get(i), routePoints.get(i + 1));
|
int prevPointIndex = 0;
|
||||||
int startIndex = pair.first.getTrkPtIndex();
|
if (routePoints.isEmpty() && points.size() > 1) {
|
||||||
if (startIndex < 0 || startIndex < prevPointIndex || startIndex >= points.size()) {
|
routePoints.add(points.get(0));
|
||||||
startIndex = findPointIndex(pair.first, points, prevPointIndex);
|
routePoints.add(points.get(points.size() - 1));
|
||||||
}
|
}
|
||||||
int endIndex = pair.second.getTrkPtIndex();
|
for (int i = 0; i < routePoints.size() - 1; i++) {
|
||||||
if (endIndex < 0 || endIndex < startIndex || endIndex >= points.size()) {
|
Pair<WptPt, WptPt> pair = new Pair<>(routePoints.get(i), routePoints.get(i + 1));
|
||||||
endIndex = findPointIndex(pair.second, points, startIndex);
|
int startIndex = pair.first.getTrkPtIndex();
|
||||||
}
|
if (startIndex < 0 || startIndex < prevPointIndex || startIndex >= points.size()) {
|
||||||
if (startIndex >= 0 && endIndex >= 0) {
|
startIndex = findPointIndex(pair.first, points, prevPointIndex);
|
||||||
List<WptPt> pairPoints = new ArrayList<>();
|
|
||||||
for (int j = startIndex; j < endIndex && j < points.size(); j++) {
|
|
||||||
pairPoints.add(points.get(j));
|
|
||||||
prevPointIndex = j;
|
|
||||||
}
|
}
|
||||||
if (points.size() > prevPointIndex + 1) {
|
int endIndex = pair.second.getTrkPtIndex();
|
||||||
pairPoints.add(points.get(prevPointIndex + 1));
|
if (endIndex < 0 || endIndex < startIndex || endIndex >= points.size()) {
|
||||||
|
endIndex = findPointIndex(pair.second, points, startIndex);
|
||||||
}
|
}
|
||||||
Iterator<RouteSegmentResult> it = segments.iterator();
|
if (startIndex >= 0 && endIndex >= 0) {
|
||||||
int k = endIndex - startIndex - 1;
|
List<WptPt> pairPoints = new ArrayList<>();
|
||||||
List<RouteSegmentResult> pairSegments = new ArrayList<>();
|
for (int j = startIndex; j < endIndex && j < points.size(); j++) {
|
||||||
if (k == 0 && !segments.isEmpty()) {
|
pairPoints.add(points.get(j));
|
||||||
pairSegments.add(segments.remove(0));
|
prevPointIndex = j;
|
||||||
} else {
|
|
||||||
while (it.hasNext() && k > 0) {
|
|
||||||
RouteSegmentResult s = it.next();
|
|
||||||
pairSegments.add(s);
|
|
||||||
it.remove();
|
|
||||||
k -= Math.abs(s.getEndPointIndex() - s.getStartPointIndex());
|
|
||||||
}
|
}
|
||||||
|
if (points.size() > prevPointIndex + 1) {
|
||||||
|
pairPoints.add(points.get(prevPointIndex + 1));
|
||||||
|
}
|
||||||
|
Iterator<RouteSegmentResult> it = routeSegments.iterator();
|
||||||
|
int k = endIndex - startIndex - 1;
|
||||||
|
List<RouteSegmentResult> pairSegments = new ArrayList<>();
|
||||||
|
if (k == 0 && !routeSegments.isEmpty()) {
|
||||||
|
pairSegments.add(routeSegments.remove(0));
|
||||||
|
} else {
|
||||||
|
while (it.hasNext() && k > 0) {
|
||||||
|
RouteSegmentResult s = it.next();
|
||||||
|
pairSegments.add(s);
|
||||||
|
it.remove();
|
||||||
|
k -= Math.abs(s.getEndPointIndex() - s.getStartPointIndex());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ApplicationMode appMode = ApplicationMode.valueOfStringKey(pair.first.getProfileType(), DEFAULT_APP_MODE);
|
||||||
|
roadSegmentData.put(pair, new RoadSegmentData(appMode, pair.first, pair.second, pairPoints, pairSegments));
|
||||||
}
|
}
|
||||||
ApplicationMode appMode = ApplicationMode.valueOfStringKey(pair.first.getProfileType(), DEFAULT_APP_MODE);
|
}
|
||||||
roadSegmentData.put(pair, new RoadSegmentData(appMode, pair.first, pair.second, pairPoints, pairSegments));
|
if (!routePoints.isEmpty() && si < segments.size() - 1) {
|
||||||
|
routePoints.get(routePoints.size() - 1).setProfileType(ApplicationMode.GAP.getStringKey());
|
||||||
|
}
|
||||||
|
addPoints(routePoints);
|
||||||
|
} else {
|
||||||
|
addPoints(points);
|
||||||
|
if (!points.isEmpty() && si < segments.size() - 1) {
|
||||||
|
points.get(points.size() - 1).setProfileType(ApplicationMode.GAP.getStringKey());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addPoints(routePoints);
|
|
||||||
} else {
|
|
||||||
addPoints(points);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)) {
|
if (gpxApproximation == null || Algorithms.isEmpty(gpxApproximation.finalPoints) || Algorithms.isEmpty(gpxApproximation.result)) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
roadSegmentData.clear();
|
|
||||||
List<WptPt> routePoints = new ArrayList<>();
|
List<WptPt> routePoints = new ArrayList<>();
|
||||||
List<GpxPoint> gpxPoints = gpxApproximation.finalPoints;
|
List<GpxPoint> gpxPoints = gpxApproximation.finalPoints;
|
||||||
for (int i = 0; i < gpxPoints.size(); i++) {
|
for (int i = 0; i < gpxPoints.size(); i++) {
|
||||||
|
@ -566,7 +666,13 @@ public class MeasurementEditingContext {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addPoints(routePoints);
|
WptPt lastOriginalPoint = originalPoints.get(originalPoints.size() - 1);
|
||||||
|
WptPt lastRoutePoint = routePoints.get(routePoints.size() - 1);
|
||||||
|
if (ApplicationMode.GAP.getStringKey().equals(lastOriginalPoint.getProfileType())) {
|
||||||
|
lastRoutePoint.setProfileType(ApplicationMode.GAP.getStringKey());
|
||||||
|
}
|
||||||
|
replacePoints(originalPoints, routePoints);
|
||||||
|
return routePoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isLastGpxPoint(List<GpxPoint> gpxPoints, int index) {
|
private boolean isLastGpxPoint(List<GpxPoint> gpxPoints, int index) {
|
||||||
|
@ -624,24 +730,21 @@ public class MeasurementEditingContext {
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isTrackSnappedToRoad() {
|
private void updateSegmentsForSnap(boolean both) {
|
||||||
GpxData gpxData = getGpxData();
|
recreateSegments(beforeSegments = new ArrayList<>(),
|
||||||
return gpxData != null && gpxData.getTrkSegment() != null
|
beforeSegmentsForSnap = new ArrayList<>(), before.points, true);
|
||||||
&& !gpxData.getTrkSegment().points.isEmpty()
|
|
||||||
&& gpxData.getGpxFile().hasRoute();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateCacheForSnap(boolean both) {
|
|
||||||
recreateCacheForSnap(beforeCacheForSnap = new TrkSegment(), before, true);
|
|
||||||
if (both) {
|
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) {
|
private void updateSegmentsForSnap(boolean both, boolean calculateIfNeeded) {
|
||||||
recreateCacheForSnap(beforeCacheForSnap = new TrkSegment(), before, calculateIfNeeded);
|
recreateSegments(beforeSegments = new ArrayList<>(),
|
||||||
|
beforeSegmentsForSnap = new ArrayList<>(), before.points, calculateIfNeeded);
|
||||||
if (both) {
|
if (both) {
|
||||||
recreateCacheForSnap(afterCacheForSnap = new TrkSegment(), after, calculateIfNeeded);
|
recreateSegments(afterSegments = new ArrayList<>(),
|
||||||
|
afterSegmentsForSnap = new ArrayList<>(), after.points, calculateIfNeeded);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -694,7 +797,7 @@ public class MeasurementEditingContext {
|
||||||
int pairs = pointsToCalculateSize;
|
int pairs = pointsToCalculateSize;
|
||||||
if (pairs != 0) {
|
if (pairs != 0) {
|
||||||
float pairProgress = 100f / pairs;
|
float pairProgress = 100f / pairs;
|
||||||
progress = (int)(calculatedPairs * pairProgress + (float) progress / pairs);
|
progress = (int) (calculatedPairs * pairProgress + (float) progress / pairs);
|
||||||
}
|
}
|
||||||
progressListener.updateProgress(progress);
|
progressListener.updateProgress(progress);
|
||||||
}
|
}
|
||||||
|
@ -738,7 +841,7 @@ public class MeasurementEditingContext {
|
||||||
application.runInUIThread(new Runnable() {
|
application.runInUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
updateCacheForSnap(true, false);
|
updateSegmentsForSnap(true, false);
|
||||||
progressListener.refresh();
|
progressListener.refresh();
|
||||||
RouteCalculationParams params = getParams(false);
|
RouteCalculationParams params = getParams(false);
|
||||||
if (params != null) {
|
if (params != null) {
|
||||||
|
@ -753,34 +856,41 @@ public class MeasurementEditingContext {
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<WptPt> getRoutePoints() {
|
public List<List<WptPt>> getRoutePoints() {
|
||||||
List<WptPt> res = new ArrayList<>();
|
List<List<WptPt>> res = new ArrayList<>();
|
||||||
List<WptPt> points = new ArrayList<>(before.points);
|
List<WptPt> plainPoints = new ArrayList<>(before.points);
|
||||||
points.addAll(after.points);
|
plainPoints.addAll(after.points);
|
||||||
int size = points.size();
|
List<WptPt> points = new ArrayList<>();
|
||||||
for (int i = 0; i < size - 1; i++) {
|
for (WptPt point : plainPoints) {
|
||||||
Pair<WptPt, WptPt> pair = new Pair<>(points.get(i), points.get(i + 1));
|
if (point.getTrkPtIndex() != -1) {
|
||||||
RoadSegmentData data = this.roadSegmentData.get(pair);
|
points.add(point);
|
||||||
if (data != null) {
|
if (ApplicationMode.GAP.getStringKey().equals(point.getProfileType())) {
|
||||||
res.addAll(data.points);
|
res.add(points);
|
||||||
|
points = new ArrayList<>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!points.isEmpty()) {
|
||||||
|
res.add(points);
|
||||||
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public GPXFile exportRouteAsGpx(@NonNull String gpxName) {
|
public GPXFile exportGpx(@NonNull String gpxName) {
|
||||||
if (application == null || before.points.isEmpty() || !hasRoute()) {
|
if (application == null || before.points.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
return RouteExporter.exportRoute(gpxName, getRouteSegments(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TrkSegment getRouteSegment(int startPointIndex, int endPointIndex) {
|
||||||
List<RouteSegmentResult> route = new ArrayList<>();
|
List<RouteSegmentResult> route = new ArrayList<>();
|
||||||
List<Location> locations = new ArrayList<>();
|
List<Location> locations = new ArrayList<>();
|
||||||
before.points.get(0).setTrkPtIndex(0);
|
for (int i = startPointIndex; i < endPointIndex; i++) {
|
||||||
int size = before.points.size();
|
|
||||||
for (int i = 0; i < size - 1; i++) {
|
|
||||||
Pair<WptPt, WptPt> pair = new Pair<>(before.points.get(i), before.points.get(i + 1));
|
Pair<WptPt, WptPt> pair = new Pair<>(before.points.get(i), before.points.get(i + 1));
|
||||||
RoadSegmentData data = this.roadSegmentData.get(pair);
|
RoadSegmentData data = this.roadSegmentData.get(pair);
|
||||||
if (data != null) {
|
if (data != null && data.points != null && data.segments != null) {
|
||||||
for (WptPt pt : data.points) {
|
for (WptPt pt : data.points) {
|
||||||
Location l = new Location("");
|
Location l = new Location("");
|
||||||
l.setLatitude(pt.getLatitude());
|
l.setLatitude(pt.getLatitude());
|
||||||
|
@ -790,11 +900,42 @@ public class MeasurementEditingContext {
|
||||||
}
|
}
|
||||||
locations.add(l);
|
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);
|
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 (ApplicationMode.GAP.getStringKey().equals(pt.getProfileType())) {
|
||||||
|
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 {
|
interface SnapToRoadProgressListener {
|
||||||
|
|
|
@ -36,9 +36,7 @@ import net.osmand.AndroidUtils;
|
||||||
import net.osmand.FileUtils;
|
import net.osmand.FileUtils;
|
||||||
import net.osmand.GPXUtilities;
|
import net.osmand.GPXUtilities;
|
||||||
import net.osmand.GPXUtilities.GPXFile;
|
import net.osmand.GPXUtilities.GPXFile;
|
||||||
import net.osmand.GPXUtilities.TrkSegment;
|
|
||||||
import net.osmand.GPXUtilities.WptPt;
|
import net.osmand.GPXUtilities.WptPt;
|
||||||
import net.osmand.LocationsHolder;
|
|
||||||
import net.osmand.data.LatLon;
|
import net.osmand.data.LatLon;
|
||||||
import net.osmand.data.QuadRect;
|
import net.osmand.data.QuadRect;
|
||||||
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
|
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
|
||||||
|
@ -55,7 +53,6 @@ import net.osmand.plus.base.BaseOsmAndFragment;
|
||||||
import net.osmand.plus.base.ContextMenuFragment.MenuState;
|
import net.osmand.plus.base.ContextMenuFragment.MenuState;
|
||||||
import net.osmand.plus.helpers.AndroidUiHelper;
|
import net.osmand.plus.helpers.AndroidUiHelper;
|
||||||
import net.osmand.plus.measurementtool.GpxApproximationFragment.GpxApproximationFragmentListener;
|
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.OptionsBottomSheetDialogFragment.OptionsFragmentListener;
|
||||||
import net.osmand.plus.measurementtool.RouteBetweenPointsBottomSheetDialogFragment.RouteBetweenPointsDialogMode;
|
import net.osmand.plus.measurementtool.RouteBetweenPointsBottomSheetDialogFragment.RouteBetweenPointsDialogMode;
|
||||||
import net.osmand.plus.measurementtool.RouteBetweenPointsBottomSheetDialogFragment.RouteBetweenPointsDialogType;
|
import net.osmand.plus.measurementtool.RouteBetweenPointsBottomSheetDialogFragment.RouteBetweenPointsDialogType;
|
||||||
|
@ -140,7 +137,6 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
private static final int UNDO_MODE = 0x8;
|
private static final int UNDO_MODE = 0x8;
|
||||||
private int modes = 0x0;
|
private int modes = 0x0;
|
||||||
|
|
||||||
private boolean approximationApplied = false;
|
|
||||||
private boolean portrait;
|
private boolean portrait;
|
||||||
private boolean nightMode;
|
private boolean nightMode;
|
||||||
private int cachedMapPosition;
|
private int cachedMapPosition;
|
||||||
|
@ -150,7 +146,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
private LatLon initialPoint;
|
private LatLon initialPoint;
|
||||||
|
|
||||||
enum SaveType {
|
enum SaveType {
|
||||||
ROUTE_POINT,
|
ROUTE,
|
||||||
LINE
|
LINE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,7 +339,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
mainView.findViewById(R.id.options_button).setOnClickListener(new OnClickListener() {
|
mainView.findViewById(R.id.options_button).setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
boolean trackSnappedToRoad = editingCtx.isTrackSnappedToRoad() || editingCtx.isNewData() || approximationApplied;
|
boolean trackSnappedToRoad = !editingCtx.isApproximationNeeded();
|
||||||
OptionsBottomSheetDialogFragment.showInstance(mapActivity.getSupportFragmentManager(),
|
OptionsBottomSheetDialogFragment.showInstance(mapActivity.getSupportFragmentManager(),
|
||||||
MeasurementToolFragment.this,
|
MeasurementToolFragment.this,
|
||||||
trackSnappedToRoad,
|
trackSnappedToRoad,
|
||||||
|
@ -475,8 +471,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
updateToolbar();
|
updateToolbar();
|
||||||
|
|
||||||
final GpxData gpxData = editingCtx.getGpxData();
|
final GpxData gpxData = editingCtx.getGpxData();
|
||||||
adapter = new MeasurementToolAdapter(getMapActivity(), editingCtx.getPoints(),
|
adapter = new MeasurementToolAdapter(getMapActivity(), editingCtx.getPoints());
|
||||||
gpxData != null ? gpxData.getActionType() : null);
|
|
||||||
if (portrait) {
|
if (portrait) {
|
||||||
pointsRv = mainView.findViewById(R.id.measure_points_recycler_view);
|
pointsRv = mainView.findViewById(R.id.measure_points_recycler_view);
|
||||||
} else {
|
} else {
|
||||||
|
@ -503,7 +498,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
if (savedInstanceState == null) {
|
if (savedInstanceState == null) {
|
||||||
if (fileName != null) {
|
if (fileName != null) {
|
||||||
addNewGpxData(getGpxFile(fileName));
|
addNewGpxData(getGpxFile(fileName));
|
||||||
} else if (!editingCtx.isNewData() && !editingCtx.hasRoutePoints() && !editingCtx.hasRoute() && editingCtx.getPointsCount() > 1) {
|
} else if (editingCtx.isApproximationNeeded()) {
|
||||||
enterApproximationMode(mapActivity);
|
enterApproximationMode(mapActivity);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -536,7 +531,6 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
if (mapActivity != null) {
|
if (mapActivity != null) {
|
||||||
editingCtx.getCommandManager().setMeasurementLayer(mapActivity.getMapLayers().getMeasurementToolLayer());
|
editingCtx.getCommandManager().setMeasurementLayer(mapActivity.getMapLayers().getMeasurementToolLayer());
|
||||||
enterMeasurementMode();
|
enterMeasurementMode();
|
||||||
updateSnapToRoadControls();
|
|
||||||
if (gpxData != null && addPoints) {
|
if (gpxData != null && addPoints) {
|
||||||
if (!isUndoMode()) {
|
if (!isUndoMode()) {
|
||||||
List<WptPt> points = gpxData.getGpxFile().getRoutePoints();
|
List<WptPt> points = gpxData.getGpxFile().getRoutePoints();
|
||||||
|
@ -547,13 +541,9 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ActionType actionType = gpxData.getActionType();
|
collectPoints();
|
||||||
if (actionType == ActionType.ADD_ROUTE_POINTS) {
|
|
||||||
displayRoutePoints();
|
|
||||||
} else if (actionType == ActionType.EDIT_SEGMENT) {
|
|
||||||
displaySegmentPoints();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
updateSnapToRoadControls();
|
||||||
setMode(UNDO_MODE, false);
|
setMode(UNDO_MODE, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -638,16 +628,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
|
|
||||||
private void updateMainIcon() {
|
private void updateMainIcon() {
|
||||||
GpxData gpxData = editingCtx.getGpxData();
|
GpxData gpxData = editingCtx.getGpxData();
|
||||||
if (gpxData != null) {
|
mainIcon.setImageDrawable(getActiveIcon(gpxData != null ? R.drawable.ic_action_polygom_dark : R.drawable.ic_action_ruler));
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startSnapToRoad(boolean rememberPreviousTitle) {
|
private void startSnapToRoad(boolean rememberPreviousTitle) {
|
||||||
|
@ -659,15 +640,15 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
toolBarController.setTitle(getString(R.string.route_between_points));
|
toolBarController.setTitle(getString(R.string.route_between_points));
|
||||||
mapActivity.refreshMap();
|
mapActivity.refreshMap();
|
||||||
|
|
||||||
if (editingCtx.isNewData() || editingCtx.hasRoutePoints() || editingCtx.hasRoute() || editingCtx.getPointsCount() <= 2) {
|
if (editingCtx.isApproximationNeeded()) {
|
||||||
|
enterApproximationMode(mapActivity);
|
||||||
|
} else {
|
||||||
RouteBetweenPointsBottomSheetDialogFragment.showInstance(mapActivity.getSupportFragmentManager(),
|
RouteBetweenPointsBottomSheetDialogFragment.showInstance(mapActivity.getSupportFragmentManager(),
|
||||||
this, RouteBetweenPointsDialogType.WHOLE_ROUTE_CALCULATION,
|
this, RouteBetweenPointsDialogType.WHOLE_ROUTE_CALCULATION,
|
||||||
editingCtx.getLastCalculationMode() == CalculationMode.NEXT_SEGMENT
|
editingCtx.getLastCalculationMode() == CalculationMode.NEXT_SEGMENT
|
||||||
? RouteBetweenPointsDialogMode.SINGLE
|
? RouteBetweenPointsDialogMode.SINGLE
|
||||||
: RouteBetweenPointsDialogMode.ALL,
|
: RouteBetweenPointsDialogMode.ALL,
|
||||||
editingCtx.getAppMode());
|
editingCtx.getAppMode());
|
||||||
} else {
|
|
||||||
enterApproximationMode(mapActivity);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -676,12 +657,11 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
MapActivity mapActivity = getMapActivity();
|
MapActivity mapActivity = getMapActivity();
|
||||||
if (mapActivity != null) {
|
if (mapActivity != null) {
|
||||||
if (editingCtx.getPointsCount() > 0) {
|
if (editingCtx.getPointsCount() > 0) {
|
||||||
GpxData gpxData = editingCtx.getGpxData();
|
if (editingCtx.isNewData() || isInEditMode()) {
|
||||||
if (editingCtx.isNewData() || (isInEditMode() && gpxData.getActionType() == ActionType.EDIT_SEGMENT)) {
|
|
||||||
if (showDialog) {
|
if (showDialog) {
|
||||||
openSaveAsNewTrackMenu(mapActivity);
|
openSaveAsNewTrackMenu(mapActivity);
|
||||||
} else {
|
} else {
|
||||||
saveNewGpx(null, getSuggestedFileName(), true, false, finalSaveAction);
|
saveNewGpx("", getSuggestedFileName(), true, false, finalSaveAction);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
addToGpx(mapActivity, finalSaveAction);
|
addToGpx(mapActivity, finalSaveAction);
|
||||||
|
@ -695,6 +675,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
@Override
|
@Override
|
||||||
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
MapActivity mapActivity = getMapActivity();
|
||||||
switch (requestCode) {
|
switch (requestCode) {
|
||||||
case SnapTrackWarningFragment.REQUEST_CODE:
|
case SnapTrackWarningFragment.REQUEST_CODE:
|
||||||
switch (resultCode) {
|
switch (resultCode) {
|
||||||
|
@ -705,14 +686,16 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
updateToolbar();
|
updateToolbar();
|
||||||
break;
|
break;
|
||||||
case SnapTrackWarningFragment.CONTINUE_RESULT_CODE:
|
case SnapTrackWarningFragment.CONTINUE_RESULT_CODE:
|
||||||
MapActivity mapActivity = getMapActivity();
|
|
||||||
if (mapActivity != null) {
|
if (mapActivity != null) {
|
||||||
ApplicationMode mode = editingCtx.getAppMode();
|
ApplicationMode mode = editingCtx.getAppMode();
|
||||||
if (mode == ApplicationMode.DEFAULT || "public_transport".equals(mode.getRoutingProfile())) {
|
if (mode == ApplicationMode.DEFAULT || "public_transport".equals(mode.getRoutingProfile())) {
|
||||||
mode = null;
|
mode = null;
|
||||||
}
|
}
|
||||||
GpxApproximationFragment.showInstance(mapActivity.getSupportFragmentManager(),
|
List<List<WptPt>> pointsSegments = editingCtx.getPointsSegments(true, false);
|
||||||
this, new LocationsHolder(editingCtx.getPoints()), mode);
|
if (!pointsSegments.isEmpty()) {
|
||||||
|
GpxApproximationFragment.showInstance(
|
||||||
|
mapActivity.getSupportFragmentManager(), this, pointsSegments, mode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -720,10 +703,14 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
case ExitBottomSheetDialogFragment.REQUEST_CODE:
|
case ExitBottomSheetDialogFragment.REQUEST_CODE:
|
||||||
switch (resultCode) {
|
switch (resultCode) {
|
||||||
case ExitBottomSheetDialogFragment.EXIT_RESULT_CODE:
|
case ExitBottomSheetDialogFragment.EXIT_RESULT_CODE:
|
||||||
dismiss(getMapActivity());
|
if (mapActivity != null) {
|
||||||
|
dismiss(getMapActivity());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ExitBottomSheetDialogFragment.SAVE_RESULT_CODE:
|
case ExitBottomSheetDialogFragment.SAVE_RESULT_CODE:
|
||||||
openSaveAsNewTrackMenu(getMapActivity());
|
if (mapActivity != null) {
|
||||||
|
openSaveAsNewTrackMenu(getMapActivity());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -755,7 +742,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
} else {
|
} else {
|
||||||
String trackName = getSuggestedFileName();
|
String trackName = getSuggestedFileName();
|
||||||
if (editingCtx.hasRoute()) {
|
if (editingCtx.hasRoute()) {
|
||||||
GPXFile gpx = editingCtx.exportRouteAsGpx(trackName);
|
GPXFile gpx = editingCtx.exportGpx(trackName);
|
||||||
if (gpx != null) {
|
if (gpx != null) {
|
||||||
dismiss(mapActivity);
|
dismiss(mapActivity);
|
||||||
runNavigation(gpx, appMode);
|
runNavigation(gpx, appMode);
|
||||||
|
@ -763,15 +750,15 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
Toast.makeText(mapActivity, getString(R.string.error_occurred_saving_gpx), Toast.LENGTH_SHORT).show();
|
Toast.makeText(mapActivity, getString(R.string.error_occurred_saving_gpx), Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (editingCtx.isNewData() || editingCtx.hasRoutePoints()) {
|
if (editingCtx.isApproximationNeeded()) {
|
||||||
|
setMode(DIRECTION_MODE, true);
|
||||||
|
enterApproximationMode(mapActivity);
|
||||||
|
} else {
|
||||||
GPXFile gpx = new GPXFile(Version.getFullVersion(requireMyApplication()));
|
GPXFile gpx = new GPXFile(Version.getFullVersion(requireMyApplication()));
|
||||||
gpx.addRoutePoints(points);
|
gpx.addRoutePoints(points, true);
|
||||||
dismiss(mapActivity);
|
dismiss(mapActivity);
|
||||||
targetPointsHelper.clearAllPoints(false);
|
targetPointsHelper.clearAllPoints(false);
|
||||||
mapActions.enterRoutePlanningModeGivenGpx(gpx, appMode, null, null, true, true, MenuState.HEADER_ONLY);
|
mapActions.enterRoutePlanningModeGivenGpx(gpx, appMode, null, null, true, true, MenuState.HEADER_ONLY);
|
||||||
} else {
|
|
||||||
setMode(DIRECTION_MODE, true);
|
|
||||||
enterApproximationMode(mapActivity);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1044,8 +1031,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
SelectedGpxFile selectedGpxFile = mapActivity.getMyApplication().getSelectedGpxHelper()
|
SelectedGpxFile selectedGpxFile = mapActivity.getMyApplication().getSelectedGpxHelper()
|
||||||
.getSelectedFileByPath(gpxFile.path);
|
.getSelectedFileByPath(gpxFile.path);
|
||||||
boolean showOnMap = selectedGpxFile != null;
|
boolean showOnMap = selectedGpxFile != null;
|
||||||
saveExistingGpx(gpxFile, showOnMap, ActionType.ADD_SEGMENT,
|
saveExistingGpx(gpxFile, showOnMap, false, FinalSaveAction.SHOW_TOAST);
|
||||||
editingCtx.hasRoute() ? SaveType.ROUTE_POINT : SaveType.LINE, FinalSaveAction.SHOW_TOAST);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1070,10 +1056,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
private GpxData setupGpxData(@Nullable GPXFile gpxFile) {
|
private GpxData setupGpxData(@Nullable GPXFile gpxFile) {
|
||||||
GpxData gpxData = null;
|
GpxData gpxData = null;
|
||||||
if (gpxFile != null) {
|
if (gpxFile != null) {
|
||||||
QuadRect rect = gpxFile.getRect();
|
gpxData = new GpxData(gpxFile);
|
||||||
TrkSegment segment = gpxFile.getNonEmptyTrkSegment();
|
|
||||||
ActionType actionType = segment == null ? ActionType.ADD_ROUTE_POINTS : ActionType.EDIT_SEGMENT;
|
|
||||||
gpxData = new GpxData(gpxFile, rect, actionType, segment);
|
|
||||||
}
|
}
|
||||||
editingCtx.setGpxData(gpxData);
|
editingCtx.setGpxData(gpxData);
|
||||||
return gpxData;
|
return gpxData;
|
||||||
|
@ -1091,22 +1074,8 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSaveAsNewTrack(String folderName, String fileName, boolean showOnMap, boolean simplifiedTrack) {
|
public void onSaveAsNewTrack(String folderName, String fileName, boolean showOnMap, boolean simplified) {
|
||||||
saveNewGpx(folderName, fileName, showOnMap, simplifiedTrack, FinalSaveAction.SHOW_IS_SAVED_FRAGMENT);
|
saveNewGpx(folderName, fileName, showOnMap, simplified, 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private MeasurementAdapterListener createMeasurementAdapterListener(final ItemTouchHelper touchHelper) {
|
private MeasurementAdapterListener createMeasurementAdapterListener(final ItemTouchHelper touchHelper) {
|
||||||
|
@ -1182,7 +1151,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
final ApplicationMode appMode = editingCtx.getAppMode();
|
final ApplicationMode appMode = editingCtx.getAppMode();
|
||||||
if (mapActivity != null) {
|
if (mapActivity != null) {
|
||||||
Drawable icon;
|
Drawable icon;
|
||||||
if (editingCtx.isTrackSnappedToRoad() || editingCtx.isNewData() || approximationApplied) {
|
if (!editingCtx.isApproximationNeeded() || editingCtx.isNewData()) {
|
||||||
if (appMode == MeasurementEditingContext.DEFAULT_APP_MODE) {
|
if (appMode == MeasurementEditingContext.DEFAULT_APP_MODE) {
|
||||||
icon = getActiveIcon(R.drawable.ic_action_split_interval);
|
icon = getActiveIcon(R.drawable.ic_action_split_interval);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1204,23 +1173,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displayRoutePoints() {
|
private void collectPoints() {
|
||||||
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);
|
|
||||||
}
|
|
||||||
adapter.notifyDataSetChanged();
|
|
||||||
updateDistancePointsText();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void displaySegmentPoints() {
|
|
||||||
MeasurementToolLayer measurementLayer = getMeasurementLayer();
|
MeasurementToolLayer measurementLayer = getMeasurementLayer();
|
||||||
if (measurementLayer != null) {
|
if (measurementLayer != null) {
|
||||||
if (!isUndoMode()) {
|
if (!isUndoMode()) {
|
||||||
|
@ -1515,8 +1468,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
SelectedGpxFile selectedGpxFile =
|
SelectedGpxFile selectedGpxFile =
|
||||||
mapActivity.getMyApplication().getSelectedGpxHelper().getSelectedFileByPath(gpx.path);
|
mapActivity.getMyApplication().getSelectedGpxHelper().getSelectedFileByPath(gpx.path);
|
||||||
boolean showOnMap = selectedGpxFile != null;
|
boolean showOnMap = selectedGpxFile != null;
|
||||||
saveExistingGpx(gpx, showOnMap, gpxData.getActionType(),
|
saveExistingGpx(gpx, showOnMap, false, finalSaveAction);
|
||||||
editingCtx.hasRoute() ? SaveType.ROUTE_POINT : SaveType.LINE, finalSaveAction);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1540,30 +1492,44 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
return displayedName;
|
return displayedName;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveNewGpx(@NonNull File dir, @NonNull String fileName, boolean showOnMap, SaveType saveType, FinalSaveAction finalSaveAction) {
|
private void saveNewGpx(String folderName, String fileName, boolean showOnMap,
|
||||||
saveGpx(new File(dir, fileName), null, null, saveType, finalSaveAction, 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,
|
private void saveNewGpx(@NonNull File dir, @NonNull String fileName, boolean showOnMap,
|
||||||
SaveType saveType, FinalSaveAction finalSaveAction) {
|
boolean simplified, FinalSaveAction finalSaveAction) {
|
||||||
saveGpx(new File(gpx.path), gpx, actionType, saveType, finalSaveAction, showOnMap);
|
saveGpx(new File(dir, fileName), null, simplified, finalSaveAction, showOnMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveGpx(@NonNull final File outFile, @Nullable GPXFile gpxFile, final ActionType actionType,
|
private void saveExistingGpx(@NonNull GPXFile gpx, boolean showOnMap,
|
||||||
SaveType saveType, final FinalSaveAction finalSaveAction, final boolean showOnMap) {
|
boolean simplified, FinalSaveAction finalSaveAction) {
|
||||||
|
saveGpx(new File(gpx.path), gpx, simplified, finalSaveAction, showOnMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveGpx(@NonNull final File outFile, @Nullable GPXFile gpxFile, boolean simplified,
|
||||||
|
final FinalSaveAction finalSaveAction, final boolean showOnMap) {
|
||||||
SaveGpxRouteListener saveGpxRouteListener = new SaveGpxRouteListener() {
|
SaveGpxRouteListener saveGpxRouteListener = new SaveGpxRouteListener() {
|
||||||
@Override
|
@Override
|
||||||
public void gpxSavingFinished(Exception warning, GPXFile savedGpxFile, File backupFile) {
|
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, showOnMap, saveGpxRouteListener);
|
||||||
saveTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
saveTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onGpxSaved(Exception warning, GPXFile savedGpxFile, final File outFile, final File backupFile,
|
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();
|
MapActivity mapActivity = getMapActivity();
|
||||||
if (mapActivity == null) {
|
if (mapActivity == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -1571,9 +1537,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
mapActivity.refreshMap();
|
mapActivity.refreshMap();
|
||||||
if (warning == null) {
|
if (warning == null) {
|
||||||
if (editingCtx.isNewData() && savedGpxFile != null) {
|
if (editingCtx.isNewData() && savedGpxFile != null) {
|
||||||
QuadRect rect = savedGpxFile.getRect();
|
GpxData gpxData = new GpxData(savedGpxFile);
|
||||||
TrkSegment segment = savedGpxFile.getNonEmptyTrkSegment();
|
|
||||||
GpxData gpxData = new GpxData(savedGpxFile, rect, ActionType.EDIT_SEGMENT, segment);
|
|
||||||
editingCtx.setGpxData(gpxData);
|
editingCtx.setGpxData(gpxData);
|
||||||
updateToolbar();
|
updateToolbar();
|
||||||
}
|
}
|
||||||
|
@ -1599,7 +1563,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
GPXFile gpx = GPXUtilities.loadGPXFile(outFile);
|
GPXFile gpx = GPXUtilities.loadGPXFile(outFile);
|
||||||
setupGpxData(gpx);
|
setupGpxData(gpx);
|
||||||
if (showOnMap) {
|
if (showOnMap) {
|
||||||
showGpxOnMap(app, gpx, actionType, false);
|
showGpxOnMap(app, gpx, false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setupGpxData(null);
|
setupGpxData(null);
|
||||||
|
@ -1645,12 +1609,10 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static void showGpxOnMap(OsmandApplication app, GPXFile gpx, ActionType actionType, boolean isNewGpx) {
|
protected static void showGpxOnMap(OsmandApplication app, GPXFile gpx, boolean isNewGpx) {
|
||||||
SelectedGpxFile sf = app.getSelectedGpxHelper().selectGpxFile(gpx, true, false);
|
SelectedGpxFile sf = app.getSelectedGpxHelper().selectGpxFile(gpx, true, false);
|
||||||
if (sf != null && !isNewGpx) {
|
if (sf != null && !isNewGpx) {
|
||||||
if (actionType == ActionType.ADD_SEGMENT || actionType == ActionType.EDIT_SEGMENT) {
|
sf.processPoints(app);
|
||||||
sf.processPoints(app);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1689,25 +1651,9 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
if (mapActivity == null) {
|
if (mapActivity == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final GpxData gpxData = editingCtx.getGpxData();
|
|
||||||
String fileName = getSuggestedFileName();
|
String fileName = getSuggestedFileName();
|
||||||
String actionStr = getString(R.string.plan_route);
|
|
||||||
boolean editMode = isInEditMode();
|
boolean editMode = isInEditMode();
|
||||||
if (editMode) {
|
String actionStr = getString(editMode ? R.string.edit_line : R.string.plan_route);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!editMode && editingCtx.getPointsCount() > 1) {
|
if (!editMode && editingCtx.getPointsCount() > 1) {
|
||||||
toolBarController.setTitle(fileName.replace('_', ' '));
|
toolBarController.setTitle(fileName.replace('_', ' '));
|
||||||
toolBarController.setDescription(actionStr);
|
toolBarController.setDescription(actionStr);
|
||||||
|
@ -1954,12 +1900,13 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onGpxApproximationDone(GpxRouteApproximation gpxApproximation, ApplicationMode mode) {
|
public void onGpxApproximationDone(List<GpxRouteApproximation> gpxApproximations, List<List<WptPt>> pointsList, ApplicationMode mode) {
|
||||||
MeasurementToolLayer measurementLayer = getMeasurementLayer();
|
MeasurementToolLayer measurementLayer = getMeasurementLayer();
|
||||||
if (measurementLayer != null) {
|
if (measurementLayer != null) {
|
||||||
|
boolean approximationMode = editingCtx.isInApproximationMode();
|
||||||
editingCtx.setInApproximationMode(true);
|
editingCtx.setInApproximationMode(true);
|
||||||
ApplyGpxApproximationCommand command = new ApplyGpxApproximationCommand(measurementLayer, gpxApproximation, mode);
|
ApplyGpxApproximationCommand command = new ApplyGpxApproximationCommand(measurementLayer, gpxApproximations, pointsList, mode);
|
||||||
if (!editingCtx.getCommandManager().update(command)) {
|
if (!approximationMode || !editingCtx.getCommandManager().update(command)) {
|
||||||
editingCtx.getCommandManager().execute(command);
|
editingCtx.getCommandManager().execute(command);
|
||||||
}
|
}
|
||||||
if (pointsListOpened) {
|
if (pointsListOpened) {
|
||||||
|
@ -1971,7 +1918,6 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onApplyGpxApproximation() {
|
public void onApplyGpxApproximation() {
|
||||||
approximationApplied = true;
|
|
||||||
exitApproximationMode();
|
exitApproximationMode();
|
||||||
doAddOrMovePointCommonStuff();
|
doAddOrMovePointCommonStuff();
|
||||||
updateSnapToRoadControls();
|
updateSnapToRoadControls();
|
||||||
|
@ -1986,7 +1932,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
if (mapActivity != null) {
|
if (mapActivity != null) {
|
||||||
if (editingCtx.hasRoute()) {
|
if (editingCtx.hasRoute()) {
|
||||||
String trackName = getSuggestedFileName();
|
String trackName = getSuggestedFileName();
|
||||||
GPXFile gpx = editingCtx.exportRouteAsGpx(trackName);
|
GPXFile gpx = editingCtx.exportGpx(trackName);
|
||||||
if (gpx != null) {
|
if (gpx != null) {
|
||||||
ApplicationMode appMode = editingCtx.getAppMode();
|
ApplicationMode appMode = editingCtx.getAppMode();
|
||||||
dismiss(mapActivity);
|
dismiss(mapActivity);
|
||||||
|
|
|
@ -183,22 +183,27 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL
|
||||||
lineAttrs.updatePaints(view.getApplication(), settings, tb);
|
lineAttrs.updatePaints(view.getApplication(), settings, tb);
|
||||||
|
|
||||||
if (editingCtx.isInApproximationMode()) {
|
if (editingCtx.isInApproximationMode()) {
|
||||||
List<WptPt> originalTrackPointList = editingCtx.getOriginalTrackPointList();
|
List<List<WptPt>> originalPointsList = editingCtx.getOriginalSegmentPointsList();
|
||||||
if (originalTrackPointList != null) {
|
if (originalPointsList != null) {
|
||||||
lineAttrs.customColorPaint.setColor(ContextCompat.getColor(view.getContext(),
|
lineAttrs.customColorPaint.setColor(ContextCompat.getColor(view.getContext(),
|
||||||
R.color.activity_background_transparent_color_dark));
|
R.color.activity_background_transparent_color_dark));
|
||||||
new Renderable.StandardTrack(new ArrayList<>(originalTrackPointList), 17.2).
|
for (List<WptPt> points : originalPointsList) {
|
||||||
drawSegment(view.getZoom(), lineAttrs.customColorPaint, canvas, tb);
|
new Renderable.StandardTrack(new ArrayList<>(points), 17.2).
|
||||||
|
drawSegment(view.getZoom(), lineAttrs.customColorPaint, canvas, tb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TrkSegment before = editingCtx.getBeforeTrkSegmentLine();
|
List<TrkSegment> before = editingCtx.getBeforeTrkSegmentLine();
|
||||||
new Renderable.StandardTrack(new ArrayList<>(before.points), 17.2).
|
for (TrkSegment segment : before) {
|
||||||
drawSegment(view.getZoom(), lineAttrs.paint, canvas, tb);
|
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();
|
||||||
drawSegment(view.getZoom(), lineAttrs.paint, canvas, tb);
|
for (TrkSegment segment : after) {
|
||||||
|
new Renderable.StandardTrack(new ArrayList<>(segment.points), 17.2).
|
||||||
|
drawSegment(view.getZoom(), lineAttrs.paint, canvas, tb);
|
||||||
|
}
|
||||||
|
|
||||||
drawPoints(canvas, tb);
|
drawPoints(canvas, tb);
|
||||||
}
|
}
|
||||||
|
@ -308,36 +313,48 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawBeforeAfterPath(Canvas canvas, RotatedTileBox tb) {
|
private void drawBeforeAfterPath(Canvas canvas, RotatedTileBox tb) {
|
||||||
TrkSegment before = editingCtx.getBeforeTrkSegmentLine();
|
List<TrkSegment> before = editingCtx.getBeforeTrkSegmentLine();
|
||||||
TrkSegment after = editingCtx.getAfterTrkSegmentLine();
|
List<TrkSegment> after = editingCtx.getAfterTrkSegmentLine();
|
||||||
if (before.points.size() > 0 || after.points.size() > 0) {
|
if (before.size() > 0 || after.size() > 0) {
|
||||||
path.reset();
|
path.reset();
|
||||||
tx.clear();
|
tx.clear();
|
||||||
ty.clear();
|
ty.clear();
|
||||||
|
|
||||||
if (before.points.size() > 0) {
|
boolean hasPointsBefore = false;
|
||||||
WptPt pt = before.points.get(before.points.size() - 1);
|
if (before.size() > 0) {
|
||||||
float locX = tb.getPixXFromLatLon(pt.lat, pt.lon);
|
TrkSegment segment = before.get(before.size() - 1);
|
||||||
float locY = tb.getPixYFromLatLon(pt.lat, pt.lon);
|
if (segment.points.size() > 0) {
|
||||||
tx.add(locX);
|
hasPointsBefore = true;
|
||||||
ty.add(locY);
|
WptPt pt = segment.points.get(segment.points.size() - 1);
|
||||||
tx.add((float) tb.getCenterPixelX());
|
if (!ApplicationMode.GAP.getStringKey().equals(pt.getProfileType())) {
|
||||||
ty.add((float) tb.getCenterPixelY());
|
float locX = tb.getPixXFromLatLon(pt.lat, pt.lon);
|
||||||
}
|
float locY = tb.getPixYFromLatLon(pt.lat, pt.lon);
|
||||||
if (after.points.size() > 0) {
|
tx.add(locX);
|
||||||
if (before.points.size() == 0) {
|
ty.add(locY);
|
||||||
tx.add((float) tb.getCenterPixelX());
|
tx.add((float) tb.getCenterPixelX());
|
||||||
ty.add((float) tb.getCenterPixelY());
|
ty.add((float) tb.getCenterPixelY());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 = 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);
|
||||||
}
|
}
|
||||||
WptPt pt = after.points.get(0);
|
|
||||||
float locX = tb.getPixXFromLatLon(pt.lat, pt.lon);
|
|
||||||
float locY = tb.getPixYFromLatLon(pt.lat, pt.lon);
|
|
||||||
tx.add(locX);
|
|
||||||
ty.add(locY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GeometryWay.calculatePath(tb, tx, ty, path);
|
if (!tx.isEmpty() && !ty.isEmpty()) {
|
||||||
canvas.drawPath(path, lineAttrs.paint);
|
GeometryWay.calculatePath(tb, tx, ty, path);
|
||||||
|
canvas.drawPath(path, lineAttrs.paint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,7 +384,6 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL
|
||||||
pt.lon = l.getLongitude();
|
pt.lon = l.getLongitude();
|
||||||
boolean allowed = editingCtx.getPointsCount() == 0 || !editingCtx.getPoints().get(editingCtx.getPointsCount() - 1).equals(pt);
|
boolean allowed = editingCtx.getPointsCount() == 0 || !editingCtx.getPoints().get(editingCtx.getPointsCount() - 1).equals(pt);
|
||||||
if (allowed) {
|
if (allowed) {
|
||||||
|
|
||||||
ApplicationMode applicationMode = editingCtx.getAppMode();
|
ApplicationMode applicationMode = editingCtx.getAppMode();
|
||||||
if (applicationMode != MeasurementEditingContext.DEFAULT_APP_MODE) {
|
if (applicationMode != MeasurementEditingContext.DEFAULT_APP_MODE) {
|
||||||
pt.setProfileType(applicationMode.getStringKey());
|
pt.setProfileType(applicationMode.getStringKey());
|
||||||
|
|
|
@ -4,6 +4,8 @@ import android.app.ProgressDialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import net.osmand.AndroidUtils;
|
import net.osmand.AndroidUtils;
|
||||||
import net.osmand.FileUtils;
|
import net.osmand.FileUtils;
|
||||||
import net.osmand.GPXUtilities;
|
import net.osmand.GPXUtilities;
|
||||||
|
@ -15,13 +17,10 @@ import net.osmand.plus.OsmandApplication;
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
import net.osmand.plus.Version;
|
import net.osmand.plus.Version;
|
||||||
import net.osmand.plus.activities.MapActivity;
|
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 net.osmand.util.Algorithms;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static net.osmand.IndexConstants.GPX_FILE_EXT;
|
import static net.osmand.IndexConstants.GPX_FILE_EXT;
|
||||||
|
@ -31,26 +30,22 @@ class SaveGpxRouteAsyncTask extends AsyncTask<Void, Void, Exception> {
|
||||||
private WeakReference<MeasurementToolFragment> fragmentRef;
|
private WeakReference<MeasurementToolFragment> fragmentRef;
|
||||||
private ProgressDialog progressDialog;
|
private ProgressDialog progressDialog;
|
||||||
|
|
||||||
private SaveType saveType;
|
|
||||||
private ActionType actionType;
|
|
||||||
|
|
||||||
private File outFile;
|
private File outFile;
|
||||||
private File backupFile;
|
private File backupFile;
|
||||||
private GPXFile gpxFile;
|
private GPXFile gpxFile;
|
||||||
private GPXFile savedGpxFile;
|
private GPXFile savedGpxFile;
|
||||||
|
private boolean simplified;
|
||||||
private boolean showOnMap;
|
private boolean showOnMap;
|
||||||
|
|
||||||
private SaveGpxRouteListener saveGpxRouteListener;
|
private SaveGpxRouteListener saveGpxRouteListener;
|
||||||
|
|
||||||
|
|
||||||
public SaveGpxRouteAsyncTask(MeasurementToolFragment fragment, File outFile, GPXFile gpxFile,
|
public SaveGpxRouteAsyncTask(MeasurementToolFragment fragment, File outFile, GPXFile gpxFile,
|
||||||
ActionType actionType, SaveType saveType, boolean showOnMap, SaveGpxRouteListener saveGpxRouteListener) {
|
boolean simplified, boolean showOnMap, SaveGpxRouteListener saveGpxRouteListener) {
|
||||||
fragmentRef = new WeakReference<>(fragment);
|
fragmentRef = new WeakReference<>(fragment);
|
||||||
this.outFile = outFile;
|
this.outFile = outFile;
|
||||||
this.showOnMap = showOnMap;
|
this.showOnMap = showOnMap;
|
||||||
this.gpxFile = gpxFile;
|
this.gpxFile = gpxFile;
|
||||||
this.actionType = actionType;
|
this.simplified = simplified;
|
||||||
this.saveType = saveType;
|
|
||||||
this.saveGpxRouteListener = saveGpxRouteListener;
|
this.saveGpxRouteListener = saveGpxRouteListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,119 +72,70 @@ class SaveGpxRouteAsyncTask extends AsyncTask<Void, Void, Exception> {
|
||||||
OsmandApplication app = mapActivity.getMyApplication();
|
OsmandApplication app = mapActivity.getMyApplication();
|
||||||
MeasurementToolLayer measurementLayer = mapActivity.getMapLayers().getMeasurementToolLayer();
|
MeasurementToolLayer measurementLayer = mapActivity.getMapLayers().getMeasurementToolLayer();
|
||||||
MeasurementEditingContext editingCtx = fragment.getEditingCtx();
|
MeasurementEditingContext editingCtx = fragment.getEditingCtx();
|
||||||
|
Exception res = null;
|
||||||
List<WptPt> points = editingCtx.getPoints();
|
|
||||||
TrkSegment before = editingCtx.getBeforeTrkSegmentLine();
|
|
||||||
TrkSegment after = editingCtx.getAfterTrkSegmentLine();
|
|
||||||
if (gpxFile == null) {
|
if (gpxFile == null) {
|
||||||
String fileName = outFile.getName();
|
String fileName = outFile.getName();
|
||||||
String trackName = fileName.substring(0, fileName.length() - GPX_FILE_EXT.length());
|
String trackName = fileName.substring(0, fileName.length() - GPX_FILE_EXT.length());
|
||||||
GPXFile gpx = new GPXFile(Version.getFullVersion(app));
|
GPXFile gpx = generateGpxFile(measurementLayer, editingCtx, trackName, new GPXFile(Version.getFullVersion(app)));
|
||||||
if (measurementLayer != null) {
|
res = GPXUtilities.writeGpxFile(outFile, gpx);
|
||||||
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);
|
|
||||||
gpx.path = outFile.getAbsolutePath();
|
gpx.path = outFile.getAbsolutePath();
|
||||||
savedGpxFile = gpx;
|
savedGpxFile = gpx;
|
||||||
if (showOnMap) {
|
if (showOnMap) {
|
||||||
MeasurementToolFragment.showGpxOnMap(app, gpx, actionType, true);
|
MeasurementToolFragment.showGpxOnMap(app, gpx, true);
|
||||||
}
|
}
|
||||||
return res;
|
|
||||||
} else {
|
} else {
|
||||||
GPXFile gpx = gpxFile;
|
|
||||||
backupFile = FileUtils.backupFile(app, outFile);
|
backupFile = FileUtils.backupFile(app, outFile);
|
||||||
String trackName = Algorithms.getFileNameWithoutExtension(outFile);
|
String trackName = Algorithms.getFileNameWithoutExtension(outFile);
|
||||||
if (measurementLayer != null) {
|
GPXFile gpx = generateGpxFile(measurementLayer, editingCtx, trackName, gpxFile);
|
||||||
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;
|
|
||||||
if (!gpx.showCurrentTrack) {
|
if (!gpx.showCurrentTrack) {
|
||||||
res = GPXUtilities.writeGpxFile(outFile, gpx);
|
res = GPXUtilities.writeGpxFile(outFile, gpx);
|
||||||
}
|
}
|
||||||
savedGpxFile = gpx;
|
savedGpxFile = gpx;
|
||||||
if (showOnMap) {
|
if (showOnMap) {
|
||||||
MeasurementToolFragment.showGpxOnMap(app, gpx, actionType, false);
|
MeasurementToolFragment.showGpxOnMap(app, gpx, false);
|
||||||
}
|
}
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
private GPXFile generateGpxFile(MeasurementToolLayer measurementLayer, MeasurementEditingContext editingCtx,
|
||||||
|
String trackName, @Nullable 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<WptPt> gpxPoints = null;
|
||||||
|
if (gpx != null) {
|
||||||
|
gpxPoints = gpx.getPoints();
|
||||||
|
}
|
||||||
|
gpx = newGpx;
|
||||||
|
List<List<WptPt>> routePoints = editingCtx.getRoutePoints();
|
||||||
|
for (List<WptPt> points : routePoints) {
|
||||||
|
gpx.addRoutePoints(points, true);
|
||||||
|
}
|
||||||
|
if (!Algorithms.isEmpty(gpxPoints)) {
|
||||||
|
gpx.addPoints(gpxPoints);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return gpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package net.osmand.plus.measurementtool;
|
package net.osmand.plus.measurementtool;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.graphics.drawable.Drawable;
|
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.SimpleBottomSheetItem;
|
||||||
import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleDividerItem;
|
import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleDividerItem;
|
||||||
import net.osmand.plus.helpers.FontCache;
|
import net.osmand.plus.helpers.FontCache;
|
||||||
import net.osmand.plus.measurementtool.GpxData.ActionType;
|
|
||||||
import net.osmand.plus.settings.backend.ApplicationMode;
|
import net.osmand.plus.settings.backend.ApplicationMode;
|
||||||
import net.osmand.util.MapUtils;
|
import net.osmand.util.MapUtils;
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ public class SelectedPointBottomSheetDialogFragment extends MenuBottomSheetDialo
|
||||||
private static final Log LOG = PlatformUtil.getLog(SelectedPointBottomSheetDialogFragment.class);
|
private static final Log LOG = PlatformUtil.getLog(SelectedPointBottomSheetDialogFragment.class);
|
||||||
private MeasurementEditingContext editingCtx;
|
private MeasurementEditingContext editingCtx;
|
||||||
|
|
||||||
|
@SuppressLint("InflateParams")
|
||||||
@Override
|
@Override
|
||||||
public void createMenuItems(Bundle savedInstanceState) {
|
public void createMenuItems(Bundle savedInstanceState) {
|
||||||
MapActivity mapActivity = getMapActivity();
|
MapActivity mapActivity = getMapActivity();
|
||||||
|
@ -264,11 +265,7 @@ public class SelectedPointBottomSheetDialogFragment extends MenuBottomSheetDialo
|
||||||
if (!TextUtils.isEmpty(pointName)) {
|
if (!TextUtils.isEmpty(pointName)) {
|
||||||
return pointName;
|
return pointName;
|
||||||
}
|
}
|
||||||
GpxData gpxData = editingCtx.getGpxData();
|
return getString(R.string.ltr_or_rtl_combine_via_dash, getString(R.string.plugin_distance_point), String.valueOf(pos + 1));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@ -305,18 +302,15 @@ public class SelectedPointBottomSheetDialogFragment extends MenuBottomSheetDialo
|
||||||
}
|
}
|
||||||
description.append(OsmAndFormatter.getFormattedDistance(dist, mapActivity.getMyApplication()));
|
description.append(OsmAndFormatter.getFormattedDistance(dist, mapActivity.getMyApplication()));
|
||||||
}
|
}
|
||||||
GpxData gpxData = editingCtx.getGpxData();
|
double elevation = pt.ele;
|
||||||
if (gpxData != null && gpxData.getActionType() == ActionType.EDIT_SEGMENT) {
|
if (!Double.isNaN(elevation)) {
|
||||||
double elevation = pt.ele;
|
description.append(" ").append((getString(R.string.altitude)).substring(0, 1)).append(": ");
|
||||||
if (!Double.isNaN(elevation)) {
|
description.append(OsmAndFormatter.getFormattedAlt(elevation, mapActivity.getMyApplication()));
|
||||||
description.append(" ").append((getString(R.string.altitude)).substring(0, 1)).append(": ");
|
}
|
||||||
description.append(OsmAndFormatter.getFormattedAlt(elevation, mapActivity.getMyApplication()));
|
float speed = (float) pt.speed;
|
||||||
}
|
if (speed != 0) {
|
||||||
float speed = (float) pt.speed;
|
description.append(" ").append((getString(R.string.map_widget_speed)).substring(0, 1)).append(": ");
|
||||||
if (speed != 0) {
|
description.append(OsmAndFormatter.getFormattedSpeed(speed, mapActivity.getMyApplication()));
|
||||||
description.append(" ").append((getString(R.string.map_widget_speed)).substring(0, 1)).append(": ");
|
|
||||||
description.append(OsmAndFormatter.getFormattedSpeed(speed, mapActivity.getMyApplication()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return description.toString();
|
return description.toString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@ import net.osmand.plus.OsmAndFormatter;
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
import net.osmand.plus.UiUtilities;
|
import net.osmand.plus.UiUtilities;
|
||||||
import net.osmand.plus.activities.MapActivity;
|
import net.osmand.plus.activities.MapActivity;
|
||||||
import net.osmand.plus.measurementtool.GpxData.ActionType;
|
|
||||||
import net.osmand.plus.views.controls.ReorderItemTouchHelperCallback;
|
import net.osmand.plus.views.controls.ReorderItemTouchHelperCallback;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -32,13 +31,11 @@ public class MeasurementToolAdapter extends RecyclerView.Adapter<MeasurementTool
|
||||||
private final List<WptPt> points;
|
private final List<WptPt> points;
|
||||||
private MeasurementAdapterListener listener;
|
private MeasurementAdapterListener listener;
|
||||||
private boolean nightMode;
|
private boolean nightMode;
|
||||||
private final ActionType actionType;
|
|
||||||
private final static String BULLET = " • ";
|
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.mapActivity = mapActivity;
|
||||||
this.points = points;
|
this.points = points;
|
||||||
this.actionType = actionType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAdapterListener(MeasurementAdapterListener listener) {
|
public void setAdapterListener(MeasurementAdapterListener listener) {
|
||||||
|
@ -79,11 +76,7 @@ public class MeasurementToolAdapter extends RecyclerView.Adapter<MeasurementTool
|
||||||
if (!TextUtils.isEmpty(pointTitle)) {
|
if (!TextUtils.isEmpty(pointTitle)) {
|
||||||
holder.title.setText(pointTitle);
|
holder.title.setText(pointTitle);
|
||||||
} else {
|
} else {
|
||||||
if (actionType == ActionType.ADD_ROUTE_POINTS) {
|
holder.title.setText(mapActivity.getString(R.string.ltr_or_rtl_combine_via_dash, mapActivity.getString(R.string.plugin_distance_point), String.valueOf(pos + 1)));
|
||||||
holder.title.setText(mapActivity.getString(R.string.route_point) + " - " + (pos + 1));
|
|
||||||
} else {
|
|
||||||
holder.title.setText(mapActivity.getString(R.string.plugin_distance_point) + " - " + (pos + 1));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
String pointDesc = pt.desc;
|
String pointDesc = pt.desc;
|
||||||
if (!TextUtils.isEmpty(pointDesc)) {
|
if (!TextUtils.isEmpty(pointDesc)) {
|
||||||
|
@ -114,21 +107,20 @@ public class MeasurementToolAdapter extends RecyclerView.Adapter<MeasurementTool
|
||||||
holder.descr.setText(text);
|
holder.descr.setText(text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (actionType == ActionType.EDIT_SEGMENT) {
|
double elevation = pt.ele;
|
||||||
double elevation = pt.ele;
|
if (!Double.isNaN(elevation)) {
|
||||||
if (!Double.isNaN(elevation)) {
|
String eleStr = (mapActivity.getString(R.string.altitude)).substring(0, 1);
|
||||||
String eleStr = (mapActivity.getString(R.string.altitude)).substring(0, 1);
|
holder.elevation.setText(mapActivity.getString(R.string.ltr_or_rtl_combine_via_colon,
|
||||||
holder.elevation.setText(eleStr + ": " + OsmAndFormatter.getFormattedAlt(elevation, mapActivity.getMyApplication()));
|
eleStr, OsmAndFormatter.getFormattedAlt(elevation, mapActivity.getMyApplication())));
|
||||||
} else {
|
} else {
|
||||||
holder.elevation.setText("");
|
holder.elevation.setText("");
|
||||||
}
|
}
|
||||||
float speed = (float) pt.speed;
|
float speed = (float) pt.speed;
|
||||||
if (speed != 0) {
|
if (speed != 0) {
|
||||||
String speedStr = (mapActivity.getString(R.string.map_widget_speed)).substring(0, 1);
|
String speedStr = (mapActivity.getString(R.string.map_widget_speed)).substring(0, 1);
|
||||||
holder.speed.setText(speedStr + ": " + OsmAndFormatter.getFormattedSpeed(speed, mapActivity.getMyApplication()));
|
holder.speed.setText(speedStr + ": " + OsmAndFormatter.getFormattedSpeed(speed, mapActivity.getMyApplication()));
|
||||||
} else {
|
} else {
|
||||||
holder.speed.setText("");
|
holder.speed.setText("");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
holder.deleteBtn.setImageDrawable(iconsCache.getIcon(R.drawable.ic_action_remove_dark,
|
holder.deleteBtn.setImageDrawable(iconsCache.getIcon(R.drawable.ic_action_remove_dark,
|
||||||
nightMode ? R.color.icon_color_default_dark : R.color.icon_color_default_light));
|
nightMode ? R.color.icon_color_default_dark : R.color.icon_color_default_light));
|
||||||
|
|
|
@ -1,24 +1,36 @@
|
||||||
package net.osmand.plus.measurementtool.command;
|
package net.osmand.plus.measurementtool.command;
|
||||||
|
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import net.osmand.GPXUtilities.WptPt;
|
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.measurementtool.MeasurementToolLayer;
|
||||||
import net.osmand.plus.settings.backend.ApplicationMode;
|
import net.osmand.plus.settings.backend.ApplicationMode;
|
||||||
import net.osmand.router.RoutePlannerFrontEnd.GpxRouteApproximation;
|
import net.osmand.router.RoutePlannerFrontEnd.GpxRouteApproximation;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class ApplyGpxApproximationCommand extends MeasurementModeCommand {
|
public class ApplyGpxApproximationCommand extends MeasurementModeCommand {
|
||||||
|
|
||||||
private ApplicationMode mode;
|
private ApplicationMode mode;
|
||||||
private GpxRouteApproximation approximation;
|
|
||||||
private List<WptPt> points;
|
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);
|
super(measurementLayer);
|
||||||
this.approximation = approximation;
|
this.approximations = approximations;
|
||||||
|
this.segmentPointsList = segmentPointsList;
|
||||||
|
this.originalSegmentPointsList = new ArrayList<>(segmentPointsList);
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +38,10 @@ public class ApplyGpxApproximationCommand extends MeasurementModeCommand {
|
||||||
return points;
|
return points;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<List<WptPt>> getOriginalSegmentPointsList() {
|
||||||
|
return originalSegmentPointsList;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MeasurementCommandType getType() {
|
public MeasurementCommandType getType() {
|
||||||
return MeasurementCommandType.APPROXIMATE_POINTS;
|
return MeasurementCommandType.APPROXIMATE_POINTS;
|
||||||
|
@ -33,8 +49,9 @@ public class ApplyGpxApproximationCommand extends MeasurementModeCommand {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean execute() {
|
public boolean execute() {
|
||||||
List<WptPt> pts = getEditingCtx().getPoints();
|
MeasurementEditingContext ctx = getEditingCtx();
|
||||||
points = new ArrayList<>(pts);
|
points = new ArrayList<>(ctx.getPoints());
|
||||||
|
roadSegmentData = ctx.getRoadSegmentData();
|
||||||
applyApproximation();
|
applyApproximation();
|
||||||
refreshMap();
|
refreshMap();
|
||||||
return true;
|
return true;
|
||||||
|
@ -44,7 +61,7 @@ public class ApplyGpxApproximationCommand extends MeasurementModeCommand {
|
||||||
public boolean update(@NonNull Command command) {
|
public boolean update(@NonNull Command command) {
|
||||||
if (command instanceof ApplyGpxApproximationCommand) {
|
if (command instanceof ApplyGpxApproximationCommand) {
|
||||||
ApplyGpxApproximationCommand approxCommand = (ApplyGpxApproximationCommand) command;
|
ApplyGpxApproximationCommand approxCommand = (ApplyGpxApproximationCommand) command;
|
||||||
approximation = approxCommand.approximation;
|
approximations = approxCommand.approximations;
|
||||||
mode = approxCommand.mode;
|
mode = approxCommand.mode;
|
||||||
applyApproximation();
|
applyApproximation();
|
||||||
refreshMap();
|
refreshMap();
|
||||||
|
@ -55,10 +72,12 @@ public class ApplyGpxApproximationCommand extends MeasurementModeCommand {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void undo() {
|
public void undo() {
|
||||||
getEditingCtx().resetAppMode();
|
MeasurementEditingContext ctx = getEditingCtx();
|
||||||
getEditingCtx().clearSegments();
|
ctx.resetAppMode();
|
||||||
getEditingCtx().addPoints(points);
|
ctx.clearSegments();
|
||||||
getEditingCtx().updateCacheForSnap();
|
ctx.setRoadSegmentData(roadSegmentData);
|
||||||
|
ctx.addPoints(points);
|
||||||
|
segmentPointsList = new ArrayList<>(originalSegmentPointsList);
|
||||||
refreshMap();
|
refreshMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,8 +88,15 @@ public class ApplyGpxApproximationCommand extends MeasurementModeCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void applyApproximation() {
|
public void applyApproximation() {
|
||||||
getEditingCtx().setAppMode(mode);
|
MeasurementEditingContext ctx = getEditingCtx();
|
||||||
getEditingCtx().clearSegments();
|
ctx.setAppMode(mode);
|
||||||
getEditingCtx().setPoints(approximation, 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,7 @@ public class ChangeRouteModeCommand extends MeasurementModeCommand {
|
||||||
editingCtx.addPoints(oldPoints);
|
editingCtx.addPoints(oldPoints);
|
||||||
editingCtx.setAppMode(oldMode);
|
editingCtx.setAppMode(oldMode);
|
||||||
editingCtx.setRoadSegmentData(oldRoadSegmentData);
|
editingCtx.setRoadSegmentData(oldRoadSegmentData);
|
||||||
editingCtx.updateCacheForSnap();
|
editingCtx.updateSegmentsForSnap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -146,7 +146,7 @@ public class ChangeRouteModeCommand extends MeasurementModeCommand {
|
||||||
if (newRoadSegmentData != null) {
|
if (newRoadSegmentData != null) {
|
||||||
editingCtx.setRoadSegmentData(newRoadSegmentData);
|
editingCtx.setRoadSegmentData(newRoadSegmentData);
|
||||||
}
|
}
|
||||||
editingCtx.updateCacheForSnap();
|
editingCtx.updateSegmentsForSnap();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateProfileType(WptPt pt) {
|
private void updateProfileType(WptPt pt) {
|
||||||
|
|
|
@ -1,14 +1,20 @@
|
||||||
package net.osmand.plus.measurementtool.command;
|
package net.osmand.plus.measurementtool.command;
|
||||||
|
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
import net.osmand.GPXUtilities.WptPt;
|
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.measurementtool.MeasurementToolLayer;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class ClearPointsCommand extends MeasurementModeCommand {
|
public class ClearPointsCommand extends MeasurementModeCommand {
|
||||||
|
|
||||||
private List<WptPt> points;
|
private List<WptPt> points;
|
||||||
|
private Map<Pair<WptPt, WptPt>, RoadSegmentData> roadSegmentData;
|
||||||
private ClearCommandMode clearMode;
|
private ClearCommandMode clearMode;
|
||||||
private int pointPosition;
|
private int pointPosition;
|
||||||
|
|
||||||
|
@ -31,27 +37,30 @@ public class ClearPointsCommand extends MeasurementModeCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void executeCommand() {
|
private void executeCommand() {
|
||||||
List<WptPt> pts = getEditingCtx().getPoints();
|
MeasurementEditingContext ctx = getEditingCtx();
|
||||||
|
List<WptPt> pts = ctx.getPoints();
|
||||||
points = new ArrayList<>(pts);
|
points = new ArrayList<>(pts);
|
||||||
|
roadSegmentData = ctx.getRoadSegmentData();
|
||||||
switch (clearMode) {
|
switch (clearMode) {
|
||||||
case ALL:
|
case ALL:
|
||||||
pts.clear();
|
pts.clear();
|
||||||
getEditingCtx().clearSegments();
|
ctx.clearSegments();
|
||||||
break;
|
break;
|
||||||
case BEFORE:
|
case BEFORE:
|
||||||
getEditingCtx().trimBefore(pointPosition);
|
ctx.trimBefore(pointPosition);
|
||||||
break;
|
break;
|
||||||
case AFTER:
|
case AFTER:
|
||||||
getEditingCtx().trimAfter(pointPosition);
|
ctx.trimAfter(pointPosition);
|
||||||
}
|
}
|
||||||
refreshMap();
|
refreshMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void undo() {
|
public void undo() {
|
||||||
getEditingCtx().clearSegments();
|
MeasurementEditingContext ctx = getEditingCtx();
|
||||||
getEditingCtx().addPoints(points);
|
ctx.clearSegments();
|
||||||
getEditingCtx().updateCacheForSnap();
|
ctx.setRoadSegmentData(roadSegmentData);
|
||||||
|
ctx.addPoints(points);
|
||||||
refreshMap();
|
refreshMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,6 @@ public class MeasurementCommandManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public MeasurementModeCommand getLastCommand() {
|
public MeasurementModeCommand getLastCommand() {
|
||||||
return undoCommands.getLast();
|
return undoCommands.getFirst();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ public class ReorderPointCommand extends MeasurementModeCommand {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean execute() {
|
public boolean execute() {
|
||||||
getEditingCtx().updateCacheForSnap();
|
getEditingCtx().updateSegmentsForSnap();
|
||||||
refreshMap();
|
refreshMap();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ public class ReorderPointCommand extends MeasurementModeCommand {
|
||||||
private void reorder(int addTo, int removeFrom) {
|
private void reorder(int addTo, int removeFrom) {
|
||||||
List<WptPt> points = getEditingCtx().getPoints();
|
List<WptPt> points = getEditingCtx().getPoints();
|
||||||
points.add(addTo, points.remove(removeFrom));
|
points.add(addTo, points.remove(removeFrom));
|
||||||
getEditingCtx().updateCacheForSnap();
|
getEditingCtx().updateSegmentsForSnap();
|
||||||
refreshMap();
|
refreshMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ public class ReversePointsCommand extends MeasurementModeCommand {
|
||||||
WptPt lastPoint = newPoints.get(newPoints.size() - 1);
|
WptPt lastPoint = newPoints.get(newPoints.size() - 1);
|
||||||
editingCtx.setAppMode(ApplicationMode.valueOfStringKey(lastPoint.getProfileType(), DEFAULT_APP_MODE));
|
editingCtx.setAppMode(ApplicationMode.valueOfStringKey(lastPoint.getProfileType(), DEFAULT_APP_MODE));
|
||||||
}
|
}
|
||||||
editingCtx.updateCacheForSnap();
|
editingCtx.updateSegmentsForSnap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -57,7 +57,7 @@ public class ReversePointsCommand extends MeasurementModeCommand {
|
||||||
editingCtx.addPoints(oldPoints);
|
editingCtx.addPoints(oldPoints);
|
||||||
editingCtx.setAppMode(oldMode);
|
editingCtx.setAppMode(oldMode);
|
||||||
editingCtx.setRoadSegmentData(oldRoadSegmentData);
|
editingCtx.setRoadSegmentData(oldRoadSegmentData);
|
||||||
editingCtx.updateCacheForSnap();
|
editingCtx.updateSegmentsForSnap();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,14 +50,13 @@ import net.osmand.plus.GpxSelectionHelper.GpxDisplayItemType;
|
||||||
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
|
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
|
||||||
import net.osmand.plus.OsmAndFormatter;
|
import net.osmand.plus.OsmAndFormatter;
|
||||||
import net.osmand.plus.OsmandApplication;
|
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.R;
|
||||||
import net.osmand.plus.activities.MapActivity;
|
import net.osmand.plus.activities.MapActivity;
|
||||||
import net.osmand.plus.activities.TrackActivity;
|
import net.osmand.plus.activities.TrackActivity;
|
||||||
import net.osmand.plus.dialogs.GpxAppearanceAdapter;
|
import net.osmand.plus.dialogs.GpxAppearanceAdapter;
|
||||||
import net.osmand.plus.measurementtool.GpxData;
|
|
||||||
import net.osmand.plus.myplaces.TrackBitmapDrawer.TrackBitmapDrawerListener;
|
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.GpxSplitType;
|
||||||
import net.osmand.plus.track.SplitTrackAsyncTask;
|
import net.osmand.plus.track.SplitTrackAsyncTask;
|
||||||
import net.osmand.plus.track.SplitTrackAsyncTask.SplitTrackListener;
|
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();
|
TrackActivity activity = getTrackActivity();
|
||||||
if (activity != null) {
|
if (activity != null) {
|
||||||
activity.addNewGpxData(actionType);
|
activity.addNewGpxData();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addNewGpxData(GpxData.ActionType actionType, GPXUtilities.TrkSegment segment) {
|
|
||||||
TrackActivity activity = getTrackActivity();
|
|
||||||
if (activity != null) {
|
|
||||||
activity.addNewGpxData(actionType, segment);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -951,10 +943,8 @@ public class TrackActivityFragmentAdapter implements TrackBitmapDrawerListener {
|
||||||
PointDescription pointWptDescription =
|
PointDescription pointWptDescription =
|
||||||
new PointDescription(PointDescription.POINT_TYPE_WPT, app.getString(R.string.add_waypoint));
|
new PointDescription(PointDescription.POINT_TYPE_WPT, app.getString(R.string.add_waypoint));
|
||||||
addPoint(pointWptDescription);
|
addPoint(pointWptDescription);
|
||||||
} else if (i == R.id.route_text_layout || i == R.id.route_fab) {
|
} else if (i == R.id.route_text_layout || i == R.id.route_fab || i == R.id.line_fab) {
|
||||||
addNewGpxData(GpxData.ActionType.ADD_ROUTE_POINTS);
|
addNewGpxData();
|
||||||
} else if (i == R.id.line_text_layout || i == R.id.line_fab) {
|
|
||||||
addNewGpxData(GpxData.ActionType.ADD_SEGMENT);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -65,11 +65,10 @@ import net.osmand.plus.helpers.GpxUiHelper;
|
||||||
import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetAxisType;
|
import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetAxisType;
|
||||||
import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetType;
|
import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetType;
|
||||||
import net.osmand.plus.helpers.GpxUiHelper.OrderedLineDataSet;
|
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.myplaces.TrackBitmapDrawer.TrackBitmapDrawerListener;
|
||||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
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;
|
||||||
import net.osmand.plus.views.controls.PagerSlidingTabStrip.CustomTabProvider;
|
import net.osmand.plus.views.controls.PagerSlidingTabStrip.CustomTabProvider;
|
||||||
import net.osmand.plus.views.controls.WrapContentHeightViewPager;
|
import net.osmand.plus.views.controls.WrapContentHeightViewPager;
|
||||||
|
@ -1026,7 +1025,7 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit
|
||||||
private void editSegment() {
|
private void editSegment() {
|
||||||
TrkSegment segment = getTrkSegment();
|
TrkSegment segment = getTrkSegment();
|
||||||
if (segment != null && fragmentAdapter != null) {
|
if (segment != null && fragmentAdapter != null) {
|
||||||
fragmentAdapter.addNewGpxData(GpxData.ActionType.EDIT_SEGMENT, segment);
|
fragmentAdapter.addNewGpxData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,6 @@ import androidx.fragment.app.FragmentManager;
|
||||||
import net.osmand.AndroidUtils;
|
import net.osmand.AndroidUtils;
|
||||||
import net.osmand.CallbackWithObject;
|
import net.osmand.CallbackWithObject;
|
||||||
import net.osmand.GPXUtilities.GPXFile;
|
import net.osmand.GPXUtilities.GPXFile;
|
||||||
import net.osmand.GPXUtilities.TrkSegment;
|
|
||||||
import net.osmand.GPXUtilities.WptPt;
|
import net.osmand.GPXUtilities.WptPt;
|
||||||
import net.osmand.IndexConstants;
|
import net.osmand.IndexConstants;
|
||||||
import net.osmand.PlatformUtil;
|
import net.osmand.PlatformUtil;
|
||||||
|
@ -44,7 +43,6 @@ import net.osmand.plus.helpers.GpxUiHelper.GPXInfo;
|
||||||
import net.osmand.plus.importfiles.ImportHelper;
|
import net.osmand.plus.importfiles.ImportHelper;
|
||||||
import net.osmand.plus.importfiles.ImportHelper.OnGpxImportCompleteListener;
|
import net.osmand.plus.importfiles.ImportHelper.OnGpxImportCompleteListener;
|
||||||
import net.osmand.plus.measurementtool.GpxData;
|
import net.osmand.plus.measurementtool.GpxData;
|
||||||
import net.osmand.plus.measurementtool.GpxData.ActionType;
|
|
||||||
import net.osmand.plus.measurementtool.MeasurementEditingContext;
|
import net.osmand.plus.measurementtool.MeasurementEditingContext;
|
||||||
import net.osmand.plus.measurementtool.MeasurementToolFragment;
|
import net.osmand.plus.measurementtool.MeasurementToolFragment;
|
||||||
import net.osmand.plus.routepreparationmenu.RoutingOptionsHelper.LocalRoutingParameter;
|
import net.osmand.plus.routepreparationmenu.RoutingOptionsHelper.LocalRoutingParameter;
|
||||||
|
@ -554,10 +552,7 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca
|
||||||
MapActivity mapActivity = getMapActivity();
|
MapActivity mapActivity = getMapActivity();
|
||||||
if (mapActivity != null && gpxFile != null) {
|
if (mapActivity != null && gpxFile != null) {
|
||||||
editingTrack = true;
|
editingTrack = true;
|
||||||
QuadRect rect = gpxFile.getRect();
|
GpxData gpxData = new GpxData(gpxFile);
|
||||||
TrkSegment segment = gpxFile.getNonEmptyTrkSegment();
|
|
||||||
ActionType actionType = segment == null ? ActionType.ADD_ROUTE_POINTS : ActionType.EDIT_SEGMENT;
|
|
||||||
GpxData gpxData = new GpxData(gpxFile, rect, actionType, segment);
|
|
||||||
MeasurementEditingContext editingContext = new MeasurementEditingContext();
|
MeasurementEditingContext editingContext = new MeasurementEditingContext();
|
||||||
editingContext.setGpxData(gpxData);
|
editingContext.setGpxData(gpxData);
|
||||||
editingContext.setAppMode(app.getRoutingHelper().getAppMode());
|
editingContext.setAppMode(app.getRoutingHelper().getAppMode());
|
||||||
|
|
|
@ -1,28 +1,23 @@
|
||||||
package net.osmand.plus.routing;
|
package net.osmand.plus.routing;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import net.osmand.LocationsHolder;
|
import net.osmand.LocationsHolder;
|
||||||
import net.osmand.PlatformUtil;
|
import net.osmand.PlatformUtil;
|
||||||
import net.osmand.ResultMatcher;
|
import net.osmand.ResultMatcher;
|
||||||
import net.osmand.data.LatLon;
|
import net.osmand.data.LatLon;
|
||||||
import net.osmand.plus.OsmandApplication;
|
import net.osmand.plus.OsmandApplication;
|
||||||
import net.osmand.plus.measurementtool.GpxApproximationFragment;
|
|
||||||
import net.osmand.plus.routing.RouteProvider.RoutingEnvironment;
|
import net.osmand.plus.routing.RouteProvider.RoutingEnvironment;
|
||||||
import net.osmand.plus.settings.backend.ApplicationMode;
|
import net.osmand.plus.settings.backend.ApplicationMode;
|
||||||
import net.osmand.router.RouteCalculationProgress;
|
import net.osmand.router.RouteCalculationProgress;
|
||||||
import net.osmand.router.RoutePlannerFrontEnd;
|
|
||||||
import net.osmand.router.RoutePlannerFrontEnd.GpxPoint;
|
import net.osmand.router.RoutePlannerFrontEnd.GpxPoint;
|
||||||
import net.osmand.router.RoutePlannerFrontEnd.GpxRouteApproximation;
|
import net.osmand.router.RoutePlannerFrontEnd.GpxRouteApproximation;
|
||||||
import net.osmand.search.core.SearchResult;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
@ -31,29 +26,31 @@ public class GpxApproximator {
|
||||||
|
|
||||||
protected static final Log log = PlatformUtil.getLog(GpxApproximator.class);
|
protected static final Log log = PlatformUtil.getLog(GpxApproximator.class);
|
||||||
|
|
||||||
private OsmandApplication ctx;
|
private final OsmandApplication ctx;
|
||||||
private RoutingHelper routingHelper;
|
private final RoutingHelper routingHelper;
|
||||||
|
|
||||||
private RoutingEnvironment env;
|
private RoutingEnvironment env;
|
||||||
private GpxRouteApproximation gctx;
|
private GpxRouteApproximation gctx;
|
||||||
private ApplicationMode mode;
|
private ApplicationMode mode;
|
||||||
private LocationsHolder locationsHolder;
|
private final LocationsHolder locationsHolder;
|
||||||
private List<GpxPoint> points;
|
private List<GpxPoint> points;
|
||||||
private LatLon start;
|
private LatLon start;
|
||||||
private LatLon end;
|
private LatLon end;
|
||||||
private double pointApproximation = 50;
|
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 GpxApproximationProgressCallback approximationProgress;
|
||||||
private Future<?> currentApproximationTask;
|
|
||||||
|
|
||||||
public interface GpxApproximationProgressCallback {
|
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 {
|
public GpxApproximator(@NonNull OsmandApplication ctx, @NonNull LocationsHolder locationsHolder) throws IOException {
|
||||||
|
@ -61,12 +58,7 @@ public class GpxApproximator {
|
||||||
this.locationsHolder = locationsHolder;
|
this.locationsHolder = locationsHolder;
|
||||||
this.routingHelper = ctx.getRoutingHelper();
|
this.routingHelper = ctx.getRoutingHelper();
|
||||||
this.mode = ApplicationMode.CAR;
|
this.mode = ApplicationMode.CAR;
|
||||||
if (locationsHolder.getSize() > 1) {
|
initEnvironment(mode, locationsHolder);
|
||||||
start = locationsHolder.getLatLon(0);
|
|
||||||
end = locationsHolder.getLatLon(locationsHolder.getSize() - 1);
|
|
||||||
prepareEnvironment(ctx, mode);
|
|
||||||
}
|
|
||||||
init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public GpxApproximator(@NonNull OsmandApplication ctx, @NonNull ApplicationMode mode, double pointApproximation, @NonNull LocationsHolder locationsHolder) throws IOException {
|
public GpxApproximator(@NonNull OsmandApplication ctx, @NonNull ApplicationMode mode, double pointApproximation, @NonNull LocationsHolder locationsHolder) throws IOException {
|
||||||
|
@ -75,16 +67,19 @@ public class GpxApproximator {
|
||||||
this.pointApproximation = pointApproximation;
|
this.pointApproximation = pointApproximation;
|
||||||
this.routingHelper = ctx.getRoutingHelper();
|
this.routingHelper = ctx.getRoutingHelper();
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
|
initEnvironment(mode, locationsHolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initEnvironment(@NonNull ApplicationMode mode, @NonNull LocationsHolder locationsHolder) throws IOException {
|
||||||
if (locationsHolder.getSize() > 1) {
|
if (locationsHolder.getSize() > 1) {
|
||||||
start = locationsHolder.getLatLon(0);
|
start = locationsHolder.getLatLon(0);
|
||||||
end = locationsHolder.getLatLon(locationsHolder.getSize() - 1);
|
end = locationsHolder.getLatLon(locationsHolder.getSize() - 1);
|
||||||
prepareEnvironment(ctx, mode);
|
prepareEnvironment(ctx, mode);
|
||||||
}
|
}
|
||||||
init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init() {
|
public static void cancelPendingApproximations() {
|
||||||
singleThreadedExecutor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
|
SINGLE_THREAD_EXECUTOR.getQueue().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void prepareEnvironment(@NonNull OsmandApplication ctx, @NonNull ApplicationMode mode) throws IOException {
|
private void prepareEnvironment(@NonNull OsmandApplication ctx, @NonNull ApplicationMode mode) throws IOException {
|
||||||
|
@ -140,6 +135,10 @@ public class GpxApproximator {
|
||||||
this.approximationProgress = approximationProgress;
|
this.approximationProgress = approximationProgress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return gctx != null && gctx.ctx.calculationProgress.isCancelled;
|
||||||
|
}
|
||||||
|
|
||||||
public void cancelApproximation() {
|
public void cancelApproximation() {
|
||||||
if (gctx != null) {
|
if (gctx != null) {
|
||||||
gctx.ctx.calculationProgress.isCancelled = true;
|
gctx.ctx.calculationProgress.isCancelled = true;
|
||||||
|
@ -154,10 +153,7 @@ public class GpxApproximator {
|
||||||
this.gctx = gctx;
|
this.gctx = gctx;
|
||||||
startProgress();
|
startProgress();
|
||||||
updateProgress(gctx);
|
updateProgress(gctx);
|
||||||
if (currentApproximationTask != null) {
|
approximationTask = new Runnable() {
|
||||||
currentApproximationTask.cancel(true);
|
|
||||||
}
|
|
||||||
currentApproximationTask = singleThreadedExecutor.submit(new Runnable() {
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
|
@ -166,21 +162,23 @@ public class GpxApproximator {
|
||||||
resultMatcher.publish(null);
|
resultMatcher.publish(null);
|
||||||
log.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
approximationTask = null;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
SINGLE_THREAD_EXECUTOR.submit(approximationTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startProgress() {
|
private void startProgress() {
|
||||||
final GpxApproximationProgressCallback approximationProgress = this.approximationProgress;
|
final GpxApproximationProgressCallback approximationProgress = this.approximationProgress;
|
||||||
if (approximationProgress != null) {
|
if (approximationProgress != null) {
|
||||||
approximationProgress.start();
|
approximationProgress.start(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void finishProgress() {
|
private void finishProgress() {
|
||||||
final GpxApproximationProgressCallback approximationProgress = this.approximationProgress;
|
final GpxApproximationProgressCallback approximationProgress = this.approximationProgress;
|
||||||
if (approximationProgress != null) {
|
if (approximationProgress != null) {
|
||||||
approximationProgress.finish();
|
approximationProgress.finish(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,12 +190,12 @@ public class GpxApproximator {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
RouteCalculationProgress calculationProgress = gctx.ctx.calculationProgress;
|
RouteCalculationProgress calculationProgress = gctx.ctx.calculationProgress;
|
||||||
if (!gctx.result.isEmpty() && GpxApproximator.this.gctx == gctx) {
|
if (approximationTask == null && GpxApproximator.this.gctx == gctx) {
|
||||||
finishProgress();
|
finishProgress();
|
||||||
}
|
}
|
||||||
if (gctx.result.isEmpty() && calculationProgress != null && !calculationProgress.isCancelled) {
|
if (approximationTask != null && calculationProgress != null && !calculationProgress.isCancelled) {
|
||||||
float pr = calculationProgress.getLinearProgress();
|
float pr = calculationProgress.getLinearProgress();
|
||||||
approximationProgress.updateProgress((int) pr);
|
approximationProgress.updateProgress(GpxApproximator.this, (int) pr);
|
||||||
if (GpxApproximator.this.gctx != gctx) {
|
if (GpxApproximator.this.gctx != gctx) {
|
||||||
// different calculation started
|
// different calculation started
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -78,6 +78,7 @@ public class ApplicationMode {
|
||||||
public static final ApplicationMode DEFAULT = createBase(R.string.app_mode_default, "default")
|
public static final ApplicationMode DEFAULT = createBase(R.string.app_mode_default, "default")
|
||||||
.icon(R.drawable.ic_world_globe_dark).reg();
|
.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")
|
public static final ApplicationMode CAR = createBase(R.string.app_mode_car, "car")
|
||||||
.icon(R.drawable.ic_action_car_dark)
|
.icon(R.drawable.ic_action_car_dark)
|
||||||
|
|
Loading…
Reference in a new issue