/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2005-2008, 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.grid.io.imageio.geotiff;
import java.lang.ref.Reference;
import java.text.ParseException;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.measure.unit.NonSI;
import javax.measure.unit.SI;
import javax.measure.unit.Unit;
import org.geotools.coverage.grid.io.imageio.geotiff.codes.GeoTiffCoordinateTransformationsCodes;
import org.geotools.coverage.grid.io.imageio.geotiff.codes.GeoTiffGCSCodes;
import org.geotools.coverage.grid.io.imageio.geotiff.codes.GeoTiffPCSCodes;
import org.geotools.coverage.grid.io.imageio.geotiff.codes.GeoTiffUoMCodes;
import org.geotools.metadata.iso.citation.Citations;
import org.geotools.referencing.AbstractIdentifiedObject;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.referencing.datum.DefaultEllipsoid;
import org.geotools.referencing.datum.DefaultGeodeticDatum;
import org.geotools.referencing.datum.DefaultPrimeMeridian;
import org.geotools.referencing.operation.projection.AlbersEqualArea;
import org.geotools.referencing.operation.projection.LambertAzimuthalEqualArea;
import org.geotools.referencing.operation.projection.LambertConformal;
import org.geotools.referencing.operation.projection.MapProjection;
import org.geotools.referencing.operation.projection.Mercator;
import org.geotools.referencing.operation.projection.ObliqueMercator;
import org.geotools.referencing.operation.projection.ObliqueStereographic;
import org.geotools.referencing.operation.projection.Orthographic;
import org.geotools.referencing.operation.projection.PolarStereographic;
import org.geotools.referencing.operation.projection.Stereographic;
import org.geotools.referencing.operation.projection.TransverseMercator;
import org.geotools.referencing.operation.transform.ConcatenatedTransform;
import org.geotools.resources.CRSUtilities;
import org.geotools.resources.i18n.ErrorKeys;
import org.geotools.resources.i18n.Errors;
import org.geotools.util.SoftValueHashMap;
import org.opengis.metadata.Identifier;
import org.opengis.metadata.citation.Citation;
import org.opengis.parameter.GeneralParameterValue;
import org.opengis.parameter.ParameterValue;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.referencing.IdentifiedObject;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.crs.GeographicCRS;
import org.opengis.referencing.crs.ProjectedCRS;
import org.opengis.referencing.cs.EllipsoidalCS;
import org.opengis.referencing.datum.Ellipsoid;
import org.opengis.referencing.datum.GeodeticDatum;
import org.opengis.referencing.datum.PrimeMeridian;
import org.opengis.referencing.operation.Conversion;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.OperationMethod;
/**
* This class implements a simple reusable adapter to adapt a
* {@link CoordinateReferenceSystem} into useful Geotiff metadata by mean of
* {@link GeoTiffIIOMetadataEncoder}.
*
* <p>
* Since {@link CoordinateReferenceSystem} are essentially immutable this class
* implements a static pool of {@link CRS2GeoTiffMetadataAdapter} objects that
* would allow to avoid parsing the same {@link CoordinateReferenceSystem} more
* than once.
*
* @author Simone Giannecchini
*
* @since 2.2
*
* @source $URL:
* http://svn.geotools.org/geotools/trunk/gt/plugin/geotiff/src/org/geotools/gce/geotiff/crs_adapters/CRS2GeoTiffMetadataAdapter.java $
*/
public final class CRS2GeoTiffMetadataAdapter {
/**
* The default value for {@link #maxStrongReferences} .
*/
public static final int DEFAULT_MAX = 100;
/**
* The pool of cached objects.
*/
private final static Map pool = Collections
.synchronizedMap(new SoftValueHashMap(DEFAULT_MAX));
/**
* The {@link CoordinateReferenceSystem} to be get the metadata from:
*/
private CoordinateReferenceSystem crs;
/**
* Returns an object from the pool for the specified code. If the object was
* retained as a {@linkplain Reference weak reference}, the
* {@link Reference#get referent} is returned.
*
* @todo Consider logging a message here to the finer or finest level.
*/
public static Object get(final Object key) {
synchronized (pool) {
Object object = pool.get(key);
if (object == null) {
object = new CRS2GeoTiffMetadataAdapter(
(CoordinateReferenceSystem) key);
put(key, object);
}
return object;
}
}
/**
* Releases resources immediately instead of waiting for the garbage
* collector.
*/
public static void clear() {
synchronized (pool) {
pool.clear();
}
}
/**
* Put an element in the pool. This method is invoked everytime a
* {@code createFoo(...)} method is invoked, even if an object was already
* in the pool for the given code, for the following reasons: 1) Replaces
* weak reference by strong reference (if applicable) and 2) Alters the
* linked hash set order, so that this object is declared as the last one
* used.
*/
private static void put(final Object key, final Object object) {
synchronized (pool) {
pool.put(key, object);
}
}
/**
* Constructs a parser using the default set of symbols and factories.
*/
public CRS2GeoTiffMetadataAdapter(final CoordinateReferenceSystem crs) {
this.crs = crs;
}
/**
* Searches for an EPSG code inside this <code>IdentifiedObject</code>.
*
* <p>
* It is important to remark that this function should be seen as an hack
* hence it may change in the near future. DO not rely on it!
*
* @param obj
* An <code>IdentifiedObject</code> to look for an EPSG code
* into.
* @return An EPSG numeric code, if one is found, -1 otherwise.
*/
private static int getEPSGCode(final IdentifiedObject obj) {
// looking for an EPSG code
final Set<? extends Identifier> identifiers = obj.getIdentifiers();
final Iterator<? extends Identifier> it = identifiers.iterator();
String code = "";
Citation cite;
Identifier identifier;
while (it.hasNext()) {
identifier = it.next();
cite = identifier.getAuthority();
if (Citations.identifierMatches(cite, "EPSG")) {
code = identifier.getCode();
break;
}
}
try {
return Integer.parseInt(code);
} catch (Exception e) {
}
// an error occurred;
return -1;
}
/**
* Parses a coordinate reference system.
*
* <p>
* For the moment we can only encode geographic and projected coordinate
* reference systems, we cannot encode the other types like vertical
* coordinate reference systems.
*
* @throws GeoTiffException
*/
public GeoTiffIIOMetadataEncoder parseCoordinateReferenceSystem()
throws GeoTiffException {
final GeoTiffIIOMetadataEncoder metadata = new GeoTiffIIOMetadataEncoder();
// /////////////////////////////////////////////////////////////////////
//
// CREATING METADATA AND SETTING BASE FIELDS FOR THEM
//
// /////////////////////////////////////////////////////////////////////
// model type
final int modelType = (crs instanceof ProjectedCRS) ? 1 : 2;
// GTModelTypeGeoKey
metadata
.addGeoShortParam(GeoTiffConstants.GTModelTypeGeoKey, modelType);
switch (modelType) {
// /////////////////////////////////////////////////////////////////////
//
// GEOGRAPHIC COORDINATE REFERENCE SYSTEMCREATING METADATA AND SETTING
// BASE FIELDS FOR THEM
//
// /////////////////////////////////////////////////////////////////////
case GeoTiffGCSCodes.ModelTypeGeographic:
parseGeoGCS((DefaultGeographicCRS) crs, metadata);
break;
// /////////////////////////////////////////////////////////////////////
//
// PROJECTED COORDINATE REFERENCE SYSTEMCREATING METADATA AND SETTING
// BASE FIELDS FOR THEM
//
// /////////////////////////////////////////////////////////////////////
case GeoTiffPCSCodes.ModelTypeProjected:
parseProjCRS((ProjectedCRS) crs, metadata);
break;
default:
throw new GeoTiffException(
null,
"The supplied grid coverage uses an unsupported crs! You are allowed to use only projected and geographic coordinate reference systems",
null);
}
return metadata;
//
// if ("VERT_CS".equals(keyword)) {
// parseVertCS(element);
// }
//
// if ("LOCAL_CS".equals(keyword)) {
// parseLocalCS(element);
// }
//
// if ("COMPD_CS".equals(keyword)) {
// parseCompdCS(element);
// }
//
// if ("FITTED_CS".equals(keyword)) {
// parseFittedCS(element);
// }
}
/**
* Parses a "PROJCS" element. This element has the following pattern:
*
* <blockquote><code>
* PROJCS["<name>", <geographic cs>, <projection>, {<parameter>,}*,
* <linear unit> {,<twin axes>}{,<authority>}]
* </code></blockquote>
*
* @param projectedCRS
* The parent element.
* @param metadata
* @return The "PROJCS" element as a {@link ProjectedCRS} object.
* @throws ParseException
* if the "GEOGCS" element can't be parsed.
*/
private void parseProjCRS(final ProjectedCRS projectedCRS,
GeoTiffIIOMetadataEncoder metadata) {
// do we have a code for this pcrs
final int code = getEPSGCode(projectedCRS);
if (code != -1) {
metadata.addGeoShortParam(GeoTiffPCSCodes.ProjectedCSTypeGeoKey,
code);
return;
}
// user defined projected coordinate reference system.
// key 3072
metadata.addGeoShortParam(GeoTiffPCSCodes.ProjectedCSTypeGeoKey, 32767);
// name of the user defined projected crs
// key 3073
// metadata.addGeoAscii(GeoTiffPCSCodes.PCSCitationGeoKey, projectedCRS
// .getName().getCode());
// projection
parseProjection(projectedCRS, metadata);
// geographic crs
parseGeoGCS((DefaultGeographicCRS) (projectedCRS.getBaseCRS()),
metadata);
}
/**
* Parsing ProjectionGeoKey 3074 for a <code>ProjectedCRS</code>.
*
* @param projectedCRS
* The <code>ProjectedCRS</code> to parse.
* @param metadata
*/
private void parseProjection(final ProjectedCRS projectedCRS,
final GeoTiffIIOMetadataEncoder metadata) {
// getting the conversion
final Conversion conversion = projectedCRS.getConversionFromBase();
final int code = getEPSGCode(conversion);
if (code != -1) {
metadata.addGeoShortParam(GeoTiffPCSCodes.ProjectionGeoKey, code);
return;
}
// user defined projection
// key 3074
final String conversionName = conversion.getName().getCode();
metadata.addGeoShortParam(GeoTiffPCSCodes.ProjectionGeoKey, 32767);
metadata.addGeoAscii(GeoTiffPCSCodes.PCSCitationGeoKey, conversionName);
final OperationMethod method = conversion.getMethod();
// looking for the parameters
String name = method.getName().getCode();
name = name.trim();
name = name.replace(' ', '_');
final MathTransform mt = conversion.getMathTransform();
final MapProjection projTransf;
if (!(mt instanceof ConcatenatedTransform))
projTransf = (MapProjection) mt;
else {
final ConcatenatedTransform tr = (ConcatenatedTransform) mt;
final MathTransform m1 = tr.transform1, m2 = tr.transform2;
if (m1 instanceof MapProjection)
projTransf = (MapProjection) m1;
else
projTransf = (MapProjection) m2;
}
// key 3075 and parameters
parseCoordinateProjectionTransform(projTransf, name, metadata);
// parse linear unit
parseLinearUnit(projectedCRS, metadata);
}
/**
* Parses a linear unit for a <code>ProjectedCRS</code>.
*
* @todo complete the list of linear unit of measures and clean the
* exception
* @param projectedCRS
* @param metadata
*/
private void parseLinearUnit(final ProjectedCRS projectedCRS,
GeoTiffIIOMetadataEncoder metadata) {
// getting the linear unit
final Unit linearUnit = CRSUtilities.getUnit(projectedCRS
.getCoordinateSystem());
if (linearUnit != null && !SI.METER.isCompatible(linearUnit)) {
throw new IllegalArgumentException(Errors.format(
ErrorKeys.NON_LINEAR_UNIT_$1, linearUnit));
}
if (SI.METER.isCompatible(linearUnit)) {
if (SI.METER.equals(linearUnit)) {
metadata.addGeoShortParam(
GeoTiffPCSCodes.ProjLinearUnitsGeoKey,
GeoTiffUoMCodes.Linear_Meter);
metadata.addGeoDoubleParam(
GeoTiffPCSCodes.ProjLinearUnitSizeGeoKey, 1.0);
}
if (NonSI.NAUTICAL_MILE.equals(linearUnit)) {
metadata.addGeoShortParam(
GeoTiffPCSCodes.ProjLinearUnitsGeoKey,
GeoTiffUoMCodes.Linear_Mile_International_Nautical);
metadata.addGeoDoubleParam(
GeoTiffPCSCodes.ProjLinearUnitSizeGeoKey, linearUnit
.getConverterTo(SI.METER).convert(1));
}
if (NonSI.FOOT.equals(linearUnit)) {
metadata.addGeoShortParam(
GeoTiffPCSCodes.ProjLinearUnitsGeoKey,
GeoTiffUoMCodes.Linear_Foot);
metadata.addGeoDoubleParam(
GeoTiffPCSCodes.ProjLinearUnitSizeGeoKey, linearUnit
.getConverterTo(SI.METER).convert(1));
}
if (NonSI.YARD.equals(linearUnit)) {
metadata.addGeoShortParam(
GeoTiffPCSCodes.ProjLinearUnitsGeoKey,
GeoTiffUoMCodes.Linear_Yard_Sears);// ??
metadata.addGeoDoubleParam(
GeoTiffPCSCodes.ProjLinearUnitSizeGeoKey, linearUnit
.getConverterTo(SI.METER).convert(1));
}
}
}
/**
* Parses a along with coordinate transformation and its parameters.
*
* @param name
* @param metadata
*
* @param conversion
* @throws GeoTiffException
*/
private void parseCoordinateProjectionTransform(
final MapProjection projTransf, final String name,
GeoTiffIIOMetadataEncoder metadata) {
final ParameterValueGroup parameters = projTransf.getParameterValues();
// /////////////////////////////////////////////////////////////////////
//
// Transverse Mercator
//
// /////////////////////////////////////////////////////////////////////
if (projTransf instanceof TransverseMercator
&& name.equalsIgnoreCase("transverse_mercator")) {
// key 3075
metadata
.addGeoShortParam(
GeoTiffPCSCodes.ProjCoordTransGeoKey,
GeoTiffCoordinateTransformationsCodes.CT_TransverseMercator);
// metadata.addGeoAscii(GeoTiffPCSCodes.PCSCitationGeoKey, name);
// params
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjNatOriginLongGeoKey,
parameters.parameter("central_meridian").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjNatOriginLatGeoKey,
parameters.parameter("latitude_of_origin").doubleValue());
metadata.addGeoDoubleParam(
GeoTiffPCSCodes.ProjScaleAtNatOriginGeoKey, parameters
.parameter("scale_factor").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjFalseEastingGeoKey,
parameters.parameter("false_easting").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjFalseNorthingGeoKey,
parameters.parameter("false_northing").doubleValue());
return;
}
// /////////////////////////////////////////////////////////////////////
//
// Mercator_1SP
// Mercator_2SP
//
// /////////////////////////////////////////////////////////////////////
if (projTransf instanceof Mercator
&& (name.equalsIgnoreCase("mercator_1SP") || name
.equalsIgnoreCase("Mercator_2SP"))) {
// key 3075
metadata.addGeoShortParam(GeoTiffPCSCodes.ProjCoordTransGeoKey,
GeoTiffCoordinateTransformationsCodes.CT_Mercator);
// metadata.addGeoAscii(GeoTiffPCSCodes.PCSCitationGeoKey, name);
// params
List<GeneralParameterValue> values = parameters.values();
for (GeneralParameterValue value : values){
if (value instanceof ParameterValue){
ParameterValue paramValue = (ParameterValue) value;
if (AbstractIdentifiedObject.nameMatches(value.getDescriptor(), "latitude_of_origin")) {
metadata.addGeoDoubleParam(
GeoTiffPCSCodes.ProjNatOriginLatGeoKey,(paramValue).doubleValue());
}else if (AbstractIdentifiedObject.nameMatches(value.getDescriptor(), "central_meridian")) {
metadata.addGeoDoubleParam(
GeoTiffPCSCodes.ProjNatOriginLongGeoKey,(paramValue).doubleValue());
}else if (AbstractIdentifiedObject.nameMatches(value.getDescriptor(), "scale_factor")) {
metadata.addGeoDoubleParam(
GeoTiffPCSCodes.ProjScaleAtNatOriginGeoKey,(paramValue).doubleValue());
}else if (AbstractIdentifiedObject.nameMatches(value.getDescriptor(), "standard_parallel_1")) {
metadata.addGeoDoubleParam(
GeoTiffPCSCodes.ProjStdParallel1GeoKey,(paramValue).doubleValue());
}else if (AbstractIdentifiedObject.nameMatches(value.getDescriptor(), "false_easting")) {
metadata.addGeoDoubleParam(
GeoTiffPCSCodes.ProjFalseEastingGeoKey,(paramValue).doubleValue());
}else if (AbstractIdentifiedObject.nameMatches(value.getDescriptor(), "false_northing")) {
metadata.addGeoDoubleParam(
GeoTiffPCSCodes.ProjFalseNorthingGeoKey,(paramValue).doubleValue());
}
}
}
return;
}
// /////////////////////////////////////////////////////////////////////
//
// Lamber conformal 1sp
//
// /////////////////////////////////////////////////////////////////////
if (projTransf instanceof LambertConformal && name.indexOf("1") != -1) {
// key 3075
metadata
.addGeoShortParam(
GeoTiffPCSCodes.ProjCoordTransGeoKey,
GeoTiffCoordinateTransformationsCodes.CT_LambertConfConic_Helmert);
// metadata.addGeoAscii(GeoTiffPCSCodes.PCSCitationGeoKey, name);
// params
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjNatOriginLongGeoKey,
parameters.parameter("central_meridian").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjNatOriginLatGeoKey,
parameters.parameter("latitude_of_origin").doubleValue());
metadata.addGeoDoubleParam(
GeoTiffPCSCodes.ProjScaleAtNatOriginGeoKey, parameters
.parameter("scale_factor").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjFalseEastingGeoKey,
parameters.parameter("false_easting").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjFalseNorthingGeoKey,
parameters.parameter("false_northing").doubleValue());
return;
}
// /////////////////////////////////////////////////////////////////////
//
// LAMBERT_CONFORMAL_CONIC_2SP
// lambert_conformal_conic_2SP_Belgium
//
// /////////////////////////////////////////////////////////////////////
if (projTransf instanceof LambertConformal && name.indexOf("2") != -1) {
// key 3075
metadata
.addGeoShortParam(
GeoTiffPCSCodes.ProjCoordTransGeoKey,
GeoTiffCoordinateTransformationsCodes.CT_LambertConfConic_2SP);
// metadata.addGeoAscii(GeoTiffPCSCodes.PCSCitationGeoKey, name);
// params
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjNatOriginLongGeoKey,
parameters.parameter("central_meridian").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjNatOriginLatGeoKey,
parameters.parameter("latitude_of_origin").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjStdParallel1GeoKey,
parameters.parameter("standard_parallel_1").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjStdParallel2GeoKey,
parameters.parameter("standard_parallel_2").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjFalseEastingGeoKey,
parameters.parameter("false_easting").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjFalseNorthingGeoKey,
parameters.parameter("false_northing").doubleValue());
return;
}
// if (name.equalsIgnoreCase("equidistant_conic")
// || code == GeoTiffMetadata2CRSAdapter.CT_EquidistantConic) {
// parameters = mtFactory
// .getDefaultParameters("equidistant_conic");
// parameters.parameter("central_meridian").setValue(
// getOriginLong());
// parameters.parameter("latitude_of_origin").setValue(
// getOriginLat());
// parameters
// .parameter("standard_parallel_1")
// .setValue(
// this
// .getGeoKeyAsDouble(GeoTiffIIOMetadataDecoder.ProjStdParallel1GeoKey));
// parameters
// .parameter("standard_parallel_2")
// .setValue(
// this
// .getGeoKeyAsDouble(GeoTiffIIOMetadataDecoder.ProjStdParallel2GeoKey));
// parameters.parameter("false_easting").setValue(
// getFalseEasting());
// parameters.parameter("false_northing").setValue(
// getFalseNorthing());
//
// return parameters;
// }
// /////////////////////////////////////////////////////////////////////
//
// stereographic
//
// /////////////////////////////////////////////////////////////////////
if (projTransf instanceof Stereographic
&& name.equalsIgnoreCase("stereographic")) {
// key 3075
metadata.addGeoShortParam(GeoTiffPCSCodes.ProjCoordTransGeoKey,
GeoTiffCoordinateTransformationsCodes.CT_Stereographic);
// metadata.addGeoAscii(GeoTiffPCSCodes.PCSCitationGeoKey, name);
// params
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjNatOriginLongGeoKey,
parameters.parameter("central_meridian").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjNatOriginLatGeoKey,
parameters.parameter("latitude_of_origin").doubleValue());
metadata.addGeoDoubleParam(
GeoTiffPCSCodes.ProjScaleAtNatOriginGeoKey, parameters
.parameter("scale_factor").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjFalseEastingGeoKey,
parameters.parameter("false_easting").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjFalseNorthingGeoKey,
parameters.parameter("false_northing").doubleValue());
return;
}
// /////////////////////////////////////////////////////////////////////
//
// polar_stereographic
//
// /////////////////////////////////////////////////////////////////////
if (projTransf instanceof PolarStereographic
&& name.equalsIgnoreCase("polar_stereographic")) {
// key 3075
metadata
.addGeoShortParam(
GeoTiffPCSCodes.ProjCoordTransGeoKey,
GeoTiffCoordinateTransformationsCodes.CT_PolarStereographic);
// metadata.addGeoAscii(GeoTiffPCSCodes.PCSCitationGeoKey, name);
// params
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjNatOriginLongGeoKey,
parameters.parameter("central_meridian").doubleValue());
metadata.addGeoDoubleParam(
GeoTiffPCSCodes.ProjStraightVertPoleLongGeoKey, parameters
.parameter("latitude_of_origin").doubleValue());
metadata.addGeoDoubleParam(
GeoTiffPCSCodes.ProjScaleAtNatOriginGeoKey, parameters
.parameter("scale_factor").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjFalseEastingGeoKey,
parameters.parameter("false_easting").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjFalseNorthingGeoKey,
parameters.parameter("false_northing").doubleValue());
return;
}
// /////////////////////////////////////////////////////////////////////
//
// Oblique_Stereographic
//
// /////////////////////////////////////////////////////////////////////
if(projTransf instanceof ObliqueStereographic
&& name.equalsIgnoreCase("Oblique_Stereographic")) {
metadata.addGeoShortParam(
GeoTiffPCSCodes.ProjCoordTransGeoKey,
GeoTiffCoordinateTransformationsCodes.CT_ObliqueStereographic);
// metadata.addGeoAscii(GeoTiffPCSCodes.PCSCitationGeoKey, name);
// params
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjNatOriginLongGeoKey,
parameters.parameter("central_meridian").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjNatOriginLatGeoKey,
parameters.parameter("latitude_of_origin").doubleValue());
metadata.addGeoDoubleParam(
GeoTiffPCSCodes.ProjScaleAtNatOriginGeoKey, parameters
.parameter("scale_factor").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjFalseEastingGeoKey,
parameters.parameter("false_easting").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjFalseNorthingGeoKey,
parameters.parameter("false_northing").doubleValue());
return;
}
// /////////////////////////////////////////////////////////////////////
//
// Oblique Mercator
//
// /////////////////////////////////////////////////////////////////////
if (projTransf instanceof ObliqueMercator
&& (name.equalsIgnoreCase("oblique_mercator") || name
.equalsIgnoreCase("hotine_oblique_mercator"))) {
// key 3075
metadata.addGeoShortParam(GeoTiffPCSCodes.ProjCoordTransGeoKey,
GeoTiffCoordinateTransformationsCodes.CT_ObliqueMercator);
// metadata.addGeoAscii(GeoTiffPCSCodes.PCSCitationGeoKey, name);
// params
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjCenterLongGeoKey,
parameters.parameter("longitude_of_center").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjCenterLatGeoKey,
parameters.parameter("latitude_of_center").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjScaleAtCenterGeoKey,
parameters.parameter("scale_factor").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjFalseEastingGeoKey,
parameters.parameter("false_easting").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjAzimuthAngleGeoKey,
parameters.parameter("azimuth").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjFalseNorthingGeoKey,
parameters.parameter("false_northing").doubleValue());
// rectified grid angle???
return;
}
// /////////////////////////////////////////////////////////////////////
//
// albers_Conic_Equal_Area
//
// /////////////////////////////////////////////////////////////////////
if (projTransf instanceof AlbersEqualArea
&& name.equalsIgnoreCase("albers_Conic_Equal_Area")) {
// key 3075
metadata.addGeoShortParam(GeoTiffPCSCodes.ProjCoordTransGeoKey,
GeoTiffCoordinateTransformationsCodes.CT_AlbersEqualArea);
// metadata.addGeoAscii(GeoTiffPCSCodes.PCSCitationGeoKey, name);
// params
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjNatOriginLongGeoKey,
parameters.parameter("longitude_of_center").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjNatOriginLatGeoKey,
parameters.parameter("latitude_of_center").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjFalseEastingGeoKey,
parameters.parameter("false_easting").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjFalseNorthingGeoKey,
parameters.parameter("false_northing").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjStdParallel1GeoKey,
parameters.parameter("standard_parallel_1").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjStdParallel2GeoKey,
parameters.parameter("standard_parallel_2").doubleValue());
// rectified grid angle???
return;
}
// /////////////////////////////////////////////////////////////////////
//
// Orthographic
//
// /////////////////////////////////////////////////////////////////////
if (projTransf instanceof Orthographic
&& name.equalsIgnoreCase("Orthographic")) {
// key 3075
metadata.addGeoShortParam(GeoTiffPCSCodes.ProjCoordTransGeoKey,
GeoTiffCoordinateTransformationsCodes.CT_Orthographic);
// metadata.addGeoAscii(GeoTiffPCSCodes.PCSCitationGeoKey, name);
// params
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjCenterLongGeoKey,
parameters.parameter("central_meridian").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjCenterLongGeoKey,
parameters.parameter("latitude_of_origin").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjFalseEastingGeoKey,
parameters.parameter("false_easting").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjFalseNorthingGeoKey,
parameters.parameter("false_northing").doubleValue());
return;
}
// /////////////////////////////////////////////////////////////////////
//
// Lambert Azimuthal Equal Area
//
// /////////////////////////////////////////////////////////////////////
if (projTransf instanceof LambertAzimuthalEqualArea
&& name.equalsIgnoreCase("Lambert_Azimuthal_Equal_Area")) {
// key 3075
metadata.addGeoShortParam(GeoTiffPCSCodes.ProjCoordTransGeoKey,
GeoTiffCoordinateTransformationsCodes.CT_LambertAzimEqualArea);
// metadata.addGeoAscii(GeoTiffPCSCodes.PCSCitationGeoKey, name);
// params
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjCenterLatGeoKey,
parameters.parameter("latitude_of_center").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjCenterLongGeoKey,
parameters.parameter("longitude_of_center").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjFalseEastingGeoKey,
parameters.parameter("false_easting").doubleValue());
metadata.addGeoDoubleParam(GeoTiffPCSCodes.ProjFalseNorthingGeoKey,
parameters.parameter("false_northing").doubleValue());
return;
}
// throw new
// GeoTiffException(null,"CRS2GeoTiffMetadataAdapter::parseCoordinateTransform::unknown
// projection transform");
}
/**
* Parses a "GEOGCS" element. This element has the following pattern:
*
* <blockquote><code>
* GEOGCS["<name>", <datum>, <prime meridian>, <angular unit> {,<twin axes>} {,<authority>}]
* </code></blockquote>
*
* @param geographicCRS
* The parent element.
* @param metadata
* @return The "GEOGCS" element as a {@link GeographicCRS} object.
*/
private void parseGeoGCS(DefaultGeographicCRS geographicCRS,
GeoTiffIIOMetadataEncoder metadata) {
// is it one of the EPSG standard GCS?
final int code = getEPSGCode(geographicCRS);
if (code != -1) {
metadata.addGeoShortParam(GeoTiffGCSCodes.GeographicTypeGeoKey,
code);
return;
}
// /////////////////////////////////////////////////////////////////////
//
// User defined CRS
//
// /////////////////////////////////////////////////////////////////////
// user defined geographic coordinate reference system.
metadata.addGeoShortParam(GeoTiffGCSCodes.GeographicTypeGeoKey, 32767);
// get the name of the gcs which will become a citation for the user
// define crs
metadata.addGeoAscii(GeoTiffGCSCodes.GeogCitationGeoKey, geographicCRS
.getName().getCode());
// geodetic datum
final DefaultGeodeticDatum datum = (DefaultGeodeticDatum) geographicCRS
.getDatum();
parseDatum(datum, metadata);
// angular unit
final Unit angularUnit = ((EllipsoidalCS) geographicCRS
.getCoordinateSystem()).getAxis(0).getUnit();
parseUnit(angularUnit, 0, metadata);
// prime meridian
parsePrimem((DefaultPrimeMeridian) datum.getPrimeMeridian(), metadata);
// linear unit
// final Unit linearUnit = datum.getEllipsoid().getAxisUnit();
// parseUnit(linearUnit, 1, metadata);
}
/**
* Parses a "DATUM" element. This element has the following pattern:
*
* <blockquote><code>
* DATUM["<name>", <spheroid> {,<to wgs84>} {,<authority>}]
* </code></blockquote>
*
* @param datum
* The parent element.
* @param metadata
* @param meridian
* the prime meridian.
* @return The "DATUM" element as a {@link GeodeticDatum} object.
*/
private void parseDatum(final DefaultGeodeticDatum datum,
GeoTiffIIOMetadataEncoder metadata) {
// looking for an EPSG code
final int code = getEPSGCode(datum);
if (code != -1) {
metadata.addGeoShortParam(GeoTiffGCSCodes.GeogGeodeticDatumGeoKey,
code);
return;
}
/**
* user defined datum
*/
// set the datum as user defined
metadata.addGeoShortParam(GeoTiffGCSCodes.GeogGeodeticDatumGeoKey,
32767);
// set the name
// metadata.addGeoAscii(GeoTiffGCSCodes.GeogCitationGeoKey, datum
// .getName().getCode());
parseSpheroid((DefaultEllipsoid) datum.getEllipsoid(), metadata);
}
/**
* Parses a "SPHEROID" element. This element has the following pattern:
*
* <blockquote><code>
* SPHEROID["<name>", <semi-major axis>, <inverse flattening> {,<authority>}]
* </code></blockquote>
*
* @param metadata
*
* @param parent
* The parent element.
* @return The "SPHEROID" element as an {@link Ellipsoid} object.
*/
private void parseSpheroid(final DefaultEllipsoid ellipsoid,
GeoTiffIIOMetadataEncoder metadata) {
final int code = getEPSGCode(ellipsoid);
if (code != -1) {
metadata
.addGeoShortParam(GeoTiffGCSCodes.GeogEllipsoidGeoKey, code);
return;
}
// user defined ellipsoid
metadata.addGeoShortParam(GeoTiffGCSCodes.GeogEllipsoidGeoKey, 32767);
// setting the name
// metadata.addGeoAscii(GeoTiffGCSCodes.GeogCitationGeoKey, ellipsoid
// .getName().getCode());
// setting semimajor axis
metadata.addGeoDoubleParam(GeoTiffGCSCodes.GeogSemiMajorAxisGeoKey,
ellipsoid.getSemiMajorAxis());
// setting inverse flattening
metadata.addGeoDoubleParam(GeoTiffGCSCodes.GeogInvFlatteningGeoKey,
ellipsoid.getInverseFlattening());
}
/**
* Parses a "PRIMEM" element. This element has the following pattern:
*
* <blockquote><code>
* PRIMEM["<name>", <longitude> {,<authority>}]
* </code></blockquote>
*
* @param metadata
*
* @param parent
* The parent element.
* @param angularUnit
* The contextual unit.
* @return The "PRIMEM" element as a {@link PrimeMeridian} object.
*/
private void parsePrimem(final DefaultPrimeMeridian pm,
GeoTiffIIOMetadataEncoder metadata) {
// looking for an EPSG code
final int numCode = getEPSGCode(pm);
if (numCode > 0)
metadata.addGeoShortParam(GeoTiffGCSCodes.GeogPrimeMeridianGeoKey,
numCode);
else {
// user defined
metadata.addGeoShortParam(GeoTiffGCSCodes.GeogPrimeMeridianGeoKey,
32767);
// citation
// metadata.addGeoAscii(GeoTiffGCSCodes.GeogCitationGeoKey, pm
// .getName().getCode());
// longitude
metadata.addGeoDoubleParam(
GeoTiffGCSCodes.GeogPrimeMeridianLongGeoKey, pm
.getGreenwichLongitude());
}
}
/**
* Parses an "UNIT" element. This element has the following pattern:
*
* <blockquote><code>
* UNIT["<name>", <conversion factor> {,<authority>}]
* </code></blockquote>
*
* @param unit
* The parent element.
* @param unit
* The contextual unit. Usually {@link SI#METRE} or
* {@link SI#RADIAN}.
* @param metadata
* @return The "UNIT" element as an {@link Unit} object.
* @todo Authority code is currently ignored. We may consider to create a
* subclass of {@link Unit} which implements {@link IdentifiedObject}
* in a future version.
*/
private void parseUnit(Unit unit, int model,
GeoTiffIIOMetadataEncoder metadata) {
// final UnitFormat unitFormat = UnitFormat.getStandardInstance();
// user defined
metadata.addGeoShortParam(
model == 0 ? GeoTiffGCSCodes.GeogAngularUnitsGeoKey
: GeoTiffPCSCodes.ProjLinearUnitsGeoKey, 32767);
// preparing the string to write here
// citation
// metadata.addGeoAscii(GeoTiffGCSCodes.GeogCitationGeoKey, unit
// .toString());// unitFormat.labelFor(unit)
Unit base = null;
if (SI.METER.isCompatible(unit)) {
base = SI.METER;
} else if (SI.SECOND.isCompatible(unit)) {
base = SI.SECOND;
} else if (SI.RADIAN.isCompatible(unit)) {
if (!Unit.ONE.equals(unit)) {
base = SI.RADIAN;
}
}
if (base != null) {
metadata.addGeoDoubleParam(
model == 0 ? GeoTiffGCSCodes.GeogAngularUnitSizeGeoKey
: GeoTiffGCSCodes.GeogLinearUnitSizeGeoKey, unit
.getConverterTo(base).convert(1));
} else
metadata.addGeoDoubleParam(
model == 0 ? GeoTiffGCSCodes.GeogAngularUnitSizeGeoKey
: GeoTiffGCSCodes.GeogLinearUnitSizeGeoKey, 1);
}
}