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