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