1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.files.rinex.utils;
18
19 import org.hipparchus.util.FastMath;
20 import org.orekit.errors.OrekitException;
21 import org.orekit.errors.OrekitMessages;
22 import org.orekit.files.rinex.section.CommonLabel;
23 import org.orekit.files.rinex.section.Label;
24 import org.orekit.files.rinex.section.RinexBaseHeader;
25 import org.orekit.files.rinex.section.RinexComment;
26 import org.orekit.time.DateTimeComponents;
27 import org.orekit.utils.formatting.FastDecimalFormatter;
28 import org.orekit.utils.formatting.FastDoubleFormatter;
29 import org.orekit.utils.formatting.FastLongFormatter;
30 import org.orekit.utils.formatting.FastScientificFormatter;
31
32 import java.io.IOException;
33 import java.util.Collections;
34 import java.util.List;
35
36
37
38
39
40
41 public abstract class BaseRinexWriter<T extends RinexBaseHeader> implements AutoCloseable {
42
43
44 public static final FastLongFormatter TWO_DIGITS_INTEGER = new FastLongFormatter(2, false);
45
46
47 public static final FastLongFormatter PADDED_TWO_DIGITS_INTEGER = new FastLongFormatter(2, true);
48
49
50 public static final FastLongFormatter THREE_DIGITS_INTEGER = new FastLongFormatter(3, false);
51
52
53 public static final FastLongFormatter FOUR_DIGITS_INTEGER = new FastLongFormatter(4, false);
54
55
56 public static final FastLongFormatter PADDED_FOUR_DIGITS_INTEGER = new FastLongFormatter(4, true);
57
58
59 public static final FastLongFormatter SIX_DIGITS_INTEGER = new FastLongFormatter(6, false);
60
61
62 public static final FastDoubleFormatter NINE_TWO_DIGITS_FLOAT = new FastDecimalFormatter(9, 2);
63
64
65 public static final FastDoubleFormatter NINETEEN_SCIENTIFIC_FLOAT = new FastScientificFormatter(19);
66
67
68 private final Appendable output;
69
70
71 private final String outputName;
72
73
74 private boolean closed;
75
76
77 private T savedHeader;
78
79
80 private int savedLabelIndex;
81
82
83 private List<RinexComment> savedComments;
84
85
86 private int lineNumber;
87
88
89 private int column;
90
91
92
93
94
95 protected BaseRinexWriter(final Appendable output, final String outputName) {
96 this.output = output;
97 this.outputName = outputName;
98 this.savedComments = Collections.emptyList();
99 this.closed = false;
100 }
101
102
103 @Override
104 public void close() throws IOException {
105 try {
106 if (!closed && output instanceof AutoCloseable closeable) {
107 closeable.close();
108 }
109 closed = true;
110
111 } catch (Exception ex) {
112
113 throw new IOException(ex);
114 }
115 }
116
117
118
119
120 public void prepareComments(final List<RinexComment> comments) {
121 savedComments = comments;
122 }
123
124
125
126
127
128
129 protected void writeHeader(final T header, final int labelIndex) throws IOException {
130
131
132 if (savedHeader != null) {
133 throw new OrekitException(OrekitMessages.HEADER_ALREADY_WRITTEN, outputName);
134 }
135 savedHeader = header;
136 savedLabelIndex = labelIndex;
137 lineNumber = 1;
138
139 }
140
141
142
143
144 protected T getHeader() {
145 return savedHeader;
146 }
147
148
149
150
151 protected int getColumn() {
152 return column;
153 }
154
155
156
157
158
159 protected void finishHeaderLine(final Label label) throws IOException {
160 checkOutputNotClosed();
161 for (int i = column; i < savedLabelIndex; ++i) {
162 output.append(' ');
163 }
164 output.append(label.getLabel());
165 finishLine();
166 }
167
168
169
170
171 public void finishLine() throws IOException {
172
173 checkOutputNotClosed();
174
175
176 output.append(System.lineSeparator());
177 lineNumber++;
178 column = 0;
179
180
181 for (final RinexComment comment : savedComments) {
182 if (comment.getLineNumber() == lineNumber) {
183 outputField(comment.getText(), savedLabelIndex, true);
184 output.append(CommonLabel.COMMENT.getLabel());
185 output.append(System.lineSeparator());
186 lineNumber++;
187 column = 0;
188 } else if (comment.getLineNumber() > lineNumber) {
189 break;
190 }
191 }
192
193 }
194
195
196
197
198
199
200 protected void writeHeaderLine(final String s, final Label label) throws IOException {
201 if (s != null) {
202 outputField(s, s.length(), true);
203 finishHeaderLine(label);
204 }
205 }
206
207
208
209 protected void checkHeaderWritten() {
210 if (savedHeader == null) {
211 throw new OrekitException(OrekitMessages.HEADER_NOT_WRITTEN, outputName);
212 }
213 }
214
215
216
217
218
219 protected boolean exceedsHeaderLength(final int tentative) {
220 return tentative > savedLabelIndex;
221 }
222
223
224
225
226
227 protected void writeProgramRunByDate(final RinexBaseHeader header)
228 throws IOException {
229 outputField(header.getProgramName(), 20, true);
230 outputField(header.getRunByName(), 40, true);
231 final DateTimeComponents dtc = header.getCreationDateComponents();
232 if (header.getFormatVersion() < 3.0 && dtc.getTime().getSecond() < 0.5) {
233 outputField(PADDED_TWO_DIGITS_INTEGER, dtc.getDate().getDay(), 42);
234 outputField('-', 43);
235 outputField(dtc.getDate().getMonthEnum().getUpperCaseAbbreviation(), 46, true);
236 outputField('-', 47);
237 outputField(PADDED_TWO_DIGITS_INTEGER, dtc.getDate().getYear() % 100, 49);
238 outputField(PADDED_TWO_DIGITS_INTEGER, dtc.getTime().getHour(), 52);
239 outputField(':', 53);
240 outputField(PADDED_TWO_DIGITS_INTEGER, dtc.getTime().getMinute(), 55);
241 outputField(header.getCreationTimeZone(), 58, true);
242 } else {
243 outputField(PADDED_FOUR_DIGITS_INTEGER, dtc.getDate().getYear(), 44);
244 outputField(PADDED_TWO_DIGITS_INTEGER, dtc.getDate().getMonth(), 46);
245 outputField(PADDED_TWO_DIGITS_INTEGER, dtc.getDate().getDay(), 48);
246 outputField(PADDED_TWO_DIGITS_INTEGER, dtc.getTime().getHour(), 51);
247 outputField(PADDED_TWO_DIGITS_INTEGER, dtc.getTime().getMinute(), 53);
248 outputField(PADDED_TWO_DIGITS_INTEGER, (int) FastMath.rint(dtc.getTime().getSecond()), 55);
249 outputField(header.getCreationTimeZone(), 59, false);
250 }
251 finishHeaderLine(CommonLabel.PROGRAM);
252 }
253
254
255
256
257
258
259 public void outputField(final char c, final int next) throws IOException {
260 outputField(Character.toString(c), next, false);
261 }
262
263
264
265
266
267
268
269 public void outputField(final FastLongFormatter formatter, final int value, final int next) throws IOException {
270 outputField(formatter.toString(value), next, false);
271 }
272
273
274
275
276
277
278
279 public void outputField(final FastLongFormatter formatter, final long value, final int next) throws IOException {
280 outputField(formatter.toString(value), next, false);
281 }
282
283
284
285
286
287
288
289 public void outputField(final FastDoubleFormatter formatter, final double value, final int next) throws IOException {
290 if (Double.isNaN(value)) {
291
292 outputField("", next, true);
293 } else {
294 outputField(formatter.toString(value), next, false);
295 }
296 }
297
298
299
300
301
302
303
304 public void outputField(final String field, final int next, final boolean leftJustified) throws IOException {
305 final int padding = next - (field == null ? 0 : field.length()) - column;
306 if (padding < 0) {
307 throw new OrekitException(OrekitMessages.FIELD_TOO_LONG, field, next - column);
308 }
309 checkOutputNotClosed();
310 if (leftJustified && field != null) {
311 output.append(field);
312 }
313 for (int i = 0; i < padding; ++i) {
314 output.append(' ');
315 }
316 if (!leftJustified && field != null) {
317 output.append(field);
318 }
319 column = next;
320 }
321
322
323
324 private void checkOutputNotClosed() {
325 if (closed) {
326 throw new OrekitException(OrekitMessages.OUTPUT_ALREADY_CLOSED, outputName);
327 }
328 }
329
330 }