Statistics
| Revision:

root / org.gvsig.geotools.proj / trunk / org.gvsig.geotools.proj / org.gvsig.geotools.proj.catalog.impl / src / main / java / org / gvsig / geotools / proj / catalog / GtCRSCatalogManager.java @ 839

History | View | Annotate | Download (18.3 KB)

1
package org.gvsig.geotools.proj.catalog;
2

    
3
import java.io.File;
4
import java.sql.Connection;
5
import java.sql.PreparedStatement;
6
import java.sql.ResultSet;
7
import java.sql.SQLException;
8
import java.text.ParseException;
9
import java.util.ArrayList;
10
import java.util.Arrays;
11
import java.util.Collections;
12
import java.util.HashMap;
13
import java.util.List;
14
import java.util.Map;
15
import java.util.Set;
16

    
17
import javax.sql.DataSource;
18

    
19
import org.geotools.factory.FactoryFinder;
20
import org.geotools.factory.FactoryNotFoundException;
21
import org.geotools.factory.Hints;
22
import org.geotools.metadata.iso.citation.Citations;
23
import org.geotools.referencing.CRS;
24
import org.geotools.referencing.ReferencingFactoryFinder;
25
import org.geotools.referencing.factory.AbstractAuthorityFactory;
26
import org.geotools.referencing.factory.BufferedAuthorityFactory;
27
import org.geotools.referencing.factory.epsg.HsqlEpsgDatabase;
28
import org.geotools.referencing.factory.epsg.ThreadedEpsgFactory;
29
import org.geotools.referencing.wkt.MathTransformParser;
30
import org.geotools.referencing.wkt.Parser;
31
import org.geotools.resources.i18n.ErrorKeys;
32
import org.geotools.resources.i18n.Errors;
33
import org.gvsig.proj.catalog.CRSCatalogManager;
34
import org.gvsig.proj.catalog.CRSDefinition;
35
import org.gvsig.proj.catalog.TextSerialization;
36
import org.gvsig.proj.catalog.TextSerialization.Format;
37
import org.gvsig.proj.catalog.TransformationDefinition;
38
import org.gvsig.proj.catalog.exception.CoordinateReferenceSystemException;
39
import org.gvsig.proj.catalog.exception.UnsupportedCoordinateReferenceSystemException;
40
import org.gvsig.proj.catalog.exception.UnsupportedFormatException;
41
import org.gvsig.proj.catalog.exception.UnsupportedTransformationException;
42
import org.opengis.referencing.AuthorityFactory;
43
import org.opengis.referencing.FactoryException;
44
import org.opengis.referencing.NoSuchAuthorityCodeException;
45
import org.opengis.referencing.crs.CRSAuthorityFactory;
46
import org.opengis.referencing.crs.CRSFactory;
47
import org.opengis.referencing.crs.CompoundCRS;
48
import org.opengis.referencing.crs.CoordinateReferenceSystem;
49
import org.opengis.referencing.crs.GeocentricCRS;
50
import org.opengis.referencing.crs.GeographicCRS;
51
import org.opengis.referencing.cs.CartesianCS;
52
import org.opengis.referencing.cs.CoordinateSystem;
53
import org.opengis.referencing.cs.EllipsoidalCS;
54
import org.opengis.referencing.cs.SphericalCS;
55
import org.opengis.referencing.cs.VerticalCS;
56
import org.opengis.referencing.datum.EngineeringDatum;
57
import org.opengis.referencing.datum.GeodeticDatum;
58
import org.opengis.referencing.datum.VerticalDatum;
59
import org.opengis.referencing.operation.Conversion;
60
import org.opengis.referencing.operation.CoordinateOperation;
61
import org.opengis.referencing.operation.CoordinateOperationAuthorityFactory;
62
import org.opengis.referencing.operation.CoordinateOperationFactory;
63
import org.opengis.referencing.operation.MathTransform;
64
import org.opengis.referencing.operation.Projection;
65

    
66
public class GtCRSCatalogManager implements CRSCatalogManager {
67
        private static final String EPSG_DB_SUBFOLDER = "epsg";        
68
        private static final List<TextSerialization.Format> SUPPORTED_FORMATS = Arrays.asList(TextSerialization.Format.WKT1);
69
        private static final List<String> supportedAuthorities = Collections.unmodifiableList(Arrays.asList("EPSG", "ESRI", "USER"));
70

    
71
        public GtCRSCatalogManager() {
72
                
73
        }
74

    
75
        @Override
76
        public List<String> getAuthorityNames() {
77
                return supportedAuthorities;
78
                //return new ArrayList<String>(CRS.getSupportedAuthorities(true));
79
        }
80
        
81
        protected String toCode(String authorityName, String relCode) {
82
                return authorityName + ":" + relCode;
83
        }
84

    
85
        @Override
86
        public List<String> getCodes() {
87
                ArrayList<String> codes = new ArrayList<String>();
88
                Set<String> authorities = CRS.getSupportedAuthorities(true);
89
                for (String auth: authorities) {
90
                        CRSAuthorityFactory factory = ReferencingFactoryFinder.getCRSAuthorityFactory(auth, null);
91
                        try {
92
                                for (String code: factory.getAuthorityCodes(CoordinateReferenceSystem.class)) {
93
                                        codes.add(toCode(auth, code));
94
                                }
95
                        } catch (FactoryException | FactoryNotFoundException e) {
96
                                // TODO Auto-generated catch block
97
                                e.printStackTrace();
98
                        }
99
                }
100
                return codes;
101
        }
102

    
103
        @Override
104
        public List<String> getCodes(String authorityName) {
105
                // FIXME handle other authorities
106
                ArrayList<String> codes = new ArrayList<String>();
107

    
108
                if ("EPSG".equals(authorityName)) {
109
                        try {
110
                                CRSAuthorityFactory factory = ReferencingFactoryFinder.getCRSAuthorityFactory(authorityName, null);
111
                                for (String code: factory.getAuthorityCodes(CoordinateReferenceSystem.class)) {
112
                                        codes.add(toCode(authorityName, code));
113
                                }
114

    
115
                        } catch (FactoryException | FactoryNotFoundException e) {
116
                                // TODO Auto-generated catch block
117
                                e.printStackTrace();
118
                        }
119
                }
120
                return codes;
121
        }
122

    
123
        @Override
124
        public List<String> search(String searchString) {
125
                // FIXME handle other authorities
126
                return searchEpsg(searchString);
127
        }
128

    
129
        @Override
130
        public List<String> search(String authority, String searchString) {
131
                // FIXME handle other authorities
132
                if (authority.equals("EPSG")) {
133
                        return searchEpsg(searchString);
134
                }
135
                return Collections.emptyList();
136
        }
137
        
138
        protected List<String> searchEpsg(String searchString) {
139
                // FIXME handle other authorities
140
                CRSAuthorityFactory factory = ReferencingFactoryFinder.getCRSAuthorityFactory("EPSG", null);
141
                if (factory instanceof ThreadedEpsgFactory) {
142
                        ThreadedEpsgFactory epsgFactory = (ThreadedEpsgFactory) factory;
143
                        try {
144
                                DataSource ds = epsgFactory.getDataSource();
145
                                Connection c = ds.getConnection();
146
                                return searchEpsg(searchString, c);
147
                        } catch (SQLException e) {
148
                                // TODO Auto-generated catch block
149
                                e.printStackTrace();
150
                        }
151
                }
152
                return Collections.EMPTY_LIST;
153
        }
154
        
155
    public synchronized List<String> searchEpsg(String searchString, Connection conn) throws SQLException
156
    {
157
            ArrayList<String> codes = new ArrayList<String>();
158
            
159
            if (searchString.startsWith("EPSG:")) {
160
                    searchString = searchString.substring(5);
161
            }
162
            searchString = "%" + searchString.toLowerCase() + "%";
163
        try {
164
            // FIXME: JOIN query with area of use. Maybe also with  COORD_SYS_CODE to search for coord sys name
165
            final PreparedStatement stmt;
166
            stmt = conn.prepareStatement("SELECT COORD_REF_SYS_CODE,"
167
                  +       " COORD_REF_SYS_NAME,"
168
                  +       " AREA_OF_USE_CODE,"
169
                  +       " CRS_SCOPE,"
170
                  +       " REMARKS,"
171
                  +       " COORD_REF_SYS_KIND,"
172
                  +       " COORD_SYS_CODE,"       // Null for CompoundCRS
173
                  +       " DATUM_CODE,"           // Null for ProjectedCRS
174
                  +       " SOURCE_GEOGCRS_CODE,"  // For ProjectedCRS
175
                  +       " PROJECTION_CONV_CODE," // For ProjectedCRS
176
                  +       " CMPD_HORIZCRS_CODE,"   // For CompoundCRS only
177
                  +       " CMPD_VERTCRS_CODE"     // For CompoundCRS only
178
                  + " FROM epsg_coordinatereferencesystem"
179
                  + " WHERE COORD_REF_SYS_CODE LIKE ? OR LCASE(COORD_REF_SYS_NAME) LIKE ?"
180
                  + " OR LCASE(REMARKS) LIKE ?"
181
                  + " OR LCASE(CRS_SCOPE) LIKE ?");
182
            stmt.setString(1, searchString);
183
            stmt.setString(2, searchString);
184
            stmt.setString(3, searchString);
185
            stmt.setString(4, searchString);
186
            ResultSet result = stmt.executeQuery();
187
            while (result.next()) {
188
                final String epsg    = result.getString(1);//getString(result, 1, code);
189
                final String name    = result.getString(2);//getString(result, 2, code);
190
                final String area    = result.getString(3);
191
                final String scope   = result.getString(4);
192
                final String remarks = result.getString(5);
193

    
194
                final String csCode  = result.getString(7);
195
                final String dmCode    = result.getString( 8); // geographic
196
                final String geoCode = result.getString(9);
197
                final String opCode  = result.getString(10);
198
                // vertical:
199
                final String code1 = result.getString(11);
200
                final String code2 = result.getString(12);
201
                codes.add(epsg);
202
            }
203
            result.close();
204
        } catch (SQLException exception) {
205
            throw exception;
206
        }
207
        conn.close();
208
        return codes;
209
    }
210

    
211
        @Override
212
        public DefaultCRSDefinition getCRSDefinition(String code) throws UnsupportedCoordinateReferenceSystemException {
213
                CoordinateReferenceSystem crs;
214
                try {
215
                        crs = CRS.decode(code);
216
                } catch (NoSuchAuthorityCodeException e) {
217
                        throw new UnsupportedCoordinateReferenceSystemException(code, e);
218
                } catch (FactoryException e) {
219
                        throw new UnsupportedCoordinateReferenceSystemException(code, e);
220
                }
221
                return new DefaultCRSDefinition(crs);
222
        }
223
        
224
        public DefaultCRSDefinition getCRSDefinition(CoordinateReferenceSystem crs) throws UnsupportedCoordinateReferenceSystemException {
225
                return new DefaultCRSDefinition(crs);
226
        }
227

    
228

    
229
        @Override
230
        public CRSDefinition getCompoundCRS(CRSDefinition... crsList) throws UnsupportedCoordinateReferenceSystemException {
231
                ArrayList<CoordinateReferenceSystem> components = new ArrayList<CoordinateReferenceSystem>();
232
                for (CRSDefinition def: crsList) {
233
                        if (def instanceof DefaultCRSDefinition) {
234
                                components.add(((DefaultCRSDefinition)def).getInternalCRS());        
235
                        }
236
                        else {
237
                                def = new DefaultCRSDefinition(def.toWKT());
238
                        }
239
                }
240
            CRSFactory crsFactory = ReferencingFactoryFinder.getCRSFactory(null);
241
                CoordinateReferenceSystem compoundCRS;
242
                try {
243
                    Map<String, String> properties = new HashMap<String, String>();
244
                    crsFactory.createCompoundCRS(properties, components.toArray(new CoordinateReferenceSystem[components.size()]));
245
                        compoundCRS = crsFactory.createCompoundCRS(properties, components.toArray(new CoordinateReferenceSystem[components.size()]));;
246
                        return new DefaultCRSDefinition(compoundCRS);
247
                } catch (FactoryException e) {
248
                        throw new UnsupportedCoordinateReferenceSystemException(e);
249
                }
250
        }
251
        
252
        @Override
253
        public DefaultCRSDefinition parseCRSDefinition(String def) throws UnsupportedCoordinateReferenceSystemException {
254
                CoordinateReferenceSystem crs;
255
                try {
256
                        crs = CRS.decode(def);
257
                } catch (FactoryException e1) {
258
                        try {
259
                                crs = CRS.parseWKT(def);
260
                        } catch (NoSuchAuthorityCodeException e) {
261
                                throw new UnsupportedCoordinateReferenceSystemException(def, e);
262
                        } catch (FactoryException e) {
263
                                throw new UnsupportedCoordinateReferenceSystemException(def, e);
264
                        }                        
265
                }
266
                return new DefaultCRSDefinition(crs);
267
        }
268
        
269

    
270
        @Override
271
        public DefaultCRSDefinition parseCRSDefinition(String def, Format format)
272
                        throws UnsupportedCoordinateReferenceSystemException, UnsupportedFormatException {
273
                if (SUPPORTED_FORMATS.contains(format)) {
274
                        parseCRSDefinition(def);
275
                }
276
                throw new UnsupportedFormatException(format);
277
        }
278
        
279
        @Override
280
        public TransformationDefinition getTransformationDefinition(String code)
281
                        throws UnsupportedTransformationException {
282
                try {
283
                        AuthorityFactory factory = ReferencingFactoryFinder.getCoordinateOperationAuthorityFactory(
284
                                        "EPSG",
285
                                        null);
286
                        CoordinateOperation op;
287
                        if (factory instanceof AbstractAuthorityFactory) {
288
                                op = ((AbstractAuthorityFactory)factory).createCoordinateOperation(code);
289
                        }
290
                        else {
291
                                Object obj;
292
                                // We need to check the returned object type, since AuthorityFactory.createObject()
293
                                // will not create a CoordinateOperatoin if there is a CRS that has the same code as the coordinate operation 
294
                                obj = factory.createObject(code);
295
                                if (obj instanceof CoordinateOperation) {
296
                                        // we have it
297
                                        op = (CoordinateOperation) obj;
298
                                }
299
                                else { // we found another object having the same code, sigh 
300
                                        throw new UnsupportedTransformationException(code);
301
                                }
302
                        }
303
                        return new DefaultTransformationDefinition(op,
304
                                        getCRSDefinition(op.getSourceCRS()), getCRSDefinition(op.getTargetCRS()));
305
                } catch (FactoryException | CoordinateReferenceSystemException e) {
306
                        throw new UnsupportedTransformationException(code, e);
307
                }
308
        }
309

    
310
        @Override
311
        public TransformationDefinition parseTransformationDefinition(String def, String sourceCRS, String targetCRS)
312
                        throws UnsupportedTransformationException, ParseException {
313
                DefaultCRSDefinition source;
314
                try {
315
                        source = parseCRSDefinition(sourceCRS);
316
                        DefaultCRSDefinition target = parseCRSDefinition(sourceCRS);
317
                        MathTransformParser parser = new MathTransformParser();
318
                        MathTransform mt = parser.parseMathTransform(def);
319
                        return new DefaultTransformationDefinition(mt, source, target);
320
                } catch (CoordinateReferenceSystemException e) {
321
                        throw new UnsupportedTransformationException(e);
322
                }
323
        }
324

    
325
        @Override
326
        public TransformationDefinition parseTransformationDefinition(String def, String sourceCRS, String targetCRS,
327
                        Format format) throws UnsupportedTransformationException, ParseException, UnsupportedFormatException {
328
                if (format==Format.WKT1) {
329
                        return parseTransformationDefinition(def, sourceCRS, targetCRS);
330
                }
331
                throw new UnsupportedFormatException(format);
332
        }
333
        
334
        @Override
335
        public DefaultTransformationDefinition parseTransformationDefinition(String def)
336
                        throws ParseException, CoordinateReferenceSystemException {
337
                // This implementation don't support this method because only WKT1 format is supported,
338
                // but try to parse to raise an indicative exception 
339
                MathTransformParser parser = new MathTransformParser();
340
                parser.parseMathTransform(def);
341
                throw new CoordinateReferenceSystemException("Not enough information to construct the transformation. WKT1 does not encode source and target CRSs");
342
        }
343

    
344
        @Override
345
        public DefaultTransformationDefinition parseTransformationDefinition(String def, Format format)
346
                        throws ParseException, CoordinateReferenceSystemException {
347
                if (SUPPORTED_FORMATS.contains(format)) {
348
                        parseTransformationDefinition(def);
349
                }
350
                throw new UnsupportedFormatException(format);
351
        }
352

    
353
        @Override
354
        public String registerCoordinateReferenceSystem(String wktDefinition, String description) {
355
                // TODO Auto-generated method stub
356
                return null;
357
        }
358

    
359
        @Override
360
        public String registerTransformation(String wktDefinition, String sourceCRS, String targetCRS, String description)
361
                        throws UnsupportedTransformationException, ParseException {
362
                // TODO Auto-generated method stub
363
                return null;
364
        }
365

    
366
        @Override
367
        public String registerCoordinateTransformationPVT(String sourceCRS, String targetCRS, String description,
368
                        float xTraslation, float yTraslation, float zTraslation, float xRotation, float yRotation, float zRotation,
369
                        float scaleDifference) {
370
                // TODO Auto-generated method stub
371
                return null;
372
        }
373

    
374
        @Override
375
        public String registerCoordinateTransformationCFR(String sourceCRS, String targetCRS, String description,
376
                        float xTraslation, float yTraslation, float zTraslation, float xRotation, float yRotation, float zRotation,
377
                        float scaleDifference) {
378
                // TODO Auto-generated method stub
379
                return null;
380
        }
381

    
382
        @Override
383
        public String registerCoordinateTransformation(String sourceCRS, String targetCRS, String description,
384
                        File ntv2Grid) {
385
                // TODO Auto-generated method stub
386
                return null;
387
        }
388

    
389
        @Override
390
        public List<TransformationDefinition> getCoordinateTransformations(CRSDefinition source, CRSDefinition target)
391
                        throws UnsupportedTransformationException {
392
                DefaultCRSDefinition sourceDef = (DefaultCRSDefinition) source;
393
                DefaultCRSDefinition targetDef = (DefaultCRSDefinition) target;
394
                ArrayList<TransformationDefinition> transforms = new ArrayList<TransformationDefinition>();
395
                try {
396
                        CoordinateReferenceSystem sourceCRS = sourceDef.getInternalCRS();
397
                        CoordinateReferenceSystem targetCRS = targetDef.getInternalCRS();
398
                CoordinateOperationFactory operationFactory = CRS.getCoordinateOperationFactory(false);
399
                Set<CoordinateOperation> ops = operationFactory.findOperations(sourceCRS, targetCRS);
400
                for (CoordinateOperation op: ops) {
401
                        DefaultTransformationDefinition def = new DefaultTransformationDefinition(op, sourceDef, targetDef);
402
                        transforms.add(def);
403
                }
404
                } catch (FactoryException e) {
405
                        // FIXME: we should log instead of raising an exception
406
                        throw new UnsupportedTransformationException(e);
407
                }
408
                return transforms;
409
        }
410

    
411
        @Override
412
        public List<TransformationDefinition> getCoordinateTransformations(String source, String target) throws UnsupportedTransformationException {
413
                ArrayList<TransformationDefinition> transforms = new ArrayList<TransformationDefinition>();
414
                try {
415
                        DefaultCRSDefinition sourceDef = getCRSDefinition(source);
416
                        DefaultCRSDefinition targetDef = getCRSDefinition(target);
417
                        CoordinateReferenceSystem sourceCRS = sourceDef.getInternalCRS();
418
                        CoordinateReferenceSystem targetCRS = targetDef.getInternalCRS();
419
                CoordinateOperationFactory operationFactory = CRS.getCoordinateOperationFactory(false);
420
                Set<CoordinateOperation> ops = operationFactory.findOperations(sourceCRS, targetCRS);
421
                for (CoordinateOperation op: ops) {
422
                        DefaultTransformationDefinition def = new DefaultTransformationDefinition(op, sourceDef, targetDef);
423
                        transforms.add(def);
424
                }
425
                } catch (FactoryException | UnsupportedCoordinateReferenceSystemException e) {
426
                        // FIXME: we should log instead of raising an exception
427
                        throw new UnsupportedTransformationException(e);
428
                }
429
                return transforms;
430
        }
431

    
432
        /**
433
         * Sets the path to the folder to be used by the library to load the CRS and
434
         * transformation definitions. The specified path must contain one or more subfolders,
435
         * containg the CRS and transformation database in the appropriate format:
436
         * <ul><li>for EPSG database: a "epsg" subfolder must exist, which contains a HSQL database
437
         * called "EPSG". The structure of this database must be the same used by Geotools,
438
         * which is essentially based in the EPSG data model.</li>
439
         * </ul>
440
         * 
441
         * This method only has effect when it is called before any other method in the manager
442
         * (before instantiating any CRS, transformation, etc). 
443
         * 
444
         * @param path The path to the folder containing the system CRS and transformation
445
         * definitions
446
         */
447
        @Override
448
        public void setSystemDataPath(File path) {
449
                System.setProperty(HsqlEpsgDatabase.DIRECTORY_KEY, path.getAbsolutePath() + "/" + EPSG_DB_SUBFOLDER);
450
        }
451

    
452
        @Override
453
        public void setUserDataPath(File path) {
454
                // TODO Auto-generated method stub
455
                
456
        }
457

    
458
        @Override
459
        public List<TextSerialization.Format> getSupportedFormats() {
460
                // TODO Auto-generated method stub
461
                return SUPPORTED_FORMATS;
462
        }
463

    
464
}