CelestialBodyFactory.java

  1. /* Copyright 2002-2013 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.util.ArrayList;
  19. import java.util.HashMap;
  20. import java.util.List;
  21. import java.util.Map;

  22. import org.orekit.errors.OrekitException;
  23. import org.orekit.errors.OrekitMessages;

  24. /** Factory class for bodies of the solar system.
  25.  * <p>The {@link #getSun() Sun}, the {@link #getMoon() Moon} and the planets
  26.  * (including the Pluto dwarf planet) are provided by this factory. In addition,
  27.  * two important points are provided for convenience: the {@link
  28.  * #getSolarSystemBarycenter() solar system barycenter} and the {@link
  29.  * #getEarthMoonBarycenter() Earth-Moon barycenter}.</p>
  30.  * <p>The underlying body-centered frames are either direct children of {@link
  31.  * org.orekit.frames.FramesFactory#getEME2000() EME2000} (for {@link #getMoon() Moon}
  32.  * and {@link #getEarthMoonBarycenter() Earth-Moon barycenter}) or children from other
  33.  * body-centered frames. For example, the path from EME2000 to
  34.  * Jupiter-centered frame is: EME2000, Earth-Moon barycenter centered,
  35.  * solar system barycenter centered, Jupiter-centered. The defining transforms
  36.  * of these frames are combinations of simple linear {@link
  37.  * org.orekit.frames.Transform#Transform(org.orekit.time.AbsoluteDate,
  38.  * org.apache.commons.math3.geometry.euclidean.threed.Vector3D,
  39.  * org.apache.commons.math3.geometry.euclidean.threed.Vector3D) translation/velocity} transforms
  40.  * without any rotation. The frame axes are therefore always parallel to
  41.  * {@link org.orekit.frames.FramesFactory#getEME2000() EME2000} frame axes.</p>
  42.  * <p>The position of the bodies provided by this class are interpolated using
  43.  * the JPL DE 405/DE 406 ephemerides.</p>
  44.  * @author Luc Maisonobe
  45.  */
  46. public class CelestialBodyFactory {

  47.     /** Predefined name for solar system barycenter.
  48.      * @see #getBody(String)
  49.      */
  50.     public static final String SOLAR_SYSTEM_BARYCENTER = "solar system barycenter";

  51.     /** Predefined name for Sun.
  52.      * @see #getBody(String)
  53.      */
  54.     public static final String SUN = "Sun";

  55.     /** Predefined name for Mercury.
  56.      * @see #getBody(String)
  57.      */
  58.     public static final String MERCURY = "Mercury";

  59.     /** Predefined name for Venus.
  60.      * @see #getBody(String)
  61.      */
  62.     public static final String VENUS = "Venus";

  63.     /** Predefined name for Earth-Moon barycenter.
  64.      * @see #getBody(String)
  65.      */
  66.     public static final String EARTH_MOON = "Earth-Moon barycenter";

  67.     /** Predefined name for Earth.
  68.      * @see #getBody(String)
  69.      */
  70.     public static final String EARTH = "Earth";

  71.     /** Predefined name for Moon.
  72.      * @see #getBody(String)
  73.      */
  74.     public static final String MOON = "Moon";

  75.     /** Predefined name for Mars.
  76.      * @see #getBody(String)
  77.      */
  78.     public static final String MARS = "Mars";

  79.     /** Predefined name for Jupiter.
  80.      * @see #getBody(String)
  81.      */
  82.     public static final String JUPITER = "Jupiter";

  83.     /** Predefined name for Saturn.
  84.      * @see #getBody(String)
  85.      */
  86.     public static final String SATURN = "Saturn";

  87.     /** Predefined name for Uranus.
  88.      * @see #getBody(String)
  89.      */
  90.     public static final String URANUS = "Uranus";

  91.     /** Predefined name for Neptune.
  92.      * @see #getBody(String)
  93.      */
  94.     public static final String NEPTUNE = "Neptune";

  95.     /** Predefined name for Pluto.
  96.      * @see #getBody(String)
  97.      */
  98.     public static final String PLUTO = "Pluto";

  99.     /** Celestial body loaders map. */
  100.     private static final Map<String, List<CelestialBodyLoader>> LOADERS_MAP =
  101.         new HashMap<String, List<CelestialBodyLoader>>();

  102.     /** Celestial body map. */
  103.     private static final Map<String, CelestialBody> CELESTIAL_BODIES_MAP =
  104.         new HashMap<String, CelestialBody>();

  105.     /** Private constructor.
  106.      * <p>This class is a utility class, it should neither have a public
  107.      * nor a default constructor. This private constructor prevents
  108.      * the compiler from generating one automatically.</p>
  109.      */
  110.     private CelestialBodyFactory() {
  111.     }

  112.     /** Add a loader for celestial bodies.
  113.      * @param name name of the body (may be one of the predefined names or a user-defined name)
  114.      * @param loader custom loader to add for the body
  115.      * @see #addDefaultCelestialBodyLoader(String)
  116.      * @see #clearCelestialBodyLoaders(String)
  117.      * @see #clearCelestialBodyLoaders()
  118.      */
  119.     public static void addCelestialBodyLoader(final String name, final CelestialBodyLoader loader) {
  120.         synchronized (LOADERS_MAP) {
  121.             List<CelestialBodyLoader> loaders = LOADERS_MAP.get(name);
  122.             if (loaders == null) {
  123.                 loaders = new ArrayList<CelestialBodyLoader>();
  124.                 LOADERS_MAP.put(name, loaders);
  125.             }
  126.             loaders.add(loader);
  127.         }
  128.     }

  129.     /** Add the default loaders for all predefined celestial bodies.
  130.      * @param supportedNames regular expression for supported files names
  131.      * (may be null if the default JPL file names are used)
  132.      * <p>
  133.      * The default loaders look for DE405 or DE406 JPL ephemerides.
  134.      * </p>
  135.      * @see <a href="ftp://ssd.jpl.nasa.gov/pub/eph/planets/unix/de405">DE405 JPL ephemerides</a>
  136.      * @see <a href="ftp://ssd.jpl.nasa.gov/pub/eph/planets/unix/de406">DE406 JPL ephemerides</a>
  137.      * @see #addCelestialBodyLoader(String, CelestialBodyLoader)
  138.      * @see #addDefaultCelestialBodyLoader(String)
  139.      * @see #clearCelestialBodyLoaders(String)
  140.      * @see #clearCelestialBodyLoaders()
  141.      * @exception OrekitException if the header constants cannot be read
  142.      */
  143.     public static void addDefaultCelestialBodyLoader(final String supportedNames)
  144.         throws OrekitException {
  145.         addDefaultCelestialBodyLoader(SOLAR_SYSTEM_BARYCENTER, supportedNames);
  146.         addDefaultCelestialBodyLoader(SUN,                     supportedNames);
  147.         addDefaultCelestialBodyLoader(MERCURY,                 supportedNames);
  148.         addDefaultCelestialBodyLoader(VENUS,                   supportedNames);
  149.         addDefaultCelestialBodyLoader(EARTH_MOON,              supportedNames);
  150.         addDefaultCelestialBodyLoader(EARTH,                   supportedNames);
  151.         addDefaultCelestialBodyLoader(MOON,                    supportedNames);
  152.         addDefaultCelestialBodyLoader(MARS,                    supportedNames);
  153.         addDefaultCelestialBodyLoader(JUPITER,                 supportedNames);
  154.         addDefaultCelestialBodyLoader(SATURN,                  supportedNames);
  155.         addDefaultCelestialBodyLoader(URANUS,                  supportedNames);
  156.         addDefaultCelestialBodyLoader(NEPTUNE,                 supportedNames);
  157.         addDefaultCelestialBodyLoader(PLUTO,                   supportedNames);
  158.     }

  159.     /** Add the default loaders for celestial bodies.
  160.      * @param name name of the body (if not one of the predefined names, the method does nothing)
  161.      * @param supportedNames regular expression for supported files names
  162.      * (may be null if the default JPL file names are used)
  163.      * <p>
  164.      * The default loaders look for DE405 or DE406 JPL ephemerides.
  165.      * </p>
  166.      * @see <a href="ftp://ssd.jpl.nasa.gov/pub/eph/planets/unix/de405">DE405 JPL ephemerides</a>
  167.      * @see <a href="ftp://ssd.jpl.nasa.gov/pub/eph/planets/unix/de406">DE406 JPL ephemerides</a>
  168.      * @see #addCelestialBodyLoader(String, CelestialBodyLoader)
  169.      * @see #addDefaultCelestialBodyLoader(String)
  170.      * @see #clearCelestialBodyLoaders(String)
  171.      * @see #clearCelestialBodyLoaders()
  172.      * @exception OrekitException if the header constants cannot be read
  173.      */
  174.     public static void addDefaultCelestialBodyLoader(final String name, final String supportedNames)
  175.         throws OrekitException {

  176.         CelestialBodyLoader loader = null;
  177.         if (name.equals(SOLAR_SYSTEM_BARYCENTER)) {
  178.             loader =
  179.                 new JPLEphemeridesLoader(supportedNames, JPLEphemeridesLoader.EphemerisType.SOLAR_SYSTEM_BARYCENTER);
  180.         } else if (name.equals(SUN)) {
  181.             loader =
  182.                 new JPLEphemeridesLoader(supportedNames, JPLEphemeridesLoader.EphemerisType.SUN);
  183.         } else if (name.equals(MERCURY)) {
  184.             loader =
  185.                 new JPLEphemeridesLoader(supportedNames, JPLEphemeridesLoader.EphemerisType.MERCURY);
  186.         } else if (name.equals(VENUS)) {
  187.             loader =
  188.                 new JPLEphemeridesLoader(supportedNames, JPLEphemeridesLoader.EphemerisType.VENUS);
  189.         } else if (name.equals(EARTH_MOON)) {
  190.             loader =
  191.                 new JPLEphemeridesLoader(supportedNames, JPLEphemeridesLoader.EphemerisType.EARTH_MOON);
  192.         } else if (name.equals(EARTH)) {
  193.             loader =
  194.                 new JPLEphemeridesLoader(supportedNames, JPLEphemeridesLoader.EphemerisType.EARTH);
  195.         } else if (name.equals(MOON)) {
  196.             loader =
  197.                 new JPLEphemeridesLoader(supportedNames, JPLEphemeridesLoader.EphemerisType.MOON);
  198.         } else if (name.equals(MARS)) {
  199.             loader =
  200.                 new JPLEphemeridesLoader(supportedNames, JPLEphemeridesLoader.EphemerisType.MARS);
  201.         } else if (name.equals(JUPITER)) {
  202.             loader =
  203.                 new JPLEphemeridesLoader(supportedNames, JPLEphemeridesLoader.EphemerisType.JUPITER);
  204.         } else if (name.equals(SATURN)) {
  205.             loader =
  206.                 new JPLEphemeridesLoader(supportedNames, JPLEphemeridesLoader.EphemerisType.SATURN);
  207.         } else if (name.equals(URANUS)) {
  208.             loader =
  209.                 new JPLEphemeridesLoader(supportedNames, JPLEphemeridesLoader.EphemerisType.URANUS);
  210.         } else if (name.equals(NEPTUNE)) {
  211.             loader =
  212.                 new JPLEphemeridesLoader(supportedNames, JPLEphemeridesLoader.EphemerisType.NEPTUNE);
  213.         } else if (name.equals(PLUTO)) {
  214.             loader =
  215.                 new JPLEphemeridesLoader(supportedNames, JPLEphemeridesLoader.EphemerisType.PLUTO);
  216.         }

  217.         if (loader != null) {
  218.             addCelestialBodyLoader(name, loader);
  219.         }

  220.     }

  221.     /** Clear loaders for one celestial body.
  222.      * <p>
  223.      * Calling this method also clears the celestial body that
  224.      * has been loaded via this {@link CelestialBodyLoader}.
  225.      * </p>
  226.      * @param name name of the body
  227.      * @see #addCelestialBodyLoader(String, CelestialBodyLoader)
  228.      * @see #clearCelestialBodyLoaders()
  229.      * @see #clearCelestialBodyCache(String)
  230.      */
  231.     public static void clearCelestialBodyLoaders(final String name) {
  232.         // use same synchronization order as in getBody to prevent deadlocks
  233.         synchronized (CELESTIAL_BODIES_MAP) {
  234.             // take advantage of reentrent synchronization as
  235.             // clearCelestialBodyCache uses the same lock inside
  236.             clearCelestialBodyCache(name);

  237.             synchronized (LOADERS_MAP) {
  238.                 LOADERS_MAP.remove(name);
  239.             }
  240.         }
  241.     }

  242.     /** Clear loaders for all celestial bodies.
  243.      * <p>
  244.      * Calling this method also clears all loaded celestial bodies.
  245.      * </p>
  246.      * @see #addCelestialBodyLoader(String, CelestialBodyLoader)
  247.      * @see #clearCelestialBodyLoaders(String)
  248.      * @see #clearCelestialBodyCache()
  249.      */
  250.     public static void clearCelestialBodyLoaders() {
  251.         synchronized (CELESTIAL_BODIES_MAP) {
  252.             clearCelestialBodyCache();

  253.             synchronized (LOADERS_MAP) {
  254.                 LOADERS_MAP.clear();
  255.             }
  256.         }
  257.     }

  258.     /** Clear the specified celestial body from the internal cache.
  259.      * @param name name of the body
  260.      */
  261.     public static void clearCelestialBodyCache(final String name) {
  262.         synchronized (CELESTIAL_BODIES_MAP) {
  263.             CELESTIAL_BODIES_MAP.remove(name);
  264.         }
  265.     }

  266.     /** Clear all loaded celestial bodies.
  267.      * <p>
  268.      * Calling this method will remove all loaded bodies from the internal
  269.      * cache. Subsequent calls to {@link #getBody(String)} or similar methods
  270.      * will result in a reload of the requested body from the configured loader(s).
  271.      * </p>
  272.      */
  273.     public static void clearCelestialBodyCache() {
  274.         synchronized (CELESTIAL_BODIES_MAP) {
  275.             CELESTIAL_BODIES_MAP.clear();
  276.         }
  277.     }

  278.     /** Get the solar system barycenter aggregated body.
  279.      * @return solar system barycenter aggregated body
  280.      * @exception OrekitException if the celestial body cannot be built
  281.      */
  282.     public static CelestialBody getSolarSystemBarycenter() throws OrekitException {
  283.         return getBody(SOLAR_SYSTEM_BARYCENTER);
  284.     }

  285.     /** Get the Sun singleton body.
  286.      * @return Sun body
  287.      * @exception OrekitException if the celestial body cannot be built
  288.      */
  289.     public static CelestialBody getSun() throws OrekitException {
  290.         return getBody(SUN);
  291.     }

  292.     /** Get the Mercury singleton body.
  293.      * @return Sun body
  294.      * @exception OrekitException if the celestial body cannot be built
  295.      */
  296.     public static CelestialBody getMercury() throws OrekitException {
  297.         return getBody(MERCURY);
  298.     }

  299.     /** Get the Venus singleton body.
  300.      * @return Venus body
  301.      * @exception OrekitException if the celestial body cannot be built
  302.      */
  303.     public static CelestialBody getVenus() throws OrekitException {
  304.         return getBody(VENUS);
  305.     }

  306.     /** Get the Earth-Moon barycenter singleton bodies pair.
  307.      * @return Earth-Moon barycenter bodies pair
  308.      * @exception OrekitException if the celestial body cannot be built
  309.      */
  310.     public static CelestialBody getEarthMoonBarycenter() throws OrekitException {
  311.         return getBody(EARTH_MOON);
  312.     }

  313.     /** Get the Earth singleton body.
  314.      * @return Earth body
  315.      * @exception OrekitException if the celestial body cannot be built
  316.      */
  317.     public static CelestialBody getEarth() throws OrekitException {
  318.         return getBody(EARTH);
  319.     }

  320.     /** Get the Moon singleton body.
  321.      * @return Moon body
  322.      * @exception OrekitException if the celestial body cannot be built
  323.      */
  324.     public static CelestialBody getMoon() throws OrekitException {
  325.         return getBody(MOON);
  326.     }

  327.     /** Get the Mars singleton body.
  328.      * @return Mars body
  329.      * @exception OrekitException if the celestial body cannot be built
  330.      */
  331.     public static CelestialBody getMars() throws OrekitException {
  332.         return getBody(MARS);
  333.     }

  334.     /** Get the Jupiter singleton body.
  335.      * @return Jupiter body
  336.      * @exception OrekitException if the celestial body cannot be built
  337.      */
  338.     public static CelestialBody getJupiter() throws OrekitException {
  339.         return getBody(JUPITER);
  340.     }

  341.     /** Get the Saturn singleton body.
  342.      * @return Saturn body
  343.      * @exception OrekitException if the celestial body cannot be built
  344.      */
  345.     public static CelestialBody getSaturn() throws OrekitException {
  346.         return getBody(SATURN);
  347.     }

  348.     /** Get the Uranus singleton body.
  349.      * @return Uranus body
  350.      * @exception OrekitException if the celestial body cannot be built
  351.      */
  352.     public static CelestialBody getUranus() throws OrekitException {
  353.         return getBody(URANUS);
  354.     }

  355.     /** Get the Neptune singleton body.
  356.      * @return Neptune body
  357.      * @exception OrekitException if the celestial body cannot be built
  358.      */
  359.     public static CelestialBody getNeptune() throws OrekitException {
  360.         return getBody(NEPTUNE);
  361.     }

  362.     /** Get the Pluto singleton body.
  363.      * @return Pluto body
  364.      * @exception OrekitException if the celestial body cannot be built
  365.      */
  366.     public static CelestialBody getPluto() throws OrekitException {
  367.         return getBody(PLUTO);
  368.     }

  369.     /** Get a celestial body.
  370.      * <p>
  371.      * If no {@link CelestialBodyLoader} has been added by calling {@link
  372.      * #addCelestialBodyLoader(String, CelestialBodyLoader)
  373.      * addCelestialBodyLoader} or if {@link #clearCelestialBodyLoaders(String)
  374.      * clearCelestialBodyLoaders} has been called afterwards,
  375.      * the {@link #addDefaultCelestialBodyLoader(String, String)
  376.      * addDefaultCelestialBodyLoader} method will be called automatically,
  377.      * once with the default name for JPL DE ephemerides and once with the
  378.      * default name for IMCCE INPOP files.
  379.      * </p>
  380.      * @param name name of the celestial body
  381.      * @return celestial body
  382.      * @exception OrekitException if the celestial body cannot be built
  383.      */
  384.     public static CelestialBody getBody(final String name)
  385.         throws OrekitException {
  386.         synchronized (CELESTIAL_BODIES_MAP) {
  387.             CelestialBody body = CELESTIAL_BODIES_MAP.get(name);
  388.             if (body == null) {
  389.                 synchronized (LOADERS_MAP) {
  390.                     List<CelestialBodyLoader> loaders = LOADERS_MAP.get(name);
  391.                     if ((loaders == null) || loaders.isEmpty()) {
  392.                         addDefaultCelestialBodyLoader(name, JPLEphemeridesLoader.DEFAULT_DE_SUPPORTED_NAMES);
  393.                         addDefaultCelestialBodyLoader(name, JPLEphemeridesLoader.DEFAULT_INPOP_SUPPORTED_NAMES);
  394.                         loaders = LOADERS_MAP.get(name);
  395.                     }
  396.                     OrekitException delayedException = null;
  397.                     for (CelestialBodyLoader loader : loaders) {
  398.                         try {
  399.                             body = loader.loadCelestialBody(name);
  400.                             if (body != null) {
  401.                                 break;
  402.                             }
  403.                         } catch (OrekitException oe) {
  404.                             delayedException = oe;
  405.                         }
  406.                     }
  407.                     if (body == null) {
  408.                         throw (delayedException != null) ?
  409.                               delayedException :
  410.                               new OrekitException(OrekitMessages.NO_DATA_LOADED_FOR_CELESTIAL_BODY, name);
  411.                     }

  412.                 }

  413.                 // save the body
  414.                 CELESTIAL_BODIES_MAP.put(name, body);

  415.             }

  416.             return body;

  417.         }
  418.     }

  419. }