1   /* Copyright 2022-2026 Thales Alenia Space
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.frames;
18  
19  import java.util.LinkedHashMap;
20  import java.util.Map;
21  import java.util.concurrent.locks.ReentrantLock;
22  import java.util.function.Function;
23  
24  import org.orekit.time.AbsoluteDate;
25  
26  /** Thread-safe cached provider for frame transforms.
27   * <p>
28   * This provider is based on a thread-safe Least Recently Used cache
29   * using date as it access key, hence saving computation time on
30   * transform building.
31   * </p>
32   * <p>
33   * This class is thread-safe.
34   * </p>
35   * @author Luc Maisonobe
36   * @since 13.0.3
37   */
38  public class CachedTransformProvider {
39  
40      /** Origin frame. */
41      private final Frame origin;
42  
43      /** Destination frame. */
44      private final Frame destination;
45  
46      /** Number of transforms kept in the date-based cache. */
47      private final int cacheSize;
48  
49      /** Generator for full transforms. */
50      private final Function<AbsoluteDate, Transform> fullGenerator;
51  
52      /** Generator for kinematic transforms. */
53      private final Function<AbsoluteDate, KinematicTransform> kinematicGenerator;
54  
55      /** Generator for static transforms. */
56      private final Function<AbsoluteDate, StaticTransform> staticGenerator;
57  
58      /** Lock for concurrent access. */
59      private final ReentrantLock lock;
60  
61      /** Transforms LRU cache. */
62      private final Map<AbsoluteDate, Transform> fullCache;
63  
64      /** Transforms LRU cache. */
65      private final Map<AbsoluteDate, KinematicTransform> kinematicCache;
66  
67      /** Transforms LRU cache. */
68      private final Map<AbsoluteDate, StaticTransform> staticCache;
69  
70      /** Simple constructor.
71       * @param origin             origin frame
72       * @param destination        destination frame
73       * @param fullGenerator      generator for full transforms
74       * @param kinematicGenerator generator for kinematic transforms
75       * @param staticGenerator    generator for static transforms
76       * @param cacheSize          number of transforms kept in the date-based cache
77       */
78      public CachedTransformProvider(final Frame origin, final Frame destination,
79                                     final Function<AbsoluteDate, Transform> fullGenerator,
80                                     final Function<AbsoluteDate, KinematicTransform> kinematicGenerator,
81                                     final Function<AbsoluteDate, StaticTransform> staticGenerator,
82                                     final int cacheSize) {
83  
84          this.origin             = origin;
85          this.destination        = destination;
86          this.cacheSize          = cacheSize;
87          this.fullGenerator      = fullGenerator;
88          this.kinematicGenerator = kinematicGenerator;
89          this.staticGenerator    = staticGenerator;
90          this.lock               = new ReentrantLock();
91  
92          // cache for full transforms
93          this.fullCache = new LinkedHashMap<>(cacheSize, 0.75f, true) {
94              /**
95               * {@inheritDoc}
96               */
97              @Override
98              protected boolean removeEldestEntry(final Map.Entry<AbsoluteDate, Transform> eldest) {
99                  return size() > cacheSize;
100             }
101         };
102 
103         // cache for kinematic transforms
104         this.kinematicCache = new LinkedHashMap<>(cacheSize, 0.75f, true) {
105             /**
106              * {@inheritDoc}
107              */
108             @Override
109             protected boolean removeEldestEntry(final Map.Entry<AbsoluteDate, KinematicTransform> eldest) {
110                 return size() > cacheSize;
111             }
112         };
113 
114         // cache for static transforms
115         this.staticCache = new LinkedHashMap<>(cacheSize, 0.75f, true) {
116             /**
117              * {@inheritDoc}
118              */
119             @Override
120             protected boolean removeEldestEntry(final Map.Entry<AbsoluteDate, StaticTransform> eldest) {
121                 return size() > cacheSize;
122             }
123         };
124 
125     }
126 
127     /** Get origin frame.
128      * @return origin frame
129      */
130     public Frame getOrigin() {
131         return origin;
132     }
133 
134     /** Get destination frame.
135      * @return destination frame
136      */
137     public Frame getDestination() {
138         return destination;
139     }
140 
141     /** Get the nmber of transforms kept in the date-based cache.
142      * @return nmber of transforms kept in the date-based cache
143      */
144     public int getCacheSize() {
145         return cacheSize;
146     }
147 
148     /** Get the {@link Transform} corresponding to specified date.
149      * @param date current date
150      * @return transform at specified date
151      */
152     public Transform getTransform(final AbsoluteDate date) {
153         lock.lock();
154         try {
155             return fullCache.computeIfAbsent(date, fullGenerator);
156         } finally {
157             lock.unlock();
158         }
159     }
160 
161     /** Get the {@link Transform} corresponding to specified date.
162      * @param date current date
163      * @return transform at specified date
164      */
165     public KinematicTransform getKinematicTransform(final AbsoluteDate date) {
166         lock.lock();
167         try {
168             return kinematicCache.computeIfAbsent(date, kinematicGenerator);
169         } finally {
170             lock.unlock();
171         }
172     }
173 
174     /** Get the {@link Transform} corresponding to specified date.
175      * @param date current date
176      * @return transform at specified date
177      */
178     public StaticTransform getStaticTransform(final AbsoluteDate date) {
179         lock.lock();
180         try {
181             return staticCache.computeIfAbsent(date, staticGenerator);
182         } finally {
183             lock.unlock();
184         }
185     }
186 
187 }