Statistics
| Revision:

root / org.gvsig.projection.jcrs / trunk / org.gvsig.projection.jcrs / org.gvsig.projection.jcrs.lib / src / main / java / org / gvsig / crs / CrsFactory.java @ 822

History | View | Annotate | Download (20.7 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2006 Instituto de Desarrollo Regional and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 */
19
package org.gvsig.crs;
20

    
21
import es.idr.teledeteccion.connection.EpsgConnection;
22
import es.idr.teledeteccion.connection.Query;
23
import es.idr.teledeteccion.connection.epsg.HSQLDataSource;
24

    
25
import java.io.File;
26
import java.sql.ResultSet;
27
import java.sql.SQLException;
28
import java.util.TreeMap;
29
import java.util.Vector;
30

    
31
import org.apache.commons.lang3.StringUtils;
32
import org.cresques.cts.ICRSFactory;
33
import org.cresques.cts.IProjection;
34
import org.gdal.gdal.gdal;
35
import org.gdal.osr.SpatialReference;
36
import org.gvsig.crs.repository.EpsgRepository;
37
import org.gvsig.crs.repository.EpsgRepositoryGT;
38
import org.gvsig.crs.repository.EsriRepository;
39
import org.gvsig.crs.repository.EsriRepositoryGT;
40
import org.gvsig.crs.repository.ICrsRepository;
41
import org.gvsig.crs.repository.Iau2000Repository;
42
import org.gvsig.crs.repository.Iau2000RepositoryGT;
43
import org.gvsig.crs.repository.NoAuthRepository;
44
import org.gvsig.crs.repository.NoAuthRepositoryGT;
45
import org.gvsig.crs.repository.UsrRepository;
46
import org.gvsig.crs.repository.UsrRepositoryGT;
47
import org.gvsig.tools.dispose.Disposable;
48
import org.slf4j.Logger;
49
import org.slf4j.LoggerFactory;
50

    
51
/**
52
 * Clase que consigue el CRS a trav?s del c?digo de la EPSG o de
53
 * la cadena WKT
54
 *
55
 * @author Diego Guerrero Sevilla (diego.guerrero@uclm.es)
56
 * @param <E>
57
 *
58
 */
59
public class CrsFactory<E> implements ICRSFactory {
60

    
61
    private static Logger logger = LoggerFactory.getLogger(CrsFactory.class);
62
    static TreeMap data = new TreeMap();
63

    
64
    private static File databaseFolder = null;
65
    private static File projLibFolder = null;
66
    private static boolean enableMemoryCache = true;
67
    private static File epsgDatabaseFile = null;
68

    
69
    public CrsFactory() {
70
    }
71

    
72
    /**
73
     * Obtiene un CRS a partir de su c?digo (p.e. EPSG:23030).
74
     *
75
     * @param code
76
     * @return
77
     * @throws CrsException
78
     */
79
    public ICrs getCRS(String code) throws CrsException {
80
        return getCRS(code,null,null);
81
    }
82

    
83
    public ICrs getCRS(String code, String theSourceParams, String theTargetParams) throws CrsException {
84

    
85
        String keyOfCache = getKeyOfCache(code,theSourceParams,theTargetParams);
86
        if (enableMemoryCache && data.containsKey(keyOfCache)) {
87
            return (ICrs) data.get(keyOfCache);
88
        }
89
        String sourceParams = theSourceParams;
90
        String targetParams = theTargetParams;
91
        String crsCode = code;
92

    
93
        ICrs crs = null;
94

    
95
        if ( code.indexOf(":", code.indexOf(":") + 1) >= 0 ) {
96
            crsCode = code.substring(0, code.indexOf(":", code.indexOf(":") + 1));
97
            if ( code.indexOf("@") == -1 ) {
98
                crsCode = crsCode.substring(0, crsCode.indexOf(","));
99
            } else {
100
                sourceParams = code.substring(code.indexOf("@") + 1, code.lastIndexOf("@"));
101
                targetParams = code.substring(code.lastIndexOf("@") + 1);
102

    
103
                if ( sourceParams.equals("") ) {
104
                    sourceParams = null;
105
                } else if ( targetParams.equals("1") ) { // Compatibilidad con versiones de libJCrs sin soporte para transf. compuestas.
106
                    targetParams = sourceParams;
107
                    sourceParams = "";
108
                }
109
                if ( targetParams.equals("") || targetParams.equals("0") ) // Compatibilidad con versiones de libJCrs sin soporte para transf. compuestas.
110
                {
111
                    targetParams = null;
112
                }
113
            }
114
        }
115
        crs = getSimpleCRS(crsCode);
116
        if( sourceParams!=null || targetParams!=null ) {
117
            crs.setTransformationParams(sourceParams, targetParams);
118
        }
119

    
120
        if( enableMemoryCache ) {
121
            keyOfCache = getKeyOfCache(crsCode,sourceParams,targetParams);
122
            data.put(keyOfCache, crs);
123
        }
124

    
125

    
126
        return crs;
127
    }
128

    
129
    private String getKeyOfCache(String code, String theSourceParams, String theTargetParams) {
130
        String keyOfCache = code;
131
        if( theSourceParams!=null ) {
132
            keyOfCache += ":proj@" + theSourceParams + "@";
133
            if( theTargetParams!=null ) {
134
                keyOfCache += theTargetParams;
135
            }
136
        }
137
        return keyOfCache;
138
    }
139

    
140
    private ICrs getSimpleCRS(String code) throws CrsException {
141

    
142
        String repoId = "";
143
        String crsCode = "";
144
        ICrs crs = null;
145
        ICrsRepository repo = null;
146

    
147
        try {
148
                repoId = code.substring(0, code.indexOf(":"));
149
                crsCode = code.substring(code.indexOf(":") + 1);
150

    
151
                if ( repoId.equals("EPSG") ) {
152
                    repo = new EpsgRepositoryGT();
153
                    crs = repo.getCrs(crsCode);
154
                    if ( crs == null ) {
155
                        repo = new EpsgRepository();
156
                        crs = repo.getCrs(crsCode);
157
                    }
158
                } else if ( repoId.equals("IAU2000") ) {
159
                    repo = new Iau2000RepositoryGT();
160
                    crs = repo.getCrs(crsCode);
161
                    if ( crs == null ) {
162
                        repo = new Iau2000Repository();
163
                        crs = repo.getCrs(crsCode);
164
                    }
165
                } else if ( repoId.equals("CRS") ) {
166
                    repo = new NoAuthRepositoryGT();
167
                    crs = repo.getCrs(crsCode);
168
                    if ( crs == null ) {
169
                        repo = new NoAuthRepository();
170
                        crs = repo.getCrs(crsCode);
171
                    }
172
                } else if ( repoId.equals("ESRI") ) {
173
                    repo = new EsriRepositoryGT();
174
                    crs = repo.getCrs(crsCode);
175
                    if ( crs == null ) {
176
                        repo = new EsriRepository();
177
                        crs = repo.getCrs(crsCode);
178
                    }
179
                } else if ( repoId.equals("USR") ) {
180
                    repo = new UsrRepositoryGT();
181
                    crs = repo.getCrs(crsCode);
182
                    if ( crs == null ) {
183
                        repo = new UsrRepository();
184
                        crs = repo.getCrs(crsCode);
185
                    }
186
                }
187
                if ( crs == null ) {
188
                    logger.debug("Can't find CRS '" + code + "' in available repositories.");
189
                } else {
190
                    logger.debug("Found CRS '" + code + "' in repository '" +
191
                            (repo == null ? "unknow" : (repo.getClass().getSimpleName())) + "'.");
192
                }
193
                return crs;
194
        } finally {
195
            if( repo instanceof Disposable ) {
196
                ((Disposable)repo).dispose();
197
            }
198
        }
199
    }
200

    
201

    
202
    /**
203
     *
204
     * @param epsg_code
205
     * @param code
206
     * @return
207
     * @throws CrsException
208
     */
209
    public ICrs getCRS(int epsg_code, String code) throws CrsException {
210
        Crs crs = new Crs(epsg_code, code);
211
        return crs;
212
    }
213

    
214
    /**
215
     *
216
     * @param epsg_code
217
     * @param code
218
     * @param params
219
     * @return
220
     * @throws CrsException
221
     */
222
    public ICrs getCRS(int epsg_code, String code, String params) throws CrsException {
223
        Crs crs = new Crs(epsg_code, code, params);
224
        return crs;
225
    }
226

    
227
    /**
228
     *
229
     */
230
    public IProjection get(String name) {
231
        try {
232
            return getCRS(name,null,null);
233
        } catch (CrsException e) {
234
            logger.error("Can't get CRS name '" + name + "'.", e);
235
        }
236
        return null;
237
    }
238

    
239
    /**
240
     *
241
     */
242
    public boolean doesRigurousTransformations() {
243
        return true;
244
    }
245

    
246
    public static File getDataBaseFolder() {
247
        return databaseFolder;
248
    }
249

    
250
    public static void setDataBaseFolder(File folder) {
251
        databaseFolder = folder;
252
    }
253

    
254
    public static File getProjLibFolder() {
255
        return projLibFolder;
256
    }
257

    
258
    public static void setProjLibFolder(File folder) {
259
        projLibFolder = folder;
260
    }
261

    
262
    public static void setEnableMemoryCacheOfCRS(boolean enableMemoryCache) {
263
        CrsFactory.enableMemoryCache = enableMemoryCache;
264
    }
265

    
266
    public static boolean isEnableMemoryCacheOfCRS() {
267
        return enableMemoryCache;
268
    }
269

    
270
    public static File getEpsgDatabaseFile() {
271
        if ( epsgDatabaseFile == null ) {
272
            epsgDatabaseFile = new File(getDataBaseFolder(), "EPSG.sql");
273
        }
274
        return epsgDatabaseFile;
275

    
276
    }
277

    
278
    public static void setEpsgDatabaseFile(File databaseFile) {
279
       epsgDatabaseFile = databaseFile;
280
        if ( !epsgDatabaseFile.isAbsolute() ) {
281
            epsgDatabaseFile = new File(getDataBaseFolder(), epsgDatabaseFile.getPath());
282
        }
283
    }
284

    
285
    public static void initializeDatabase() {
286
        try {
287
            HSQLDataSource ds = new HSQLDataSource();
288
            ds.initializeDatabase();
289
        } catch (SQLException ex) {
290
            logger.warn("Can't initialize the database.",ex);
291
        }
292
    }
293

    
294
    public static void initializeDatabaseInbackground() {
295
        Thread th = new Thread(new Runnable() {
296
                public void run() {
297
                    CrsFactory.initializeDatabase();
298
                }
299
            },
300
            "EPSG-Initialization"
301
        );
302
        th.start();
303
    }
304

    
305
    public IProjection get(String format, String value) {
306
        if (ICRSFactory.FORMAT_WKT_ESRI.equalsIgnoreCase(format)) {
307
            gdal.SetConfigOption("GDAL_FIX_ESRI_WKT", "NO"); // NO, TOWGS84, DATUM and GEOGCS
308
            SpatialReference sr = new SpatialReference();
309
            Vector<String> vector = new Vector<String>();
310
            vector.add(value);
311
            try {
312
                sr.ImportFromESRI(vector);
313
                sr.Fixup();
314
            } catch (Exception e) {
315
                logger.debug("Can't import from ESRI WKT.", e);
316
                return null;
317
            }
318
            SpatialReference sr2 = getFixedSpatiaReference(sr);
319
            if( sr2==null ) {
320
                return null;
321
            }
322
            return new Crs(sr);
323
         
324
        } else if (ICRSFactory.FORMAT_WKT.equalsIgnoreCase(format)) {
325
            SpatialReference sr = getSpatialReferenceFromWKT(value);
326
            return new Crs(sr);
327

    
328
        } else if (ICRSFactory.FORMAT_PROJ4.equalsIgnoreCase(format)) {
329
            SpatialReference sr = new SpatialReference();
330
            sr.ImportFromProj4(value);
331
            return new Crs(sr);
332
        }
333
        return null;
334
    }
335
    
336
    public static SpatialReference getSpatialReferenceFromWKT(String wkt) {
337
            SpatialReference sr = new SpatialReference();
338
            sr.ImportFromWkt(wkt);
339
            SpatialReference sr2 = getFixedSpatiaReference(sr);
340
            if( sr2==null ) {
341
                return sr;
342
            }
343
            return sr2;
344
    }
345

    
346
    private static SpatialReference getFixedSpatiaReference(SpatialReference sr) {
347
        try {
348
            sr.AutoIdentifyEPSG();
349
            String authorityCode = sr.GetAuthorityCode(null);
350
            if (!StringUtils.isEmpty(authorityCode)) {
351
                logger.debug("AuthorityCode: " + authorityCode);
352
                return sr;
353
            }
354
        } catch (Exception e) {
355
            logger.debug("Can't AutoIdentifyEPSG.", e);
356
        }
357
        boolean bProj4;
358
        try {
359
            @SuppressWarnings("unused")
360
            String proj4 = sr.ExportToProj4();
361
            bProj4 = true;
362
        } catch (Exception e2) {
363
            logger.debug("Can't ExportToProj4.", e2);
364
            bProj4 = false;
365
        }
366
        int code;
367
        try {
368
            code = identifyEPSG(sr, bProj4);
369
            if ((code == 0) && (bProj4 == true)) {
370
                code = identifyESRI(sr);
371
                if (code == -1) {
372
                    code = identifyEPSG(sr, false);
373
                    if (code == 0) {
374
                        return null;
375
                    }
376
                }
377
            }
378
        } catch (SQLException e3) {
379
            return null;
380
        }
381
        SpatialReference sr2 = new SpatialReference();
382
        try {
383
            sr2.ImportFromEPSG(code);
384
            return sr2;
385
        } catch (Exception e4) {
386
            logger.warn("Can't find the best candidate.", e4);
387
            return null;
388
        }
389
    }
390
    
391
    private static int identifyEPSG(SpatialReference sr, boolean bProj4) throws SQLException {
392

    
393
        int best_code = 0;
394
        int best_dist = 99;
395
        int dist = 99;
396

    
397
        String kind = null;
398
        String attr = null;
399
        if (sr.IsGeographic() == 1) {
400
            kind = "geographic 2D";
401
            attr = "GEOGCS";
402
        } else {
403
            if (sr.IsProjected() == 1) {
404
                kind = "projected";
405
                attr = "PROJCS";
406
            }
407
        }
408

    
409
        String source_sr_name = sr.GetAttrValue(attr);
410
        sr.StripCTParms();
411

    
412
        EpsgConnection conn = new EpsgConnection();
413
        conn.setConnectionEPSG();
414

    
415
        String sql = "SELECT coord_ref_sys_code FROM EPSG_COORDINATEREFERENCESYSTEM WHERE coord_ref_sys_kind = '"
416
                + kind + "' AND REPLACE(REPLACE(LOWER(coord_ref_sys_name),' / ',' '),'-',' ') LIKE '%"
417
                + normalizeESRI(source_sr_name) + "%' AND deprecated = 0";
418
        logger.debug(sql);
419

    
420
        ResultSet result = Query.select(sql, conn.getConnection());
421

    
422
        while (result.next()) {
423
            int code = result.getInt("coord_ref_sys_code");
424
            try {
425
                logger.debug("Trying to match EPSG:{}...", code);
426
                SpatialReference target_sr = new SpatialReference();
427
                target_sr.ImportFromEPSG(code);
428
                String target_sr_name = target_sr.GetAttrValue(attr);
429
                target_sr.StripCTParms();
430
                logger.debug("Source SR name: {}", source_sr_name);
431
                logger.debug("Target SR name: {}", target_sr_name);
432
                if (bProj4) {
433
                    String source_proj4 = sr.ExportToProj4();
434
                    String target_proj4 = target_sr.ExportToProj4();
435
                    logger.debug("Source proj4: {}", source_proj4);
436
                    logger.debug("Target proj4: {}", target_proj4);
437
                    if (StringUtils.equals(source_proj4, target_proj4)) {
438
                        dist = StringUtils.getLevenshteinDistance(normalizeESRI(source_sr_name), normalizeEPSG(target_sr_name));
439
                        if (dist == 0) {
440
                            logger.debug("EPSG:{} matches!", code);
441
                            return code;
442
                        }
443
                    }
444
                } else {
445
                    dist = StringUtils.getLevenshteinDistance(normalizeESRI(source_sr_name), normalizeEPSG(target_sr_name));
446
                    if (dist == 0) {
447
                        logger.debug("EPSG:{} matches!", code);
448
                        return code;
449
                    }
450
                }
451
                if (dist < best_dist) {
452
                    best_dist = dist;
453
                    best_code = code;
454
                }
455
            } catch (Exception e) {
456
                logger.debug("Can't ImportFromEPSG.", e);
457
            }
458

    
459
        }
460

    
461
        if (best_code > 0) { // && best_dist <= 5
462
            logger.debug("EPSG:{} is the best match (Levenshtein Distance = {}).", best_code, best_dist);
463
        } /*else {
464
            //best_code = 0;
465
            logger.debug("No EPSG code matches!");
466
        }*/
467
        return best_code;
468
    }
469

    
470
    private static int identifyESRI(SpatialReference sr) throws SQLException {
471

    
472
        int code0 = -1;
473

    
474
        EpsgConnection conn = new EpsgConnection();
475
        conn.setConnectionEsri();
476

    
477
        String sql = "";
478
        if (sr.IsGeographic() == 1) {
479
            sql = "SELECT ESRI_CODE, ESRI_WKT FROM ESRI WHERE ESRI_WKT LIKE 'GEOGCS%'"
480
                    + " AND ESRI_GEOG LIKE '" + sr.GetAttrValue("GEOGCS") + "'";
481
        } else {
482
            if (sr.IsProjected() == 1) {
483
                sql = "SELECT ESRI_CODE, ESRI_WKT FROM ESRI WHERE ESRI_WKT LIKE 'PROJCS%'"
484
                        + " AND ESRI_PROJ LIKE '" + sr.GetAttrValue("PROJCS") + "'";
485
            }
486
        }
487
        logger.debug(sql);
488

    
489
        ResultSet result = Query.select(sql, conn.getConnection());
490

    
491
        while (result.next()) {
492
            int code = result.getInt("ESRI_CODE");
493
            String wkt = result.getString("ESRI_WKT");
494
            logger.debug("Trying to match ESRI:{}...", code);
495
            try {
496
                SpatialReference target_sr = new SpatialReference();
497
                target_sr.ImportFromWkt(wkt);
498
                target_sr.MorphFromESRI();
499
                String source_proj4 = sr.ExportToProj4();
500
                String target_proj4 = target_sr.ExportToProj4();
501
                if (StringUtils.equals(source_proj4, target_proj4)) {
502
                    conn.close();
503
                    logger.debug("ESRI:{} matches!", code);
504
                    return code;
505
                }
506
            } catch (Exception e) {
507
                //logger.debug("Can't identify the ESRI code...");
508
            }
509
        }
510
        
511
        conn.close();
512
        logger.debug("Can't identify the ESRI code...");
513
        return code0;
514
    }
515

    
516
    private static String normalizeESRI(String sr_name) {
517
        String name;
518
        name = StringUtils.replace(sr_name, "GCS_", "");
519
        name = StringUtils.replaceChars(name, "()", "");
520
        name = StringUtils.replace(name, "WGS_19", "WGS "); // e.g. WGS_1984 --> WGS 84
521
        name = StringUtils.replace(name, "_19", ""); // e.g. NAD_1927 --> NAD27
522
        name = StringUtils.replace(name, "_20", "20"); // e.g. ITRF_2008 --> ITRF2008
523
        name = StringUtils.replace(name, "_Adj_1958", "(58)");
524
        name = StringUtils.replace(name, "_Bern", " (Bern)");
525
        name = StringUtils.replace(name, "_CGQ77", "(CGQ77)");
526
        name = StringUtils.replace(name, "_CORS96", "(CORS96)");
527
        name = StringUtils.replace(name, "_CSRS", "(CSRS)");
528
        name = StringUtils.replace(name, "_DEF_1976", "(76)");
529
        name = StringUtils.replace(name, "_ED77", "(ED77)");
530
        name = StringUtils.replace(name, "_HARN", "(HARN)");
531
        name = StringUtils.replace(name, "_MA11", "(MA11)");
532
        name = StringUtils.replace(name, "_NSRS2007", "(NSRS2007)");
533
        name = StringUtils.replace(name, "_PA11", "(PA11)");
534
        name = StringUtils.replace(name, "_StatePlane", "");
535
        name = StringUtils.replaceAll(name, "(_FIPS_)\\d{4}", "");
536
        name = StringUtils.replaceAll(name, "_m$", "(m)");
537
        
538
        name = StringUtils.replace(name, "1870_Madrid", "1870 (Madrid)");
539
        name = StringUtils.replace(name, "83_2011", "83(2011)"); // e.g. NAD_1983_2011 --> NAD83(2011)
540
        name = StringUtils.replaceAll(name, "Feet_Intl$", "(ft)");
541
        name = StringUtils.replaceAll(name, "Feet$", "(ftUS)");
542
        name = StringUtils.replace(name, "Ferro", "(Ferro)");
543
        name = StringUtils.replaceAll(name, "ftUS$", "(ftUS)");
544
        name = StringUtils.replaceAll(name, "ft$", "(ft)");
545
        name = StringUtils.replace(name, "Hungarian_1972", "HD72");
546
        name = StringUtils.replace(name, "Indonesian_1974", "ID74");
547
        name = StringUtils.replace(name, "Lisboa", "Lisbon");
548
        name = StringUtils.replace(name, "Lisbon_Lisbon", "Lisbon (Lisbon)");
549
        name = StringUtils.replace(name, "MGI_M", "MGI Austria M"); //"MGI_M" --> "MGI / Austria M"
550
        name = StringUtils.replace(name, "New_Brunswick_Stereographic", "New Brunswick Stereographic (ATS77)");
551
        name = StringUtils.replace(name, "Oslo_Norway", "(Oslo) NGO");
552
        name = StringUtils.replace(name, "Paris", "(Paris)");
553
        name = StringUtils.replace(name, "St_", "St. ");
554
        name = StringUtils.replace(name, "TC_1948", "TC(1948)");
555
        
556
        name = StringUtils.replace(name, "_", " ");
557
        name = StringUtils.replace(name, "-", " ");
558
        name = StringUtils.lowerCase(name);
559
        return name;
560
    }
561
    
562
    private static String normalizeEPSG(String sr_name) {
563
        String name;
564
        name = StringUtils.replace(sr_name, " / ", " ");
565
        name = StringUtils.replace(name, "-", " ");
566
        name = StringUtils.lowerCase(name);
567
        return name;
568
    }
569

    
570
    /* (non-Javadoc)
571
     * @see org.cresques.cts.ICRSFactory#export(java.lang.String, org.cresques.cts.IProjection)
572
     */
573
    public String export(String format, IProjection proj) {
574
        return proj.export(format);
575
    }
576
}