blob: 11e7bc8ed22d41a0ea76284836015089a118dd84 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.sis.measure;
import org.opengis.geometry.DirectPosition;
import org.opengis.referencing.cs.AxisDirection;
/**
* A latitude angle in decimal degrees.
* Positive latitudes are North, while negative latitudes are South.
* The latitude symbol is the Greek lower-case letter phi (φ).
*
* <p>Because the Earth is not a perfect sphere, there is small differences in the latitude values of a point
* depending on how the latitude is defined:</p>
*
* <ul>
* <li><cite>Geodetic latitude</cite> is the angle between the equatorial plane and a line perpendicular
* to the {@linkplain org.apache.sis.referencing.datum.DefaultEllipsoid ellipsoid} surface.</li>
* <li><cite>Geocentric latitude</cite> is the angle between the equatorial plane and a line going from
* the Earth center. It differs from geodetic latitude by less than 11 angular minutes.</li>
* <li><cite>Astronomical latitude</cite> is the angle between the equatorial plane and a line given
* by the direction of a plumb line (the "true vertical").</li>
* <li>Above list is not exhaustive. There is also <cite>geomagnetic latitude</cite>, <i>etc.</i></li>
* </ul>
*
* The kind of latitude is unspecified by this {@code Latitude} class, and rather depends on the context:
* the latitude is <cite>geodetic</cite> if the coordinate reference system is
* {@linkplain org.apache.sis.referencing.crs.DefaultGeographicCRS geographic},
* or <cite>geocentric</cite> if the coordinate reference system is
* {@linkplain org.apache.sis.referencing.crs.DefaultGeocentricCRS geocentric}.
* If the context is unknown, then geodetic latitude can usually be assumed.
*
* <h2>Immutability and thread safety</h2>
* This final class is immutable and thus inherently thread-safe.
*
* @author Martin Desruisseaux (MPO, IRD, Geomatys)
* @version 0.8
*
* @see Longitude
* @see AngleFormat
* @see org.apache.sis.geometry.CoordinateFormat
*
* @since 0.3
* @module
*/
public final class Latitude extends Angle {
/**
* Serial number for inter-operability with different versions.
*/
private static final long serialVersionUID = -2227675003893702061L;
/**
* Minimum usual value for latitude ({@value}°).
*
* @see org.apache.sis.referencing.cs.DefaultCoordinateSystemAxis#getMinimumValue()
*/
public static final double MIN_VALUE = -90;
/**
* Maximum usual value for latitude (+{@value}°).
*
* @see org.apache.sis.referencing.cs.DefaultCoordinateSystemAxis#getMaximumValue()
*/
public static final double MAX_VALUE = +90;
/**
* Construct a new latitude with the specified angular value.
*
* @param φ latitude value in decimal degrees.
*/
public Latitude(final double φ) {
super(φ);
}
/**
* Constructs a newly allocated {@code Latitude} object that contain the angular value
* represented by the string. The string should represent an angle in either fractional
* degrees (e.g. 45.5°) or degrees with minutes and seconds (e.g. 45°30').
* The hemisphere (N or S) is optional (default to North).
*
* <p>This is a convenience constructor mostly for testing purpose, since it uses a fixed
* locale. Developers should consider using {@link AngleFormat} for end-user applications
* instead of this constructor.</p>
*
* @param string a string to be converted to a {@code Latitude}.
* @throws NumberFormatException if the string does not contain a parsable angle,
* or represents a longitude angle.
*
* @see AngleFormat#parse(String)
*/
public Latitude(final String string) throws NumberFormatException {
super(string);
}
/**
* Constructs a newly allocated object containing the latitude value of the given position.
* For this method, the latitude value is defined as the angular value associated to the first axis
* oriented toward {@linkplain AxisDirection#NORTH North} or {@linkplain AxisDirection#SOUTH South}.
* Note that this is not necessarily the <cite>geodetic latitudes</cite> used in
* {@linkplain org.apache.sis.referencing.crs.DefaultGeographicCRS geographic CRS};
* it may also be <cite>geocentric latitudes</cite>.
*
* <p>If the axis direction is South, then the sign of the coordinate value is inverted.
* If the coordinate value uses another angular units than {@linkplain Units#DEGREE degrees},
* then a unit conversion is applied.</p>
*
* @param position the coordinate from which to extract the latitude value in degrees.
* @throws IllegalArgumentException if the given coordinate it not associated to a CRS,
* or if no axis oriented toward North or South is found, or if that axis does
* not use {@linkplain Units#isAngular angular units}.
*
* @since 0.8
*/
public Latitude(final DirectPosition position) throws IllegalArgumentException {
super(valueOf(position, AxisDirection.NORTH, AxisDirection.SOUTH));
}
/**
* Returns the hemisphere character for an angle of the given sign.
* This is used only by {@link #toString()}, not by {@link AngleFormat}.
*/
@Override
final char hemisphere(final boolean negative) {
return negative ? 'S' : 'N';
}
/**
* Upper threshold before to format an angle as an ordinary number.
* This is used only by {@link #toString()}, not by {@link AngleFormat}.
*/
@Override
final double maximum() {
return 90;
}
/**
* Returns the given latitude value clamped to the [{@linkplain #MIN_VALUE -90} … {@linkplain #MAX_VALUE 90}]° range.
* If the given value is outside the latitude range, then this method replaces it by ±90° with the same sign than the
* given φ value.
*
* <p>Special cases:</p>
* <ul>
* <li>{@linkplain Double#NaN NaN} values are returned unchanged</li>
* <li>±∞ are mapped to ±90° (with the same sign)</li>
* <li>±0 are returned unchanged (i.e. the sign of negative and positive zero is preserved)</li>
* </ul>
*
* @param φ the latitude value in decimal degrees.
* @return the given value clamped to the [-90 … 90]° range, or NaN if the given value was NaN.
*
* @see Longitude#normalize(double)
*
* @since 0.4
*/
public static double clamp(final double φ) {
if < MIN_VALUE) return MIN_VALUE;
if > MAX_VALUE) return MAX_VALUE;
return φ;
}
}