0001: /*
0002: * GeoTools - OpenSource mapping toolkit
0003: * http://geotools.org
0004: * (C) 2005-2006, GeoTools Project Managment Committee (PMC)
0005: *
0006: * This library is free software; you can redistribute it and/or
0007: * modify it under the terms of the GNU Lesser General Public
0008: * License as published by the Free Software Foundation;
0009: * version 2.1 of the License.
0010: *
0011: * This library is distributed in the hope that it will be useful,
0012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * Lesser General Public License for more details.
0015: */
0016: package org.geotools.gce.geotiff.crs_adapters;
0017:
0018: import java.lang.ref.Reference;
0019: import java.text.ParseException;
0020: import java.util.Collections;
0021: import java.util.Iterator;
0022: import java.util.Map;
0023: import java.util.Set;
0024:
0025: import javax.units.NonSI;
0026: import javax.units.SI;
0027: import javax.units.Unit;
0028:
0029: import org.geotools.gce.geotiff.GeoTiffException;
0030: import org.geotools.gce.geotiff.IIOMetadataAdpaters.GeoTiffIIOMetadataEncoder;
0031: import org.geotools.gce.geotiff.IIOMetadataAdpaters.utils.GeoTiffConstants;
0032: import org.geotools.gce.geotiff.IIOMetadataAdpaters.utils.codes.GeoTiffCoordinateTransformationsCodes;
0033: import org.geotools.gce.geotiff.IIOMetadataAdpaters.utils.codes.GeoTiffGCSCodes;
0034: import org.geotools.gce.geotiff.IIOMetadataAdpaters.utils.codes.GeoTiffPCSCodes;
0035: import org.geotools.gce.geotiff.IIOMetadataAdpaters.utils.codes.GeoTiffUoMCodes;
0036: import org.geotools.referencing.crs.DefaultGeographicCRS;
0037: import org.geotools.referencing.datum.DefaultEllipsoid;
0038: import org.geotools.referencing.datum.DefaultGeodeticDatum;
0039: import org.geotools.referencing.datum.DefaultPrimeMeridian;
0040: import org.geotools.referencing.operation.projection.AlbersEqualArea;
0041: import org.geotools.referencing.operation.projection.LambertConformal;
0042: import org.geotools.referencing.operation.projection.MapProjection;
0043: import org.geotools.referencing.operation.projection.Mercator;
0044: import org.geotools.referencing.operation.projection.ObliqueMercator;
0045: import org.geotools.referencing.operation.projection.Orthographic;
0046: import org.geotools.referencing.operation.projection.PolarStereographic;
0047: import org.geotools.referencing.operation.projection.Stereographic;
0048: import org.geotools.referencing.operation.projection.TransverseMercator;
0049: import org.geotools.referencing.operation.transform.ConcatenatedTransform;
0050: import org.geotools.resources.CRSUtilities;
0051: import org.geotools.resources.i18n.ErrorKeys;
0052: import org.geotools.resources.i18n.Errors;
0053: import org.geotools.util.SoftValueHashMap;
0054: import org.opengis.metadata.Identifier;
0055: import org.opengis.metadata.citation.Citation;
0056: import org.opengis.parameter.ParameterValueGroup;
0057: import org.opengis.referencing.IdentifiedObject;
0058: import org.opengis.referencing.crs.CoordinateReferenceSystem;
0059: import org.opengis.referencing.crs.GeographicCRS;
0060: import org.opengis.referencing.crs.ProjectedCRS;
0061: import org.opengis.referencing.cs.EllipsoidalCS;
0062: import org.opengis.referencing.datum.Ellipsoid;
0063: import org.opengis.referencing.datum.GeodeticDatum;
0064: import org.opengis.referencing.datum.PrimeMeridian;
0065: import org.opengis.referencing.operation.Conversion;
0066: import org.opengis.referencing.operation.MathTransform;
0067: import org.opengis.referencing.operation.OperationMethod;
0068:
0069: /**
0070: * This class implements a simple reusable adapter to adapt a
0071: * {@link CoordinateReferenceSystem} into useful Geotiff metadata by mean of
0072: * {@link GeoTiffIIOMetadataEncoder}.
0073: *
0074: * <p>
0075: * Since {@link CoordinateReferenceSystem} are essentially immutable this class
0076: * implements a static pool of {@link CRS2GeoTiffMetadataAdapter} objects that
0077: * would allow to avoid parsing the same {@link CoordinateReferenceSystem} more
0078: * than once.
0079: *
0080: * @author simone giannecchini
0081: *
0082: * @since 2.2
0083: *
0084: * @source $URL:
0085: * http://svn.geotools.org/geotools/trunk/gt/plugin/geotiff/src/org/geotools/gce/geotiff/crs_adapters/CRS2GeoTiffMetadataAdapter.java $
0086: */
0087: public final class CRS2GeoTiffMetadataAdapter {
0088: /**
0089: * The default value for {@link #maxStrongReferences} .
0090: */
0091: public static final int DEFAULT_MAX = 20;
0092:
0093: /**
0094: * The pool of cached objects.
0095: */
0096: private final static Map pool = Collections
0097: .synchronizedMap(new SoftValueHashMap(DEFAULT_MAX));
0098:
0099: /**
0100: * The {@link CoordinateReferenceSystem} to be get the metadata from:
0101: */
0102: private CoordinateReferenceSystem crs;
0103:
0104: /**
0105: * Returns an object from the pool for the specified code. If the object was
0106: * retained as a {@linkplain Reference weak reference}, the
0107: * {@link Reference#get referent} is returned.
0108: *
0109: * @todo Consider logging a message here to the finer or finest level.
0110: */
0111: public static Object get(final Object key) {
0112: synchronized (pool) {
0113:
0114: Object object = pool.get(key);
0115: if (object == null) {
0116: object = new CRS2GeoTiffMetadataAdapter(
0117: (CoordinateReferenceSystem) key);
0118: put(key, object);
0119: }
0120: return object;
0121: }
0122: }
0123:
0124: /**
0125: * Releases resources immediately instead of waiting for the garbage
0126: * collector.
0127: */
0128: public static void clear() {
0129: synchronized (pool) {
0130: pool.clear();
0131: }
0132: }
0133:
0134: /**
0135: * Put an element in the pool. This method is invoked everytime a
0136: * {@code createFoo(...)} method is invoked, even if an object was already
0137: * in the pool for the given code, for the following reasons: 1) Replaces
0138: * weak reference by strong reference (if applicable) and 2) Alters the
0139: * linked hash set order, so that this object is declared as the last one
0140: * used.
0141: */
0142: private static void put(final Object key, final Object object) {
0143: synchronized (pool) {
0144: pool.put(key, object);
0145:
0146: }
0147: }
0148:
0149: /**
0150: * Constructs a parser using the default set of symbols and factories.
0151: */
0152: public CRS2GeoTiffMetadataAdapter(
0153: final CoordinateReferenceSystem crs) {
0154: this .crs = crs;
0155: }
0156:
0157: /**
0158: * Searches for an EPSG code inside this <code>IdentifiedObject</code>.
0159: *
0160: * <p>
0161: * It is importanto to remarck that this function should be seen as an hack
0162: * hence it may change in the near future. DO not rely on it!
0163: *
0164: * @param obj
0165: * An <code>IdentifiedObject</code> to look for an EPSG code
0166: * into.
0167: * @return An EPSG numeric code, if one is found, -1 otherwise.
0168: */
0169: private static int getEPSGCode(final IdentifiedObject obj) {
0170: // looking for an EPSG code
0171: final Set identifiers = obj.getIdentifiers();
0172: final Iterator it = identifiers.iterator();
0173: String code = "";
0174: while (it.hasNext()) {
0175: final Identifier identifier = ((Identifier) it.next());
0176: final Citation cite = (Citation) identifier.getAuthority();
0177: if (cite.getIdentifiers().contains("EPSG")) {
0178: code = identifier.getCode();
0179: break;
0180:
0181: }
0182: }
0183:
0184: try {
0185: return Integer.parseInt(code);
0186: } catch (Exception e) {
0187:
0188: }
0189: // an error occurred;
0190: return -1;
0191: }
0192:
0193: /**
0194: * Parses a coordinate reference system.
0195: *
0196: * <p>
0197: * For the moment we can only encode geographic and projected coordinate
0198: * reference systes, we cannot encode the other types like vertical
0199: * coordinate reference systems.
0200: *
0201: * @throws GeoTiffException
0202: */
0203: public GeoTiffIIOMetadataEncoder parseCoordinateReferenceSystem()
0204: throws GeoTiffException {
0205: final GeoTiffIIOMetadataEncoder metadata = new GeoTiffIIOMetadataEncoder();
0206: // /////////////////////////////////////////////////////////////////////
0207: //
0208: // CREATING METADATA AND SETTING BASE FIELDS FOR THEM
0209: //
0210: // /////////////////////////////////////////////////////////////////////
0211: // model type
0212: final int modelType = (crs instanceof ProjectedCRS) ? 1 : 2;
0213:
0214: // GTModelTypeGeoKey
0215: metadata.addGeoShortParam(GeoTiffConstants.GTModelTypeGeoKey,
0216: modelType);
0217:
0218: switch (modelType) {
0219: // /////////////////////////////////////////////////////////////////////
0220: //
0221: // GEOGRAPHIC COORDINATE REFERENCE SYSTEMCREATING METADATA AND SETTING
0222: // BASE FIELDS FOR THEM
0223: //
0224: // /////////////////////////////////////////////////////////////////////
0225: case GeoTiffGCSCodes.ModelTypeGeographic:
0226:
0227: parseGeoGCS((DefaultGeographicCRS) crs, metadata);
0228:
0229: break;
0230:
0231: // /////////////////////////////////////////////////////////////////////
0232: //
0233: // PROJECTED COORDINATE REFERENCE SYSTEMCREATING METADATA AND SETTING
0234: // BASE FIELDS FOR THEM
0235: //
0236: // /////////////////////////////////////////////////////////////////////
0237: case GeoTiffPCSCodes.ModelTypeProjected:
0238: parseProjCRS((ProjectedCRS) crs, metadata);
0239:
0240: break;
0241:
0242: default:
0243: throw new GeoTiffException(
0244: null,
0245: "The supplied grid coverage uses an unsupported crs! You are allowed to use only projected and geographic coordinate reference systems",
0246: null);
0247: }
0248: return metadata;
0249:
0250: //
0251: // if ("VERT_CS".equals(keyword)) {
0252: // parseVertCS(element);
0253: // }
0254: //
0255: // if ("LOCAL_CS".equals(keyword)) {
0256: // parseLocalCS(element);
0257: // }
0258: //
0259: // if ("COMPD_CS".equals(keyword)) {
0260: // parseCompdCS(element);
0261: // }
0262: //
0263: // if ("FITTED_CS".equals(keyword)) {
0264: // parseFittedCS(element);
0265: // }
0266:
0267: }
0268:
0269: /**
0270: * Parses a "PROJCS" element. This element has the following pattern:
0271: *
0272: * <blockquote><code>
0273: * PROJCS["<name>", <geographic cs>, <projection>, {<parameter>,}*,
0274: * <linear unit> {,<twin axes>}{,<authority>}]
0275: * </code></blockquote>
0276: *
0277: * @param projectedCRS
0278: * The parent element.
0279: * @param metadata
0280: * @return The "PROJCS" element as a {@link ProjectedCRS} object.
0281: * @throws ParseException
0282: * if the "GEOGCS" element can't be parsed.
0283: */
0284: private void parseProjCRS(final ProjectedCRS projectedCRS,
0285: GeoTiffIIOMetadataEncoder metadata) {
0286:
0287: // do we have a code for this pcrs
0288: final int code = getEPSGCode(projectedCRS);
0289: if (code != -1) {
0290: metadata.addGeoShortParam(
0291: GeoTiffPCSCodes.ProjectedCSTypeGeoKey, code);
0292: return;
0293: }
0294:
0295: // user defined projected coordinate reference system.
0296: // key 3072
0297: metadata.addGeoShortParam(
0298: GeoTiffPCSCodes.ProjectedCSTypeGeoKey, 32767);
0299:
0300: // name of the user defined projected crs
0301: // key 3073
0302: metadata.addGeoAscii(GeoTiffPCSCodes.PCSCitationGeoKey,
0303: projectedCRS.getName().getCode());
0304:
0305: // projection
0306: parseProjection(projectedCRS, metadata);
0307:
0308: // gographic crs
0309: parseGeoGCS((DefaultGeographicCRS) (projectedCRS.getBaseCRS()),
0310: metadata);
0311:
0312: }
0313:
0314: /**
0315: * Parsing ProjectionGeoKey 3074 for a <code>ProjectedCRS</code>.
0316: *
0317: * @param projectedCRS
0318: * The <code>ProjectedCRS</code> to parse.
0319: * @param metadata
0320: */
0321: private void parseProjection(final ProjectedCRS projectedCRS,
0322: final GeoTiffIIOMetadataEncoder metadata) {
0323: // getting the conversion
0324: final Conversion conversion = projectedCRS
0325: .getConversionFromBase();
0326: final int code = getEPSGCode(conversion);
0327: if (code != -1) {
0328: metadata.addGeoShortParam(GeoTiffPCSCodes.ProjectionGeoKey,
0329: code);
0330: return;
0331: }
0332:
0333: // user defined projection
0334: // key 3074
0335: final String conversionName = conversion.getName().getCode();
0336: metadata.addGeoShortParam(GeoTiffPCSCodes.ProjectionGeoKey,
0337: 32767);
0338: metadata.addGeoAscii(GeoTiffPCSCodes.PCSCitationGeoKey,
0339: conversionName);
0340:
0341: final OperationMethod method = conversion.getMethod();
0342: // looking for the parameters
0343: String name = method.getName().getCode();
0344: name = name.trim();
0345: name = name.replace(' ', '_');
0346: final MathTransform mt = conversion.getMathTransform();
0347: final MapProjection projTransf;
0348: if (!(mt instanceof ConcatenatedTransform))
0349: projTransf = (MapProjection) mt;
0350: else {
0351: final ConcatenatedTransform tr = (ConcatenatedTransform) mt;
0352: final MathTransform m1 = tr.transform1, m2 = tr.transform2;
0353: if (m1 instanceof MapProjection)
0354: projTransf = (MapProjection) m1;
0355: else
0356: projTransf = (MapProjection) m2;
0357: }
0358:
0359: // key 3075 and parameters
0360: parseCoordinateProjectionTransform(projTransf, name, metadata);
0361:
0362: // parse linear unit
0363: parseLinearUnit(projectedCRS, metadata);
0364:
0365: }
0366:
0367: /**
0368: * Parses a linear unit for a <code>ProjectedCRS</code>.
0369: *
0370: * @todo complete the list of linear unit of measures and clean the
0371: * exception
0372: * @param projectedCRS
0373: * @param metadata
0374: */
0375: private void parseLinearUnit(final ProjectedCRS projectedCRS,
0376: GeoTiffIIOMetadataEncoder metadata) {
0377:
0378: // getting the linear unit
0379: final Unit linearUnit = CRSUtilities.getUnit(projectedCRS
0380: .getCoordinateSystem());
0381: if (linearUnit != null && !SI.METER.isCompatible(linearUnit)) {
0382: throw new IllegalArgumentException(Errors.format(
0383: ErrorKeys.NON_LINEAR_UNIT_$1, linearUnit));
0384: }
0385: if (SI.METER.isCompatible(linearUnit)) {
0386: if (SI.METER.equals(linearUnit)) {
0387: metadata.addGeoShortParam(
0388: GeoTiffPCSCodes.ProjLinearUnitsGeoKey,
0389: GeoTiffUoMCodes.Linear_Meter);
0390: metadata.addGeoDoubleParam(
0391: GeoTiffPCSCodes.ProjLinearUnitSizeGeoKey, 1.0);
0392: }
0393: if (NonSI.NAUTICAL_MILE.equals(linearUnit)) {
0394: metadata
0395: .addGeoShortParam(
0396: GeoTiffPCSCodes.ProjLinearUnitsGeoKey,
0397: GeoTiffUoMCodes.Linear_Mile_International_Nautical);
0398: metadata.addGeoDoubleParam(
0399: GeoTiffPCSCodes.ProjLinearUnitSizeGeoKey,
0400: linearUnit.getConverterTo(SI.METER).convert(1));
0401: }
0402: if (NonSI.FOOT.equals(linearUnit)) {
0403: metadata.addGeoShortParam(
0404: GeoTiffPCSCodes.ProjLinearUnitsGeoKey,
0405: GeoTiffUoMCodes.Linear_Foot);
0406: metadata.addGeoDoubleParam(
0407: GeoTiffPCSCodes.ProjLinearUnitSizeGeoKey,
0408: linearUnit.getConverterTo(SI.METER).convert(1));
0409: }
0410: if (NonSI.YARD.equals(linearUnit)) {
0411: metadata.addGeoShortParam(
0412: GeoTiffPCSCodes.ProjLinearUnitsGeoKey,
0413: GeoTiffUoMCodes.Linear_Yard_Sears);// ??
0414: metadata.addGeoDoubleParam(
0415: GeoTiffPCSCodes.ProjLinearUnitSizeGeoKey,
0416: linearUnit.getConverterTo(SI.METER).convert(1));
0417: }
0418: }
0419: }
0420:
0421: /**
0422: * Parses a along with coordinate transformation and its parameters.
0423: *
0424: * @param name
0425: * @param metadata
0426: *
0427: * @param conversion
0428: * @throws GeoTiffException
0429: */
0430: private void parseCoordinateProjectionTransform(
0431: final MapProjection projTransf, final String name,
0432: GeoTiffIIOMetadataEncoder metadata) {
0433:
0434: final ParameterValueGroup parameters = projTransf
0435: .getParameterValues();
0436:
0437: // /////////////////////////////////////////////////////////////////////
0438: //
0439: // Transverse Mercator
0440: //
0441: // /////////////////////////////////////////////////////////////////////
0442: if (projTransf instanceof TransverseMercator
0443: && name.equalsIgnoreCase("transverse_mercator")) {
0444: // key 3075
0445: metadata
0446: .addGeoShortParam(
0447: GeoTiffPCSCodes.ProjCoordTransGeoKey,
0448: GeoTiffCoordinateTransformationsCodes.CT_TransverseMercator);
0449: metadata.addGeoAscii(GeoTiffPCSCodes.PCSCitationGeoKey,
0450: name);
0451:
0452: // params
0453: metadata.addGeoDoubleParam(
0454: GeoTiffPCSCodes.ProjNatOriginLongGeoKey, parameters
0455: .parameter("central_meridian")
0456: .doubleValue());
0457: metadata.addGeoDoubleParam(
0458: GeoTiffPCSCodes.ProjNatOriginLatGeoKey, parameters
0459: .parameter("latitude_of_origin")
0460: .doubleValue());
0461: metadata.addGeoDoubleParam(
0462: GeoTiffPCSCodes.ProjScaleAtNatOriginGeoKey,
0463: parameters.parameter("scale_factor").doubleValue());
0464: metadata.addGeoDoubleParam(
0465: GeoTiffPCSCodes.ProjFalseEastingGeoKey, parameters
0466: .parameter("false_easting").doubleValue());
0467: metadata.addGeoDoubleParam(
0468: GeoTiffPCSCodes.ProjFalseNorthingGeoKey, parameters
0469: .parameter("false_northing").doubleValue());
0470: return;
0471: }
0472:
0473: // /////////////////////////////////////////////////////////////////////
0474: //
0475: // mercator_1SP
0476: // Mercator_2SP
0477: //
0478: // /////////////////////////////////////////////////////////////////////
0479: if (projTransf instanceof Mercator
0480: && (name.equalsIgnoreCase("mercator_1SP") || name
0481: .equalsIgnoreCase("Mercator_2SP"))) {
0482: // key 3075
0483: metadata.addGeoShortParam(
0484: GeoTiffPCSCodes.ProjCoordTransGeoKey,
0485: GeoTiffCoordinateTransformationsCodes.CT_Mercator);
0486: metadata.addGeoAscii(GeoTiffPCSCodes.PCSCitationGeoKey,
0487: name);
0488:
0489: // params
0490: metadata.addGeoDoubleParam(
0491: GeoTiffPCSCodes.ProjNatOriginLongGeoKey, parameters
0492: .parameter("central_meridian")
0493: .doubleValue());
0494: // metadata.addGeoDoubleParam(
0495: // GeoTiffIIOMetadataDecoder.ProjNatOriginLatGeoKey,
0496: // parameters.parameter("latitude_of_origin").doubleValue());
0497: metadata.addGeoDoubleParam(
0498: GeoTiffPCSCodes.ProjScaleAtNatOriginGeoKey,
0499: parameters.parameter("scale_factor").doubleValue());
0500: metadata.addGeoDoubleParam(
0501: GeoTiffPCSCodes.ProjFalseEastingGeoKey, parameters
0502: .parameter("false_easting").doubleValue());
0503: metadata.addGeoDoubleParam(
0504: GeoTiffPCSCodes.ProjFalseNorthingGeoKey, parameters
0505: .parameter("false_northing").doubleValue());
0506: return;
0507:
0508: }
0509:
0510: // /////////////////////////////////////////////////////////////////////
0511: //
0512: // Lamber conformal 1sp
0513: // Mercator_2SP
0514: //
0515: // /////////////////////////////////////////////////////////////////////
0516: if (projTransf instanceof LambertConformal
0517: && name.indexOf("1") != -1) {
0518:
0519: // key 3075
0520: metadata
0521: .addGeoShortParam(
0522: GeoTiffPCSCodes.ProjCoordTransGeoKey,
0523: GeoTiffCoordinateTransformationsCodes.CT_LambertConfConic_Helmert);
0524: metadata.addGeoAscii(GeoTiffPCSCodes.PCSCitationGeoKey,
0525: name);
0526:
0527: // params
0528: metadata.addGeoDoubleParam(
0529: GeoTiffPCSCodes.ProjNatOriginLongGeoKey, parameters
0530: .parameter("central_meridian")
0531: .doubleValue());
0532: metadata.addGeoDoubleParam(
0533: GeoTiffPCSCodes.ProjNatOriginLatGeoKey, parameters
0534: .parameter("latitude_of_origin")
0535: .doubleValue());
0536: metadata.addGeoDoubleParam(
0537: GeoTiffPCSCodes.ProjScaleAtNatOriginGeoKey,
0538: parameters.parameter("scale_factor").doubleValue());
0539: metadata.addGeoDoubleParam(
0540: GeoTiffPCSCodes.ProjFalseEastingGeoKey, parameters
0541: .parameter("false_easting").doubleValue());
0542: metadata.addGeoDoubleParam(
0543: GeoTiffPCSCodes.ProjFalseNorthingGeoKey, parameters
0544: .parameter("false_northing").doubleValue());
0545: return;
0546:
0547: }
0548:
0549: // /////////////////////////////////////////////////////////////////////
0550: //
0551: // LAMBERT_CONFORMAT_CONIC_2SP
0552: // lambert_conformal_conic_2SP_Belgium
0553: //
0554: // /////////////////////////////////////////////////////////////////////
0555: if (projTransf instanceof LambertConformal
0556: && name.indexOf("2") != -1) {
0557: // key 3075
0558: metadata
0559: .addGeoShortParam(
0560: GeoTiffPCSCodes.ProjCoordTransGeoKey,
0561: GeoTiffCoordinateTransformationsCodes.CT_LambertConfConic_2SP);
0562: metadata.addGeoAscii(GeoTiffPCSCodes.PCSCitationGeoKey,
0563: name);
0564:
0565: // params
0566: metadata.addGeoDoubleParam(
0567: GeoTiffPCSCodes.ProjNatOriginLongGeoKey, parameters
0568: .parameter("central_meridian")
0569: .doubleValue());
0570: metadata.addGeoDoubleParam(
0571: GeoTiffPCSCodes.ProjNatOriginLatGeoKey, parameters
0572: .parameter("latitude_of_origin")
0573: .doubleValue());
0574: metadata.addGeoDoubleParam(
0575: GeoTiffPCSCodes.ProjStdParallel1GeoKey, parameters
0576: .parameter("standard_parallel_1")
0577: .doubleValue());
0578: metadata.addGeoDoubleParam(
0579: GeoTiffPCSCodes.ProjStdParallel2GeoKey, parameters
0580: .parameter("standard_parallel_2")
0581: .doubleValue());
0582: metadata.addGeoDoubleParam(
0583: GeoTiffPCSCodes.ProjFalseEastingGeoKey, parameters
0584: .parameter("false_easting").doubleValue());
0585: metadata.addGeoDoubleParam(
0586: GeoTiffPCSCodes.ProjFalseNorthingGeoKey, parameters
0587: .parameter("false_northing").doubleValue());
0588: return;
0589:
0590: }
0591:
0592: // if (name.equalsIgnoreCase("equidistant_conic")
0593: // || code == GeoTiffMetadata2CRSAdapter.CT_EquidistantConic) {
0594: // parameters = mtFactory
0595: // .getDefaultParameters("equidistant_conic");
0596: // parameters.parameter("central_meridian").setValue(
0597: // getOriginLong());
0598: // parameters.parameter("latitude_of_origin").setValue(
0599: // getOriginLat());
0600: // parameters
0601: // .parameter("standard_parallel_1")
0602: // .setValue(
0603: // this
0604: // .getGeoKeyAsDouble(GeoTiffIIOMetadataDecoder.ProjStdParallel1GeoKey));
0605: // parameters
0606: // .parameter("standard_parallel_2")
0607: // .setValue(
0608: // this
0609: // .getGeoKeyAsDouble(GeoTiffIIOMetadataDecoder.ProjStdParallel2GeoKey));
0610: // parameters.parameter("false_easting").setValue(
0611: // getFalseEasting());
0612: // parameters.parameter("false_northing").setValue(
0613: // getFalseNorthing());
0614: //
0615: // return parameters;
0616: // }
0617:
0618: // /////////////////////////////////////////////////////////////////////
0619: //
0620: // stereographic
0621: //
0622: // /////////////////////////////////////////////////////////////////////
0623: if (projTransf instanceof Stereographic
0624: && name.equalsIgnoreCase("stereographic")) {
0625:
0626: // key 3075
0627: metadata
0628: .addGeoShortParam(
0629: GeoTiffPCSCodes.ProjCoordTransGeoKey,
0630: GeoTiffCoordinateTransformationsCodes.CT_Stereographic);
0631: metadata.addGeoAscii(GeoTiffPCSCodes.PCSCitationGeoKey,
0632: name);
0633:
0634: // params
0635: metadata.addGeoDoubleParam(
0636: GeoTiffPCSCodes.ProjNatOriginLongGeoKey, parameters
0637: .parameter("central_meridian")
0638: .doubleValue());
0639: metadata.addGeoDoubleParam(
0640: GeoTiffPCSCodes.ProjNatOriginLatGeoKey, parameters
0641: .parameter("latitude_of_origin")
0642: .doubleValue());
0643: metadata.addGeoDoubleParam(
0644: GeoTiffPCSCodes.ProjScaleAtNatOriginGeoKey,
0645: parameters.parameter("scale_factor").doubleValue());
0646: metadata.addGeoDoubleParam(
0647: GeoTiffPCSCodes.ProjFalseEastingGeoKey, parameters
0648: .parameter("false_easting").doubleValue());
0649: metadata.addGeoDoubleParam(
0650: GeoTiffPCSCodes.ProjFalseNorthingGeoKey, parameters
0651: .parameter("false_northing").doubleValue());
0652: return;
0653:
0654: }
0655:
0656: // /////////////////////////////////////////////////////////////////////
0657: //
0658: // polar_stereographic
0659: //
0660: // /////////////////////////////////////////////////////////////////////
0661: if (projTransf instanceof PolarStereographic
0662: && name.equalsIgnoreCase("polar_stereographic")) {
0663: // key 3075
0664: metadata
0665: .addGeoShortParam(
0666: GeoTiffPCSCodes.ProjCoordTransGeoKey,
0667: GeoTiffCoordinateTransformationsCodes.CT_PolarStereographic);
0668: metadata.addGeoAscii(GeoTiffPCSCodes.PCSCitationGeoKey,
0669: name);
0670:
0671: // params
0672: metadata.addGeoDoubleParam(
0673: GeoTiffPCSCodes.ProjNatOriginLongGeoKey, parameters
0674: .parameter("central_meridian")
0675: .doubleValue());
0676: metadata.addGeoDoubleParam(
0677: GeoTiffPCSCodes.ProjStraightVertPoleLongGeoKey,
0678: parameters.parameter("latitude_of_origin")
0679: .doubleValue());
0680: metadata.addGeoDoubleParam(
0681: GeoTiffPCSCodes.ProjScaleAtNatOriginGeoKey,
0682: parameters.parameter("scale_factor").doubleValue());
0683: metadata.addGeoDoubleParam(
0684: GeoTiffPCSCodes.ProjFalseEastingGeoKey, parameters
0685: .parameter("false_easting").doubleValue());
0686: metadata.addGeoDoubleParam(
0687: GeoTiffPCSCodes.ProjFalseNorthingGeoKey, parameters
0688: .parameter("false_northing").doubleValue());
0689: return;
0690:
0691: }
0692: // /////////////////////////////////////////////////////////////////////
0693: //
0694: // Transverse Mercator
0695: //
0696: // /////////////////////////////////////////////////////////////////////
0697: if (projTransf instanceof ObliqueMercator
0698: && (name.equalsIgnoreCase("oblique_mercator") || name
0699: .equalsIgnoreCase("hotine_oblique_mercator"))) {
0700:
0701: // key 3075
0702: metadata
0703: .addGeoShortParam(
0704: GeoTiffPCSCodes.ProjCoordTransGeoKey,
0705: GeoTiffCoordinateTransformationsCodes.CT_ObliqueMercator);
0706: metadata.addGeoAscii(GeoTiffPCSCodes.PCSCitationGeoKey,
0707: name);
0708:
0709: // params
0710: metadata.addGeoDoubleParam(
0711: GeoTiffPCSCodes.ProjCenterLongGeoKey, parameters
0712: .parameter("longitude_of_center")
0713: .doubleValue());
0714: metadata.addGeoDoubleParam(
0715: GeoTiffPCSCodes.ProjCenterLatGeoKey, parameters
0716: .parameter("latitude_of_center")
0717: .doubleValue());
0718: metadata.addGeoDoubleParam(
0719: GeoTiffPCSCodes.ProjScaleAtCenterGeoKey, parameters
0720: .parameter("scale_factor").doubleValue());
0721: metadata.addGeoDoubleParam(
0722: GeoTiffPCSCodes.ProjFalseEastingGeoKey, parameters
0723: .parameter("false_easting").doubleValue());
0724: metadata.addGeoDoubleParam(
0725: GeoTiffPCSCodes.ProjAzimuthAngleGeoKey, parameters
0726: .parameter("azimuth").doubleValue());
0727: metadata.addGeoDoubleParam(
0728: GeoTiffPCSCodes.ProjFalseNorthingGeoKey, parameters
0729: .parameter("false_northing").doubleValue());
0730: // rectified grid angle???
0731: return;
0732:
0733: }
0734: // /////////////////////////////////////////////////////////////////////
0735: //
0736: // albers_Conic_Equal_Area
0737: //
0738: // /////////////////////////////////////////////////////////////////////
0739: if (projTransf instanceof AlbersEqualArea
0740: && name.equalsIgnoreCase("albers_Conic_Equal_Area")) {
0741:
0742: // key 3075
0743: metadata
0744: .addGeoShortParam(
0745: GeoTiffPCSCodes.ProjCoordTransGeoKey,
0746: GeoTiffCoordinateTransformationsCodes.CT_AlbersEqualArea);
0747: metadata.addGeoAscii(GeoTiffPCSCodes.PCSCitationGeoKey,
0748: name);
0749:
0750: // params
0751: metadata.addGeoDoubleParam(
0752: GeoTiffPCSCodes.ProjNatOriginLongGeoKey, parameters
0753: .parameter("longitude_of_center")
0754: .doubleValue());
0755: metadata.addGeoDoubleParam(
0756: GeoTiffPCSCodes.ProjNatOriginLatGeoKey, parameters
0757: .parameter("latitude_of_center")
0758: .doubleValue());
0759: metadata.addGeoDoubleParam(
0760: GeoTiffPCSCodes.ProjFalseEastingGeoKey, parameters
0761: .parameter("false_easting").doubleValue());
0762: metadata.addGeoDoubleParam(
0763: GeoTiffPCSCodes.ProjFalseNorthingGeoKey, parameters
0764: .parameter("false_northing").doubleValue());
0765: metadata.addGeoDoubleParam(
0766: GeoTiffPCSCodes.ProjStdParallel1GeoKey, parameters
0767: .parameter("standard_parallel_1")
0768: .doubleValue());
0769: metadata.addGeoDoubleParam(
0770: GeoTiffPCSCodes.ProjStdParallel2GeoKey, parameters
0771: .parameter("standard_parallel_2")
0772: .doubleValue());
0773: // rectified grid angle???
0774: return;
0775:
0776: }
0777:
0778: // /////////////////////////////////////////////////////////////////////
0779: //
0780: // Orthographic
0781: //
0782: // /////////////////////////////////////////////////////////////////////
0783: if (projTransf instanceof Orthographic
0784: && name.equalsIgnoreCase("Orthographic")) {
0785:
0786: // key 3075
0787: metadata
0788: .addGeoShortParam(
0789: GeoTiffPCSCodes.ProjCoordTransGeoKey,
0790: GeoTiffCoordinateTransformationsCodes.CT_Orthographic);
0791: metadata.addGeoAscii(GeoTiffPCSCodes.PCSCitationGeoKey,
0792: name);
0793:
0794: // params
0795: metadata.addGeoDoubleParam(
0796: GeoTiffPCSCodes.ProjCenterLongGeoKey, parameters
0797: .parameter("central_meridian")
0798: .doubleValue());
0799: metadata.addGeoDoubleParam(
0800: GeoTiffPCSCodes.ProjCenterLongGeoKey, parameters
0801: .parameter("latitude_of_origin")
0802: .doubleValue());
0803: metadata.addGeoDoubleParam(
0804: GeoTiffPCSCodes.ProjFalseEastingGeoKey, parameters
0805: .parameter("false_easting").doubleValue());
0806: metadata.addGeoDoubleParam(
0807: GeoTiffPCSCodes.ProjFalseNorthingGeoKey, parameters
0808: .parameter("false_northing").doubleValue());
0809: return;
0810: }
0811: // throw new
0812: // GeoTiffException(null,"CRS2GeoTiffMetadataAdapter::parseCoordinateTransform::unknown
0813: // prohection transform");
0814:
0815: }
0816:
0817: /**
0818: * Parses a "GEOGCS" element. This element has the following pattern:
0819: *
0820: * <blockquote><code>
0821: * GEOGCS["<name>", <datum>, <prime meridian>, <angular unit> {,<twin axes>} {,<authority>}]
0822: * </code></blockquote>
0823: *
0824: * @param geographicCRS
0825: * The parent element.
0826: * @param metadata
0827: * @return The "GEOGCS" element as a {@link GeographicCRS} object.
0828: */
0829: private void parseGeoGCS(DefaultGeographicCRS geographicCRS,
0830: GeoTiffIIOMetadataEncoder metadata) {
0831:
0832: // is it one of the EPSG standard GCS?
0833: final int code = getEPSGCode(geographicCRS);
0834: if (code != -1) {
0835: metadata.addGeoShortParam(
0836: GeoTiffGCSCodes.GeographicTypeGeoKey, code);
0837: return;
0838: }
0839:
0840: // /////////////////////////////////////////////////////////////////////
0841: //
0842: // User defined CRS
0843: //
0844: // /////////////////////////////////////////////////////////////////////
0845: // user defined geographic coordinate reference system.
0846: metadata.addGeoShortParam(GeoTiffGCSCodes.GeographicTypeGeoKey,
0847: 32767);
0848:
0849: // get the name of the gcs which will become a citation for the user
0850: // define crs
0851: metadata.addGeoAscii(GeoTiffGCSCodes.GeogCitationGeoKey,
0852: geographicCRS.getName().getCode());
0853:
0854: // geodetic datum
0855: final DefaultGeodeticDatum datum = (DefaultGeodeticDatum) geographicCRS
0856: .getDatum();
0857: parseDatum(datum, metadata);
0858:
0859: // angular unit
0860: final Unit angularUnit = ((EllipsoidalCS) geographicCRS
0861: .getCoordinateSystem()).getAxis(0).getUnit();
0862: parseUnit(angularUnit, 0, metadata);
0863:
0864: // prime meridian
0865: parsePrimem((DefaultPrimeMeridian) datum.getPrimeMeridian(),
0866: metadata);
0867:
0868: // linear unit
0869: final Unit linearUnit = datum.getEllipsoid().getAxisUnit();
0870: parseUnit(linearUnit, 1, metadata);
0871:
0872: }
0873:
0874: /**
0875: * Parses a "DATUM" element. This element has the following pattern:
0876: *
0877: * <blockquote><code>
0878: * DATUM["<name>", <spheroid> {,<to wgs84>} {,<authority>}]
0879: * </code></blockquote>
0880: *
0881: * @param datum
0882: * The parent element.
0883: * @param metadata
0884: * @param meridian
0885: * the prime meridian.
0886: * @return The "DATUM" element as a {@link GeodeticDatum} object.
0887: */
0888: private void parseDatum(final DefaultGeodeticDatum datum,
0889: GeoTiffIIOMetadataEncoder metadata) {
0890:
0891: // looking for an EPSG code
0892: final int code = getEPSGCode(datum);
0893: if (code != -1) {
0894: metadata.addGeoShortParam(
0895: GeoTiffGCSCodes.GeogGeodeticDatumGeoKey, code);
0896: return;
0897: }
0898:
0899: /**
0900: * user defined datum
0901: */
0902: // set the datum as user defined
0903: metadata.addGeoShortParam(
0904: GeoTiffGCSCodes.GeogGeodeticDatumGeoKey, 32767);
0905:
0906: // set the name
0907: metadata.addGeoAscii(GeoTiffGCSCodes.GeogCitationGeoKey, datum
0908: .getName().getCode());
0909:
0910: parseSpheroid((DefaultEllipsoid) datum.getEllipsoid(), metadata);
0911:
0912: }
0913:
0914: /**
0915: * Parses a "SPHEROID" element. This element has the following pattern:
0916: *
0917: * <blockquote><code>
0918: * SPHEROID["<name>", <semi-major axis>, <inverse flattening> {,<authority>}]
0919: * </code></blockquote>
0920: *
0921: * @param metadata
0922: *
0923: * @param parent
0924: * The parent element.
0925: * @return The "SPHEROID" element as an {@link Ellipsoid} object.
0926: */
0927: private void parseSpheroid(final DefaultEllipsoid ellipsoid,
0928: GeoTiffIIOMetadataEncoder metadata) {
0929:
0930: final int code = getEPSGCode(ellipsoid);
0931: if (code != -1) {
0932:
0933: metadata.addGeoShortParam(
0934: GeoTiffGCSCodes.GeogEllipsoidGeoKey, code);
0935: return;
0936: }
0937:
0938: // user definde ellipsoid
0939: metadata.addGeoShortParam(GeoTiffGCSCodes.GeogEllipsoidGeoKey,
0940: 32767);
0941: // setting the name
0942: metadata.addGeoAscii(GeoTiffGCSCodes.GeogCitationGeoKey,
0943: ellipsoid.getName().getCode());
0944:
0945: // setting semimajor axis
0946: metadata.addGeoDoubleParam(
0947: GeoTiffGCSCodes.GeogSemiMajorAxisGeoKey, ellipsoid
0948: .getSemiMajorAxis());
0949:
0950: // setting inverse flattening
0951: metadata.addGeoDoubleParam(
0952: GeoTiffGCSCodes.GeogInvFlatteningGeoKey, ellipsoid
0953: .getInverseFlattening());
0954:
0955: }
0956:
0957: /**
0958: * Parses a "PRIMEM" element. This element has the following pattern:
0959: *
0960: * <blockquote><code>
0961: * PRIMEM["<name>", <longitude> {,<authority>}]
0962: * </code></blockquote>
0963: *
0964: * @param metadata
0965: *
0966: * @param parent
0967: * The parent element.
0968: * @param angularUnit
0969: * The contextual unit.
0970: * @return The "PRIMEM" element as a {@link PrimeMeridian} object.
0971: */
0972: private void parsePrimem(final DefaultPrimeMeridian pm,
0973: GeoTiffIIOMetadataEncoder metadata) {
0974: // looking for an EPSG code
0975: final int numCode = getEPSGCode(pm);
0976: if (numCode > 0)
0977: metadata.addGeoShortParam(
0978: GeoTiffGCSCodes.GeogPrimeMeridianGeoKey, numCode);
0979: else {
0980: // user defined
0981: metadata.addGeoShortParam(
0982: GeoTiffGCSCodes.GeogPrimeMeridianGeoKey, 32767);
0983:
0984: // citation
0985: metadata.addGeoAscii(GeoTiffGCSCodes.GeogCitationGeoKey, pm
0986: .getName().getCode());
0987:
0988: // longitude
0989: metadata.addGeoDoubleParam(
0990: GeoTiffGCSCodes.GeogPrimeMeridianLongGeoKey, pm
0991: .getGreenwichLongitude());
0992: }
0993:
0994: }
0995:
0996: /**
0997: * Parses an "UNIT" element. This element has the following pattern:
0998: *
0999: * <blockquote><code>
1000: * UNIT["<name>", <conversion factor> {,<authority>}]
1001: * </code></blockquote>
1002: *
1003: * @param unit
1004: * The parent element.
1005: * @param unit
1006: * The contextual unit. Usually {@link SI#METRE} or
1007: * {@link SI#RADIAN}.
1008: * @param metadata
1009: * @return The "UNIT" element as an {@link Unit} object.
1010: * @todo Authority code is currently ignored. We may consider to create a
1011: * subclass of {@link Unit} which implements {@link IdentifiedObject}
1012: * in a future version.
1013: */
1014: private void parseUnit(Unit unit, int model,
1015: GeoTiffIIOMetadataEncoder metadata) {
1016:
1017: // final UnitFormat unitFormat = UnitFormat.getStandardInstance();
1018: // user defined
1019: metadata.addGeoShortParam(
1020: model == 0 ? GeoTiffGCSCodes.GeogAngularUnitsGeoKey
1021: : GeoTiffPCSCodes.ProjLinearUnitsGeoKey, 32767);
1022:
1023: // preparing the string to write here
1024:
1025: // citation
1026: metadata.addGeoAscii(GeoTiffGCSCodes.GeogCitationGeoKey, unit
1027: .toString());// unitFormat.labelFor(unit)
1028:
1029: Unit base = null;
1030: if (SI.METER.isCompatible(unit)) {
1031: base = SI.METER;
1032: } else if (SI.SECOND.isCompatible(unit)) {
1033: base = SI.SECOND;
1034: } else if (SI.RADIAN.isCompatible(unit)) {
1035: if (!Unit.ONE.equals(unit)) {
1036: base = SI.RADIAN;
1037: }
1038: }
1039: if (base != null) {
1040: metadata
1041: .addGeoDoubleParam(
1042: model == 0 ? GeoTiffGCSCodes.GeogAngularUnitSizeGeoKey
1043: : GeoTiffGCSCodes.GeogLinearUnitSizeGeoKey,
1044: unit.getConverterTo(base).convert(1));
1045: } else
1046: metadata
1047: .addGeoDoubleParam(
1048: model == 0 ? GeoTiffGCSCodes.GeogAngularUnitSizeGeoKey
1049: : GeoTiffGCSCodes.GeogLinearUnitSizeGeoKey,
1050: 1);
1051: }
1052:
1053: }
|