/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2007-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.image.io.metadata;
import org.opengis.parameter.ParameterValue;
import org.opengis.referencing.datum.Datum;
import org.opengis.referencing.cs.AxisDirection;
import org.opengis.referencing.cs.CoordinateSystem;
import org.opengis.referencing.cs.CoordinateSystemAxis;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.datum.Ellipsoid;
import org.opengis.referencing.datum.GeodeticDatum;
import org.opengis.referencing.operation.Projection;
/**
* A {@code <CoordinateReferenceSystem>} element in
* {@linkplain GeographicMetadataFormat geographic metadata format}, together with its
* {@code <CoordinateSystem>} and {@code <Datum>} child elements.
*
* @since 2.4
* @source $URL$
* @version $Id$
* @author Martin Desruisseaux
* @author Cédric Briançon
*/
public class ImageReferencing extends MetadataAccessor {
/**
* The {@code "rectifiedGridDomain/crs/cs"} node.
*/
ChildList<Axis> cs;
/**
* The {@code "rectifiedGridDomain/crs/projection"} node.
*/
ChildList<Parameter> projection;
/**
* The {@code "rectifiedGridDomain/crs/datum"} node.
*/
private MetadataAccessor datum;
/**
* The {@code "rectifiedGridDomain/crs/datum/ellipsoid"} node, present only
* in the case of a {@linkplain GeodeticDatum geodetic datum}.
*/
private MetadataAccessor ellipsoid;
/**
* The {@code "rectifiedGridDomain/crs/datum/primeMeridian"} node, present only
* in the case of a {@linkplain GeodeticDatum geodetic datum}.
*/
private MetadataAccessor primeMeridian;
/**
* The {@code "rectifiedGridDomain/crs/datum/ellipsoid/semiMajorAxis"} node.
*/
private MetadataAccessor semiMajorAxis;
/**
* The {@code "rectifiedGridDomain/crs/datum/ellipsoid/secondDefiningParameter/semiMinorAxis"}
* node.
*/
private MetadataAccessor semiMinorAxis;
/**
* The {@code "rectifiedGridDomain/crs/datum/ellipsoid/secondDefiningParameter/inverseFlattening"}
* node.
*/
private MetadataAccessor inverseFlattening;
/**
* Creates a parser for a coordinate system. This constructor should not be invoked
* directly; use {@link GeographicMetadata#getReferencing} instead.
*
* @param metadata The metadata node.
*/
protected ImageReferencing(final GeographicMetadata metadata) {
super(metadata, "rectifiedGridDomain/crs", null);
}
/**
* Returns the number of dimensions, which is the number of {@linkplain Axis axes}
* of the {@linkplain CoordinateSystem coordinate system}.
*/
public int getDimension() {
return getCoordinateSystemAccessor().childCount();
}
/**
* Returns the {@linkplain Identification#name name} and {@linkplain Identification#type type}
* of the {@linkplain CoordinateReferenceSystem coordinate reference system}.
*
* @see CoordinateReferenceSystem
*/
public Identification getCoordinateReferenceSystem() {
return new Identification(this);
}
/**
* Sets the {@linkplain Identification#name name} and {@linkplain Identification#type type}
* of the {@linkplain CoordinateReferenceSystem coordinate reference system}.
*
* @param name The coordinate reference system name, or {@code null} if unknown.
* @param type The coordinate reference system type (usually
* {@value GeographicMetadataFormat#GEOGRAPHIC} or
* {@value GeographicMetadataFormat#PROJECTED}), or {@code null} if unknown.
*
* @see CoordinateReferenceSystem
*/
public void setCoordinateReferenceSystem(final String name, final String type) {
setAttributeAsString("name", name);
setAttributeAsEnum ("type", type, GeographicMetadataFormat.CRS_TYPES);
}
/**
* Returns the {@linkplain Identification#name name} and
* {@linkplain Identification#type type} of the
* {@linkplain CoordinateSystem coordinate system}, or {@code null} if it is
* not defined.
*
* @see CoordinateSystem
*/
public Identification getCoordinateSystem() {
return (cs != null) ? new Identification(cs) : null;
}
/**
* Sets the {@linkplain Identification#name name} and {@linkplain Identification#type type}
* of the {@linkplain CoordinateSystem coordinate system}.
*
* @param name The coordinate system name, or {@code null} if unknown.
* @param type The coordinate system type (usually
* {@value GeographicMetadataFormat#ELLIPSOIDAL} or
* {@value GeographicMetadataFormat#CARTESIAN}), or {@code null} if unknown.
*
* @see CoordinateSystem
*/
public void setCoordinateSystem(final String name, final String type) {
final MetadataAccessor cs = getCoordinateSystemAccessor();
cs.setAttributeAsString("name", name);
cs.setAttributeAsEnum ("type", type, GeographicMetadataFormat.CS_TYPES);
}
/**
* Returns the {@linkplain Identification#name name} and {@linkplain Identification#type type}
* of the {@linkplain Datum datum}, or {@code null} if it is not defined.
*
* @see Datum
*/
public Identification getDatum() {
return (datum != null) ? new Identification(datum) : null;
}
/**
* Sets the {@linkplain Identification#name name} and {@linkplain Identification#type type}
* of the {@linkplain Datum datum}.
*
* @param name The datum name, or {@code null} if unknown.
* @param type The datum type (usually {@value GeographicMetadataFormat#GEODETIC}), or
* {@code null} if unknown.
*
* @see Datum
*/
public void setDatum(final String name, final String type) {
final MetadataAccessor datum = getDatumAccessor();
datum.setAttributeAsString("name", name);
datum.setAttributeAsEnum ("type", type, GeographicMetadataFormat.DATUM_TYPES);
}
/**
* Returns the name of the {@linkplain Ellipsoid ellipsoid}, or {@code null} if
* not defined.
*
* @see Ellipsoid
*/
public String getEllipsoidName() {
return (ellipsoid != null) ? ellipsoid.getAttributeAsString("name") : null;
}
/**
* Sets the name of the {@linkplain Ellipsoid ellipsoid}.
*
* @param name The ellipsoid name, or {@code null} if unknown.
*
* @see Ellipsoid
*/
public void setEllipsoidName(final String name) {
getEllipsoidAccessor().setAttributeAsString("name", name);
}
/**
* Returns the unit of the {@linkplain Ellipsoid ellipsoid}, or {@code null}
* if it is not defined.
*
* @see Ellipsoid
*/
public String getEllipsoidUnit() {
return (ellipsoid != null) ? ellipsoid.getAttributeAsString("unit") : null;
}
/**
* Sets the unit of the {@linkplain Ellipsoid ellipsoid}.
*
* @param unit The ellipsoid unit, or {@code null} if unknown.
*
* @see Ellipsoid
*/
public void setEllipsoidUnit(final String unit) {
getEllipsoidAccessor().setAttributeAsString("unit", unit);
}
/**
* Returns the semi-major axis value for this {@linkplain Ellipsoid ellipsoid}.
* or {@code Double.NaN} if not defined.
*
* @see Ellipsoid
*/
public double getSemiMajorAxis() {
final Double semiMajor = (semiMajorAxis != null) ?
semiMajorAxis.getUserObject(Double.class) : null;
return (semiMajor == null) ? Double.NaN : semiMajor;
}
/**
* Sets the semi-major axis value of the {@linkplain Ellipsoid ellipsoid}.
*
* @param value The semi-major axis value, or {@code null} if unknown.
*
* @see Ellipsoid
*/
public void setSemiMajorAxis(final double value) {
getSemiMajorAxisAccessor().setUserObject(value);
}
/**
* Returns the semi-minor axis value for this {@linkplain Ellipsoid ellipsoid},
* or {@code Double.NaN} if not defined.
*
* @see Ellipsoid
*/
public double getSemiMinorAxis() {
final Double semiMinor = (semiMinorAxis != null) ?
semiMinorAxis.getUserObject(Double.class) : null;
return (semiMinor == null) ? Double.NaN : semiMinor;
}
/**
* Sets the semi-minor axis value of the {@linkplain Ellipsoid ellipsoid}. This
* method should be called only if the {@link #setInverseFlattening} method
* has not already been called.
*
* @param value The semi-minor axis value, or {@code null} if unknown.
*
* @see Ellipsoid
*/
public void setSemiMinorAxis(final double value) {
getSemiMinorAxisAccessor().setUserObject(value);
}
/**
* Returns the inverseFlattening value for this {@linkplain Ellipsoid ellipsoid},
* or {@code null} if not defined.
*
* @see Ellipsoid
*/
public double getInverseFlattening() {
return (inverseFlattening != null) ?
inverseFlattening.getUserObject(Double.class) : null;
}
/**
* Sets the inverseFlattening value of the {@linkplain Ellipsoid ellipsoid}. This
* method should be called only if the {@link #setSemiMinorAxis} method
* has not already been called.
*
* @param value The inverseFlattening value, or {@code null} if unknown.
*
* @see Ellipsoid
*/
public void setInverseFlattening(final double value) {
getInverseFlatteningAccessor().setUserObject(value);
}
/**
* Returns the axis at the specified index.
*
* @param index the axis index, ranging from 0 inclusive to {@link #getDimension}
* exclusive.
* @throws IndexOutOfBoundsException if the index is out of bounds.
*/
public Axis getAxis(final int index) throws IndexOutOfBoundsException {
return getCoordinateSystemAccessor().getChild(index);
}
/**
* Adds an {@linkplain CoordinateSystemAxis axis} to the
* {@linkplain CoordinateSystem coordinate system}.
*
* @param name The axis name, or {@code null} if unknown.
* @param direction The {@linkplain AxisDirection axis direction}
* (usually {@code "east"}, {@code "weast"}, {@code "north"}, {@code "south"},
* {@code "up"} or {@code "down"}), or {@code null} if unknown.
* @param units The axis units symbol, or {@code null} if unknown.
*
* @see CoordinateSystemAxis
* @see AxisDirection
*/
public Axis addAxis(final String name, final String direction, final String units) {
final Axis axis = getCoordinateSystemAccessor().addChild();
axis.setName(name);
axis.setDirection(direction);
axis.setUnits(units);
return axis;
}
/**
* Returns the parameter at the index for the {@linkplain Projection projection},
* or {@code null} if not defined.
*
* @param index the parameter index.
* @throws IndexOutOfBoundsException if the index is out of bounds.
*/
public Parameter getParameter(final int index) throws IndexOutOfBoundsException {
return (projection != null) ? projection.getChild(index) : null;
}
/**
* Returns all parameters found for the {@linkplain Projection projection} in an
* array, or an empty array if no parameters have been defined, but never {@code null}.
*/
public Parameter[] getParameters() {
final int size = (projection != null) ? projection.childCount() : 0;
final Parameter[] params = new Parameter[size];
for (int i=0; i<size; i++) {
params[i] = getProjectionAccessor().getChild(i);
}
return params;
}
/**
* Adds an {@linkplain ParameterValue parameter} to the
* {@linkplain Projection projection}.
*
* @param name The parameter name, or {@code null} if unknown.
* @param value The value for this parameter, or {@code Double.NaN} if unknown.
*
* @see ParameterValue
*/
public Parameter addParameter(final String name, final double value) {
final Parameter parameter = getProjectionAccessor().addChild();
parameter.setName(name);
parameter.setValue(value);
return parameter;
}
/**
* Returns the prime meridian name, or {@code null} if not defined.
*/
public String getPrimeMeridianName() {
return (primeMeridian != null) ? primeMeridian.getAttributeAsString("name") : null;
}
/**
* Sets the name of the prime meridian.
*
* @param name The name of the prime meridian, or {@code null} if not known.
*/
public void setPrimeMeridianName(final String name) {
getPrimeMeridianAccessor().setAttributeAsString("name", name);
}
/**
* Returns the prime meridian greenwich longitude, or {@code Double.NaN} if this
* value is not defined.
*/
public double getPrimeMeridianGreenwichLongitude() {
final Double green = (primeMeridian != null) ?
primeMeridian.getAttributeAsDouble("greenwichLongitude") : null;
return (green == null) ? Double.NaN : green;
}
/**
* Sets the greenwich longitude for the prime meridian.
*
* @param greenwichLongitude The greenwich longitude for the prime meridian, or
* {@code null} if not known.
*/
public void setPrimeMeridianGreenwichLongitude(final double greenwichLongitude) {
getPrimeMeridianAccessor().
setAttributeAsDouble("greenwichLongitude", greenwichLongitude);
}
/**
* Returns the name of the {@code Projection projection}, or {@code null} if not
* defined.
*/
public String getProjectionName() {
return (projection != null) ? projection.getAttributeAsString("name") : null;
}
/**
* Sets the name of the {@linkplain Projection projection}.
*
* @param name The projection name, or {@code null} if unknown.
*
* @see Projection
*/
public void setProjectionName(final String name) {
getProjectionAccessor().setAttributeAsString("name", name);
}
/**
* Returns the {@linkplain CoordinateReferenceSystem coordinate reference system} in
* <A HREF="http://geoapi.sourceforge.net/snapshot/javadoc/org/opengis/referencing/doc-files/WKT.html"><cite>Well
* Known Text</cite> format</A>, or {@code null} if none.
*/
@Deprecated
public String getWKT() {
return getAttributeAsString("WKT");
}
/**
* Sets the {@linkplain CoordinateReferenceSystem coordinate reference system} in
* <A HREF="http://geoapi.sourceforge.net/snapshot/javadoc/org/opengis/referencing/doc-files/WKT.html"><cite>Well
* Known Text</cite> format</A>.
*/
@Deprecated
public void setWKT(final String wkt) {
setAttributeAsString("WKT", wkt);
}
/**
* Builds a {@linkplain MetadataAccessor coordinate system accessor} if it is
* not already instanciated, and returns it, or return the current one if defined.
*/
private ChildList<Axis> getCoordinateSystemAccessor() {
if (cs == null) {
cs = new ChildList.Axes(metadata);
}
return cs;
}
/**
* Builds a {@linkplain MetadataAccessor datum accessor} if it is not already
* instanciated, and returns it, or return the current datum if defined.
*/
private MetadataAccessor getDatumAccessor() {
if (datum == null) {
datum = new MetadataAccessor(metadata, "rectifiedGridDomain/crs/datum", null);
}
return datum;
}
/**
* Builds a {@linkplain MetadataAccessor ellipsoid accessor} if it is not already
* instanciated, and returns it, or return the current one if defined.
*/
private MetadataAccessor getEllipsoidAccessor() {
if (ellipsoid == null) {
ellipsoid = new MetadataAccessor(metadata,
"rectifiedGridDomain/crs/datum/ellipsoid", null);
}
return ellipsoid;
}
/**
* Builds a {@linkplain MetadataAccessor inverse flattening accessor} if it is not
* already instanciated, and returns it, or return the current one if defined.
*/
private MetadataAccessor getInverseFlatteningAccessor() {
if (inverseFlattening == null) {
inverseFlattening = new MetadataAccessor(metadata,
"rectifiedGridDomain/crs/datum/ellipsoid/secondDefiningParameter/inverseFlattening", null);
}
return inverseFlattening;
}
/**
* Builds a {@linkplain MetadataAccessor prime meridian accessor} if it is not
* already instanciated, and returns it, or return the current one if defined.
*/
private MetadataAccessor getPrimeMeridianAccessor() {
if (primeMeridian == null) {
primeMeridian = new MetadataAccessor(metadata,
"rectifiedGridDomain/crs/datum/primeMeridian", null);
}
return primeMeridian;
}
/**
* Builds a {@linkplain MetadataAccessor projection accessor} if it is not
* already instanciated, and returns it, or return the current one if defined.
*/
private ChildList<Parameter> getProjectionAccessor() {
if (projection == null) {
projection = new ChildList.Parameters(metadata);
}
return projection;
}
/**
* Builds a {@linkplain MetadataAccessor semi major axis accessor} if it is not
* already instanciated, and returns it, or return the current one if defined.
*/
private MetadataAccessor getSemiMajorAxisAccessor() {
if (semiMajorAxis == null) {
semiMajorAxis = new MetadataAccessor(metadata,
"rectifiedGridDomain/crs/datum/ellipsoid/semiMajorAxis", null);
}
return semiMajorAxis;
}
/**
* Builds a {@linkplain MetadataAccessor semi minor axis accessor} if it is not
* already instanciated, and returns it, or return the current one if defined.
*/
private MetadataAccessor getSemiMinorAxisAccessor() {
if (semiMinorAxis == null) {
semiMinorAxis = new MetadataAccessor(metadata,
"rectifiedGridDomain/crs/datum/ellipsoid/secondDefiningParameter/semiMinorAxis", null);
}
return semiMinorAxis;
}
}