Changeset 5228 in josm


Ignore:
Timestamp:
May 10, 2012 10:09:59 PM (13 months 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.