1 /* Copyright 2011-2012 Space Applications Services
2 * Licensed to CS Communication & Systèmes (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.utils;
18
19 import java.io.BufferedReader;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.InputStreamReader;
23 import java.io.StreamTokenizer;
24 import java.nio.charset.StandardCharsets;
25 import java.text.ParseException;
26 import java.util.LinkedList;
27 import java.util.List;
28
29 import org.orekit.data.DataLoader;
30
31 /** Used to read an interpolation table from a data file.
32 * @author Thomas Neidhart
33 */
34 public class InterpolationTableLoader implements DataLoader {
35
36 /** Abscissa grid for the bi-variate interpolation function read from the file. */
37 private double[] xArr;
38
39 /** Ordinate grid for the bi-variate interpolation function read from the file. */
40 private double[] yArr;
41
42 /** Values samples for the bi-variate interpolation function read from the file. */
43 private double[][] fArr;
44
45 /** Empty constructor.
46 * <p>
47 * This constructor is not strictly necessary, but it prevents spurious
48 * javadoc warnings with JDK 18 and later.
49 * </p>
50 * @since 12.0
51 */
52 public InterpolationTableLoader() {
53 // nothing to do
54 }
55
56 /** Returns a copy of the abscissa grid for the interpolation function.
57 * @return the abscissa grid for the interpolation function,
58 * or <code>null</code> if the file could not be read
59 */
60 public double[] getAbscissaGrid() {
61 return xArr.clone();
62 }
63
64 /** Returns a copy of the ordinate grid for the interpolation function.
65 * @return the ordinate grid for the interpolation function,
66 * or <code>null</code> if the file could not be read
67 */
68 public double[] getOrdinateGrid() {
69 return yArr.clone();
70 }
71
72 /** Returns a copy of the values samples for the interpolation function.
73 * @return the values samples for the interpolation function,
74 * or <code>null</code> if the file could not be read
75 */
76 public double[][] getValuesSamples() {
77 return fArr.clone();
78 }
79
80 /** {@inheritDoc} */
81 public boolean stillAcceptsData() {
82 return xArr == null;
83 }
84
85 /** Loads an bi-variate interpolation table from the given {@link InputStream}.
86 * The format of the table is as follows (number of rows/columns can be extended):
87 * <pre>
88 * Table: tableName
89 *
90 * | 0.0 | 60.0 | 66.0
91 * -------------------------
92 * 0 | 0.0 | 0.003 | 0.006
93 * 500 | 0.0 | 0.003 | 0.006
94 * </pre>
95 * @param input the input stream to read data from
96 * @param name the name of the input file
97 * @exception IOException if data can't be read
98 * @exception ParseException if data can't be parsed
99 */
100 public void loadData(final InputStream input, final String name)
101 throws IOException, ParseException {
102
103 final List<Double> xValues = new LinkedList<>();
104 final List<Double> yValues = new LinkedList<>();
105 final LinkedList<List<Double>> cellValues = new LinkedList<>();
106
107 final StreamTokenizer tokenizer =
108 new StreamTokenizer(new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)));
109
110 // ignore comments starting with a #
111 tokenizer.commentChar('#');
112 tokenizer.eolIsSignificant(true);
113
114 int tokenCount = 0;
115 boolean headerRow = false;
116 boolean done = false;
117
118 do {
119 switch (tokenizer.nextToken()) {
120
121 case StreamTokenizer.TT_EOF:
122 done = true;
123 break;
124
125 case StreamTokenizer.TT_EOL:
126 // end of header row
127 if (yValues.size() > 0) {
128 headerRow = false;
129 }
130 tokenCount = 0;
131 break;
132
133 case StreamTokenizer.TT_NUMBER:
134 if (headerRow) {
135 yValues.add(tokenizer.nval);
136 } else {
137 if (tokenCount == 0) {
138 xValues.add(tokenizer.nval);
139 cellValues.add(new LinkedList<>());
140 } else {
141 cellValues.getLast().add(tokenizer.nval);
142 }
143 }
144 tokenCount++;
145 break;
146
147 case StreamTokenizer.TT_WORD:
148 // we are in the header row now
149 if (tokenizer.sval.startsWith("Table")) {
150 headerRow = true;
151 }
152 break;
153
154 default:
155 break;
156 }
157
158 } while (!done);
159
160 xArr = toPrimitiveArray(xValues);
161 yArr = toPrimitiveArray(yValues);
162 fArr = new double[cellValues.size()][];
163 int idx = 0;
164
165 for (List<Double> row : cellValues) {
166 fArr[idx++] = toPrimitiveArray(row);
167 }
168
169 }
170
171 /** Converts a list of {@link Double} objects into an array of double primitives.
172 * @param list the list of {@link Double} objects
173 * @return the double array containing the list elements
174 */
175 private double[] toPrimitiveArray(final List<Double> list) {
176 final double[] result = new double[list.size()];
177 int idx = 0;
178 for (Double element : list) {
179 result[idx++] = element;
180 }
181 return result;
182 }
183 }