StepHandlerMultiplexer.java

  1. /* Copyright 2002-2024 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.propagation.sampling;

  18. import java.util.ArrayList;
  19. import java.util.Collections;
  20. import java.util.Iterator;
  21. import java.util.List;

  22. import org.orekit.propagation.SpacecraftState;
  23. import org.orekit.time.AbsoluteDate;

  24. /** This class gathers several {@link OrekitStepHandler} instances into one.
  25.  *
  26.  * @author Luc Maisonobe
  27.  */
  28. public class StepHandlerMultiplexer implements OrekitStepHandler {

  29.     /** Underlying step handlers. */
  30.     private final List<OrekitStepHandler> handlers;

  31.     /** Target time. */
  32.     private AbsoluteDate target;

  33.     /** Last known state. */
  34.     private SpacecraftState last;

  35.     /** Simple constructor.
  36.      */
  37.     public StepHandlerMultiplexer() {
  38.         handlers = new ArrayList<>();
  39.     }

  40.     /** Add a handler for variable size step.
  41.      * <p>
  42.      * If propagation is ongoing (i.e. global {@link #init(SpacecraftState, AbsoluteDate)
  43.      * init} already called and global {@link #finish(SpacecraftState) finish} not called
  44.      * yet), then the local {@link OrekitStepHandler#init(SpacecraftState, AbsoluteDate)
  45.      * OrekitStepHandler.init} method of the added handler will be called with the last
  46.      * known state, so the handler starts properly.
  47.      * </p>
  48.      * @param handler step handler to add
  49.      */
  50.     public void add(final OrekitStepHandler handler) {
  51.         handlers.add(handler);
  52.         if (last != null) {
  53.             // propagation is ongoing, we need to call init now for this handler
  54.             handler.init(last, target);
  55.         }
  56.     }

  57.     /** Add a handler for fixed size step.
  58.      * <p>
  59.      * If propagation is ongoing (i.e. global {@link #init(SpacecraftState, AbsoluteDate)
  60.      * init} already called and global {@link #finish(SpacecraftState) finish} not called
  61.      * yet), then the local {@link OrekitFixedStepHandler#init(SpacecraftState, AbsoluteDate, double)
  62.      * OrekitFixedStepHandler.init} method of the added handler will be called with the
  63.      * last known state, so the handler starts properly.
  64.      * </p>
  65.      * @param h fixed stepsize (s)
  66.      * @param handler handler called at the end of each finalized step
  67.      * @since 11.0
  68.      */
  69.     public void add(final double h, final OrekitFixedStepHandler handler) {
  70.         final OrekitStepHandler normalized = new OrekitStepNormalizer(h, handler);
  71.         handlers.add(normalized);
  72.         if (last != null) {
  73.             // propagation is ongoing, we need to call init now for this handler
  74.             normalized.init(last, target);
  75.         }
  76.     }

  77.     /** Get an unmodifiable view of all handlers.
  78.      * <p>
  79.      * Note that if {@link OrekitFixedStepHandler fixed step handlers} have
  80.      * been {@link #add(double, OrekitFixedStepHandler)}, then they will
  81.      * show up wrapped within {@link OrekitStepNormalizer step normalizers}.
  82.      * </p>
  83.      * @return an unmodifiable view of all handlers
  84.      * @since 11.0
  85.      */
  86.     public List<OrekitStepHandler> getHandlers() {
  87.         return Collections.unmodifiableList(handlers);
  88.     }

  89.     /** Remove a handler.
  90.      * <p>
  91.      * If propagation is ongoing (i.e. global {@link #init(SpacecraftState, AbsoluteDate)
  92.      * init} already called and global {@link #finish(SpacecraftState) finish} not called
  93.      * yet), then the local {@link OrekitStepHandler#finish(SpacecraftState)
  94.      * OrekitStepHandler.finish} method of the removed handler will be called with the last
  95.      * known state, so the handler stops properly.
  96.      * </p>
  97.      * @param handler step handler to remove
  98.      * @since 11.0
  99.      */
  100.     public void remove(final OrekitStepHandler handler) {
  101.         final Iterator<OrekitStepHandler> iterator = handlers.iterator();
  102.         while (iterator.hasNext()) {
  103.             if (iterator.next() == handler) {
  104.                 if (last != null) {
  105.                     // propagation is ongoing, we need to call finish now for this handler
  106.                     handler.finish(last);
  107.                 }
  108.                 iterator.remove();
  109.                 return;
  110.             }
  111.         }
  112.     }

  113.     /** Remove a handler.
  114.      * <p>
  115.      * If propagation is ongoing (i.e. global {@link #init(SpacecraftState, AbsoluteDate)
  116.      * init} already called and global {@link #finish(SpacecraftState) finish} not called
  117.      * yet), then the local {@link OrekitFixedStepHandler#finish(SpacecraftState)
  118.      * OrekitFixedStepHandler.finish} method of the removed handler will be called with the
  119.      * last known state, so the handler stops properly.
  120.      * </p>
  121.      * @param handler step handler to remove
  122.      * @since 11.0
  123.      */
  124.     public void remove(final OrekitFixedStepHandler handler) {
  125.         final Iterator<OrekitStepHandler> iterator = handlers.iterator();
  126.         while (iterator.hasNext()) {
  127.             final OrekitStepHandler current = iterator.next();
  128.             if (current instanceof OrekitStepNormalizer &&
  129.                 ((OrekitStepNormalizer) current).getFixedStepHandler() == handler) {
  130.                 if (last != null) {
  131.                     // propagation is ongoing, we need to call finish now for this handler
  132.                     current.finish(last);
  133.                 }
  134.                 iterator.remove();
  135.                 return;
  136.             }
  137.         }
  138.     }

  139.     /** Remove all handlers managed by this multiplexer.
  140.      * <p>
  141.      * If propagation is ongoing (i.e. global {@link #init(SpacecraftState, AbsoluteDate)
  142.      * init} already called and global {@link #finish(SpacecraftState) finish} not called
  143.      * yet), then the local {@link OrekitStepHandler#finish(SpacecraftState)
  144.      * OrekitStepHandler.finish} and {@link OrekitFixedStepHandler#finish(SpacecraftState)
  145.      * OrekitFixedStepHandler.finish} methods of the removed handlers will be called with the
  146.      * last known state, so the handlers stop properly.
  147.      * </p>
  148.      * @since 11.0
  149.      */
  150.     public void clear() {
  151.         if (last != null) {
  152.             // propagation is ongoing, we need to call finish now for all handlers
  153.             handlers.forEach(h -> h.finish(last));
  154.         }
  155.         handlers.clear();
  156.     }

  157.     /** {@inheritDoc} */
  158.     public void init(final SpacecraftState s0, final AbsoluteDate t) {
  159.         this.target = t;
  160.         this.last   = s0;
  161.         for (final OrekitStepHandler handler : handlers) {
  162.             handler.init(s0, t);
  163.         }
  164.     }

  165.     /** {@inheritDoc} */
  166.     public void handleStep(final OrekitStepInterpolator interpolator) {
  167.         this.last = interpolator.getCurrentState();
  168.         for (final OrekitStepHandler handler : handlers) {
  169.             handler.handleStep(interpolator);
  170.         }
  171.     }

  172.     /** {@inheritDoc} */
  173.     public void finish(final SpacecraftState finalState) {
  174.         this.target = null;
  175.         this.last   = null;
  176.         for (final OrekitStepHandler handler : handlers) {
  177.             handler.finish(finalState);
  178.         }
  179.     }

  180. }