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.propagation.sampling; 18 19 import java.util.ArrayList; 20 import java.util.Collections; 21 import java.util.Iterator; 22 import java.util.List; 23 24 import org.orekit.propagation.SpacecraftState; 25 import org.orekit.time.AbsoluteDate; 26 27 /** This class gathers several {@link OrekitStepHandler} instances into one. 28 * 29 * @author Luc Maisonobe 30 */ 31 public class StepHandlerMultiplexer implements OrekitStepHandler { 32 33 /** Underlying step handlers. */ 34 private final List<OrekitStepHandler> handlers; 35 36 /** Target time. */ 37 private AbsoluteDate target; 38 39 /** Last known state. */ 40 private SpacecraftState last; 41 42 /** Simple constructor. 43 */ 44 public StepHandlerMultiplexer() { 45 handlers = new ArrayList<>(); 46 } 47 48 /** Add a handler for variable size step. 49 * <p> 50 * If propagation is ongoing (i.e. global {@link #init(SpacecraftState, AbsoluteDate) 51 * init} already called and global {@link #finish(SpacecraftState) finish} not called 52 * yet), then the local {@link OrekitStepHandler#init(SpacecraftState, AbsoluteDate) 53 * OrekitStepHandler.init} method of the added handler will be called with the last 54 * known state, so the handler starts properly. 55 * </p> 56 * @param handler step handler to add 57 */ 58 public void add(final OrekitStepHandler handler) { 59 handlers.add(handler); 60 if (last != null) { 61 // propagation is ongoing, we need to call init now for this handler 62 handler.init(last, target); 63 } 64 } 65 66 /** Add a handler for fixed size step. 67 * <p> 68 * If propagation is ongoing (i.e. global {@link #init(SpacecraftState, AbsoluteDate) 69 * init} already called and global {@link #finish(SpacecraftState) finish} not called 70 * yet), then the local {@link OrekitFixedStepHandler#init(SpacecraftState, AbsoluteDate, double) 71 * OrekitFixedStepHandler.init} method of the added handler will be called with the 72 * last known state, so the handler starts properly. 73 * </p> 74 * @param h fixed stepsize (s) 75 * @param handler handler called at the end of each finalized step 76 * @since 11.0 77 */ 78 public void add(final double h, final OrekitFixedStepHandler handler) { 79 final OrekitStepHandler normalized = new OrekitStepNormalizer(h, handler); 80 handlers.add(normalized); 81 if (last != null) { 82 // propagation is ongoing, we need to call init now for this handler 83 normalized.init(last, target); 84 } 85 } 86 87 /** Get an unmodifiable view of all handlers. 88 * <p> 89 * Note that if {@link OrekitFixedStepHandler fixed step handlers} have 90 * been {@link #add(double, OrekitFixedStepHandler)}, then they will 91 * show up wrapped within {@link OrekitStepNormalizer step normalizers}. 92 * </p> 93 * @return an unmodifiable view of all handlers 94 * @since 11.0 95 */ 96 public List<OrekitStepHandler> getHandlers() { 97 return Collections.unmodifiableList(handlers); 98 } 99 100 /** Remove a handler. 101 * <p> 102 * If propagation is ongoing (i.e. global {@link #init(SpacecraftState, AbsoluteDate) 103 * init} already called and global {@link #finish(SpacecraftState) finish} not called 104 * yet), then the local {@link OrekitStepHandler#finish(SpacecraftState) 105 * OrekitStepHandler.finish} method of the removed handler will be called with the last 106 * known state, so the handler stops properly. 107 * </p> 108 * @param handler step handler to remove 109 * @since 11.0 110 */ 111 public void remove(final OrekitStepHandler handler) { 112 final Iterator<OrekitStepHandler> iterator = handlers.iterator(); 113 while (iterator.hasNext()) { 114 if (iterator.next() == handler) { 115 if (last != null) { 116 // propagation is ongoing, we need to call finish now for this handler 117 handler.finish(last); 118 } 119 iterator.remove(); 120 return; 121 } 122 } 123 } 124 125 /** Remove a handler. 126 * <p> 127 * If propagation is ongoing (i.e. global {@link #init(SpacecraftState, AbsoluteDate) 128 * init} already called and global {@link #finish(SpacecraftState) finish} not called 129 * yet), then the local {@link OrekitFixedStepHandler#finish(SpacecraftState) 130 * OrekitFixedStepHandler.finish} method of the removed handler will be called with the 131 * last known state, so the handler stops properly. 132 * </p> 133 * @param handler step handler to remove 134 * @since 11.0 135 */ 136 public void remove(final OrekitFixedStepHandler handler) { 137 final Iterator<OrekitStepHandler> iterator = handlers.iterator(); 138 while (iterator.hasNext()) { 139 final OrekitStepHandler current = iterator.next(); 140 if (current instanceof OrekitStepNormalizer && 141 ((OrekitStepNormalizer) current).getFixedStepHandler() == handler) { 142 if (last != null) { 143 // propagation is ongoing, we need to call finish now for this handler 144 current.finish(last); 145 } 146 iterator.remove(); 147 return; 148 } 149 } 150 } 151 152 /** Remove all handlers managed by this multiplexer. 153 * <p> 154 * If propagation is ongoing (i.e. global {@link #init(SpacecraftState, AbsoluteDate) 155 * init} already called and global {@link #finish(SpacecraftState) finish} not called 156 * yet), then the local {@link OrekitStepHandler#finish(SpacecraftState) 157 * OrekitStepHandler.finish} and {@link OrekitFixedStepHandler#finish(SpacecraftState) 158 * OrekitFixedStepHandler.finish} methods of the removed handlers will be called with the 159 * last known state, so the handlers stop properly. 160 * </p> 161 * @since 11.0 162 */ 163 public void clear() { 164 if (last != null) { 165 // propagation is ongoing, we need to call finish now for all handlers 166 handlers.forEach(h -> h.finish(last)); 167 } 168 handlers.clear(); 169 } 170 171 /** {@inheritDoc} */ 172 public void init(final SpacecraftState s0, final AbsoluteDate t) { 173 this.target = t; 174 this.last = s0; 175 for (final OrekitStepHandler handler : handlers) { 176 handler.init(s0, t); 177 } 178 } 179 180 /** {@inheritDoc} */ 181 public void handleStep(final OrekitStepInterpolator interpolator) { 182 this.last = interpolator.getCurrentState(); 183 for (final OrekitStepHandler handler : handlers) { 184 handler.handleStep(interpolator); 185 } 186 } 187 188 /** {@inheritDoc} */ 189 public void finish(final SpacecraftState finalState) { 190 this.target = null; 191 this.last = null; 192 for (final OrekitStepHandler handler : handlers) { 193 handler.finish(finalState); 194 } 195 } 196 197 }