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 }