Ignore:
Timestamp:
2012-05-10T22:09:59+02:00 (12 years ago)
Author:
bastiK
Message:

improved custom projection

Location:
trunk/src/org/openstreetmap/josm/data/projection
Files:
4 edited

Legend:

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

    r5227 r5228  
    4141     */
    4242    protected String pref = null;
     43    protected Bounds bounds;
    4344
    4445    protected static class Param {
     
    6364        public final static Param lat_1 = new Param("lat_1", true);
    6465        public final static Param lat_2 = new Param("lat_2", true);
     66        public final static Param wktext = new Param("wktext", false);  // ignored
     67        public final static Param units = new Param("units", true);     // ignored
     68        public final static Param no_defs = new Param("no_defs", false);
     69        public final static Param init = new Param("init", true);
     70        // JOSM extension, not present in PROJ.4
     71        public final static Param bounds = new Param("bounds", true);
    6572
    6673        public final static Set<Param> params = new HashSet<Param>(Arrays.asList(
    6774                x_0, y_0, lon_0, k_0, ellps, a, es, rf, f, b, datum, towgs84,
    68                 nadgrids, proj, lat_0, lat_1, lat_2
     75                nadgrids, proj, lat_0, lat_1, lat_2, wktext, units, no_defs,
     76                init, bounds
    6977        ));
    7078
     
    8391
    8492    public void update(String pref) throws ProjectionConfigurationException {
     93        this.pref = pref;
    8594        if (pref == null) {
    86             this.pref = null;
    8795            ellps = Ellipsoid.WGS84;
    8896            datum = WGS84Datum.INSTANCE;
    8997            proj = new org.openstreetmap.josm.data.projection.proj.Mercator();
     98            bounds = new Bounds(
     99                    new LatLon(-85.05112877980659, -180.0),
     100                    new LatLon(85.05112877980659, 180.0));
    90101        } else {
    91             Map<String, String> parameters = new HashMap<String, String>();
    92             String[] parts = pref.trim().split("\\s+");
    93             if (pref.trim().isEmpty()) {
    94                 parts = new String[0];
    95             }
    96             for (int i = 0; i < parts.length; i++) {
    97                 String part = parts[i];
    98                 if (part.isEmpty() || part.charAt(0) != '+')
    99                     throw new ProjectionConfigurationException(tr("Parameter must begin with a ''+'' sign (found ''{0}'')", part));
    100                 Matcher m = Pattern.compile("\\+([a-zA-Z0-9_]+)(=(.*))?").matcher(part);
    101                 if (m.matches()) {
    102                     String key = m.group(1);
    103                     String value = null;
    104                     if (m.groupCount() >= 3) {
    105                         value = m.group(3);
    106                     }
    107                     if (!Param.paramsByKey.containsKey(key))
    108                         throw new ProjectionConfigurationException(tr("Unkown parameter: ''{0}''.", key));
    109                     if (Param.paramsByKey.get(key).hasValue && value == null)
    110                         throw new ProjectionConfigurationException(tr("Value expected for parameter ''{0}''.", key));
    111                     if (!Param.paramsByKey.get(key).hasValue && value != null)
    112                         throw new ProjectionConfigurationException(tr("No value expected for parameter ''{0}''.", key));
    113                     parameters.put(key, value);
    114                 } else
    115                     throw new ProjectionConfigurationException(tr("Unexpected parameter format (''{0}'')", part));
    116             }
     102            Map<String, String> parameters = parseParameterList(pref);
    117103            ellps = parseEllipsoid(parameters);
    118104            datum = parseDatum(parameters, ellps);
     
    124110            s = parameters.get(Param.y_0.key);
    125111            if (s != null) {
    126                 this.y_0 = parseDouble(s, Param.x_0.key);
     112                this.y_0 = parseDouble(s, Param.y_0.key);
    127113            }
    128114            s = parameters.get(Param.lon_0.key);
    129115            if (s != null) {
    130                 this.lon_0 = parseAngle(s, Param.x_0.key);
     116                this.lon_0 = parseAngle(s, Param.lon_0.key);
    131117            }
    132118            s = parameters.get(Param.k_0.key);
    133119            if (s != null) {
    134                 this.k_0 = parseDouble(s, Param.x_0.key);
    135             }
    136             this.pref = pref;
    137         }
     120                this.k_0 = parseDouble(s, Param.k_0.key);
     121            }
     122            s = parameters.get(Param.bounds.key);
     123            if (s != null) {
     124                this.bounds = parseBounds(s);
     125            }
     126        }
     127    }
     128
     129    private Map<String, String> parseParameterList(String pref) throws ProjectionConfigurationException {
     130        Map<String, String> parameters = new HashMap<String, String>();
     131        String[] parts = pref.trim().split("\\s+");
     132        if (pref.trim().isEmpty()) {
     133            parts = new String[0];
     134        }
     135        for (int i = 0; i < parts.length; i++) {
     136            String part = parts[i];
     137            if (part.isEmpty() || part.charAt(0) != '+')
     138                throw new ProjectionConfigurationException(tr("Parameter must begin with a ''+'' character (found ''{0}'')", part));
     139            Matcher m = Pattern.compile("\\+([a-zA-Z0-9_]+)(=(.*))?").matcher(part);
     140            if (m.matches()) {
     141                String key = m.group(1);
     142                // alias
     143                if (key.equals("k")) {
     144                    key = Param.k_0.key;
     145                }
     146                String value = null;
     147                if (m.groupCount() >= 3) {
     148                    value = m.group(3);
     149                    // same aliases
     150                    if (key.equals(Param.proj.key)) {
     151                        if (value.equals("longlat") || value.equals("latlon") || value.equals("latlong")) {
     152                            value = "lonlat";
     153                        }
     154                    }
     155                }
     156                if (!Param.paramsByKey.containsKey(key))
     157                    throw new ProjectionConfigurationException(tr("Unkown parameter: ''{0}''.", key));
     158                if (Param.paramsByKey.get(key).hasValue && value == null)
     159                    throw new ProjectionConfigurationException(tr("Value expected for parameter ''{0}''.", key));
     160                if (!Param.paramsByKey.get(key).hasValue && value != null)
     161                    throw new ProjectionConfigurationException(tr("No value expected for parameter ''{0}''.", key));
     162                parameters.put(key, value);
     163            } else
     164                throw new ProjectionConfigurationException(tr("Unexpected parameter format (''{0}'')", part));
     165        }
     166        // recursive resolution of +init includes
     167        String initKey = parameters.get(Param.init.key);
     168        if (initKey != null) {
     169            String init = Projections.getInit(initKey);
     170            if (init == null)
     171                throw new ProjectionConfigurationException(tr("Value ''{0}'' for option +init not supported.", initKey));
     172            Map<String, String> initp = null;
     173            try {
     174                initp = parseParameterList(init);
     175            } catch (ProjectionConfigurationException ex) {
     176                throw new ProjectionConfigurationException(tr(initKey+": "+ex.getMessage()));
     177            }
     178            for (Map.Entry<String, String> e : parameters.entrySet()) {
     179                initp.put(e.getKey(), e.getValue());
     180            }
     181            return initp;
     182        }
     183        return parameters;
    138184    }
    139185
     
    174220                parameters.containsKey(Param.b.key))
    175221            throw new ProjectionConfigurationException(tr("Combination of ellipsoid parameters is not supported."));
     222        if (parameters.containsKey(Param.no_defs.key))
     223            throw new ProjectionConfigurationException(tr("Ellipsoid required (+ellps=* or +a=*, +b=*)"));
    176224        // nothing specified, use WGS84 as default
    177225        return Ellipsoid.WGS84;
     
    181229        String nadgridsId = parameters.get(Param.nadgrids.key);
    182230        if (nadgridsId != null) {
    183             NTV2GridShiftFileWrapper nadgrids = Projections.getNadgrids(nadgridsId);
     231            NTV2GridShiftFileWrapper nadgrids = Projections.getNTV2Grid(nadgridsId);
    184232            if (nadgrids == null)
    185233                throw new ProjectionConfigurationException(tr("Grid shift file ''{0}'' for option +nadgrids not supported.", nadgridsId));
     
    196244            if (datum == null) throw new ProjectionConfigurationException(tr("Unkown datum identifier: ''{0}''", datumId));
    197245            return datum;
    198         } else
    199             return new CentricDatum(null, null, ellps);
     246        }
     247        if (parameters.containsKey(Param.no_defs.key))
     248            throw new ProjectionConfigurationException(tr("Datum required (+datum=*, +towgs84=* or +nadgirds=*)"));
     249        return new CentricDatum(null, null, ellps);
    200250    }
    201251
     
    267317        proj.initialize(projParams);
    268318        return proj;
    269 
     319    }
     320
     321    public Bounds parseBounds(String boundsStr) throws ProjectionConfigurationException {
     322        String[] numStr = boundsStr.split(",");
     323        if (numStr.length != 4)
     324            throw new ProjectionConfigurationException(tr("Unexpected number of arguments for parameter ''+bounds'' (must be 4)"));
     325        return new Bounds(parseAngle(numStr[1], "minlat (+bounds)"),
     326                parseAngle(numStr[0], "minlon (+bounds)"),
     327                parseAngle(numStr[3], "maxlat (+bounds)"),
     328                parseAngle(numStr[2], "maxlon (+bounds)"));
    270329    }
    271330
     
    374433    @Override
    375434    public Bounds getWorldBoundsLatLon() {
     435        if (bounds != null) return bounds;
    376436        return new Bounds(
    377             new LatLon(-85.05112877980659, -180.0),
    378             new LatLon(85.05112877980659, 180.0)); // FIXME
     437            new LatLon(-90.0, -180.0),
     438            new LatLon(90.0, 180.0));
    379439    }
    380440
  • trunk/src/org/openstreetmap/josm/data/projection/CustomProjectionPrefGui.java

    r5227 r5228  
    1010import java.awt.event.ActionListener;
    1111import java.util.ArrayList;
     12import java.util.Arrays;
    1213import java.util.Collection;
    1314import java.util.Collections;
     15import java.util.LinkedList;
    1416import java.util.List;
    1517import java.util.Map;
     
    2022import javax.swing.JPanel;
    2123import javax.swing.JTextField;
    22 
     24import javax.swing.plaf.basic.BasicComboBoxEditor;
     25
     26import org.openstreetmap.josm.Main;
    2327import org.openstreetmap.josm.gui.ExtendedDialog;
    2428import org.openstreetmap.josm.gui.preferences.projection.SubPrefsOptions;
     29import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionListItem;
    2530import org.openstreetmap.josm.gui.widgets.AbstractTextComponentValidator;
     31import org.openstreetmap.josm.gui.widgets.HistoryComboBox;
    2632import org.openstreetmap.josm.gui.widgets.HtmlPanel;
    2733import org.openstreetmap.josm.tools.GBC;
     
    3339    @Override
    3440    public void setupPreferencePanel(JPanel p, ActionListener listener) {
    35         JPanel inner = new PreferencePanel();
     41        JPanel inner = new PreferencePanel(listener);
    3642        p.setLayout(new GridBagLayout());
    3743        p.add(inner, GBC.std().fill(GBC.HORIZONTAL));
     
    4046    private class PreferencePanel extends JPanel {
    4147
    42         public final JTextField input;
    43 
    44         public PreferencePanel() {
    45             input = new JTextField(pref == null ? "" : pref, 30);
    46             build();
    47         }
    48 
    49         private void build() {
     48        public JTextField input;
     49        private HistoryComboBox cbInput;
     50
     51        public PreferencePanel(ActionListener listener) {
     52            build(listener);
     53        }
     54
     55        private void build(final ActionListener listener) {
     56            input = new JTextField(30);
     57            cbInput = new HistoryComboBox();
     58            cbInput.setPrototypeDisplayValue(new AutoCompletionListItem("xxxx"));
     59            cbInput.setEditor(new BasicComboBoxEditor() {
     60                @Override
     61                protected JTextField createEditorComponent() {
     62                    return input;
     63                }
     64            });
     65            Collection<String> samples = Arrays.asList(
     66                    "+proj=lonlat +ellps=WGS84 +datum=WGS84 +bounds=-180,-90,180,90",
     67                    "+proj=tmerc +lat_0=0 +lon_0=9 +k_0=1 +x_0=3500000 +y_0=0 +ellps=bessel +nadgrids=BETA2007.gsb");
     68            List<String> inputHistory = new LinkedList<String>(Main.pref.getCollection("projection.custom.value.history", samples));
     69            Collections.reverse(inputHistory);
     70            cbInput.setPossibleItems(inputHistory);
     71            cbInput.setText(pref == null ? "" : pref);
     72
    5073            final HtmlPanel errorsPanel = new HtmlPanel();
    5174            errorsPanel.setVisible(false);
     
    6487                        feedbackValid(tr("Projection configuration is valid."));
    6588                    }
     89                    listener.actionPerformed(null);
    6690                }
    6791
     
    109133            this.setLayout(new GridBagLayout());
    110134            JPanel p2 = new JPanel(new GridBagLayout());
    111             p2.add(input, GBC.std().fill(GBC.HORIZONTAL).insets(0, 20, 5, 5));
     135            p2.add(cbInput, GBC.std().fill(GBC.HORIZONTAL).insets(0, 20, 5, 5));
    112136            p2.add(btnCheck, GBC.eol().insets(0, 20, 0, 5));
    113137            this.add(p2, GBC.eol().fill(GBC.HORIZONTAL));
     
    120144            p2.add(GBC.glue(1, 0), GBC.eol().fill(GBC.HORIZONTAL));
    121145            this.add(p2, GBC.eol().fill(GBC.HORIZONTAL));
     146        }
     147
     148        public void rememberHistory() {
     149            cbInput.addCurrentItemToHistory();
     150            Main.pref.putCollection("projection.custom.value.history", cbInput.getHistory());
    122151        }
    123152    }
     
    150179            s.append("&nbsp;&nbsp;&nbsp;&nbsp;"+tr("Build-in:")+" ");
    151180            s.append(listKeys(Projections.nadgrids)+"<br>");
     181            s.append("<b>+bounds=</b>minlon,minlat,maxlon,maxlat - <i>"+tr("Projection bounds (in degrees)")+"</i><br>");
    152182
    153183            HtmlPanel info = new HtmlPanel(s.toString());
     
    166196        PreferencePanel prefPanel = (PreferencePanel) p.getComponent(0);
    167197        String pref = prefPanel.input.getText();
     198        prefPanel.rememberHistory();
    168199        return Collections.singleton(pref);
    169200    }
  • trunk/src/org/openstreetmap/josm/data/projection/Projections.java

    r5227 r5228  
    22package org.openstreetmap.josm.data.projection;
    33
     4import java.io.BufferedReader;
     5import java.io.IOException;
     6import java.io.InputStream;
     7import java.io.InputStreamReader;
    48import java.util.ArrayList;
    59import java.util.Arrays;
    610import java.util.HashMap;
    711import java.util.Map;
     12import java.util.regex.Matcher;
     13import java.util.regex.Pattern;
    814
    915import org.openstreetmap.josm.Main;
     
    2026import org.openstreetmap.josm.data.projection.proj.SwissObliqueMercator;
    2127import org.openstreetmap.josm.data.projection.proj.TransverseMercator;
     28import org.openstreetmap.josm.io.MirroredInputStream;
    2229
    2330/**
     
    8087     * should be compatible to PROJ.4
    8188     */
     89    public static Map<String, ProjFactory> projs = new HashMap<String, ProjFactory>();
    8290    public static Map<String, Ellipsoid> ellipsoids = new HashMap<String, Ellipsoid>();
    83     public static Map<String, ProjFactory> projs = new HashMap<String, ProjFactory>();
    8491    public static Map<String, Datum> datums = new HashMap<String, Datum>();
    8592    public static Map<String, NTV2GridShiftFileWrapper> nadgrids = new HashMap<String, NTV2GridShiftFileWrapper>();
     93    public static Map<String, String> inits = new HashMap<String, String>();
    8694
    8795    static {
    8896        registerBaseProjection("lonlat", LonLat.class, "core");
    89         registerBaseProjection("merc", org.openstreetmap.josm.data.projection.proj.Mercator.class, "core");
     97        registerBaseProjection("josm:smerc", org.openstreetmap.josm.data.projection.proj.Mercator.class, "core");
    9098        registerBaseProjection("lcc", LambertConformalConic.class, "core");
    9199        registerBaseProjection("somerc", SwissObliqueMercator.class, "core");
     
    101109        nadgrids.put("BETA2007.gsb", NTV2GridShiftFileWrapper.BETA2007);
    102110        nadgrids.put("ntf_r93_b.gsb", NTV2GridShiftFileWrapper.ntf_rgf93);
     111
     112        loadInits();
    103113    }
    104114
     
    134144    }
    135145
    136     public static NTV2GridShiftFileWrapper getNadgrids(String id) {
     146    public static NTV2GridShiftFileWrapper getNTV2Grid(String id) {
    137147        return nadgrids.get(id);
    138148    }
     149
     150    public static String getInit(String id) {
     151        return inits.get(id);
     152    }
     153
     154    /**
     155     * Load +init "presets" from file
     156     */
     157    private static void loadInits() {
     158        Pattern epsgPattern = Pattern.compile("\\A<(\\d+)>(.*)<>\\Z");
     159        try {
     160            InputStream in = new MirroredInputStream("resource://data/epsg");
     161            BufferedReader r = new BufferedReader(new InputStreamReader(in));
     162            String line;
     163            while ((line = r.readLine()) != null) {
     164                line = line.trim();
     165                if (!line.startsWith("#")) {
     166                    Matcher m = epsgPattern.matcher(line);
     167                    if (m.matches()) {
     168                        inits.put("epsg:" + m.group(1), m.group(2).trim());
     169                    } else {
     170                        System.err.println("Warning: failed to parse line from the epsg projection definition: "+line);
     171                    }
     172                }
     173            }
     174        } catch (IOException ex) {
     175            throw new RuntimeException();
     176        }
     177    }
    139178}
  • trunk/src/org/openstreetmap/josm/data/projection/proj/Mercator.java

    r5066 r5228  
    2020    @Override
    2121    public String getProj4Id() {
    22         return "merc";
     22        return null; // "merc" is ellipsoidal Mercator projection in PROJ.4
    2323    }
    2424
Note: See TracChangeset for help on using the changeset viewer.