ParseInfo.java
/* Copyright 2002-2024 Luc Maisonobe
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.files.sinex;
import org.hipparchus.util.FastMath;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.DateComponents;
import org.orekit.time.TimeScale;
import org.orekit.time.TimeScales;
import org.orekit.utils.Constants;
import org.orekit.utils.units.Unit;
import java.util.regex.Pattern;
/** Transient data used for parsing a SINEX file.
* @param <T> type of the SINEX files
* @author Luc Maisonobe
* @since 13.0
*/
public abstract class ParseInfo<T extends AbstractSinex> {
/** 00:000:00000 epoch. */
private static final String DEFAULT_EPOCH_TWO_DIGITS = "00:000:00000";
/** 0000:000:00000 epoch. */
private static final String DEFAULT_EPOCH_FOUR_DIGITS = "0000:000:00000";
/** Pattern for delimiting regular expressions. */
private static final Pattern SEPARATOR = Pattern.compile(":");
/** Time scales. */
private final TimeScales timeScales;
/** Name of the data source. */
private String name;
/** Current line. */
private String line;
/** Current line number of the navigation message. */
private int lineNumber;
/** SINEX file creation date as extracted for the first line. */
private AbsoluteDate creationDate;
/** SINEX file creation date as extracted for the first line. */
private String creationDateString;
/** Start time of the data used in the Sinex solution. */
private AbsoluteDate startDate;
/** Start time of the data used in the Sinex solution. */
private String startDateString;
/** End time of the data used in the Sinex solution. */
private AbsoluteDate endDate;
/** End time of the data used in the Sinex solution. */
private String endDateString;
/** Time scale. */
private TimeScale timeScale;
/** Simple constructor.
* @param timeScales time scales
*/
protected ParseInfo(final TimeScales timeScales) {
this.timeScales = timeScales;
}
/** Start parsing of a new data source.
* @param newName name of the new data source
*/
void newSource(final String newName) {
// initialize parsing
this.name = newName;
this.line = null;
this.lineNumber = 0;
}
/** Get name of data source.
* @return name of data source
*/
protected String getName() {
return name;
}
/** Set current line.
* @param line current line
*/
void setLine(final String line)
{
this.line = line;
}
/** Get current line.
* @return current line
*/
String getLine() {
return line;
}
/** Increment line number.
*/
void incrementLineNumber() {
++lineNumber;
}
/** Get current line number.
* @return current line number
*/
int getLineNumber() {
return lineNumber;
}
/** Set creation date.
* @param dateString creation date
*/
protected void setCreationDate(final String dateString) {
this.creationDateString = dateString;
this.creationDate = stringEpochToAbsoluteDate(creationDateString, false);
}
/** Get creation date.
* @return creation date
*/
protected AbsoluteDate getCreationDate() {
return creationDate;
}
/** Set start date if earlier than previous setting.
* @param candidateStartDateString candidate start date
*/
protected void setStartDateIfEarlier(final String candidateStartDateString) {
final AbsoluteDate candidateStart = stringEpochToAbsoluteDate(candidateStartDateString, true);
if (startDate == null || candidateStart.isBefore(startDate)) {
// this is either the first setting
// or we are parsing a new data source referring to an earlier date than previous ones
this.startDateString = candidateStartDateString;
this.startDate = candidateStart;
}
}
/** Get start date.
* @return start date
*/
protected AbsoluteDate getStartDate() {
return startDate;
}
/** Set end date if later than previous setting.
* @param candidateEndDateString end date
*/
protected void setEndDateIfLater(final String candidateEndDateString) {
final AbsoluteDate candidateEnd = stringEpochToAbsoluteDate(candidateEndDateString, true);
if (endDate == null || candidateEnd.isAfter(endDate)) {
// this is either the first setting
// or we are parsing a new data source referring to a later date than previous ones
this.endDateString = candidateEndDateString;
this.endDate = candidateEnd;
}
}
/** Get end date.
* @return end date
*/
protected AbsoluteDate getEndDate() {
return endDate;
}
/** Set time scale.
* @param timeScale time scale
*/
protected void setTimeScale(final TimeScale timeScale) {
this.timeScale = timeScale;
// A time scale has been parsed, update start, end, and creation dates
// to take into account the time scale
if (startDateString != null) {
startDate = stringEpochToAbsoluteDate(startDateString, true);
}
if (endDateString != null) {
endDate = stringEpochToAbsoluteDate(endDateString, false);
}
if (creationDateString != null) {
creationDate = stringEpochToAbsoluteDate(creationDateString, false);
}
}
/** Get time scales.
* @return time scales
*/
TimeScales getTimeScales() {
return timeScales;
}
/** Build the parsed file.
* @return built parsed file
*/
protected abstract T build();
/** Extract a string from current line.
* @param start start index of the string
* @param length length of the string
* @return parsed string
*/
protected String parseString(final int start, final int length) {
return line.substring(start, FastMath.min(line.length(), start + length)).trim();
}
/** Extract a double from current line.
* @param start start index of the real
* @param length length of the real
* @return parsed real
*/
protected double parseDouble(final int start, final int length) {
return Double.parseDouble(parseString(start, length));
}
/** Extract an integer from current line.
* @param start start index of the real
* @param length length of the real
* @return parsed integer
*/
protected int parseInt(final int start, final int length) {
return Integer.parseInt(parseString(start, length));
}
/** Extract a double from current line and convert in SI unit.
* @param startUnit start index of the unit
* @param lengthUnit length of the unit
* @param startDouble start index of the real
* @param lengthDouble length of the real
* @return parsed double in SI unit
*/
protected double parseDoubleWithUnit(final int startUnit, final int lengthUnit,
final int startDouble, final int lengthDouble) {
final Unit unit = Unit.parse(parseString(startUnit, lengthUnit));
return unit.toSI(parseDouble(startDouble, lengthDouble));
}
/** Transform a String epoch to an AbsoluteDate.
* @param stringDate string epoch
* @param isStart true if epoch is a start validity epoch
* @return the corresponding AbsoluteDate
*/
protected AbsoluteDate stringEpochToAbsoluteDate(final String stringDate, final boolean isStart) {
// Deal with 00:000:00000 epochs
if (DEFAULT_EPOCH_TWO_DIGITS.equals(stringDate) || DEFAULT_EPOCH_FOUR_DIGITS.equals(stringDate)) {
// If it's a start validity epoch, the file start date shall be used.
// For end validity epoch, future infinity is acceptable.
return isStart ? startDate : AbsoluteDate.FUTURE_INFINITY;
}
// Date components
final String[] fields = SEPARATOR.split(stringDate);
// Read fields
final int digitsYear = Integer.parseInt(fields[0]);
final int day = Integer.parseInt(fields[1]);
final int secInDay = Integer.parseInt(fields[2]);
// Data year
final int year;
if (digitsYear > 50 && digitsYear < 100) {
year = 1900 + digitsYear;
} else if (digitsYear < 100) {
year = 2000 + digitsYear;
} else {
year = digitsYear;
}
// Return an absolute date.
// Initialize to 1st January of the given year because
// sometimes day is equal to 0 in the file.
return new AbsoluteDate(new DateComponents(year, 1, 1), timeScale).
shiftedBy(Constants.JULIAN_DAY * (day - 1)).
shiftedBy(secInDay);
}
}