001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.io; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.io.IOException; 007import java.io.InputStream; 008 009import org.openstreetmap.josm.data.Bounds; 010import org.openstreetmap.josm.data.gpx.GpxData; 011import org.openstreetmap.josm.data.osm.DataSet; 012import org.openstreetmap.josm.gui.progress.ProgressMonitor; 013import org.openstreetmap.josm.tools.CheckParameterUtil; 014import org.xml.sax.SAXException; 015 016/** 017 * Read content from OSM server for a given bounding box 018 * @since 627 019 */ 020public class BoundingBoxDownloader extends OsmServerReader { 021 022 /** 023 * The boundings of the desired map data. 024 */ 025 protected final double lat1; 026 protected final double lon1; 027 protected final double lat2; 028 protected final double lon2; 029 protected final boolean crosses180th; 030 031 /** 032 * Constructs a new {@code BoundingBoxDownloader}. 033 * @param downloadArea The area to download 034 */ 035 public BoundingBoxDownloader(Bounds downloadArea) { 036 CheckParameterUtil.ensureParameterNotNull(downloadArea, "downloadArea"); 037 this.lat1 = downloadArea.getMinLat(); 038 this.lon1 = downloadArea.getMinLon(); 039 this.lat2 = downloadArea.getMaxLat(); 040 this.lon2 = downloadArea.getMaxLon(); 041 this.crosses180th = downloadArea.crosses180thMeridian(); 042 } 043 044 private GpxData downloadRawGps(String url, ProgressMonitor progressMonitor) throws IOException, OsmTransferException, SAXException { 045 boolean done = false; 046 GpxData result = null; 047 for (int i = 0;!done;++i) { 048 progressMonitor.subTask(tr("Downloading points {0} to {1}...", i * 5000, ((i + 1) * 5000))); 049 try (InputStream in = getInputStream(url+i, progressMonitor.createSubTaskMonitor(1, true))) { 050 if (in == null) { 051 break; 052 } 053 progressMonitor.setTicks(0); 054 GpxReader reader = new GpxReader(in); 055 gpxParsedProperly = reader.parse(false); 056 GpxData currentGpx = reader.getGpxData(); 057 if (result == null) { 058 result = currentGpx; 059 } else if (currentGpx.hasTrackPoints()) { 060 result.mergeFrom(currentGpx); 061 } else{ 062 done = true; 063 } 064 } 065 activeConnection = null; 066 } 067 if (result != null) { 068 result.fromServer = true; 069 } 070 return result; 071 } 072 073 @Override 074 public GpxData parseRawGps(ProgressMonitor progressMonitor) throws OsmTransferException { 075 progressMonitor.beginTask("", 1); 076 try { 077 progressMonitor.indeterminateSubTask(tr("Contacting OSM Server...")); 078 if (crosses180th) { 079 // API 0.6 does not support requests crossing the 180th meridian, so make two requests 080 GpxData result = downloadRawGps("trackpoints?bbox="+lon1+","+lat1+",180.0,"+lat2+"&page=", progressMonitor); 081 result.mergeFrom(downloadRawGps("trackpoints?bbox=-180.0,"+lat1+","+lon2+","+lat2+"&page=", progressMonitor)); 082 return result; 083 } else { 084 // Simple request 085 return downloadRawGps("trackpoints?bbox="+lon1+","+lat1+","+lon2+","+lat2+"&page=", progressMonitor); 086 } 087 } catch (IllegalArgumentException e) { 088 // caused by HttpUrlConnection in case of illegal stuff in the response 089 if (cancel) 090 return null; 091 throw new OsmTransferException("Illegal characters within the HTTP-header response.", e); 092 } catch (IOException e) { 093 if (cancel) 094 return null; 095 throw new OsmTransferException(e); 096 } catch (SAXException e) { 097 throw new OsmTransferException(e); 098 } catch (OsmTransferException e) { 099 throw e; 100 } catch (RuntimeException e) { 101 if (cancel) 102 return null; 103 throw e; 104 } finally { 105 progressMonitor.finishTask(); 106 } 107 } 108 109 protected String getRequestForBbox(double lon1, double lat1, double lon2, double lat2) { 110 return "map?bbox=" + lon1 + "," + lat1 + "," + lon2 + "," + lat2; 111 } 112 113 @Override 114 public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException { 115 progressMonitor.beginTask(tr("Contacting OSM Server..."), 10); 116 try { 117 DataSet ds = null; 118 progressMonitor.indeterminateSubTask(null); 119 if (crosses180th) { 120 // API 0.6 does not support requests crossing the 180th meridian, so make two requests 121 DataSet ds2 = null; 122 123 try (InputStream in = getInputStream(getRequestForBbox(lon1, lat1, 180.0, lat2), progressMonitor.createSubTaskMonitor(9, false))) { 124 if (in == null) 125 return null; 126 ds = OsmReader.parseDataSet(in, progressMonitor.createSubTaskMonitor(1, false)); 127 } 128 129 try (InputStream in = getInputStream(getRequestForBbox(-180.0, lat1, lon2, lat2), progressMonitor.createSubTaskMonitor(9, false))) { 130 if (in == null) 131 return null; 132 ds2 = OsmReader.parseDataSet(in, progressMonitor.createSubTaskMonitor(1, false)); 133 } 134 if (ds2 == null) 135 return null; 136 ds.mergeFrom(ds2); 137 138 } else { 139 // Simple request 140 try (InputStream in = getInputStream(getRequestForBbox(lon1, lat1, lon2, lat2), progressMonitor.createSubTaskMonitor(9, false))) { 141 if (in == null) 142 return null; 143 ds = OsmReader.parseDataSet(in, progressMonitor.createSubTaskMonitor(1, false)); 144 } 145 } 146 return ds; 147 } catch(OsmTransferException e) { 148 throw e; 149 } catch (Exception e) { 150 throw new OsmTransferException(e); 151 } finally { 152 progressMonitor.finishTask(); 153 activeConnection = null; 154 } 155 } 156}