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