Index: src/org/openstreetmap/gui/jmapviewer/JMapViewer.java
===================================================================
--- src/org/openstreetmap/gui/jmapviewer/JMapViewer.java	(revision 26651)
+++ src/org/openstreetmap/gui/jmapviewer/JMapViewer.java	(working copy)
@@ -27,6 +27,7 @@
 import javax.swing.event.ChangeListener;
 
 import org.openstreetmap.gui.jmapviewer.interfaces.MapMarker;
+import org.openstreetmap.gui.jmapviewer.interfaces.MapPolygon;
 import org.openstreetmap.gui.jmapviewer.interfaces.MapRectangle;
 import org.openstreetmap.gui.jmapviewer.interfaces.TileCache;
 import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
@@ -56,9 +57,11 @@
 
     protected List<MapMarker> mapMarkerList;
     protected List<MapRectangle> mapRectangleList;
+    protected List<MapPolygon> mapPolygonList;
 
     protected boolean mapMarkersVisible;
     protected boolean mapRectanglesVisible;
+    protected boolean mapPolygonsVisible;
 
     protected boolean tileGridVisible;
 
@@ -115,8 +118,10 @@
         tileController = new TileController(tileSource, tileCache, this);
         mapMarkerList = new LinkedList<MapMarker>();
         mapRectangleList = new LinkedList<MapRectangle>();
+        mapPolygonList = new LinkedList<MapPolygon>();
         mapMarkersVisible = true;
         mapRectanglesVisible = true;
+        mapPolygonsVisible = true;
         tileGridVisible = false;
         setLayout(null);
         initializeZoomSlider();
@@ -246,35 +251,65 @@
     }
 
     /**
-     * Sets the displayed map pane and zoom level so that all map markers are
+     * Sets the displayed map pane and zoom level so that all chosen map elements are
      * visible.
      */
-    public void setDisplayToFitMapMarkers() {
-        if (mapMarkerList == null || mapMarkerList.size() == 0)
+    public void setDisplayToFitMapElements(boolean markers, boolean rectangles, boolean polygons) {
+        int nbElemToCheck = 0;
+        if (markers && mapMarkerList != null)
+            nbElemToCheck += mapMarkerList.size();
+        if (rectangles && mapRectangleList != null)
+            nbElemToCheck += mapRectangleList.size();
+        if (polygons && mapPolygonList != null)
+            nbElemToCheck += mapPolygonList.size();
+        if (nbElemToCheck == 0)
             return;
+        
         int x_min = Integer.MAX_VALUE;
         int y_min = Integer.MAX_VALUE;
         int x_max = Integer.MIN_VALUE;
         int y_max = Integer.MIN_VALUE;
         int mapZoomMax = tileController.getTileSource().getMaxZoom();
-        for (MapMarker marker : mapMarkerList) {
-            int x = OsmMercator.LonToX(marker.getLon(), mapZoomMax);
-            int y = OsmMercator.LatToY(marker.getLat(), mapZoomMax);
-            x_max = Math.max(x_max, x);
-            y_max = Math.max(y_max, y);
-            x_min = Math.min(x_min, x);
-            y_min = Math.min(y_min, y);
+        
+        if (markers) {
+            for (MapMarker marker : mapMarkerList) {
+                int x = OsmMercator.LonToX(marker.getLon(), mapZoomMax);
+                int y = OsmMercator.LatToY(marker.getLat(), mapZoomMax);
+                x_max = Math.max(x_max, x);
+                y_max = Math.max(y_max, y);
+                x_min = Math.min(x_min, x);
+                y_min = Math.min(y_min, y);
+            }
         }
+        
+        if (rectangles) {
+            for (MapRectangle rectangle : mapRectangleList) {
+                x_max = Math.max(x_max, OsmMercator.LonToX(rectangle.getBottomRight().getLon(), mapZoomMax));
+                y_max = Math.max(y_max, OsmMercator.LatToY(rectangle.getTopLeft().getLat(), mapZoomMax));
+                x_min = Math.min(x_min, OsmMercator.LonToX(rectangle.getTopLeft().getLon(), mapZoomMax));
+                y_min = Math.min(y_min, OsmMercator.LatToY(rectangle.getBottomRight().getLat(), mapZoomMax));
+            }
+        }
+        
+        if (polygons) {
+            for (MapPolygon polygon : mapPolygonList) {
+                for (Coordinate c : polygon.getPoints()) {
+                    int x = OsmMercator.LonToX(c.getLon(), mapZoomMax);
+                    int y = OsmMercator.LatToY(c.getLat(), mapZoomMax);
+                    x_max = Math.max(x_max, x);
+                    y_max = Math.max(y_max, y);
+                    x_min = Math.min(x_min, x);
+                    y_min = Math.min(y_min, y);
+                }
+            }
+        }
+        
         int height = Math.max(0, getHeight());
         int width = Math.max(0, getWidth());
-        // System.out.println(x_min + " < x < " + x_max);
-        // System.out.println(y_min + " < y < " + y_max);
-        // System.out.println("tiles: " + width + " " + height);
         int newZoom = mapZoomMax;
         int x = x_max - x_min;
         int y = y_max - y_min;
         while (x > width || y > height) {
-            // System.out.println("zoom: " + zoom + " -> " + x + " " + y);
             newZoom--;
             x >>= 1;
             y >>= 1;
@@ -286,48 +321,32 @@
         y /= z;
         setDisplayPosition(x, y, newZoom);
     }
-
+    
     /**
      * Sets the displayed map pane and zoom level so that all map markers are
      * visible.
      */
-    public void setDisplayToFitMapRectangle() {
-        if (mapRectangleList == null || mapRectangleList.size() == 0)
-            return;
-        int x_min = Integer.MAX_VALUE;
-        int y_min = Integer.MAX_VALUE;
-        int x_max = Integer.MIN_VALUE;
-        int y_max = Integer.MIN_VALUE;
-        int mapZoomMax = tileController.getTileSource().getMaxZoom();
-        for (MapRectangle rectangle : mapRectangleList) {
-            x_max = Math.max(x_max, OsmMercator.LonToX(rectangle.getBottomRight().getLon(), mapZoomMax));
-            y_max = Math.max(y_max, OsmMercator.LatToY(rectangle.getTopLeft().getLat(), mapZoomMax));
-            x_min = Math.min(x_min, OsmMercator.LonToX(rectangle.getTopLeft().getLon(), mapZoomMax));
-            y_min = Math.min(y_min, OsmMercator.LatToY(rectangle.getBottomRight().getLat(), mapZoomMax));
-        }
-        int height = Math.max(0, getHeight());
-        int width = Math.max(0, getWidth());
-        // System.out.println(x_min + " < x < " + x_max);
-        // System.out.println(y_min + " < y < " + y_max);
-        // System.out.println("tiles: " + width + " " + height);
-        int newZoom = mapZoomMax;
-        int x = x_max - x_min;
-        int y = y_max - y_min;
-        while (x > width || y > height) {
-            // System.out.println("zoom: " + zoom + " -> " + x + " " + y);
-            newZoom--;
-            x >>= 1;
-            y >>= 1;
-        }
-        x = x_min + (x_max - x_min) / 2;
-        y = y_min + (y_max - y_min) / 2;
-        int z = 1 << (mapZoomMax - newZoom);
-        x /= z;
-        y /= z;
-        setDisplayPosition(x, y, newZoom);
+    public void setDisplayToFitMapMarkers() {
+        setDisplayToFitMapElements(true, false, false);
     }
 
     /**
+     * Sets the displayed map pane and zoom level so that all map rectangles are
+     * visible.
+     */
+    public void setDisplayToFitMapRectangles() {
+        setDisplayToFitMapElements(false, true, false);
+    }
+    
+    /**
+     * Sets the displayed map pane and zoom level so that all map polygons are
+     * visible.
+     */
+    public void setDisplayToFitMapPolygons() {
+        setDisplayToFitMapElements(false, false, true);
+    }
+
+    /**
      * Calculates the latitude/longitude coordinate of the center of the
      * currently displayed map area.
      * 
@@ -506,17 +525,15 @@
 
         // g.drawString("Tiles in cache: " + tileCache.getTileCount(), 50, 20);
 
+        if (mapPolygonsVisible && mapPolygonList != null) {
+            for (MapPolygon polygon : mapPolygonList) {
+                paintPolygon(g, polygon);
+            }
+        }
+
         if (mapRectanglesVisible && mapRectangleList != null) {
             for (MapRectangle rectangle : mapRectangleList) {
-                Coordinate topLeft = rectangle.getTopLeft();
-                Coordinate bottomRight = rectangle.getBottomRight();
-                if (topLeft != null && bottomRight != null) {
-                    Point pTopLeft = getMapPosition(topLeft.getLat(), topLeft.getLon(), false);
-                    Point pBottomRight = getMapPosition(bottomRight.getLat(), bottomRight.getLon(), false);
-                    if (pTopLeft != null && pBottomRight != null) {
-                        rectangle.paint(g, pTopLeft, pBottomRight);
-                    }
-                }
+                paintRectangle(g, rectangle);
             }
         }
 
@@ -539,6 +556,39 @@
     }
 
     /**
+     * Paint a single rectangle.
+     */
+    protected void paintRectangle(Graphics g, MapRectangle rectangle) {
+        Coordinate topLeft = rectangle.getTopLeft();
+        Coordinate bottomRight = rectangle.getBottomRight();
+        if (topLeft != null && bottomRight != null) {
+            Point pTopLeft = getMapPosition(topLeft, false);
+            Point pBottomRight = getMapPosition(bottomRight, false);
+            if (pTopLeft != null && pBottomRight != null) {
+                rectangle.paint(g, pTopLeft, pBottomRight);
+            }
+        }
+    }
+
+    /**
+     * Paint a single polygon.
+     */
+    protected void paintPolygon(Graphics g, MapPolygon polygon) {
+        List<Coordinate> coords = polygon.getPoints();
+        if (coords != null && coords.size() >= 3) {
+            List<Point> points = new LinkedList<Point>();
+            for (Coordinate c : coords) {
+                Point p = getMapPosition(c, false);
+                if (p == null) {
+                    return;
+                }
+                points.add(p);
+            }
+            polygon.paint(g, points);
+        }
+    }
+    
+    /**
      * Moves the visible map pane.
      * 
      * @param x
@@ -660,6 +710,15 @@
         return mapRectangleList;
     }
 
+    public void setMapPolygonList(List<MapPolygon> mapPolygonList) {
+        this.mapPolygonList = mapPolygonList;
+        repaint();
+    }
+
+    public List<MapPolygon> getMapPolygonList() {
+        return mapPolygonList;
+    }
+
     public void addMapMarker(MapMarker marker) {
         mapMarkerList.add(marker);
         repaint();
@@ -690,6 +749,21 @@
         repaint();
     }
 
+    public void addMapPolygon(MapPolygon polygon) {
+        mapPolygonList.add(polygon);
+        repaint();
+    }
+
+    public void removeMapPolygon(MapPolygon polygon) {
+        mapPolygonList.remove(polygon);
+        repaint();
+    }
+
+    public void removeAllMapPolygons() {
+        mapPolygonList.clear();
+        repaint();
+    }
+    
     public void setZoomContolsVisible(boolean visible) {
         zoomSlider.setVisible(visible);
         zoomInButton.setVisible(visible);
@@ -735,7 +809,7 @@
     /**
      * Enables or disables painting of the {@link MapRectangle}
      * 
-     * @param mapMarkersVisible
+     * @param mapRectanglesVisible
      * @see #addMapRectangle(MapRectangle)
      * @see #getMapRectangleList()
      */
@@ -744,6 +818,22 @@
         repaint();
     }
 
+    public boolean isMapPolygonsVisible() {
+        return mapPolygonsVisible;
+    }
+
+    /**
+     * Enables or disables painting of the {@link MapPolygon}
+     * 
+     * @param mapPolygonsVisible
+     * @see #addMapPolygon(MapPolygon)
+     * @see #getMapPolygonList()
+     */
+    public void setMapPolygonsVisible(boolean mapPolygonsVisible) {
+        this.mapPolygonsVisible = mapPolygonsVisible;
+        repaint();
+    }
+
     /*
      * (non-Javadoc)
      * 
Index: src/org/openstreetmap/gui/jmapviewer/MapPolygonImpl.java
===================================================================
--- src/org/openstreetmap/gui/jmapviewer/MapPolygonImpl.java	(revision 0)
+++ src/org/openstreetmap/gui/jmapviewer/MapPolygonImpl.java	(revision 0)
@@ -0,0 +1,85 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.gui.jmapviewer;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Point;
+import java.awt.Polygon;
+import java.awt.Stroke;
+import java.util.List;
+
+import org.openstreetmap.gui.jmapviewer.interfaces.MapPolygon;
+
+/**
+ * @author Vincent
+ *
+ */
+public class MapPolygonImpl implements MapPolygon {
+
+    private List<Coordinate> points;
+    private Color color;
+    private Stroke stroke;
+
+    public MapPolygonImpl(List<Coordinate> points) {
+        this(points, Color.BLUE, new BasicStroke(2));
+    }
+
+    public MapPolygonImpl(List<Coordinate> points, Color color, Stroke stroke) {
+        this.points = points;
+        this.color = color;
+        this.stroke = stroke;
+    }
+
+    /* (non-Javadoc)
+     * @see org.openstreetmap.gui.jmapviewer.interfaces.MapPolygon#getPoints()
+     */
+    @Override
+    public List<Coordinate> getPoints() {
+        return this.points;
+    }
+
+    /* (non-Javadoc)
+     * @see org.openstreetmap.gui.jmapviewer.interfaces.MapPolygon#paint(java.awt.Graphics, java.util.List)
+     */
+    @Override
+    public void paint(Graphics g, List<Point> points) {
+        Polygon polygon = new Polygon();
+        for (Point p : points) {
+            polygon.addPoint(p.x, p.y);
+        }
+        paint(g, polygon);
+    }
+
+    /* (non-Javadoc)
+     * @see org.openstreetmap.gui.jmapviewer.interfaces.MapPolygon#paint(java.awt.Graphics, java.awt.Polygon)
+     */
+    @Override
+    public void paint(Graphics g, Polygon polygon) {
+        // Prepare graphics
+        Color oldColor = g.getColor();
+        g.setColor(color);
+        Stroke oldStroke = null;
+        if (g instanceof Graphics2D) {
+            Graphics2D g2 = (Graphics2D) g;
+            oldStroke = g2.getStroke();
+            g2.setStroke(stroke);
+        }
+        // Draw
+        g.drawPolygon(polygon);
+        // Restore graphics
+        g.setColor(oldColor);
+        if (g instanceof Graphics2D) {
+            ((Graphics2D) g).setStroke(oldStroke);
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "MapPolygon [points=" + points + "]";
+    }
+}
Index: src/org/openstreetmap/gui/jmapviewer/MapRectangleImpl.java
===================================================================
--- src/org/openstreetmap/gui/jmapviewer/MapRectangleImpl.java	(revision 26651)
+++ src/org/openstreetmap/gui/jmapviewer/MapRectangleImpl.java	(working copy)
@@ -1,9 +1,12 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.gui.jmapviewer;
 
+import java.awt.BasicStroke;
 import java.awt.Color;
 import java.awt.Graphics;
+import java.awt.Graphics2D;
 import java.awt.Point;
+import java.awt.Stroke;
 
 import org.openstreetmap.gui.jmapviewer.interfaces.MapRectangle;
 import org.openstreetmap.josm.data.Bounds;
@@ -16,16 +19,18 @@
 
     private Coordinate topLeft;
     private Coordinate bottomRight;
-    Color color;
+    private Color color;
+    private Stroke stroke;
 
     public MapRectangleImpl(Bounds bounds) {
-        this(bounds, Color.BLUE);
+        this(bounds, Color.BLUE, new BasicStroke(2));
     }
 
-    public MapRectangleImpl(Bounds bounds, Color color) {
+    public MapRectangleImpl(Bounds bounds, Color color, Stroke stroke) {
         this.topLeft = new Coordinate(bounds.getMax().lat(), bounds.getMin().lon());
         this.bottomRight = new Coordinate(bounds.getMin().lat(), bounds.getMax().lon());
         this.color = color;
+        this.stroke = stroke;
     }
 
     /* (non-Javadoc)
@@ -49,8 +54,22 @@
      */
     @Override
     public void paint(Graphics g, Point topLeft, Point bottomRight) {
+        // Prepare graphics
+        Color oldColor = g.getColor();
         g.setColor(color);
+        Stroke oldStroke = null;
+        if (g instanceof Graphics2D) {
+            Graphics2D g2 = (Graphics2D) g;
+            oldStroke = g2.getStroke();
+            g2.setStroke(stroke);
+        }
+        // Draw
         g.drawRect(topLeft.x, topLeft.y, bottomRight.x - topLeft.x, bottomRight.y - topLeft.y);
+        // Restore graphics
+        g.setColor(oldColor);
+        if (g instanceof Graphics2D) {
+            ((Graphics2D) g).setStroke(oldStroke);
+        }
     }
 
     @Override
Index: src/org/openstreetmap/gui/jmapviewer/interfaces/MapPolygon.java
===================================================================
--- src/org/openstreetmap/gui/jmapviewer/interfaces/MapPolygon.java	(revision 0)
+++ src/org/openstreetmap/gui/jmapviewer/interfaces/MapPolygon.java	(revision 0)
@@ -0,0 +1,40 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.gui.jmapviewer.interfaces;
+
+import java.awt.Graphics;
+import java.awt.Point;
+import java.awt.Polygon;
+import java.util.List;
+
+import org.openstreetmap.gui.jmapviewer.Coordinate;
+
+/**
+ * Interface to be implemented by polygons that can be displayed on the map.
+ *
+ * @author Vincent
+ */
+public interface MapPolygon {
+
+    /**
+     * @return Latitude/Longitude of each point of polygon
+     */
+    public List<Coordinate> getPoints();
+
+    /**
+     * Paints the map rectangle on the map. The <code>points</code> 
+     * are specifying the coordinates within <code>g</code>
+     *
+     * @param g
+     * @param points
+     */
+    public void paint(Graphics g, List<Point> points);
+
+    /**
+     * Paints the map rectangle on the map. The <code>polygon</code> 
+     * is specifying the coordinates within <code>g</code>
+     *
+     * @param g
+     * @param polygon
+     */
+    public void paint(Graphics g, Polygon polygon);
+}
Index: src/org/openstreetmap/josm/data/Bounds.java
===================================================================
--- src/org/openstreetmap/josm/data/Bounds.java	(revision 4419)
+++ src/org/openstreetmap/josm/data/Bounds.java	(working copy)
@@ -42,20 +42,20 @@
     }
 
     public Bounds(double minlat, double minlon, double maxlat, double maxlon) {
-        this.minLat = roundToOsmPrecision(minlat);
-        this.minLon = roundToOsmPrecision(minlon);
-        this.maxLat = roundToOsmPrecision(maxlat);
-        this.maxLon = roundToOsmPrecision(maxlon);
+        this.minLat = LatLon.roundToOsmPrecision(minlat);
+        this.minLon = LatLon.roundToOsmPrecision(minlon);
+        this.maxLat = LatLon.roundToOsmPrecision(maxlat);
+        this.maxLon = LatLon.roundToOsmPrecision(maxlon);
     }
 
     public Bounds(double [] coords) {
         CheckParameterUtil.ensureParameterNotNull(coords, "coords");
         if (coords.length != 4)
             throw new IllegalArgumentException(MessageFormat.format("Expected array of length 4, got {0}", coords.length));
-        this.minLat = roundToOsmPrecision(coords[0]);
-        this.minLon = roundToOsmPrecision(coords[1]);
-        this.maxLat = roundToOsmPrecision(coords[2]);
-        this.maxLon = roundToOsmPrecision(coords[3]);
+        this.minLat = LatLon.roundToOsmPrecision(coords[0]);
+        this.minLon = LatLon.roundToOsmPrecision(coords[1]);
+        this.maxLat = LatLon.roundToOsmPrecision(coords[2]);
+        this.maxLon = LatLon.roundToOsmPrecision(coords[3]);
     }
 
     public Bounds(String asString, String separator) throws IllegalArgumentException {
@@ -80,10 +80,10 @@
         if (!LatLon.isValidLon(values[3]))
             throw new IllegalArgumentException(tr("Illegal latitude value ''{0}''", values[3]));
 
-        this.minLat = roundToOsmPrecision(values[0]);
-        this.minLon = roundToOsmPrecision(values[1]);
-        this.maxLat = roundToOsmPrecision(values[2]);
-        this.maxLon = roundToOsmPrecision(values[3]);
+        this.minLat = LatLon.roundToOsmPrecision(values[0]);
+        this.minLon = LatLon.roundToOsmPrecision(values[1]);
+        this.maxLat = LatLon.roundToOsmPrecision(values[2]);
+        this.maxLon = LatLon.roundToOsmPrecision(values[3]);
     }
 
     public Bounds(Bounds other) {
@@ -113,10 +113,10 @@
         if (lonExtent <= 0.0)
             throw new IllegalArgumentException(MessageFormat.format("Parameter ''{0}'' > 0.0 exptected, got {1}", "lonExtent", lonExtent));
 
-        this.minLat = roundToOsmPrecision(center.lat() - latExtent / 2);
-        this.minLon = roundToOsmPrecision(center.lon() - lonExtent / 2);
-        this.maxLat = roundToOsmPrecision(center.lat() + latExtent / 2);
-        this.maxLon = roundToOsmPrecision(center.lon() + lonExtent / 2);
+        this.minLat = LatLon.roundToOsmPrecision(center.lat() - latExtent / 2);
+        this.minLon = LatLon.roundToOsmPrecision(center.lon() - lonExtent / 2);
+        this.maxLat = LatLon.roundToOsmPrecision(center.lat() + latExtent / 2);
+        this.maxLon = LatLon.roundToOsmPrecision(center.lon() + lonExtent / 2);
     }
 
     @Override public String toString() {
@@ -144,16 +144,16 @@
      */
     public void extend(LatLon ll) {
         if (ll.lat() < minLat) {
-            minLat = roundToOsmPrecision(ll.lat());
+            minLat = LatLon.roundToOsmPrecision(ll.lat());
         }
         if (ll.lon() < minLon) {
-            minLon = roundToOsmPrecision(ll.lon());
+            minLon = LatLon.roundToOsmPrecision(ll.lon());
         }
         if (ll.lat() > maxLat) {
-            maxLat = roundToOsmPrecision(ll.lat());
+            maxLat = LatLon.roundToOsmPrecision(ll.lat());
         }
         if (ll.lon() > maxLon) {
-            maxLon = roundToOsmPrecision(ll.lon());
+            maxLon = LatLon.roundToOsmPrecision(ll.lon());
         }
     }
 
@@ -283,14 +283,4 @@
             return false;
         return true;
     }
-
-    /**
-     * Returns the value rounded to OSM precisions, i.e. to
-     * LatLon.MAX_SERVER_PRECISION
-     *
-     * @return rounded value
-     */
-    private double roundToOsmPrecision(double value) {
-        return Math.round(value / LatLon.MAX_SERVER_PRECISION) * LatLon.MAX_SERVER_PRECISION;
-    }
 }
Index: src/org/openstreetmap/josm/data/coor/LatLon.java
===================================================================
--- src/org/openstreetmap/josm/data/coor/LatLon.java	(revision 4419)
+++ src/org/openstreetmap/josm/data/coor/LatLon.java	(working copy)
@@ -222,7 +222,17 @@
     @Override public String toString() {
         return "LatLon[lat="+lat()+",lon="+lon()+"]";
     }
-
+    
+    /**
+     * Returns the value rounded to OSM precisions, i.e. to
+     * LatLon.MAX_SERVER_PRECISION
+     *
+     * @return rounded value
+     */
+    public static double roundToOsmPrecision(double value) {
+        return Math.round(value / MAX_SERVER_PRECISION) * MAX_SERVER_PRECISION;
+    }
+    
     /**
      * Replies a clone of this lat LatLon, rounded to OSM precisions, i.e. to
      * MAX_SERVER_PRECISION
@@ -231,8 +241,8 @@
      */
     public LatLon getRoundedToOsmPrecision() {
         return new LatLon(
-                Math.round(lat() / MAX_SERVER_PRECISION) * MAX_SERVER_PRECISION,
-                Math.round(lon() / MAX_SERVER_PRECISION) * MAX_SERVER_PRECISION
+                roundToOsmPrecision(lat()),
+                roundToOsmPrecision(lon())
         );
     }
 
Index: src/org/openstreetmap/josm/data/imagery/ImageryInfo.java
===================================================================
--- src/org/openstreetmap/josm/data/imagery/ImageryInfo.java	(revision 4419)
+++ src/org/openstreetmap/josm/data/imagery/ImageryInfo.java	(working copy)
@@ -40,6 +40,26 @@
             return urlString;
         }
     }
+    
+    public static class ImageryBounds extends Bounds {
+        public ImageryBounds(String asString, String separator) {
+            super(asString, separator);
+        }
+
+        private List<Shape> shapes = new ArrayList<Shape>();
+        
+        public void addShape(Shape shape) {
+            this.shapes.add(shape);
+        }
+
+        public void setShapes(List<Shape> shapes) {
+            this.shapes = shapes;
+        }
+
+        public List<Shape> getShapes() {
+            return shapes;
+        }
+    }
 
     private String name;
     private String url = null;
@@ -51,7 +71,7 @@
     private int maxZoom = 0;
     private int defaultMaxZoom = 0;
     private int defaultMinZoom = 0;
-    private Bounds bounds = null;
+    private ImageryBounds bounds = null;
     private List<String> serverProjections;
     private String attributionText;
     private String attributionImage;
@@ -106,6 +126,15 @@
         res.add(attributionLinkURL);
         res.add(attributionImage);
         res.add(termsOfUseURL);
+        // Shapes
+        String shapesString = "";
+        for (Shape s : bounds.getShapes()) {
+            if (!shapesString.isEmpty()) {
+                shapesString += ";";
+            }
+            shapesString += s.encodeAsString(",");
+        }
+        res.add(shapesString.isEmpty() ? null : shapesString);
         return res;
     }
 
@@ -127,7 +156,7 @@
         }
         if(array.size() >= 5 && !array.get(4).isEmpty()) {
             try {
-                bounds = new Bounds(array.get(4), ",");
+                bounds = new ImageryBounds(array.get(4), ",");
             } catch (IllegalArgumentException e) {
                 Main.warn(e.toString());
             }
@@ -144,6 +173,15 @@
         if(array.size() >= 9 && !array.get(8).isEmpty()) {
             setTermsOfUseURL(array.get(8));
         }
+        if(bounds != null && array.size() >= 10 && !array.get(9).isEmpty()) {
+            try {
+                for (String s : array.get(9).split(";")) {
+                    bounds.addShape(new Shape(s, ","));
+                }
+            } catch (IllegalArgumentException e) {
+                Main.warn(e.toString());
+            }
+        }
     }
 
     public ImageryInfo(ImageryInfo i) {
@@ -200,16 +238,16 @@
         this.maxZoom = maxZoom;
     }
 
-    public void setBounds(Bounds b) {
+    public void setBounds(ImageryBounds b) {
         this.bounds = b;
     }
 
-    public Bounds getBounds() {
+    public ImageryBounds getBounds() {
         return bounds;
     }
 
     public void setAttributionText(String text) {
-         attributionText = text;
+        attributionText = text;
     }
 
     public void setAttributionImage(String text) {
Index: src/org/openstreetmap/josm/data/imagery/Shape.java
===================================================================
--- src/org/openstreetmap/josm/data/imagery/Shape.java	(revision 0)
+++ src/org/openstreetmap/josm/data/imagery/Shape.java	(revision 0)
@@ -0,0 +1,74 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.imagery;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.openstreetmap.gui.jmapviewer.Coordinate;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.tools.CheckParameterUtil;
+
+/**
+ * @author Vincent
+ *
+ */
+public class Shape {
+
+    private List<Coordinate> coords = new ArrayList<Coordinate>();
+    
+    public Shape(String asString, String separator) throws IllegalArgumentException {
+        CheckParameterUtil.ensureParameterNotNull(asString, "asString");
+        String[] components = asString.split(separator);
+        if (components.length % 2 != 0)
+            throw new IllegalArgumentException(MessageFormat.format("Even number of doubles excpected in string, got {0}: {1}", components.length, asString));
+        for (int i=0; i<components.length; i+=2) {
+            addPoint(components[i], components[i+1]);
+        }
+    }
+
+    public Shape() {
+    }
+
+    public String encodeAsString(String separator) {
+        StringBuffer sb = new StringBuffer();
+        for (Coordinate c : coords) {
+            if (sb.length() != 0) {
+                sb.append(separator);
+            }
+            sb.append(c.getLat()).append(separator).append(c.getLon());
+        }
+        return sb.toString();
+    }
+
+    public List<Coordinate> getPoints() {
+        return coords;
+    }
+
+    public void addPoint(String sLat, String sLon) throws IllegalArgumentException {
+        CheckParameterUtil.ensureParameterNotNull(sLat, "sLat");
+        CheckParameterUtil.ensureParameterNotNull(sLon, "sLon");
+
+        double lat, lon;
+        
+        try {
+            lat = Double.parseDouble(sLat);
+            if (!LatLon.isValidLat(lat))
+                throw new IllegalArgumentException(tr("Illegal latitude value ''{0}''", lat));
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException(MessageFormat.format("Illegal double value ''{0}''", sLat));
+        }
+
+        try {
+            lon = Double.parseDouble(sLon);
+            if (!LatLon.isValidLon(lon))
+                throw new IllegalArgumentException(tr("Illegal longitude value ''{0}''", lon));
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException(MessageFormat.format("Illegal double value ''{0}''", sLon));
+        }
+        
+        coords.add(new Coordinate(LatLon.roundToOsmPrecision(lat), LatLon.roundToOsmPrecision(lon)));
+    }
+}
Index: src/org/openstreetmap/josm/gui/preferences/ImageryPreference.java
===================================================================
--- src/org/openstreetmap/josm/gui/preferences/ImageryPreference.java	(revision 4419)
+++ src/org/openstreetmap/josm/gui/preferences/ImageryPreference.java	(working copy)
@@ -17,6 +17,7 @@
 import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
@@ -50,14 +51,17 @@
 import javax.swing.table.TableColumnModel;
 
 import org.openstreetmap.gui.jmapviewer.JMapViewer;
+import org.openstreetmap.gui.jmapviewer.MapPolygonImpl;
 import org.openstreetmap.gui.jmapviewer.MapRectangleImpl;
+import org.openstreetmap.gui.jmapviewer.interfaces.MapPolygon;
 import org.openstreetmap.gui.jmapviewer.interfaces.MapRectangle;
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.imagery.ImageryInfo;
+import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryBounds;
 import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
 import org.openstreetmap.josm.data.imagery.ImageryLayerInfo;
 import org.openstreetmap.josm.data.imagery.OffsetBookmark;
+import org.openstreetmap.josm.data.imagery.Shape;
 import org.openstreetmap.josm.gui.layer.ImageryLayer;
 import org.openstreetmap.josm.gui.layer.TMSLayer;
 import org.openstreetmap.josm.gui.layer.WMSLayer;
@@ -459,42 +463,73 @@
 
         // Listener of default providers list selection
         private final class DefListSelectionListener implements ListSelectionListener {
-            // The current drawn rectangles
+            // The current drawn rectangles and polygons
             private final Map<Integer, MapRectangle> mapRectangles;
+            private final Map<Integer, List<MapPolygon>> mapPolygons;
 
             private DefListSelectionListener() {
                 this.mapRectangles = new HashMap<Integer, MapRectangle>();
+                this.mapPolygons = new HashMap<Integer, List<MapPolygon>>();
             }
 
             @Override
             public void valueChanged(ListSelectionEvent e) {
-                // First index is set to -1 when the list is refreshed, so discard all map rectangles
+                // First index is set to -1 when the list is refreshed, so discard all map rectangles and polygons
                 if (e.getFirstIndex() == -1) {
                     map.removeAllMapRectangles();
+                    map.removeAllMapPolygons();
                     mapRectangles.clear();
+                    mapPolygons.clear();
                     // Only process complete (final) selection events
                 } else if (!e.getValueIsAdjusting()) {
                     for (int i = e.getFirstIndex(); i<=e.getLastIndex(); i++) {
-                        Bounds bounds = modeldef.getRow(i).getBounds();
-                        if (bounds != null) {
-                            if (listdef.getSelectionModel().isSelectedIndex(i)) {
-                                if (!mapRectangles.containsKey(i)) {
-                                    // Add new map rectangle
-                                    MapRectangle rectangle = new MapRectangleImpl(bounds);
-                                    mapRectangles.put(i, rectangle);
-                                    map.addMapRectangle(rectangle);
+                        updateBoundsAndShapes(i);
+                    }
+                    // If needed, adjust map to show all map rectangles and polygons
+                    if (!mapRectangles.isEmpty() || !mapPolygons.isEmpty()) {
+                        map.setDisplayToFitMapElements(false, true, true);
+                        map.zoomOut();
+                    }
+                }
+            }
+            
+            private void updateBoundsAndShapes(int i) {
+                ImageryBounds bounds = modeldef.getRow(i).getBounds();
+                if (bounds != null) {
+                    List<Shape> shapes = bounds.getShapes();
+                    if (shapes != null && !shapes.isEmpty()) {
+                        if (listdef.getSelectionModel().isSelectedIndex(i)) {
+                            if (!mapPolygons.containsKey(i)) {
+                                List<MapPolygon> list = new ArrayList<MapPolygon>();
+                                mapPolygons.put(i, list);
+                                // Add new map polygons
+                                for (Shape shape : shapes) {
+                                    MapPolygon polygon = new MapPolygonImpl(shape.getPoints());
+                                    list.add(polygon);
+                                    map.addMapPolygon(polygon);
                                 }
-                            } else if (mapRectangles.containsKey(i)) {
-                                // Remove previousliy drawn map rectangle
-                                map.removeMapRectangle(mapRectangles.get(i));
-                                mapRectangles.remove(i);
                             }
+                        } else if (mapPolygons.containsKey(i)) {
+                            // Remove previously drawn map polygons
+                            for (MapPolygon polygon : mapPolygons.get(i)) {
+                                map.removeMapPolygon(polygon);
+                            }
+                            mapPolygons.remove(i);
                         }
-                    }
-                    // If needed, adjust map to show all map rectangles
-                    if (!mapRectangles.isEmpty()) {
-                        map.setDisplayToFitMapRectangle();
-                        map.zoomOut();
+                     // Only display bounds when no polygons (shapes) are defined for this provider
+                    } else {
+                        if (listdef.getSelectionModel().isSelectedIndex(i)) {
+                            if (!mapRectangles.containsKey(i)) {
+                                // Add new map rectangle
+                                MapRectangle rectangle = new MapRectangleImpl(bounds);
+                                mapRectangles.put(i, rectangle);
+                                map.addMapRectangle(rectangle);
+                            }
+                        } else if (mapRectangles.containsKey(i)) {
+                            // Remove previously drawn map rectangle
+                            map.removeMapRectangle(mapRectangles.get(i));
+                            mapRectangles.remove(i);
+                        }
                     }
                 }
             }
Index: src/org/openstreetmap/josm/io/imagery/ImageryReader.java
===================================================================
--- src/org/openstreetmap/josm/io/imagery/ImageryReader.java	(revision 4419)
+++ src/org/openstreetmap/josm/io/imagery/ImageryReader.java	(working copy)
@@ -18,9 +18,10 @@
 import javax.xml.parsers.SAXParserFactory;
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.imagery.ImageryInfo;
+import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryBounds;
 import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
+import org.openstreetmap.josm.data.imagery.Shape;
 import org.openstreetmap.josm.io.MirroredInputStream;
 import org.openstreetmap.josm.io.UTFInputStreamReader;
 import org.openstreetmap.josm.tools.Utils;
@@ -40,10 +41,12 @@
         ENTRY_ATTRIBUTE,    // note we are inside an entry attribute to collect the character data
         SUPPORTED_PROJECTIONS,
         PR,
+        SHAPE,
+        SHAPE_POINT,
         UNKNOWN,            // element is not recognized in the current context
     }
 
-    public ImageryReader(String source) throws IOException {
+    public ImageryReader(String source) {
         this.source = source;
     }
 
@@ -142,7 +145,7 @@
                         if (val.length >= 5 && !val[4].isEmpty()) {
                             // 5th parameter optional for bounds
                             try {
-                                info.setBounds(new Bounds(val[4], ","));
+                                info.setBounds(new ImageryBounds(val[4], ","));
                             } catch (IllegalArgumentException e) {
                                 Main.warn(e.toString());
                             }
@@ -189,7 +192,8 @@
         boolean skipEntry;
 
         ImageryInfo entry;
-        Bounds bounds;
+        ImageryBounds bounds;
+        Shape shape;
         List<String> supported_srs;
 
         @Override public void startDocument() {
@@ -240,7 +244,7 @@
                         newState = State.ENTRY_ATTRIBUTE;
                     } else if (qName.equals("bounds")) {
                         try {
-                            bounds = new Bounds(
+                            bounds = new ImageryBounds(
                                     atts.getValue("min-lat") + "," +
                                     atts.getValue("min-lon") + "," +
                                     atts.getValue("max-lat") + "," +
@@ -254,6 +258,22 @@
                         newState = State.SUPPORTED_PROJECTIONS;
                     }
                     break;
+                case ENTRY_ATTRIBUTE:
+                    if (qName.equals("shape")) {
+                        shape = new Shape();
+                        newState = State.SHAPE;
+                    }
+                    break;
+                case SHAPE:
+                    if (qName.equals("point")) {
+                        try {
+                            shape.addPoint(atts.getValue("lat"), atts.getValue("lon"));
+                        } catch (IllegalArgumentException e) {
+                            break;
+                        }
+                        newState = State.SHAPE_POINT;
+                    }
+                    break;
                 case SUPPORTED_PROJECTIONS:
                     if (qName.equals("pr")) {
                         newState = State.PR;
@@ -358,6 +378,10 @@
                     } else {
                     }
                     break;
+                case SHAPE:
+                    bounds.addShape(shape);
+                    shape = null;
+                    break;
                 case PR:
                     supported_srs.add(accumulator.toString());
                     break;
