Changeset 4580 in josm


Ignore:
Timestamp:
2011-11-06T15:00:56+01:00 (8 years 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.