mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-21 13:15:35 +00:00
bug6076: add .vak file extension, convert forestay load to tons
This commit is contained in:
+5
@@ -8,7 +8,12 @@ import com.sap.sse.common.Timed;
|
|||||||
* not throw an exception.
|
* not throw an exception.
|
||||||
*/
|
*/
|
||||||
public interface DoubleVectorFix extends Timed {
|
public interface DoubleVectorFix extends Timed {
|
||||||
|
/**
|
||||||
|
* Obtains a copy of the array of {@link Double} values in this fix. Changes to the array returned
|
||||||
|
* do <em>not</em> modify this fix.
|
||||||
|
*/
|
||||||
Double[] get();
|
Double[] get();
|
||||||
|
|
||||||
Double get(int index);
|
Double get(int index);
|
||||||
/**
|
/**
|
||||||
* Tells whether at least one component is not {@code null}
|
* Tells whether at least one component is not {@code null}
|
||||||
|
|||||||
+49
-44
@@ -44,56 +44,61 @@ public class ExpeditionGPSFixImporter implements GPSFixImporter {
|
|||||||
TrackFileImportDeviceIdentifier device = new TrackFileImportDeviceIdentifierImpl(sourceName, getType() + "@" + new Date());
|
TrackFileImportDeviceIdentifier device = new TrackFileImportDeviceIdentifierImpl(sourceName, getType() + "@" + new Date());
|
||||||
final AtomicBoolean importedFixes = new AtomicBoolean(false);
|
final AtomicBoolean importedFixes = new AtomicBoolean(false);
|
||||||
CompressedStreamsUtil.handlePotentiallyCompressedFiles(sourceName, inputStream,
|
CompressedStreamsUtil.handlePotentiallyCompressedFiles(sourceName, inputStream,
|
||||||
charset, new ExpeditionImportFileHandler() {
|
charset, getExpeditionImportFileHandler(callback, device, importedFixes));
|
||||||
@Override
|
return importedFixes.get();
|
||||||
protected void handleExpeditionFile(String fileName, InputStream stream, Charset charset) throws IOException {
|
}
|
||||||
final BufferedReader br = new BufferedReader(new InputStreamReader(stream, charset));
|
|
||||||
final String headerLine = br.readLine();
|
protected ExpeditionImportFileHandler getExpeditionImportFileHandler(Callback callback,
|
||||||
final ExpeditionExtendedDataImporterImpl importer = new ExpeditionExtendedDataImporterImpl();
|
TrackFileImportDeviceIdentifier device, final AtomicBoolean importedFixes) {
|
||||||
final Map<String, Integer> columnDefinitions = importer.parseHeader(headerLine);
|
return new ExpeditionImportFileHandler() {
|
||||||
final AtomicInteger lineNr = new AtomicInteger(0);
|
@Override
|
||||||
br.lines().forEach(line -> {
|
protected void handleExpeditionFile(String fileName, InputStream stream, Charset charset) throws IOException {
|
||||||
if (!line.trim().isEmpty()) {
|
final BufferedReader br = new BufferedReader(new InputStreamReader(stream, charset));
|
||||||
importer.parseLine(lineNr.incrementAndGet(), fileName, line,
|
final String headerLine = br.readLine();
|
||||||
columnDefinitions, (timePoint, columnValues, columns) -> {
|
final ExpeditionExtendedDataImporterImpl importer = new ExpeditionExtendedDataImporterImpl();
|
||||||
final double latDeg = Double
|
final Map<String, Integer> columnDefinitions = importer.parseHeader(headerLine);
|
||||||
.parseDouble(columnValues[columns.get(LAT_COLUMN_HEADING)]);
|
final AtomicInteger lineNr = new AtomicInteger(0);
|
||||||
final double lonDeg = Double
|
br.lines().forEach(line -> {
|
||||||
.parseDouble(columnValues[columns.get(LON_COLUMN_HEADING)]);
|
if (!line.trim().isEmpty()) {
|
||||||
final double cogDeg = Double
|
importer.parseLine(lineNr.incrementAndGet(), fileName, line,
|
||||||
.parseDouble(columnValues[columns.get(COG_COLUMN_HEADING)]);
|
columnDefinitions, (timePoint, columnValues, columns) -> {
|
||||||
final double sogKnots = Double
|
final double latDeg = Double
|
||||||
.parseDouble(columnValues[columns.get(SOG_COLUMN_HEADING)]);
|
.parseDouble(columnValues[columns.get(LAT_COLUMN_HEADING)]);
|
||||||
final DegreePosition position = new DegreePosition(latDeg, lonDeg);
|
final double lonDeg = Double
|
||||||
Bearing optionalTrueHeading;
|
.parseDouble(columnValues[columns.get(LON_COLUMN_HEADING)]);
|
||||||
if (columns.containsKey(HDT_COLUMN_HEADING)) {
|
final double cogDeg = Double
|
||||||
try {
|
.parseDouble(columnValues[columns.get(COG_COLUMN_HEADING)]);
|
||||||
optionalTrueHeading = new DegreeBearingImpl(Double.parseDouble(columnValues[columns.get(HDT_COLUMN_HEADING)]))
|
final double sogKnots = Double
|
||||||
.add(DeclinationService.INSTANCE.getDeclination(timePoint, position, /* timeout ms */ 1000).getBearingCorrectedTo(timePoint));
|
.parseDouble(columnValues[columns.get(SOG_COLUMN_HEADING)]);
|
||||||
} catch (NumberFormatException | IOException | ParseException e) {
|
final DegreePosition position = new DegreePosition(latDeg, lonDeg);
|
||||||
logger.log(Level.WARNING, "Problem obtaining declination for Expedition fix heading", e);
|
Bearing optionalTrueHeading;
|
||||||
optionalTrueHeading = null;
|
if (columns.containsKey(HDT_COLUMN_HEADING)) {
|
||||||
}
|
try {
|
||||||
} else {
|
optionalTrueHeading = new DegreeBearingImpl(Double.parseDouble(columnValues[columns.get(HDT_COLUMN_HEADING)]))
|
||||||
optionalTrueHeading = null;
|
.add(DeclinationService.INSTANCE.getDeclination(timePoint, position, /* timeout ms */ 1000).getBearingCorrectedTo(timePoint));
|
||||||
}
|
} catch (NumberFormatException | IOException | ParseException e) {
|
||||||
final GPSFixMoving fix = new GPSFixMovingImpl(
|
logger.log(Level.WARNING, "Problem obtaining declination for Expedition fix heading", e);
|
||||||
position, timePoint,
|
optionalTrueHeading = null;
|
||||||
new KnotSpeedWithBearingImpl(sogKnots,
|
}
|
||||||
new DegreeBearingImpl(cogDeg)), optionalTrueHeading);
|
} else {
|
||||||
callback.addFix(fix, device);
|
optionalTrueHeading = null;
|
||||||
importedFixes.set(true);
|
}
|
||||||
});
|
final GPSFixMoving fix = new GPSFixMovingImpl(
|
||||||
}
|
position, timePoint,
|
||||||
});
|
new KnotSpeedWithBearingImpl(sogKnots,
|
||||||
|
new DegreeBearingImpl(cogDeg)), optionalTrueHeading);
|
||||||
|
callback.addFix(fix, device);
|
||||||
|
importedFixes.set(true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return importedFixes.get();
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterable<String> getSupportedFileExtensions() {
|
public Iterable<String> getSupportedFileExtensions() {
|
||||||
return ExpeditionImportFileHandler.supportedExpeditionLogFileExtensions;
|
return getExpeditionImportFileHandler(null, null, null).getSupportedFileExtensions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+1
-1
@@ -70,7 +70,7 @@ public class TestReadingVakarosFiles {
|
|||||||
Math.abs(sensorFix.get(BravoExtendedSensorDataMetadata.HEEL.getColumnIndex()) - -1.7) < EPSILON &&
|
Math.abs(sensorFix.get(BravoExtendedSensorDataMetadata.HEEL.getColumnIndex()) - -1.7) < EPSILON &&
|
||||||
Math.abs(sensorFix.get(BravoExtendedSensorDataMetadata.PITCH.getColumnIndex()) - 4.6) < EPSILON &&
|
Math.abs(sensorFix.get(BravoExtendedSensorDataMetadata.PITCH.getColumnIndex()) - 4.6) < EPSILON &&
|
||||||
Math.abs(sensorFix.get(BravoExtendedSensorDataMetadata.EXPEDITION_KICKER_TENSION.getColumnIndex()) - 1.4) < EPSILON &&
|
Math.abs(sensorFix.get(BravoExtendedSensorDataMetadata.EXPEDITION_KICKER_TENSION.getColumnIndex()) - 1.4) < EPSILON &&
|
||||||
Math.abs(sensorFix.get(BravoExtendedSensorDataMetadata.FORESTAY_LOAD.getColumnIndex()) - 141.2) < EPSILON) {
|
Math.abs(sensorFix.get(BravoExtendedSensorDataMetadata.FORESTAY_LOAD.getColumnIndex()) - 0.1412) < EPSILON) {
|
||||||
foundSensorFix = true;
|
foundSensorFix = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
+44
-1
@@ -1,17 +1,26 @@
|
|||||||
package com.sap.sailing.domain.vakarosadapter;
|
package com.sap.sailing.domain.vakarosadapter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import com.sap.sailing.domain.common.sensordata.ExpeditionExtendedSensorDataMetadata;
|
import com.sap.sailing.domain.common.sensordata.ExpeditionExtendedSensorDataMetadata;
|
||||||
|
import com.sap.sailing.domain.common.tracking.DoubleVectorFix;
|
||||||
|
import com.sap.sailing.domain.common.tracking.impl.DoubleVectorFixImpl;
|
||||||
|
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
|
||||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifierImpl;
|
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifierImpl;
|
||||||
import com.sap.sailing.domain.trackimport.FormatNotSupportedException;
|
import com.sap.sailing.domain.trackimport.FormatNotSupportedException;
|
||||||
import com.sap.sailing.server.trackfiles.impl.ExpeditionExtendedDataImporterImpl;
|
import com.sap.sailing.server.trackfiles.impl.ExpeditionExtendedDataImporterImpl;
|
||||||
|
import com.sap.sailing.server.trackfiles.impl.ExpeditionImportFileHandler;
|
||||||
import com.sap.sse.common.TimePoint;
|
import com.sap.sse.common.TimePoint;
|
||||||
import com.sap.sse.common.Util;
|
import com.sap.sse.common.Util;
|
||||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||||
@@ -24,10 +33,44 @@ public class VakarosExtendedDataImporterImpl extends ExpeditionExtendedDataImpor
|
|||||||
private static final String HEEL_COLUMN_HEADING = "roll";
|
private static final String HEEL_COLUMN_HEADING = "roll";
|
||||||
private static final String PITCH_COLUMN_HEADING = "pitch";
|
private static final String PITCH_COLUMN_HEADING = "pitch";
|
||||||
private static final String LOAD_GDF1_COLUMN_HEADING = "load_gdf1";
|
private static final String LOAD_GDF1_COLUMN_HEADING = "load_gdf1";
|
||||||
|
private static final double LOAD_GDF1_CONVERSION_FACTOR_TO_FORESTAY_LOAD_IN_TONS = 1./1000.;
|
||||||
private static final String LOAD_GDF2_COLUMN_HEADING = "load_gdf2";
|
private static final String LOAD_GDF2_COLUMN_HEADING = "load_gdf2";
|
||||||
|
|
||||||
public VakarosExtendedDataImporterImpl() {
|
public VakarosExtendedDataImporterImpl() {
|
||||||
super(VAKAROS_EXTENDED); // FIXME the ExpeditionImportFileHandler has a hard-coded set of file name extensions; we want our own!
|
super(VAKAROS_EXTENDED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The file handler returned by this method uses a special {@link Callback} implementation that inspects the
|
||||||
|
* {@link DoubleVectorFix} parsed from the stream, and if it finds a value for {@link #LOAD_GDF1_COLUMN_HEADING}, it
|
||||||
|
* applies the conversion factor {@link #LOAD_GDF1_CONVERSION_FACTOR_TO_FORESTAY_LOAD_IN_TONS} to this metric before
|
||||||
|
* passing the fix on to the actual {@code callback}.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected ExpeditionImportFileHandler getFileHandler(TrackFileImportDeviceIdentifier trackIdentifier, AtomicBoolean importedFixes, Callback callback) {
|
||||||
|
final Map<String, Integer> columnNamesToIndexInDoubleFix = getColumnNamesToIndexInDoubleFix();
|
||||||
|
return new ExpeditionImportFileHandler(Arrays.asList("vak", "csv", "log", "txt")) {
|
||||||
|
@Override
|
||||||
|
protected void handleExpeditionFile(String fileName, InputStream inputStream, Charset charset) throws IOException, FormatNotSupportedException {
|
||||||
|
final Callback unitConvertingCallback = new Callback() {
|
||||||
|
@Override
|
||||||
|
public void addFixes(Iterable<DoubleVectorFix> fixes, TrackFileImportDeviceIdentifier device) {
|
||||||
|
callback.addFixes(Util.map(fixes, fix->{
|
||||||
|
final DoubleVectorFix newFix;
|
||||||
|
if (fix.get(columnNamesToIndexInDoubleFix.get(LOAD_GDF1_COLUMN_HEADING)) != null) {
|
||||||
|
final Double[] values = fix.get();
|
||||||
|
values[columnNamesToIndexInDoubleFix.get(LOAD_GDF1_COLUMN_HEADING)] = values[columnNamesToIndexInDoubleFix.get(LOAD_GDF1_COLUMN_HEADING)] * LOAD_GDF1_CONVERSION_FACTOR_TO_FORESTAY_LOAD_IN_TONS;
|
||||||
|
newFix = new DoubleVectorFixImpl(fix.getTimePoint(), values);
|
||||||
|
} else {
|
||||||
|
newFix = fix; // LOAD_GDF1 was not set, so no conversion necessary, use fix as-is
|
||||||
|
}
|
||||||
|
return newFix;
|
||||||
|
}), device);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
VakarosExtendedDataImporterImpl.this.handleExpeditionFile(fileName, inputStream, charset, trackIdentifier, importedFixes, unitConvertingCallback);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+1
-1
@@ -49,7 +49,7 @@ public class VakarosGPSFixImporter implements GPSFixImporter {
|
|||||||
final TrackFileImportDeviceIdentifier gpsDevice = new TrackFileImportDeviceIdentifierImpl(sourceName, getType() + "@" + new Date());
|
final TrackFileImportDeviceIdentifier gpsDevice = new TrackFileImportDeviceIdentifierImpl(sourceName, getType() + "@" + new Date());
|
||||||
final AtomicBoolean importedFixes = new AtomicBoolean(false);
|
final AtomicBoolean importedFixes = new AtomicBoolean(false);
|
||||||
CompressedStreamsUtil.handlePotentiallyCompressedFiles(sourceName, inputStream,
|
CompressedStreamsUtil.handlePotentiallyCompressedFiles(sourceName, inputStream,
|
||||||
charset, new ExpeditionImportFileHandler() {
|
charset, new ExpeditionImportFileHandler(Arrays.asList("vak", "csv", "log", "txt")) {
|
||||||
@Override
|
@Override
|
||||||
protected void handleExpeditionFile(String fileName, InputStream stream, Charset charset) throws IOException {
|
protected void handleExpeditionFile(String fileName, InputStream stream, Charset charset) throws IOException {
|
||||||
final BufferedReader br = new BufferedReader(new InputStreamReader(stream, charset));
|
final BufferedReader br = new BufferedReader(new InputStreamReader(stream, charset));
|
||||||
|
|||||||
+5
@@ -5,6 +5,11 @@
|
|||||||
<div id="mainContent">
|
<div id="mainContent">
|
||||||
<h4 class="articleHeadline">What's New - SAP Sailing Analytics</h4>
|
<h4 class="articleHeadline">What's New - SAP Sailing Analytics</h4>
|
||||||
<div class="innerContent">
|
<div class="innerContent">
|
||||||
|
<h5 class="articleSubheadline">February 2025</h5>
|
||||||
|
<ul class="bulletList">
|
||||||
|
<li>There are new importers for the Vakaros CSV file format. See details in the
|
||||||
|
<a href="/release_notes_admin.html">administrative release notes</a>.</li>
|
||||||
|
</ul>
|
||||||
<h5 class="articleSubheadline">January 2025</h5>
|
<h5 class="articleSubheadline">January 2025</h5>
|
||||||
<ul class="bulletList">
|
<ul class="bulletList">
|
||||||
<li>Export of Polar data as CSV has been fixed now in Data Mining.</li>
|
<li>Export of Polar data as CSV has been fixed now in Data Mining.</li>
|
||||||
|
|||||||
+15
-1
@@ -1,8 +1,15 @@
|
|||||||
package com.sap.sailing.server.gateway.trackfiles.impl;
|
package com.sap.sailing.server.gateway.trackfiles.impl;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.sap.sailing.domain.trackimport.FormatNotSupportedException;
|
||||||
|
import com.sap.sailing.server.trackfiles.impl.ExpeditionImportFileHandler;
|
||||||
|
|
||||||
public class ExpeditionImportFilenameUtilsTest {
|
public class ExpeditionImportFilenameUtilsTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -69,7 +76,14 @@ public class ExpeditionImportFilenameUtilsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void testCase(String actualFilename, String expectedResult) {
|
private void testCase(String actualFilename, String expectedResult) {
|
||||||
Assert.assertEquals(expectedResult, ExpeditionImportFilenameUtils.truncateFilenameExtentions(actualFilename));
|
Assert.assertEquals(expectedResult, ExpeditionImportFilenameUtils.truncateFilenameExtentions(actualFilename, new ExpeditionImportFileHandler() {
|
||||||
|
@Override
|
||||||
|
protected void handleExpeditionFile(String fileName, InputStream inputStream, Charset charset)
|
||||||
|
throws IOException, FormatNotSupportedException {
|
||||||
|
// used only to resolve the file name extensions
|
||||||
|
}
|
||||||
|
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-1
@@ -96,6 +96,7 @@ import com.sap.sailing.server.operationaltransformation.CreateLeaderboardGroup;
|
|||||||
import com.sap.sailing.server.operationaltransformation.CreateRegattaLeaderboard;
|
import com.sap.sailing.server.operationaltransformation.CreateRegattaLeaderboard;
|
||||||
import com.sap.sailing.server.operationaltransformation.UpdateEvent;
|
import com.sap.sailing.server.operationaltransformation.UpdateEvent;
|
||||||
import com.sap.sailing.server.security.PermissionAwareRaceTrackingHandler;
|
import com.sap.sailing.server.security.PermissionAwareRaceTrackingHandler;
|
||||||
|
import com.sap.sailing.server.trackfiles.impl.ExpeditionImportFileHandler;
|
||||||
import com.sap.sailing.server.util.WaitForTrackedRaceUtil;
|
import com.sap.sailing.server.util.WaitForTrackedRaceUtil;
|
||||||
import com.sap.sse.common.Distance;
|
import com.sap.sse.common.Distance;
|
||||||
import com.sap.sse.common.Duration;
|
import com.sap.sse.common.Duration;
|
||||||
@@ -291,7 +292,11 @@ public class ExpeditionAllInOneImporter {
|
|||||||
securityService.checkCurrentUserServerPermission(ServerActions.CREATE_OBJECT);
|
securityService.checkCurrentUserServerPermission(ServerActions.CREATE_OBJECT);
|
||||||
final List<ErrorImportDTO> errors = new ArrayList<>();
|
final List<ErrorImportDTO> errors = new ArrayList<>();
|
||||||
final String importTimeString = DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now(ZoneOffset.UTC));
|
final String importTimeString = DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now(ZoneOffset.UTC));
|
||||||
final String filename = ExpeditionImportFilenameUtils.truncateFilenameExtentions(filenameWithSuffix);
|
final String filename = ExpeditionImportFilenameUtils.truncateFilenameExtentions(filenameWithSuffix, new ExpeditionImportFileHandler() {
|
||||||
|
@Override // used only to resolve the standard file name extensions defined by the Expedition import file handler
|
||||||
|
protected void handleExpeditionFile(String fileName, InputStream inputStream, Charset charset)
|
||||||
|
throws IOException, FormatNotSupportedException {
|
||||||
|
}});
|
||||||
final String filenameWithDateTimeSuffix = filename + "_" + importTimeString;
|
final String filenameWithDateTimeSuffix = filename + "_" + importTimeString;
|
||||||
final String trackedRaceName = filenameWithDateTimeSuffix;
|
final String trackedRaceName = filenameWithDateTimeSuffix;
|
||||||
final String windSourceId = filenameWithDateTimeSuffix;
|
final String windSourceId = filenameWithDateTimeSuffix;
|
||||||
|
|||||||
+6
-4
@@ -1,13 +1,15 @@
|
|||||||
package com.sap.sailing.server.gateway.trackfiles.impl;
|
package com.sap.sailing.server.gateway.trackfiles.impl;
|
||||||
|
|
||||||
import static com.sap.sailing.server.trackfiles.impl.ExpeditionImportFileHandler.supportedExpeditionArchiveFileExtensions;
|
import java.util.Arrays;
|
||||||
import static com.sap.sailing.server.trackfiles.impl.ExpeditionImportFileHandler.supportedExpeditionLogFileExtensions;
|
|
||||||
|
import com.sap.sailing.server.trackfiles.impl.ExpeditionImportFileHandler;
|
||||||
|
|
||||||
class ExpeditionImportFilenameUtils {
|
class ExpeditionImportFilenameUtils {
|
||||||
|
private static final Iterable<String> supportedExpeditionArchiveFileExtensions = Arrays.asList("gz", "zip");
|
||||||
|
|
||||||
static String truncateFilenameExtentions(String filenameWithExtensions) {
|
static String truncateFilenameExtentions(String filenameWithExtensions, ExpeditionImportFileHandler fileHandler) {
|
||||||
return removeTailIfExists(removeTailIfExists(filenameWithExtensions, supportedExpeditionArchiveFileExtensions),
|
return removeTailIfExists(removeTailIfExists(filenameWithExtensions, supportedExpeditionArchiveFileExtensions),
|
||||||
supportedExpeditionLogFileExtensions);
|
fileHandler.getSupportedFileExtensions());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String removeTailIfExists(String source, Iterable<String> extensionsToRemove) {
|
private static String removeTailIfExists(String source, Iterable<String> extensionsToRemove) {
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@ public class GPSFixImporterRegistration {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers the <code>importer</code> as an OSGi service for the {@link GPSFixImporter} interface, once for each
|
* Registers the <code>importer</code> as an OSGi service for the {@link GPSFixImporter} interface, once for each
|
||||||
* {@link GPSFixImporter#getSupportedFileExtensions() supported file extension} , using its
|
* {@link GPSFixImporter#getSupportedFileExtensions() supported file extension}, using its
|
||||||
* {@link GPSFixImporter#getType() type} as the {@link TypeBasedServiceFinder#TYPE} property and the
|
* {@link GPSFixImporter#getType() type} as the {@link TypeBasedServiceFinder#TYPE} property and the
|
||||||
* file extension as the {@link GPSFixImporter#FILE_EXTENSION_PROPERTY} property.
|
* file extension as the {@link GPSFixImporter#FILE_EXTENSION_PROPERTY} property.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+40
-32
@@ -106,42 +106,50 @@ public class ExpeditionExtendedDataImporterImpl extends AbstractDoubleVectorFixI
|
|||||||
String sourceName, boolean downsample) throws FormatNotSupportedException, IOException {
|
String sourceName, boolean downsample) throws FormatNotSupportedException, IOException {
|
||||||
final TrackFileImportDeviceIdentifier trackIdentifier = getTrackIdentifier(filename, sourceName);
|
final TrackFileImportDeviceIdentifier trackIdentifier = getTrackIdentifier(filename, sourceName);
|
||||||
final AtomicBoolean importedFixes = new AtomicBoolean(false);
|
final AtomicBoolean importedFixes = new AtomicBoolean(false);
|
||||||
CompressedStreamsUtil.handlePotentiallyCompressedFiles(filename, inputStream, charset, new ExpeditionImportFileHandler() {
|
CompressedStreamsUtil.handlePotentiallyCompressedFiles(filename, inputStream, charset, getFileHandler(trackIdentifier, importedFixes, callback));
|
||||||
|
return importedFixes.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ExpeditionImportFileHandler getFileHandler(TrackFileImportDeviceIdentifier trackIdentifier, AtomicBoolean importedFixes, Callback callback) {
|
||||||
|
return new ExpeditionImportFileHandler() {
|
||||||
@Override
|
@Override
|
||||||
protected void handleExpeditionFile(String fileName, InputStream inputStream, Charset charset) throws IOException, FormatNotSupportedException {
|
protected void handleExpeditionFile(String fileName, InputStream inputStream, Charset charset) throws IOException, FormatNotSupportedException {
|
||||||
logger.fine("Start parsing Expedition file");
|
ExpeditionExtendedDataImporterImpl.this.handleExpeditionFile(fileName, inputStream, charset, trackIdentifier, importedFixes, callback);
|
||||||
final AtomicLong lineNr = new AtomicLong();
|
}
|
||||||
final BufferedReader buffer = new BufferedReader(new InputStreamReader(inputStream));
|
};
|
||||||
String headerLine = buffer.readLine();
|
}
|
||||||
lineNr.incrementAndGet();
|
|
||||||
logger.fine("Validate and parse header columns");
|
protected void handleExpeditionFile(String fileName, InputStream inputStream, Charset charset, TrackFileImportDeviceIdentifier trackIdentifier, AtomicBoolean importedFixes, Callback callback) throws IOException, FormatNotSupportedException {
|
||||||
final Map<String, Integer> colIndices = parseHeader(headerLine);
|
logger.fine("Start parsing Expedition file");
|
||||||
validateHeader(colIndices);
|
final AtomicLong lineNr = new AtomicLong();
|
||||||
buffer.lines().forEach(line -> {
|
final BufferedReader buffer = new BufferedReader(new InputStreamReader(inputStream));
|
||||||
lineNr.incrementAndGet();
|
String headerLine = buffer.readLine();
|
||||||
if (!line.trim().isEmpty()) {
|
lineNr.incrementAndGet();
|
||||||
parseLine(lineNr.get(), filename, line, colIndices,
|
logger.fine("Validate and parse header columns");
|
||||||
(timePoint, lineContentTokens, columnsInFileFromHeader) -> {
|
final Map<String, Integer> colIndices = parseHeader(headerLine);
|
||||||
final Double[] trackFixData = new Double[trackColumnCount];
|
validateHeader(colIndices);
|
||||||
for (final Entry<String, Integer> columnFromFile : columnsInFileFromHeader.entrySet()) {
|
buffer.lines().forEach(line -> {
|
||||||
final Integer indexInDoubleVectorFix = columnNamesInFileAndTheirValueIndexInResultingDoubleVectorFix.get(columnFromFile.getKey());
|
lineNr.incrementAndGet();
|
||||||
if (indexInDoubleVectorFix != null) {
|
if (!line.trim().isEmpty()) {
|
||||||
final Double value = columnFromFile.getValue() >= lineContentTokens.length ? null
|
parseLine(lineNr.get(), fileName, line, colIndices,
|
||||||
: lineContentTokens[columnFromFile.getValue()].trim().isEmpty() ? null
|
(timePoint, lineContentTokens, columnsInFileFromHeader) -> {
|
||||||
: Double.parseDouble(lineContentTokens[columnFromFile.getValue()]);
|
final Double[] trackFixData = new Double[trackColumnCount];
|
||||||
trackFixData[indexInDoubleVectorFix] = value;
|
for (final Entry<String, Integer> columnFromFile : columnsInFileFromHeader.entrySet()) {
|
||||||
}
|
final Integer indexInDoubleVectorFix = columnNamesInFileAndTheirValueIndexInResultingDoubleVectorFix.get(columnFromFile.getKey());
|
||||||
}
|
if (indexInDoubleVectorFix != null) {
|
||||||
importedFixes.set(true);
|
final Double value = columnFromFile.getValue() >= lineContentTokens.length ? null
|
||||||
callback.addFixes(
|
: lineContentTokens[columnFromFile.getValue()].trim().isEmpty() ? null
|
||||||
Collections.singleton(new DoubleVectorFixImpl(timePoint, trackFixData)),
|
: Double.parseDouble(lineContentTokens[columnFromFile.getValue()]);
|
||||||
trackIdentifier);
|
trackFixData[indexInDoubleVectorFix] = value;
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
});
|
importedFixes.set(true);
|
||||||
|
callback.addFixes(
|
||||||
|
Collections.singleton(new DoubleVectorFixImpl(timePoint, trackFixData)),
|
||||||
|
trackIdentifier);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return importedFixes.get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected TrackFileImportDeviceIdentifierImpl getTrackIdentifier(String filename, String sourceName) {
|
protected TrackFileImportDeviceIdentifierImpl getTrackIdentifier(String filename, String sourceName) {
|
||||||
|
|||||||
+11
-10
@@ -3,23 +3,24 @@ package com.sap.sailing.server.trackfiles.impl;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.sap.sailing.domain.trackimport.FormatNotSupportedException;
|
import com.sap.sailing.domain.trackimport.FormatNotSupportedException;
|
||||||
|
|
||||||
public abstract class ExpeditionImportFileHandler implements CompressedStreamsUtil.FileHandler {
|
public abstract class ExpeditionImportFileHandler implements CompressedStreamsUtil.FileHandler {
|
||||||
|
|
||||||
public static final List<String> supportedExpeditionLogFileExtensions = Arrays.asList("csv", "log", "txt");
|
public final Iterable<String> supportedExpeditionLogFileExtensions;
|
||||||
public static final List<String> supportedExpeditionArchiveFileExtensions = Arrays.asList("gz", "zip");
|
|
||||||
public static final List<String> supportedExpeditionFileExtensions;
|
|
||||||
|
|
||||||
static {
|
public Iterable<String> getSupportedFileExtensions() {
|
||||||
final List<String> allExtensions = new ArrayList<>(supportedExpeditionLogFileExtensions);
|
return supportedExpeditionLogFileExtensions;
|
||||||
allExtensions.addAll(supportedExpeditionArchiveFileExtensions);
|
}
|
||||||
supportedExpeditionFileExtensions = Collections.unmodifiableList(allExtensions);
|
|
||||||
|
protected ExpeditionImportFileHandler(Iterable<String> supportedFileExtensions) {
|
||||||
|
this.supportedExpeditionLogFileExtensions = supportedFileExtensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ExpeditionImportFileHandler() {
|
||||||
|
this(Arrays.asList("csv", "log", "txt"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -23,6 +23,17 @@
|
|||||||
<div class="mainContent">
|
<div class="mainContent">
|
||||||
<h2 class="releaseHeadline">Release Notes - Administration Console</h2>
|
<h2 class="releaseHeadline">Release Notes - Administration Console</h2>
|
||||||
<div class="innerContent">
|
<div class="innerContent">
|
||||||
|
<h2 class="articleSubheadline">February 2025</h2>
|
||||||
|
<ul class="bulletList">
|
||||||
|
<li>In the <a href="/gwt/AdminConsole.html#SmartphoneTrackingPlace:">admin console's</a>
|
||||||
|
Smartphone Tracking panel, when importing data from files to create new device mappings
|
||||||
|
there is now a "Vakaros" / "VAKAROS_EXTENDED" menu entry when using "Import fixes"
|
||||||
|
or "Import additional sensor data," respectively. With these, files obtained from
|
||||||
|
Vakaros devices can be imported with their time stamps, GPS information (lat/lon,
|
||||||
|
COG, SOG) and, when available, from the "additional" sensor data heel, pitch,
|
||||||
|
and the two special values load_GDF1 and load_GDF2, which we map to the
|
||||||
|
forestay load and the kicker tension values, respectively.</li>
|
||||||
|
</ul>
|
||||||
<h2 class="articleSubheadline">January 2025</h2>
|
<h2 class="articleSubheadline">January 2025</h2>
|
||||||
<ul class="bulletList">
|
<ul class="bulletList">
|
||||||
<li>When exporting wind from the Admin Console's Tracked Races / Tracked Races panel,
|
<li>When exporting wind from the Admin Console's Tracked Races / Tracked Races panel,
|
||||||
|
|||||||
Reference in New Issue
Block a user