commit
41d76662bd
44 changed files with 1236 additions and 810 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,20 @@ 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 boolean isGap() {
|
||||||
|
String profileType = getProfileType();
|
||||||
|
return GAP_PROFILE_TYPE.equals(profileType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGap() {
|
||||||
|
setProfileType(GAP_PROFILE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
public void removeProfileType() {
|
public void removeProfileType() {
|
||||||
getExtensionsToWrite().remove(PROFILE_TYPE_EXTENSION);
|
getExtensionsToWrite().remove(PROFILE_TYPE_EXTENSION);
|
||||||
}
|
}
|
||||||
|
@ -374,11 +389,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 +413,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 +1097,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 +1124,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 +1234,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 +1259,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 +1343,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 +1391,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 +1634,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 +1746,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 +1833,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 +1862,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 +1874,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 +1928,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 +1973,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 +2142,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 +2447,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 +2467,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;
|
||||||
}
|
}
|
||||||
|
|
32
OsmAnd/res/drawable/shadow.xml
Normal file
32
OsmAnd/res/drawable/shadow.xml
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<item>
|
||||||
|
<shape
|
||||||
|
android:dither="true"
|
||||||
|
android:shape="rectangle">
|
||||||
|
|
||||||
|
<gradient
|
||||||
|
android:angle="90"
|
||||||
|
android:startColor="#1A000000"
|
||||||
|
android:centerColor="#00FFFFFF"
|
||||||
|
android:endColor="#00FFFFFF" />
|
||||||
|
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
<item>
|
||||||
|
<shape
|
||||||
|
android:dither="true"
|
||||||
|
android:shape="rectangle">
|
||||||
|
|
||||||
|
<gradient
|
||||||
|
android:angle="90"
|
||||||
|
android:startColor="#0D000000"
|
||||||
|
android:centerColor="#00FFFFFF"
|
||||||
|
android:endColor="#00FFFFFF" />
|
||||||
|
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
</layer-list>
|
|
@ -38,9 +38,9 @@
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/buttons_shadow"
|
android:id="@+id/buttons_shadow"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="10dp"
|
android:layout_height="8dp"
|
||||||
android:layout_gravity="bottom"
|
android:layout_gravity="bottom"
|
||||||
android:background="@drawable/bg_contextmenu_shadow_top_light"
|
android:background="@drawable/shadow"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
<include layout="@layout/bottom_buttons" />
|
<include layout="@layout/bottom_buttons" />
|
||||||
|
|
|
@ -33,9 +33,9 @@
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/buttons_shadow"
|
android:id="@+id/buttons_shadow"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="10dp"
|
android:layout_height="8dp"
|
||||||
android:layout_gravity="bottom"
|
android:layout_gravity="bottom"
|
||||||
android:background="@drawable/bg_contextmenu_shadow_top_light"
|
android:background="@drawable/shadow"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
|
|
@ -32,8 +32,8 @@
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/buttons_shadow"
|
android:id="@+id/buttons_shadow"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="10dp"
|
android:layout_height="8dp"
|
||||||
android:background="@drawable/bg_contextmenu_shadow_top_light" />
|
android:background="@drawable/shadow" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -128,9 +128,9 @@
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/buttons_shadow"
|
android:id="@+id/buttons_shadow"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="10dp"
|
android:layout_height="8dp"
|
||||||
android:layout_gravity="bottom"
|
android:layout_gravity="bottom"
|
||||||
android:background="@drawable/bg_contextmenu_shadow_top_light" />
|
android:background="@drawable/shadow" />
|
||||||
|
|
||||||
<include
|
<include
|
||||||
layout="@layout/bottom_buttons"
|
layout="@layout/bottom_buttons"
|
||||||
|
|
|
@ -98,9 +98,9 @@
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/buttons_shadow"
|
android:id="@+id/buttons_shadow"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="10dp"
|
android:layout_height="8dp"
|
||||||
android:layout_gravity="bottom"
|
android:layout_gravity="bottom"
|
||||||
android:background="@drawable/bg_contextmenu_shadow_top_light" />
|
android:background="@drawable/shadow" />
|
||||||
|
|
||||||
<include
|
<include
|
||||||
layout="@layout/bottom_buttons"
|
layout="@layout/bottom_buttons"
|
||||||
|
|
|
@ -591,9 +591,9 @@
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/buttons_shadow"
|
android:id="@+id/buttons_shadow"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="10dp"
|
android:layout_height="8dp"
|
||||||
android:layout_gravity="bottom"
|
android:layout_gravity="bottom"
|
||||||
android:background="@drawable/bg_contextmenu_shadow_top_light" />
|
android:background="@drawable/shadow" />
|
||||||
|
|
||||||
<include
|
<include
|
||||||
layout="@layout/route_info_menu_control_buttons"
|
layout="@layout/route_info_menu_control_buttons"
|
||||||
|
|
|
@ -129,9 +129,9 @@
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/buttons_shadow"
|
android:id="@+id/buttons_shadow"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="10dp"
|
android:layout_height="8dp"
|
||||||
android:layout_gravity="bottom"
|
android:layout_gravity="bottom"
|
||||||
android:background="@drawable/bg_contextmenu_shadow_top_light" />
|
android:background="@drawable/shadow" />
|
||||||
|
|
||||||
<include
|
<include
|
||||||
layout="@layout/bottom_buttons"
|
layout="@layout/bottom_buttons"
|
||||||
|
|
|
@ -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="message_graph_will_be_available_after_recalculation">Wait for the route recalculation.\nGraph will be available after recalculation.</string>
|
<string name="message_graph_will_be_available_after_recalculation">Wait for the route recalculation.\nGraph will be available after recalculation.</string>
|
||||||
<string name="message_need_calculate_route_before_show_graph">%1$s data available only on the roads, you need to calculate a route using “Route between points” to get it.</string>
|
<string name="message_need_calculate_route_before_show_graph">%1$s data available only on the roads, you need to calculate a route using “Route between points” to get it.</string>
|
||||||
<string name="shared_string_graph">Graph</string>
|
<string name="shared_string_graph">Graph</string>
|
||||||
|
|
|
@ -428,7 +428,7 @@ public class FavouritesDbHelper {
|
||||||
while (fl) {
|
while (fl) {
|
||||||
fl = false;
|
fl = false;
|
||||||
for (FavouritePoint fp : fdb.getFavouritePoints()) {
|
for (FavouritePoint fp : fdb.getFavouritePoints()) {
|
||||||
if (fp.getName().equals(name) && p.getLatitude() != fp.getLatitude() && p.getLongitude() != fp.getLongitude()) {
|
if (fp.getName().equals(name) && p.getLatitude() != fp.getLatitude() && p.getLongitude() != fp.getLongitude() && fp.getCategory().equals(p.getCategory())) {
|
||||||
number++;
|
number++;
|
||||||
index = " (" + number + ")";
|
index = " (" + number + ")";
|
||||||
name = p.getName() + index;
|
name = p.getName() + index;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -423,7 +423,7 @@ public abstract class MenuBottomSheetDialogFragment extends BottomSheetDialogFra
|
||||||
|
|
||||||
private LayerDrawable createBackgroundDrawable(@NonNull Context ctx, @DrawableRes int shadowDrawableResId) {
|
private LayerDrawable createBackgroundDrawable(@NonNull Context ctx, @DrawableRes int shadowDrawableResId) {
|
||||||
Drawable shadowDrawable = ContextCompat.getDrawable(ctx, shadowDrawableResId);
|
Drawable shadowDrawable = ContextCompat.getDrawable(ctx, shadowDrawableResId);
|
||||||
Drawable[] layers = new Drawable[] {shadowDrawable, getColoredBg(ctx)};
|
Drawable[] layers = new Drawable[]{shadowDrawable, getColoredBg(ctx)};
|
||||||
return new LayerDrawable(layers);
|
return new LayerDrawable(layers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,6 +434,21 @@ public abstract class MenuBottomSheetDialogFragment extends BottomSheetDialogFra
|
||||||
return !app.getSettings().isLightContent();
|
return !app.getSettings().isLightContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void showShadowButton() {
|
||||||
|
buttonsShadow.setVisibility(View.VISIBLE);
|
||||||
|
buttonsShadow.animate()
|
||||||
|
.alpha(0.8f)
|
||||||
|
.setDuration(200)
|
||||||
|
.setListener(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hideShadowButton() {
|
||||||
|
buttonsShadow.animate()
|
||||||
|
.alpha(0f)
|
||||||
|
.setDuration(200);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private void setupScrollShadow(View view) {
|
private void setupScrollShadow(View view) {
|
||||||
final View scrollView;
|
final View scrollView;
|
||||||
if (useScrollableItemsContainer()) {
|
if (useScrollableItemsContainer()) {
|
||||||
|
@ -446,7 +461,11 @@ public abstract class MenuBottomSheetDialogFragment extends BottomSheetDialogFra
|
||||||
@Override
|
@Override
|
||||||
public void onScrollChanged() {
|
public void onScrollChanged() {
|
||||||
boolean scrollToBottomAvailable = scrollView.canScrollVertically(1);
|
boolean scrollToBottomAvailable = scrollView.canScrollVertically(1);
|
||||||
AndroidUiHelper.updateVisibility(buttonsShadow, scrollToBottomAvailable);
|
if (scrollToBottomAvailable) {
|
||||||
|
showShadowButton();
|
||||||
|
} else {
|
||||||
|
hideShadowButton();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -670,7 +670,10 @@ public class ImportHelper {
|
||||||
}
|
}
|
||||||
fp.setAddress(p.getExtensionsToRead().get("address"));
|
fp.setAddress(p.getExtensionsToRead().get("address"));
|
||||||
fp.setColor(p.getColor(0));
|
fp.setColor(p.getColor(0));
|
||||||
fp.setIconIdFromName(app, p.getIconName());
|
String iconName = p.getIconName();
|
||||||
|
if (iconName != null) {
|
||||||
|
fp.setIconIdFromName(app, iconName);
|
||||||
|
}
|
||||||
fp.setBackgroundType(BackgroundType.getByTypeName(p.getBackgroundType(), DEFAULT_BACKGROUND_TYPE));
|
fp.setBackgroundType(BackgroundType.getByTypeName(p.getBackgroundType(), DEFAULT_BACKGROUND_TYPE));
|
||||||
favourites.add(fp);
|
favourites.add(fp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -341,7 +341,7 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen
|
||||||
if (editingCtx.getGpxData() != null) {
|
if (editingCtx.getGpxData() != null) {
|
||||||
gpx = editingCtx.getGpxData().getGpxFile();
|
gpx = editingCtx.getGpxData().getGpxFile();
|
||||||
} else {
|
} else {
|
||||||
gpx = editingCtx.exportRouteAsGpx(GRAPH_DATA_GPX_FILE_NAME);
|
gpx = editingCtx.exportGpx(GRAPH_DATA_GPX_FILE_NAME);
|
||||||
}
|
}
|
||||||
return gpx != null ? gpx.getAnalysis(0) : null;
|
return gpx != null ? gpx.getAnalysis(0) : null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
@ -63,6 +65,7 @@ public class MeasurementEditingContext {
|
||||||
private WptPt originalPointToMove;
|
private WptPt originalPointToMove;
|
||||||
|
|
||||||
private boolean inAddPointMode;
|
private boolean inAddPointMode;
|
||||||
|
private boolean inAddPointBeforeMode;
|
||||||
private boolean inApproximationMode;
|
private boolean inApproximationMode;
|
||||||
private int calculatedPairs;
|
private int calculatedPairs;
|
||||||
private int pointsToCalculateSize;
|
private int pointsToCalculateSize;
|
||||||
|
@ -72,18 +75,23 @@ public class MeasurementEditingContext {
|
||||||
private RouteCalculationProgress calculationProgress;
|
private RouteCalculationProgress calculationProgress;
|
||||||
private Map<Pair<WptPt, WptPt>, RoadSegmentData> roadSegmentData = new ConcurrentHashMap<>();
|
private Map<Pair<WptPt, WptPt>, RoadSegmentData> roadSegmentData = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
|
||||||
public enum CalculationMode {
|
public enum CalculationMode {
|
||||||
NEXT_SEGMENT,
|
NEXT_SEGMENT,
|
||||||
WHOLE_TRACK
|
WHOLE_TRACK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum AdditionMode {
|
||||||
|
UNDEFINED,
|
||||||
|
ADD_AFTER,
|
||||||
|
ADD_BEFORE,
|
||||||
|
}
|
||||||
|
|
||||||
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 +164,12 @@ public class MeasurementEditingContext {
|
||||||
return inAddPointMode;
|
return inAddPointMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateCacheForSnap() {
|
public boolean isInAddPointBeforeMode() {
|
||||||
updateCacheForSnap(true);
|
return inAddPointBeforeMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateSegmentsForSnap() {
|
||||||
|
updateSegmentsForSnap(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSelectedPointPosition() {
|
public int getSelectedPointPosition() {
|
||||||
|
@ -176,8 +188,9 @@ public class MeasurementEditingContext {
|
||||||
this.originalPointToMove = originalPointToMove;
|
this.originalPointToMove = originalPointToMove;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setInAddPointMode(boolean inAddPointMode) {
|
void setInAddPointMode(boolean inAddPointMode, boolean inAddPointAfterMode) {
|
||||||
this.inAddPointMode = inAddPointMode;
|
this.inAddPointMode = inAddPointMode;
|
||||||
|
this.inAddPointBeforeMode = inAddPointAfterMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isInApproximationMode() {
|
public boolean isInApproximationMode() {
|
||||||
|
@ -188,10 +201,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 +226,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 +261,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 +288,104 @@ 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 boolean isSelectionNeedApproximation() {
|
||||||
|
boolean hasDefaultPoints = false;
|
||||||
|
boolean newData = isNewData();
|
||||||
|
if (!newData && selectedPointPosition != -1) {
|
||||||
|
WptPt selectedPoint = getPoints().get(selectedPointPosition);
|
||||||
|
List<TrkSegment> segments = getBeforeSegments();
|
||||||
|
List<WptPt> points = null;
|
||||||
|
for (TrkSegment segment : segments) {
|
||||||
|
if (segment.points.contains(selectedPoint)) {
|
||||||
|
points = segment.points;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WptPt prevPoint = null;
|
||||||
|
if (points != null) {
|
||||||
|
for (WptPt point : points) {
|
||||||
|
if (!point.hasProfile() && (prevPoint == null || !prevPoint.hasProfile())) {
|
||||||
|
hasDefaultPoints = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prevPoint = point;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !newData && hasDefaultPoints && getPoints().size() > 2;
|
||||||
|
}
|
||||||
|
|
||||||
public void clearSnappedToRoadPoints() {
|
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<TrkSegment> getBeforeSegments() {
|
||||||
|
return beforeSegments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TrkSegment> getAfterSegments() {
|
||||||
|
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 = point.isGap();
|
||||||
|
boolean plainPoint = Algorithms.isEmpty(profileType) || (isGap && Algorithms.isEmpty(prevProfileType));
|
||||||
|
boolean routePoint = !plainPoint;
|
||||||
|
if (plain && plainPoint || route && routePoint) {
|
||||||
|
segment.add(point);
|
||||||
|
if (isGap) {
|
||||||
|
res.add(segment);
|
||||||
|
segment = new ArrayList<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prevProfileType = profileType;
|
||||||
|
}
|
||||||
|
if (!segment.isEmpty()) {
|
||||||
|
res.add(segment);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
List<WptPt> getBeforePoints() {
|
List<WptPt> getBeforePoints() {
|
||||||
return before.points;
|
return before.points;
|
||||||
}
|
}
|
||||||
|
@ -335,31 +420,118 @@ 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void preAddPoint(int position, AdditionMode additionMode, WptPt point) {
|
||||||
|
switch (additionMode) {
|
||||||
|
case UNDEFINED: {
|
||||||
|
if (appMode != MeasurementEditingContext.DEFAULT_APP_MODE) {
|
||||||
|
point.setProfileType(appMode.getStringKey());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ADD_AFTER: {
|
||||||
|
List<WptPt> points = getBeforePoints();
|
||||||
|
if (position > 0 && position <= points.size()) {
|
||||||
|
WptPt prevPt = points.get(position - 1);
|
||||||
|
if (prevPt.isGap()) {
|
||||||
|
point.setGap();
|
||||||
|
if (position > 1) {
|
||||||
|
WptPt pt = points.get(position - 2);
|
||||||
|
if (pt.hasProfile()) {
|
||||||
|
prevPt.setProfileType(pt.getProfileType());
|
||||||
|
} else {
|
||||||
|
prevPt.removeProfileType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (prevPt.hasProfile()) {
|
||||||
|
point.setProfileType(prevPt.getProfileType());
|
||||||
|
}
|
||||||
|
} else if (appMode != MeasurementEditingContext.DEFAULT_APP_MODE) {
|
||||||
|
point.setProfileType(appMode.getStringKey());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ADD_BEFORE: {
|
||||||
|
List<WptPt> points = getAfterPoints();
|
||||||
|
if (position >= -1 && position + 1 < points.size()) {
|
||||||
|
WptPt nextPt = points.get(position + 1);
|
||||||
|
if (nextPt.hasProfile()) {
|
||||||
|
point.setProfileType(nextPt.getProfileType());
|
||||||
|
}
|
||||||
|
} else if (appMode != MeasurementEditingContext.DEFAULT_APP_MODE) {
|
||||||
|
point.setProfileType(appMode.getStringKey());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addPoint(WptPt pt) {
|
public void addPoint(WptPt pt) {
|
||||||
|
addPoint(pt, AdditionMode.UNDEFINED);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addPoint(WptPt pt, AdditionMode additionMode) {
|
||||||
|
if (additionMode == AdditionMode.ADD_AFTER || additionMode == AdditionMode.ADD_BEFORE) {
|
||||||
|
preAddPoint(additionMode == AdditionMode.ADD_BEFORE ? -1 : getBeforePoints().size(), additionMode, pt);
|
||||||
|
}
|
||||||
before.points.add(pt);
|
before.points.add(pt);
|
||||||
updateCacheForSnap(false);
|
updateSegmentsForSnap(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addPoint(int position, WptPt pt) {
|
public void addPoint(int position, WptPt pt) {
|
||||||
|
addPoint(position, pt, AdditionMode.UNDEFINED);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addPoint(int position, WptPt pt, AdditionMode additionMode) {
|
||||||
|
if (additionMode == AdditionMode.ADD_AFTER || additionMode == AdditionMode.ADD_BEFORE) {
|
||||||
|
preAddPoint(position, additionMode, pt);
|
||||||
|
}
|
||||||
before.points.add(position, pt);
|
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) {
|
||||||
if (position < 0 || position >= before.points.size()) {
|
if (position < 0 || position >= before.points.size()) {
|
||||||
return new WptPt();
|
return new WptPt();
|
||||||
}
|
}
|
||||||
WptPt pt = before.points.remove(position);
|
WptPt pt = before.points.get(position);
|
||||||
|
if (position > 0 && pt.isGap()) {
|
||||||
|
WptPt prevPt = before.points.get(position - 1);
|
||||||
|
if (!prevPt.isGap()) {
|
||||||
|
prevPt.setGap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
before.points.remove(position);
|
||||||
if (updateSnapToRoad) {
|
if (updateSnapToRoad) {
|
||||||
updateCacheForSnap(false);
|
updateSegmentsForSnap(false);
|
||||||
}
|
}
|
||||||
return pt;
|
return pt;
|
||||||
}
|
}
|
||||||
|
@ -382,24 +554,40 @@ 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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFirstPointSelected() {
|
public boolean isFirstPointSelected() {
|
||||||
return selectedPointPosition == 0;
|
return isBorderPointSelected(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isLastPointSelected() {
|
public boolean isLastPointSelected() {
|
||||||
return selectedPointPosition == getPoints().size() - 1;
|
return isBorderPointSelected(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBorderPointSelected(boolean first) {
|
||||||
|
WptPt selectedPoint = getPoints().get(selectedPointPosition);
|
||||||
|
List<TrkSegment> segments = getBeforeSegments();
|
||||||
|
int count = 0;
|
||||||
|
for (TrkSegment segment : segments) {
|
||||||
|
int i = segment.points.indexOf(selectedPoint);
|
||||||
|
if (i != -1) {
|
||||||
|
int segmentPosition = selectedPointPosition - count;
|
||||||
|
return first ? segmentPosition == 0 : segmentPosition == segment.points.size() - 1;
|
||||||
|
} else {
|
||||||
|
count += segment.points.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ApplicationMode getSelectedPointAppMode() {
|
public ApplicationMode getSelectedPointAppMode() {
|
||||||
|
@ -438,8 +626,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -447,7 +637,7 @@ public class MeasurementEditingContext {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Pair<WptPt, WptPt>> getOrderedRoadSegmentDataKeys() {
|
private List<Pair<WptPt, WptPt>> getOrderedRoadSegmentDataKeys() {
|
||||||
List<Pair<WptPt, WptPt>> keys = new ArrayList<>();
|
List<Pair<WptPt, WptPt>> keys = 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++) {
|
||||||
|
@ -456,99 +646,141 @@ public class MeasurementEditingContext {
|
||||||
}
|
}
|
||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
if (original.points.size() > 1) {
|
boolean isDefault = profileType.equals(DEFAULT_APP_MODE.getStringKey());
|
||||||
for (int i = 0; i < original.points.size() - 1; i++) {
|
boolean isGap = point.isGap();
|
||||||
Pair<WptPt, WptPt> pair = new Pair<>(original.points.get(i), original.points.get(i + 1));
|
if (defaultMode && !isDefault && !isGap) {
|
||||||
RoadSegmentData data = this.roadSegmentData.get(pair);
|
roadSegmentIndexes.add(segments.size() - 1);
|
||||||
List<WptPt> pts = data != null ? data.getPoints() : null;
|
defaultMode = false;
|
||||||
if (pts != null) {
|
}
|
||||||
cache.points.addAll(pts);
|
if (isGap) {
|
||||||
} else {
|
if (!s.points.isEmpty()) {
|
||||||
if (calculateIfNeeded && !hasDefaultModeOnly) {
|
s = new TrkSegment();
|
||||||
scheduleRouteCalculateIfNotEmpty();
|
segments.add(s);
|
||||||
|
defaultMode = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cache.points.addAll(Arrays.asList(pair.first, pair.second));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cache.points.addAll(original.points);
|
s.points.addAll(points);
|
||||||
|
}
|
||||||
|
if (s.points.isEmpty()) {
|
||||||
|
segments.remove(s);
|
||||||
|
}
|
||||||
|
if (!segments.isEmpty()) {
|
||||||
|
for (TrkSegment segment : segments) {
|
||||||
|
TrkSegment segmentForSnap = new TrkSegment();
|
||||||
|
for (int i = 0; i < segment.points.size() - 1; i++) {
|
||||||
|
Pair<WptPt, WptPt> pair = new Pair<>(segment.points.get(i), segment.points.get(i + 1));
|
||||||
|
RoadSegmentData data = this.roadSegmentData.get(pair);
|
||||||
|
List<WptPt> pts = data != null ? data.getPoints() : null;
|
||||||
|
if (pts != null) {
|
||||||
|
segmentForSnap.points.addAll(pts);
|
||||||
|
} else {
|
||||||
|
if (calculateIfNeeded && roadSegmentIndexes.contains(segmentsForSnap.size())) {
|
||||||
|
scheduleRouteCalculateIfNotEmpty();
|
||||||
|
}
|
||||||
|
segmentForSnap.points.addAll(Arrays.asList(pair.first, pair.second));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (segmentForSnap.points.isEmpty()) {
|
||||||
|
segmentForSnap.points.addAll(segment.points);
|
||||||
|
}
|
||||||
|
segmentsForSnap.add(segmentForSnap);
|
||||||
|
}
|
||||||
|
} else if (!points.isEmpty()) {
|
||||||
|
TrkSegment segmentForSnap = new TrkSegment();
|
||||||
|
segmentForSnap.points.addAll(points);
|
||||||
|
segmentsForSnap.add(segmentForSnap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addPoints() {
|
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).setGap();
|
||||||
|
}
|
||||||
|
addPoints(routePoints);
|
||||||
|
} else {
|
||||||
|
addPoints(points);
|
||||||
|
if (!points.isEmpty() && si < segments.size() - 1) {
|
||||||
|
points.get(points.size() - 1).setGap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addPoints(routePoints);
|
|
||||||
} else {
|
|
||||||
addPoints(points);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPoints(GpxRouteApproximation gpxApproximation, ApplicationMode mode) {
|
public List<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++) {
|
||||||
|
@ -590,7 +822,13 @@ public class MeasurementEditingContext {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addPoints(routePoints);
|
WptPt lastOriginalPoint = originalPoints.get(originalPoints.size() - 1);
|
||||||
|
WptPt lastRoutePoint = routePoints.get(routePoints.size() - 1);
|
||||||
|
if (lastOriginalPoint.isGap()) {
|
||||||
|
lastRoutePoint.setGap();
|
||||||
|
}
|
||||||
|
replacePoints(originalPoints, routePoints);
|
||||||
|
return routePoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isLastGpxPoint(List<GpxPoint> gpxPoints, int index) {
|
private boolean isLastGpxPoint(List<GpxPoint> gpxPoints, int index) {
|
||||||
|
@ -648,24 +886,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -718,7 +953,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);
|
||||||
}
|
}
|
||||||
|
@ -762,7 +997,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) {
|
||||||
|
@ -777,34 +1012,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 (point.isGap()) {
|
||||||
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());
|
||||||
|
@ -814,11 +1056,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 (pt.isGap()) {
|
||||||
|
lastPointIndexes.add(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lastPointIndexes.isEmpty() || lastPointIndexes.get(lastPointIndexes.size() - 1) < before.points.size() - 1) {
|
||||||
|
lastPointIndexes.add(before.points.size() - 1);
|
||||||
|
}
|
||||||
|
int firstPointIndex = 0;
|
||||||
|
for (Integer lastPointIndex : lastPointIndexes) {
|
||||||
|
TrkSegment segment = getRouteSegment(firstPointIndex, lastPointIndex);
|
||||||
|
if (segment != null) {
|
||||||
|
res.add(segment);
|
||||||
|
}
|
||||||
|
firstPointIndex = lastPointIndex + 1;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SnapToRoadProgressListener {
|
interface SnapToRoadProgressListener {
|
||||||
|
|
|
@ -34,9 +34,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;
|
||||||
|
@ -53,7 +51,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;
|
||||||
|
@ -139,7 +136,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;
|
||||||
|
@ -149,7 +145,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
private LatLon initialPoint;
|
private LatLon initialPoint;
|
||||||
|
|
||||||
enum SaveType {
|
enum SaveType {
|
||||||
ROUTE_POINT,
|
ROUTE,
|
||||||
LINE
|
LINE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,7 +351,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,
|
||||||
|
@ -503,7 +499,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 {
|
||||||
|
@ -570,7 +566,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();
|
||||||
|
@ -581,13 +576,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -675,16 +666,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) {
|
||||||
|
@ -696,15 +678,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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -713,12 +695,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);
|
||||||
|
@ -732,6 +713,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) {
|
||||||
|
@ -742,14 +724,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;
|
||||||
}
|
}
|
||||||
|
@ -757,10 +741,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -792,7 +780,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);
|
||||||
|
@ -800,15 +788,15 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
Toast.makeText(mapActivity, getString(R.string.error_occurred_saving_gpx), Toast.LENGTH_SHORT).show();
|
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -860,7 +848,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addToTheTrackOnClick() {
|
public void addToTrackOnClick() {
|
||||||
MapActivity mapActivity = getMapActivity();
|
MapActivity mapActivity = getMapActivity();
|
||||||
if (mapActivity != null) {
|
if (mapActivity != null) {
|
||||||
if (editingCtx.getPointsCount() > 0) {
|
if (editingCtx.getPointsCount() > 0) {
|
||||||
|
@ -927,7 +915,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
MeasurementToolLayer measurementLayer = getMeasurementLayer();
|
MeasurementToolLayer measurementLayer = getMeasurementLayer();
|
||||||
if (measurementLayer != null) {
|
if (measurementLayer != null) {
|
||||||
measurementLayer.moveMapToPoint(editingCtx.getSelectedPointPosition());
|
measurementLayer.moveMapToPoint(editingCtx.getSelectedPointPosition());
|
||||||
editingCtx.setInAddPointMode(true);
|
editingCtx.setInAddPointMode(true, false);
|
||||||
editingCtx.splitSegments(editingCtx.getSelectedPointPosition() + 1);
|
editingCtx.splitSegments(editingCtx.getSelectedPointPosition() + 1);
|
||||||
}
|
}
|
||||||
((TextView) mainView.findViewById(R.id.add_point_before_after_text)).setText(mainView.getResources().getString(R.string.add_point_after));
|
((TextView) mainView.findViewById(R.id.add_point_before_after_text)).setText(mainView.getResources().getString(R.string.add_point_after));
|
||||||
|
@ -940,7 +928,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
MeasurementToolLayer measurementLayer = getMeasurementLayer();
|
MeasurementToolLayer measurementLayer = getMeasurementLayer();
|
||||||
if (measurementLayer != null) {
|
if (measurementLayer != null) {
|
||||||
measurementLayer.moveMapToPoint(editingCtx.getSelectedPointPosition());
|
measurementLayer.moveMapToPoint(editingCtx.getSelectedPointPosition());
|
||||||
editingCtx.setInAddPointMode(true);
|
editingCtx.setInAddPointMode(true, true);
|
||||||
editingCtx.splitSegments(editingCtx.getSelectedPointPosition());
|
editingCtx.splitSegments(editingCtx.getSelectedPointPosition());
|
||||||
}
|
}
|
||||||
((TextView) mainView.findViewById(R.id.add_point_before_after_text)).setText(mainView.getResources().getString(R.string.add_point_before));
|
((TextView) mainView.findViewById(R.id.add_point_before_after_text)).setText(mainView.getResources().getString(R.string.add_point_before));
|
||||||
|
@ -1081,8 +1069,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
SelectedGpxFile selectedGpxFile = mapActivity.getMyApplication().getSelectedGpxHelper()
|
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, true, FinalSaveAction.SHOW_TOAST);
|
||||||
editingCtx.hasRoute() ? SaveType.ROUTE_POINT : SaveType.LINE, FinalSaveAction.SHOW_TOAST);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1107,10 +1094,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;
|
||||||
|
@ -1128,22 +1112,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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MeasurementAdapterListener createMeasurementAdapterListener(final ItemTouchHelper touchHelper) {
|
MeasurementAdapterListener createMeasurementAdapterListener(final ItemTouchHelper touchHelper) {
|
||||||
|
@ -1219,7 +1189,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 {
|
||||||
|
@ -1241,23 +1211,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);
|
|
||||||
}
|
|
||||||
updateAdditionalInfoView();
|
|
||||||
updateDistancePointsText();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void displaySegmentPoints() {
|
|
||||||
MeasurementToolLayer measurementLayer = getMeasurementLayer();
|
MeasurementToolLayer measurementLayer = getMeasurementLayer();
|
||||||
if (measurementLayer != null) {
|
if (measurementLayer != null) {
|
||||||
if (!isUndoMode()) {
|
if (!isUndoMode()) {
|
||||||
|
@ -1354,7 +1308,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
switchAddPointBeforeAfterMode(false);
|
switchAddPointBeforeAfterMode(false);
|
||||||
editingCtx.splitSegments(editingCtx.getBeforePoints().size() + editingCtx.getAfterPoints().size());
|
editingCtx.splitSegments(editingCtx.getBeforePoints().size() + editingCtx.getAfterPoints().size());
|
||||||
editingCtx.setSelectedPointPosition(-1);
|
editingCtx.setSelectedPointPosition(-1);
|
||||||
editingCtx.setInAddPointMode(false);
|
editingCtx.setInAddPointMode(false, false);
|
||||||
MeasurementToolLayer measurementLayer = getMeasurementLayer();
|
MeasurementToolLayer measurementLayer = getMeasurementLayer();
|
||||||
if (measurementLayer != null) {
|
if (measurementLayer != null) {
|
||||||
measurementLayer.refreshMap();
|
measurementLayer.refreshMap();
|
||||||
|
@ -1366,7 +1320,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
switchAddPointBeforeAfterMode(false);
|
switchAddPointBeforeAfterMode(false);
|
||||||
editingCtx.splitSegments(editingCtx.getBeforePoints().size() + editingCtx.getAfterPoints().size());
|
editingCtx.splitSegments(editingCtx.getBeforePoints().size() + editingCtx.getAfterPoints().size());
|
||||||
editingCtx.setSelectedPointPosition(-1);
|
editingCtx.setSelectedPointPosition(-1);
|
||||||
editingCtx.setInAddPointMode(false);
|
editingCtx.setInAddPointMode(false, false);
|
||||||
MeasurementToolLayer measurementToolLayer = getMeasurementLayer();
|
MeasurementToolLayer measurementToolLayer = getMeasurementLayer();
|
||||||
if (measurementToolLayer != null) {
|
if (measurementToolLayer != null) {
|
||||||
measurementToolLayer.refreshMap();
|
measurementToolLayer.refreshMap();
|
||||||
|
@ -1520,8 +1474,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, false, finalSaveAction);
|
||||||
editingCtx.hasRoute() ? SaveType.ROUTE_POINT : SaveType.LINE, finalSaveAction);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1555,30 +1508,45 @@ 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, false, 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, boolean addToTrack, FinalSaveAction finalSaveAction) {
|
||||||
|
saveGpx(new File(gpx.path), gpx, simplified, addToTrack, finalSaveAction, showOnMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveGpx(@NonNull final File outFile, @Nullable GPXFile gpxFile, boolean simplified,
|
||||||
|
boolean addToTrack, final FinalSaveAction finalSaveAction, final boolean showOnMap) {
|
||||||
SaveGpxRouteListener saveGpxRouteListener = new SaveGpxRouteListener() {
|
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,
|
||||||
|
addToTrack, 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;
|
||||||
|
@ -1586,9 +1554,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();
|
||||||
}
|
}
|
||||||
|
@ -1614,7 +1580,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);
|
||||||
|
@ -1660,12 +1626,10 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static void showGpxOnMap(OsmandApplication app, GPXFile gpx, ActionType actionType, boolean isNewGpx) {
|
protected static void showGpxOnMap(OsmandApplication app, GPXFile gpx, boolean isNewGpx) {
|
||||||
SelectedGpxFile sf = app.getSelectedGpxHelper().selectGpxFile(gpx, true, false);
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1704,25 +1668,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);
|
||||||
|
@ -1969,12 +1917,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 (additionalInfoExpanded) {
|
if (additionalInfoExpanded) {
|
||||||
|
@ -1986,7 +1935,6 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onApplyGpxApproximation() {
|
public void onApplyGpxApproximation() {
|
||||||
approximationApplied = true;
|
|
||||||
exitApproximationMode();
|
exitApproximationMode();
|
||||||
doAddOrMovePointCommonStuff();
|
doAddOrMovePointCommonStuff();
|
||||||
updateSnapToRoadControls();
|
updateSnapToRoadControls();
|
||||||
|
@ -2001,7 +1949,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);
|
||||||
|
|
|
@ -17,7 +17,7 @@ import net.osmand.data.PointDescription;
|
||||||
import net.osmand.data.QuadRect;
|
import net.osmand.data.QuadRect;
|
||||||
import net.osmand.data.RotatedTileBox;
|
import net.osmand.data.RotatedTileBox;
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
import net.osmand.plus.settings.backend.ApplicationMode;
|
import net.osmand.plus.measurementtool.MeasurementEditingContext.AdditionMode;
|
||||||
import net.osmand.plus.views.OsmandMapLayer;
|
import net.osmand.plus.views.OsmandMapLayer;
|
||||||
import net.osmand.plus.views.OsmandMapTileView;
|
import net.osmand.plus.views.OsmandMapTileView;
|
||||||
import net.osmand.plus.views.Renderable;
|
import net.osmand.plus.views.Renderable;
|
||||||
|
@ -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,52 @@ 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.getBeforeSegments();
|
||||||
TrkSegment after = editingCtx.getAfterTrkSegmentLine();
|
List<TrkSegment> after = editingCtx.getAfterSegments();
|
||||||
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);
|
boolean hasGapBefore = false;
|
||||||
float locX = tb.getPixXFromLatLon(pt.lat, pt.lon);
|
if (before.size() > 0) {
|
||||||
float locY = tb.getPixYFromLatLon(pt.lat, pt.lon);
|
TrkSegment segment = before.get(before.size() - 1);
|
||||||
tx.add(locX);
|
if (segment.points.size() > 0) {
|
||||||
ty.add(locY);
|
hasPointsBefore = true;
|
||||||
tx.add((float) tb.getCenterPixelX());
|
WptPt pt = segment.points.get(segment.points.size() - 1);
|
||||||
ty.add((float) tb.getCenterPixelY());
|
hasGapBefore = pt.isGap();
|
||||||
}
|
if (!pt.isGap() || !editingCtx.isInAddPointBeforeMode()) {
|
||||||
if (after.points.size() > 0) {
|
float locX = tb.getPixXFromLatLon(pt.lat, pt.lon);
|
||||||
if (before.points.size() == 0) {
|
float locY = tb.getPixYFromLatLon(pt.lat, pt.lon);
|
||||||
|
tx.add(locX);
|
||||||
|
ty.add(locY);
|
||||||
|
}
|
||||||
tx.add((float) tb.getCenterPixelX());
|
tx.add((float) tb.getCenterPixelX());
|
||||||
ty.add((float) tb.getCenterPixelY());
|
ty.add((float) tb.getCenterPixelY());
|
||||||
}
|
}
|
||||||
WptPt pt = after.points.get(0);
|
}
|
||||||
float locX = tb.getPixXFromLatLon(pt.lat, pt.lon);
|
if (after.size() > 0) {
|
||||||
float locY = tb.getPixYFromLatLon(pt.lat, pt.lon);
|
TrkSegment segment = after.get(0);
|
||||||
tx.add(locX);
|
if (segment.points.size() > 0) {
|
||||||
ty.add(locY);
|
if (!hasPointsBefore) {
|
||||||
|
tx.add((float) tb.getCenterPixelX());
|
||||||
|
ty.add((float) tb.getCenterPixelY());
|
||||||
|
}
|
||||||
|
if (!hasGapBefore || editingCtx.isInAddPointBeforeMode()) {
|
||||||
|
WptPt pt = segment.points.get(0);
|
||||||
|
float locX = tb.getPixXFromLatLon(pt.lat, pt.lon);
|
||||||
|
float locY = tb.getPixYFromLatLon(pt.lat, pt.lon);
|
||||||
|
tx.add(locX);
|
||||||
|
ty.add(locY);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GeometryWay.calculatePath(tb, tx, ty, path);
|
if (!tx.isEmpty() && !ty.isEmpty()) {
|
||||||
canvas.drawPath(path, lineAttrs.paint);
|
GeometryWay.calculatePath(tb, tx, ty, path);
|
||||||
|
canvas.drawPath(path, lineAttrs.paint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,7 +380,7 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL
|
||||||
canvas.rotate(tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY());
|
canvas.rotate(tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY());
|
||||||
}
|
}
|
||||||
|
|
||||||
public WptPt addCenterPoint() {
|
public WptPt addCenterPoint(boolean addPointBefore) {
|
||||||
RotatedTileBox tb = view.getCurrentRotatedTileBox();
|
RotatedTileBox tb = view.getCurrentRotatedTileBox();
|
||||||
LatLon l = tb.getCenterLatLon();
|
LatLon l = tb.getCenterLatLon();
|
||||||
WptPt pt = new WptPt();
|
WptPt pt = new WptPt();
|
||||||
|
@ -367,18 +388,13 @@ 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) {
|
||||||
|
editingCtx.addPoint(pt, addPointBefore ? AdditionMode.ADD_BEFORE : AdditionMode.ADD_AFTER);
|
||||||
ApplicationMode applicationMode = editingCtx.getAppMode();
|
|
||||||
if (applicationMode != MeasurementEditingContext.DEFAULT_APP_MODE) {
|
|
||||||
pt.setProfileType(applicationMode.getStringKey());
|
|
||||||
}
|
|
||||||
editingCtx.addPoint(pt);
|
|
||||||
return pt;
|
return pt;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WptPt addPoint() {
|
public WptPt addPoint(boolean addPointBefore) {
|
||||||
if (pressedPointLatLon != null) {
|
if (pressedPointLatLon != null) {
|
||||||
WptPt pt = new WptPt();
|
WptPt pt = new WptPt();
|
||||||
double lat = pressedPointLatLon.getLatitude();
|
double lat = pressedPointLatLon.getLatitude();
|
||||||
|
@ -388,11 +404,7 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL
|
||||||
pressedPointLatLon = null;
|
pressedPointLatLon = null;
|
||||||
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();
|
editingCtx.addPoint(pt, addPointBefore ? AdditionMode.ADD_BEFORE : AdditionMode.ADD_AFTER);
|
||||||
if (applicationMode != MeasurementEditingContext.DEFAULT_APP_MODE) {
|
|
||||||
pt.setProfileType(applicationMode.getStringKey());
|
|
||||||
}
|
|
||||||
editingCtx.addPoint(pt);
|
|
||||||
moveMapToLatLon(lat, lon);
|
moveMapToLatLon(lat, lon);
|
||||||
return pt;
|
return pt;
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,7 @@ public class OptionsBottomSheetDialogFragment extends MenuBottomSheetDialogFragm
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
Fragment fragment = getTargetFragment();
|
Fragment fragment = getTargetFragment();
|
||||||
if (fragment instanceof OptionsFragmentListener) {
|
if (fragment instanceof OptionsFragmentListener) {
|
||||||
((OptionsFragmentListener) fragment).addToTheTrackOnClick();
|
((OptionsFragmentListener) fragment).addToTrackOnClick();
|
||||||
}
|
}
|
||||||
dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
|
@ -229,7 +229,7 @@ public class OptionsBottomSheetDialogFragment extends MenuBottomSheetDialogFragm
|
||||||
|
|
||||||
void saveAsNewTrackOnClick();
|
void saveAsNewTrackOnClick();
|
||||||
|
|
||||||
void addToTheTrackOnClick();
|
void addToTrackOnClick();
|
||||||
|
|
||||||
void directionsOnClick();
|
void directionsOnClick();
|
||||||
|
|
||||||
|
|
|
@ -35,9 +35,7 @@ public class PointsCard extends BaseCard implements OnUpdateAdditionalInfoListen
|
||||||
@Override
|
@Override
|
||||||
protected void updateContent() {
|
protected void updateContent() {
|
||||||
MeasurementEditingContext editingCtx = fragment.getEditingCtx();
|
MeasurementEditingContext editingCtx = fragment.getEditingCtx();
|
||||||
final GpxData gpxData = editingCtx.getGpxData();
|
adapter = new MeasurementToolAdapter(mapActivity, editingCtx.getPoints());
|
||||||
adapter = new MeasurementToolAdapter(mapActivity, editingCtx.getPoints(),
|
|
||||||
gpxData != null ? gpxData.getActionType() : null);
|
|
||||||
RecyclerView pointsRv = view.findViewById(R.id.measure_points_recycler_view);
|
RecyclerView pointsRv = view.findViewById(R.id.measure_points_recycler_view);
|
||||||
ItemTouchHelper touchHelper = new ItemTouchHelper(new ReorderItemTouchHelperCallback(adapter));
|
ItemTouchHelper touchHelper = new ItemTouchHelper(new ReorderItemTouchHelperCallback(adapter));
|
||||||
touchHelper.attachToRecyclerView(pointsRv);
|
touchHelper.attachToRecyclerView(pointsRv);
|
||||||
|
|
|
@ -4,10 +4,13 @@ import android.app.ProgressDialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import net.osmand.AndroidUtils;
|
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.Route;
|
||||||
import net.osmand.GPXUtilities.Track;
|
import net.osmand.GPXUtilities.Track;
|
||||||
import net.osmand.GPXUtilities.TrkSegment;
|
import net.osmand.GPXUtilities.TrkSegment;
|
||||||
import net.osmand.GPXUtilities.WptPt;
|
import net.osmand.GPXUtilities.WptPt;
|
||||||
|
@ -15,42 +18,38 @@ 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;
|
||||||
|
|
||||||
class SaveGpxRouteAsyncTask extends AsyncTask<Void, Void, Exception> {
|
class SaveGpxRouteAsyncTask extends AsyncTask<Void, Void, Exception> {
|
||||||
|
|
||||||
private WeakReference<MeasurementToolFragment> fragmentRef;
|
private final WeakReference<MeasurementToolFragment> fragmentRef;
|
||||||
private ProgressDialog progressDialog;
|
private ProgressDialog progressDialog;
|
||||||
|
|
||||||
private SaveType saveType;
|
private final File outFile;
|
||||||
private ActionType actionType;
|
|
||||||
|
|
||||||
private File outFile;
|
|
||||||
private File backupFile;
|
private File backupFile;
|
||||||
private GPXFile gpxFile;
|
private final GPXFile gpxFile;
|
||||||
private GPXFile savedGpxFile;
|
private GPXFile savedGpxFile;
|
||||||
private boolean showOnMap;
|
private final boolean simplified;
|
||||||
|
private final boolean addToTrack;
|
||||||
private SaveGpxRouteListener saveGpxRouteListener;
|
private final boolean showOnMap;
|
||||||
|
|
||||||
|
private final 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 addToTrack, 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.addToTrack = addToTrack;
|
||||||
this.saveGpxRouteListener = saveGpxRouteListener;
|
this.saveGpxRouteListener = saveGpxRouteListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,119 +76,73 @@ 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, @NonNull GPXFile gpx) {
|
||||||
|
if (measurementLayer != null) {
|
||||||
|
List<TrkSegment> before = editingCtx.getBeforeTrkSegmentLine();
|
||||||
|
List<TrkSegment> after = editingCtx.getAfterTrkSegmentLine();
|
||||||
|
if (simplified) {
|
||||||
|
Track track = new Track();
|
||||||
|
track.name = trackName;
|
||||||
|
gpx.tracks.add(track);
|
||||||
|
for (TrkSegment s : before) {
|
||||||
|
TrkSegment segment = new TrkSegment();
|
||||||
|
segment.points.addAll(s.points);
|
||||||
|
track.segments.add(segment);
|
||||||
|
}
|
||||||
|
for (TrkSegment s : after) {
|
||||||
|
TrkSegment segment = new TrkSegment();
|
||||||
|
segment.points.addAll(s.points);
|
||||||
|
track.segments.add(segment);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GPXFile newGpx = editingCtx.exportGpx(trackName);
|
||||||
|
if (newGpx != null) {
|
||||||
|
List<Track> gpxTracks = gpx.tracks;
|
||||||
|
List<WptPt> gpxPoints = gpx.getPoints();
|
||||||
|
List<Route> gpxRoutes = gpx.routes;
|
||||||
|
gpx = newGpx;
|
||||||
|
List<List<WptPt>> routePoints = editingCtx.getRoutePoints();
|
||||||
|
for (List<WptPt> points : routePoints) {
|
||||||
|
gpx.addRoutePoints(points, true);
|
||||||
|
}
|
||||||
|
if (!Algorithms.isEmpty(gpxPoints)) {
|
||||||
|
gpx.addPoints(gpxPoints);
|
||||||
|
}
|
||||||
|
if (addToTrack) {
|
||||||
|
gpx.tracks.addAll(gpxTracks);
|
||||||
|
gpx.routes.addAll(gpxRoutes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return gpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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();
|
||||||
|
@ -172,7 +173,7 @@ public class SelectedPointBottomSheetDialogFragment extends MenuBottomSheetDialo
|
||||||
dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.setDisabled(editingCtx.isFirstPointSelected())
|
.setDisabled(editingCtx.isFirstPointSelected() || editingCtx.isSelectionNeedApproximation())
|
||||||
.create();
|
.create();
|
||||||
items.add(changeRouteTypeBefore);
|
items.add(changeRouteTypeBefore);
|
||||||
|
|
||||||
|
@ -191,7 +192,7 @@ public class SelectedPointBottomSheetDialogFragment extends MenuBottomSheetDialo
|
||||||
dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.setDisabled(editingCtx.isLastPointSelected())
|
.setDisabled(editingCtx.isLastPointSelected() || editingCtx.isSelectionNeedApproximation())
|
||||||
.create();
|
.create();
|
||||||
items.add(changeRouteTypeAfter);
|
items.add(changeRouteTypeAfter);
|
||||||
|
|
||||||
|
@ -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));
|
||||||
|
|
|
@ -3,48 +3,57 @@ package net.osmand.plus.measurementtool.command;
|
||||||
import net.osmand.data.LatLon;
|
import net.osmand.data.LatLon;
|
||||||
import net.osmand.GPXUtilities.WptPt;
|
import net.osmand.GPXUtilities.WptPt;
|
||||||
import net.osmand.plus.measurementtool.MeasurementEditingContext;
|
import net.osmand.plus.measurementtool.MeasurementEditingContext;
|
||||||
|
import net.osmand.plus.measurementtool.MeasurementEditingContext.AdditionMode;
|
||||||
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 java.util.List;
|
||||||
|
|
||||||
public class AddPointCommand extends MeasurementModeCommand {
|
public class AddPointCommand extends MeasurementModeCommand {
|
||||||
|
|
||||||
private int position;
|
private int position;
|
||||||
private WptPt point;
|
private WptPt point;
|
||||||
|
private String prevPointProfile;
|
||||||
private boolean center;
|
private boolean center;
|
||||||
|
private boolean addPointBefore;
|
||||||
|
|
||||||
public AddPointCommand(MeasurementToolLayer measurementLayer, boolean center) {
|
public AddPointCommand(MeasurementToolLayer measurementLayer, boolean center) {
|
||||||
super(measurementLayer);
|
super(measurementLayer);
|
||||||
init(measurementLayer, null, center);
|
init(null, center);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AddPointCommand(MeasurementToolLayer measurementLayer, LatLon latLon) {
|
public AddPointCommand(MeasurementToolLayer measurementLayer, LatLon latLon) {
|
||||||
super(measurementLayer);
|
super(measurementLayer);
|
||||||
init(measurementLayer, latLon, false);
|
init(latLon, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init(MeasurementToolLayer measurementLayer, LatLon latLon, boolean center) {
|
private void init(LatLon latLon, boolean center) {
|
||||||
|
MeasurementEditingContext ctx = getEditingCtx();
|
||||||
if (latLon != null) {
|
if (latLon != null) {
|
||||||
point = new WptPt();
|
point = new WptPt();
|
||||||
point.lat = latLon.getLatitude();
|
point.lat = latLon.getLatitude();
|
||||||
point.lon = latLon.getLongitude();
|
point.lon = latLon.getLongitude();
|
||||||
ApplicationMode appMode = measurementLayer.getEditingCtx().getAppMode();
|
|
||||||
if (appMode != MeasurementEditingContext.DEFAULT_APP_MODE) {
|
|
||||||
point.setProfileType(appMode.getStringKey());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.center = center;
|
this.center = center;
|
||||||
position = measurementLayer.getEditingCtx().getPointsCount();
|
position = ctx.getPointsCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean execute() {
|
public boolean execute() {
|
||||||
|
MeasurementEditingContext ctx = getEditingCtx();
|
||||||
|
addPointBefore = ctx.isInAddPointBeforeMode();
|
||||||
|
List<WptPt> points = ctx.getPoints();
|
||||||
|
if (points.size() > 0) {
|
||||||
|
WptPt prevPt = points.get(points.size() - 1);
|
||||||
|
prevPointProfile = prevPt.getProfileType();
|
||||||
|
}
|
||||||
if (point != null) {
|
if (point != null) {
|
||||||
getEditingCtx().addPoint(point);
|
ctx.addPoint(point, addPointBefore ? AdditionMode.ADD_BEFORE : AdditionMode.ADD_AFTER);
|
||||||
measurementLayer.moveMapToPoint(position);
|
measurementLayer.moveMapToPoint(position);
|
||||||
} else if (center) {
|
} else if (center) {
|
||||||
point = measurementLayer.addCenterPoint();
|
point = measurementLayer.addCenterPoint(addPointBefore);
|
||||||
} else {
|
} else {
|
||||||
point = measurementLayer.addPoint();
|
point = measurementLayer.addPoint(addPointBefore);
|
||||||
}
|
}
|
||||||
refreshMap();
|
refreshMap();
|
||||||
return point != null;
|
return point != null;
|
||||||
|
@ -52,13 +61,22 @@ public class AddPointCommand extends MeasurementModeCommand {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void undo() {
|
public void undo() {
|
||||||
getEditingCtx().removePoint(position, true);
|
MeasurementEditingContext ctx = getEditingCtx();
|
||||||
|
if (position > 0) {
|
||||||
|
WptPt prevPt = ctx.getPoints().get(position - 1);
|
||||||
|
if (prevPointProfile != null) {
|
||||||
|
prevPt.setProfileType(prevPointProfile);
|
||||||
|
} else {
|
||||||
|
prevPt.removeProfileType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.removePoint(position, true);
|
||||||
refreshMap();
|
refreshMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void redo() {
|
public void redo() {
|
||||||
getEditingCtx().addPoint(position, point);
|
getEditingCtx().addPoint(position, point, addPointBefore ? AdditionMode.ADD_BEFORE : AdditionMode.ADD_AFTER);
|
||||||
refreshMap();
|
refreshMap();
|
||||||
measurementLayer.moveMapToPoint(position);
|
measurementLayer.moveMapToPoint(position);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,14 +146,16 @@ 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) {
|
||||||
if (newMode != null && newMode != DEFAULT_APP_MODE) {
|
if (!pt.isGap()) {
|
||||||
pt.setProfileType(newMode.getStringKey());
|
if (newMode != null && newMode != DEFAULT_APP_MODE) {
|
||||||
} else {
|
pt.setProfileType(newMode.getStringKey());
|
||||||
pt.removeProfileType();
|
} else {
|
||||||
|
pt.removeProfileType();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ public class RemovePointCommand extends MeasurementModeCommand {
|
||||||
|
|
||||||
private final int position;
|
private final int position;
|
||||||
private WptPt point;
|
private WptPt point;
|
||||||
|
private String prevPointProfile;
|
||||||
|
|
||||||
public RemovePointCommand(MeasurementToolLayer measurementLayer, int position) {
|
public RemovePointCommand(MeasurementToolLayer measurementLayer, int position) {
|
||||||
super(measurementLayer);
|
super(measurementLayer);
|
||||||
|
@ -15,6 +16,9 @@ public class RemovePointCommand extends MeasurementModeCommand {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean execute() {
|
public boolean execute() {
|
||||||
|
if (position > 0) {
|
||||||
|
prevPointProfile = getEditingCtx().getPoints().get(position - 1).getProfileType();
|
||||||
|
}
|
||||||
point = getEditingCtx().removePoint(position, true);
|
point = getEditingCtx().removePoint(position, true);
|
||||||
refreshMap();
|
refreshMap();
|
||||||
return true;
|
return true;
|
||||||
|
@ -22,6 +26,14 @@ public class RemovePointCommand extends MeasurementModeCommand {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void undo() {
|
public void undo() {
|
||||||
|
if (position > 0) {
|
||||||
|
WptPt prevPt = getEditingCtx().getPoints().get(position - 1);
|
||||||
|
if (prevPointProfile != null) {
|
||||||
|
prevPt.setProfileType(prevPointProfile);
|
||||||
|
} else {
|
||||||
|
prevPt.removeProfileType();
|
||||||
|
}
|
||||||
|
}
|
||||||
getEditingCtx().addPoint(position, point);
|
getEditingCtx().addPoint(position, point);
|
||||||
refreshMap();
|
refreshMap();
|
||||||
measurementLayer.moveMapToPoint(position);
|
measurementLayer.moveMapToPoint(position);
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
package net.osmand.plus.routepreparationmenu;
|
package net.osmand.plus.routepreparationmenu;
|
||||||
|
|
||||||
|
import android.animation.Animator;
|
||||||
|
import android.animation.AnimatorListenerAdapter;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.ActivityNotFoundException;
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.graphics.drawable.AnimationDrawable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
@ -16,6 +19,7 @@ import android.view.ViewGroup.MarginLayoutParams;
|
||||||
import android.view.ViewTreeObserver.OnScrollChangedListener;
|
import android.view.ViewTreeObserver.OnScrollChangedListener;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
@ -24,7 +28,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 +47,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;
|
||||||
|
@ -86,6 +88,8 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca
|
||||||
|
|
||||||
private GPXFile gpxFile;
|
private GPXFile gpxFile;
|
||||||
|
|
||||||
|
private View buttonsShadow;
|
||||||
|
|
||||||
private boolean editingTrack;
|
private boolean editingTrack;
|
||||||
private boolean selectingTrack;
|
private boolean selectingTrack;
|
||||||
private int menuTitleHeight;
|
private int menuTitleHeight;
|
||||||
|
@ -148,6 +152,7 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca
|
||||||
View view = super.onCreateView(inflater, container, savedInstanceState);
|
View view = super.onCreateView(inflater, container, savedInstanceState);
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
ImageButton closeButton = view.findViewById(R.id.close_button);
|
ImageButton closeButton = view.findViewById(R.id.close_button);
|
||||||
|
buttonsShadow = view.findViewById(R.id.buttons_shadow);
|
||||||
closeButton.setImageDrawable(getContentIcon(AndroidUtils.getNavigationIconResId(app)));
|
closeButton.setImageDrawable(getContentIcon(AndroidUtils.getNavigationIconResId(app)));
|
||||||
closeButton.setOnClickListener(new View.OnClickListener() {
|
closeButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -174,6 +179,22 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void showShadowButton() {
|
||||||
|
buttonsShadow.setVisibility(View.VISIBLE);
|
||||||
|
buttonsShadow.animate()
|
||||||
|
.alpha(0.8f)
|
||||||
|
.setDuration(200)
|
||||||
|
.setListener(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hideShadowButton() {
|
||||||
|
buttonsShadow.animate()
|
||||||
|
.alpha(0f)
|
||||||
|
.setDuration(200);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void setupCards() {
|
private void setupCards() {
|
||||||
MapActivity mapActivity = getMapActivity();
|
MapActivity mapActivity = getMapActivity();
|
||||||
if (mapActivity != null) {
|
if (mapActivity != null) {
|
||||||
|
@ -554,10 +575,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());
|
||||||
|
@ -598,20 +616,16 @@ public class FollowTrackFragment extends ContextMenuScrollFragment implements Ca
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupScrollShadow() {
|
private void setupScrollShadow() {
|
||||||
int shadowIconId = isNightMode() ? R.drawable.bg_contextmenu_shadow : R.drawable.bg_contextmenu_shadow;
|
|
||||||
final Drawable shadowIcon = app.getUIUtilities().getIcon(shadowIconId);
|
|
||||||
|
|
||||||
final View scrollView = getBottomScrollView();
|
final View scrollView = getBottomScrollView();
|
||||||
final FrameLayout bottomContainer = getBottomContainer();
|
|
||||||
scrollView.getViewTreeObserver().addOnScrollChangedListener(new OnScrollChangedListener() {
|
scrollView.getViewTreeObserver().addOnScrollChangedListener(new OnScrollChangedListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onScrollChanged() {
|
public void onScrollChanged() {
|
||||||
int scrollY = scrollView.getScrollY();
|
boolean scrollToBottomAvailable = scrollView.canScrollVertically(1);
|
||||||
if (scrollY <= 0 && bottomContainer.getForeground() != null) {
|
if (scrollToBottomAvailable) {
|
||||||
bottomContainer.setForeground(null);
|
showShadowButton();
|
||||||
} else if (scrollY > 0 && bottomContainer.getForeground() == null) {
|
} else {
|
||||||
bottomContainer.setForeground(shadowIcon);
|
hideShadowButton();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -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,15 @@ 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() {
|
|
||||||
singleThreadedExecutor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void prepareEnvironment(@NonNull OsmandApplication ctx, @NonNull ApplicationMode mode) throws IOException {
|
private void prepareEnvironment(@NonNull OsmandApplication ctx, @NonNull ApplicationMode mode) throws IOException {
|
||||||
|
@ -140,6 +131,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 +149,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 +158,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,15 +186,13 @@ 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
|
|
||||||
} else {
|
|
||||||
updateProgress(gctx);
|
updateProgress(gctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -475,24 +475,33 @@ public class TrackAppearanceFragment extends ContextMenuScrollFragment implement
|
||||||
AndroidUiHelper.updateVisibility(saveButton, true);
|
AndroidUiHelper.updateVisibility(saveButton, true);
|
||||||
AndroidUiHelper.updateVisibility(view.findViewById(R.id.buttons_divider), true);
|
AndroidUiHelper.updateVisibility(view.findViewById(R.id.buttons_divider), true);
|
||||||
}
|
}
|
||||||
|
private void showShadowButton() {
|
||||||
|
buttonsShadow.setVisibility(View.VISIBLE);
|
||||||
|
buttonsShadow.animate()
|
||||||
|
.alpha(0.8f)
|
||||||
|
.setDuration(200)
|
||||||
|
.setListener(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hideShadowButton() {
|
||||||
|
buttonsShadow.animate()
|
||||||
|
.alpha(0f)
|
||||||
|
.setDuration(200);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private void setupScrollShadow() {
|
private void setupScrollShadow() {
|
||||||
int shadowIconId = isNightMode() ? R.drawable.bg_contextmenu_shadow : R.drawable.bg_contextmenu_shadow;
|
|
||||||
final Drawable shadowIcon = app.getUIUtilities().getIcon(shadowIconId);
|
|
||||||
|
|
||||||
final View scrollView = getBottomScrollView();
|
final View scrollView = getBottomScrollView();
|
||||||
final FrameLayout bottomContainer = getBottomContainer();
|
|
||||||
scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
|
scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onScrollChanged() {
|
public void onScrollChanged() {
|
||||||
int scrollY = scrollView.getScrollY();
|
boolean scrollToBottomAvailable = scrollView.canScrollVertically(1);
|
||||||
if (scrollY <= 0 && bottomContainer.getForeground() != null) {
|
if (scrollToBottomAvailable) {
|
||||||
bottomContainer.setForeground(null);
|
showShadowButton();
|
||||||
} else if (scrollY > 0 && bottomContainer.getForeground() == null) {
|
} else {
|
||||||
bottomContainer.setForeground(shadowIcon);
|
hideShadowButton();
|
||||||
}
|
}
|
||||||
updateButtonsShadow();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue