FieldGeodeticPoint.java

  1. /* Copyright 2002-2025 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.Field;
  21. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  22. import org.hipparchus.util.CompositeFormat;
  23. import org.hipparchus.util.FastMath;
  24. import org.hipparchus.util.FieldSinCos;
  25. import org.hipparchus.util.MathUtils;

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

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

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

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

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

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

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

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

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

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

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

  76.     /** Build a new instance from a {@link GeodeticPoint}.
  77.      * @param field field to which the elements belong
  78.      * @param geodeticPoint geodetic point to convert
  79.      * @since 12.1
  80.      */
  81.     public FieldGeodeticPoint(final Field<T> field, final GeodeticPoint geodeticPoint) {
  82.         this(field.getZero().newInstance(geodeticPoint.getLatitude()),
  83.              field.getZero().newInstance(geodeticPoint.getLongitude()),
  84.              field.getZero().newInstance(geodeticPoint.getAltitude()));
  85.     }

  86.     /** Get the latitude.
  87.      * @return latitude, an angular value in the range [-π/2, π/2]
  88.      */
  89.     public T getLatitude() {
  90.         return latitude;
  91.     }

  92.     /** Get the longitude.
  93.      * @return longitude, an angular value in the range [-π, π]
  94.      */
  95.     public T getLongitude() {
  96.         return longitude;
  97.     }

  98.     /** Get the altitude.
  99.      * @return altitude
  100.      */
  101.     public T getAltitude() {
  102.         return altitude;
  103.     }

  104.     /** Get the direction above the point, expressed in parent shape frame.
  105.      * <p>The zenith direction is defined as the normal to local horizontal plane.</p>
  106.      * @return unit vector in the zenith direction
  107.      * @see #getNadir()
  108.      */
  109.     public FieldVector3D<T> getZenith() {
  110.         if (zenith == null) {
  111.             final FieldSinCos<T> scLat = FastMath.sinCos(latitude);
  112.             final FieldSinCos<T> scLon = FastMath.sinCos(longitude);
  113.             zenith = new FieldVector3D<>(scLon.cos().multiply(scLat.cos()),
  114.                                          scLon.sin().multiply(scLat.cos()),
  115.                                          scLat.sin());
  116.         }
  117.         return zenith;
  118.     }

  119.     /** Get the direction below the point, expressed in parent shape frame.
  120.      * <p>The nadir direction is the opposite of zenith direction.</p>
  121.      * @return unit vector in the nadir direction
  122.      * @see #getZenith()
  123.      */
  124.     public FieldVector3D<T> getNadir() {
  125.         if (nadir == null) {
  126.             nadir = getZenith().negate();
  127.         }
  128.         return nadir;
  129.     }

  130.     /** Get the direction to the north of point, expressed in parent shape frame.
  131.      * <p>The north direction is defined in the horizontal plane
  132.      * (normal to zenith direction) and following the local meridian.</p>
  133.      * @return unit vector in the north direction
  134.      * @see #getSouth()
  135.      */
  136.     public FieldVector3D<T> getNorth() {
  137.         if (north == null) {
  138.             final FieldSinCos<T> scLat = FastMath.sinCos(latitude);
  139.             final FieldSinCos<T> scLon = FastMath.sinCos(longitude);
  140.             north = new FieldVector3D<>(scLon.cos().multiply(scLat.sin()).negate(),
  141.                                         scLon.sin().multiply(scLat.sin()).negate(),
  142.                                         scLat.cos());
  143.         }
  144.         return north;
  145.     }

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

  157.     /** Get the direction to the east of point, expressed in parent shape frame.
  158.      * <p>The east direction is defined in the horizontal plane
  159.      * in order to complete direct triangle (east, north, zenith).</p>
  160.      * @return unit vector in the east direction
  161.      * @see #getWest()
  162.      */
  163.     public FieldVector3D<T> getEast() {
  164.         if (east == null) {
  165.             final FieldSinCos<T> scLon = FastMath.sinCos(longitude);
  166.             east = new FieldVector3D<>(scLon.sin().negate(),
  167.                                        scLon.cos(),
  168.                                        longitude.getField().getZero());
  169.         }
  170.         return east;
  171.     }

  172.     /** Get the direction to the west of point, expressed in parent shape frame.
  173.      * <p>The west direction is the opposite of east direction.</p>
  174.      * @return unit vector in the west direction
  175.      * @see #getEast()
  176.      */
  177.     public FieldVector3D<T> getWest() {
  178.         if (west == null) {
  179.             west = getEast().negate();
  180.         }
  181.         return west;
  182.     }

  183.     /**
  184.      * Get non-Field equivalent.
  185.      * @return geodetic point
  186.      * @since 12.2
  187.      */
  188.     public GeodeticPoint toGeodeticPoint() {
  189.         return new GeodeticPoint(latitude.getReal(), longitude.getReal(), altitude.getReal());
  190.     }

  191.     @Override
  192.     public boolean equals(final Object object) {
  193.         if (object instanceof FieldGeodeticPoint<?>) {
  194.             @SuppressWarnings("unchecked")
  195.             final FieldGeodeticPoint<T> other = (FieldGeodeticPoint<T>) object;
  196.             return getLatitude().equals(other.getLatitude()) &&
  197.                    getLongitude().equals(other.getLongitude()) &&
  198.                    getAltitude().equals(other.getAltitude());
  199.         }
  200.         return false;
  201.     }

  202.     @Override
  203.     public int hashCode() {
  204.         return getLatitude().hashCode() ^
  205.                getLongitude().hashCode() ^
  206.                getAltitude().hashCode();
  207.     }

  208.     @Override
  209.     public String toString() {
  210.         final NumberFormat format = CompositeFormat.getDefaultNumberFormat();
  211.         return "{lat: " +
  212.                format.format(FastMath.toDegrees(getLatitude().getReal())) +
  213.                " deg, lon: " +
  214.                format.format(FastMath.toDegrees(getLongitude().getReal())) +
  215.                " deg, alt: " +
  216.                format.format(getAltitude().getReal()) +
  217.                "}";
  218.     }

  219. }