1   /* Copyright 2022-2025 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 org.orekit.time.AbsoluteDate;
20  
21  import java.util.LinkedHashMap;
22  import java.util.Map;
23  import java.util.concurrent.locks.ReentrantLock;
24  import java.util.function.Function;
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<AbsoluteDate, Transform>(cacheSize, 0.75f, true) {
94              /** {@inheritDoc} */
95              @Override
96              protected boolean removeEldestEntry(final Map.Entry<AbsoluteDate, Transform> eldest) {
97                  return size() > cacheSize;
98              }
99          };
100 
101         // cache for kinematic transforms
102         this.kinematicCache = new LinkedHashMap<AbsoluteDate, KinematicTransform>(cacheSize, 0.75f, true) {
103             /** {@inheritDoc} */
104             @Override
105             protected boolean removeEldestEntry(final Map.Entry<AbsoluteDate, KinematicTransform> eldest) {
106                 return size() > cacheSize;
107             }
108         };
109 
110         // cache for static transforms
111         this.staticCache = new LinkedHashMap<AbsoluteDate, StaticTransform>(cacheSize, 0.75f, true) {
112             /** {@inheritDoc} */
113             @Override
114             protected boolean removeEldestEntry(final Map.Entry<AbsoluteDate, StaticTransform> eldest) {
115                 return size() > cacheSize;
116             }
117         };
118 
119     }
120 
121     /** Get origin frame.
122      * @return origin frame
123      */
124     public Frame getOrigin() {
125         return origin;
126     }
127 
128     /** Get destination frame.
129      * @return destination frame
130      */
131     public Frame getDestination() {
132         return destination;
133     }
134 
135     /** Get the nmber of transforms kept in the date-based cache.
136      * @return nmber of transforms kept in the date-based cache
137      */
138     public int getCacheSize() {
139         return cacheSize;
140     }
141 
142     /** Get the {@link Transform} corresponding to specified date.
143      * @param date current date
144      * @return transform at specified date
145      */
146     public Transform getTransform(final AbsoluteDate date) {
147         lock.lock();
148         try {
149             return fullCache.computeIfAbsent(date, fullGenerator);
150         } finally {
151             lock.unlock();
152         }
153     }
154 
155     /** Get the {@link Transform} corresponding to specified date.
156      * @param date current date
157      * @return transform at specified date
158      */
159     public KinematicTransform getKinematicTransform(final AbsoluteDate date) {
160         lock.lock();
161         try {
162             return kinematicCache.computeIfAbsent(date, kinematicGenerator);
163         } finally {
164             lock.unlock();
165         }
166     }
167 
168     /** Get the {@link Transform} corresponding to specified date.
169      * @param date current date
170      * @return transform at specified date
171      */
172     public StaticTransform getStaticTransform(final AbsoluteDate date) {
173         lock.lock();
174         try {
175             return staticCache.computeIfAbsent(date, staticGenerator);
176         } finally {
177             lock.unlock();
178         }
179     }
180 
181 }