Changeset 4126 in josm for trunk/src


Ignore:
Timestamp:
2011-06-07T19:05:14+02:00 (13 years ago)
Author:
bastiK
Message:

memory optimizations for Node & WayPoint (Patch by Gubaer, modified)

The field 'proj' in CachedLatLon is a waste of memory. For the 2 classes where this has the greatest impact, the cache for the projected coordinates is replaced by 2 simple double fields (east & north). On projection change, they have to be invalidated explicitly. This is handled by the DataSet & the GpxLayer.

Location:
trunk/src/org/openstreetmap/josm
Files:
1 added
33 edited

Legend:

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

    r3993 r4126  
    1616import java.awt.event.WindowEvent;
    1717import java.io.File;
     18import java.lang.ref.WeakReference;
    1819import java.net.URI;
    1920import java.net.URISyntaxException;
    2021import java.util.ArrayList;
    2122import java.util.Collection;
     23import java.util.Iterator;
    2224import java.util.List;
    2325import java.util.Map;
     
    5658import org.openstreetmap.josm.data.osm.PrimitiveDeepCopy;
    5759import org.openstreetmap.josm.data.projection.Projection;
     60import org.openstreetmap.josm.data.projection.ProjectionChangeListener;
    5861import org.openstreetmap.josm.data.validation.OsmValidator;
    5962import org.openstreetmap.josm.gui.GettingStarted;
     
    7376import org.openstreetmap.josm.io.OsmApi;
    7477import org.openstreetmap.josm.plugins.PluginHandler;
     78import org.openstreetmap.josm.tools.CheckParameterUtil;
    7579import org.openstreetmap.josm.tools.I18n;
    7680import org.openstreetmap.josm.tools.ImageProvider;
     
    119123    public static PrimitiveDeepCopy pasteBuffer = new PrimitiveDeepCopy();
    120124    public static Layer pasteSource;
    121     /**
    122      * The projection method used.
    123      */
    124     public static Projection proj;
     125
    125126    /**
    126127     * The MapFrame. Use setMapFrame to set or clear it.
     
    154155     */
    155156    static public int debug_level = 1;
    156     static public final void debug(String msg) {
     157    static public void debug(String msg) {
    157158        if (debug_level <= 0)
    158159            return;
     
    213214        platform.startupHook();
    214215
    215         // We try to establish an API connection early, so that any API 
     216        // We try to establish an API connection early, so that any API
    216217        // capabilities are already known to the editor instance. However
    217218        // if it goes wrong that's not critical at this stage.
     
    768769        System.err.println("Error: Could not recognize Java Version: "+version);
    769770    }
     771
     772    /* ----------------------------------------------------------------------------------------- */
     773    /* projection handling  - Main is a registry for a single, global projection instance        */
     774    /*                                                                                           */
     775    /* TODO: For historical reasons the registry is implemented by Main. An alternative approach */
     776    /* would be a singleton org.openstreetmap.josm.data.projection.ProjectionRegistry class.     */
     777    /* ----------------------------------------------------------------------------------------- */
     778    /**
     779     * The projection method used.
     780     * @deprecated use {@link #getProjection()} and {@link #setProjection(Projection)} instead.
     781     * For the time being still publicly available, but avoid/migrate write access to it. Use
     782     * {@link #setProjection(Projection)} in order to trigger a projection change event.
     783     */
     784    @Deprecated
     785    public static Projection proj;
     786
     787    /**
     788     * Replies the current projection.
     789     *
     790     * @return
     791     */
     792    public static Projection getProjection() {
     793        return proj;
     794    }
     795
     796    /**
     797     * Sets the current projection
     798     *
     799     * @param p the projection
     800     */
     801    public static void setProjection(Projection p) {
     802        CheckParameterUtil.ensureParameterNotNull(p);
     803        Projection oldValue = proj;
     804        proj = p;
     805        fireProjectionChanged(oldValue, proj);
     806    }
     807
     808    /*
     809     * Keep WeakReferences to the listeners. This relieves clients from the burden of
     810     * explicitly removing the listeners and allows us to transparently register every
     811     * created dataset as projection change listener.
     812     */
     813    private static final ArrayList<WeakReference<ProjectionChangeListener>> listeners = new ArrayList<WeakReference<ProjectionChangeListener>>();
     814
     815    private static void fireProjectionChanged(Projection oldValue, Projection newValue) {
     816        if (newValue == null ^ oldValue == null
     817                || (newValue != null && oldValue != null && !newValue.getClass().getName().equals(oldValue.getClass().getName()))) {
     818
     819            synchronized(Main.class) {
     820                Iterator<WeakReference<ProjectionChangeListener>> it = listeners.iterator();
     821                while(it.hasNext()){
     822                    WeakReference<ProjectionChangeListener> wr = it.next();
     823                    if (wr.get() == null) {
     824                        it.remove();
     825                        continue;
     826                    }
     827                    wr.get().projectionChanged(oldValue, newValue);
     828                }
     829            }
     830            if (newValue != null) {
     831                Bounds b = (Main.map != null && Main.map.mapView != null) ? Main.map.mapView.getRealBounds() : null;
     832                if (b != null){
     833                    Main.map.mapView.zoomTo(b);
     834                }
     835            }
     836            /* TODO - remove layers with fixed projection */
     837        }
     838    }
     839
     840    /**
     841     * Register a projection change listener
     842     *
     843     * @param listener the listener. Ignored if null.
     844     */
     845    public static void addProjectionChangeListener(ProjectionChangeListener listener) {
     846        if (listener == null) return;
     847        synchronized (Main.class) {
     848            for (WeakReference<ProjectionChangeListener> wr : listeners) {
     849                // already registered ? => abort
     850                if (wr.get() == listener) return;
     851            }
     852        }
     853        listeners.add(new WeakReference<ProjectionChangeListener>(listener));
     854    }
     855
     856    /**
     857     * Removes a projection change listener
     858     *
     859     * @param listener the listener. Ignored if null.
     860     */
     861    public static void removeProjectionChangeListener(ProjectionChangeListener listener) {
     862        if (listener == null) return;
     863        synchronized(Main.class){
     864            Iterator<WeakReference<ProjectionChangeListener>> it = listeners.iterator();
     865            while(it.hasNext()){
     866                WeakReference<ProjectionChangeListener> wr = it.next();
     867                // remove the listener - and any other listener which god garbage
     868                // collected in the meantime
     869                if (wr.get() == null || wr.get() == listener) {
     870                    it.remove();
     871                }
     872            }
     873        }
     874    }
    770875}
  • trunk/src/org/openstreetmap/josm/actions/CreateCircleAction.java

    r3083 r4126  
    153153                    double x = xc + r*Math.cos(a);
    154154                    double y = yc + r*Math.sin(a);
    155                     Node n = new Node(Main.proj.eastNorth2latlon(new EastNorth(x,y)));
     155                    Node n = new Node(Main.getProjection().eastNorth2latlon(new EastNorth(x,y)));
    156156                    wayToAdd.add(n);
    157157                    cmds.add(new AddCommand(n));
     
    245245                double x = xc + r*Math.cos(a);
    246246                double y = yc + r*Math.sin(a);
    247                 Node n = new Node(Main.proj.eastNorth2latlon(new EastNorth(x,y)));
     247                Node n = new Node(Main.getProjection().eastNorth2latlon(new EastNorth(x,y)));
    248248                wayToAdd.add(n);
    249249                cmds.add(new AddCommand(n));
  • trunk/src/org/openstreetmap/josm/actions/ImageryAdjustAction.java

    r4001 r4126  
    162162            pnl.add(new JMultilineLabel(tr("Use arrow keys or drag the imagery layer with mouse to adjust the imagery offset.\n" +
    163163                    "You can also enter east and north offset in the {0} coordinates.\n" +
    164                     "If you want to save the offset as bookmark, enter the bookmark name below",Main.proj.toString())), GBC.eop());
     164                    "If you want to save the offset as bookmark, enter the bookmark name below",Main.getProjection().toString())), GBC.eop());
    165165            pnl.add(new JLabel(tr("Offset: ")),GBC.std());
    166166            pnl.add(tOffset,GBC.eol().fill(GBC.HORIZONTAL).insets(0,0,0,5));
     
    211211        public void updateOffsetIntl() {
    212212            // Support projections with very small numbers (e.g. 4326)
    213             int precision = Main.proj.getDefaultZoomInPPD() >= 1.0 ? 2 : 7;
     213            int precision = Main.getProjection().getDefaultZoomInPPD() >= 1.0 ? 2 : 7;
    214214            // US locale to force decimal separator to be '.'
    215215            tOffset.setText(new java.util.Formatter(java.util.Locale.US).format(
  • trunk/src/org/openstreetmap/josm/actions/OrthogonalizeAction.java

    r3757 r4126  
    117117        if (!isEnabled())
    118118            return;
    119         if ("EPSG:4326".equals(Main.proj.toString())) {
     119        if ("EPSG:4326".equals(Main.getProjection().toString())) {
    120120            String msg = tr("<html>You are using the EPSG:4326 projection which might lead<br>" +
    121121                    "to undesirable results when doing rectangular alignments.<br>" +
  • trunk/src/org/openstreetmap/josm/actions/mapmode/ExtrudeAction.java

    r3939 r4126  
    255255
    256256            // find out the movement distance, in metres
    257             double distance = Main.proj.eastNorth2latlon(initialN1en).greatCircleDistance(Main.proj.eastNorth2latlon(newN1en));
     257            double distance = Main.getProjection().eastNorth2latlon(initialN1en).greatCircleDistance(Main.getProjection().eastNorth2latlon(newN1en));
    258258            Main.map.statusLine.setDist(distance);
    259259            updateStatusLine();
     
    309309                        //move existing node
    310310                        Node n1Old = selectedSegment.getFirstNode();
    311                         cmds.add(new MoveCommand(n1Old, Main.proj.eastNorth2latlon(newN1en)));
     311                        cmds.add(new MoveCommand(n1Old, Main.getProjection().eastNorth2latlon(newN1en)));
    312312                    } else {
    313313                        //introduce new node
    314                         Node n1New = new Node(Main.proj.eastNorth2latlon(newN1en));
     314                        Node n1New = new Node(Main.getProjection().eastNorth2latlon(newN1en));
    315315                        wnew.addNode(insertionPoint, n1New);
    316316                        insertionPoint ++;
     
    326326                        //move existing node
    327327                        Node n2Old = selectedSegment.getSecondNode();
    328                         cmds.add(new MoveCommand(n2Old, Main.proj.eastNorth2latlon(newN2en)));
     328                        cmds.add(new MoveCommand(n2Old, Main.getProjection().eastNorth2latlon(newN2en)));
    329329                    } else {
    330330                        //introduce new node
    331                         Node n2New = new Node(Main.proj.eastNorth2latlon(newN2en));
     331                        Node n2New = new Node(Main.getProjection().eastNorth2latlon(newN2en));
    332332                        wnew.addNode(insertionPoint, n2New);
    333333                        insertionPoint ++;
  • trunk/src/org/openstreetmap/josm/command/MoveCommand.java

    r3682 r4126  
    1212import javax.swing.JLabel;
    1313
    14 import org.openstreetmap.josm.data.coor.CachedLatLon;
    1514import org.openstreetmap.josm.data.coor.EastNorth;
    1615import org.openstreetmap.josm.data.coor.LatLon;
     
    1817import org.openstreetmap.josm.data.osm.OsmPrimitive;
    1918import org.openstreetmap.josm.data.osm.visitor.AllNodesVisitor;
     19import org.openstreetmap.josm.data.projection.Projections;
    2020import org.openstreetmap.josm.tools.ImageProvider;
    2121
     
    5959
    6060    public MoveCommand(Node node, LatLon position) {
    61         this(Collections.singleton((OsmPrimitive) node), node.getEastNorth().sub(new CachedLatLon(position).getEastNorth()));
     61        this(Collections.singleton((OsmPrimitive) node), node.getEastNorth().sub(Projections.project(position)));
    6262    }
    6363
  • trunk/src/org/openstreetmap/josm/data/coor/CachedLatLon.java

    r3253 r4126  
    55import org.openstreetmap.josm.data.projection.Projection;
    66
     7/**
     8 * LatLon class that maintains a cache of projected EastNorth coordinates.
     9 *
     10 * This class is convenient to use, but has relatively high memory costs.
     11 * It keeps a pointer to the last known projection in order to detect projection
     12 * changes.
     13 *
     14 * Node and WayPoint have another, optimized, cache for projected coordinates.
     15 */
    716public class CachedLatLon extends LatLon {
    817    private EastNorth eastNorth;
     
    1928
    2029    public CachedLatLon(EastNorth eastNorth) {
    21         super(Main.proj.eastNorth2latlon(eastNorth));
    22         proj = Main.proj;
     30        super(Main.getProjection().eastNorth2latlon(eastNorth));
     31        proj = Main.getProjection();
    2332        this.eastNorth = eastNorth;
    2433    }
     
    3039
    3140    public final void setEastNorth(EastNorth eastNorth) {
    32         proj = Main.proj;
     41        proj = Main.getProjection();
    3342        this.eastNorth = eastNorth;
    3443        LatLon l = proj.eastNorth2latlon(eastNorth);
     
    3645    }
    3746
     47    /**
     48     * Replies the projected east/north coordinates.
     49     *
     50     * @return the internally cached east/north coordinates. null, if the globally defined projection is null
     51     */
    3852    public final EastNorth getEastNorth() {
    39         if(proj != Main.proj)
     53        if(proj != Main.getProjection())
    4054        {
    41             proj = Main.proj;
     55            proj = Main.getProjection();
    4256            eastNorth = proj.latlon2eastNorth(this);
    4357        }
  • trunk/src/org/openstreetmap/josm/data/coor/LatLon.java

    r3656 r4126  
    106106        case DEGREES_MINUTES_SECONDS: return dms(y) + ((y < 0) ? SOUTH : NORTH);
    107107        case NAUTICAL: return dm(y) + ((y < 0) ? SOUTH : NORTH);
    108         case EAST_NORTH: return cDdFormatter.format(Main.proj.latlon2eastNorth(this).north());
     108        case EAST_NORTH: return cDdFormatter.format(Main.getProjection().latlon2eastNorth(this).north());
    109109        default: return "ERR";
    110110        }
     
    122122        case DEGREES_MINUTES_SECONDS: return dms(x) + ((x < 0) ? WEST : EAST);
    123123        case NAUTICAL: return dm(x) + ((x < 0) ? WEST : EAST);
    124         case EAST_NORTH: return cDdFormatter.format(Main.proj.latlon2eastNorth(this).east());
     124        case EAST_NORTH: return cDdFormatter.format(Main.getProjection().latlon2eastNorth(this).east());
    125125        default: return "ERR";
    126126        }
     
    142142     */
    143143    public boolean isOutSideWorld() {
    144         Bounds b = Main.proj.getWorldBoundsLatLon();
     144        Bounds b = Main.getProjection().getWorldBoundsLatLon();
    145145        return lat() < b.getMin().lat() || lat() > b.getMax().lat() ||
    146146        lon() < b.getMin().lon() || lon() > b.getMax().lon();
  • trunk/src/org/openstreetmap/josm/data/gpx/WayPoint.java

    r3321 r4126  
    77import java.util.Date;
    88
    9 import org.openstreetmap.josm.data.coor.CachedLatLon;
     9import org.openstreetmap.josm.Main;
    1010import org.openstreetmap.josm.data.coor.EastNorth;
    1111import org.openstreetmap.josm.data.coor.LatLon;
     12import org.openstreetmap.josm.data.projection.Projections;
    1213import org.openstreetmap.josm.tools.PrimaryDateParser;
    1314
     
    2627
    2728    public WayPoint(LatLon ll) {
    28         coor = new CachedLatLon(ll);
     29        lat = ll.lat();
     30        lon = ll.lon();
    2931    }
    3032
    31     private final CachedLatLon coor;
     33    /*
     34     * We "inline" lat/lon, rather than usinga LatLon internally => reduces memory overhead. Relevant
     35     * because a lot of GPX waypoints are created when GPS tracks are downloaded from the OSM server.
     36     */
     37    private double lat = 0;
     38    private double lon = 0;
     39
     40    /*
     41     * internal cache of projected coordinates
     42     */
     43    private double east = Double.NaN;
     44    private double north = Double.NaN;
     45
     46    /**
     47     * Invalidate the internal cache of east/north coordinates.
     48     */
     49    public void invalidateEastNorthCache() {
     50        this.east = Double.NaN;
     51        this.north = Double.NaN;
     52    }
    3253
    3354    public final LatLon getCoor() {
    34         return coor;
     55        return new LatLon(lat,lon);
    3556    }
    3657
     58    /**
     59     * <p>Replies the projected east/north coordinates.</p>
     60     *
     61     * <p>Uses the {@link Main#getProjection() global projection} to project the lan/lon-coordinates.
     62     * Internally caches the projected coordinates.</p>
     63     *
     64     * <p><strong>Caveat:</strong> doesn't listen to projection changes. Clients must
     65     * {@link #reproject() trigger a reprojection} or {@link #invalidateEastNorthCache() invalidate the internal cache}.</p>
     66     *
     67     * @return the east north coordinates or {@code null}
     68     * @see #invalidateEastNorthCache()
     69     *
     70     */
    3771    public final EastNorth getEastNorth() {
    38         return coor.getEastNorth();
     72        if (Double.isNaN(east) || Double.isNaN(north)) {
     73            // projected coordinates haven't been calculated yet,
     74            // so fill the cache of the projected waypoint coordinates
     75            EastNorth en = Projections.project(new LatLon(lat, lon));
     76            this.east = en.east();
     77            this.north = en.north();
     78        }
     79        return new EastNorth(east, north);
    3980    }
    4081
    4182    @Override
    4283    public String toString() {
    43         return "WayPoint (" + (attr.containsKey("name") ? attr.get("name") + ", " :"") + coor.toString() + ", " + attr + ")";
     84        return "WayPoint (" + (attr.containsKey("name") ? attr.get("name") + ", " :"") + getCoor().toString() + ", " + attr + ")";
    4485    }
    4586
     
    5798    }
    5899
    59     public int compareTo(WayPoint w)
    60     {
     100    public int compareTo(WayPoint w) {
    61101        return Double.compare(time, w.time);
    62102    }
  • trunk/src/org/openstreetmap/josm/data/imagery/OffsetBookmark.java

    r3966 r4126  
    3030    public boolean isUsable(ImageryLayer layer) {
    3131        if (proj == null) return false;
    32         if (!Main.proj.toCode().equals(proj.toCode())) return false;
     32        if (!Main.getProjection().toCode().equals(proj.toCode())) return false;
    3333        return layer.getInfo().getName().equals(layerName);
    3434    }
     
    122122        LatLon center;
    123123        if (Main.map != null && Main.map.mapView != null) {
    124             center = Main.proj.eastNorth2latlon(Main.map.mapView.getCenter());
     124            center = Main.getProjection().eastNorth2latlon(Main.map.mapView.getCenter());
    125125        } else {
    126126            center = new LatLon(0,0);
    127127        }
    128128        OffsetBookmark nb = new OffsetBookmark(
    129                 Main.proj, layer.getInfo().getName(),
     129                Main.getProjection(), layer.getInfo().getName(),
    130130                name, layer.getDx(), layer.getDy(), center.lon(), center.lat());
    131131        for (ListIterator<OffsetBookmark> it = allBookmarks.listIterator();it.hasNext();) {
  • trunk/src/org/openstreetmap/josm/data/osm/DataSet.java

    r4087 r4126  
    2020import java.util.concurrent.locks.ReentrantReadWriteLock;
    2121
     22import org.openstreetmap.josm.Main;
    2223import org.openstreetmap.josm.data.Bounds;
    2324import org.openstreetmap.josm.data.SelectionChangedListener;
     
    3435import org.openstreetmap.josm.data.osm.event.TagsChangedEvent;
    3536import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent;
     37import org.openstreetmap.josm.data.projection.Projection;
     38import org.openstreetmap.josm.data.projection.ProjectionChangeListener;
    3639import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionManager;
    3740import org.openstreetmap.josm.tools.FilteredCollection;
    3841import org.openstreetmap.josm.tools.Predicate;
    3942import org.openstreetmap.josm.tools.SubclassFilteredCollection;
     43import org.openstreetmap.josm.tools.Utils;
    4044
    4145/**
     
    8387 * @author imi
    8488 */
    85 public class DataSet implements Cloneable {
     89public class DataSet implements Cloneable, ProjectionChangeListener {
    8690
    8791    /**
     
    120124    private final ReadWriteLock lock = new ReentrantReadWriteLock();
    121125    private final Object selectionLock = new Object();
     126
     127    public DataSet() {
     128        /*
     129         * Transparently register as projection change lister. No need to explicitly remove the
     130         * the listener, projection change listeners are managed as WeakReferences.
     131         */
     132        Main.addProjectionChangeListener(this);
     133    }
    122134
    123135    public Lock getReadLock() {
     
    975987    }
    976988
     989    /**
     990     * Invalidates the internal cache of projected east/north coordinates.
     991     *
     992     * This method can be invoked after the globally configured projection method
     993     * changed. In contrast to {@link DataSet#reproject()} it only invalidates the
     994     * cache and doesn't reproject the coordinates.
     995     */
     996    public void invalidateEastNorthCache() {
     997        if (Main.getProjection() == null) return; // sanity check
     998        try {
     999            beginUpdate();
     1000            for (Node n: Utils.filteredCollection(allPrimitives, Node.class)) {
     1001                n.invalidateEastNorthCache();
     1002            }
     1003        } finally {
     1004            endUpdate();
     1005        }
     1006    }
     1007
    9771008    public void cleanupDeletedPrimitives() {
    9781009        beginUpdate();
     
    10641095        return ret;
    10651096    }
     1097
     1098    /* --------------------------------------------------------------------------------- */
     1099    /* interface ProjectionChangeListner                                                 */
     1100    /* --------------------------------------------------------------------------------- */
     1101    @Override
     1102    public void projectionChanged(Projection oldValue, Projection newValue) {
     1103        invalidateEastNorthCache();
     1104    }
    10661105}
  • trunk/src/org/openstreetmap/josm/data/osm/INode.java

    r4098 r4126  
    66
    77public interface INode extends IPrimitive {
    8    
     8
    99    LatLon getCoor();
    1010    void setCoor(LatLon coor);
    1111    EastNorth getEastNorth();
    1212    void setEastNorth(EastNorth eastNorth);
    13 
    1413}
  • trunk/src/org/openstreetmap/josm/data/osm/Node.java

    r4100 r4126  
    22package org.openstreetmap.josm.data.osm;
    33
    4 import org.openstreetmap.josm.data.coor.CachedLatLon;
     4import org.openstreetmap.josm.Main;
    55import org.openstreetmap.josm.data.coor.EastNorth;
    66import org.openstreetmap.josm.data.coor.LatLon;
    77import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor;
    88import org.openstreetmap.josm.data.osm.visitor.Visitor;
     9import org.openstreetmap.josm.data.projection.Projections;
    910
    1011/**
     
    1516public final class Node extends OsmPrimitive implements INode {
    1617
    17     private CachedLatLon coor;
     18    /*
     19     * We "inline" lat/lon rather than using a LatLon-object => reduces memory footprint
     20     */
     21    static private final double COORDINATE_NOT_DEFINED = Double.NaN;
     22    private double lat = COORDINATE_NOT_DEFINED;
     23    private double lon = COORDINATE_NOT_DEFINED;
     24
     25    /*
     26     * the cached projected coordinates
     27     */
     28    private double east = Double.NaN;
     29    private double north = Double.NaN;
     30
     31    private boolean isLatLonKnown() {
     32        return lat != COORDINATE_NOT_DEFINED && lon != COORDINATE_NOT_DEFINED;
     33    }
    1834
    1935    @Override
     
    4662    @Override
    4763    public final LatLon getCoor() {
    48         return coor;
    49     }
    50 
     64        if (!isLatLonKnown()) return null;
     65        return new LatLon(lat,lon);
     66    }
     67
     68    /**
     69     * <p>Replies the projected east/north coordinates.</p>
     70     *
     71     * <p>Uses the {@link Main#getProjection() global projection} to project the lan/lon-coordinates.
     72     * Internally caches the projected coordinates.</p>
     73     *
     74     * <p><strong>Caveat:</strong> doesn't listen to projection changes. Clients must
     75     * {@link #invalidateEastNorthCache() invalidate the internal cache}.</p>
     76     *
     77     * <p>Replies {@code null} if this node doesn't know lat/lon-coordinates, i.e. because it is an incomplete node.
     78     *
     79     * @return the east north coordinates or {@code null}
     80     * @see #invalidateEastNorthCache()
     81     *
     82     */
    5183    @Override
    5284    public final EastNorth getEastNorth() {
    53         return coor != null ? coor.getEastNorth() : null;
     85        if (!isLatLonKnown()) return null;
     86       
     87        if (getDataSet() == null)
     88            // there is no dataset that listens for projection changes
     89            // and invalidates the cache, so we don't use the cache at all
     90            return Projections.project(new LatLon(lat, lon));
     91       
     92        if (Double.isNaN(east) || Double.isNaN(north)) {
     93            // projected coordinates haven't been calculated yet,
     94            // so fill the cache of the projected node coordinates
     95            EastNorth en = Projections.project(new LatLon(lat, lon));
     96            this.east = en.east();
     97            this.north = en.north();
     98        }
     99        return new EastNorth(east, north);
    54100    }
    55101
     
    58104     */
    59105    protected void setCoorInternal(LatLon coor, EastNorth eastNorth) {
    60         if(this.coor == null) {
    61             if (eastNorth == null) {
    62                 this.coor = new CachedLatLon(coor);
    63             } else {
    64                 this.coor = new CachedLatLon(eastNorth);
    65             }
    66         } else {
    67             if (eastNorth == null) {
    68                 this.coor.setCoor(coor);
    69             } else {
    70                 this.coor.setEastNorth(eastNorth);
    71             }
    72         }
     106        if (coor != null) {
     107            this.lat = coor.lat();
     108            this.lon = coor.lon();
     109            invalidateEastNorthCache();
     110        } else if (eastNorth != null) {
     111            LatLon ll = Projections.inverseProject(eastNorth);
     112            this.lat = ll.lat();
     113            this.lon = ll.lon();
     114            this.east = eastNorth.east();
     115            this.north = eastNorth.north();
     116        } else
     117            throw new IllegalArgumentException();
    73118    }
    74119
     
    150195        try {
    151196            super.cloneFrom(osm);
    152             setCoor(((Node)osm).coor);
     197            setCoor(((Node)osm).getCoor());
    153198        } finally {
    154199            writeUnlock(locked);
     
    173218            super.mergeFrom(other);
    174219            if (!other.isIncomplete()) {
    175                 setCoor(new LatLon(((Node)other).coor));
     220                setCoor(((Node)other).getCoor());
    176221            }
    177222        } finally {
     
    200245
    201246    @Override public String toString() {
    202         String coorDesc = coor == null?"":"lat="+coor.lat()+",lon="+coor.lon();
     247        String coorDesc = isLatLonKnown() ? "lat="+lat+",lon="+lon : "";
    203248        return "{Node id=" + getUniqueId() + " version=" + getVersion() + " " + getFlagsAsString() + " "  + coorDesc+"}";
    204249    }
     
    211256            return false;
    212257        Node n = (Node)other;
    213         if (coor == null && n.coor == null)
     258        LatLon coor = getCoor();
     259        LatLon otherCoor = n.getCoor();
     260        if (coor == null && otherCoor == null)
    214261            return true;
    215         else if (coor != null && n.coor != null)
    216             return coor.equalsEpsilon(n.coor);
     262        else if (coor != null && otherCoor != null)
     263            return coor.equalsEpsilon(otherCoor);
    217264        else
    218265            return false;
     
    241288    @Override
    242289    public void updatePosition() {
    243         // TODO: replace CachedLatLon with simple doubles and update precalculated EastNorth value here
    244290    }
    245291
     
    253299        builder.append(toString());
    254300        builder.append("\n");
    255         if (coor == null) {
     301        if (isLatLonKnown()) {
    256302            builder.append("Coor is null\n");
    257303        } else {
    258             builder.append(String.format("EastNorth: %s\n", coor.getEastNorth()));
    259             builder.append(coor.getProjection());
     304            builder.append(String.format("EastNorth: %s\n", getEastNorth()));
     305            builder.append(Main.getProjection());
    260306            builder.append("\n");
    261307        }
     
    263309        return builder.toString();
    264310    }
     311
     312    /**
     313     * Invoke to invalidate the internal cache of projected east/north coordinates.
     314     * Coordinates are reprojected on demand when the {@link #getEastNorth()} is invoked
     315     * next time.
     316     */
     317    public void invalidateEastNorthCache() {
     318        this.east = Double.NaN;
     319        this.north = Double.NaN;
     320    }
    265321}
  • trunk/src/org/openstreetmap/josm/data/osm/NodeData.java

    r4100 r4126  
    22package org.openstreetmap.josm.data.osm;
    33
    4 import org.openstreetmap.josm.data.coor.CachedLatLon;
    54import org.openstreetmap.josm.data.coor.EastNorth;
    65import org.openstreetmap.josm.data.coor.LatLon;
    76import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor;
     7import org.openstreetmap.josm.data.projection.Projections;
    88
    99public class NodeData extends PrimitiveData implements INode {
    1010
    11     private final CachedLatLon coor = new CachedLatLon(0, 0);
     11    /*
     12     * we "inline" lat/lon coordinates instead of using a LatLon => reduces memory footprint
     13     */
     14    private double lat = Double.NaN;
     15    private double lon = Double.NaN;
    1216
    13     public NodeData() {
    14 
    15     }
     17    public NodeData() {}
    1618
    1719    public NodeData(NodeData data) {
     
    2022    }
    2123
     24    private boolean isLatLonKnown() {
     25        return lat != Double.NaN && lon != Double.NaN;
     26    }
     27   
    2228    @Override
    2329    public LatLon getCoor() {
    24         return coor;
     30        return isLatLonKnown() ? new LatLon(lat,lon) : null;
    2531    }
    2632
    2733    @Override
    2834    public void setCoor(LatLon coor) {
    29         this.coor.setCoor(coor);
     35        if (coor == null) {
     36            this.lat = Double.NaN;
     37            this.lon = Double.NaN;
     38        } else {
     39            this.lat = coor.lat();
     40            this.lon = coor.lon();
     41        }
    3042    }
    3143
    3244    @Override
    3345    public EastNorth getEastNorth() {
    34         return this.coor.getEastNorth();
     46        /*
     47         * No internal caching of projected coordinates needed. In contrast to getEastNorth()
     48         * on Node, this method is rarely used. Caching would be overkill.
     49         */
     50        return Projections.project(getCoor());
    3551    }
    3652
    3753    @Override
    3854    public void setEastNorth(EastNorth eastNorth) {
    39         this.coor.setEastNorth(eastNorth);
     55        LatLon ll = Projections.inverseProject(eastNorth);
     56        setCoor(ll);
    4057    }
    4158
     
    4764    @Override
    4865    public String toString() {
    49         return super.toString() + " NODE " + coor;
     66        return super.toString() + " NODE " + getCoor();
    5067    }
    5168
     
    5471        return OsmPrimitiveType.NODE;
    5572    }
    56    
    57     @Override 
     73
     74    @Override
    5875    public void visit(PrimitiveVisitor visitor) {
    5976        visitor.visit(this);
     
    6481        return formatter.format(this);
    6582    }
    66 
    6783}
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/BoundingXYVisitor.java

    r4065 r4126  
    113113        if (bounds == null)
    114114            return;
    115         LatLon minLatlon = Main.proj.eastNorth2latlon(bounds.getMin());
    116         LatLon maxLatlon = Main.proj.eastNorth2latlon(bounds.getMax());
     115        LatLon minLatlon = Main.getProjection().eastNorth2latlon(bounds.getMin());
     116        LatLon maxLatlon = Main.getProjection().eastNorth2latlon(bounds.getMax());
    117117        bounds = new ProjectionBounds(
    118                 Main.proj.latlon2eastNorth(new LatLon(minLatlon.lat() - enlargeDegree, minLatlon.lon() - enlargeDegree)),
    119                 Main.proj.latlon2eastNorth(new LatLon(maxLatlon.lat() + enlargeDegree, maxLatlon.lon() + enlargeDegree)));
     118                Main.getProjection().latlon2eastNorth(new LatLon(minLatlon.lat() - enlargeDegree, minLatlon.lon() - enlargeDegree)),
     119                Main.getProjection().latlon2eastNorth(new LatLon(maxLatlon.lat() + enlargeDegree, maxLatlon.lon() + enlargeDegree)));
    120120    }
    121121
  • trunk/src/org/openstreetmap/josm/data/projection/Projections.java

    r3874 r4126  
    22package org.openstreetmap.josm.data.projection;
    33
     4import java.util.ArrayList;
    45import java.util.Arrays;
    5 import java.util.ArrayList;
     6
     7import org.openstreetmap.josm.Main;
     8import org.openstreetmap.josm.data.coor.EastNorth;
     9import org.openstreetmap.josm.data.coor.LatLon;
    610
    711/**
     
    1418     */
    1519    private static ArrayList<Projection> allProjections =
    16     new ArrayList<Projection>(Arrays.asList(new Projection[] {
    17         // global projections
    18         new Epsg4326(),
    19         new Mercator(),
    20         new UTM(),
    21         // regional - alphabetical order by country name
    22         new LambertEST(), // Still needs proper default zoom
    23         new Lambert(),    // Still needs proper default zoom
    24         new LambertCC9Zones(),    // Still needs proper default zoom
    25         new UTM_France_DOM(),
    26         new TransverseMercatorLV(),
    27         new Puwg(),
    28         new Epsg3008(), // SWEREF99 13 30
    29         new SwissGrid(),
    30     }));
     20        new ArrayList<Projection>(Arrays.asList(new Projection[] {
     21                // global projections
     22                new Epsg4326(),
     23                new Mercator(),
     24                new UTM(),
     25                // regional - alphabetical order by country name
     26                new LambertEST(), // Still needs proper default zoom
     27                new Lambert(),    // Still needs proper default zoom
     28                new LambertCC9Zones(),    // Still needs proper default zoom
     29                new UTM_France_DOM(),
     30                new TransverseMercatorLV(),
     31                new Puwg(),
     32                new Epsg3008(), // SWEREF99 13 30
     33                new SwissGrid(),
     34        }));
    3135
    3236    public static ArrayList<Projection> getProjections() {
     
    4347        allProjections.add(proj);
    4448    }
     49
     50    static public EastNorth project(LatLon ll) {
     51        if (ll == null) return null;
     52        return Main.getProjection().latlon2eastNorth(ll);
     53    }
     54
     55    static public LatLon inverseProject(EastNorth en) {
     56        if (en == null) return null;
     57        return Main.getProjection().eastNorth2latlon(en);
     58    }
    4559}
  • trunk/src/org/openstreetmap/josm/data/validation/OsmValidator.java

    r4051 r4126  
    2323import org.openstreetmap.josm.Main;
    2424import org.openstreetmap.josm.actions.ValidateAction;
    25 import org.openstreetmap.josm.actions.upload.ValidateUploadHook;
    2625import org.openstreetmap.josm.data.projection.Epsg4326;
    2726import org.openstreetmap.josm.data.projection.Lambert;
     
    3029import org.openstreetmap.josm.data.validation.tests.CrossingWays;
    3130import org.openstreetmap.josm.data.validation.tests.DuplicateNode;
     31import org.openstreetmap.josm.data.validation.tests.DuplicateRelation;
    3232import org.openstreetmap.josm.data.validation.tests.DuplicateWay;
    33 import org.openstreetmap.josm.data.validation.tests.DuplicateRelation;
    3433import org.openstreetmap.josm.data.validation.tests.DuplicatedWayNodes;
    3534import org.openstreetmap.josm.data.validation.tests.MultipolygonTest;
     
    4847import org.openstreetmap.josm.data.validation.tests.WronglyOrderedWays;
    4948import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
    50 import org.openstreetmap.josm.gui.layer.ValidatorLayer;
    5149import org.openstreetmap.josm.gui.layer.Layer;
    5250import org.openstreetmap.josm.gui.layer.OsmDataLayer;
     51import org.openstreetmap.josm.gui.layer.ValidatorLayer;
    5352import org.openstreetmap.josm.gui.preferences.ValidatorPreference;
    5453
     
    7776    @SuppressWarnings("unchecked")
    7877    public static Class<Test>[] allAvailableTests = new Class[] {
    79             DuplicateNode.class, // ID    1 ..   99
    80             OverlappingWays.class, // ID  101 ..  199
    81             UntaggedNode.class, // ID  201 ..  299
    82             UntaggedWay.class, // ID  301 ..  399
    83             SelfIntersectingWay.class, // ID  401 ..  499
    84             DuplicatedWayNodes.class, // ID  501 ..  599
    85             CrossingWays.class, // ID  601 ..  699
    86             SimilarNamedWays.class, // ID  701 ..  799
    87             NodesWithSameName.class, // ID  801 ..  899
    88             Coastlines.class, // ID  901 ..  999
    89             WronglyOrderedWays.class, // ID 1001 .. 1099
    90             UnclosedWays.class, // ID 1101 .. 1199
    91             TagChecker.class, // ID 1201 .. 1299
    92             UnconnectedWays.class, // ID 1301 .. 1399
    93             DuplicateWay.class, // ID 1401 .. 1499
    94             NameMismatch.class, // ID  1501 ..  1599
    95             MultipolygonTest.class, // ID  1601 ..  1699
    96             RelationChecker.class, // ID  1701 ..  1799
    97             TurnrestrictionTest.class, // ID  1801 ..  1899
    98             DuplicateRelation.class, // ID 1901 .. 1999
     78        DuplicateNode.class, // ID    1 ..   99
     79        OverlappingWays.class, // ID  101 ..  199
     80        UntaggedNode.class, // ID  201 ..  299
     81        UntaggedWay.class, // ID  301 ..  399
     82        SelfIntersectingWay.class, // ID  401 ..  499
     83        DuplicatedWayNodes.class, // ID  501 ..  599
     84        CrossingWays.class, // ID  601 ..  699
     85        SimilarNamedWays.class, // ID  701 ..  799
     86        NodesWithSameName.class, // ID  801 ..  899
     87        Coastlines.class, // ID  901 ..  999
     88        WronglyOrderedWays.class, // ID 1001 .. 1099
     89        UnclosedWays.class, // ID 1101 .. 1199
     90        TagChecker.class, // ID 1201 .. 1299
     91        UnconnectedWays.class, // ID 1301 .. 1399
     92        DuplicateWay.class, // ID 1401 .. 1499
     93        NameMismatch.class, // ID  1501 ..  1599
     94        MultipolygonTest.class, // ID  1601 ..  1699
     95        RelationChecker.class, // ID  1701 ..  1799
     96        TurnrestrictionTest.class, // ID  1801 ..  1899
     97        DuplicateRelation.class, // ID 1901 .. 1999
    9998    };
    10099
     
    242241     */
    243242    public void initializeGridDetail() {
    244         if (Main.proj.toString().equals(new Epsg4326().toString())) {
     243        if (Main.getProjection().toString().equals(new Epsg4326().toString())) {
    245244            OsmValidator.griddetail = 10000;
    246         } else if (Main.proj.toString().equals(new Mercator().toString())) {
     245        } else if (Main.getProjection().toString().equals(new Mercator().toString())) {
    247246            OsmValidator.griddetail = 0.01;
    248         } else if (Main.proj.toString().equals(new Lambert().toString())) {
     247        } else if (Main.getProjection().toString().equals(new Lambert().toString())) {
    249248            OsmValidator.griddetail = 0.1;
    250249        }
     
    265264                JOptionPane.showMessageDialog(Main.parent,
    266265                        tr("Error initializing test {0}:\n {1}", test.getClass()
    267                         .getSimpleName(), e),
    268                         tr("Error"),
    269                         JOptionPane.ERROR_MESSAGE);
     266                                .getSimpleName(), e),
     267                                tr("Error"),
     268                                JOptionPane.ERROR_MESSAGE);
    270269            }
    271270        }
  • trunk/src/org/openstreetmap/josm/gui/MapView.java

    r3896 r4126  
    118118     *
    119119     * @param listener the listener. Ignored if null or already registered.
    120      * @param initialFire Fire an edit-layer-changed-event right after adding 
     120     * @param initialFire Fire an edit-layer-changed-event right after adding
    121121     * the listener in case there is an edit layer present
    122122     */
     
    285285        }
    286286        layer.addPropertyChangeListener(this);
     287        Main.addProjectionChangeListener(layer);
    287288        AudioPlayer.reset();
    288289        repaint();
     
    359360
    360361        layers.remove(layer);
     362        Main.removeProjectionChangeListener(layer);
    361363        fireLayerRemoved(layer);
    362364        layer.removePropertyChangeListener(this);
  • trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java

    r4079 r4126  
    3939import org.openstreetmap.josm.data.preferences.IntegerProperty;
    4040import org.openstreetmap.josm.data.projection.Projection;
     41import org.openstreetmap.josm.data.projection.Projections;
    4142import org.openstreetmap.josm.gui.help.Helpful;
    4243import org.openstreetmap.josm.gui.preferences.ProjectionPreference;
     
    9697     * northing/easting space of the projection.
    9798     */
    98     private double scale = Main.proj.getDefaultZoomInPPD();
     99    private double scale = Main.getProjection().getDefaultZoomInPPD();
    99100    /**
    100101     * Center n/e coordinate of the desired screen center.
     
    111112
    112113    private EastNorth calculateDefaultCenter() {
    113         Bounds b = Main.proj.getWorldBoundsLatLon();
     114        Bounds b = Main.getProjection().getWorldBoundsLatLon();
    114115        double lat = (b.getMax().lat() + b.getMin().lat())/2;
    115116        double lon = (b.getMax().lon() + b.getMin().lon())/2;
    116117
    117         return Main.proj.latlon2eastNorth(new LatLon(lat, lon));
     118        return Main.getProjection().latlon2eastNorth(new LatLon(lat, lon));
    118119    }
    119120
     
    209210        EastNorth p2 = getEastNorth(r.x + r.width, r.y + r.height);
    210211
    211         Bounds result = new Bounds(Main.proj.eastNorth2latlon(p1));
     212        Bounds result = new Bounds(Main.getProjection().eastNorth2latlon(p1));
    212213
    213214        double eastMin = Math.min(p1.east(), p2.east());
     
    219220
    220221        for (int i=0; i < 10; i++) {
    221             result.extend(Main.proj.eastNorth2latlon(new EastNorth(eastMin + i * deltaEast, northMin)));
    222             result.extend(Main.proj.eastNorth2latlon(new EastNorth(eastMin + i * deltaEast, northMax)));
    223             result.extend(Main.proj.eastNorth2latlon(new EastNorth(eastMin, northMin  + i * deltaNorth)));
    224             result.extend(Main.proj.eastNorth2latlon(new EastNorth(eastMax, northMin  + i * deltaNorth)));
     222            result.extend(Main.getProjection().eastNorth2latlon(new EastNorth(eastMin + i * deltaEast, northMin)));
     223            result.extend(Main.getProjection().eastNorth2latlon(new EastNorth(eastMin + i * deltaEast, northMax)));
     224            result.extend(Main.getProjection().eastNorth2latlon(new EastNorth(eastMin, northMin  + i * deltaNorth)));
     225            result.extend(Main.getProjection().eastNorth2latlon(new EastNorth(eastMax, northMin  + i * deltaNorth)));
    225226        }
    226227
     
    250251            return getPoint2D(getProjection().latlon2eastNorth(latlon));
    251252    }
     253
    252254    public Point2D getPoint2D(Node n) {
    253255        return getPoint2D(n.getEastNorth());
     
    282284    public void zoomTo(EastNorth newCenter, double newScale) {
    283285        Bounds b = getProjection().getWorldBoundsLatLon();
    284         CachedLatLon cl = new CachedLatLon(newCenter);
     286        LatLon cl = Projections.inverseProject(newCenter);
    285287        boolean changed = false;
    286288        double lat = cl.lat();
     
    291293        else if(lon > b.getMax().lon()) {changed = true; lon = b.getMax().lon(); }
    292294        if(changed) {
    293             newCenter = new CachedLatLon(lat, lon).getEastNorth();
     295            newCenter = Projections.project(new LatLon(lat,lon));
    294296        }
    295297        int width = getWidth()/2;
     
    350352
    351353    public void zoomTo(LatLon newCenter) {
    352         if(newCenter instanceof CachedLatLon) {
    353             zoomTo(((CachedLatLon)newCenter).getEastNorth(), scale);
    354         } else {
    355             zoomTo(getProjection().latlon2eastNorth(newCenter), scale);
    356         }
     354        zoomTo(Projections.project(newCenter));
    357355    }
    358356
    359357    public void smoothScrollTo(LatLon newCenter) {
    360         if (newCenter instanceof CachedLatLon) {
    361             smoothScrollTo(((CachedLatLon)newCenter).getEastNorth());
    362         } else {
    363             smoothScrollTo(getProjection().latlon2eastNorth(newCenter));
    364         }
     358        smoothScrollTo(Projections.project(newCenter));
    365359    }
    366360
     
    441435
    442436        public ZoomData(EastNorth center, double scale) {
    443             this.center = new CachedLatLon(center);
     437            this.center = Projections.inverseProject(center);
    444438            this.scale = scale;
    445439        }
     
    11451139     */
    11461140    public Projection getProjection() {
    1147         return Main.proj;
     1141        return Main.getProjection();
    11481142    }
    11491143
  • trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java

    r4043 r4126  
    5252import org.openstreetmap.josm.data.coor.LatLon;
    5353import org.openstreetmap.josm.data.gpx.GpxData;
     54import org.openstreetmap.josm.data.gpx.GpxRoute;
    5455import org.openstreetmap.josm.data.gpx.GpxTrack;
    5556import org.openstreetmap.josm.data.gpx.GpxTrackSegment;
     
    5960import org.openstreetmap.josm.data.osm.Way;
    6061import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
     62import org.openstreetmap.josm.data.projection.Projection;
    6163import org.openstreetmap.josm.gui.ConditionalOptionPaneUtil;
    6264import org.openstreetmap.josm.gui.HelpAwareOptionPane;
     
    330332
    331333        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
    332         Main.pref.getBoolean("mappaint.gpx.use-antialiasing", false) ?
    333                 RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF);
     334                Main.pref.getBoolean("mappaint.gpx.use-antialiasing", false) ?
     335                        RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF);
    334336
    335337        /****************************************************************
     
    12311233        if (bestEN == null)
    12321234            return null;
    1233         WayPoint best = new WayPoint(Main.proj.eastNorth2latlon(bestEN));
     1235        WayPoint best = new WayPoint(Main.getProjection().eastNorth2latlon(bestEN));
    12341236        best.time = bestTime;
    12351237        return best;
     
    14901492            importer.importDataHandleExceptions(files, NullProgressMonitor.INSTANCE);
    14911493        }
    1492 
     1494    }
     1495
     1496    @Override
     1497    public void projectionChanged(Projection oldValue, Projection newValue) {
     1498        if (newValue == null) return;
     1499        if (data.waypoints != null) {
     1500            for (WayPoint wp : data.waypoints){
     1501                wp.invalidateEastNorthCache();
     1502            }
     1503        }
     1504        if (data.tracks != null){
     1505            for (GpxTrack track: data.tracks) {
     1506                for (GpxTrackSegment segment: track.getSegments()) {
     1507                    for (WayPoint wp: segment.getWayPoints()) {
     1508                        wp.invalidateEastNorthCache();
     1509                    }
     1510                }
     1511            }
     1512        }
     1513        if (data.routes != null) {
     1514            for (GpxRoute route: data.routes) {
     1515                if (route.routePoints == null) {
     1516                    continue;
     1517                }
     1518                for (WayPoint wp: route.routePoints) {
     1519                    wp.invalidateEastNorthCache();
     1520                }
     1521            }
     1522        }
    14931523    }
    14941524}
  • trunk/src/org/openstreetmap/josm/gui/layer/ImageryLayer.java

    r4065 r4126  
    8383
    8484    public double getPPD(){
    85         if (Main.map == null || Main.map.mapView == null) return Main.proj.getDefaultZoomInPPD();
     85        if (Main.map == null || Main.map.mapView == null) return Main.getProjection().getDefaultZoomInPPD();
    8686        ProjectionBounds bounds = Main.map.mapView.getProjectionBounds();
    8787        return Main.map.mapView.getWidth() / (bounds.maxEast - bounds.minEast);
  • trunk/src/org/openstreetmap/josm/gui/layer/Layer.java

    r3705 r4126  
    2323import org.openstreetmap.josm.data.Bounds;
    2424import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
     25import org.openstreetmap.josm.data.projection.Projection;
     26import org.openstreetmap.josm.data.projection.ProjectionChangeListener;
    2527import org.openstreetmap.josm.gui.MapView;
    2628import org.openstreetmap.josm.tools.Destroyable;
     
    4244 * @author imi
    4345 */
    44 abstract public class Layer implements Destroyable, MapViewPaintable {
     46abstract public class Layer implements Destroyable, MapViewPaintable, ProjectionChangeListener {
    4547
    4648    public interface LayerAction {
     
    362364        }
    363365    }
     366
     367    /* --------------------------------------------------------------------------------- */
     368    /* interface ProjectionChangeListener                                                */
     369    /* --------------------------------------------------------------------------------- */
     370    @Override
     371    public void projectionChanged(Projection oldValue, Projection newValue) {
     372        // default implementation does nothing - override in subclasses
     373    }
    364374}
  • trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java

    r4087 r4126  
    6262import org.openstreetmap.josm.data.osm.visitor.paint.MapRendererFactory;
    6363import org.openstreetmap.josm.data.osm.visitor.paint.Rendering;
     64import org.openstreetmap.josm.data.projection.Projection;
    6465import org.openstreetmap.josm.data.validation.TestError;
    6566import org.openstreetmap.josm.gui.HelpAwareOptionPane;
     
    8081 */
    8182public class OsmDataLayer extends Layer implements Listener, SelectionChangedListener {
     83    // static private final Logger logger = Logger.getLogger(OsmDataLayer.class.getName());
     84
    8285    static public final String REQUIRES_SAVE_TO_DISK_PROP = OsmDataLayer.class.getName() + ".requiresSaveToDisk";
    8386    static public final String REQUIRES_UPLOAD_TO_SERVER_PROP = OsmDataLayer.class.getName() + ".requiresUploadToServer";
     
    658661            }
    659662        }
    660 
    661663    }
    662664
     
    675677        isChanged = true;
    676678    }
     679
     680    @Override
     681    public void projectionChanged(Projection oldValue, Projection newValue) {
     682        /*
     683         * No reprojection required. The dataset itself is registered as projection
     684         * change listener and already got notified.
     685         */
     686    }
    677687}
  • trunk/src/org/openstreetmap/josm/gui/layer/RawGpsLayer.java

    r3408 r4126  
    9595        public GpsPoint(LatLon ll, String t) {
    9696            latlon = ll;
    97             eastNorth = Main.proj.latlon2eastNorth(ll);
     97            eastNorth = Main.getProjection().latlon2eastNorth(ll);
    9898            time = t;
    9999        }
  • trunk/src/org/openstreetmap/josm/gui/layer/TMSLayer.java

    r4017 r4126  
    871871
    872872    private Point pixelPos(LatLon ll) {
    873         return Main.map.mapView.getPoint(Main.proj.latlon2eastNorth(ll).add(getDx(), getDy()));
     873        return Main.map.mapView.getPoint(Main.getProjection().latlon2eastNorth(ll).add(getDx(), getDy()));
    874874    }
    875875    private Point pixelPos(Tile t) {
     
    879879    }
    880880    private LatLon getShiftedLatLon(EastNorth en) {
    881         return Main.proj.eastNorth2latlon(en.add(-getDx(), -getDy()));
     881        return Main.getProjection().eastNorth2latlon(en.add(-getDx(), -getDy()));
    882882    }
    883883    private Coordinate getShiftedCoord(EastNorth en) {
  • trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/Marker.java

    r3530 r4126  
    1616import javax.swing.Icon;
    1717
    18 import org.openstreetmap.josm.data.coor.CachedLatLon;
    1918import org.openstreetmap.josm.data.coor.EastNorth;
    2019import org.openstreetmap.josm.data.coor.LatLon;
     
    2322import org.openstreetmap.josm.data.gpx.WayPoint;
    2423import org.openstreetmap.josm.data.preferences.IntegerProperty;
     24import org.openstreetmap.josm.data.projection.Projections;
    2525import org.openstreetmap.josm.gui.MapView;
    2626import org.openstreetmap.josm.tools.ImageProvider;
     
    7070                             may be adjusted later to sync with other data, so not final */
    7171
    72     private CachedLatLon coor;
     72    private LatLon coor;
    7373
    7474    public final void setCoor(LatLon coor) {
    75         if(this.coor == null) {
    76             this.coor = new CachedLatLon(coor);
    77         } else {
    78             this.coor.setCoor(coor);
    79         }
     75        this.coor = new LatLon(coor);
    8076    }
    8177
     
    8581
    8682    public final void setEastNorth(EastNorth eastNorth) {
    87         coor.setEastNorth(eastNorth);
     83        this.coor = Projections.inverseProject(eastNorth);
    8884    }
    8985
    9086    public final EastNorth getEastNorth() {
    91         return coor.getEastNorth();
     87        return Projections.project(this.coor);
    9288    }
    9389
     
    264260     */
    265261    public String getText() {
    266         if (this.text != null ) {
     262        if (this.text != null )
    267263            return this.text;
    268         }
    269         else {
     264        else
    270265            return getText(this.textMap);
    271         }
    272266    }
    273267
  • trunk/src/org/openstreetmap/josm/gui/preferences/ImageryPreference.java

    r4028 r4126  
    734734                @Override
    735735                public void actionPerformed(ActionEvent e) {
    736                     OffsetBookmark b = new OffsetBookmark(Main.proj,"","",0,0);
     736                    OffsetBookmark b = new OffsetBookmark(Main.getProjection(),"","",0,0);
    737737                    model.addRow(b);
    738738                }
  • trunk/src/org/openstreetmap/josm/gui/preferences/ProjectionPreference.java

    r3874 r4126  
    99import java.util.ArrayList;
    1010import java.util.Collection;
    11 import java.util.concurrent.CopyOnWriteArrayList;
    1211
    1312import javax.swing.BorderFactory;
     
    2726import org.openstreetmap.josm.data.projection.Mercator;
    2827import org.openstreetmap.josm.data.projection.Projection;
     28import org.openstreetmap.josm.data.projection.ProjectionSubPrefs;
    2929import org.openstreetmap.josm.data.projection.Projections;
    30 import org.openstreetmap.josm.data.projection.ProjectionSubPrefs;
    3130import org.openstreetmap.josm.gui.NavigatableComponent;
    3231import org.openstreetmap.josm.plugins.PluginHandler;
     
    3938            return new ProjectionPreference();
    4039        }
    41     }
    42 
    43     public interface ProjectionChangedListener {
    44         void projectionChanged();
    4540    }
    4641
     
    6560    }
    6661
    67     //TODO This is not nice place for a listener code but probably only Dataset will want to listen for projection changes so it's acceptable
    68     private static CopyOnWriteArrayList<ProjectionChangedListener> listeners = new CopyOnWriteArrayList<ProjectionChangedListener>();
    69 
    70     public static void addProjectionChangedListener(ProjectionChangedListener listener) {
    71         listeners.addIfAbsent(listener);
    72     }
    73 
    74     public static void removeProjectionChangedListener(ProjectionChangedListener listener) {
    75         listeners.remove(listener);
    76     }
    77 
    78     private static void fireProjectionChanged() {
    79         for (ProjectionChangedListener listener: listeners) {
    80             listener.projectionChanged();
    81         }
    82     }
    83 
    84 
    8562    /**
    8663     * Combobox with all projections available
     
    161138        gui.mapcontent.addTab(tr("Map Projection"), scrollpane);
    162139
    163         updateMeta(Main.proj);
     140        updateMeta(Main.getProjection());
    164141    }
    165142
     
    202179    {
    203180        Bounds b = (Main.map != null && Main.map.mapView != null) ? Main.map.mapView.getRealBounds() : null;
    204         Projection oldProj = Main.proj;
    205 
    206         Projection p = null;
     181
     182        Projection proj = null;
    207183        for (ClassLoader cl : PluginHandler.getResourceClassLoaders()) {
    208184            try {
    209                 p = (Projection) Class.forName(name, true, cl).newInstance();
     185                proj = (Projection) Class.forName(name, true, cl).newInstance();
    210186            } catch (final Exception e) {
    211187            }
    212             if (p != null) {
    213                 Main.proj = p;
    214                 break;
    215             }
    216         }
    217         if (p == null) {
     188            if (proj != null) {
     189                break;
     190            }
     191        }
     192        if (proj == null) {
    218193            JOptionPane.showMessageDialog(
    219194                    Main.parent,
     
    223198            );
    224199            coll = null;
    225             Main.proj = new Mercator();
    226             name = Main.proj.getClass().getName();
     200            proj = new Mercator();
     201            name = Main.getProjection().getClass().getName();
    227202        }
    228203        PROP_SUB_PROJECTION.put(coll);
    229204        PROP_PROJECTION_SUBPROJECTION.put(coll, name);
    230         if(Main.proj instanceof ProjectionSubPrefs) {
    231             ((ProjectionSubPrefs) Main.proj).setPreferences(coll);
    232         }
    233         fireProjectionChanged(); // This should be probably called from the if bellow, but hashCode condition doesn't look sure enough
    234         if(b != null && (!Main.proj.getClass().getName().equals(oldProj.getClass().getName()) || Main.proj.hashCode() != oldProj.hashCode()))
     205        if(proj instanceof ProjectionSubPrefs) {
     206            ((ProjectionSubPrefs) proj).setPreferences(coll);
     207        }
     208        Projection oldProj = Main.getProjection();
     209        Main.setProjection(proj);
     210        if(b != null && (!proj.getClass().getName().equals(oldProj.getClass().getName()) || proj.hashCode() != oldProj.hashCode()))
    235211        {
    236212            Main.map.mapView.zoomTo(b);
  • trunk/src/org/openstreetmap/josm/io/imagery/Grabber.java

    r4065 r4126  
    4141        }
    4242
    43         this.proj = Main.proj;
     43        this.proj = Main.getProjection();
    4444        this.pixelPerDegree = request.getPixelPerDegree();
    4545        this.request = request;
  • trunk/src/org/openstreetmap/josm/io/imagery/HTMLGrabber.java

    r4065 r4126  
    5252        BufferedImage img = layer.normalizeImage(ImageIO.read(bais));
    5353        bais.reset();
    54         layer.cache.saveToCache(layer.isOverlapEnabled()?img:null, bais, Main.proj, pixelPerDegree, b.minEast, b.minNorth);
     54        layer.cache.saveToCache(layer.isOverlapEnabled()?img:null, bais, Main.getProjection(), pixelPerDegree, b.minEast, b.minNorth);
    5555
    5656        return img;
  • trunk/src/org/openstreetmap/josm/io/imagery/OsmosnimkiOffsetServer.java

    r3852 r4126  
    4040    @Override
    4141    public EastNorth getOffset(ImageryInfo info, EastNorth en) {
    42         LatLon ll = Main.proj.eastNorth2latlon(en);
     42        LatLon ll = Main.getProjection().eastNorth2latlon(en);
    4343        try {
    4444            URL url = new URL(this.url + "action=GetOffsetForPoint&lat=" + ll.lat() + "&lon=" + ll.lon() + "&id=" + URLEncoder.encode(info.getFullUrl(), "UTF-8"));
     
    5050            String sLon = s.substring(1,i);
    5151            String sLat = s.substring(i+1,s.length()-1);
    52             return Main.proj.latlon2eastNorth(new LatLon(Double.valueOf(sLat),Double.valueOf(sLon))).sub(en);
     52            return Main.getProjection().latlon2eastNorth(new LatLon(Double.valueOf(sLat),Double.valueOf(sLon))).sub(en);
    5353        } catch (Exception e) {
    5454            e.printStackTrace();
  • trunk/src/org/openstreetmap/josm/io/imagery/WMSGrabber.java

    r4065 r4126  
    7272    protected URL getURL(double w, double s,double e,double n,
    7373            int wi, int ht) throws MalformedURLException {
    74         String myProj = Main.proj.toCode();
    75         if(Main.proj instanceof Mercator) // don't use mercator code directly
     74        String myProj = Main.getProjection().toCode();
     75        if(Main.getProjection() instanceof Mercator) // don't use mercator code directly
    7676        {
    77             LatLon sw = Main.proj.eastNorth2latlon(new EastNorth(w, s));
    78             LatLon ne = Main.proj.eastNorth2latlon(new EastNorth(e, n));
     77            LatLon sw = Main.getProjection().eastNorth2latlon(new EastNorth(w, s));
     78            LatLon ne = Main.getProjection().eastNorth2latlon(new EastNorth(e, n));
    7979            myProj = "EPSG:4326";
    8080            s = sw.lat();
     
    114114    static public String getProjection(String baseURL, Boolean warn)
    115115    {
    116         String projname = Main.proj.toCode();
    117         if(Main.proj instanceof Mercator) {
     116        String projname = Main.getProjection().toCode();
     117        if(Main.getProjection() instanceof Mercator) {
    118118            projname = "EPSG:4326";
    119119        }
     
    146146    @Override
    147147    public boolean loadFromCache(WMSRequest request) {
    148         BufferedImage cached = layer.cache.getExactMatch(Main.proj, pixelPerDegree, b.minEast, b.minNorth);
     148        BufferedImage cached = layer.cache.getExactMatch(Main.getProjection(), pixelPerDegree, b.minEast, b.minNorth);
    149149
    150150        if (cached != null) {
     
    152152            return true;
    153153        } else if (request.isAllowPartialCacheMatch()) {
    154             BufferedImage partialMatch = layer.cache.getPartialMatch(Main.proj, pixelPerDegree, b.minEast, b.minNorth);
     154            BufferedImage partialMatch = layer.cache.getPartialMatch(Main.getProjection(), pixelPerDegree, b.minEast, b.minNorth);
    155155            if (partialMatch != null) {
    156156                request.finish(State.PARTLY_IN_CACHE, partialMatch);
     
    194194        BufferedImage img = layer.normalizeImage(ImageIO.read(bais));
    195195        bais.reset();
    196         layer.cache.saveToCache(layer.isOverlapEnabled()?img:null, bais, Main.proj, pixelPerDegree, b.minEast, b.minNorth);
     196        layer.cache.saveToCache(layer.isOverlapEnabled()?img:null, bais, Main.getProjection(), pixelPerDegree, b.minEast, b.minNorth);
    197197        return img;
    198198    }
  • trunk/src/org/openstreetmap/josm/tools/Geometry.java

    r4085 r4126  
    112112                                }
    113113
    114                                 Node newNode = new Node(Main.proj.eastNorth2latlon(intersection));
     114                                Node newNode = new Node(Main.getProjection().eastNorth2latlon(intersection));
    115115                                Node intNode = newNode;
    116116                                boolean insertInSeg1 = false;
     
    458458        return inside;
    459459    }
    460    
     460
    461461    /**
    462462     * returns area of a closed way in square meters
     
    478478        return Math.abs(area/2);
    479479    }
    480    
     480
    481481    protected static double calcX(Node p1){
    482482        double lat1, lon1, lat2, lon2;
     
    495495        return 6367000 * c;
    496496    }
    497    
     497
    498498    protected static double calcY(Node p1){
    499499        double lat1, lon1, lat2, lon2;
Note: See TracChangeset for help on using the changeset viewer.