001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/src/org/deegree/crs/configuration/AbstractCRSProvider.java $ 002 /*---------------------------------------------------------------------------- 003 This file is part of deegree, http://deegree.org/ 004 Copyright (C) 2001-2009 by: 005 Department of Geography, University of Bonn 006 and 007 lat/lon GmbH 008 009 This library is free software; you can redistribute it and/or modify it under 010 the terms of the GNU Lesser General Public License as published by the Free 011 Software Foundation; either version 2.1 of the License, or (at your option) 012 any later version. 013 This library is distributed in the hope that it will be useful, but WITHOUT 014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 015 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 016 details. 017 You should have received a copy of the GNU Lesser General Public License 018 along with this library; if not, write to the Free Software Foundation, Inc., 019 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 020 021 Contact information: 022 023 lat/lon GmbH 024 Aennchenstr. 19, 53177 Bonn 025 Germany 026 http://lat-lon.de/ 027 028 Department of Geography, University of Bonn 029 Prof. Dr. Klaus Greve 030 Postfach 1147, 53001 Bonn 031 Germany 032 http://www.geographie.uni-bonn.de/deegree/ 033 034 e-mail: info@deegree.org 035 ----------------------------------------------------------------------------*/ 036 037 package org.deegree.crs.configuration; 038 039 import static org.deegree.crs.utilities.MappingUtils.matchEPSGString; 040 041 import java.io.IOException; 042 import java.lang.reflect.Constructor; 043 import java.lang.reflect.InvocationTargetException; 044 import java.util.HashMap; 045 import java.util.Map; 046 import java.util.Properties; 047 048 import org.deegree.crs.Identifiable; 049 import org.deegree.crs.components.GeodeticDatum; 050 import org.deegree.crs.configuration.resources.CRSResource; 051 import org.deegree.crs.coordinatesystems.CompoundCRS; 052 import org.deegree.crs.coordinatesystems.CoordinateSystem; 053 import org.deegree.crs.coordinatesystems.GeographicCRS; 054 import org.deegree.crs.coordinatesystems.ProjectedCRS; 055 import org.deegree.crs.exceptions.CRSConfigurationException; 056 import org.deegree.crs.projections.azimuthal.LambertAzimuthalEqualArea; 057 import org.deegree.crs.projections.azimuthal.StereographicAlternative; 058 import org.deegree.crs.projections.azimuthal.StereographicAzimuthal; 059 import org.deegree.crs.projections.conic.LambertConformalConic; 060 import org.deegree.crs.projections.cylindric.TransverseMercator; 061 import org.deegree.crs.transformations.Transformation; 062 import org.deegree.crs.transformations.coordinate.GeocentricTransform; 063 import org.deegree.crs.transformations.coordinate.NotSupportedTransformation; 064 import org.deegree.crs.transformations.helmert.Helmert; 065 import org.deegree.crs.transformations.polynomial.PolynomialTransformation; 066 import org.deegree.framework.log.ILogger; 067 import org.deegree.framework.log.LoggerFactory; 068 import org.deegree.i18n.Messages; 069 070 /** 071 * add class documentation here. 072 * 073 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a> 074 * 075 * @author last edited by: $Author: rbezema $ 076 * 077 * @version $Revision: 23328 $, $Date: 2010-03-30 17:40:30 +0200 (Di, 30 Mär 2010) $ 078 * @param <T> 079 * the type of object the parse method awaits. 080 * 081 */ 082 public abstract class AbstractCRSProvider<T> implements CRSProvider { 083 084 private static ILogger LOG = LoggerFactory.getLogger( AbstractCRSProvider.class ); 085 086 private Map<String, Identifiable> cachedIdentifiables = new HashMap<String, Identifiable>( 42124 ); 087 088 private CRSResource<T> resolver; 089 090 /** 091 * @param <K> 092 * @param properties 093 * @param subType 094 * @param defaultResolver 095 */ 096 @SuppressWarnings("unchecked") 097 public <K extends CRSResource<T>> AbstractCRSProvider( Properties properties, Class<K> subType, 098 CRSResource<T> defaultResolver ) { 099 if ( properties == null ) { 100 throw new IllegalArgumentException( "The properties may not be null." ); 101 } 102 String className = properties.getProperty( "CRS_RESOURCE" ); 103 if ( className == null || "".equals( className.trim() ) ) { 104 if ( defaultResolver != null ) { 105 LOG.logWarning( "Found no configured CRS-Resource to use, trying default: " 106 + defaultResolver.getClass().getCanonicalName() ); 107 resolver = defaultResolver; 108 } else { 109 LOG.logDebug( "Found no configured CRS-Resource and no default crs resource supplied, hoping for the set method." ); 110 } 111 } else { 112 try { 113 Class<?> tc = null; 114 if ( subType == null ) { 115 StringBuilder sb = new StringBuilder( "No subtype suplied trying to use " ); 116 if ( defaultResolver != null ) { 117 sb.append( " the default resolver: " ); 118 tc = defaultResolver.getClass(); 119 } else { 120 tc = CRSResource.class; 121 } 122 sb.append( tc.getCanonicalName() ).append( " to create a subtype from. " ); 123 LOG.logWarning( sb.toString() ); 124 } else { 125 tc = Class.forName( subType.getName() ); 126 } 127 // use reflection to instantiate the configured provider. 128 Class<?> t = Class.forName( className ); 129 t.asSubclass( tc ); 130 LOG.logDebug( "Trying to load configured CRS provider from classname: " + className ); 131 Constructor<?> constructor = t.getConstructor( this.getClass(), Properties.class ); 132 if ( constructor == null ) { 133 LOG.logError( "No constructor ( " + this.getClass() + ", Properties.class) found in class:" 134 + className ); 135 } else { 136 resolver = (K) constructor.newInstance( this, properties ); 137 } 138 } catch ( InstantiationException e ) { 139 LOG.logError( Messages.getMessage( "CRS_CONFIG_INSTANTIATION_ERROR", className, e.getMessage() ) ); 140 } catch ( IllegalAccessException e ) { 141 LOG.logError( Messages.getMessage( "CRS_CONFIG_INSTANTIATION_ERROR", className, e.getMessage() ), e ); 142 } catch ( ClassNotFoundException e ) { 143 LOG.logError( Messages.getMessage( "CRS_CONFIG_INSTANTIATION_ERROR", className, e.getMessage() ), e ); 144 } catch ( SecurityException e ) { 145 LOG.logError( Messages.getMessage( "CRS_CONFIG_INSTANTIATION_ERROR", className, e.getMessage() ), e ); 146 } catch ( NoSuchMethodException e ) { 147 LOG.logError( Messages.getMessage( "CRS_CONFIG_INSTANTIATION_ERROR", className, e.getMessage() ), e ); 148 } catch ( IllegalArgumentException e ) { 149 LOG.logError( Messages.getMessage( "CRS_CONFIG_INSTANTIATION_ERROR", className, e.getMessage() ), e ); 150 } catch ( InvocationTargetException e ) { 151 LOG.logError( Messages.getMessage( "CRS_CONFIG_INSTANTIATION_ERROR", className, e.getMessage() ), e ); 152 } catch ( Throwable t ) { 153 LOG.logError( Messages.getMessage( "CRS_CONFIG_INSTANTIATION_ERROR", className, t.getMessage() ), t ); 154 } finally { 155 if ( resolver == null ) { 156 LOG.logInfo( "The configured class: " + className + " was not instantiated." ); 157 if ( defaultResolver != null ) { 158 LOG.logInfo( "Trying to instantiate the default resolver: " 159 + defaultResolver.getClass().getCanonicalName() ); 160 resolver = defaultResolver; 161 } else { 162 LOG.logWarning( "No default crs resource supplied, hoping for the set method." ); 163 } 164 } 165 } 166 } 167 } 168 169 public CoordinateSystem getCRSByID( String id ) 170 throws CRSConfigurationException { 171 if ( resolver == null ) { 172 throw new CRSConfigurationException( "No resolver initialized, this may not be." ); 173 } 174 CoordinateSystem result = null; 175 if ( id != null && !"".equals( id.trim() ) ) { 176 LOG.logDebug( "Trying to load crs with id: " + id + " from cache." ); 177 if ( LOG.isDebug() ) { 178 LOG.logDebug( cachedIdentifiables.keySet().toString() ); 179 } 180 if ( cachedIdentifiables.containsKey( id ) ) { 181 Identifiable r = cachedIdentifiables.get( id ); 182 LOG.logDebug( "Found Identifiable: " + r.getIdAndName() + " from given id: " + id ); 183 if ( !( r instanceof CoordinateSystem ) ) { 184 LOG.logError( "Found Identifiable: " + r.getIdAndName() 185 + " but it is not a coordinate system, your db is inconsistend return null." ); 186 r = null; 187 } 188 result = (CoordinateSystem) r; 189 } 190 if ( result == null ) { 191 LOG.logDebug( "No crs with id: " + id + " found in cache." ); 192 try { 193 result = parseCoordinateSystem( resolver.getURIAsType( id ) ); 194 } catch ( IOException e ) { 195 LOG.logDebug( e.getLocalizedMessage(), e ); 196 throw new CRSConfigurationException( e ); 197 } 198 if ( result != null ) { 199 GeographicCRS t = null; 200 if ( result.getType() == CoordinateSystem.COMPOUND_CRS ) { 201 if ( ( (CompoundCRS) result ).getUnderlyingCRS().getType() == CoordinateSystem.PROJECTED_CRS ) { 202 t = ( (ProjectedCRS) ( (CompoundCRS) result ).getUnderlyingCRS() ).getGeographicCRS(); 203 } else if ( ( (CompoundCRS) result ).getUnderlyingCRS().getType() == CoordinateSystem.GEOGRAPHIC_CRS ) { 204 t = (GeographicCRS) ( (CompoundCRS) result ).getUnderlyingCRS(); 205 } else { 206 LOG.logWarning( "Wgs84 Transformation lookup is currently only supported for GeographicCRS-chains." ); 207 } 208 } else if ( result.getType() == CoordinateSystem.PROJECTED_CRS ) { 209 t = ( (ProjectedCRS) result ).getGeographicCRS(); 210 } else if ( result.getType() == CoordinateSystem.GEOGRAPHIC_CRS ) { 211 t = (GeographicCRS) result; 212 } else { 213 LOG.logWarning( "Wgs84 Transformation lookup is currently only supported for GeographicCRS-chains." ); 214 } 215 if ( t != null ) { 216 Helmert wgs84 = t.getGeodeticDatum().getWGS84Conversion(); 217 if ( wgs84 == null ) { 218 wgs84 = resolver.getWGS84Transformation( t ); 219 } 220 if ( wgs84 != null ) { 221 if ( wgs84.getSourceCRS() == null ) { 222 wgs84.setSourceCRS( t ); 223 addIdToCache( wgs84, true ); 224 } 225 GeodeticDatum datum = result.getGeodeticDatum(); 226 if ( datum != null ) { 227 datum.setToWGS84( wgs84 ); 228 // update the cache as well 229 addIdToCache( datum, true ); 230 } 231 232 } 233 } 234 } 235 } 236 } 237 if ( result == null ) { 238 LOG.logDebug( "The id: " 239 + id 240 + " could not be mapped to a valid deegree-crs, currently projectedCRS, geographicCRS, compoundCRS and geocentricCRS are supported." ); 241 } else { 242 /** 243 * Adding the used underlying crs's to the cache. 244 */ 245 addIdToCache( result, false ); 246 if ( result.getType() == CoordinateSystem.COMPOUND_CRS ) { 247 addIdToCache( ( (CompoundCRS) result ).getUnderlyingCRS(), false ); 248 if ( ( (CompoundCRS) result ).getUnderlyingCRS().getType() == CoordinateSystem.PROJECTED_CRS ) { 249 addIdToCache( ( (ProjectedCRS) ( (CompoundCRS) result ).getUnderlyingCRS() ).getGeographicCRS(), 250 false ); 251 } 252 } else if ( result.getType() == CoordinateSystem.PROJECTED_CRS ) { 253 addIdToCache( ( (ProjectedCRS) result ).getGeographicCRS(), false ); 254 } 255 256 } 257 return result; 258 259 } 260 261 /** 262 * Set the resolver to the given resolver. 263 * 264 * @param newResolver 265 */ 266 public void setResolver( CRSResource<T> newResolver ) { 267 if ( LOG.isDebug() ) { 268 LOG.logDebug( "The following resolver was set: " + newResolver + ", it will replace the old resolver: " 269 + this.resolver ); 270 } 271 this.resolver = newResolver; 272 } 273 274 /** 275 * @return the resolver for a type. 276 */ 277 protected CRSResource<T> getResolver() { 278 return resolver; 279 } 280 281 /** 282 * @param crsDefinition 283 * containing the definition of a crs in the understood type. 284 * @return a {@link CoordinateSystem} instance initialized with values from the given type definition fragment or 285 * <code>null</code> if the given crsDefinition is <code>null</code> or not known. 286 * @throws CRSConfigurationException 287 * if an error was found in the given crsDefintion 288 */ 289 protected abstract CoordinateSystem parseCoordinateSystem( T crsDefinition ) 290 throws CRSConfigurationException; 291 292 /** 293 * @param transformationDefinition 294 * containing the parameters needed to build a Transformation. 295 * @return a {@link Transformation} instance initialized with values from the given definition or <code>null</code> 296 * if the given transformationDefintion is <code>null</code>. If the parsed transformation is not supported 297 * or a {@link NotSupportedTransformation} will be returned. 298 * @throws CRSConfigurationException 299 * if an error was found in the given crsDefintion 300 */ 301 public abstract Transformation parseTransformation( T transformationDefinition ) 302 throws CRSConfigurationException; 303 304 /** 305 * Clears the cache. 306 */ 307 public void clearCache() { 308 try { 309 synchronized ( cachedIdentifiables ) { 310 cachedIdentifiables.clear(); 311 cachedIdentifiables.notifyAll(); 312 } 313 } catch ( Exception e ) { 314 LOG.logWarning( "The clearing of the cache could not be forefullfilled because: " + e.getLocalizedMessage() ); 315 } 316 } 317 318 /** 319 * The id are what they are, not trimming 'upcasing' or other modifications will be done in this method. 320 * 321 * @param expectedType 322 * The class of type T which is expected. 323 * @param <V> 324 * the type to cast to if the casting fails, null will be returned. 325 * @param ids 326 * to search the cache for 327 * @return the {@link Identifiable} of the first matching id or <code>null</code> if it was not found. 328 */ 329 public <V extends Identifiable> V getCachedIdentifiable( Class<V> expectedType, Identifiable ids ) { 330 if ( ids == null ) { 331 return null; 332 } 333 return getCachedIdentifiable( expectedType, ids.getIdentifiers() ); 334 } 335 336 /** 337 * The id are what they are, not trimming 'upcasing' or other modifications will be done in this method. 338 * 339 * @param expectedType 340 * The class of type T which is expected. 341 * @param <V> 342 * the type to cast to if the casting fails, null will be returned. 343 * @param ids 344 * to search the cache for 345 * @return the {@link Identifiable} of the first matching id or <code>null</code> if it was not found. 346 */ 347 public <V extends Identifiable> V getCachedIdentifiable( Class<V> expectedType, String[] ids ) { 348 if ( ids == null || ids.length == 0 ) { 349 return null; 350 } 351 V result = null; 352 for ( int i = 0; i < ids.length && result == null; i++ ) { 353 result = getCachedIdentifiable( expectedType, ids[i] ); 354 if ( LOG.isDebug() ) { 355 LOG.logDebug( "Searched for id: " + ids[i] + " resulted in: " 356 + ( ( result == null ) ? "null" : result.getIdentifier() ) ); 357 } 358 } 359 return result; 360 } 361 362 /** 363 * The id is as it is, not trimming 'upcasing' or other modifications will be done in this method. 364 * 365 * @param expectedType 366 * The class of type T which is expected. 367 * @param <V> 368 * the type to cast to if the casting fails, null will be returned. 369 * 370 * @param id 371 * to search the cache for 372 * @return the {@link Identifiable} or <code>null</code> if it was not found or the wrong type was found. 373 */ 374 @SuppressWarnings("unchecked") 375 public <V extends Identifiable> V getCachedIdentifiable( Class<V> expectedType, String id ) { 376 if ( id == null ) { 377 return null; 378 } 379 V result = null; 380 try { 381 result = (V) cachedIdentifiables.get( id ); 382 } catch ( ClassCastException cce ) { 383 LOG.logError( "Given id is not of type: " + expectedType.getCanonicalName() + " found following error: " 384 + cce.getLocalizedMessage() ); 385 } 386 if ( LOG.isDebug() ) { 387 LOG.logDebug( "Searched for id: " + id + " resulted in: " 388 + ( ( result == null ) ? "null" : result.getIdentifier() ) ); 389 } 390 return result; 391 } 392 393 /** 394 * The id is as it is, not trimming 'upcasing' or other modifications will be done in this method. 395 * 396 * @param <V> 397 * the type to cast to if the casting fails, null will be returned. 398 * 399 * @param id 400 * to search the cache for 401 * @return the {@link Identifiable} or <code>null</code> if it was not found or the wrong type was found. 402 */ 403 @SuppressWarnings("unchecked") 404 public <V extends Identifiable> V getCachedIdentifiable( String id ) { 405 if ( id == null ) { 406 return null; 407 } 408 V result = (V) cachedIdentifiables.get( id ); 409 if ( LOG.isDebug() ) { 410 LOG.logDebug( "Searched for id: " + id + " resulted in: " 411 + ( ( result == null ) ? "null" : result.getIdentifier() ) ); 412 } 413 return result; 414 } 415 416 /** 417 * Add the id to the cache, by mapping it to all its identifiers. 418 * 419 * @param <V> 420 * type of Identifiable 421 * @param identifiable 422 * to insert into cache 423 * @param update 424 * if true an existing identifiable in the cache will be overwritten. 425 * @return the identifiable 426 */ 427 public <V extends Identifiable> V addIdToCache( V identifiable, boolean update ) { 428 if ( identifiable == null ) { 429 return null; 430 } 431 try { 432 synchronized ( cachedIdentifiables ) { 433 434 for ( String idString : identifiable.getIdentifiers() ) { 435 if ( idString != null && !"".equals( idString.trim() ) ) { 436 if ( cachedIdentifiables.containsKey( idString ) && cachedIdentifiables.get( idString ) != null ) { 437 if ( update ) { 438 LOG.logDebug( "Updating cache with new identifiable: " + idString ); 439 cachedIdentifiables.put( idString, identifiable ); 440 } 441 } else { 442 LOG.logDebug( "Adding new identifiable to cache: " + idString ); 443 cachedIdentifiables.put( idString, identifiable ); 444 } 445 } else { 446 LOG.logWarning( "Not adding the null string id to the cache of identifiable: " 447 + identifiable.getIdentifier() ); 448 } 449 } 450 cachedIdentifiables.notifyAll(); 451 } 452 } catch ( Exception e ) { 453 LOG.logError( "Could not add identifiable to cache because: " + e.getLocalizedMessage(), e ); 454 } 455 return identifiable; 456 } 457 458 /** 459 * The <code>SupportedTransformations</code> enumeration defines currently supported transformations 460 * 461 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a> 462 * 463 * @author last edited by: $Author: rbezema $ 464 * 465 * @version $Revision: 23328 $, $Date: 2010-03-30 17:40:30 +0200 (Di, 30 Mär 2010) $ 466 * 467 */ 468 public enum SupportedTransformations { 469 /** 470 * The {@link Helmert}, transformation with 7 values 471 */ 472 HELMERT_7, 473 /** 474 * The {@link Helmert}, transformation with 3 values 475 */ 476 HELMERT_3, 477 /** 478 * The {@link GeocentricTransform} going from geographic to geocentric. 479 */ 480 GEOGRAPHIC_GEOCENTRIC, 481 /** 482 * The primemeridian rotation going from any to greenwich 483 */ 484 LONGITUDE_ROTATION, 485 /** 486 * The {@link PolynomialTransformation} defining the general 2, 3, ... degree polynomial transformation 487 */ 488 GENERAL_POLYNOMIAL, 489 /** 490 * The ntv2, currently not supported 491 */ 492 NTV2, 493 /** 494 * A not supported projection 495 */ 496 NOT_SUPPORTED 497 } 498 499 /** 500 * The <code>SupportedTransformationParameters</code> enumeration defines currently supported transformation 501 * parameters 502 * 503 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a> 504 * 505 * @author last edited by: $Author: rbezema $ 506 * 507 * @version $Revision: 23328 $, $Date: 2010-03-30 17:40:30 +0200 (Di, 30 Mär 2010) $ 508 * 509 */ 510 public enum SupportedTransformationParameters { 511 /** 512 * The X TRANSLATION of a (3/7) helmert transformation. 513 */ 514 X_AXIS_TRANSLATION, 515 /** 516 * The Y TRANSLATION of a (3/7) helmert transformation. 517 */ 518 Y_AXIS_TRANSLATION, 519 /** 520 * The Z TRANSLATION of a (3/7) helmert transformation. 521 */ 522 Z_AXIS_TRANSLATION, 523 /** 524 * The X Rotation of a (3/7) helmert transformation. 525 */ 526 X_AXIS_ROTATION, 527 /** 528 * The Y Rotation of a (3/7) helmert transformation. 529 */ 530 Y_AXIS_ROTATION, 531 /** 532 * The Z Rotation of a (3/7) helmert transformation. 533 */ 534 Z_AXIS_ROTATION, 535 /** 536 * The Difference of scale of a (3/7) helmert transformation. 537 */ 538 SCALE_DIFFERENCE, 539 /** 540 * The longitude offset of a longitude rotation 541 */ 542 LONGITUDE_OFFSET, 543 /** 544 * GENERIC transformation parameters are not yet supported. 545 */ 546 GENERIC_POLYNOMIAL_PARAM, 547 /** 548 * A not supported projection parameter. 549 */ 550 NOT_SUPPORTED 551 } 552 553 /** 554 * The <code>SupportedProjections</code> enumeration defines currently supported projections 555 * 556 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a> 557 * 558 * @author last edited by: $Author: rbezema $ 559 * 560 * @version $Revision: 23328 $, $Date: 2010-03-30 17:40:30 +0200 (Di, 30 Mär 2010) $ 561 * 562 */ 563 public enum SupportedProjections { 564 /** 565 * The {@link TransverseMercator} projection 566 */ 567 TRANSVERSE_MERCATOR, 568 /** 569 * The {@link LambertConformalConic} projection 570 */ 571 LAMBERT_CONFORMAL, 572 /** 573 * The {@link LambertAzimuthalEqualArea} projection 574 */ 575 LAMBERT_AZIMUTHAL_EQUAL_AREA, 576 /** 577 * Snyders {@link StereographicAzimuthal} implementation of the stereographic azimuthal projection 578 */ 579 STEREOGRAPHIC_AZIMUTHAL, 580 /** 581 * EPSG {@link StereographicAlternative} implementation of the Stereographic azimuthal projection 582 */ 583 STEREOGRAPHIC_AZIMUTHAL_ALTERNATIVE, 584 /** 585 * A not supported projection 586 */ 587 NOT_SUPPORTED 588 } 589 590 /** 591 * The <code>SupportedProjectionParameters</code> enumeration defines currently supported projection parameters 592 * 593 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a> 594 * 595 * @author last edited by: $Author: rbezema $ 596 * 597 * @version $Revision: 23328 $, $Date: 2010-03-30 17:40:30 +0200 (Di, 30 Mär 2010) $ 598 * 599 */ 600 public enum SupportedProjectionParameters { 601 /** 602 * The latitude of natural origin of a given projection, aka. projectionLatitude, central-latitude or 603 * latitude-of-origin, in Snyder referenced as phi_1 for azimuthal, phi_0 for other projections. 604 */ 605 LATITUDE_OF_NATURAL_ORIGIN, 606 /** 607 * The longitude of natural origin of a given projection, aka. projectionLongitude, projection-meridian, 608 * central-meridian, in Snyder referenced as lambda_0 609 */ 610 LONGITUDE_OF_NATURAL_ORIGIN, 611 /** 612 * The false easting of the projection. 613 */ 614 FALSE_EASTING, 615 /** 616 * The false northing of the projection. 617 */ 618 FALSE_NORTHING, 619 /** 620 * The scale at the natural origin of the projection. 621 */ 622 SCALE_AT_NATURAL_ORIGIN, 623 /** 624 * The latitude which the scale is 1 of a stereographic azimuthal projection. 625 */ 626 TRUE_SCALE_LATITUDE, 627 /** 628 * The first parallel latitude of conic projections. 629 */ 630 FIRST_PARALLEL_LATITUDE, 631 /** 632 * The second parallel latitude of conic projections. 633 */ 634 SECOND_PARALLEL_LATITUDE, 635 636 /** 637 * A not supported projection parameter. 638 */ 639 NOT_SUPPORTED 640 } 641 642 /** 643 * 644 * @param identifiers 645 * to check for. 646 * @return a mapped projection or {@link SupportedProjections#NOT_SUPPORTED}, never <code>null</code> 647 */ 648 protected SupportedProjections mapProjections( String[] identifiers ) { 649 if ( identifiers == null || identifiers.length == 0 ) { 650 return SupportedProjections.NOT_SUPPORTED; 651 } 652 for ( String id : identifiers ) { 653 if ( id != null && !"".equals( id.trim() ) ) { 654 String compare = id.trim(); 655 if ( "TransverseMercator".equalsIgnoreCase( compare ) 656 || "Transverse Merctator".equalsIgnoreCase( compare ) 657 || matchEPSGString( compare, "method", "9807" ) ) { 658 return SupportedProjections.TRANSVERSE_MERCATOR; 659 } else if ( "lambertAzimuthalEqualArea".equalsIgnoreCase( compare ) 660 || "Lambert Azimuthal Equal Area".equalsIgnoreCase( compare ) 661 || "Lambert Azimuthal Equal Area (Spherical)".equalsIgnoreCase( compare ) 662 || matchEPSGString( compare, "method", "9820" ) 663 || matchEPSGString( compare, "method", "9821" ) ) { 664 return SupportedProjections.LAMBERT_AZIMUTHAL_EQUAL_AREA; 665 } else if ( "stereographicAlternative".equalsIgnoreCase( compare ) 666 || "Oblique Stereographic".equalsIgnoreCase( compare ) 667 || compare.contains( "Polar Stereographic" ) || matchEPSGString( compare, "method", "9809" ) 668 || matchEPSGString( compare, "method", "9810" ) 669 || matchEPSGString( compare, "method", "9829" ) 670 || matchEPSGString( compare, "method", "9830" ) ) { 671 return SupportedProjections.STEREOGRAPHIC_AZIMUTHAL_ALTERNATIVE; 672 } else if ( "stereographicAzimuthal".equalsIgnoreCase( compare ) ) { 673 return SupportedProjections.STEREOGRAPHIC_AZIMUTHAL; 674 } else if ( "lambertConformalConic".equalsIgnoreCase( compare ) 675 || compare.contains( "Lambert Conic Conformal" ) 676 || matchEPSGString( compare, "method", "9801" ) 677 || matchEPSGString( compare, "method", "9802" ) 678 || matchEPSGString( compare, "method", "9803" ) ) { 679 return SupportedProjections.LAMBERT_CONFORMAL; 680 } 681 } 682 } 683 return SupportedProjections.NOT_SUPPORTED; 684 } 685 686 /** 687 * 688 * @param identifiers 689 * to check for. 690 * @return a mapped projections parameters or {@link SupportedProjectionParameters#NOT_SUPPORTED}, never 691 * <code>null</code> 692 */ 693 protected SupportedProjectionParameters mapProjectionParameters( String[] identifiers ) { 694 if ( identifiers == null || identifiers.length == 0 ) { 695 return SupportedProjectionParameters.NOT_SUPPORTED; 696 } 697 for ( String name : identifiers ) { 698 if ( name != null && !"".equals( name.trim() ) ) { 699 String compare = name.trim(); 700 if ( "Latitude of natural origin".equalsIgnoreCase( compare ) 701 || "Latitude of false origin".equalsIgnoreCase( compare ) 702 || "central latitude".equalsIgnoreCase( compare ) 703 || "latitude of origin".equalsIgnoreCase( compare ) 704 || "latitudeOfNaturalOrigin".equalsIgnoreCase( compare ) 705 || matchEPSGString( compare, "parameter", "8801" ) 706 || matchEPSGString( compare, "parameter", "8811" ) 707 || matchEPSGString( compare, "parameter", "8821" ) ) { 708 return SupportedProjectionParameters.LATITUDE_OF_NATURAL_ORIGIN; 709 } else if ( "Longitude of natural origin".equalsIgnoreCase( compare ) 710 || "Central Meridian".equalsIgnoreCase( compare ) || "CM".equalsIgnoreCase( compare ) 711 || "Longitude of origin".equalsIgnoreCase( compare ) 712 || "Longitude of false origin".equalsIgnoreCase( compare ) 713 || "longitudeOfNaturalOrigin".equalsIgnoreCase( compare ) 714 || matchEPSGString( compare, "parameter", "8802" ) 715 || matchEPSGString( compare, "parameter", "8812" ) 716 || matchEPSGString( compare, "parameter", "8822" ) ) { 717 return SupportedProjectionParameters.LONGITUDE_OF_NATURAL_ORIGIN; 718 } else if ( "Scale factor at natural origin".equalsIgnoreCase( compare ) 719 || "scaleFactor".equalsIgnoreCase( compare ) 720 || matchEPSGString( compare, "parameter", "8805" ) ) { 721 return SupportedProjectionParameters.SCALE_AT_NATURAL_ORIGIN; 722 } else if ( "Latitude of pseudo standard parallel ".equalsIgnoreCase( compare ) 723 || "Latitude of standard parallel ".equalsIgnoreCase( compare ) 724 || "trueScaleLatitude".equalsIgnoreCase( compare ) 725 || matchEPSGString( compare, "parameter", "8832" ) 726 || matchEPSGString( compare, "parameter", "8818" ) ) { 727 return SupportedProjectionParameters.TRUE_SCALE_LATITUDE; 728 } else if ( "False easting".equalsIgnoreCase( compare ) || "falseEasting".equalsIgnoreCase( compare ) 729 || "false westing".equalsIgnoreCase( compare ) 730 || "Easting at false origin".equalsIgnoreCase( compare ) 731 || matchEPSGString( compare, "parameter", "8806" ) 732 || matchEPSGString( compare, "parameter", "8816" ) 733 || matchEPSGString( compare, "parameter", "8826" ) ) { 734 return SupportedProjectionParameters.FALSE_EASTING; 735 } else if ( "False northing".equalsIgnoreCase( compare ) || "falseNorthing".equalsIgnoreCase( compare ) 736 || "false southing".equalsIgnoreCase( compare ) 737 || "Northing at false origin".equalsIgnoreCase( compare ) 738 || matchEPSGString( compare, "parameter", "8807" ) 739 || matchEPSGString( compare, "parameter", "8827" ) 740 || matchEPSGString( compare, "parameter", "8817" ) ) { 741 return SupportedProjectionParameters.FALSE_NORTHING; 742 } else if ( "Latitude of 1st standard parallel".equalsIgnoreCase( compare ) 743 || "firstParallelLatitude".equalsIgnoreCase( compare ) 744 || matchEPSGString( compare, "parameter", "8823" ) ) { 745 return SupportedProjectionParameters.FIRST_PARALLEL_LATITUDE; 746 } else if ( "Latitude of 2nd standard parallel".equalsIgnoreCase( compare ) 747 || "secondParallelLatitude".equalsIgnoreCase( compare ) 748 || matchEPSGString( compare, "parameter", "8824" ) ) { 749 return SupportedProjectionParameters.SECOND_PARALLEL_LATITUDE; 750 } 751 752 } 753 } 754 return SupportedProjectionParameters.NOT_SUPPORTED; 755 } 756 757 /** 758 * 759 * @param identifiers 760 * to check for. 761 * @return a mapped transformation or {@link SupportedTransformations#NOT_SUPPORTED}, never <code>null</code> 762 */ 763 protected SupportedTransformations mapTransformation( String[] identifiers ) { 764 if ( identifiers == null || identifiers.length == 0 ) { 765 return SupportedTransformations.NOT_SUPPORTED; 766 } 767 for ( String id : identifiers ) { 768 if ( id != null && !"".equals( id.trim() ) ) { 769 String compare = id.trim(); 770 if ( "Longitude rotation".equalsIgnoreCase( compare ) || matchEPSGString( compare, "method", "9601" ) ) { 771 return SupportedTransformations.LONGITUDE_ROTATION; 772 } else if ( "Geographic/geocentric conversions".equalsIgnoreCase( compare ) 773 || matchEPSGString( compare, "method", "9602" ) ) { 774 return SupportedTransformations.GEOGRAPHIC_GEOCENTRIC; 775 } else if ( "Geocentric translations".equalsIgnoreCase( compare ) 776 || matchEPSGString( compare, "method", "9603" ) ) { 777 return SupportedTransformations.HELMERT_3; 778 } else if ( "Position Vector 7-param. transformation".equalsIgnoreCase( compare ) 779 || "Coordinate Frame rotation".equalsIgnoreCase( compare ) 780 || matchEPSGString( compare, "method", "9606" ) 781 || matchEPSGString( compare, "method", "9607" ) ) { 782 return SupportedTransformations.HELMERT_7; 783 } else if ( "NTv2".equalsIgnoreCase( compare ) || matchEPSGString( compare, "method", "9615" ) ) { 784 return SupportedTransformations.NOT_SUPPORTED; 785 } else if ( matchEPSGString( compare, "method", "9645" ) || matchEPSGString( compare, "method", "9646" ) 786 || matchEPSGString( compare, "method", "9647" ) 787 || matchEPSGString( compare, "method", "9648" ) ) { 788 return SupportedTransformations.GENERAL_POLYNOMIAL; 789 } 790 } 791 } 792 return SupportedTransformations.NOT_SUPPORTED; 793 } 794 795 /** 796 * 797 * @param identifiers 798 * to check for. 799 * @return a mapped transformation or {@link SupportedTransformations#NOT_SUPPORTED}, never <code>null</code> 800 */ 801 protected SupportedTransformationParameters mapTransformationParameters( String[] identifiers ) { 802 if ( identifiers == null || identifiers.length == 0 ) { 803 return SupportedTransformationParameters.NOT_SUPPORTED; 804 } 805 for ( String id : identifiers ) { 806 if ( id != null && !"".equals( id.trim() ) ) { 807 String compare = id.trim(); 808 if ( "Longitude offset".equalsIgnoreCase( compare ) || matchEPSGString( compare, "parameter", "8602" ) ) { 809 return SupportedTransformationParameters.LONGITUDE_OFFSET; 810 } else if ( "X-axis translation".equalsIgnoreCase( compare ) 811 || matchEPSGString( compare, "parameter", "8605" ) ) { 812 return SupportedTransformationParameters.X_AXIS_TRANSLATION; 813 } else if ( "Y-axis translation".equalsIgnoreCase( compare ) 814 || matchEPSGString( compare, "parameter", "8606" ) ) { 815 return SupportedTransformationParameters.Y_AXIS_TRANSLATION; 816 } else if ( "Z-axis translation".equalsIgnoreCase( compare ) 817 || matchEPSGString( compare, "parameter", "8607" ) ) { 818 return SupportedTransformationParameters.Z_AXIS_TRANSLATION; 819 } else if ( "X-axis rotation".equalsIgnoreCase( compare ) 820 || matchEPSGString( compare, "parameter", "8608" ) ) { 821 return SupportedTransformationParameters.X_AXIS_ROTATION; 822 } else if ( "Y-axis rotation".equalsIgnoreCase( compare ) 823 || matchEPSGString( compare, "parameter", "8609" ) ) { 824 return SupportedTransformationParameters.Y_AXIS_ROTATION; 825 } else if ( "Z-axis rotation".equalsIgnoreCase( compare ) 826 || matchEPSGString( compare, "parameter", "8610" ) ) { 827 return SupportedTransformationParameters.Z_AXIS_ROTATION; 828 } else if ( "Scale difference".equalsIgnoreCase( compare ) 829 || matchEPSGString( compare, "parameter", "8611" ) ) { 830 return SupportedTransformationParameters.SCALE_DIFFERENCE; 831 } 832 } 833 } 834 return SupportedTransformationParameters.NOT_SUPPORTED; 835 } 836 }