subsurface/core/save-profiledata.c
Berthold Stoeger 2645fa1495 profile: remove fast argument of create_plot_info_new()
This prevented calculation of the pressure data when dragging
planner handles. However, this lead to weird artifacts.

As an alternative, if this turns out to be too slow, we might
disable the plotting of the pressure curves instead.

That said, even on my super-slow fanless laptop, this performs
reasonably.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00

272 lines
7.6 KiB
C

#include "core/profile.h"
#include "core/display.h"
#include "core/errorhelper.h"
#include "core/file.h"
#include "core/membuffer.h"
#include "core/subsurface-string.h"
#include "core/save-profiledata.h"
#include "core/version.h"
#include <errno.h>
static void put_int(struct membuffer *b, int val)
{
put_format(b, "\"%d\", ", val);
}
static void put_int_with_nl(struct membuffer *b, int val)
{
put_format(b, "\"%d\"\n", val);
}
static void put_csv_string(struct membuffer *b, const char *val)
{
put_format(b, "\"%s\", ", val);
}
static void put_csv_string_with_nl(struct membuffer *b, const char *val)
{
put_format(b, "\"%s\"\n", val);
}
static void put_double(struct membuffer *b, double val)
{
put_format(b, "\"%f\", ", val);
}
static void put_video_time(struct membuffer *b, int secs)
{
int hours = secs / 3600;
secs -= hours * 3600;
int mins = secs / 60;
secs -= mins * 60;
put_format(b, "%d:%02d:%02d.000,", hours, mins, secs);
}
static void put_pd(struct membuffer *b, const struct plot_info *pi, int idx)
{
const struct plot_data *entry = pi->entry + idx;
put_int(b, entry->in_deco);
put_int(b, entry->sec);
for (int c = 0; c < pi->nr_cylinders; c++) {
put_int(b, get_plot_sensor_pressure(pi, idx, c));
put_int(b, get_plot_interpolated_pressure(pi, idx, c));
}
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_int(b, entry->mod);
put_int(b, entry->ead);
put_int(b, entry->end);
put_int(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_with_nl(b, entry->icd_warning ? 1 : 0);
}
static void put_headers(struct membuffer *b, int nr_cylinders)
{
put_csv_string(b, "in_deco");
put_csv_string(b, "sec");
for (int c = 0; c < nr_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_with_nl(b, "icd_warning");
}
static void put_st_event(struct membuffer *b, struct plot_data *entry, int offset, int length)
{
double value;
int decimals;
const char *unit;
if (entry->sec < offset || entry->sec > offset + length)
return;
put_format(b, "Dialogue: 0,");
put_video_time(b, entry->sec - offset);
put_video_time(b, (entry+1)->sec - offset < length ? (entry+1)->sec - offset : length);
put_format(b, "Default,,0,0,0,,");
put_format(b, "%d:%02d ", FRACTION(entry->sec, 60));
value = get_depth_units(entry->depth, &decimals, &unit);
put_format(b, "D=%02.2f %s ", value, unit);
if (entry->temperature) {
value = get_temp_units(entry->temperature, &unit);
put_format(b, "T=%.1f%s ", value, unit);
}
// Only show NDL if it is not essentially infinite, show TTS for mandatory stops.
if (entry->ndl_calc < 3600) {
if (entry->ndl_calc > 0)
put_format(b, "NDL=%d:%02d ", FRACTION(entry->ndl_calc, 60));
else
if (entry->tts_calc > 0)
put_format(b, "TTS=%d:%02d ", FRACTION(entry->tts_calc, 60));
}
if (entry->surface_gf > 0.0) {
put_format(b, "sGF=%.1f%% ", entry->surface_gf);
}
put_format(b, "\n");
}
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;
init_plot_info(&pi);
for_each_dive(i, dive) {
if (select_only && !dive->selected)
continue;
create_plot_info_new(dive, &dive->dc, &pi, planner_deco_state);
put_headers(b, pi.nr_cylinders);
for (int i = 0; i < pi.nr; i++)
put_pd(b, &pi, i);
put_format(b, "\n");
free_plot_info_data(&pi);
}
}
void save_subtitles_buffer(struct membuffer *b, struct dive *dive, int offset, int length)
{
struct plot_info pi;
struct deco_state *planner_deco_state = NULL;
init_plot_info(&pi);
create_plot_info_new(dive, &dive->dc, &pi, planner_deco_state);
put_format(b, "[Script Info]\n");
put_format(b, "; Script generated by Subsurface %s\n", subsurface_canonical_version());
put_format(b, "ScriptType: v4.00+\nPlayResX: 384\nPlayResY: 288\n\n");
put_format(b, "[V4+ Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\n");
put_format(b, "Style: Default,Arial,12,&Hffffff,&Hffffff,&H0,&H0,0,0,0,0,100,100,0,0,1,1,0,7,10,10,10,0\n\n");
put_format(b, "[Events]\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n");
for (int i = 0; i < pi.nr; i++) {
put_st_event(b, &pi.entry[i], offset, length);
}
put_format(b, "\n");
free_plot_info_data(&pi);
}
int save_profiledata(const char *filename, 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(errno));
free_buffer(&buf);
return error;
}