FieldGeodeticPoint.java

  1. /* Copyright 2002-2016 CS Systèmes d'Information
  2.  * Licensed to CS Systèmes d'Information (CS) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * CS licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *   http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.orekit.bodies;

  18. import java.io.Serializable;
  19. import java.text.NumberFormat;

  20. import org.apache.commons.math3.RealFieldElement;
  21. import org.apache.commons.math3.geometry.euclidean.threed.FieldVector3D;
  22. import org.apache.commons.math3.util.CompositeFormat;
  23. import org.apache.commons.math3.util.FastMath;
  24. import org.apache.commons.math3.util.MathUtils;

  25. /** Point location relative to a 2D body surface, using {@link RealFieldElement}.
  26.  * <p>Instance of this class are guaranteed to be immutable.</p>
  27.  * @param <T> the type of the field elements
  28.  * @since 7.1
  29.  * @see BodyShape
  30.  * @author Luc Maisonobe
  31.  */
  32. public class FieldGeodeticPoint<T extends RealFieldElement<T>> implements Serializable {

  33.     /** Serializable UID. */
  34.     private static final long serialVersionUID = 20150821L;

  35.     /** Latitude of the point (rad). */
  36.     private final T latitude;

  37.     /** Longitude of the point (rad). */
  38.     private final T longitude;

  39.     /** Altitude of the point (m). */
  40.     private final T altitude;

  41.     /** Zenith direction. */
  42.     private transient FieldVector3D<T> zenith;

  43.     /** Nadir direction. */
  44.     private transient FieldVector3D<T> nadir;

  45.     /** North direction. */
  46.     private transient FieldVector3D<T> north;

  47.     /** South direction. */
  48.     private transient FieldVector3D<T> south;

  49.     /** East direction. */
  50.     private transient FieldVector3D<T> east;

  51.     /** West direction. */
  52.     private transient FieldVector3D<T> west;

  53.     /**
  54.      * Build a new instance. The angular coordinates will be normalized so that
  55.      * the latitude is between ±π/2 and the longitude is between ±π.
  56.      *
  57.      * @param latitude latitude of the point
  58.      * @param longitude longitude of the point
  59.      * @param altitude altitude of the point
  60.      */
  61.     public FieldGeodeticPoint(final T latitude, final T longitude,
  62.                               final T altitude) {
  63.         double lat = MathUtils.normalizeAngle(latitude.getReal(), FastMath.PI / 2);
  64.         double lon = MathUtils.normalizeAngle(longitude.getReal(), 0);
  65.         if (lat > FastMath.PI / 2.0) {
  66.             // latitude is beyond the pole -> add 180 to longitude
  67.             lat = FastMath.PI - lat;
  68.             lon = MathUtils.normalizeAngle(longitude.getReal() + FastMath.PI, 0);
  69.         }
  70.         final double deltaLat = lat - latitude.getReal();
  71.         final double deltaLon = lon - longitude.getReal();
  72.         this.latitude  = latitude.add(deltaLat);
  73.         this.longitude = longitude.add(deltaLon);
  74.         this.altitude  = altitude;
  75.     }

  76.     /** Get the latitude.
  77.      * @return latitude, an angular value in the range [-π/2, π/2]
  78.      */
  79.     public T getLatitude() {
  80.         return latitude;
  81.     }

  82.     /** Get the longitude.
  83.      * @return longitude, an angular value in the range [-π, π]
  84.      */
  85.     public T getLongitude() {
  86.         return longitude;
  87.     }

  88.     /** Get the altitude.
  89.      * @return altitude
  90.      */
  91.     public T getAltitude() {
  92.         return altitude;
  93.     }

  94.     /** Get the direction above the point, expressed in parent shape frame.
  95.      * <p>The zenith direction is defined as the normal to local horizontal plane.</p>
  96.      * @return unit vector in the zenith direction
  97.      * @see #getNadir()
  98.      */
  99.     public FieldVector3D<T> getZenith() {
  100.         if (zenith == null) {
  101.             final T cosLat = latitude.cos();
  102.             final T sinLat = latitude.sin();
  103.             final T cosLon = longitude.cos();
  104.             final T sinLon = longitude.sin();
  105.             zenith = new FieldVector3D<T>(cosLon.multiply(cosLat),
  106.                                           sinLon.multiply(cosLat),
  107.                                           sinLat);
  108.         }
  109.         return zenith;
  110.     }

  111.     /** Get the direction below the point, expressed in parent shape frame.
  112.      * <p>The nadir direction is the opposite of zenith direction.</p>
  113.      * @return unit vector in the nadir direction
  114.      * @see #getZenith()
  115.      */
  116.     public FieldVector3D<T> getNadir() {
  117.         if (nadir == null) {
  118.             nadir = getZenith().negate();
  119.         }
  120.         return nadir;
  121.     }

  122.     /** Get the direction to the north of point, expressed in parent shape frame.
  123.      * <p>The north direction is defined in the horizontal plane
  124.      * (normal to zenith direction) and following the local meridian.</p>
  125.      * @return unit vector in the north direction
  126.      * @see #getSouth()
  127.      */
  128.     public FieldVector3D<T> getNorth() {
  129.         if (north == null) {
  130.             final T cosLat = latitude.cos();
  131.             final T sinLat = latitude.sin();
  132.             final T cosLon = longitude.cos();
  133.             final T sinLon = longitude.sin();
  134.             north = new FieldVector3D<T>(cosLon.multiply(sinLat).negate(),
  135.                                          sinLon.multiply(sinLat).negate(),
  136.                                          cosLat);
  137.         }
  138.         return north;
  139.     }

  140.     /** Get the direction to the south of point, expressed in parent shape frame.
  141.      * <p>The south direction is the opposite of north direction.</p>
  142.      * @return unit vector in the south direction
  143.      * @see #getNorth()
  144.      */
  145.     public FieldVector3D<T> getSouth() {
  146.         if (south == null) {
  147.             south = getNorth().negate();
  148.         }
  149.         return south;
  150.     }

  151.     /** Get the direction to the east of point, expressed in parent shape frame.
  152.      * <p>The east direction is defined in the horizontal plane
  153.      * in order to complete direct triangle (east, north, zenith).</p>
  154.      * @return unit vector in the east direction
  155.      * @see #getWest()
  156.      */
  157.     public FieldVector3D<T> getEast() {
  158.         if (east == null) {
  159.             east = new FieldVector3D<T>(longitude.sin().negate(),
  160.                                         longitude.cos(),
  161.                                         longitude.getField().getZero());
  162.         }
  163.         return east;
  164.     }

  165.     /** Get the direction to the west of point, expressed in parent shape frame.
  166.      * <p>The west direction is the opposite of east direction.</p>
  167.      * @return unit vector in the west direction
  168.      * @see #getEast()
  169.      */
  170.     public FieldVector3D<T> getWest() {
  171.         if (west == null) {
  172.             west = getEast().negate();
  173.         }
  174.         return west;
  175.     }

  176.     @Override
  177.     public boolean equals(final Object object) {
  178.         if (object instanceof FieldGeodeticPoint<?>) {
  179.             @SuppressWarnings("unchecked")
  180.             final FieldGeodeticPoint<T> other = (FieldGeodeticPoint<T>) object;
  181.             return getLatitude().equals(other.getLatitude()) &&
  182.                    getLongitude().equals(other.getLongitude()) &&
  183.                    getAltitude().equals(other.getAltitude());
  184.         }
  185.         return false;
  186.     }

  187.     @Override
  188.     public int hashCode() {
  189.         return getLatitude().hashCode() ^
  190.                getLongitude().hashCode() ^
  191.                getAltitude().hashCode();
  192.     }

  193.     @Override
  194.     public String toString() {
  195.         final NumberFormat format = CompositeFormat.getDefaultNumberFormat();
  196.         return "{lat: " +
  197.                format.format(FastMath.toDegrees(getLatitude().getReal())) +
  198.                " deg, lon: " +
  199.                format.format(FastMath.toDegrees(getLongitude().getReal())) +
  200.                " deg, alt: " +
  201.                format.format(getAltitude().getReal()) +
  202.                "}";
  203.     }

  204. }