Changeset 4580 in josm


Ignore:
Timestamp:
06.11.2011 15:00:56 (7 months ago)
Author:
Don-vip
Message:

see #2212 - Allow JOSM to download data crossing the 180th meridian

Location:
trunk
Files:
1 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/Bounds.java

    r4573 r4580  
    141141            throw new IllegalArgumentException(MessageFormat.format("Parameter ''{0}'' > 0.0 exptected, got {1}", "lonExtent", lonExtent)); 
    142142 
    143         this.minLat = LatLon.roundToOsmPrecision(center.lat() - latExtent / 2); 
    144         this.minLon = LatLon.roundToOsmPrecision(center.lon() - lonExtent / 2); 
    145         this.maxLat = LatLon.roundToOsmPrecision(center.lat() + latExtent / 2); 
    146         this.maxLon = LatLon.roundToOsmPrecision(center.lon() + lonExtent / 2); 
     143        this.minLat = LatLon.roundToOsmPrecision(LatLon.toIntervalLat(center.lat() - latExtent / 2)); 
     144        this.minLon = LatLon.roundToOsmPrecision(LatLon.toIntervalLon(center.lon() - lonExtent / 2)); 
     145        this.maxLat = LatLon.roundToOsmPrecision(LatLon.toIntervalLat(center.lat() + latExtent / 2)); 
     146        this.maxLon = LatLon.roundToOsmPrecision(LatLon.toIntervalLon(center.lon() + lonExtent / 2)); 
    147147    } 
    148148 
     
    164164    public LatLon getCenter() 
    165165    { 
    166         return getMin().getCenter(getMax()); 
     166        if (crosses180thMeridian()) { 
     167            LatLon result = new LatLon(minLat, minLon-360.0).getCenter(getMax()); 
     168            if (result.lon() < -180.0) { 
     169                result.setLocation(result.lon()+360.0, result.lat()); 
     170            } 
     171            return result; 
     172        } else { 
     173            return getMin().getCenter(getMax()); 
     174        } 
    167175    } 
    168176 
     
    174182            minLat = LatLon.roundToOsmPrecision(ll.lat()); 
    175183        } 
    176         if (ll.lon() < minLon) { 
    177             minLon = LatLon.roundToOsmPrecision(ll.lon()); 
    178         } 
    179184        if (ll.lat() > maxLat) { 
    180185            maxLat = LatLon.roundToOsmPrecision(ll.lat()); 
    181186        } 
    182         if (ll.lon() > maxLon) { 
    183             maxLon = LatLon.roundToOsmPrecision(ll.lon()); 
     187        if (crosses180thMeridian()) { 
     188            if (ll.lon() > maxLon && ll.lon() < minLon) { 
     189                if (Math.abs(ll.lon() - minLon) <= Math.abs(ll.lon() - maxLon)) { 
     190                    minLon = LatLon.roundToOsmPrecision(ll.lon()); 
     191                } else { 
     192                    maxLon = LatLon.roundToOsmPrecision(ll.lon()); 
     193                } 
     194            } 
     195        } else { 
     196            if (ll.lon() < minLon) { 
     197                minLon = LatLon.roundToOsmPrecision(ll.lon()); 
     198            } 
     199            if (ll.lon() > maxLon) { 
     200                maxLon = LatLon.roundToOsmPrecision(ll.lon()); 
     201            } 
    184202        } 
    185203    } 
     
    189207        extend(b.getMax()); 
    190208    } 
     209     
    191210    /** 
    192211     * Is the given point within this bounds? 
    193212     */ 
    194213    public boolean contains(LatLon ll) { 
    195         if (ll.lat() < minLat || ll.lon() < minLon) 
    196             return false; 
    197         if (ll.lat() > maxLat || ll.lon() > maxLon) 
    198             return false; 
     214        if (ll.lat() < minLat || ll.lat() > maxLat) 
     215            return false; 
     216        if (crosses180thMeridian()) { 
     217            if (ll.lon() > maxLon && ll.lon() < minLon) 
     218                return false; 
     219        } else { 
     220            if (ll.lon() < minLon || ll.lon() > maxLon) 
     221                return false; 
     222        } 
    199223        return true; 
    200224    } 
    201225 
     226    private static boolean intersectsLonCrossing(Bounds crossing, Bounds notCrossing) { 
     227        return notCrossing.minLon <= crossing.maxLon || notCrossing.maxLon >= crossing.minLon; 
     228    } 
     229     
    202230    /** 
    203231     * The two bounds intersect? Compared to java Shape.intersects, if does not use 
     
    205233     */ 
    206234    public boolean intersects(Bounds b) { 
    207         return b.maxLat >= minLat && 
    208         b.maxLon >= minLon && 
    209         b.minLat <= maxLat && 
    210         b.minLon <= maxLon; 
    211     } 
    212  
    213  
     235        if (b.maxLat < minLat || b.minLat > maxLat) 
     236            return false; 
     237         
     238        if (crosses180thMeridian() && !b.crosses180thMeridian()) { 
     239            return intersectsLonCrossing(this, b); 
     240        } else if (!crosses180thMeridian() && b.crosses180thMeridian()) { 
     241            return intersectsLonCrossing(b, this); 
     242        } else if (crosses180thMeridian() && b.crosses180thMeridian()) { 
     243            return true; 
     244        } else { 
     245            return b.maxLon >= minLon && b.minLon <= maxLon; 
     246        } 
     247    } 
     248 
     249    /** 
     250     * Determines if this Bounds object crosses the 180th Meridian. 
     251     * See http://wiki.openstreetmap.org/wiki/180th_meridian 
     252     * @return true if this Bounds object crosses the 180th Meridian. 
     253     */ 
     254    public boolean crosses180thMeridian() { 
     255        return this.minLon > this.maxLon; 
     256    } 
     257     
    214258    /** 
    215259     * Converts the lat/lon bounding box to an object of type Rectangle2D.Double 
     
    217261     */ 
    218262    public Rectangle2D.Double asRect() { 
    219         return new Rectangle2D.Double(minLon, minLat, maxLon-minLon, maxLat-minLat); 
     263        double w = maxLon-minLon + (crosses180thMeridian() ? 360.0 : 0.0); 
     264        return new Rectangle2D.Double(minLon, minLat, w, maxLat-minLat); 
    220265    } 
    221266 
    222267    public double getArea() { 
    223         return (maxLon - minLon) * (maxLat - minLat); 
     268        double w = maxLon-minLon + (crosses180thMeridian() ? 360.0 : 0.0); 
     269        return w * (maxLat - minLat); 
    224270    } 
    225271 
     
    250296    } 
    251297 
    252     private double toIntervalLat(double value, double min, double max) { 
    253         if (value < min) 
    254             return min; 
    255         if (value > max) 
    256             return max; 
    257         return value; 
    258     } 
    259  
    260     private double toIntervalLon(double value) { 
    261         if (value < -180 || value > 180) { 
    262             value = (value + 180) % 360; 
    263             if (value < 0) { 
    264                 value += 360; 
    265             } 
    266             return value - 180; 
    267         } else 
    268             return value; 
    269     } 
    270  
    271298    public void normalize() { 
    272         minLat = toIntervalLat(minLat, -90, 90); 
    273         maxLat = toIntervalLat(maxLat, -90, 90); 
    274         minLon = toIntervalLon(minLon); 
    275         maxLon = toIntervalLon(maxLon); 
     299        minLat = LatLon.toIntervalLat(minLat); 
     300        maxLat = LatLon.toIntervalLat(maxLat); 
     301        minLon = LatLon.toIntervalLon(minLon); 
     302        maxLon = LatLon.toIntervalLon(maxLon); 
    276303    } 
    277304 
  • trunk/src/org/openstreetmap/josm/data/coor/LatLon.java

    r4574 r4580  
    7777                return isValidLat(lat()) && isValidLon(lon()); 
    7878        } 
     79         
     80    public static double toIntervalLat(double value) { 
     81        if (value < -90) 
     82            return -90; 
     83        if (value > 90) 
     84            return 90; 
     85        return value; 
     86    } 
     87 
     88    /** 
     89     * Returns a valid OSM longitude [-180,+180] for the given extended longitude value. 
     90     * For example, a value of -181 will return +179, a value of +181 will return -179.  
     91     * @param lon A longitude value not restricted to the [-180,+180] range. 
     92     */ 
     93    public static double toIntervalLon(double value) { 
     94        if (isValidLon(value)) { 
     95            return value; 
     96        } else { 
     97            int n = (int) (value + Math.signum(value)*180.0) / 360; 
     98            return value - n*360.0; 
     99        } 
     100    } 
    79101         
    80102    /** 
     
    165187     */ 
    166188    public boolean isWithin(Bounds b) { 
    167         return lat() >= b.getMin().lat() && lat() <= b.getMax().lat() && lon() > b.getMin().lon() && lon() < b.getMax().lon(); 
     189        return b.contains(this); 
    168190    } 
    169191 
  • trunk/src/org/openstreetmap/josm/data/osm/DataSet.java

    r4414 r4580  
    11751175        return ret; 
    11761176    } 
     1177     
     1178    /** 
     1179     * Moves all primitives and datasources from DataSet "from" to this DataSet 
     1180     * @param from The source DataSet 
     1181     */ 
     1182    public void mergeFrom(DataSet from) { 
     1183        if (from != null) { 
     1184            for (Node n : from.getNodes()) { 
     1185                from.removePrimitive(n); 
     1186                addPrimitive(n); 
     1187            } 
     1188            for (Way w : from.getWays()) { 
     1189                from.removePrimitive(w); 
     1190                addPrimitive(w); 
     1191            } 
     1192            for (Relation r : from.getRelations()) { 
     1193                from.removePrimitive(r); 
     1194                addPrimitive(r); 
     1195            } 
     1196            dataSources.addAll(from.dataSources); 
     1197            from.dataSources.clear(); 
     1198        } 
     1199    } 
    11771200 
    11781201    /* --------------------------------------------------------------------------------- */ 
  • trunk/src/org/openstreetmap/josm/gui/bbox/SlippyMapBBoxChooser.java

    r4552 r4580  
    311311        iSelectionRectEnd = pEnd; 
    312312 
    313         Coordinate l1 = getPosition(p_max); 
    314         Coordinate l2 = getPosition(p_min); 
     313        Coordinate l1 = getPosition(p_max); // lon may be outside [-180,180] 
     314        Coordinate l2 = getPosition(p_min); // lon may be outside [-180,180] 
    315315        Bounds b = new Bounds( 
    316316                new LatLon( 
    317317                        Math.min(l2.getLat(), l1.getLat()), 
    318                         Math.min(l1.getLon(), l2.getLon()) 
     318                        LatLon.toIntervalLon(Math.min(l1.getLon(), l2.getLon())) 
    319319                ), 
    320320                new LatLon( 
    321321                        Math.max(l2.getLat(), l1.getLat()), 
    322                         Math.max(l1.getLon(), l2.getLon())) 
     322                        LatLon.toIntervalLon(Math.max(l1.getLon(), l2.getLon()))) 
    323323        ); 
    324324        Bounds oldValue = this.bbox; 
     
    364364 
    365365        this.bbox = bbox; 
     366        double minLon = bbox.getMin().lon(); 
     367        double maxLon = bbox.getMax().lon(); 
     368         
     369        if (bbox.crosses180thMeridian()) { 
     370            minLon -= 360.0; 
     371        } 
     372 
    366373        int y1 = OsmMercator.LatToY(bbox.getMin().lat(), MAX_ZOOM); 
    367374        int y2 = OsmMercator.LatToY(bbox.getMax().lat(), MAX_ZOOM); 
    368         int x1 = OsmMercator.LonToX(bbox.getMin().lon(), MAX_ZOOM); 
    369         int x2 = OsmMercator.LonToX(bbox.getMax().lon(), MAX_ZOOM); 
    370  
     375        int x1 = OsmMercator.LonToX(minLon, MAX_ZOOM); 
     376        int x2 = OsmMercator.LonToX(maxLon, MAX_ZOOM); 
     377         
    371378        iSelectionRectStart = new Point(Math.min(x1, x2), Math.min(y1, y2)); 
    372379        iSelectionRectEnd = new Point(Math.max(x1, x2), Math.max(y1, y2)); 
  • trunk/src/org/openstreetmap/josm/io/BoundingBoxDownloader.java

    r4521 r4580  
    2222    private final double lat2; 
    2323    private final double lon2; 
     24    private final boolean crosses180th; 
    2425 
    2526    public BoundingBoxDownloader(Bounds downloadArea) { 
     
    2829        this.lat2 = downloadArea.getMax().lat(); 
    2930        this.lon2 = downloadArea.getMax().lon(); 
     31        this.crosses180th = downloadArea.crosses180thMeridian(); 
    3032    } 
    3133 
     34    private GpxData downloadRawGps(String url, ProgressMonitor progressMonitor) throws IOException, OsmTransferException, SAXException { 
     35        boolean done = false; 
     36        GpxData result = null; 
     37        for (int i = 0;!done;++i) { 
     38            progressMonitor.subTask(tr("Downloading points {0} to {1}...", i * 5000, ((i + 1) * 5000))); 
     39            InputStream in = getInputStream(url+i, progressMonitor.createSubTaskMonitor(1, true)); 
     40            if (in == null) { 
     41                break; 
     42            } 
     43            progressMonitor.setTicks(0); 
     44            GpxReader reader = new GpxReader(in); 
     45            reader.parse(false); 
     46            GpxData currentGpx = reader.data; 
     47            if (result == null) { 
     48                result = currentGpx; 
     49            } else if (currentGpx.hasTrackPoints()) { 
     50                result.mergeFrom(currentGpx); 
     51            } else{ 
     52                done = true; 
     53            } 
     54            in.close(); 
     55            activeConnection = null; 
     56        } 
     57        result.fromServer = true; 
     58        return result; 
     59    } 
     60     
    3261    /** 
    3362     * Retrieve raw gps waypoints from the server API. 
     
    4170        try { 
    4271            progressMonitor.indeterminateSubTask(tr("Contacting OSM Server...")); 
    43             String url = "trackpoints?bbox="+lon1+","+lat1+","+lon2+","+lat2+"&page="; 
    44  
    45             boolean done = false; 
    46             GpxData result = null; 
    47             for (int i = 0;!done;++i) { 
    48                 progressMonitor.subTask(tr("Downloading points {0} to {1}...", i * 5000, ((i + 1) * 5000))); 
    49                 InputStream in = getInputStream(url+i, progressMonitor.createSubTaskMonitor(1, true)); 
    50                 if (in == null) { 
    51                     break; 
    52                 } 
    53                 progressMonitor.setTicks(0); 
    54                 GpxReader reader = new GpxReader(in); 
    55                 reader.parse(false); 
    56                 GpxData currentGpx = reader.data; 
    57                 if (result == null) { 
    58                     result = currentGpx; 
    59                 } else if (currentGpx.hasTrackPoints()) { 
    60                     result.mergeFrom(currentGpx); 
    61                 } else{ 
    62                     done = true; 
    63                 } 
    64                 in.close(); 
    65                 activeConnection = null; 
     72            if (crosses180th) { 
     73                // API 0.6 does not support requests crossing the 180th meridian, so make two requests 
     74                GpxData result = downloadRawGps("trackpoints?bbox="+lon1+","+lat1+",180.0,"+lat2+"&page=", progressMonitor); 
     75                result.mergeFrom(downloadRawGps("trackpoints?bbox=-180.0,"+lat1+","+lon2+","+lat2+"&page=", progressMonitor)); 
     76                return result; 
     77            } else { 
     78                // Simple request 
     79                return downloadRawGps("trackpoints?bbox="+lon1+","+lat1+","+lon2+","+lat2+"&page=", progressMonitor); 
    6680            } 
    67             result.fromServer = true; 
    68             return result; 
    6981        } catch (IllegalArgumentException e) { 
    7082            // caused by HttpUrlConnection in case of illegal stuff in the response 
     
    98110        InputStream in = null; 
    99111        try { 
     112            DataSet ds = null; 
    100113            progressMonitor.indeterminateSubTask(null); 
    101             in = getInputStream("map?bbox="+lon1+","+lat1+","+lon2+","+lat2, progressMonitor.createSubTaskMonitor(9, false)); 
    102             if (in == null) 
    103                 return null; 
    104             return OsmReader.parseDataSet(in, progressMonitor.createSubTaskMonitor(1, false)); 
     114            if (crosses180th) { 
     115                // API 0.6 does not support requests crossing the 180th meridian, so make two requests 
     116                in = getInputStream("map?bbox="+lon1+","+lat1+",180.0,"+lat2, progressMonitor.createSubTaskMonitor(9, false)); 
     117                if (in == null) 
     118                    return null; 
     119                ds = OsmReader.parseDataSet(in, progressMonitor.createSubTaskMonitor(1, false)); 
     120 
     121                in = getInputStream("map?bbox=-180.0,"+lat1+","+lon2+","+lat2, progressMonitor.createSubTaskMonitor(9, false)); 
     122                if (in == null) 
     123                    return null; 
     124                DataSet ds2 = OsmReader.parseDataSet(in, progressMonitor.createSubTaskMonitor(1, false)); 
     125                if (ds2 == null) 
     126                    return null; 
     127                ds.mergeFrom(ds2); 
     128                 
     129            } else { 
     130                // Simple request 
     131                in = getInputStream("map?bbox="+lon1+","+lat1+","+lon2+","+lat2, progressMonitor.createSubTaskMonitor(9, false)); 
     132                if (in == null) 
     133                    return null; 
     134                ds = OsmReader.parseDataSet(in, progressMonitor.createSubTaskMonitor(1, false)); 
     135            } 
     136            return ds; 
    105137        } catch(OsmTransferException e) { 
    106138            throw e; 
  • trunk/test/unit/org/openstreetmap/josm/data/coor/LatLonTest.java

    r4574 r4580  
    7373        assertEquals(LatLon.roundToOsmPrecisionStrict(99.9999999),  99.9999999, 0); 
    7474    } 
     75     
     76    @Test 
     77    public void toIntervalLonTests() { 
     78        assertEquals(-180.0, LatLon.toIntervalLon(-180.0), 0); 
     79        assertEquals(0.0, LatLon.toIntervalLon(0.0), 0); 
     80        assertEquals(180.0, LatLon.toIntervalLon(180.0), 0); 
     81 
     82        assertEquals(179.0, LatLon.toIntervalLon(-181.0), 0); 
     83        assertEquals(-179.0, LatLon.toIntervalLon(181.0), 0); 
     84 
     85        assertEquals(-1.0, LatLon.toIntervalLon(359.0), 0); 
     86        assertEquals(1.0, LatLon.toIntervalLon(-359.0), 0); 
     87 
     88        assertEquals(1.0, LatLon.toIntervalLon(361.0), 0); 
     89        assertEquals(-1.0, LatLon.toIntervalLon(-361.0), 0); 
     90 
     91        assertEquals(179.0, LatLon.toIntervalLon(539.0), 0); 
     92        assertEquals(-179.0, LatLon.toIntervalLon(-539.0), 0); 
     93 
     94        assertEquals(-179.0, LatLon.toIntervalLon(541.0), 0); 
     95        assertEquals(179.0, LatLon.toIntervalLon(-541.0), 0); 
     96    } 
    7597} 
Note: See TracChangeset for help on using the changeset viewer.