//
// CoordinateSystem.java
//
/*
VisAD system for interactive analysis and visualization of numerical
data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/
package visad;
/**
CoordinateSystem is the VisAD abstract superclass for coordinate systems for
vectors in R^n for n>0. Specific coordinate systems are defined by
extending this class and providing coordinate transformation logic in
the toReference and fromReference methods.<P>
CoordinateSystem objects should be immutable.<P>
*/
public abstract class CoordinateSystem extends Object
implements java.io.Serializable {
/** reference coordinate system (e.g., (Latitude, Longitude, Radius) ) */
private final RealTupleType Reference;
private final int DomainDimension;
/** not required to be convertable with Reference.DefaultUnits */
private final Unit[] CoordinateSystemUnits;
/**
* Constructs from the type of the reference coordinate system and units for
* values in this coordinate system. Subclasses must supply reference type
* and units.
* @param reference The type of the reference coordinate
* system. Numeric values in the reference
* coordinate system shall be in units of
* <code>reference.getDefaultUnits()</code>
* unless specified otherwise.
* @param units The default units for this coordinate system.
* Numeric values in this coordinate system shall
* be in units of <code>units</code> unless
* specified otherwise. May be <code>null</code>
* or an array of <code>null</code>s.
* @throws VisADException Couldn't create necessary VisAD object.
*/
public CoordinateSystem(RealTupleType reference, Unit[] units)
throws VisADException {
if (reference == null) {
throw new CoordinateSystemException(
"CoordinateSystem: Reference may not be null");
}
if (reference.getCoordinateSystem() != null) {
throw new CoordinateSystemException(
"CoordinateSystem: Reference may not have a DefaultCoordinateSystem");
}
Reference = reference;
DomainDimension = Reference.getDimension();
if (units != null && DomainDimension != units.length) {
throw new UnitException("CoordinateSystem: units dimension does not match");
}
CoordinateSystemUnits = new Unit[DomainDimension];
if (units != null) {
for (int i=0; i<DomainDimension; i++) CoordinateSystemUnits[i] = units[i];
}
}
/**
* trusted constructor for initializers (does not throw
* any declared Exceptions)
* @param reference The type of the reference coordinate
* system. Numeric values in the reference
* coordinate system shall be in units of
* <code>reference.getDefaultUnits()</code>
* unless specified otherwise.
* @param units The default units for this coordinate system.
* Numeric values in this coordinate system shall
* be in units of <code>units</code> unless
* specified otherwise. May be <code>null</code>
* or an array of <code>null</code>s.
* @param b dummy argument for trusted constructor signature
*/
CoordinateSystem(RealTupleType reference, Unit[] units, boolean b) {
Reference = reference;
DomainDimension = Reference.getDimension();
CoordinateSystemUnits = new Unit[DomainDimension];
if (units != null) {
for (int i=0; i<DomainDimension; i++) CoordinateSystemUnits[i] = units[i];
}
}
/**
* Return the reference RealTupleType for this CoordinateSystem.
* @return reference RealTupleType
*/
public RealTupleType getReference() {
return Reference;
}
/**
* Return the number of components in the reference RealTupleType.
* @return dimension of the reference.
*/
public int getDimension() {
return DomainDimension;
}
/**
* Return the Units for this CoordinateSystem's reference
* RealTupleType. These are the units of the return values from
* {@link #toReference}.
* @return copy of the Units array used at construction.
*/
public Unit[] getReferenceUnits() {
return Reference.getDefaultUnits();
}
/**
* Return the Units for this CoordinateSystem. The Units
* are what's expected for the input data for the
* {@link #toReference} method.
* @return copy of the Units array used at construction.
*/
public Unit[] getCoordinateSystemUnits() {
return Unit.copyUnitsArray(CoordinateSystemUnits);
}
/**
* Convert RealTuple values to Reference coordinates;
* for efficiency, input and output values are passed as
* double[][] arrays rather than RealTuple[] arrays; the array
* organization is double[tuple_dimension][number_of_tuples];
* can modify and return argument array.
* @param value array of values assumed to be in coordinateSystem
* units. Input array is not guaranteed to be immutable
* and could be used for return.
* @return array of double values in reference coordinates and Units.
* @throws VisADException if problem with conversion.
*/
public abstract double[][] toReference(double[][] value) throws VisADException;
/**
* Convert RealTuple values from Reference coordinates;
* for efficiency, input and output values are passed as
* double[][] arrays rather than RealTuple[] arrays; the array
* organization is double[tuple_dimension][number_of_tuples];
* can modify and return argument array.
* @param value array of values assumed to be in reference
* Units. Input array is not guaranteed to be immutable
* and could be used for return.
* @return array of double values in CoordinateSystem Units.
* @throws VisADException if problem with conversion.
*/
public abstract double[][] fromReference(double[][] value) throws VisADException;
/**
* Convert RealTuple values to Reference coordinates;
* for efficiency, input and output values are passed as
* float[][] arrays rather than RealTuple[] arrays; the array
* organization is float[tuple_dimension][number_of_tuples];
* can modify and return argument array. This implementation
* converts the input array to doubles and calls {@link
* #toReference(double[][])} and then returns that converted
* double array back as a float array. For efficiency, subclasses
* should override this implementation.
* @param value array of values assumed to be in coordinateSystem
* units. Input array is not guaranteed to be immutable
* and could be used for return.
* @return array of float values in reference coordinates and Units.
* @throws VisADException if problem with conversion.
*/
public float[][] toReference(float[][] value) throws VisADException {
double[][] val = Set.floatToDouble(value);
val = toReference(val);
return Set.doubleToFloat(val);
}
/**
* Convert RealTuple values from Reference coordinates;
* for efficiency, input and output values are passed as
* float[][] arrays rather than RealTuple[] arrays; the array
* organization is float[tuple_dimension][number_of_tuples];
* can modify and return argument array. This implementation
* converts the input array to doubles and calls {@link
* #toReference(double[][])} and then returns that converted
* double array back as a float array. For efficiency, subclasses
* should override this implementation.
* @param value array of values assumed to be in reference
* Units. Input array is not guaranteed to be immutable
* and could be used for return.
* @return array of float values in this CoordinateSystem Units.
* @throws VisADException if problem with conversion.
*/
public float[][] fromReference(float[][] value) throws VisADException {
double[][] val = Set.floatToDouble(value);
val = fromReference(val);
return Set.doubleToFloat(val);
}
/**
* Check to see if a conversion can be done between values
* of one RealTupleType and another given the CoordinateSystems
* supplied.
* @param out The output {@link RealTupleType}.
* @param coord_out The coordinate system transformation associated
* with the output {@link RealTupleType} or <code>
* null</code>.
* @param in The input {@link RealTupleType}.
* @param coord_in The coordinate system transformation associated
* with the output {@link RealTupleType} or <code>
* null</code>.
*
* @return true if conversion is possible.
*/
public static boolean canConvert(RealTupleType out, CoordinateSystem coord_out,
RealTupleType in, CoordinateSystem coord_in) {
if (out == null) return (in == null);
if (out.equals(in)) return true;
RealTupleType ref_out = out;
if (coord_out != null) ref_out = coord_out.getReference();
RealTupleType ref_in = in;
if (coord_in != null) ref_in = coord_in.getReference();
return ref_out.equals(ref_in);
}
/**
* <p>Transforms double-valued coordinates between two {@link RealTupleType}s.
* Unit conversion is always performed even if no coordinate transformation
* is done.</p>
*
* <p>This implementation uses {@link #transformCoordinatesFreeUnits} to do
* most of the transformation.</p>
*
* <p>If both {@link RealTupleType}s have a reference coordinate system, then
* this implementation <em>always</em> transforms the input domain values by
* first transforming them according to the input reference coordinate system
* and then inverse transforming them according to the output reference
* coordinate system -- even if the input and output {@link RealTupleType}s
* are equal.</p>
*
* @param out The output {@link RealTupleType}.
* @param coord_out The coordinate system transformation associated
* with the output {@link RealTupleType} or <code>
* null</code>.
* @param units_out The output units.
* @param errors_out The output error estimates or <code>null</code>.
* @param in The input {@link RealTupleType}.
* @param coord_in The coordinate system transformation associated
* with the output {@link RealTupleType} or <code>
* null</code>.
* @param units_in The input units or <code>null</code>.
* @param errors_in The input error estimates or <code>null</code>.
* @param value The input coordinate values. <code>value[i][j]
* </code> is the <code>j</code>-th sample of the
* <code>i</code>-th component. The values might
* be modified upon return from this method.
* @return The transformed coordinate values not in the input
* array.
* @throws VisADException if a VisAD failure occurs.
* @throws NullPointerException if <code>units_out</code> is
* <code>null</code>.
*/
public static double[][] transformCoordinates(
RealTupleType out, CoordinateSystem coord_out,
Unit[] units_out, ErrorEstimate[] errors_out,
RealTupleType in, CoordinateSystem coord_in,
Unit[] units_in, ErrorEstimate[] errors_in,
double[][] value) throws VisADException {
return transformCoordinates(out, coord_out, units_out, errors_out,
in, coord_in, units_in, errors_in,
value, true);
}
/**
* <p>Transforms double-valued coordinates between two {@link RealTupleType}s.
* Unit conversion is always performed even if no coordinate transformation
* is done.</p>
*
* <p>This implementation uses {@link #transformCoordinatesFreeUnits} to do
* most of the transformation.</p>
*
* <p>If both {@link RealTupleType}s have a reference coordinate system, then
* this implementation <em>always</em> transforms the input domain values by
* first transforming them according to the input reference coordinate system
* and then inverse transforming them according to the output reference
* coordinate system -- even if the input and output {@link RealTupleType}s
* are equal.</p>
*
* @param out The output {@link RealTupleType}.
* @param coord_out The coordinate system transformation associated
* with the output {@link RealTupleType} or <code>
* null</code>.
* @param units_out The output units.
* @param errors_out The output error estimates or <code>null</code>.
* @param in The input {@link RealTupleType}.
* @param coord_in The coordinate system transformation associated
* with the output {@link RealTupleType} or <code>
* null</code>.
* @param units_in The input units or <code>null</code>.
* @param errors_in The input error estimates or <code>null</code>.
* @param value The input coordinate values. <code>value[i][j]
* </code> is the <code>j</code>-th sample of the
* <code>i</code>-th component. The values might
* be modified upon return from this method.
* @param copy if false, the underlying <code>value</code> array
* transformations may be done in place.
* @return The transformed coordinate values not in the input
* array, if copy is true.
* @throws VisADException if a VisAD failure occurs.
* @throws NullPointerException if <code>units_out</code> is
* <code>null</code>.
*/
public static double[][] transformCoordinates(
RealTupleType out, CoordinateSystem coord_out,
Unit[] units_out, ErrorEstimate[] errors_out,
RealTupleType in, CoordinateSystem coord_in,
Unit[] units_in, ErrorEstimate[] errors_in,
double[][] value, boolean copy) throws VisADException {
int n = out.getDimension();
Unit[] units_free = new Unit[n];
double[][] old_value = value;
value =
transformCoordinatesFreeUnits(out, coord_out, units_free, errors_out,
in, coord_in, units_in, errors_in, value);
// WLH 21 Nov 2001
if (value == old_value) {
value = new double[n][];
for (int i=0; i<n; i++) value[i] = old_value[i];
}
ErrorEstimate[] sub_errors_out = new ErrorEstimate[1];
if (errors_out == null) {
for (int i=0; i<n; i++) {
value[i] = Unit.transformUnits(units_out[i], sub_errors_out, units_free[i],
null, value[i], copy);
}
}
else {
for (int i=0; i<n; i++) {
value[i] = Unit.transformUnits(units_out[i], sub_errors_out, units_free[i],
errors_out[i], value[i], copy);
errors_out[i] = sub_errors_out[0];
}
}
return value;
}
/**
* <p>Transforms double-valued coordinates between two {@link RealTupleType}s.
* This is just like {@link #transformCoordinates}, except that final Unit
* conversion to <code>units_out</code> is not done; rather,
* <code>units_out[i]</code> is set to the final {@link Unit} of
* <code>value[i]</code>.</p>
*
* <p>If both {@link RealTupleType}s have a reference coordinate system, then
* this implementation <em>always</em> transforms the input domain values by
* first transforming them according to the input reference coordinate system
* and then inverse transforming them according to the output reference
* coordinate system -- even if the input and output {@link RealTupleType}s
* are equal.</p>
*
* @param out The output {@link RealTupleType}.
* @param coord_out The coordinate system transformation associated
* with the output {@link RealTupleType} or <code>
* null</code>.
* @param units_out The output units or <code>null</code>.
* @param errors_out The output error estimates or <code>null</code>.
* @param in The input {@link RealTupleType}.
* @param coord_in The coordinate system transformation associated
* with the output {@link RealTupleType} or <code>
* null</code>.
* @param units_in The input units or <code>null</code>.
* @param errors_in The input error estimates or <code>null</code>.
* @param value The input coordinate values. <code>value[i][j]
* </code> is the <code>j</code>-th sample of the
* <code>i</code>-th component.
* @return The transformed coordinate values. Possibly
* in the input array.
* @throws VisADException if a VisAD failure occurs.
*/
public static double[][] transformCoordinatesFreeUnits(
RealTupleType out, CoordinateSystem coord_out,
Unit[] units_out, ErrorEstimate[] errors_out,
RealTupleType in, CoordinateSystem coord_in,
Unit[] units_in, ErrorEstimate[] errors_in,
double[][] value) throws VisADException {
int n = in.getDimension();
// prepare for error calculations, if any
double[][] error_values = new double[1][1];
boolean any_transform = false;
boolean any_errors = false;
if (errors_in != null && errors_out != null) {
any_errors = true;
for (int i=0; i<n; i++) {
if (errors_in[i] == null) any_errors = false;
}
}
if (errors_out != null) {
// set default errors_out in case no transform
if (errors_in != null) {
for (int i=0; i<n; i++) errors_out[i] = errors_in[i];
}
else {
for (int i=0; i<n; i++) errors_out[i] = null;
}
}
// prepare for Unit calculations
Unit[] units = Unit.copyUnitsArray(units_in);
if (units == null) units = new Unit[n];
Unit[] error_units = Unit.copyUnitsArray(units);
if (units_out != null) {
// set default units_out in case no transform
for (int i=0; i<n; i++) units_out[i] = units[i];
}
// WLH 28 March 2000
// ensure coord_out and coord_in include any RealTupleType defaults
if (coord_out == null) coord_out = out.getCoordinateSystem();
if (coord_in == null) coord_in = in.getCoordinateSystem();
if (out.equals(in)) {
if (coord_in == null && coord_out == null) return value;
if (coord_in == null || coord_out == null) {
throw new CoordinateSystemException(
"CoordinateSystem.transformCoordinates: inconsistency");
}
if (!coord_in.equals(coord_out)) {
if (any_errors) {
if (!any_transform) {
error_values = ErrorEstimate.init_error_values(errors_in);
}
any_transform = true;
error_values = coord_in.toReference(error_values, error_units);
error_values = coord_out.fromReference(error_values, error_units);
}
value = coord_in.toReference(value, units);
value = coord_out.fromReference(value, units);
}
}
else { // !out.equals(in)
RealTupleType ref_out = out;
if (coord_out != null) {
ref_out = coord_out.getReference();
// WLH - this check for testing only - may eliminate later
if (out.getCoordinateSystem() == null ||
!out.getCoordinateSystem().getReference().equals(ref_out)) {
throw new CoordinateSystemException(
"CoordinateSystem.transformCoordinates: out References don't match");
}
}
RealTupleType ref_in = in;
if (coord_in != null) {
ref_in = coord_in.getReference();
// WLH - this check for testing only - may eliminate later
if (in.getCoordinateSystem() == null ||
!in.getCoordinateSystem().getReference().equals(ref_in)) {
throw new CoordinateSystemException(
"CoordinateSystem.transformCoordinates: in References don't match");
}
}
if (ref_out.equals(ref_in)) {
if (!in.equals(ref_in)) {
if (any_errors) {
if (!any_transform) {
error_values = ErrorEstimate.init_error_values(errors_in);
}
any_transform = true;
error_values = coord_in.toReference(error_values, error_units);
}
value = coord_in.toReference(value, units);
}
if (!out.equals(ref_out)) {
if (any_errors) {
if (!any_transform) {
error_values = ErrorEstimate.init_error_values(errors_in);
}
any_transform = true;
error_values = coord_out.fromReference(error_values, error_units);
}
value = coord_out.fromReference(value, units);
}
}
else { // !(ref_out.equals(ref_in)
// WLH 4 July 2000 - should throw an Exception here -
// but breaks too many things, so don't do it
}
} // end if (!out.equals(in))
// set return Units
if (units_out != null) {
for (int i=0; i<n; i++) units_out[i] = units[i];
}
// set return ErrorEstimates
if (any_errors && any_transform) {
for (int i=0; i<n; i++) {
double error = Math.abs( error_values[i][2 * i + 1] -
error_values[i][2 * i] );
errors_out[i] = new ErrorEstimate(value[i], error, units_out[i]);
}
}
return value;
}
/**
* <p>Transforms float-valued coordinates between two {@link RealTupleType}s.
* Unit conversion is always performed even if no coordinate transformation
* is done.</p>
*
* <p>This implementation uses {@link #transformCoordinatesFreeUnits} to do
* most of the transformation.</p>
*
* <p>If both {@link RealTupleType}s have a reference coordinate system, then
* this implementation <em>always</em> transforms the input domain values by
* first transforming them according to the input reference coordinate system
* and then inverse transforming them according to the output reference
* coordinate system -- even if the input and output {@link RealTupleType}s
* are equal.</p>
*
* @param out The output {@link RealTupleType}.
* @param coord_out The coordinate system transformation associated
* with the output {@link RealTupleType} or <code>
* null</code>.
* @param units_out The output units.
* @param errors_out The output error estimates or <code>null</code>.
* @param in The input {@link RealTupleType}.
* @param coord_in The coordinate system transformation associated
* with the output {@link RealTupleType} or <code>
* null</code>.
* @param units_in The input units or <code>null</code>.
* @param errors_in The input error estimates or <code>null</code>.
* @param value The input coordinate values. <code>value[i][j]
* </code> is the <code>j</code>-th sample of the
* <code>i</code>-th component. The values might
* be modified upon return from this method.
* @return The transformed coordinate values not in the input
* array.
* @throws VisADException if a VisAD failure occurs.
* @throws NullPointerException if <code>units_out</code> is
* <code>null</code>.
*/
public static float[][] transformCoordinates(
RealTupleType out, CoordinateSystem coord_out,
Unit[] units_out, ErrorEstimate[] errors_out,
RealTupleType in, CoordinateSystem coord_in,
Unit[] units_in, ErrorEstimate[] errors_in,
float[][] value) throws VisADException {
return transformCoordinates(out, coord_out, units_out, errors_out,
in, coord_in, units_in, errors_in,
value, true);
}
/**
* <p>Transforms float-valued coordinates between two {@link RealTupleType}s.
* Unit conversion is always performed even if no coordinate transformation
* is done.</p>
*
* <p>This implementation uses {@link #transformCoordinatesFreeUnits} to do
* most of the transformation.</p>
*
* <p>If both {@link RealTupleType}s have a reference coordinate system, then
* this implementation <em>always</em> transforms the input domain values by
* first transforming them according to the input reference coordinate system
* and then inverse transforming them according to the output reference
* coordinate system -- even if the input and output {@link RealTupleType}s
* are equal.</p>
*
* @param out The output {@link RealTupleType}.
* @param coord_out The coordinate system transformation associated
* with the output {@link RealTupleType} or <code>
* null</code>.
* @param units_out The output units.
* @param errors_out The output error estimates or <code>null</code>.
* @param in The input {@link RealTupleType}.
* @param coord_in The coordinate system transformation associated
* with the output {@link RealTupleType} or <code>
* null</code>.
* @param units_in The input units or <code>null</code>.
* @param errors_in The input error estimates or <code>null</code>.
* @param value The input coordinate values. <code>value[i][j]
* </code> is the <code>j</code>-th sample of the
* <code>i</code>-th component. The values might
* be modified upon return from this method.
* @param copy if false, the underlying <code>value</code> array
* transformations may be done in place.
* @return The transformed coordinate values not in the input
* array, if copy is true.
* @throws VisADException if a VisAD failure occurs.
* @throws NullPointerException if <code>units_out</code> is
* <code>null</code>.
*/
public static float[][] transformCoordinates(
RealTupleType out, CoordinateSystem coord_out,
Unit[] units_out, ErrorEstimate[] errors_out,
RealTupleType in, CoordinateSystem coord_in,
Unit[] units_in, ErrorEstimate[] errors_in,
float[][] value, boolean copy) throws VisADException {
int n = out.getDimension();
Unit[] units_free = new Unit[n];
float[][] old_value = value;
value =
transformCoordinatesFreeUnits(out, coord_out, units_free, errors_out,
in, coord_in, units_in, errors_in, value);
// WLH 21 Nov 2001
if (value == old_value) {
value = new float[n][];
for (int i=0; i<n; i++) value[i] = old_value[i];
}
ErrorEstimate[] sub_errors_out = new ErrorEstimate[1];
if (errors_out == null) {
for (int i=0; i<n; i++) {
value[i] = Unit.transformUnits(units_out[i], sub_errors_out, units_free[i],
null, value[i], copy);
}
}
else {
for (int i=0; i<n; i++) {
value[i] = Unit.transformUnits(units_out[i], sub_errors_out, units_free[i],
errors_out[i], value[i], copy);
errors_out[i] = sub_errors_out[0];
}
}
return value;
}
/**
* <p>Transforms float-valued coordinates between two {@link RealTupleType}s.
* This is just like {@link #transformCoordinates}, except that final Unit
* conversion to <code>units_out</code> is not done; rather,
* <code>units_out[i]</code> is set to the final {@link Unit} of
* <code>value[i]</code>.</p>
*
* <p>If both {@link RealTupleType}s have a reference coordinate system, then
* this implementation <em>always</em> transforms the input domain values by
* first transforming them according to the input reference coordinate system
* and then inverse transforming them according to the output reference
* coordinate system -- even if the input and output {@link RealTupleType}s
* are equal.</p>
*
* @param out The output {@link RealTupleType}.
* @param coord_out The coordinate system transformation associated
* with the output {@link RealTupleType} or <code>
* null</code>.
* @param units_out The output units or <code>null</code>.
* @param errors_out The output error estimates or <code>null</code>.
* @param in The input {@link RealTupleType}.
* @param coord_in The coordinate system transformation associated
* with the output {@link RealTupleType} or <code>
* null</code>.
* @param units_in The input units or <code>null</code>.
* @param errors_in The input error estimates or <code>null</code>.
* @param value The input coordinate values. <code>value[i][j]
* </code> is the <code>j</code>-th sample of the
* <code>i</code>-th component.
* @return The transformed coordinate values. Possibly
* in the input array.
* @throws VisADException if a VisAD failure occurs.
*/
public static float[][] transformCoordinatesFreeUnits(
RealTupleType out, CoordinateSystem coord_out,
Unit[] units_out, ErrorEstimate[] errors_out,
RealTupleType in, CoordinateSystem coord_in,
Unit[] units_in, ErrorEstimate[] errors_in,
float[][] value) throws VisADException {
int n = in.getDimension();
// prepare for error calculations, if any
double[][] error_values = new double[1][1];
boolean any_transform = false;
boolean any_errors = false;
if (errors_in != null && errors_out != null) {
any_errors = true;
for (int i=0; i<n; i++) {
if (errors_in[i] == null) any_errors = false;
}
}
if (errors_out != null) {
// set default errors_out in case no transform
if (errors_in != null) {
for (int i=0; i<n; i++) errors_out[i] = errors_in[i];
}
else {
for (int i=0; i<n; i++) errors_out[i] = null;
}
}
// prepare for Unit calculations
Unit[] units = Unit.copyUnitsArray(units_in);
if (units == null) units = new Unit[n];
Unit[] error_units = Unit.copyUnitsArray(units);
if (units_out != null) {
// set default units_out in case no transform
for (int i=0; i<n; i++) units_out[i] = units[i];
}
// WLH 28 March 2000
// ensure coord_out and coord_in include any RealTupleType defaults
if (coord_out == null) coord_out = out.getCoordinateSystem();
if (coord_in == null) coord_in = in.getCoordinateSystem();
if (out.equals(in)) {
if (coord_in == null && coord_out == null) return value;
if (coord_in == null || coord_out == null) {
throw new CoordinateSystemException(
"CoordinateSystem.transformCoordinates: inconsistency");
}
if (!coord_in.equals(coord_out)) {
if (any_errors) {
if (!any_transform) {
error_values = ErrorEstimate.init_error_values(errors_in);
}
any_transform = true;
error_values = coord_in.toReference(error_values, error_units);
error_values = coord_out.fromReference(error_values, error_units);
}
value = coord_in.toReference(value, units);
value = coord_out.fromReference(value, units);
}
}
else { // !out.equals(in)
RealTupleType ref_out = out;
if (coord_out != null) {
ref_out = coord_out.getReference();
// WLH - this check for testing only - may eliminate later
if (out.getCoordinateSystem() == null ||
!out.getCoordinateSystem().getReference().equals(ref_out)) {
throw new CoordinateSystemException(
"CoordinateSystem.transformCoordinates: out References don't match");
}
}
RealTupleType ref_in = in;
if (coord_in != null) {
ref_in = coord_in.getReference();
// WLH - this check for testing only - may eliminate later
if (in.getCoordinateSystem() == null ||
!in.getCoordinateSystem().getReference().equals(ref_in)) {
throw new CoordinateSystemException(
"CoordinateSystem.transformCoordinates: in References don't match");
}
}
if (ref_out.equals(ref_in)) {
if (!in.equals(ref_in)) {
if (any_errors) {
if (!any_transform) {
error_values = ErrorEstimate.init_error_values(errors_in);
}
any_transform = true;
error_values = coord_in.toReference(error_values, error_units);
}
value = coord_in.toReference(value, units);
}
if (!out.equals(ref_out)) {
if (any_errors) {
if (!any_transform) {
error_values = ErrorEstimate.init_error_values(errors_in);
}
any_transform = true;
error_values = coord_out.fromReference(error_values, error_units);
}
value = coord_out.fromReference(value, units);
}
}
else { // !(ref_out.equals(ref_in)
// WLH 4 July 2000 - should throw an Exception here -
// but breaks too many things, so don't do it
}
} // end if (!out.equals(in))
// set return Units
if (units_out != null) {
for (int i=0; i<n; i++) units_out[i] = units[i];
}
// set return ErrorEstimates
if (any_errors && any_transform) {
for (int i=0; i<n; i++) {
double error = Math.abs( error_values[i][2 * i + 1] -
error_values[i][2 * i] );
errors_out[i] = new ErrorEstimate(value[i], error, units_out[i]);
}
}
return value;
}
/**
* Convert values in Units specified to Reference coordinates.
* If units are non-null, they are both the Unit[] of input value,
* and a holder for Unit[] of output.
* @param value array of values assumed to be in the Units
* specified or CoordinateSystem units if null.
* @param units Units of input values. If non-null, input values
* are converted to CoordinateSystem Units (if they
* are non-null) before calling
* {@link #toReference(double[][])}.
* @return array of double values in reference coordinates and Units.
* @throws VisADException if problem with conversion.
*/
public double[][] toReference(double[][] value, Unit[] units)
throws VisADException {
int n = value.length;
if (CoordinateSystemUnits != null) {
for (int i=0; i<n; i++) {
if (CoordinateSystemUnits[i] != null) {
if (units[i] != null && !CoordinateSystemUnits[i].equals(units[i])) {
value[i] = CoordinateSystemUnits[i].toThis(value[i], units[i], false);
}
}
}
}
Unit[] us = Reference.getDefaultUnits();
if (us != null) {
for (int i=0; i<n; i++) units[i] = us[i];
}
else {
for (int i=0; i<n; i++) units[i] = null;
}
return toReference(value);
}
/**
* Convert values in Units specified to Reference coordinates.
* If units are non-null, they are both the Unit[] of input value,
* and a holder for Unit[] of output.
* @param value array of values assumed to be in the Units
* specified or CoordinateSystem units if null.
* @param units Units of input values. If non-null, input values
* are converted to CoordinateSystem Units (if they
* are non-null) before calling
* {@link #toReference(float[][])}.
* @return array of float values in reference coordinates and Units.
* @throws VisADException if problem with conversion.
*/
public float[][] toReference(float[][] value, Unit[] units)
throws VisADException {
int n = value.length;
if (CoordinateSystemUnits != null) {
for (int i=0; i<n; i++) {
if (CoordinateSystemUnits[i] != null) {
if (units[i] != null && !CoordinateSystemUnits[i].equals(units[i])) {
value[i] = CoordinateSystemUnits[i].toThis(value[i], units[i], false);
}
}
}
}
Unit[] us = Reference.getDefaultUnits();
if (us != null) {
for (int i=0; i<n; i++) units[i] = us[i];
}
else {
for (int i=0; i<n; i++) units[i] = null;
}
return toReference(value);
}
/**
* Convert values in Units specified to this CoordinateSystem's
* Units. If units are non-null, they are both the Unit[] of input value,
* and a holder for Unit[] of output.
* @param value array of values assumed to be in the Units
* specified or Reference units if null.
* @param units Units of input values. If non-null, input values
* are converted to Reference Units (if they
* are non-null) before calling
* {@link #fromReference(double[][])}.
* @return array of double values in CoordinateSystem Units.
* @throws VisADException if problem with conversion.
*/
public double[][] fromReference(double[][] value, Unit[] units)
throws VisADException {
int n = value.length;
Unit[] us = Reference.getDefaultUnits();
if (us != null) {
for (int i=0; i<n; i++) {
if (us[i] != null) {
if (units[i] != null && !us[i].equals(units[i])) {
value[i] = us[i].toThis(value[i], units[i], false);
}
}
}
}
if (CoordinateSystemUnits != null) {
for (int i=0; i<n; i++) units[i] = CoordinateSystemUnits[i];
}
else {
for (int i=0; i<n; i++) units[i] = null;
}
return fromReference(value);
}
/**
* Convert values in Units specified to this CoordinateSystem's
* Units. If units are non-null, they are both the Unit[] of input value,
* and a holder for Unit[] of output.
* @param value array of values assumed to be in the Units
* specified or Reference units if null.
* @param units Units of input values. If non-null, input values
* are converted to Reference Units (if they
* are non-null) before calling
* {@link #fromReference(float[][])}.
* @return array of float values in CoordinateSystem Units.
* @throws VisADException if problem with conversion.
*/
public float[][] fromReference(float[][] value, Unit[] units)
throws VisADException {
int n = value.length;
Unit[] us = Reference.getDefaultUnits();
if (us != null) {
for (int i=0; i<n; i++) {
if (us[i] != null) {
if (units[i] != null && !us[i].equals(units[i])) {
value[i] = us[i].toThis(value[i], units[i], false);
}
}
}
}
if (CoordinateSystemUnits != null) {
for (int i=0; i<n; i++) units[i] = CoordinateSystemUnits[i];
}
else {
for (int i=0; i<n; i++) units[i] = null;
}
return fromReference(value);
}
/**
* Indicates whether or not this instance is equal to an object
* (note must test for cs == null).
* @param cs the object in question.
* @return <code>true</code> if and only if this instance equals cs.
*/
public abstract boolean equals(Object cs);
}