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