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.getDate().getYear(), dt.getDate().getMonth(), dt.getDate().getDay(),
255 dt.getTime().getHour(), dt.getTime().getMinute(), dt.getTime().getSecond());
256 }
257
258
259 @Override
260 public String dateToString(final int year, final int month, final int day,
261 final int hour, final int minute, final double seconds) {
262 return formatter.toString(year, month, day, hour, minute, seconds);
263 }
264
265
266 @Override
267 public String unitsListToString(final List<Unit> units) {
268
269 if (units == null || units.isEmpty()) {
270
271 return null;
272 }
273
274 final StringBuilder builder = new StringBuilder();
275 builder.append('[');
276 boolean first = true;
277 for (final Unit unit : units) {
278 if (!first) {
279 builder.append(',');
280 }
281 builder.append(siToCcsdsName(unit.getName()));
282 first = false;
283 }
284 builder.append(']');
285 return builder.toString();
286
287 }
288
289
290 @Override
291 public String siToCcsdsName(final String siName) {
292
293 if (!siToCcsds.containsKey(siName)) {
294
295
296 final StringBuilder builder = new StringBuilder();
297
298
299 final List<PowerTerm> terms = Parser.buildTermsList(siName);
300
301 if (terms == null) {
302 builder.append("n/a");
303 } else {
304
305
306 boolean first = true;
307 for (final PowerTerm term : terms) {
308 if (term.getExponent().getNumerator() >= 0) {
309 if (!first) {
310 builder.append('*');
311 }
312 appendScale(builder, term.getScale());
313 appendBase(builder, term.getBase());
314 appendExponent(builder, term.getExponent());
315 first = false;
316 }
317 }
318
319 if (first) {
320
321 builder.append('1');
322 }
323
324
325 for (final PowerTerm term : terms) {
326 if (term.getExponent().getNumerator() < 0) {
327 builder.append('/');
328 appendScale(builder, term.getScale());
329 appendBase(builder, term.getBase());
330 appendExponent(builder, term.getExponent().negate());
331 }
332 }
333
334 }
335
336
337 siToCcsds.put(siName, builder.toString());
338
339 }
340
341 return siToCcsds.get(siName);
342
343 }
344
345
346
347
348
349 private void appendScale(final StringBuilder builder, final double scale) {
350 final int factor = (int) FastMath.rint(scale);
351 if (FastMath.abs(scale - factor) > 1.0e-12) {
352
353 throw new OrekitInternalError(null);
354 }
355 if (factor != 1) {
356 builder.append(factor);
357 }
358 }
359
360
361
362
363
364 private void appendBase(final StringBuilder builder, final CharSequence base) {
365 if ("°".equals(base) || "◦".equals(base)) {
366 builder.append("deg");
367 } else {
368 builder.append(base);
369 }
370 }
371
372
373
374
375
376 private void appendExponent(final StringBuilder builder, final Fraction exponent) {
377 if (!exponent.equals(Fraction.ONE)) {
378 builder.append("**");
379 if (exponent.equals(Fraction.ONE_HALF)) {
380 builder.append("0.5");
381 } else if (exponent.getNumerator() == 3 && exponent.getDenominator() == 2) {
382 builder.append("1.5");
383 } else {
384 builder.append(exponent);
385 }
386 }
387 }
388
389 }
390