Ignore:
Timestamp:
2009-07-03T12:33:32+02:00 (15 years ago)
Author:
stoecker
Message:

Large rework in projection handling - now allows only switching and more specific projections
TODO:

  • allow subprojections (i.e. settings for projections)
  • setup preferences for subprojections
  • better support of the new projection depending world bounds (how to handle valid data outside of world)
  • do not allow to zoom out of the world - zoom should stop when whole world is displayed
  • fix Lambert and SwissGrid to handle new OutOfWorld style and subprojections
  • fix new UTM projection
  • handle layers with fixed projection on projection change
  • allow easier projection switching (e.g. in menu)

NOTE:
This checkin very likely will cause problems. Please report or fix them. Older plugins may have trouble. The SVN plugins
have been fixed but may have problems nevertheless. This is a BIG change, but will make JOSMs internal structure much cleaner
and reduce lots of projection related problems.

Location:
trunk/src/org/openstreetmap/josm/data
Files:
2 added
13 edited

Legend:

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

    r1169 r1722  
    2525        this.min = min;
    2626        this.max = max;
    27     }
    28 
    29     /**
    30      * Construct bounds that span the whole world.
    31      */
    32     public Bounds() {
    33         min = new LatLon(-Projection.MAX_LAT, -Projection.MAX_LON);
    34         max = new LatLon(Projection.MAX_LAT, Projection.MAX_LON);
    3527    }
    3628
  • trunk/src/org/openstreetmap/josm/data/Preferences.java

    r1688 r1722  
    352352        put("selectionlist.visible", true);
    353353        put("commandstack.visible", true);
    354         put("projection", Mercator.class.getName());
    355354        if (System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") == -1) {
    356355            put("laf", "javax.swing.plaf.metal.MetalLookAndFeel");
  • trunk/src/org/openstreetmap/josm/data/coor/LatLon.java

    r1209 r1722  
    77import org.openstreetmap.josm.data.Bounds;
    88import org.openstreetmap.josm.data.projection.Projection;
     9import org.openstreetmap.josm.Main;
    910
    1011import java.text.DecimalFormat;
     
    8788     */
    8889    public boolean isOutSideWorld() {
    89         return lat() < -Projection.MAX_LAT || lat() > Projection.MAX_LAT ||
    90             lon() < -Projection.MAX_LON || lon() > Projection.MAX_LON;
     90        Bounds b = Main.proj.getWorldBoundsLatLon();
     91        return lat() < b.min.lat() || lat() > b.max.lat() ||
     92            lon() < b.min.lon() || lon() > b.max.lon();
    9193    }
    9294
  • trunk/src/org/openstreetmap/josm/data/gpx/GpxData.java

    r1677 r1722  
    4040    public Collection<WayPoint> waypoints = new LinkedList<WayPoint>();
    4141
    42     public Bounds bounds;
    43 
    4442    public void mergeFrom(GpxData other) {
    4543        if (storageFile == null && other.storageFile != null) {
     
    8280
    8381    // FIXME might perhaps use visitor pattern?
    84     public void recalculateBounds() {
    85         bounds = null;
     82    public Bounds recalculateBounds() {
     83        Bounds bounds = null;
    8684        for (WayPoint wpt : waypoints) {
    8785            if (bounds == null) {
     
    111109            }
    112110        }
    113         if (bounds == null) {
    114             bounds = new Bounds();
    115         }
     111        return bounds;
    116112    }
    117113
  • trunk/src/org/openstreetmap/josm/data/osm/Node.java

    r1690 r1722  
    88import org.openstreetmap.josm.data.coor.LatLon;
    99import org.openstreetmap.josm.data.coor.LatLon.CoordinateFormat;
     10import org.openstreetmap.josm.data.projection.Projection;
    1011import org.openstreetmap.josm.data.osm.visitor.Visitor;
     12import org.openstreetmap.josm.data.osm.Node;
    1113
    1214
     
    1820public final class Node extends OsmPrimitive {
    1921
    20     public LatLon coor;
    21     public volatile EastNorth eastNorth;
     22    private LatLon coor;
     23
     24    private EastNorth eastNorth;
     25    private Projection proj;
     26
    2227
    2328    public final void setCoor(LatLon coor) {
    2429        this.coor = coor;
    25         this.eastNorth = Main.proj.latlon2eastNorth(coor);
     30        proj = null;
    2631    }
    2732
     
    3136
    3237    public final void setEastNorth(EastNorth eastNorth) {
    33         this.eastNorth = eastNorth;
    34         this.coor = Main.proj.eastNorth2latlon(eastNorth);
    35     }
    36 
    37     public final void setEastNorth(double east, double north) {
    38         this.setEastNorth(new EastNorth(east, north));
     38        proj = Main.proj;
     39        eastNorth = eastNorth;
     40        this.coor = proj.eastNorth2latlon(eastNorth);
    3941    }
    4042
    4143    public final EastNorth getEastNorth() {
     44        if(proj != Main.proj)
     45        {
     46            proj = Main.proj;
     47            eastNorth = proj.latlon2eastNorth(coor);
     48        }
    4249        return eastNorth;
    4350    }
     
    4552    private static CoordinateFormat mCord;
    4653
    47     static {
     54    static public CoordinateFormat getCoordinateFormat()
     55    {
     56        return mCord;
     57    }
     58
     59    static public void setCoordinateFormat()
     60    {
    4861        try {
    4962            mCord = LatLon.CoordinateFormat.valueOf(Main.pref.get("coordinates"));
    5063        } catch (IllegalArgumentException iae) {
    51             mCord =LatLon.CoordinateFormat.DECIMAL_DEGREES;
     64            mCord = LatLon.CoordinateFormat.DECIMAL_DEGREES;
    5265        }
     66    }
     67
     68    static {
     69        setCoordinateFormat();
    5370    }
    5471
     
    7289    }
    7390
     91    public Node(EastNorth eastNorth) {
     92        setEastNorth(eastNorth);
     93    }
     94
    7495    @Override public void visit(Visitor visitor) {
    7596        visitor.visit(this);
     
    7899    @Override public void cloneFrom(OsmPrimitive osm) {
    79100        super.cloneFrom(osm);
    80         coor = ((Node)osm).coor;
    81         eastNorth = ((Node)osm).eastNorth;
     101        setCoor(((Node)osm).coor);
    82102    }
    83103
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/BoundingXYVisitor.java

    r1640 r1722  
    44import org.openstreetmap.josm.Main;
    55import org.openstreetmap.josm.data.Bounds;
     6import org.openstreetmap.josm.data.ProjectionBounds;
    67import org.openstreetmap.josm.data.coor.EastNorth;
    78import org.openstreetmap.josm.data.coor.LatLon;
     
    1920public class BoundingXYVisitor extends AbstractVisitor {
    2021
    21     public EastNorth min, max;
     22    private ProjectionBounds bounds = null;
    2223
    2324    public void visit(Node n) {
     
    3839    }
    3940
     41    public void visit(Bounds b) {
     42        if(b != null)
     43        {
     44            visit(Main.proj.latlon2eastNorth(b.min));
     45            visit(Main.proj.latlon2eastNorth(b.max));
     46        }
     47    }
     48
     49    public void visit(ProjectionBounds b) {
     50        if(b != null)
     51            bounds = new ProjectionBounds(b.min, b.max);
     52    }
     53
    4054    public void visit(EastNorth eastNorth) {
    4155        if (eastNorth != null) {
    42             if (min == null)
    43                 min = eastNorth;
    44             else if (eastNorth.east() < min.east() || eastNorth.north() < min.north())
    45                 min = new EastNorth(Math.min(min.east(), eastNorth.east()), Math.min(min.north(), eastNorth.north()));
     56            if (bounds == null)
     57                bounds = new ProjectionBounds(eastNorth, eastNorth);
     58            else
     59                bounds.extend(eastNorth);
     60        }
     61    }
    4662
    47             if (max == null)
    48                 max = eastNorth;
    49             else if (eastNorth.east() > max.east() || eastNorth.north() > max.north())
    50                 max = new EastNorth(Math.max(max.east(), eastNorth.east()), Math.max(max.north(), eastNorth.north()));
    51         }
     63    public boolean hasExtend()
     64    {
     65        return bounds != null && !bounds.min.equals(bounds.max);
    5266    }
    5367
     
    5569     * @return The bounding box or <code>null</code> if no coordinates have passed
    5670     */
    57     public Bounds getBounds() {
    58         if (min == null || max == null)
    59             return null;
    60         return new Bounds(Main.proj.eastNorth2latlon(min), Main.proj.eastNorth2latlon(max));
     71    public ProjectionBounds getBounds() {
     72        return bounds;
    6173    }
    6274
     
    7890     */
    7991    public void enlargeBoundingBox(double enlargeDegree) {
    80         if (min == null || max == null)
     92        if (bounds == null)
    8193            return;
    82         LatLon minLatlon = Main.proj.eastNorth2latlon(min);
    83         min = Main.proj.latlon2eastNorth(new LatLon(minLatlon.lat() - enlargeDegree, minLatlon.lon() - enlargeDegree));
    84         LatLon maxLatlon = Main.proj.eastNorth2latlon(max);
    85         max = Main.proj.latlon2eastNorth(new LatLon(maxLatlon.lat() + enlargeDegree, maxLatlon.lon() + enlargeDegree));
     94        LatLon minLatlon = Main.proj.eastNorth2latlon(bounds.min);
     95        LatLon maxLatlon = Main.proj.eastNorth2latlon(bounds.max);
     96        bounds = new ProjectionBounds(
     97        Main.proj.latlon2eastNorth(new LatLon(minLatlon.lat() - enlargeDegree, minLatlon.lon() - enlargeDegree)),
     98        Main.proj.latlon2eastNorth(new LatLon(maxLatlon.lat() + enlargeDegree, maxLatlon.lon() + enlargeDegree)));
    8699    }
    87100}
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/MapPaintVisitor.java

    r1696 r1722  
    12741274        useRealWidth = Main.pref.getBoolean("mappaint.useRealWidth",false);
    12751275        zoomLevelDisplay = Main.pref.getBoolean("mappaint.zoomLevelDisplay",false);
    1276         circum = Main.map.mapView.getScale()*100*Main.proj.scaleFactor()*40041455; /* circumference of the earth in meter */
     1276        circum = Main.map.mapView.getMapScale();
    12771277        styles = MapPaintStyles.getStyles().getStyleSet();
    12781278        drawMultipolygon = Main.pref.getBoolean("mappaint.multipolygon",true);
  • trunk/src/org/openstreetmap/josm/data/projection/Epsg4326.java

    r1309 r1722  
    11// License: GPL. Copyright 2007 by Immanuel Scholz and others
    22package org.openstreetmap.josm.data.projection;
     3
    34import static org.openstreetmap.josm.tools.I18n.tr;
     5
    46import org.openstreetmap.josm.data.coor.LatLon;
    57import org.openstreetmap.josm.data.coor.EastNorth;
     8import org.openstreetmap.josm.data.Bounds;
     9import org.openstreetmap.josm.data.ProjectionBounds;
    610
    711/**
     
    3236    }
    3337
    34     public double scaleFactor() {
    35         return 1.0/360;
    36     }
    37 
    3838    @Override public boolean equals(Object o) {
    3939        return o instanceof Epsg4326;
    4040    }
    4141
    42     @Override public int hashCode() {
    43         return Epsg4326.class.hashCode();
     42    public ProjectionBounds getWorldBounds()
     43    {
     44        Bounds b = getWorldBoundsLatLon();
     45        return new ProjectionBounds(latlon2eastNorth(b.min), latlon2eastNorth(b.max));
     46    }
     47
     48    public Bounds getWorldBoundsLatLon()
     49    {
     50        return new Bounds(
     51        new LatLon(-90.0, -180.0),
     52        new LatLon(90.0, 180.0));
    4453    }
    4554}
  • trunk/src/org/openstreetmap/josm/data/projection/Lambert.java

    r1583 r1722  
    1212import org.openstreetmap.josm.data.coor.EastNorth;
    1313import org.openstreetmap.josm.data.coor.LatLon;
     14import org.openstreetmap.josm.data.Bounds;
     15import org.openstreetmap.josm.data.ProjectionBounds;
    1416
    1517public class Lambert implements Projection {
     
    104106        } else {
    105107            outOfLambertZones = true; // possible when MAX_LAT is used
    106             if (p.lat() != 0 && Math.abs(p.lat()) != Projection.MAX_LAT
    107                     && p.lon() != 0 && Math.abs(p.lon()) != Projection.MAX_LON
    108                     && dontDisplayErrors == false) {
    109                 JOptionPane.showMessageDialog(Main.parent,
    110                         tr("The projection \"{0}\" is designed for\n"
    111                         + "latitudes between 46.1\u00b0 and 57\u00b0 only.\n"
    112                         + "Use another projection system if you are not using\n"
    113                         + "a French WMS server.\n"
    114                         + "Do not upload any data after this message.", this.toString()));
    115                 dontDisplayErrors = true;
    116             }
    117108        }
    118109        if (!outOfLambertZones) {
     
    167158    }
    168159
    169     public double scaleFactor() {
    170         return 1.0 / 360;
    171     }
    172 
    173160    @Override
    174161    public boolean equals(Object o) {
    175162        return o instanceof Lambert;
    176     }
    177 
    178     @Override
    179     public int hashCode() {
    180         return Lambert.class.hashCode();
    181163    }
    182164
     
    300282    }
    301283
     284    public ProjectionBounds getWorldBounds()
     285    {
     286        Bounds b = getWorldBoundsLatLon();
     287        return new ProjectionBounds(latlon2eastNorth(b.min), latlon2eastNorth(b.max));
     288    }
     289
     290    public Bounds getWorldBoundsLatLon()
     291    {
     292        return new Bounds(
     293        new LatLon(-90.0, -180.0),
     294        new LatLon(90.0, 180.0));
     295    }
    302296}
  • trunk/src/org/openstreetmap/josm/data/projection/LambertEST.java

    r1309 r1722  
    99import org.openstreetmap.josm.data.coor.EastNorth;
    1010import org.openstreetmap.josm.data.coor.LatLon;
     11import org.openstreetmap.josm.data.Bounds;
     12import org.openstreetmap.josm.data.ProjectionBounds;
    1113
    1214public class LambertEST implements Projection {
     
    105107    }
    106108
    107     public double scaleFactor() {
    108         return 1.0 / 360;
    109     }
    110 
    111109    @Override
    112110    public boolean equals(Object o) {
     
    114112    }
    115113
    116     @Override
    117     public int hashCode() {
    118         return LambertEST.class.hashCode();
     114    public ProjectionBounds getWorldBounds()
     115    {
     116        Bounds b = getWorldBoundsLatLon();
     117        return new ProjectionBounds(latlon2eastNorth(b.min), latlon2eastNorth(b.max));
     118    }
     119
     120    public Bounds getWorldBoundsLatLon()
     121    {
     122        return new Bounds(
     123        new LatLon(-90.0, -180.0),
     124        new LatLon(90.0, 180.0));
    119125    }
    120126}
  • trunk/src/org/openstreetmap/josm/data/projection/Mercator.java

    r1644 r1722  
    66import org.openstreetmap.josm.data.coor.EastNorth;
    77import org.openstreetmap.josm.data.coor.LatLon;
     8import org.openstreetmap.josm.data.Bounds;
     9import org.openstreetmap.josm.data.ProjectionBounds;
    810
    911/**
     
    4547    }
    4648
    47     public double scaleFactor() {
    48         return 1/Math.PI/2;
    49     }
    50 
    5149    @Override public boolean equals(Object o) {
    5250        return o instanceof Mercator;
    5351    }
    5452
    55     @Override public int hashCode() {
    56         return Mercator.class.hashCode();
     53    public ProjectionBounds getWorldBounds()
     54    {
     55        Bounds b = getWorldBoundsLatLon();
     56        return new ProjectionBounds(latlon2eastNorth(b.min), latlon2eastNorth(b.max));
     57    }
     58
     59    public Bounds getWorldBoundsLatLon()
     60    {
     61        return new Bounds(
     62        new LatLon(-85.05112877980659, -180.0),
     63        new LatLon(85.05112877980659, 180.0));
    5764    }
    5865}
  • trunk/src/org/openstreetmap/josm/data/projection/Projection.java

    r1582 r1722  
    44import org.openstreetmap.josm.data.coor.EastNorth;
    55import org.openstreetmap.josm.data.coor.LatLon;
     6import org.openstreetmap.josm.data.Bounds;
     7import org.openstreetmap.josm.data.ProjectionBounds;
    68
    79/**
     
    1214 */
    1315public interface Projection {
    14 
    15     /**
    16      * Maximum latitude representable.
    17      */
    18     public static final double MAX_LAT = 85.05112877980659; // Mercator squares the world
    19 
    20     /**
    21      * Maximum longditude representable.
    22      */
    23     public static final double MAX_LON = 180;
    24 
    2516    /**
    2617     * Minimum difference in location to not be represented as the same position.
     
    3627        new Lambert(),
    3728        new LambertEST(),
    38         new SwissGrid()
     29        new SwissGrid(),
     30        new UTM()
    3931    };
    4032
     
    6961
    7062    /**
    71      * The factor to multiply with an easting coordinate to get from "easting
    72      * units per pixel" to "meters per pixel"
     63     * Get the bounds of the world
    7364     */
    74     double scaleFactor();
     65    ProjectionBounds getWorldBounds();
     66    Bounds getWorldBoundsLatLon();
    7567}
  • trunk/src/org/openstreetmap/josm/data/projection/SwissGrid.java

    r1583 r1722  
    55import static org.openstreetmap.josm.tools.I18n.tr;
    66
    7 import javax.swing.JOptionPane;
    8 
    97import org.openstreetmap.josm.Main;
    108import org.openstreetmap.josm.data.coor.EastNorth;
    119import org.openstreetmap.josm.data.coor.LatLon;
     10import org.openstreetmap.josm.data.Bounds;
     11import org.openstreetmap.josm.data.ProjectionBounds;
    1212
    1313/**
     
    1919 */
    2020public class SwissGrid implements Projection {
    21     private boolean doAlertOnCoordinatesOufOfRange = true;
    22 
    23     /**
    24      * replies true if if wgs is in or reasonably close to Switzerland. False otherwise.
    25      *
    26      * @param wgs  lat/lon in WGS89
    27      * @return
    28      */
    29     protected boolean latlonInAcceptableRange(LatLon wgs) {
    30         // coordinate transformation is invoked for boundary values regardless
    31         // of current data set.
    32         //
    33         if (Math.abs(wgs.lon()) == Projection.MAX_LON && Math.abs(wgs.lat()) == Projection.MAX_LAT) {
    34             return true;
    35         }
    36         return   wgs.lon() >= 5.7 && wgs.lon() <= 10.6
    37                && wgs.lat() >= 45.7 && wgs.lat() <= 47.9;
    38     }
    39 
    40     /**
    41      * displays an alert if lat/lon are not reasonably close to Switzerland.
    42      */
    43     protected void alertCoordinatesOutOfRange() {
    44         JOptionPane.showMessageDialog(Main.parent,
    45                 tr("The projection \"{0}\" is designed for\n"
    46                 + "latitudes between 45.7\u00b0 and 47.9\u00b0\n"
    47                 + "and longitutes between 5.7\u00b0 and 10.6\u00b0 only.\n"
    48                 + "Use another projection system if you are not working\n"
    49                 + "on a data set of Switzerland or Liechtenstein.\n"
    50                 + "Do not upload any data after this message.", this.toString()),
    51                 "Current projection not suitable",
    52                 JOptionPane.WARNING_MESSAGE
    53         );
    54         doAlertOnCoordinatesOufOfRange = false;
    55     }
    56 
    5721    /**
    5822     * @param wgs  WGS84 lat/lon (ellipsoid GRS80) (in degree)
     
    6024     */
    6125    public EastNorth latlon2eastNorth(LatLon wgs) {
    62             if (!latlonInAcceptableRange(wgs)) {
    63                 if (doAlertOnCoordinatesOufOfRange) {
    64                     alertCoordinatesOutOfRange();
    65                 }
    66             }
    67 
    6826            double phi = 3600d * wgs.lat();
    6927            double lambda = 3600d * wgs.lon();
     
    13189    }
    13290
    133     public double scaleFactor() {
    134         return 1.0;
    135     }
    136 
    13791    @Override public String toString() {
    13892        return tr("Swiss Grid (Switzerland)");
     
    152106    }
    153107
    154     @Override
    155     public int hashCode() {
    156         return SwissGrid.class.hashCode();
     108    public ProjectionBounds getWorldBounds()
     109    {
     110        Bounds b = getWorldBoundsLatLon();
     111        return new ProjectionBounds(latlon2eastNorth(b.min), latlon2eastNorth(b.max));
     112    }
     113
     114    public Bounds getWorldBoundsLatLon()
     115    {
     116        return new Bounds(
     117        new LatLon(45.7, 5.7),
     118        new LatLon(47.9, 10.6));
    157119    }
    158120}
Note: See TracChangeset for help on using the changeset viewer.