FieldGeodeticPoint.java

  1. /* Copyright 2002-2022 CS GROUP
  2.  * Licensed to CS GROUP (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.text.NumberFormat;

  19. import org.hipparchus.CalculusFieldElement;
  20. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  21. import org.hipparchus.util.CompositeFormat;
  22. import org.hipparchus.util.FastMath;
  23. import org.hipparchus.util.FieldSinCos;
  24. import org.hipparchus.util.MathUtils;

  25. /** Point location relative to a 2D body surface, using {@link CalculusFieldElement}.
  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 CalculusFieldElement<T>> {

  33.     /** Latitude of the point (rad). */
  34.     private final T latitude;

  35.     /** Longitude of the point (rad). */
  36.     private final T longitude;

  37.     /** Altitude of the point (m). */
  38.     private final T altitude;

  39.     /** Zenith direction. */
  40.     private FieldVector3D<T> zenith;

  41.     /** Nadir direction. */
  42.     private FieldVector3D<T> nadir;

  43.     /** North direction. */
  44.     private FieldVector3D<T> north;

  45.     /** South direction. */
  46.     private FieldVector3D<T> south;

  47.     /** East direction. */
  48.     private FieldVector3D<T> east;

  49.     /** West direction. */
  50.     private FieldVector3D<T> west;

  51.     /**
  52.      * Build a new instance. The angular coordinates will be normalized so that
  53.      * the latitude is between ±π/2 and the longitude is between ±π.
  54.      *
  55.      * @param latitude latitude of the point (rad)
  56.      * @param longitude longitude of the point (rad)
  57.      * @param altitude altitude of the point (m)
  58.      */
  59.     public FieldGeodeticPoint(final T latitude, final T longitude,
  60.                               final T altitude) {
  61.         final T zero = latitude.getField().getZero();
  62.         final T pi   = zero.getPi();
  63.         T lat = MathUtils.normalizeAngle(latitude,  pi.multiply(0.5));
  64.         T lon = MathUtils.normalizeAngle(longitude, zero);
  65.         if (lat.getReal() > pi.multiply(0.5).getReal()) {
  66.             // latitude is beyond the pole -> add 180 to longitude
  67.             lat = pi.subtract(lat);
  68.             lon = MathUtils.normalizeAngle(longitude.add(pi), zero);
  69.         }
  70.         this.latitude  = lat;
  71.         this.longitude = lon;
  72.         this.altitude  = altitude;
  73.     }

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

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

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

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

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

  118.     /** Get the direction to the north of point, expressed in parent shape frame.
  119.      * <p>The north direction is defined in the horizontal plane
  120.      * (normal to zenith direction) and following the local meridian.</p>
  121.      * @return unit vector in the north direction
  122.      * @see #getSouth()
  123.      */
  124.     public FieldVector3D<T> getNorth() {
  125.         if (north == null) {
  126.             final FieldSinCos<T> scLat = FastMath.sinCos(latitude);
  127.             final FieldSinCos<T> scLon = FastMath.sinCos(longitude);
  128.             north = new FieldVector3D<>(scLon.cos().multiply(scLat.sin()).negate(),
  129.                                         scLon.sin().multiply(scLat.sin()).negate(),
  130.                                         scLat.cos());
  131.         }
  132.         return north;
  133.     }

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

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

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

  171.     @Override
  172.     public boolean equals(final Object object) {
  173.         if (object instanceof FieldGeodeticPoint<?>) {
  174.             @SuppressWarnings("unchecked")
  175.             final FieldGeodeticPoint<T> other = (FieldGeodeticPoint<T>) object;
  176.             return getLatitude().equals(other.getLatitude()) &&
  177.                    getLongitude().equals(other.getLongitude()) &&
  178.                    getAltitude().equals(other.getAltitude());
  179.         }
  180.         return false;
  181.     }

  182.     @Override
  183.     public int hashCode() {
  184.         return getLatitude().hashCode() ^
  185.                getLongitude().hashCode() ^
  186.                getAltitude().hashCode();
  187.     }

  188.     @Override
  189.     public String toString() {
  190.         final NumberFormat format = CompositeFormat.getDefaultNumberFormat();
  191.         return "{lat: " +
  192.                format.format(FastMath.toDegrees(getLatitude().getReal())) +
  193.                " deg, lon: " +
  194.                format.format(FastMath.toDegrees(getLongitude().getReal())) +
  195.                " deg, alt: " +
  196.                format.format(getAltitude().getReal()) +
  197.                "}";
  198.     }

  199. }