diff options
author | Robert C. Helling <helling@atdotde.de> | 2019-03-30 20:59:28 +0100 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2019-04-04 09:33:56 -0700 |
commit | 8c9e5becb20d2d8c8aa1f7108775cc520b08fae1 (patch) | |
tree | cc7bdbc918716ba4d7cf9d39acebce1ecc1cbc31 | |
parent | a89b36c661662346c6c8092bdd2cefebf8f58c8a (diff) | |
download | subsurface-8c9e5becb20d2d8c8aa1f7108775cc520b08fae1.tar.gz |
Export profile data
This introduces a csv file that contains the data from
the structs defined in profile.c, in particular all
deco information computed for the dive profle (including
NDL, TTS, ceilings, surface GFs etc).
Signed-off-by: Robert C. Helling <helling@atdotde.de>
-rw-r--r-- | CHANGELOG.md | 1 | ||||
-rw-r--r-- | core/CMakeLists.txt | 1 | ||||
-rw-r--r-- | core/save-profiledata.c | 197 | ||||
-rw-r--r-- | core/save-profiledata.h | 16 | ||||
-rw-r--r-- | desktop-widgets/divelogexportdialog.cpp | 7 | ||||
-rw-r--r-- | desktop-widgets/divelogexportdialog.ui | 12 |
6 files changed, 233 insertions, 1 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 2da845e5a..6cd5076d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ - Import: Initial support for importing Mares log software +- Export option for profile data - Planner: Allow for a final segment at the surface to display further desaturation - Desktop: Add stats by depth and temperature ranges to yearly stats [#1996] - Desktop: make sure cloud storage email addresses are lower case only diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 004f3693b..c55b5627d 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -128,6 +128,7 @@ set(SUBSURFACE_CORE_LIB_SRCS save-git.c save-html.c save-html.h + save-profiledata.c save-xml.c sha1.c sha1.h diff --git a/core/save-profiledata.c b/core/save-profiledata.c new file mode 100644 index 000000000..603045fe0 --- /dev/null +++ b/core/save-profiledata.c @@ -0,0 +1,197 @@ +#include "core/profile.h" +#include "core/profile.h" +#include "core/dive.h" +#include "core/display.h" +#include "core/membuffer.h" +#include "core/subsurface-string.h" +#include "core/save-profiledata.h" + +static void put_int(struct membuffer *b, int val) +{ + put_format(b, "\"%d\", ", val); +} + +static void put_csv_string(struct membuffer *b, const char *val) +{ + put_format(b, "\"%s\", ", val); +} + +static void put_double(struct membuffer *b, double val) +{ + put_format(b, "\"%f\" ", val); +} + +static void put_pd(struct membuffer *b, struct plot_data *entry) +{ + if (!entry) + return; + + put_int(b, entry->in_deco); + put_int(b, entry->sec); + for (int c = 0; c < MAX_CYLINDERS; c++) { + put_int(b, entry->pressure[c][0]); + put_int(b, entry->pressure[c][1]); + } + put_int(b, entry->temperature); + put_int(b, entry->depth); + put_int(b, entry->ceiling); + for (int i = 0; i < 16; i++) + put_int(b, entry->ceilings[i]); + for (int i = 0; i < 16; i++) + put_int(b, entry->percentages[i]); + put_int(b, entry->ndl); + put_int(b, entry->tts); + put_int(b, entry->rbt); + put_int(b, entry->stoptime); + put_int(b, entry->stopdepth); + put_int(b, entry->cns); + put_int(b, entry->smoothed); + put_int(b, entry->sac); + put_int(b, entry->running_sum); + put_double(b, entry->pressures.o2); + put_double(b, entry->pressures.n2); + put_double(b, entry->pressures.he); + put_int(b, entry->o2pressure.mbar); + put_int(b, entry->o2sensor[0].mbar); + put_int(b, entry->o2sensor[1].mbar); + put_int(b, entry->o2sensor[2].mbar); + put_int(b, entry->o2setpoint.mbar); + put_int(b, entry->scr_OC_pO2.mbar); + put_double(b, entry->mod); + put_double(b, entry->ead); + put_double(b, entry->end); + put_double(b, entry->eadd); + switch (entry->velocity) { + case STABLE: + put_csv_string(b, "STABLE"); + break; + case SLOW: + put_csv_string(b, "SLOW"); + break; + case MODERATE: + put_csv_string(b, "MODERATE"); + break; + case FAST: + put_csv_string(b, "FAST"); + break; + case CRAZY: + put_csv_string(b, "CRAZY"); + break; + } + put_int(b, entry->speed); + put_int(b, entry->in_deco_calc); + put_int(b, entry->ndl_calc); + put_int(b, entry->tts_calc); + put_int(b, entry->stoptime_calc); + put_int(b, entry->stopdepth_calc); + put_int(b, entry->pressure_time); + put_int(b, entry->heartbeat); + put_int(b, entry->bearing); + put_double(b, entry->ambpressure); + put_double(b, entry->gfline); + put_double(b, entry->surface_gf); + put_double(b, entry->density); + put_int(b, entry->icd_warning ? 1 : 0); +} + +static void put_headers(struct membuffer *b) +{ + put_csv_string(b, "in_deco"); + put_csv_string(b, "sec"); + for (int c = 0; c < MAX_CYLINDERS; c++) { + put_format(b, "\"pressure_%d_cylinder\", ", c); + put_format(b, "\"pressure_%d_interpolated\", ", c); + } + put_csv_string(b, "temperature"); + put_csv_string(b, "depth"); + put_csv_string(b, "ceiling"); + for (int i = 0; i < 16; i++) + put_format(b, "\"ceiling_%d\", ", i); + for (int i = 0; i < 16; i++) + put_format(b, "\"percentage_%d\", ", i); + put_csv_string(b, "ndl"); + put_csv_string(b, "tts"); + put_csv_string(b, "rbt"); + put_csv_string(b, "stoptime"); + put_csv_string(b, "stopdepth"); + put_csv_string(b, "cns"); + put_csv_string(b, "smoothed"); + put_csv_string(b, "sac"); + put_csv_string(b, "running_sum"); + put_csv_string(b, "pressureo2"); + put_csv_string(b, "pressuren2"); + put_csv_string(b, "pressurehe"); + put_csv_string(b, "o2pressure"); + put_csv_string(b, "o2sensor0"); + put_csv_string(b, "o2sensor1"); + put_csv_string(b, "o2sensor2"); + put_csv_string(b, "o2setpoint"); + put_csv_string(b, "scr_oc_po2"); + put_csv_string(b, "mod"); + put_csv_string(b, "ead"); + put_csv_string(b, "end"); + put_csv_string(b, "eadd"); + put_csv_string(b, "velocity"); + put_csv_string(b, "speed"); + put_csv_string(b, "in_deco_calc"); + put_csv_string(b, "ndl_calc"); + put_csv_string(b, "tts_calc"); + put_csv_string(b, "stoptime_calc"); + put_csv_string(b, "stopdepth_calc"); + put_csv_string(b, "pressure_time"); + put_csv_string(b, "heartbeat"); + put_csv_string(b, "bearing"); + put_csv_string(b, "ambpressure"); + put_csv_string(b, "gfline"); + put_csv_string(b, "surface_gf"); + put_csv_string(b, "density"); + put_csv_string(b, "icd_warning"); +} + +static void save_profiles_buffer(struct membuffer *b, bool select_only) +{ + int i; + struct dive *dive; + struct plot_info pi; + struct deco_state *planner_deco_state = NULL; + + for_each_dive(i, dive) { + if (select_only && !dive->selected) + continue; + pi = calculate_max_limits_new(dive, &dive->dc); + create_plot_info_new(dive, &dive->dc, &pi, false, planner_deco_state); + put_headers(b); + put_format(b, "\n"); + + for (int i = 0; i < pi.nr; i++) { + put_pd(b, &pi.entry[i]); + put_format(b, "\n"); + } + put_format(b, "\n"); + } +} + +int save_profiledata(const char *filename, const bool select_only) +{ + struct membuffer buf = { 0 }; + FILE *f; + int error = 0; + + save_profiles_buffer(&buf, select_only); + + if (same_string(filename, "-")) { + f = stdout; + } else { + error = -1; + f = subsurface_fopen(filename, "w"); + } + if (f) { + flush_buffer(&buf, f); + error = fclose(f); + } + if (error) + report_error("Save failed (%s)", strerror(error)); + + free_buffer(&buf); + return error; +} diff --git a/core/save-profiledata.h b/core/save-profiledata.h new file mode 100644 index 000000000..23e833a27 --- /dev/null +++ b/core/save-profiledata.h @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef SAVE_PROFILE_DATA_H +#define SAVE_PROFILE_DATA_H + +#include "dive.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int save_profiledata(const char *filename, bool selected_only); + +#ifdef __cplusplus +} +#endif +#endif // SAVE_PROFILE_DATA_H diff --git a/desktop-widgets/divelogexportdialog.cpp b/desktop-widgets/divelogexportdialog.cpp index 3e712fc5d..216a296eb 100644 --- a/desktop-widgets/divelogexportdialog.cpp +++ b/desktop-widgets/divelogexportdialog.cpp @@ -15,6 +15,7 @@ #include "core/settings/qPrefDisplay.h" #include "desktop-widgets/mainwindow.h" #include "profile-widget/profilewidget2.h" +#include "core/save-profiledata.h" #include "core/dive.h" // Allows access to helper functions in TeX export. // Retrieves the current unit settings defined in the Subsurface preferences. @@ -98,6 +99,8 @@ void DiveLogExportDialog::showExplanation() ui->description->setText(tr("Write dive as LaTeX macros to file.")); } else if (ui->exportProfile->isChecked()) { ui->description->setText(tr("Write the profile image as PNG file.")); + } else if (ui->exportProfileData->isChecked()) { + ui->description->setText(tr("Write profile data to a CSV file.")); } } @@ -175,6 +178,10 @@ void DiveLogExportDialog::on_buttonBox_accepted() filename = QFileDialog::getSaveFileName(this, tr("Save profile image"), lastDir); if (!filename.isNull() && !filename.isEmpty()) exportProfile(qPrintable(filename), ui->exportSelected->isChecked()); + } else if (ui->exportProfileData->isChecked()) { + filename = QFileDialog::getSaveFileName(this, tr("Save profile data"), lastDir); + if (!filename.isNull() && !filename.isEmpty()) + save_profiledata(qPrintable(filename), ui->exportSelected->isChecked()); } break; case 1: diff --git a/desktop-widgets/divelogexportdialog.ui b/desktop-widgets/divelogexportdialog.ui index 9080c647f..07b06378b 100644 --- a/desktop-widgets/divelogexportdialog.ui +++ b/desktop-widgets/divelogexportdialog.ui @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>507</width> - <height>398</height> + <height>423</height> </rect> </property> <property name="windowTitle"> @@ -231,6 +231,16 @@ </attribute> </widget> </item> + <item> + <widget class="QRadioButton" name="exportProfileData"> + <property name="text"> + <string>Profile Data CSV</string> + </property> + <attribute name="buttonGroup"> + <string notr="true">exportGroup</string> + </attribute> + </widget> + </item> </layout> </widget> </item> |