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