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 }