1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.files.ccsds.utils.generation;
18
19 import java.io.IOException;
20 import java.util.ArrayDeque;
21 import java.util.Deque;
22 import java.util.HashMap;
23 import java.util.List;
24 import java.util.Map;
25
26 import org.hipparchus.fraction.Fraction;
27 import org.hipparchus.util.FastMath;
28 import org.orekit.errors.OrekitException;
29 import org.orekit.errors.OrekitInternalError;
30 import org.orekit.errors.OrekitMessages;
31 import org.orekit.files.ccsds.definitions.TimeConverter;
32 import org.orekit.time.AbsoluteDate;
33 import org.orekit.time.DateTimeComponents;
34 import org.orekit.utils.AccurateFormatter;
35 import org.orekit.utils.Formatter;
36 import org.orekit.utils.units.Parser;
37 import org.orekit.utils.units.PowerTerm;
38 import org.orekit.utils.units.Unit;
39
40
41
42
43
44 public abstract class AbstractGenerator implements Generator {
45
46
47 private static final char NEW_LINE = '\n';
48
49
50 private final Appendable output;
51
52
53 private final String outputName;
54
55
56
57
58 private final double maxRelativeOffset;
59
60
61 private final boolean writeUnits;
62
63
64 private final Deque<String> sections;
65
66
67 private final Map<String, String> siToCcsds;
68
69
70 private final Formatter formatter;
71
72
73
74
75
76
77
78
79
80 public AbstractGenerator(final Appendable output, final String outputName,
81 final double maxRelativeOffset, final boolean writeUnits,
82 final Formatter formatter) {
83 this.output = output;
84 this.outputName = outputName;
85 this.maxRelativeOffset = maxRelativeOffset;
86 this.writeUnits = writeUnits;
87 this.sections = new ArrayDeque<>();
88 this.siToCcsds = new HashMap<>();
89 this.formatter = formatter;
90 }
91
92
93
94
95
96
97
98
99
100
101 @Deprecated
102 public AbstractGenerator(final Appendable output, final String outputName,
103 final double maxRelativeOffset, final boolean writeUnits) {
104 this(output, outputName, maxRelativeOffset, writeUnits, new AccurateFormatter());
105 }
106
107
108 @Override
109 public String getOutputName() {
110 return outputName;
111 }
112
113
114 @Override
115 public Formatter getFormatter() { return formatter; }
116
117
118
119
120
121 public boolean writeUnits(final Unit unit) {
122 return writeUnits &&
123 unit != null &&
124 !unit.getName().equals(Unit.NONE.getName()) &&
125 !unit.getName().equals(Unit.ONE.getName());
126 }
127
128
129 @Override
130 public void close() throws IOException {
131
132
133 while (!sections.isEmpty()) {
134 exitSection();
135 }
136
137 }
138
139
140 @Override
141 public void newLine() throws IOException {
142 output.append(NEW_LINE);
143 }
144
145
146 @Override
147 public void writeEntry(final String key, final List<String> value, final boolean mandatory) throws IOException {
148 if (value == null || value.isEmpty()) {
149 complain(key, mandatory);
150 } else {
151 final StringBuilder builder = new StringBuilder();
152 boolean first = true;
153 for (final String v : value) {
154 if (!first) {
155 builder.append(',');
156 }
157 builder.append(v);
158 first = false;
159 }
160 writeEntry(key, builder.toString(), null, mandatory);
161 }
162 }
163
164
165 @Override
166 public void writeEntry(final String key, final Enum<?> value, final boolean mandatory) throws IOException {
167 writeEntry(key, value == null ? null : value.name(), null, mandatory);
168 }
169
170
171 @Override
172 public void writeEntry(final String key, final TimeConverter converter, final AbsoluteDate date,
173 final boolean forceCalendar, final boolean mandatory)
174 throws IOException {
175 if (date == null) {
176 writeEntry(key, (String) null, null, mandatory);
177 } else {
178 writeEntry(key,
179 forceCalendar ? dateToCalendarString(converter, date) : dateToString(converter, date),
180 null,
181 mandatory);
182 }
183 }
184
185
186 @Override
187 public void writeEntry(final String key, final double value, final Unit unit, final boolean mandatory) throws IOException {
188 writeEntry(key, doubleToString(unit.fromSI(value)), unit, mandatory);
189 }
190
191
192 @Override
193 public void writeEntry(final String key, final Double value, final Unit unit, final boolean mandatory) throws IOException {
194 writeEntry(key, value == null ? (String) null : doubleToString(unit.fromSI(value.doubleValue())), unit, mandatory);
195 }
196
197
198 @Override
199 public void writeEntry(final String key, final char value, final boolean mandatory) throws IOException {
200 writeEntry(key, Character.toString(value), null, mandatory);
201 }
202
203
204 @Override
205 public void writeEntry(final String key, final int value, final boolean mandatory) throws IOException {
206 writeEntry(key, Integer.toString(value), null, mandatory);
207 }
208
209
210 @Override
211 public void writeRawData(final char data) throws IOException {
212 output.append(data);
213 }
214
215
216 @Override
217 public void writeRawData(final CharSequence data) throws IOException {
218 output.append(data);
219 }
220
221
222 @Override
223 public void enterSection(final String name) throws IOException {
224 sections.offerLast(name);
225 }
226
227
228 @Override
229 public String exitSection() throws IOException {
230 return sections.pollLast();
231 }
232
233
234
235
236
237 protected void complain(final String key, final boolean mandatory) {
238 if (mandatory) {
239 throw new OrekitException(OrekitMessages.CCSDS_MISSING_KEYWORD, key, outputName);
240 }
241 }
242
243
244 @Override
245 public String doubleToString(final double value) {
246 return Double.isNaN(value) ? null : formatter.toString(value);
247 }
248
249
250 @Override
251 public String dateToString(final TimeConverter converter, final AbsoluteDate date) {
252
253 if (converter.getReferenceDate() != null) {
254 final double relative = date.durationFrom(converter.getReferenceDate());
255 if (FastMath.abs(relative) <= maxRelativeOffset) {
256
257 return formatter.toString(relative);
258 }
259 }
260
261
262 return dateToCalendarString(converter, date);
263
264 }
265
266
267 @Override
268 public String dateToCalendarString(final TimeConverter converter, final AbsoluteDate date) {
269 final DateTimeComponents dt = converter.components(date);
270 return dateToString(dt.getDate().getYear(), dt.getDate().getMonth(), dt.getDate().getDay(),
271 dt.getTime().getHour(), dt.getTime().getMinute(), dt.getTime().getSecond());
272 }
273
274
275 @Override
276 public String dateToString(final int year, final int month, final int day,
277 final int hour, final int minute, final double seconds) {
278 return formatter.toString(year, month, day, hour, minute, seconds);
279 }
280
281
282 @Override
283 public String unitsListToString(final List<Unit> units) {
284
285 if (units == null || units.isEmpty()) {
286
287 return null;
288 }
289
290 final StringBuilder builder = new StringBuilder();
291 builder.append('[');
292 boolean first = true;
293 for (final Unit unit : units) {
294 if (!first) {
295 builder.append(',');
296 }
297 builder.append(siToCcsdsName(unit.getName()));
298 first = false;
299 }
300 builder.append(']');
301 return builder.toString();
302
303 }
304
305
306 @Override
307 public String siToCcsdsName(final String siName) {
308
309 if (!siToCcsds.containsKey(siName)) {
310
311
312 final StringBuilder builder = new StringBuilder();
313
314
315 final List<PowerTerm> terms = Parser.buildTermsList(siName);
316
317 if (terms == null) {
318 builder.append("n/a");
319 } else {
320
321
322 boolean first = true;
323 for (final PowerTerm term : terms) {
324 if (term.getExponent().getNumerator() >= 0) {
325 if (!first) {
326 builder.append('*');
327 }
328 appendScale(builder, term.getScale());
329 appendBase(builder, term.getBase());
330 appendExponent(builder, term.getExponent());
331 first = false;
332 }
333 }
334
335 if (first) {
336
337 builder.append('1');
338 }
339
340
341 for (final PowerTerm term : terms) {
342 if (term.getExponent().getNumerator() < 0) {
343 builder.append('/');
344 appendScale(builder, term.getScale());
345 appendBase(builder, term.getBase());
346 appendExponent(builder, term.getExponent().negate());
347 }
348 }
349
350 }
351
352
353 siToCcsds.put(siName, builder.toString());
354
355 }
356
357 return siToCcsds.get(siName);
358
359 }
360
361
362
363
364
365 private void appendScale(final StringBuilder builder, final double scale) {
366 final int factor = (int) FastMath.rint(scale);
367 if (FastMath.abs(scale - factor) > 1.0e-12) {
368
369 throw new OrekitInternalError(null);
370 }
371 if (factor != 1) {
372 builder.append(factor);
373 }
374 }
375
376
377
378
379
380 private void appendBase(final StringBuilder builder, final CharSequence base) {
381 if ("°".equals(base) || "◦".equals(base)) {
382 builder.append("deg");
383 } else {
384 builder.append(base);
385 }
386 }
387
388
389
390
391
392 private void appendExponent(final StringBuilder builder, final Fraction exponent) {
393 if (!exponent.equals(Fraction.ONE)) {
394 builder.append("**");
395 if (exponent.equals(Fraction.ONE_HALF)) {
396 builder.append("0.5");
397 } else if (exponent.getNumerator() == 3 && exponent.getDenominator() == 2) {
398 builder.append("1.5");
399 } else {
400 builder.append(exponent);
401 }
402 }
403 }
404
405 }
406