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 }