001 //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/crs/configuration/deegree/CRSParser.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.deegree;
038
039 import java.io.IOException;
040 import java.lang.reflect.Constructor;
041 import java.lang.reflect.InvocationTargetException;
042 import java.util.LinkedList;
043 import java.util.List;
044 import java.util.Map;
045 import java.util.Properties;
046
047 import javax.vecmath.Point2d;
048
049 import org.deegree.crs.Identifiable;
050 import org.deegree.crs.components.Axis;
051 import org.deegree.crs.components.Ellipsoid;
052 import org.deegree.crs.components.GeodeticDatum;
053 import org.deegree.crs.components.PrimeMeridian;
054 import org.deegree.crs.components.Unit;
055 import org.deegree.crs.configuration.resources.XMLFileResource;
056 import org.deegree.crs.coordinatesystems.CompoundCRS;
057 import org.deegree.crs.coordinatesystems.CoordinateSystem;
058 import org.deegree.crs.coordinatesystems.GeocentricCRS;
059 import org.deegree.crs.coordinatesystems.GeographicCRS;
060 import org.deegree.crs.coordinatesystems.ProjectedCRS;
061 import org.deegree.crs.exceptions.CRSConfigurationException;
062 import org.deegree.crs.projections.Projection;
063 import org.deegree.crs.projections.azimuthal.LambertAzimuthalEqualArea;
064 import org.deegree.crs.projections.azimuthal.StereographicAlternative;
065 import org.deegree.crs.projections.azimuthal.StereographicAzimuthal;
066 import org.deegree.crs.projections.conic.LambertConformalConic;
067 import org.deegree.crs.projections.cylindric.Mercator;
068 import org.deegree.crs.projections.cylindric.TransverseMercator;
069 import org.deegree.crs.transformations.Transformation;
070 import org.deegree.crs.transformations.helmert.Helmert;
071 import org.deegree.crs.transformations.polynomial.LeastSquareApproximation;
072 import org.deegree.crs.transformations.polynomial.PolynomialTransformation;
073 import org.deegree.framework.log.ILogger;
074 import org.deegree.framework.log.LoggerFactory;
075 import org.deegree.framework.xml.XMLParsingException;
076 import org.deegree.framework.xml.XMLTools;
077 import org.deegree.i18n.Messages;
078 import org.deegree.ogcbase.CommonNamespaces;
079 import org.w3c.dom.Element;
080
081 /**
082 * The <code>CRSParser</code> class TODO add class documentation here.
083 *
084 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
085 *
086 * @author last edited by: $Author: mschneider $
087 *
088 * @version $Revision: 20382 $, $Date: 2009-10-27 12:27:31 +0100 (Di, 27. Okt 2009) $
089 *
090 */
091 public class CRSParser extends XMLFileResource {
092
093 /**
094 *
095 */
096 private static final long serialVersionUID = -5621078575657838568L;
097
098 private static ILogger LOG = LoggerFactory.getLogger( CRSParser.class );
099
100 /**
101 * The prefix to use.
102 */
103 private final static String PRE = CommonNamespaces.CRS_PREFIX + ":";
104
105 private final static String XPATH_PRE = "*[" + PRE + "id='";
106
107 /**
108 * @param provider
109 * to be used for callback.
110 * @param rootElement
111 * to be used for the configuration.
112 */
113 public CRSParser( DeegreeCRSProvider provider, Element rootElement ) {
114 super( provider, rootElement );
115 }
116
117 /**
118 * @param provider
119 * @param properties
120 */
121 public CRSParser( DeegreeCRSProvider provider, Properties properties ) {
122 this( provider, properties, "definitions", CommonNamespaces.CRSNS.toASCIIString() );
123 // TODO Auto-generated constructor stub
124 }
125
126 /**
127 * @param provider
128 * @param properties
129 * @param defaultRootElement
130 * @param namespace
131 */
132 public CRSParser( DeegreeCRSProvider provider, Properties properties, String defaultRootElement, String namespace ) {
133 super( provider, properties, defaultRootElement, namespace );
134 }
135
136 /**
137 * @param crsDefintion
138 * to be parsed
139 * @return an instance of the given crs or <code>null</code> if the crsDefinition is <code>null</code> or could
140 * not be mapped to a valid type.
141 * @throws CRSConfigurationException
142 * if something went wrong while constructing the crs.
143 */
144 public CoordinateSystem parseCoordinateSystem( Element crsDefintion )
145 throws CRSConfigurationException {
146 if ( crsDefintion == null ) {
147 return null;
148 }
149 String crsType = crsDefintion.getLocalName();
150
151 CoordinateSystem result = null;
152 if ( "geographicCRS".equalsIgnoreCase( crsType ) ) {
153 result = parseGeographicCRS( crsDefintion );
154 } else if ( "projectedCRS".equalsIgnoreCase( crsType ) ) {
155 result = parseProjectedCRS( crsDefintion );
156 } else if ( "geocentricCRS".equalsIgnoreCase( crsType ) ) {
157 result = parseGeocentricCRS( crsDefintion );
158 } else if ( "compoundCRS".equalsIgnoreCase( crsType ) ) {
159 result = parseCompoundCRS( crsDefintion );
160 }
161
162 if ( result == null && LOG.isDebug() ) {
163 LOG.logDebug( "The element with localname "
164 + crsDefintion.getLocalName()
165 + " could not be mapped to a valid deegreec-crs, currently projectedCRS, geographicCRS, geocentricCRS and compoundCRS are supported." );
166 }
167 return result;
168 }
169
170 public Element getURIAsType( String uri )
171 throws IOException {
172 if ( uri == null || "".equals( uri ) ) {
173 return null;
174 }
175 String id = uri.trim().toUpperCase();
176 Element crsElement = null;
177 // String xPath ="//*[crs:id='EPSG:31466']";
178 String xPath = XPATH_PRE + id + "']";
179 try {
180 crsElement = XMLTools.getElement( getRootElement(), xPath, nsContext );
181 } catch ( XMLParsingException e ) {
182 LOG.logError( Messages.getMessage( "CRS_CONFIG_NO_RESULT_FOR_ID", id, e.getMessage() ), e );
183 }
184 if ( LOG.isDebug() ) {
185 LOG.logDebug( "Trying to find elements with xpath: " + xPath
186 + ( ( crsElement == null ) ? " [failed]" : " [success]" ) );
187 }
188 return crsElement;
189 }
190
191 public Helmert getWGS84Transformation( GeographicCRS sourceCRS ) {
192 if ( sourceCRS == null ) {
193 return null;
194 }
195 return sourceCRS.getGeodeticDatum().getWGS84Conversion();
196 }
197
198 /**
199 * @return the version of the root element of the empty string if no version attribute was found in the root
200 * element.
201 * @throws CRSConfigurationException
202 * if the root element is empty
203 */
204 public String getVersion()
205 throws CRSConfigurationException {
206 if ( getRootElement() == null ) {
207 throw new CRSConfigurationException( "The crs parser has no root element, this cannot be." );
208 }
209 return getRootElement().getAttribute( "version" );
210 }
211
212 /**
213 * Parses all elements of the identifiable object.
214 *
215 * @param element
216 * the xml-representation of the id-object
217 * @return the identifiable object or <code>null</code> if no id was given.
218 * @throws CRSConfigurationException
219 */
220 protected Identifiable parseIdentifiable( Element element )
221 throws CRSConfigurationException {
222 try {
223 String[] identifiers = XMLTools.getNodesAsStrings( element, PRE + "id", nsContext );
224 if ( identifiers == null || identifiers.length == 0 ) {
225 String msg = Messages.getMessage( "CRS_CONFIG_NO_ID", ( ( element == null ) ? "null"
226 : element.getLocalName() ) );
227 throw new CRSConfigurationException( msg );
228 }
229 for ( int i = 0; i < identifiers.length; ++i ) {
230 if ( identifiers[i] != null ) {
231 identifiers[i] = identifiers[i].toUpperCase().trim();
232 }
233 }
234 String[] names = XMLTools.getNodesAsStrings( element, PRE + "name", nsContext );
235 String[] versions = XMLTools.getNodesAsStrings( element, PRE + "version", nsContext );
236 String[] descriptions = XMLTools.getNodesAsStrings( element, PRE + "description", nsContext );
237 String[] areasOfUse = XMLTools.getNodesAsStrings( element, PRE + "areaOfUse", nsContext );
238 return new Identifiable( identifiers, names, versions, descriptions, areasOfUse );
239 } catch ( XMLParsingException e ) {
240 throw new CRSConfigurationException( Messages.getMessage( "CRS_CONFIG_PARSE_ERROR", "Identifiable",
241 ( ( element == null ) ? "null"
242 : element.getLocalName() ),
243 e.getMessage() ), e );
244 }
245 }
246
247 /**
248 * Creates an axis array for the given crs element.
249 *
250 * @param crsElement
251 * to be parsed
252 * @return an Array of axis defining their order.
253 * @throws CRSConfigurationException
254 * if a required element could not be found, or an xmlParsingException occurred, or the axisorder uses
255 * names which were not defined in the axis elements.
256 */
257 protected Axis[] parseAxisOrder( Element crsElement )
258 throws CRSConfigurationException {
259 String axisOrder = null;
260 try {
261 axisOrder = XMLTools.getRequiredNodeAsString( crsElement, PRE + "axisOrder", nsContext );
262 } catch ( XMLParsingException e ) {
263 throw new CRSConfigurationException(
264 Messages.getMessage(
265 "CRS_CONFIG_PARSE_ERROR",
266 "AxisOrder",
267 ( ( crsElement == null ) ? "null"
268 : crsElement.getLocalName() ),
269 e.getMessage() ), e );
270 }
271 if ( axisOrder == null || "".equals( axisOrder.trim() ) ) {
272 throw new CRSConfigurationException(
273 Messages.getMessage(
274 "CRS_CONFIG_PARSE_ERROR",
275 "AxisOrder",
276 ( ( crsElement == null ) ? "null"
277 : crsElement.getLocalName() ),
278 " axisOrder element may not be empty" ) );
279 }
280 axisOrder = axisOrder.trim();
281 String[] order = axisOrder.trim().split( "," );
282 Axis[] axis = new Axis[order.length];
283 String XPATH = PRE + "Axis[" + PRE + "name = '";
284 for ( int i = 0; i < order.length; ++i ) {
285 String t = order[i];
286 if ( t != null && !"".equals( t.trim() ) ) {
287 t = t.trim();
288 try {
289 Element axisElement = XMLTools.getRequiredElement( crsElement, XPATH + t + "']", nsContext );
290 String axisOrientation = XMLTools.getRequiredNodeAsString( axisElement, PRE + "axisOrientation",
291 nsContext );
292 Unit unit = parseUnit( axisElement );
293 axis[i] = new Axis( unit, t, axisOrientation );
294 } catch ( XMLParsingException e ) {
295 throw new CRSConfigurationException(
296 Messages.getMessage(
297 "CRS_CONFIG_PARSE_ERROR",
298 "Axis",
299 ( ( crsElement == null ) ? "null"
300 : crsElement.getLocalName() ),
301 e.getMessage() ), e );
302 }
303 }
304 }
305 return axis;
306 }
307
308 /**
309 * Retrieves a transformation from the resource.
310 *
311 * @param transformationDefinition
312 * @return the parsed transformation or <code>null</code> if no transformation could be parsed.
313 */
314 public Transformation parseTransformation( Element transformationDefinition ) {
315 throw new UnsupportedOperationException(
316 "The parsing of transformations is not supported by this version of the deegree crs parser." );
317 }
318
319 /**
320 * Parse all polynomial transformations for a given crs.
321 *
322 * @param crsElement
323 * to parse the transformations for.
324 * @return the list of transformations or the empty list if no transformations were found. Never <code>null</code>.
325 */
326 protected List<PolynomialTransformation> parseAlternativeTransformations( Element crsElement ) {
327 List<Element> usedTransformations = null;
328 try {
329 usedTransformations = XMLTools.getElements( crsElement, PRE + "polynomialTransformation", nsContext );
330 } catch ( XMLParsingException e ) {
331 LOG.logError( e.getMessage(), e );
332 }
333 List<PolynomialTransformation> result = new LinkedList<PolynomialTransformation>();
334 if ( usedTransformations != null ) {
335 for ( Element transformationElement : usedTransformations ) {
336 PolynomialTransformation transform = getTransformation( transformationElement );
337 if ( transform != null ) {
338 result.add( transform );
339 }
340 }
341 }
342 return result;
343 }
344
345 /**
346 * Parses the transformation variables from the given crs:coordinatesystem/crs:polynomialTransformation element. If
347 * the class attribute is given, this method will try to invoke an instance of the given class, if it fails
348 * <code>null</code> will be returned.
349 *
350 * @param transformationElement
351 * to parse the values from.
352 * @return the instantiated transformation or <code>null</code> if it could not be instantiated.
353 */
354 protected PolynomialTransformation getTransformation( Element transformationElement ) {
355 if ( transformationElement == null ) {
356 throw new CRSConfigurationException( Messages.getMessage( "CRS_INVALID_NULL_PARAMETER",
357 "transformationElement" ) );
358 }
359
360 // order is not evaluated yet, because I do not know if it is required.
361 // int order = -1;
362 String tCRS = null;
363 List<Double> aValues = new LinkedList<Double>();
364 List<Double> bValues = new LinkedList<Double>();
365 Element usedTransformation = null;
366 try {
367 usedTransformation = XMLTools.getRequiredElement( transformationElement, "*[1]", nsContext );
368 } catch ( XMLParsingException e ) {
369 throw new CRSConfigurationException( Messages.getMessage( "CRS_CONFIG_PARSE_ERROR",
370 "the transformation to use",
371 transformationElement.getLocalName(),
372 e.getLocalizedMessage() ), e );
373 }
374
375 try {
376 // order = XMLTools.getNodeAsInt( usedTransformation, PRE + "polynomialOrder", nsContext, -1 );
377 tCRS = XMLTools.getRequiredNodeAsString( usedTransformation, PRE + "targetCRS", nsContext );
378 Element tmp = XMLTools.getRequiredElement( usedTransformation, PRE + "xParameters", nsContext );
379 String tmpValues = XMLTools.getStringValue( tmp );
380 if ( tmpValues != null && !"".equals( tmpValues.trim() ) ) {
381 String[] split = tmpValues.split( "\\s" );
382 for ( String t : split ) {
383 aValues.add( Double.parseDouble( t ) );
384 }
385 }
386 tmp = XMLTools.getRequiredElement( usedTransformation, PRE + "yParameters", nsContext );
387 tmpValues = XMLTools.getStringValue( tmp );
388 if ( tmpValues != null && !"".equals( tmpValues.trim() ) ) {
389 String[] split = tmpValues.split( "\\s" );
390 for ( String t : split ) {
391 bValues.add( Double.parseDouble( t ) );
392 }
393 }
394 } catch ( XMLParsingException e ) {
395 LOG.logError( e.getMessage(), e );
396 }
397
398 if ( tCRS == null ) {
399 throw new CRSConfigurationException(
400 Messages.getMessage(
401 "CRS_CONFIG_PARSE_ERROR",
402 "targetCRS",
403 ( ( usedTransformation == null ) ? "null"
404 : usedTransformation.getLocalName() ),
405 "it is required and must denote a valid crs )" ) );
406 }
407
408 if ( aValues.size() == 0 || bValues.size() == 0 ) {
409 throw new CRSConfigurationException(
410 "The polynomial variables (xParameters and yParameters element) defining the approximation to a given transformation function are required and may not be empty" );
411 }
412
413 CoordinateSystem targetCRS = getProvider().getCRSByID( tCRS );
414
415 PolynomialTransformation result = null;
416 String name = usedTransformation.getLocalName().trim();
417 String className = transformationElement.getAttribute( "class" );
418 LOG.logDebug( "Trying to create transformation with name: " + name );
419 if ( null != className && !"".equals( className.trim() ) ) {
420 LOG.logDebug( "Trying to load user defined transformation class: " + className );
421 try {
422 Class<?> t = Class.forName( className );
423 t.asSubclass( PolynomialTransformation.class );
424
425 List<Element> children = XMLTools.getElements( usedTransformation, "*", nsContext );
426 List<Element> otherValues = new LinkedList<Element>();
427 for ( Element child : children ) {
428 if ( child != null ) {
429 String localName = child.getLocalName().trim();
430 if ( !( "targetCRS".equals( localName ) || "xParameters".equals( localName )
431 || "yParameters".equals( localName ) || "polynomialOrder".equals( localName ) ) ) {
432 otherValues.add( child );
433 }
434 }
435 }
436 /**
437 * Load the constructor with the standard projection values and the element list.
438 */
439 /**
440 * For now, just load the constructor with the two lists and the crs class.
441 */
442 Constructor<?> constructor = t.getConstructor( aValues.getClass(), bValues.getClass(),
443 targetCRS.getClass() );
444 result = (PolynomialTransformation) constructor.newInstance( aValues, bValues, targetCRS );
445 } catch ( ClassNotFoundException e ) {
446 LOG.logError( e.getMessage(), e );
447 } catch ( SecurityException e ) {
448 LOG.logError( e.getMessage(), e );
449 } catch ( NoSuchMethodException e ) {
450 LOG.logError( e.getMessage(), e );
451 } catch ( IllegalArgumentException e ) {
452 LOG.logError( e.getMessage(), e );
453 } catch ( InstantiationException e ) {
454 LOG.logError( e.getMessage(), e );
455 } catch ( IllegalAccessException e ) {
456 LOG.logError( e.getMessage(), e );
457 } catch ( InvocationTargetException e ) {
458 LOG.logError( e.getMessage(), e );
459 } catch ( XMLParsingException e ) {
460 // this will probably never happen.
461 LOG.logError( e.getMessage(), e );
462 }
463 if ( result == null ) {
464 LOG.logDebug( "Loading of user defined transformation class: " + className + " was not successful" );
465 }
466 } else if ( "leastsquare".equalsIgnoreCase( name ) ) {
467 float scaleX = 1;
468 float scaleY = 1;
469 try {
470 scaleX = (float) XMLTools.getNodeAsDouble( usedTransformation, PRE + "scaleX", nsContext, 1 );
471 } catch ( XMLParsingException e ) {
472 LOG.logError( "Could not parse scaleX from crs:leastsquare, because: " + e.getMessage(), e );
473 }
474 try {
475 scaleY = (float) XMLTools.getNodeAsDouble( usedTransformation, PRE + "scaleY", nsContext, 1 );
476 } catch ( XMLParsingException e ) {
477 LOG.logError( "Could not parse scaleY from crs:leastsquare, because: " + e.getMessage(), e );
478 }
479 result = new LeastSquareApproximation( aValues, bValues, null, targetCRS, scaleX, scaleY );
480 }
481 return result;
482 }
483
484 /**
485 * Parses a unit from the given xml-parent.
486 *
487 * @param parent
488 * xml-node to parse the unit from.
489 * @return the unit object.
490 * @throws CRSConfigurationException
491 * if the unit object could not be created.
492 */
493 protected Unit parseUnit( Element parent )
494 throws CRSConfigurationException {
495 String unitId = null;
496 try {
497 unitId = XMLTools.getNodeAsString( parent, PRE + "units", nsContext, null );
498 } catch ( XMLParsingException e ) {
499 throw new CRSConfigurationException( Messages.getMessage( "CRS_CONFIG_PARSE_ERROR", "units",
500 ( ( parent == null ) ? "null"
501 : parent.getLocalName() ),
502 e.getMessage() ), e );
503 }
504 Unit result = getProvider().getCachedIdentifiable( Unit.class, unitId );
505 if ( result == null ) {
506 result = Unit.createUnitFromString( unitId );
507 if ( result == null ) {
508 throw new CRSConfigurationException(
509 Messages.getMessage(
510 "CRS_CONFIG_PARSE_ERROR",
511 "units",
512 ( ( parent == null ) ? "null"
513 : parent.getLocalName() ),
514 "unknown unit: " + unitId ) );
515 }
516 }
517 return result;
518 }
519
520 /**
521 * @param crsElement
522 * from which the crs is to be created (using chached datums, conversioninfos and projections).
523 * @return a projected coordinatesystem based on the given xml-element.
524 * @throws CRSConfigurationException
525 * if a required element could not be found, or an xmlParsingException occurred.
526 */
527 protected CoordinateSystem parseProjectedCRS( Element crsElement )
528 throws CRSConfigurationException {
529 if ( crsElement == null ) {
530 return null;
531 }
532 // no need to get it from the cache, because the abstract provider checked it already.
533 Identifiable id = parseIdentifiable( crsElement );
534
535 Axis[] axis = parseAxisOrder( crsElement );
536 List<PolynomialTransformation> transformations = parseAlternativeTransformations( crsElement );
537 // Unit units = parseUnit( crsElement );
538
539 Element usedProjection = null;
540 String usedGeographicCRS = null;
541 try {
542 usedProjection = XMLTools.getRequiredElement( crsElement, PRE + "projection", nsContext );
543 usedGeographicCRS = XMLTools.getRequiredNodeAsString( crsElement, PRE + "usedGeographicCRS", nsContext );
544
545 } catch ( XMLParsingException e ) {
546 throw new CRSConfigurationException( Messages.getMessage( "CRS_CONFIG_PARSE_ERROR",
547 "projectiontType or usedGeographicCRS",
548 crsElement.getLocalName(), e.getMessage() ), e );
549
550 }
551 // first create the datum.
552 if ( usedGeographicCRS == null || "".equals( usedGeographicCRS.trim() ) ) {
553 throw new CRSConfigurationException( Messages.getMessage( "CRS_CONFIG_REFERENCE_ID_IS_EMPTY",
554 "usedGeographicCRS", id.getIdentifier() ) );
555 }
556 GeographicCRS geoCRS = (GeographicCRS) getProvider().getCRSByID( usedGeographicCRS );
557 if ( geoCRS == null || geoCRS.getType() != CoordinateSystem.GEOGRAPHIC_CRS ) {
558 throw new CRSConfigurationException( Messages.getMessage( "CRS_CONFIG_PROJECTEDCRS_FALSE_CRSREF",
559 id.getIdentifier(), usedGeographicCRS ) );
560 }
561
562 // // then the projection.
563 // if ( usedProjection == null || "".equals( usedProjection.trim() ) ) {
564 // throw new CRSConfigurationException( Messages.getMessage( "CRS_CONFIG_REFERENCE_ID_IS_EMPTY",
565 // "projectionType", id.getIdentifier() ) );
566 // }
567 // Projection projection = getProjectionByID( usedProjection, (GeographicCRS) geoCRS, axis[0].getUnits() );
568 Projection projection = parseProjection( usedProjection, geoCRS, axis[0].getUnits() );
569 if ( projection == null ) {
570 throw new CRSConfigurationException( Messages.getMessage( "CRS_CONFIG_PROJECTEDCRS_FALSE_PROJREF",
571 id.getIdentifier(), usedProjection ) );
572 }
573 // adding to cache will be done in AbstractCRSProvider.
574 return new ProjectedCRS( transformations, projection, axis, id );
575 }
576
577 /**
578 * @param crsElement
579 * from which the crs is to be created (using cached datums, conversioninfos and projections).
580 *
581 * @return a geographic coordinatesystem based on the given xml-element.
582 * @throws CRSConfigurationException
583 * if a required element could not be found, or an xmlParsingException occurred.
584 */
585 protected CoordinateSystem parseGeographicCRS( Element crsElement )
586 throws CRSConfigurationException {
587 if ( crsElement == null ) {
588 return null;
589 }
590 Identifiable id = parseIdentifiable( crsElement );
591 // no need to get it from the cache, because the abstract provider checked it already.
592 Axis[] axis = parseAxisOrder( crsElement );
593 List<PolynomialTransformation> transformations = parseAlternativeTransformations( crsElement );
594 // get the datum
595 GeodeticDatum usedDatum = parseReferencedGeodeticDatum( crsElement, id.getIdentifier() );
596
597 GeographicCRS result = new GeographicCRS( transformations, usedDatum, axis, id );
598 // adding to cache will be done in AbstractCRSProvider.
599 return result;
600 }
601
602 /**
603 * @param crsElement
604 * from which the crs is to be created (using cached datums, conversioninfos and projections).
605 * @return a geocentric coordinatesystem based on the given xml-element.
606 * @throws CRSConfigurationException
607 * if a required element could not be found, or an xmlParsingException occurred.
608 */
609 protected CoordinateSystem parseGeocentricCRS( Element crsElement )
610 throws CRSConfigurationException {
611 // no need to get it from the cache, because the abstract provider checked it already.
612 Identifiable id = parseIdentifiable( crsElement );
613 Axis[] axis = parseAxisOrder( crsElement );
614 List<PolynomialTransformation> transformations = parseAlternativeTransformations( crsElement );
615 GeodeticDatum usedDatum = parseReferencedGeodeticDatum( crsElement, id.getIdentifier() );
616 GeocentricCRS result = new GeocentricCRS( transformations, usedDatum, axis, id );
617 // adding to cache will be done in AbstractCRSProvider.
618 return result;
619 }
620
621 /**
622 * @param crsElement
623 * from which the crs is to be created.
624 *
625 * @return a compound coordinatesystem based on the given xml-element.
626 * @throws CRSConfigurationException
627 * if a required element could not be found, or an xmlParsingException occurred.
628 */
629 protected CoordinateSystem parseCompoundCRS( Element crsElement ) {
630 // no need to get it from the cache, because the abstract provider checked it already.
631 Identifiable id = parseIdentifiable( crsElement );
632 String usedCRS = null;
633 try {
634 usedCRS = XMLTools.getRequiredNodeAsString( crsElement, PRE + "usedCRS", nsContext );
635 } catch ( XMLParsingException e ) {
636 throw new CRSConfigurationException(
637 Messages.getMessage(
638 "CRS_CONFIG_PARSE_ERROR",
639 "usedCRS",
640 ( ( crsElement == null ) ? "null"
641 : crsElement.getLocalName() ),
642 e.getMessage() ), e );
643
644 }
645 if ( usedCRS == null || "".equals( usedCRS.trim() ) ) {
646 throw new CRSConfigurationException( Messages.getMessage( "CRS_CONFIG_REFERENCE_ID_IS_EMPTY", "usedCRS",
647 id.getIdentifier() ) );
648 }
649 CoordinateSystem usedCoordinateSystem = getProvider().getCRSByID( usedCRS );
650 if ( usedCoordinateSystem == null
651 || ( usedCoordinateSystem.getType() != CoordinateSystem.GEOGRAPHIC_CRS && usedCoordinateSystem.getType() != CoordinateSystem.PROJECTED_CRS ) ) {
652 throw new CRSConfigurationException( Messages.getMessage( "CRS_CONFIG_COMPOUND_FALSE_CRSREF",
653 id.getIdentifier(), usedCRS ) );
654 }
655
656 // get the datum
657 Axis heigtAxis = null;
658 double defaultHeight = 0;
659 try {
660 Element axisElement = XMLTools.getRequiredElement( crsElement, PRE + "heightAxis", nsContext );
661 String axisName = XMLTools.getRequiredNodeAsString( axisElement, PRE + "name", nsContext );
662 String axisOrientation = XMLTools.getRequiredNodeAsString( axisElement, PRE + "axisOrientation", nsContext );
663 Unit unit = parseUnit( axisElement );
664 heigtAxis = new Axis( unit, axisName, axisOrientation );
665 defaultHeight = XMLTools.getNodeAsDouble( crsElement, PRE + "defaultHeight", nsContext, 0 );
666 } catch ( XMLParsingException e ) {
667 LOG.logError( e.getMessage(), e );
668 throw new CRSConfigurationException( e.getMessage() );
669 }
670 // adding to cache will be done in AbstractCRSProvider.
671 return new CompoundCRS( heigtAxis, usedCoordinateSystem, defaultHeight, id );
672 }
673
674 /**
675 * Parses the required usedDatum element from the given parentElement (probably a crs element).
676 *
677 * @param parentElement
678 * to parse the required usedDatum element from.
679 * @param parentID
680 * optional for an appropriate error message.
681 * @return the Datum.
682 * @throws CRSConfigurationException
683 * if a parsing error occurred, the node was not defined or an illegal id reference (not found) was
684 * given.
685 */
686 protected GeodeticDatum parseReferencedGeodeticDatum( Element parentElement, String parentID )
687 throws CRSConfigurationException {
688 String datumID = null;
689 try {
690 datumID = XMLTools.getRequiredNodeAsString( parentElement, PRE + "usedDatum", nsContext );
691 } catch ( XMLParsingException e ) {
692 throw new CRSConfigurationException(
693 Messages.getMessage(
694 "CRS_CONFIG_PARSE_ERROR",
695 "datumID",
696 ( ( parentElement == null ) ? "null"
697 : parentElement.getLocalName() ),
698 e.getMessage() ), e );
699 }
700 if ( datumID == null || "".equals( datumID.trim() ) ) {
701 throw new CRSConfigurationException( Messages.getMessage( "CRS_CONFIG_REFERENCE_ID_IS_EMPTY", "usedDatum",
702 parentID ) );
703 }
704 GeodeticDatum usedDatum = getGeodeticDatumFromID( datumID );
705 if ( usedDatum == null ) {
706 throw new CRSConfigurationException(
707 Messages.getMessage( "CRS_CONFIG_USEDDATUM_IS_NULL", datumID, parentID ) );
708 }
709 return usedDatum;
710 }
711
712 /**
713 * @param datumID
714 * @return the
715 * @throws CRSConfigurationException
716 */
717 protected GeodeticDatum getGeodeticDatumFromID( String datumID )
718 throws CRSConfigurationException {
719 if ( datumID == null || "".equals( datumID.trim() ) ) {
720 return null;
721 }
722 String tmpDatumID = datumID.trim();
723 GeodeticDatum result = getProvider().getCachedIdentifiable( GeodeticDatum.class, tmpDatumID );
724 if ( result == null ) {
725 Element datumElement = null;
726 try {
727 datumElement = getURIAsType( tmpDatumID );
728 } catch ( IOException e ) {
729 throw new CRSConfigurationException( e );
730 }
731 if ( datumElement == null ) {
732 throw new CRSConfigurationException( Messages.getMessage( "CRS_CONFIG_NO_ELEMENT", "datum", tmpDatumID ) );
733 }
734 // get the identifiable.
735 Identifiable id = parseIdentifiable( datumElement );
736
737 // get the ellipsoid.
738 Ellipsoid ellipsoid = null;
739 try {
740 String ellipsID = XMLTools.getRequiredNodeAsString( datumElement, PRE + "usedEllipsoid", nsContext );
741 if ( ellipsID != null && !"".equals( ellipsID.trim() ) ) {
742 ellipsoid = getEllipsoidFromID( ellipsID );
743 }
744 } catch ( XMLParsingException e ) {
745 throw new CRSConfigurationException(
746 Messages.getMessage( "CRS_CONFIG_PARSE_ERROR", "usedEllipsoid",
747 datumElement.getLocalName(), e.getMessage() ),
748 e );
749 }
750 if ( ellipsoid == null ) {
751 throw new CRSConfigurationException( Messages.getMessage( "CRS_CONFIG_DATUM_HAS_NO_ELLIPSOID",
752 tmpDatumID ) );
753 }
754
755 // get the primemeridian if any.
756 PrimeMeridian pMeridian = null;
757 try {
758 String pMeridianID = XMLTools.getNodeAsString( datumElement, PRE + "usedPrimeMeridian", nsContext, null );
759 if ( pMeridianID != null && !"".equals( pMeridianID.trim() ) ) {
760 pMeridian = getPrimeMeridianFromID( pMeridianID );
761 }
762 if ( pMeridian == null ) {
763 pMeridian = PrimeMeridian.GREENWICH;
764 }
765 } catch ( XMLParsingException e ) {
766 throw new CRSConfigurationException(
767 Messages.getMessage( "CRS_CONFIG_PARSE_ERROR",
768 "usedPrimeMeridian",
769 datumElement.getLocalName(), e.getMessage() ),
770 e );
771 }
772
773 // get the WGS84 if any.
774 Helmert cInfo = null;
775 try {
776 String infoID = XMLTools.getNodeAsString( datumElement, PRE + "usedWGS84ConversionInfo", nsContext,
777 null );
778 if ( infoID != null && !"".equals( infoID.trim() ) ) {
779 cInfo = getConversionInfoFromID( infoID );
780 }
781 // if ( cInfo == null ) {
782 // cInfo = new Helmert( "Created by DeegreeCRSProvider" );
783 // }
784 } catch ( XMLParsingException e ) {
785 throw new CRSConfigurationException(
786 Messages.getMessage( "CRS_CONFIG_PARSE_ERROR",
787 "wgs84ConversionInfo",
788 datumElement.getLocalName(), e.getMessage() ),
789 e );
790 }
791
792 result = new GeodeticDatum( ellipsoid, pMeridian, cInfo, id.getIdentifiers(), id.getNames(),
793 id.getVersions(), id.getDescriptions(), id.getAreasOfUse() );
794 }
795 return getProvider().addIdToCache( result, false );
796
797 }
798
799 /**
800 * @param meridianID
801 * the id to search for.
802 * @return the primeMeridian with given id or <code>null</code>
803 * @throws CRSConfigurationException
804 * if the longitude was not set or the units could not be parsed.
805 */
806 protected PrimeMeridian getPrimeMeridianFromID( String meridianID )
807 throws CRSConfigurationException {
808 if ( meridianID == null || "".equals( meridianID.trim() ) ) {
809 return null;
810 }
811 PrimeMeridian result = getProvider().getCachedIdentifiable( PrimeMeridian.class, meridianID );
812 if ( result == null ) {
813 Element meridianElement = null;
814 try {
815 meridianElement = getURIAsType( meridianID );
816 } catch ( IOException e ) {
817 throw new CRSConfigurationException( e );
818 }
819 if ( meridianElement == null ) {
820 throw new CRSConfigurationException( Messages.getMessage( "CRS_CONFIG_NO_ELEMENT", "primeMeridian",
821 meridianID ) );
822 }
823 Identifiable id = parseIdentifiable( meridianElement );
824 Unit units = parseUnit( meridianElement );
825 double longitude = 0;
826 try {
827 longitude = XMLTools.getRequiredNodeAsDouble( meridianElement, PRE + "longitude", nsContext );
828 boolean inDegrees = XMLTools.getNodeAsBoolean( meridianElement, PRE + "longitude/@inDegrees",
829 nsContext, true );
830 longitude = ( longitude != 0 && inDegrees ) ? Math.toRadians( longitude ) : longitude;
831 } catch ( XMLParsingException e ) {
832 throw new CRSConfigurationException( Messages.getMessage( "CRS_CONFIG_PARSE_ERROR", "longitude",
833 meridianElement.getLocalName(),
834 e.getMessage() ), e );
835 }
836 result = new PrimeMeridian( units, longitude, id );
837 }
838 return getProvider().addIdToCache( result, false );
839 }
840
841 /**
842 * Tries to find a cached ellipsoid, if not found, the config will be checked.
843 *
844 * @param ellipsoidID
845 * @return an ellipsoid or <code>null</code> if no ellipsoid with given id was found, or the id was
846 * <code>null</code> or empty.
847 * @throws CRSConfigurationException
848 * if something went wrong.
849 */
850 protected Ellipsoid getEllipsoidFromID( String ellipsoidID )
851 throws CRSConfigurationException {
852 if ( ellipsoidID == null || "".equals( ellipsoidID.trim() ) ) {
853 return null;
854 }
855 Ellipsoid result = getProvider().getCachedIdentifiable( Ellipsoid.class, ellipsoidID );
856 if ( result == null ) {
857 Element ellipsoidElement = null;
858 try {
859 ellipsoidElement = getURIAsType( ellipsoidID );
860 } catch ( IOException e ) {
861 throw new CRSConfigurationException( e );
862 }
863 if ( ellipsoidElement == null ) {
864 throw new CRSConfigurationException( Messages.getMessage( "CRS_CONFIG_NO_ELEMENT", "ellipsoid",
865 ellipsoidID ) );
866 }
867 Identifiable id = parseIdentifiable( ellipsoidElement );
868 Unit units = parseUnit( ellipsoidElement );
869
870 double semiMajor = Double.NaN;
871 double inverseFlattening = Double.NaN;
872 double eccentricity = Double.NaN;
873 double semiMinorAxis = Double.NaN;
874
875 try {
876 semiMajor = XMLTools.getRequiredNodeAsDouble( ellipsoidElement, PRE + "semiMajorAxis", nsContext );
877 inverseFlattening = XMLTools.getNodeAsDouble( ellipsoidElement, PRE + "inverseFlattening", nsContext,
878 Double.NaN );
879 eccentricity = XMLTools.getNodeAsDouble( ellipsoidElement, PRE + "eccentricity", nsContext, Double.NaN );
880 semiMinorAxis = XMLTools.getNodeAsDouble( ellipsoidElement, PRE + "semiMinorAxis", nsContext,
881 Double.NaN );
882 } catch ( XMLParsingException e ) {
883 throw new CRSConfigurationException( Messages.getMessage( "CRS_CONFIG_PARSE_ERROR", "ellipsoid",
884 ellipsoidElement.getLocalName(),
885 e.getMessage() ), e );
886 }
887 if ( Double.isNaN( inverseFlattening ) && Double.isNaN( eccentricity ) && Double.isNaN( semiMinorAxis ) ) {
888 throw new CRSConfigurationException( Messages.getMessage( "CRS_CONFIG_ELLIPSOID_MISSES_PARAM",
889 ellipsoidID ) );
890 }
891 if ( !Double.isNaN( inverseFlattening ) ) {
892 result = new Ellipsoid( semiMajor, units, inverseFlattening, id.getIdentifiers(), id.getNames(),
893 id.getVersions(), id.getDescriptions(), id.getAreasOfUse() );
894 } else if ( !Double.isNaN( eccentricity ) ) {
895 result = new Ellipsoid( semiMajor, eccentricity, units, id.getIdentifiers(), id.getNames(),
896 id.getVersions(), id.getDescriptions(), id.getAreasOfUse() );
897 } else {
898 result = new Ellipsoid( units, semiMajor, semiMinorAxis, id.getIdentifiers(), id.getNames(),
899 id.getVersions(), id.getDescriptions(), id.getAreasOfUse() );
900 }
901 }
902
903 return getProvider().addIdToCache( result, false );
904 }
905
906 /**
907 * @param infoID
908 * to get the conversioninfo from.
909 * @return the configured wgs84 conversion info parameters.
910 * @throws CRSConfigurationException
911 */
912 protected Helmert getConversionInfoFromID( String infoID )
913 throws CRSConfigurationException {
914 if ( infoID == null || "".equals( infoID.trim() ) ) {
915 return null;
916 }
917 LOG.logDebug( "Searching for the wgs84 with id: " + infoID );
918 Helmert result = getProvider().getCachedIdentifiable( Helmert.class, infoID );
919 if ( result == null ) {
920
921 Element cInfoElement = null;
922 try {
923 cInfoElement = getURIAsType( infoID );
924 } catch ( IOException e ) {
925 throw new CRSConfigurationException( e );
926 }
927 if ( cInfoElement == null ) {
928 throw new CRSConfigurationException( Messages.getMessage( "CRS_CONFIG_NO_ELEMENT",
929 "wgs84ConversionInfo", infoID ) );
930 }
931 Identifiable identifiable = parseIdentifiable( cInfoElement );
932 double xT = 0, yT = 0, zT = 0, xR = 0, yR = 0, zR = 0, scale = 0;
933 try {
934 xT = XMLTools.getNodeAsDouble( cInfoElement, PRE + "xAxisTranslation", nsContext, 0 );
935 yT = XMLTools.getNodeAsDouble( cInfoElement, PRE + "yAxisTranslation", nsContext, 0 );
936 zT = XMLTools.getNodeAsDouble( cInfoElement, PRE + "zAxisTranslation", nsContext, 0 );
937 xR = XMLTools.getNodeAsDouble( cInfoElement, PRE + "xAxisRotation", nsContext, 0 );
938 yR = XMLTools.getNodeAsDouble( cInfoElement, PRE + "yAxisRotation", nsContext, 0 );
939 zR = XMLTools.getNodeAsDouble( cInfoElement, PRE + "zAxisRotation", nsContext, 0 );
940 scale = XMLTools.getNodeAsDouble( cInfoElement, PRE + "scaleDifference", nsContext, 0 );
941 } catch ( XMLParsingException e ) {
942 throw new CRSConfigurationException( Messages.getMessage( "CRS_CONFIG_PARSE_ERROR", "conversionInfo",
943 "definitions", e.getMessage() ), e );
944 }
945 result = new Helmert( xT, yT, zT, xR, yR, zR, scale, null, GeographicCRS.WGS84, identifiable );
946 }
947 return getProvider().addIdToCache( result, false );
948 }
949
950 /**
951 * Parses and instantiates the projection from the given element.
952 *
953 * @param projectionElement
954 * to create the projection from.
955 * @param underlyingCRS
956 * of the projected crs
957 * @param units
958 * of the projected crs
959 * @return the configured projection or <code>null</code> if not defined or found.
960 * @throws CRSConfigurationException
961 */
962 protected Projection parseProjection( Element projectionElement, GeographicCRS underlyingCRS, Unit units )
963 throws CRSConfigurationException {
964 if ( projectionElement == null ) {
965 throw new CRSConfigurationException(
966 Messages.getMessage( "CRS_INVALID_NULL_PARAMETER", "projectionElement" ) );
967 }
968 try {
969 Element usedProjection = XMLTools.getRequiredElement( projectionElement, "*[1]", nsContext );
970 // All projections will have following parameters
971 double latitudeOfNaturalOrigin = XMLTools.getNodeAsDouble( usedProjection, PRE + "latitudeOfNaturalOrigin",
972 nsContext, 0 );
973 boolean inDegrees = XMLTools.getNodeAsBoolean( usedProjection, PRE + "latitudeOfNaturalOrigin/@inDegrees",
974 nsContext, true );
975 latitudeOfNaturalOrigin = ( latitudeOfNaturalOrigin != 0 && inDegrees ) ? Math.toRadians( latitudeOfNaturalOrigin )
976 : latitudeOfNaturalOrigin;
977
978 double longitudeOfNaturalOrigin = XMLTools.getNodeAsDouble( usedProjection, PRE
979 + "longitudeOfNaturalOrigin",
980 nsContext, 0 );
981 inDegrees = XMLTools.getNodeAsBoolean( usedProjection, PRE + "longitudeOfNaturalOrigin/@inDegrees",
982 nsContext, true );
983 longitudeOfNaturalOrigin = ( longitudeOfNaturalOrigin != 0 && inDegrees ) ? Math.toRadians( longitudeOfNaturalOrigin )
984 : longitudeOfNaturalOrigin;
985
986 double scaleFactor = XMLTools.getNodeAsDouble( usedProjection, PRE + "scaleFactor", nsContext, 0 );
987 double falseEasting = XMLTools.getNodeAsDouble( usedProjection, PRE + "falseEasting", nsContext, 0 );
988 double falseNorthing = XMLTools.getNodeAsDouble( usedProjection, PRE + "falseNorthing", nsContext, 0 );
989
990 String projectionName = usedProjection.getLocalName().trim();
991 String className = projectionElement.getAttribute( "class" );
992 Point2d naturalOrigin = new Point2d( longitudeOfNaturalOrigin, latitudeOfNaturalOrigin );
993 Projection result = null;
994 if ( className != null && !"".equals( className.trim() ) ) {
995 LOG.logDebug( "Trying to load user defined projection class: " + className );
996 try {
997 Class<?> t = Class.forName( className );
998 t.asSubclass( Projection.class );
999 /**
1000 * try to get a constructor with a native type as a parameter, by going over the 'names' of the
1001 * classes of the parameters, the native type will show up as the typename e.g. int or long.....
1002 * <code>
1003 * public Projection( GeographicCRS geographicCRS, double falseNorthing, double falseEasting,
1004 * Point2d naturalOrigin, Unit units, double scale, boolean conformal, boolean equalArea )
1005 * </code>
1006 */
1007 List<Element> children = XMLTools.getElements( usedProjection, "*", nsContext );
1008 List<Element> otherValues = new LinkedList<Element>();
1009 for ( Element child : children ) {
1010 if ( child != null ) {
1011 String localName = child.getLocalName().trim();
1012 if ( !( "latitudeOfNaturalOrigin".equals( localName )
1013 || "longitudeOfNaturalOrigin".equals( localName )
1014 || "scaleFactor".equals( localName ) || "falseEasting".equals( localName ) || "falseNorthing".equals( localName ) ) ) {
1015 otherValues.add( child );
1016 }
1017 }
1018 }
1019 /**
1020 * Load the constructor with the standard projection values and the element list.
1021 */
1022 Constructor<?> constructor = t.getConstructor( GeographicCRS.class, double.class, double.class,
1023 Point2d.class, Unit.class, double.class, List.class );
1024 result = (Projection) constructor.newInstance( underlyingCRS, falseNorthing, falseEasting,
1025 naturalOrigin, units, scaleFactor, otherValues );
1026 } catch ( ClassNotFoundException e ) {
1027 LOG.logError( e.getMessage(), e );
1028 } catch ( SecurityException e ) {
1029 LOG.logError( e.getMessage(), e );
1030 } catch ( NoSuchMethodException e ) {
1031 LOG.logError( e.getMessage(), e );
1032 } catch ( IllegalArgumentException e ) {
1033 LOG.logError( e.getMessage(), e );
1034 } catch ( InstantiationException e ) {
1035 LOG.logError( e.getMessage(), e );
1036 } catch ( IllegalAccessException e ) {
1037 LOG.logError( e.getMessage(), e );
1038 } catch ( InvocationTargetException e ) {
1039 LOG.logError( e.getMessage(), e );
1040 }
1041 if ( result == null ) {
1042 LOG.logDebug( "Loading of user defined transformation class: " + className + " was not successful" );
1043 }
1044
1045 } else {
1046 // no selfdefined projection, try one of the following, for the projection specific parameters, if any.
1047 if ( "transverseMercator".equalsIgnoreCase( projectionName ) ) {
1048 // change schema to let projection be identifiable. fix method geodetic
1049 boolean northernHemi = XMLTools.getNodeAsBoolean( usedProjection, PRE + "northernHemisphere",
1050 nsContext, true );
1051 result = new TransverseMercator( northernHemi, underlyingCRS, falseNorthing, falseEasting,
1052 naturalOrigin, units, scaleFactor );
1053 } else if ( "lambertAzimuthalEqualArea".equalsIgnoreCase( projectionName ) ) {
1054 result = new LambertAzimuthalEqualArea( underlyingCRS, falseNorthing, falseEasting, naturalOrigin,
1055 units, scaleFactor );
1056 } else if ( "lambertConformalConic".equalsIgnoreCase( projectionName ) ) {
1057 double firstP = XMLTools.getNodeAsDouble( usedProjection, PRE + "firstParallelLatitude", nsContext,
1058 Double.NaN );
1059 inDegrees = XMLTools.getNodeAsBoolean( usedProjection, PRE + "firstParallelLatitude/@inDegrees",
1060 nsContext, true );
1061 firstP = ( !Double.isNaN( firstP ) && inDegrees ) ? Math.toRadians( firstP ) : firstP;
1062
1063 double secondP = XMLTools.getNodeAsDouble( usedProjection, PRE + "secondParallelLatitude",
1064 nsContext, Double.NaN );
1065 inDegrees = XMLTools.getNodeAsBoolean( usedProjection, PRE + "secondParallelLatitude/@inDegrees",
1066 nsContext, true );
1067 secondP = ( !Double.isNaN( secondP ) && inDegrees ) ? Math.toRadians( secondP ) : secondP;
1068 result = new LambertConformalConic( firstP, secondP, underlyingCRS, falseNorthing, falseEasting,
1069 naturalOrigin, units, scaleFactor );
1070 } else if ( "stereographicAzimuthal".equalsIgnoreCase( projectionName ) ) {
1071 double trueScaleL = XMLTools.getNodeAsDouble( usedProjection, PRE + "trueScaleLatitude", nsContext,
1072 Double.NaN );
1073 inDegrees = XMLTools.getNodeAsBoolean( usedProjection, PRE + "trueScaleLatitude/@inDegrees",
1074 nsContext, true );
1075 trueScaleL = ( !Double.isNaN( trueScaleL ) && inDegrees ) ? Math.toRadians( trueScaleL )
1076 : trueScaleL;
1077 result = new StereographicAzimuthal( trueScaleL, underlyingCRS, falseNorthing, falseEasting,
1078 naturalOrigin, units, scaleFactor );
1079 } else if ( "StereographicAlternative".equalsIgnoreCase( projectionName ) ) {
1080 result = new StereographicAlternative( underlyingCRS, falseNorthing, falseEasting, naturalOrigin,
1081 units, scaleFactor );
1082 } else if ( "mercator".equalsIgnoreCase( projectionName ) ) {
1083 result = new Mercator( underlyingCRS, falseNorthing, falseEasting, naturalOrigin, units,
1084 scaleFactor );
1085 } else {
1086 throw new CRSConfigurationException(
1087 Messages.getMessage(
1088 "CRS_CONFIG_PROJECTEDCRS_INVALID_PROJECTION",
1089 projectionName,
1090 "StereographicAlternative, stereographicAzimuthal, lambertConformalConic, lambertAzimuthalEqualArea, transverseMercator" ) );
1091
1092 }
1093 }
1094 return result;
1095 } catch ( XMLParsingException e ) {
1096 throw new CRSConfigurationException(
1097 Messages.getMessage( "CRS_CONFIG_PARSE_ERROR",
1098 "projection parameters",
1099 projectionElement.getLocalName(), e.getMessage() ),
1100 e );
1101
1102 }
1103 }
1104
1105 /**
1106 * @param <T>
1107 * should be at least of Type Identifiable.
1108 * @param uniqueList
1109 * to check against
1110 * @param mapping
1111 * to added the id of T to if it is found duplicate.
1112 * @param toBeChecked
1113 * to check.
1114 * @return the cached T if found or the given identifiable.
1115 */
1116 protected <T extends Identifiable> T checkForUniqueness( List<T> uniqueList, Map<String, String> mapping,
1117 T toBeChecked ) {
1118 T result = toBeChecked;
1119 if ( uniqueList.contains( toBeChecked ) ) {
1120 int index = uniqueList.indexOf( toBeChecked );
1121 LOG.logInfo( "The Identifiable with id: " + toBeChecked.getIdentifier() + " was found to be equal with: "
1122 + uniqueList.get( index ).getIdentifier() );
1123 String key = uniqueList.get( index ).getIdentifier();
1124 boolean updatedEPSG = false;
1125 if ( key != null && !"".equals( key.trim() ) ) {
1126 String value = mapping.get( key );
1127 String tbcID = toBeChecked.getIdentifier().toUpperCase();
1128 // it would be nicest to get the epsg code if any.
1129 if ( !key.toUpperCase().startsWith( "EPSG:" ) && tbcID.startsWith( "EPSG:" ) ) {
1130 if ( value == null || "".equals( value ) ) {
1131 value = key;
1132 } else {
1133 value += ", " + key;
1134 }
1135 updatedEPSG = true;
1136 mapping.remove( key );
1137 key = toBeChecked.getIdentifier();
1138 } else {
1139 if ( value == null || "".equals( value ) ) {
1140 value = toBeChecked.getIdentifier();
1141 } else {
1142 value += ", " + toBeChecked.getIdentifier();
1143 }
1144 }
1145 mapping.put( key, value );
1146 }
1147 // if updated to epsg, cache the epsg instead and remove the old identifiable.
1148 if ( updatedEPSG ) {
1149 uniqueList.remove( index );
1150 uniqueList.add( toBeChecked );
1151 } else {
1152 result = uniqueList.get( index );
1153 }
1154 } else {
1155 LOG.logDebug( "Adding: " + toBeChecked.getIdentifier() + " to cache." );
1156 uniqueList.add( toBeChecked );
1157 }
1158 return result;
1159 }
1160
1161 public Transformation getTransformation( CoordinateSystem sourceCRS, CoordinateSystem targetCRS ) {
1162 LOG.logError( "The retrieval of transformations is not supported for this deegree crs configuration format." );
1163 return null;
1164 }
1165
1166 /**
1167 * Gets the Element for the given id and heuristically check the localname of the resulting root Element. This
1168 * version supports following local names (see schema): <code>
1169 * <ul>
1170 * <li>ellipsoid</li>
1171 * <li>geodeticDatum</li>
1172 * <li>projectedCRS</li>
1173 * <li>geographicCRS</li>
1174 * <li>compoundCRS</li>
1175 * <li>geocentricCRS</li>
1176 * <li>primeMeridian</li>
1177 * <li>wgs84Transformation</li>
1178 * </ul>
1179 * </code>
1180 *
1181 * @param id
1182 * to look for.
1183 * @return the instantiated {@link Identifiable} or <code>null</code> if it could not be parsed.
1184 */
1185 public Identifiable parseIdentifiableObject( String id ) {
1186 if ( id == null || "".equals( id ) ) {
1187 return null;
1188 }
1189 Element resolvedID = null;
1190 try {
1191 resolvedID = getURIAsType( id );
1192 } catch ( IOException e ) {
1193 throw new CRSConfigurationException( e );
1194 }
1195 Identifiable result = null;
1196 if ( resolvedID != null ) {
1197 String localName = resolvedID.getLocalName();
1198 if ( localName != null && !"".equals( localName.trim() ) ) {
1199 if ( localName.equals( "ellipsoid" ) ) {
1200 result = getEllipsoidFromID( id );
1201 } else if ( localName.equals( "geodeticDatum" ) ) {
1202 result = getGeodeticDatumFromID( id );
1203 } else if ( localName.equals( "projectedCRS" ) || localName.equals( "geographicCRS" )
1204 || localName.equals( "compoundCRS" ) || localName.equals( "geocentricCRS" ) ) {
1205 result = getProvider().getCRSByID( id );
1206 } else if ( localName.equals( "primeMeridian" ) ) {
1207 result = getPrimeMeridianFromID( id );
1208 } else if ( localName.equals( "wgs84Transformation" ) ) {
1209 result = getConversionInfoFromID( id );
1210 }
1211 }
1212 }
1213 return result;
1214 }
1215 }