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