/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2015, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.coverage.io.netcdf.crs; import java.util.logging.Level; import java.util.logging.Logger; import org.geotools.imageio.netcdf.utilities.NetCDFUtilities; import org.geotools.referencing.crs.DefaultGeographicCRS; import org.geotools.referencing.operation.projection.AlbersEqualArea; import org.geotools.referencing.operation.projection.LambertAzimuthalEqualArea; import org.geotools.referencing.operation.projection.LambertConformal1SP; import org.geotools.referencing.operation.projection.LambertConformal2SP; import org.geotools.referencing.operation.projection.Mercator1SP; import org.geotools.referencing.operation.projection.Mercator2SP; import org.geotools.referencing.operation.projection.Orthographic; import org.geotools.referencing.operation.projection.PolarStereographic; import org.geotools.referencing.operation.projection.RotatedPole; import org.geotools.referencing.operation.projection.Stereographic; import org.geotools.referencing.operation.projection.TransverseMercator; import org.geotools.util.logging.Logging; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.crs.ProjectedCRS; import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.Projection; /** * Enum used to represent different coordinate reference systems stored within a NetCDF dataset. * NetCDF CF supports several types of projections through grid mapping. * * Unsupported projections will be specified through the spatial_ref and GeoTransform global attributes * defined by GDAL. * * @see <a href="http://cfconventions.org/Data/cf-conventions/cf-conventions-1.6/build/cf-conventions.html#appendix-grid-mappings">NetCDF CF, Appendix * F: Grid Mappings</a> * * @author Daniele Romagnoli, GeoSolutions SAS */ public enum NetCDFCoordinateReferenceSystemType { WGS84 { @Override public NetCDFCoordinate[] getCoordinates() { return NetCDFCoordinate.LATLON_COORDS; } @Override public NetCDFProjection getNetCDFProjection() { // No projection/gridMapping is needed for WGS84. // Coordinates can be used as is return null; } }, SPATIAL_REF { @Override public NetCDFProjection getNetCDFProjection() { // No Specific NetCDF CF Projection is available for this type. // We need to parse the SPATIAL_REF attribute // to setup a proper one return null; } }, ALBERS_EQUAL_AREA { @Override public NetCDFProjection getNetCDFProjection() { return NetCDFProjection.ALBERS_EQUAL_AREA; } }, LAMBERT_AZIMUTHAL_EQUAL_AREA { @Override public NetCDFProjection getNetCDFProjection() { return NetCDFProjection.LAMBERT_AZIMUTHAL_EQUAL_AREA; } }, LAMBERT_CONFORMAL_CONIC_1SP { @Override public NetCDFProjection getNetCDFProjection() { return NetCDFProjection.LAMBERT_CONFORMAL_CONIC_1SP; } }, LAMBERT_CONFORMAL_CONIC_2SP { @Override public NetCDFProjection getNetCDFProjection() { return NetCDFProjection.LAMBERT_CONFORMAL_CONIC_2SP; } }, MERCATOR_1SP { @Override public NetCDFProjection getNetCDFProjection() { return NetCDFProjection.MERCATOR_1SP; } }, MERCATOR_2SP { @Override public NetCDFProjection getNetCDFProjection() { return NetCDFProjection.MERCATOR_2SP; } }, TRANSVERSE_MERCATOR { @Override public NetCDFProjection getNetCDFProjection() { return NetCDFProjection.TRANSVERSE_MERCATOR; } }, ORTHOGRAPHIC { @Override public NetCDFProjection getNetCDFProjection() { return NetCDFProjection.ORTHOGRAPHIC; } }, POLAR_STEREOGRAPHIC { @Override public NetCDFProjection getNetCDFProjection() { return NetCDFProjection.POLAR_STEREOGRAPHIC; } }, STEREOGRAPHIC { @Override public NetCDFProjection getNetCDFProjection() { return NetCDFProjection.STEREOGRAPHIC; } }, ROTATED_POLE { @Override public NetCDFCoordinate[] getCoordinates() { return NetCDFCoordinate.RLATLON_COORDS; } @Override public NetCDFProjection getNetCDFProjection() { return NetCDFProjection.ROTATED_POLE; } }; /* TODO: THESE CRSs still need to be added * AZIMUTHAL_EQUIDISTANT, LAMBERT_CYLINDRICAL_EQUAL_AREA */ /** * Return a proper {@link NetCDFCoordinateReferenceSystemType} depending * on the input OGC {@link CoordinateReferenceSystem} instance. * * @param crs * @return */ public static NetCDFCoordinateReferenceSystemType parseCRS(CoordinateReferenceSystem crs) { NetCDFCoordinateReferenceSystemType crsType = null; if (crs instanceof DefaultGeographicCRS) { crsType = WGS84; } else if (crs instanceof ProjectedCRS) { ProjectedCRS projectedCRS = (ProjectedCRS) crs; Projection projection = projectedCRS.getConversionFromBase(); MathTransform transform = projection.getMathTransform(); if (transform instanceof TransverseMercator) { crsType = TRANSVERSE_MERCATOR; } else if (transform instanceof LambertConformal1SP) { crsType = LAMBERT_CONFORMAL_CONIC_1SP; } else if (transform instanceof LambertConformal2SP) { crsType = LAMBERT_CONFORMAL_CONIC_2SP; } else if (transform instanceof LambertAzimuthalEqualArea) { crsType = LAMBERT_AZIMUTHAL_EQUAL_AREA; } else if (transform instanceof Orthographic) { crsType = ORTHOGRAPHIC; } else if (transform instanceof PolarStereographic) { crsType = POLAR_STEREOGRAPHIC; } else if (transform instanceof Stereographic) { crsType = STEREOGRAPHIC; } else if (transform instanceof Mercator1SP) { crsType = MERCATOR_1SP; } else if (transform instanceof Mercator2SP) { crsType = MERCATOR_2SP; } else if (transform instanceof AlbersEqualArea) { crsType = ALBERS_EQUAL_AREA; } else if (transform instanceof RotatedPole) { crsType = ROTATED_POLE; } } else { // Fallback on SPATIAL_REF to deal with projection which // doesn't have a CF Mapping. crsType = SPATIAL_REF; } if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine("Using a NetCDF CRS based on " + crsType); } return crsType; } /** * Return the set of {@link NetCDFCoordinate}s for this NetCDF CRS type. * As an instance, WGS84 type uses Latitude,Longitude while * Mercator uses GeoY,GeoX. * Default implementation returns {@link NetCDFCoordinate#YX_COORDS} * since most part of the CRS Type are projected. * @return */ public NetCDFCoordinate[] getCoordinates() { return NetCDFCoordinate.YX_COORDS; } /** * Return a {@link NetCDFProjection} instance for this * specific CRS type. Note that WGS84 CRS and SPATIAL_REF * won't return a NetCDF CF projection. */ public abstract NetCDFProjection getNetCDFProjection(); private final static Logger LOGGER = Logging.getLogger(NetCDFCoordinateReferenceSystemType.class.toString()); /** * Contains basic information related to a NetCDF Coordinate such as: * - short name (as an instance: x) * - long name (as an instance: x coordinate of projection) * - standard name (as an instance: projection_x_coordinate) * - the name of the associated dimension (as an instance: x) * - the unit of measure of that coordinate (as an instance: m) */ public static class NetCDFCoordinate { private final static NetCDFCoordinate LAT_COORDINATE = new NetCDFCoordinate( NetCDFUtilities.LAT, NetCDFUtilities.LATITUDE, NetCDFUtilities.LATITUDE, NetCDFUtilities.LAT, NetCDFUtilities.LAT_UNITS); private final static NetCDFCoordinate LON_COORDINATE = new NetCDFCoordinate( NetCDFUtilities.LON, NetCDFUtilities.LONGITUDE, NetCDFUtilities.LONGITUDE, NetCDFUtilities.LON, NetCDFUtilities.LON_UNITS); private final static NetCDFCoordinate RLAT_COORDINATE = new NetCDFCoordinate( NetCDFUtilities.RLAT, NetCDFUtilities.GRID_LATITUDE, NetCDFUtilities.GRID_LATITUDE, NetCDFUtilities.RLAT, NetCDFUtilities.RLATLON_UNITS); private final static NetCDFCoordinate RLON_COORDINATE = new NetCDFCoordinate( NetCDFUtilities.RLON, NetCDFUtilities.GRID_LONGITUDE, NetCDFUtilities.GRID_LONGITUDE, NetCDFUtilities.RLON, NetCDFUtilities.RLATLON_UNITS); private final static NetCDFCoordinate X_COORDINATE = new NetCDFCoordinate( NetCDFUtilities.X, NetCDFUtilities.X_COORD_PROJ, NetCDFUtilities.X_PROJ_COORD, NetCDFUtilities.X, NetCDFUtilities.M); private final static NetCDFCoordinate Y_COORDINATE = new NetCDFCoordinate( NetCDFUtilities.Y, NetCDFUtilities.Y_COORD_PROJ, NetCDFUtilities.Y_PROJ_COORD, NetCDFUtilities.Y, NetCDFUtilities.M); public final static NetCDFCoordinate[] LATLON_COORDS = new NetCDFCoordinate[] { LAT_COORDINATE, LON_COORDINATE }; public final static NetCDFCoordinate[] RLATLON_COORDS = new NetCDFCoordinate[] { RLAT_COORDINATE, RLON_COORDINATE }; public final static NetCDFCoordinate[] YX_COORDS = new NetCDFCoordinate[] { Y_COORDINATE, X_COORDINATE }; /** short name. (as an instance: x) */ private String shortName; /** the name of the associated dimension. (as an instance: x) */ private String dimensionName; /** long name. (as an instance: x coordinate of projection) */ private String longName; /** unit of measure of that coordinate (as an instance: m) */ private String units; /** standard name (as an instance: projection_x_coordinate) */ private String standardName; public String getShortName() { return shortName; } public void setShortName(String shortName) { this.shortName = shortName; } public String getDimensionName() { return dimensionName; } public void setDimensionName(String dimensionName) { this.dimensionName = dimensionName; } public String getLongName() { return longName; } public void setName(String longName) { this.longName = longName; } public String getStandardName() { return standardName; } public void setStandardName(String standardName) { this.standardName = standardName; } public String getUnits() { return units; } public void setUnits(String units) { this.units = units; } @Override public String toString() { return "NetCDFCoordinate [shortName=" + shortName + ", dimensionName=" + dimensionName + ", longName=" + longName + ", units=" + units + ", standardName=" + standardName + "]"; } /** * Create a {@link NetCDFCoordinate} instance with all the required information */ public NetCDFCoordinate(String shortName, String longName, String standardName, String dimensionName, String units) { this.shortName = shortName; this.longName = longName; this.standardName = standardName; this.dimensionName = dimensionName; this.units = units; } } }