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 }