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      /** Returns a copy of the abscissa grid for the interpolation function.
46       * @return the abscissa grid for the interpolation function,
47       *         or <code>null</code> if the file could not be read
48       */
49      public double[] getAbscissaGrid() {
50          return xArr.clone();
51      }
52  
53      /** Returns a copy of the ordinate grid for the interpolation function.
54       * @return the ordinate grid for the interpolation function,
55       *         or <code>null</code> if the file could not be read
56       */
57      public double[] getOrdinateGrid() {
58          return yArr.clone();
59      }
60  
61      /** Returns a copy of the values samples for the interpolation function.
62       * @return the values samples for the interpolation function,
63       *         or <code>null</code> if the file could not be read
64       */
65      public double[][] getValuesSamples() {
66          return fArr.clone();
67      }
68  
69      /** {@inheritDoc} */
70      public boolean stillAcceptsData() {
71          return xArr == null;
72      }
73  
74      /** Loads an bi-variate interpolation table from the given {@link InputStream}.
75       * The format of the table is as follows (number of rows/columns can be extended):
76       * <pre>
77       *  Table: tableName
78       *
79       *      | 0.0 |  60.0 |  66.0
80       *  -------------------------
81       *    0 | 0.0 | 0.003 | 0.006
82       *  500 | 0.0 | 0.003 | 0.006
83       * </pre>
84       * @param input the input stream to read data from
85       * @param name  the name of the input file
86       * @exception IOException if data can't be read
87       * @exception ParseException if data can't be parsed
88       */
89      public void loadData(final InputStream input, final String name)
90          throws IOException, ParseException {
91  
92          final List<Double> xValues = new LinkedList<Double>();
93          final List<Double> yValues = new LinkedList<Double>();
94          final LinkedList<List<Double>> cellValues = new LinkedList<List<Double>>();
95  
96          final StreamTokenizer tokenizer =
97              new StreamTokenizer(new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)));
98  
99          // ignore comments starting with a #
100         tokenizer.commentChar('#');
101         tokenizer.eolIsSignificant(true);
102 
103         int tokenCount = 0;
104         boolean headerRow = false;
105         boolean done = false;
106 
107         do {
108             switch (tokenizer.nextToken()) {
109 
110                 case StreamTokenizer.TT_EOF:
111                     done = true;
112                     break;
113 
114                 case StreamTokenizer.TT_EOL:
115                     // end of header row
116                     if (yValues.size() > 0) {
117                         headerRow = false;
118                     }
119                     tokenCount = 0;
120                     break;
121 
122                 case StreamTokenizer.TT_NUMBER:
123                     if (headerRow) {
124                         yValues.add(tokenizer.nval);
125                     } else {
126                         if (tokenCount == 0) {
127                             xValues.add(tokenizer.nval);
128                             cellValues.add(new LinkedList<Double>());
129                         } else {
130                             cellValues.getLast().add(tokenizer.nval);
131                         }
132                     }
133                     tokenCount++;
134                     break;
135 
136                 case StreamTokenizer.TT_WORD:
137                     // we are in the header row now
138                     if (tokenizer.sval.startsWith("Table")) {
139                         headerRow = true;
140                     }
141                     break;
142 
143                 default:
144                     break;
145             }
146 
147         } while (!done);
148 
149         xArr = toPrimitiveArray(xValues);
150         yArr = toPrimitiveArray(yValues);
151         fArr = new double[cellValues.size()][];
152         int idx = 0;
153 
154         for (List<Double> row : cellValues) {
155             fArr[idx++] = toPrimitiveArray(row);
156         }
157 
158     }
159 
160     /** Converts a list of {@link Double} objects into an array of double primitives.
161      * @param list the list of {@link Double} objects
162      * @return the double array containing the list elements
163      */
164     private double[] toPrimitiveArray(final List<Double> list) {
165         final double[] result = new double[list.size()];
166         int idx = 0;
167         for (Double element : list) {
168             result[idx++] = element;
169         }
170         return result;
171     }
172 }