source: josm/trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadGpsTask.java@ 14761

Last change on this file since 14761 was 14761, checked in by GerdP, 5 years ago

fix #13195
1) BoundingBoxDownloader: Reduce number of gpx api calls: If a call returned less than 5000 points there is no need to request another page. This improves all routines which download raw GPX data from the server.
2) GpxImporter: Create a new GpxLayer even if the area contains no GPX data. This allows to keep track of the already downloaded boundaries. Without this change the continuosDownload will try agaian and again to download data from this area because the GpxLayer will not contain the information that the corresponding bbox was already downloaded.

  • Property svn:eol-style set to native
File size: 8.1 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.actions.downloadtasks;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.io.IOException;
7import java.net.URL;
8import java.util.Arrays;
9import java.util.Optional;
10import java.util.concurrent.Future;
11import java.util.regex.Matcher;
12import java.util.regex.Pattern;
13import java.util.stream.Stream;
14
15import org.openstreetmap.josm.data.Bounds;
16import org.openstreetmap.josm.data.Bounds.ParseMethod;
17import org.openstreetmap.josm.data.ProjectionBounds;
18import org.openstreetmap.josm.data.gpx.GpxData;
19import org.openstreetmap.josm.gui.MainApplication;
20import org.openstreetmap.josm.gui.PleaseWaitRunnable;
21import org.openstreetmap.josm.gui.io.importexport.GpxImporter;
22import org.openstreetmap.josm.gui.io.importexport.GpxImporter.GpxImporterData;
23import org.openstreetmap.josm.gui.layer.GpxLayer;
24import org.openstreetmap.josm.gui.layer.Layer;
25import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
26import org.openstreetmap.josm.gui.progress.ProgressMonitor;
27import org.openstreetmap.josm.gui.progress.ProgressTaskId;
28import org.openstreetmap.josm.gui.progress.ProgressTaskIds;
29import org.openstreetmap.josm.io.BoundingBoxDownloader;
30import org.openstreetmap.josm.io.OsmServerLocationReader;
31import org.openstreetmap.josm.io.OsmServerLocationReader.GpxUrlPattern;
32import org.openstreetmap.josm.io.OsmServerReader;
33import org.openstreetmap.josm.io.OsmTransferException;
34import org.openstreetmap.josm.spi.preferences.Config;
35import org.openstreetmap.josm.tools.CheckParameterUtil;
36import org.xml.sax.SAXException;
37
38/**
39 * Task allowing to download GPS data.
40 */
41public class DownloadGpsTask extends AbstractDownloadTask<GpxData> {
42
43 private DownloadTask downloadTask;
44 private GpxLayer gpxLayer;
45
46 protected String newLayerName;
47
48 @Override
49 public String[] getPatterns() {
50 return Arrays.stream(GpxUrlPattern.values()).map(GpxUrlPattern::pattern).toArray(String[]::new);
51 }
52
53 @Override
54 public String getTitle() {
55 return tr("Download GPS");
56 }
57
58 @Override
59 public Future<?> download(DownloadParams settings, Bounds downloadArea, ProgressMonitor progressMonitor) {
60 downloadTask = new DownloadTask(settings,
61 new BoundingBoxDownloader(downloadArea), progressMonitor);
62 // We need submit instead of execute so we can wait for it to finish and get the error
63 // message if necessary. If no one calls getErrorMessage() it just behaves like execute.
64 return MainApplication.worker.submit(downloadTask);
65 }
66
67 @Override
68 public Future<?> loadUrl(DownloadParams settings, String url, ProgressMonitor progressMonitor) {
69 CheckParameterUtil.ensureParameterNotNull(url, "url");
70 final Optional<String> mappedUrl = Stream.of(GpxUrlPattern.USER_TRACE_ID, GpxUrlPattern.EDIT_TRACE_ID)
71 .map(p -> Pattern.compile(p.pattern()).matcher(url))
72 .filter(Matcher::matches)
73 .map(m -> "https://www.openstreetmap.org/trace/" + m.group(2) + "/data")
74 .findFirst();
75 if (mappedUrl.isPresent()) {
76 return loadUrl(settings, mappedUrl.get(), progressMonitor);
77 }
78 if (Stream.of(GpxUrlPattern.TRACE_ID, GpxUrlPattern.EXTERNAL_GPX_SCRIPT,
79 GpxUrlPattern.EXTERNAL_GPX_FILE, GpxUrlPattern.TASKING_MANAGER)
80 .anyMatch(p -> url.matches(p.pattern()))) {
81 downloadTask = new DownloadTask(settings,
82 new OsmServerLocationReader(url), progressMonitor);
83 // Extract .gpx filename from URL to set the new layer name
84 Matcher matcher = Pattern.compile(GpxUrlPattern.EXTERNAL_GPX_FILE.pattern()).matcher(url);
85 newLayerName = matcher.matches() ? matcher.group(1) : null;
86 // We need submit instead of execute so we can wait for it to finish and get the error
87 // message if necessary. If no one calls getErrorMessage() it just behaves like execute.
88 return MainApplication.worker.submit(downloadTask);
89
90 } else if (url.matches(GpxUrlPattern.TRACKPOINTS_BBOX.pattern())) {
91 String[] table = url.split("\\?|=|&");
92 for (int i = 0; i < table.length; i++) {
93 if ("bbox".equals(table[i]) && i < table.length-1)
94 return download(settings, new Bounds(table[i+1], ",", ParseMethod.LEFT_BOTTOM_RIGHT_TOP), progressMonitor);
95 }
96 }
97 return null;
98 }
99
100 @Override
101 public void cancel() {
102 if (downloadTask != null) {
103 downloadTask.cancel();
104 }
105 }
106
107 @Override
108 public ProjectionBounds getDownloadProjectionBounds() {
109 return gpxLayer != null ? gpxLayer.getViewProjectionBounds() : null;
110 }
111
112 class DownloadTask extends PleaseWaitRunnable {
113 private final OsmServerReader reader;
114 private GpxData rawData;
115 private final boolean newLayer;
116
117 DownloadTask(DownloadParams settings, OsmServerReader reader, ProgressMonitor progressMonitor) {
118 super(tr("Downloading GPS data"), progressMonitor, false);
119 this.reader = reader;
120 this.newLayer = settings.isNewLayer();
121 }
122
123 @Override
124 public void realRun() throws IOException, SAXException, OsmTransferException {
125 try {
126 if (isCanceled())
127 return;
128 rawData = reader.parseRawGps(progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
129 } catch (OsmTransferException e) {
130 if (isCanceled())
131 return;
132 rememberException(e);
133 }
134 }
135
136 @Override
137 protected void finish() {
138 rememberDownloadedData(rawData);
139 if (rawData == null)
140 return;
141 String name = newLayerName != null ? newLayerName : tr("Downloaded GPX Data");
142
143 GpxImporterData layers = GpxImporter.loadLayers(rawData, reader.isGpxParsedProperly(), name,
144 tr("Markers from {0}", name));
145
146 gpxLayer = layers.getGpxLayer();
147 addOrMergeLayer(gpxLayer, findGpxMergeLayer());
148 addOrMergeLayer(layers.getMarkerLayer(), findMarkerMergeLayer(gpxLayer));
149
150 layers.getPostLayerTask().run();
151 }
152
153 private <L extends Layer> L addOrMergeLayer(L layer, L mergeLayer) {
154 if (layer == null) return null;
155 if (newLayer || mergeLayer == null) {
156 MainApplication.getLayerManager().addLayer(layer, zoomAfterDownload);
157 return layer;
158 } else {
159 mergeLayer.mergeFrom(layer);
160 mergeLayer.invalidate();
161 return mergeLayer;
162 }
163 }
164
165 private GpxLayer findGpxMergeLayer() {
166 boolean merge = Config.getPref().getBoolean("download.gps.mergeWithLocal", false);
167 Layer active = MainApplication.getLayerManager().getActiveLayer();
168 if (active instanceof GpxLayer && (merge || ((GpxLayer) active).data.fromServer))
169 return (GpxLayer) active;
170 for (GpxLayer l : MainApplication.getLayerManager().getLayersOfType(GpxLayer.class)) {
171 if (merge || l.data.fromServer)
172 return l;
173 }
174 return null;
175 }
176
177 private MarkerLayer findMarkerMergeLayer(GpxLayer fromLayer) {
178 for (MarkerLayer l : MainApplication.getLayerManager().getLayersOfType(MarkerLayer.class)) {
179 if (fromLayer != null && l.fromLayer == fromLayer)
180 return l;
181 }
182 return null;
183 }
184
185 @Override
186 protected void cancel() {
187 setCanceled(true);
188 if (reader != null) {
189 reader.cancel();
190 }
191 }
192
193 @Override
194 public ProgressTaskId canRunInBackground() {
195 return ProgressTaskIds.DOWNLOAD_GPS;
196 }
197 }
198
199 @Override
200 public String getConfirmationMessage(URL url) {
201 // TODO
202 return null;
203 }
204
205 @Override
206 public boolean isSafeForRemotecontrolRequests() {
207 return true;
208 }
209}
Note: See TracBrowser for help on using the repository browser.