mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
Profile: Improve Display of Bailout / Loop Events.
For dives in CCR mode, show 'bailout' and 'on loop' events whenever a gas switch from a diluent gas to a bailout gas and vice versa happens. Signed-off-by: Michael Keller <github@ike.ch>
This commit is contained in:
parent
de12d3a6ea
commit
07898f277c
16 changed files with 183 additions and 121 deletions
103
core/dive.cpp
103
core/dive.cpp
|
@ -56,7 +56,7 @@ dive::~dive() = default;
|
||||||
* equals the appropriate enum value [oxygen, diluent, bailout] given by cylinder_use_type.
|
* equals the appropriate enum value [oxygen, diluent, bailout] given by cylinder_use_type.
|
||||||
* A negative number returned indicates that a match could not be found.
|
* A negative number returned indicates that a match could not be found.
|
||||||
* Call parameters: dive = the dive being processed
|
* Call parameters: dive = the dive being processed
|
||||||
* cylinder_use_type = an enum, one of {oxygen, diluent, bailout} */
|
* cylinder_use_type = an enum, one of {oxygen, diluent, bailout} */
|
||||||
static int get_cylinder_idx_by_use(const struct dive &dive, enum cylinderuse cylinder_use_type)
|
static int get_cylinder_idx_by_use(const struct dive &dive, enum cylinderuse cylinder_use_type)
|
||||||
{
|
{
|
||||||
auto it = std::find_if(dive.cylinders.begin(), dive.cylinders.end(), [cylinder_use_type]
|
auto it = std::find_if(dive.cylinders.begin(), dive.cylinders.end(), [cylinder_use_type]
|
||||||
|
@ -156,16 +156,18 @@ void add_gas_switch_event(struct dive *dive, struct divecomputer *dc, int second
|
||||||
add_event_to_dc(dc, std::move(ev));
|
add_event_to_dc(dc, std::move(ev));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct gasmix dive::get_gasmix_from_event(const struct event &ev) const
|
std::pair<const struct gasmix, divemode_t> dive::get_gasmix_from_event(const struct event &ev, const struct divecomputer &dc) const
|
||||||
{
|
{
|
||||||
if (ev.is_gaschange()) {
|
if (ev.is_gaschange()) {
|
||||||
int index = ev.gas.index;
|
int index = ev.gas.index;
|
||||||
// FIXME: The planner uses one past cylinder-count to signify "surface air". Remove in due course.
|
// FIXME: The planner uses one past cylinder-count to signify "surface air". Remove in due course.
|
||||||
if (index >= 0 && static_cast<size_t>(index) < cylinders.size() + 1)
|
if (index >= 0 && static_cast<size_t>(index) < cylinders.size() + 1) {
|
||||||
return get_cylinder(index)->gasmix;
|
const cylinder_t *cylinder = get_cylinder(index);
|
||||||
return ev.gas.mix;
|
return std::make_pair(cylinder->gasmix, get_effective_divemode(dc, *cylinder));
|
||||||
|
}
|
||||||
|
return std::make_pair(ev.gas.mix, dc.divemode);
|
||||||
}
|
}
|
||||||
return gasmix_air;
|
return std::make_pair(gasmix_air, dc.divemode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we need this to be uniq. oh, and it has no meaning whatsoever
|
// we need this to be uniq. oh, and it has no meaning whatsoever
|
||||||
|
@ -307,7 +309,7 @@ static int get_cylinder_used(const struct dive *dive, bool used[])
|
||||||
* Some dive computers give cylinder indices, some
|
* Some dive computers give cylinder indices, some
|
||||||
* give just the gas mix.
|
* give just the gas mix.
|
||||||
*/
|
*/
|
||||||
int dive::get_cylinder_index(const struct event &ev) const
|
int dive::get_cylinder_index(const struct event &ev, const struct divecomputer &dc) const
|
||||||
{
|
{
|
||||||
if (ev.gas.index >= 0)
|
if (ev.gas.index >= 0)
|
||||||
return ev.gas.index;
|
return ev.gas.index;
|
||||||
|
@ -320,7 +322,7 @@ int dive::get_cylinder_index(const struct event &ev) const
|
||||||
*/
|
*/
|
||||||
report_info("Still looking up cylinder based on gas mix in get_cylinder_index()!");
|
report_info("Still looking up cylinder based on gas mix in get_cylinder_index()!");
|
||||||
|
|
||||||
gasmix mix = get_gasmix_from_event(ev);
|
gasmix mix = get_gasmix_from_event(ev, dc).first;
|
||||||
int best = find_best_gasmix_match(mix, cylinders);
|
int best = find_best_gasmix_match(mix, cylinders);
|
||||||
return best < 0 ? 0 : best;
|
return best < 0 ? 0 : best;
|
||||||
}
|
}
|
||||||
|
@ -1629,6 +1631,38 @@ bool is_cylinder_use_appropriate(const struct divecomputer &dc, const cylinder_t
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
divemode_t get_effective_divemode(const struct divecomputer &dc, const struct cylinder_t &cylinder)
|
||||||
|
{
|
||||||
|
divemode_t divemode = dc.divemode;
|
||||||
|
if (divemode == CCR && cylinder.cylinder_use == OC_GAS)
|
||||||
|
divemode = OC;
|
||||||
|
|
||||||
|
return divemode;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<divemode_t, int, const struct gasmix *> get_dive_status_at(const struct dive &dive, const struct divecomputer &dc, int seconds, divemode_loop *loop_mode, gasmix_loop *loop_gas)
|
||||||
|
{
|
||||||
|
if (!loop_mode)
|
||||||
|
loop_mode = new divemode_loop(dc);
|
||||||
|
if (!loop_gas)
|
||||||
|
loop_gas = new gasmix_loop(dive, dc);
|
||||||
|
auto [divemode, divemode_time] = loop_mode->at(seconds);
|
||||||
|
auto [cylinder_index, gasmix_time] = loop_gas->cylinder_index_at(seconds);
|
||||||
|
const struct gasmix *gasmix;
|
||||||
|
if (cylinder_index == -1) {
|
||||||
|
gasmix = &gasmix_air;
|
||||||
|
if (gasmix_time >= divemode_time)
|
||||||
|
divemode = OC;
|
||||||
|
} else {
|
||||||
|
const struct cylinder_t *cylinder = dive.get_cylinder(cylinder_index);
|
||||||
|
gasmix = &cylinder->gasmix;
|
||||||
|
if (gasmix_time >= divemode_time)
|
||||||
|
divemode = get_effective_divemode(dc, *cylinder);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_tuple(divemode, cylinder_index, gasmix);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Merging cylinder information is non-trivial, because the two dive computers
|
* Merging cylinder information is non-trivial, because the two dive computers
|
||||||
* may have different ideas of what the different cylinder indexing is.
|
* may have different ideas of what the different cylinder indexing is.
|
||||||
|
@ -2573,25 +2607,27 @@ gasmix_loop::gasmix_loop(const struct dive &d, const struct divecomputer &dc) :
|
||||||
|
|
||||||
std::pair<int, int> gasmix_loop::next_cylinder_index()
|
std::pair<int, int> gasmix_loop::next_cylinder_index()
|
||||||
{
|
{
|
||||||
if (dive.cylinders.empty())
|
|
||||||
return std::make_pair(-1, INT_MAX);
|
|
||||||
|
|
||||||
if (first_run) {
|
if (first_run) {
|
||||||
next_event = loop.next();
|
next_event = loop.next();
|
||||||
last_cylinder_index = 0; // default to first cylinder
|
|
||||||
last_time = 0;
|
|
||||||
if (next_event && ((!dc.samples.empty() && next_event->time.seconds == dc.samples[0].time.seconds) || next_event->time.seconds <= 1)) {
|
|
||||||
last_cylinder_index = dive.get_cylinder_index(*next_event);
|
|
||||||
last_time = next_event->time.seconds;
|
|
||||||
next_event = loop.next();
|
|
||||||
} else if (dc.divemode == CCR) {
|
|
||||||
last_cylinder_index = std::max(get_cylinder_idx_by_use(dive, DILUENT), last_cylinder_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
first_run = false;
|
first_run = false;
|
||||||
|
|
||||||
|
if (dive.cylinders.empty()) {
|
||||||
|
last_cylinder_index = -1;
|
||||||
|
last_time = 0;
|
||||||
|
} else {
|
||||||
|
last_cylinder_index = 0; // default to first cylinder
|
||||||
|
last_time = 0;
|
||||||
|
if (next_event && ((!dc.samples.empty() && next_event->time.seconds == dc.samples[0].time.seconds) || next_event->time.seconds <= 1)) {
|
||||||
|
last_cylinder_index = dive.get_cylinder_index(*next_event, dc);
|
||||||
|
last_time = next_event->time.seconds;
|
||||||
|
next_event = loop.next();
|
||||||
|
} else if (dc.divemode == CCR) {
|
||||||
|
last_cylinder_index = std::max(get_cylinder_idx_by_use(dive, DILUENT), last_cylinder_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (next_event) {
|
if (next_event) {
|
||||||
last_cylinder_index = dive.get_cylinder_index(*next_event);
|
last_cylinder_index = dive.get_cylinder_index(*next_event, dc);
|
||||||
last_time = next_event->time.seconds;
|
last_time = next_event->time.seconds;
|
||||||
next_event = loop.next();
|
next_event = loop.next();
|
||||||
} else {
|
} else {
|
||||||
|
@ -2605,16 +2641,9 @@ std::pair<int, int> gasmix_loop::next_cylinder_index()
|
||||||
|
|
||||||
std::pair<gasmix, int> gasmix_loop::next()
|
std::pair<gasmix, int> gasmix_loop::next()
|
||||||
{
|
{
|
||||||
if (first_run && dive.cylinders.empty()) {
|
|
||||||
first_run = false;
|
|
||||||
|
|
||||||
// return one cylinder of air if we don't have any cylinders
|
|
||||||
return std::make_pair(gasmix_air, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
next_cylinder_index();
|
next_cylinder_index();
|
||||||
|
|
||||||
return std::make_pair(last_cylinder_index < 0 ? gasmix_invalid : dive.get_cylinder(last_cylinder_index)->gasmix, last_time);
|
return get_last_gasmix();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<int, int> gasmix_loop::cylinder_index_at(int time)
|
std::pair<int, int> gasmix_loop::cylinder_index_at(int time)
|
||||||
|
@ -2630,13 +2659,9 @@ std::pair<int, int> gasmix_loop::cylinder_index_at(int time)
|
||||||
|
|
||||||
std::pair<gasmix, int> gasmix_loop::at(int time)
|
std::pair<gasmix, int> gasmix_loop::at(int time)
|
||||||
{
|
{
|
||||||
if (dive.cylinders.empty())
|
|
||||||
// return air if we don't have any cylinders
|
|
||||||
return std::make_pair(gasmix_air, 0);
|
|
||||||
|
|
||||||
cylinder_index_at(time);
|
cylinder_index_at(time);
|
||||||
|
|
||||||
return std::make_pair(last_cylinder_index < 0 ? gasmix_invalid : dive.get_cylinder(last_cylinder_index)->gasmix, last_time);
|
return get_last_gasmix();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool gasmix_loop::has_next() const
|
bool gasmix_loop::has_next() const
|
||||||
|
@ -2644,6 +2669,14 @@ bool gasmix_loop::has_next() const
|
||||||
return first_run || (!dive.cylinders.empty() && next_event);
|
return first_run || (!dive.cylinders.empty() && next_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<gasmix, int> gasmix_loop::get_last_gasmix()
|
||||||
|
{
|
||||||
|
if (last_cylinder_index < 0 && last_time == 0)
|
||||||
|
return std::make_pair(gasmix_air, 0);
|
||||||
|
|
||||||
|
return std::make_pair(last_cylinder_index < 0 ? gasmix_invalid : dive.get_cylinder(last_cylinder_index)->gasmix, last_time);
|
||||||
|
}
|
||||||
|
|
||||||
/* get the gas at a certain time during the dive */
|
/* get the gas at a certain time during the dive */
|
||||||
/* If there is a gasswitch at that time, it returns the new gasmix */
|
/* If there is a gasswitch at that time, it returns the new gasmix */
|
||||||
struct gasmix dive::get_gasmix_at_time(const struct divecomputer &dc, duration_t time) const
|
struct gasmix dive::get_gasmix_at_time(const struct divecomputer &dc, duration_t time) const
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "divemode.h"
|
#include "divemode.h"
|
||||||
#include "divecomputer.h"
|
#include "divecomputer.h"
|
||||||
#include "equipment.h"
|
#include "equipment.h"
|
||||||
|
#include "event.h"
|
||||||
#include "picture.h" // TODO: remove
|
#include "picture.h" // TODO: remove
|
||||||
#include "tag.h"
|
#include "tag.h"
|
||||||
|
|
||||||
|
@ -103,9 +104,9 @@ struct dive {
|
||||||
bool likely_same(const struct dive &b) const;
|
bool likely_same(const struct dive &b) const;
|
||||||
bool is_cylinder_used(int idx) const;
|
bool is_cylinder_used(int idx) const;
|
||||||
bool is_cylinder_prot(int idx) const;
|
bool is_cylinder_prot(int idx) const;
|
||||||
int get_cylinder_index(const struct event &ev) const;
|
int get_cylinder_index(const struct event &ev, const struct divecomputer &dc) const;
|
||||||
bool has_gaschange_event(const struct divecomputer *dc, int idx) const;
|
bool has_gaschange_event(const struct divecomputer *dc, int idx) const;
|
||||||
struct gasmix get_gasmix_from_event(const struct event &ev) const;
|
std::pair<const struct gasmix, divemode_t> get_gasmix_from_event(const struct event &ev, const struct divecomputer &dc) const;
|
||||||
struct gasmix get_gasmix_at_time(const struct divecomputer &dc, duration_t time) const;
|
struct gasmix get_gasmix_at_time(const struct divecomputer &dc, duration_t time) const;
|
||||||
cylinder_t *get_cylinder(int idx);
|
cylinder_t *get_cylinder(int idx);
|
||||||
cylinder_t *get_or_create_cylinder(int idx);
|
cylinder_t *get_or_create_cylinder(int idx);
|
||||||
|
@ -152,6 +153,8 @@ struct dive_or_trip {
|
||||||
extern void cylinder_renumber(struct dive &dive, int mapping[]);
|
extern void cylinder_renumber(struct dive &dive, int mapping[]);
|
||||||
extern int same_gasmix_cylinder(const cylinder_t &cyl, int cylid, const struct dive *dive, bool check_unused);
|
extern int same_gasmix_cylinder(const cylinder_t &cyl, int cylid, const struct dive *dive, bool check_unused);
|
||||||
extern bool is_cylinder_use_appropriate(const struct divecomputer &dc, const cylinder_t &cyl, bool allowNonUsable);
|
extern bool is_cylinder_use_appropriate(const struct divecomputer &dc, const cylinder_t &cyl, bool allowNonUsable);
|
||||||
|
extern divemode_t get_effective_divemode(const struct divecomputer &dc, const struct cylinder_t &cylinder);
|
||||||
|
extern std::tuple<divemode_t, int, const struct gasmix *> get_dive_status_at(const struct dive &dive, const struct divecomputer &dc, int seconds, divemode_loop *loop_mode = nullptr, gasmix_loop *loop_gas = nullptr);
|
||||||
|
|
||||||
/* Data stored when copying a dive */
|
/* Data stored when copying a dive */
|
||||||
struct dive_paste_data {
|
struct dive_paste_data {
|
||||||
|
|
|
@ -200,19 +200,20 @@ void fake_dc(struct divecomputer *dc)
|
||||||
}
|
}
|
||||||
|
|
||||||
divemode_loop::divemode_loop(const struct divecomputer &dc) :
|
divemode_loop::divemode_loop(const struct divecomputer &dc) :
|
||||||
last(dc.divemode), loop("modechange", dc)
|
last(dc.divemode), last_time(0), loop("modechange", dc)
|
||||||
{
|
{
|
||||||
/* on first invocation, get first event (if any) */
|
/* on first invocation, get first event (if any) */
|
||||||
ev = loop.next();
|
ev = loop.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
divemode_t divemode_loop::at(int time)
|
std::pair<divemode_t, int> divemode_loop::at(int time)
|
||||||
{
|
{
|
||||||
while (ev && ev->time.seconds <= time) {
|
while (ev && ev->time.seconds <= time) {
|
||||||
last = static_cast<divemode_t>(ev->value);
|
last = static_cast<divemode_t>(ev->value);
|
||||||
|
last_time = ev->time.seconds;
|
||||||
ev = loop.next();
|
ev = loop.next();
|
||||||
}
|
}
|
||||||
return last;
|
return std::make_pair(last, last_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* helper function to make it easier to work with our structures
|
/* helper function to make it easier to work with our structures
|
||||||
|
|
|
@ -424,8 +424,8 @@ static void add_dive_to_deco(struct deco_state *ds, const struct dive &dive, boo
|
||||||
{
|
{
|
||||||
const struct divecomputer *dc = &dive.dcs[0];
|
const struct divecomputer *dc = &dive.dcs[0];
|
||||||
|
|
||||||
gasmix_loop loop(dive, dive.dcs[0]);
|
gasmix_loop loop_gas(dive, dive.dcs[0]);
|
||||||
divemode_loop loop_d(dive.dcs[0]);
|
divemode_loop loop_mode(dive.dcs[0]);
|
||||||
for (auto [psample, sample]: pairwise_range(dc->samples)) {
|
for (auto [psample, sample]: pairwise_range(dc->samples)) {
|
||||||
int t0 = psample.time.seconds;
|
int t0 = psample.time.seconds;
|
||||||
int t1 = sample.time.seconds;
|
int t1 = sample.time.seconds;
|
||||||
|
@ -433,9 +433,9 @@ static void add_dive_to_deco(struct deco_state *ds, const struct dive &dive, boo
|
||||||
|
|
||||||
for (j = t0; j < t1; j++) {
|
for (j = t0; j < t1; j++) {
|
||||||
depth_t depth = interpolate(psample.depth, sample.depth, j - t0, t1 - t0);
|
depth_t depth = interpolate(psample.depth, sample.depth, j - t0, t1 - t0);
|
||||||
auto gasmix = loop.at(j).first;
|
[[maybe_unused]] auto [divemode, _cylinder_index, gasmix] = get_dive_status_at(dive, dive.dcs[0], j);
|
||||||
add_segment(ds, dive.depth_to_bar(depth), gasmix, 1, sample.setpoint.mbar,
|
add_segment(ds, dive.depth_to_bar(depth), *gasmix, 1, sample.setpoint.mbar,
|
||||||
loop_d.at(j), dive.sac,
|
divemode, dive.sac,
|
||||||
in_planner);
|
in_planner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
13
core/event.h
13
core/event.h
|
@ -73,19 +73,20 @@ class gasmix_loop {
|
||||||
const struct event *next_event;
|
const struct event *next_event;
|
||||||
int last_cylinder_index;
|
int last_cylinder_index;
|
||||||
int last_time;
|
int last_time;
|
||||||
|
std::pair<gasmix, int> get_last_gasmix();
|
||||||
public:
|
public:
|
||||||
gasmix_loop(const struct dive &dive, const struct divecomputer &dc);
|
gasmix_loop(const struct dive &dive, const struct divecomputer &dc);
|
||||||
// Return the next cylinder index / gasmix from the list of gas switches
|
// Return the next cylinder index / gasmix from the list of gas switches
|
||||||
// and the time in seconds when this gas switch happened
|
// and the time in seconds when this gas switch happened
|
||||||
// (including the potentially imaginary first gas switch to cylinder 0 / air)
|
// (including the potentially imaginary first gas switch to cylinder 0 / air)
|
||||||
std::pair<int, int> next_cylinder_index(); // -1 -> end
|
std::pair<int, int> next_cylinder_index(); // <-1, 0> => implicit air cylinder, <-1, INT_MAX> => end
|
||||||
std::pair<gasmix, int> next(); // gasmix_invalid -> end
|
std::pair<gasmix, int> next(); // <gasmix_invalid, INT_MAX> => end
|
||||||
|
|
||||||
// Return the cylinder index / gasmix at a given time during the dive
|
// Return the cylinder index / gasmix at a given time during the dive
|
||||||
// and the time in seconds when this switch to this gas happened
|
// and the time in seconds when this switch to this gas happened
|
||||||
// (including the potentially imaginary first gas switch to cylinder 0 / air)
|
// (including the potentially imaginary first gas switch to cylinder 0 / air)
|
||||||
std::pair<int, int> cylinder_index_at(int time); // -1 -> end
|
std::pair<int, int> cylinder_index_at(int time); // <-1, 0> => implicit air cylinder
|
||||||
std::pair<gasmix, int> at(int time); // gasmix_invalid -> end
|
std::pair<gasmix, int> at(int time);
|
||||||
|
|
||||||
bool has_next() const;
|
bool has_next() const;
|
||||||
};
|
};
|
||||||
|
@ -93,12 +94,14 @@ public:
|
||||||
/* Get divemodes at increasing timestamps. */
|
/* Get divemodes at increasing timestamps. */
|
||||||
class divemode_loop {
|
class divemode_loop {
|
||||||
divemode_t last;
|
divemode_t last;
|
||||||
|
int last_time;
|
||||||
event_loop loop;
|
event_loop loop;
|
||||||
const struct event *ev;
|
const struct event *ev;
|
||||||
public:
|
public:
|
||||||
divemode_loop(const struct divecomputer &dc);
|
divemode_loop(const struct divecomputer &dc);
|
||||||
// Return the divemode at a given time during the dive
|
// Return the divemode at a given time during the dive
|
||||||
divemode_t at(int time);
|
// and the time in seconds when the switch to this divemode has happened
|
||||||
|
std::pair<divemode_t, int> at(int time);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const struct event *get_first_event(const struct divecomputer &dc, const std::string &name);
|
extern const struct event *get_first_event(const struct divecomputer &dc, const std::string &name);
|
||||||
|
|
|
@ -198,7 +198,7 @@ static void fill_missing_tank_pressures(const struct dive *dive, struct plot_inf
|
||||||
dump_pr_track(cyl, track_pr);
|
dump_pr_track(cyl, track_pr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Transfer interpolated cylinder pressures from pr_track strucktures to plotdata
|
/* Transfer interpolated cylinder pressures from pr_track structures to plotdata
|
||||||
* Go down the list of tank pressures in plot_info. Align them with the start &
|
* Go down the list of tank pressures in plot_info. Align them with the start &
|
||||||
* end times of each profile segment represented by a pr_track_t structure. Get
|
* end times of each profile segment represented by a pr_track_t structure. Get
|
||||||
* the accumulated pressure_depths from the pr_track_t structures and then
|
* the accumulated pressure_depths from the pr_track_t structures and then
|
||||||
|
@ -248,7 +248,7 @@ static void fill_missing_tank_pressures(const struct dive *dive, struct plot_inf
|
||||||
last_segment = it;
|
last_segment = it;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(dive->get_cylinder(cyl)->cylinder_use == OC_GAS) {
|
if (dive->get_cylinder(cyl)->cylinder_use == OC_GAS) {
|
||||||
|
|
||||||
/* if this segment has pressure_time, then calculate a new interpolated pressure */
|
/* if this segment has pressure_time, then calculate a new interpolated pressure */
|
||||||
if (interpolate.pressure_time) {
|
if (interpolate.pressure_time) {
|
||||||
|
@ -358,16 +358,15 @@ void populate_pressure_information(const struct dive *dive, const struct divecom
|
||||||
int pressure = get_plot_sensor_pressure(pi, i, sensor);
|
int pressure = get_plot_sensor_pressure(pi, i, sensor);
|
||||||
int time = entry.sec;
|
int time = entry.sec;
|
||||||
|
|
||||||
|
[[maybe_unused]] auto [divemode, cylinder_index, _gasmix] = get_dive_status_at(*dive, *dc, time, &loop_mode, &loop_gas);
|
||||||
if (has_gaschange) {
|
if (has_gaschange) {
|
||||||
cyl = loop_gas.cylinder_index_at(time).first;
|
cyl = cylinder_index;
|
||||||
if (cyl < 0)
|
if (cyl < 0)
|
||||||
cyl = sensor;
|
cyl = sensor;
|
||||||
}
|
}
|
||||||
|
|
||||||
divemode_t dmode = loop_mode.at(time);
|
|
||||||
|
|
||||||
if (current != std::string::npos) { // calculate pressure-time, taking into account the dive mode for this specific segment.
|
if (current != std::string::npos) { // calculate pressure-time, taking into account the dive mode for this specific segment.
|
||||||
entry.pressure_time = (int)(calc_pressure_time(dive, pi.entry[i - 1], entry) * gasfactor[dmode] + 0.5);
|
entry.pressure_time = (int)(calc_pressure_time(dive, pi.entry[i - 1], entry) * gasfactor[divemode] + 0.5);
|
||||||
track[current].pressure_time += entry.pressure_time;
|
track[current].pressure_time += entry.pressure_time;
|
||||||
track[current].t_end = entry.sec;
|
track[current].t_end = entry.sec;
|
||||||
if (pressure)
|
if (pressure)
|
||||||
|
|
|
@ -83,7 +83,7 @@ int get_cylinderid_at_time(struct dive *dive, struct divecomputer *dc, duration_
|
||||||
if (event.time.seconds > time.seconds)
|
if (event.time.seconds > time.seconds)
|
||||||
break;
|
break;
|
||||||
if (event.name == "gaschange")
|
if (event.name == "gaschange")
|
||||||
cylinder_idx = dive->get_cylinder_index(event);
|
cylinder_idx = dive->get_cylinder_index(event, *dc);
|
||||||
}
|
}
|
||||||
return cylinder_idx;
|
return cylinder_idx;
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,8 @@ static int tissue_at_end(struct deco_state *ds, struct dive *dive, const struct
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
const struct sample *psample = nullptr;
|
const struct sample *psample = nullptr;
|
||||||
divemode_loop loop(*dc);
|
gasmix_loop loop_gas(*dive, *dc);
|
||||||
|
divemode_loop loop_mode(*dc);
|
||||||
for (auto &sample: dc->samples) {
|
for (auto &sample: dc->samples) {
|
||||||
o2pressure_t setpoint = psample ? psample->setpoint
|
o2pressure_t setpoint = psample ? psample->setpoint
|
||||||
: sample.setpoint;
|
: sample.setpoint;
|
||||||
|
@ -156,7 +157,8 @@ static int tissue_at_end(struct deco_state *ds, struct dive *dive, const struct
|
||||||
ds->max_bottom_ceiling_pressure.mbar = ceiling_pressure.mbar;
|
ds->max_bottom_ceiling_pressure.mbar = ceiling_pressure.mbar;
|
||||||
}
|
}
|
||||||
|
|
||||||
divemode_t divemode = loop.at(t0.seconds + 1);
|
[[maybe_unused]] auto [divemode, _cylinder_index, _gasmix] = get_dive_status_at(*dive, *dc, t0.seconds + 1, &loop_mode, &loop_gas);
|
||||||
|
|
||||||
interpolate_transition(ds, dive, t0, t1, lastdepth, sample.depth, gas, setpoint, divemode);
|
interpolate_transition(ds, dive, t0, t1, lastdepth, sample.depth, gas, setpoint, divemode);
|
||||||
psample = &sample;
|
psample = &sample;
|
||||||
t0 = t1;
|
t0 = t1;
|
||||||
|
@ -606,7 +608,7 @@ std::vector<decostop> plan(struct deco_state *ds, struct diveplan &diveplan, str
|
||||||
deco_state_cache bottom_cache;
|
deco_state_cache bottom_cache;
|
||||||
int po2;
|
int po2;
|
||||||
int transitiontime, gi;
|
int transitiontime, gi;
|
||||||
int current_cylinder, stop_cylinder;
|
int stop_cylinder;
|
||||||
size_t stopidx;
|
size_t stopidx;
|
||||||
bool stopping = false;
|
bool stopping = false;
|
||||||
bool pendinggaschange = false;
|
bool pendinggaschange = false;
|
||||||
|
@ -622,7 +624,6 @@ std::vector<decostop> plan(struct deco_state *ds, struct diveplan &diveplan, str
|
||||||
int laststoptime = timestep;
|
int laststoptime = timestep;
|
||||||
bool o2breaking = false;
|
bool o2breaking = false;
|
||||||
struct divecomputer *dc = dive->get_dc(dcNr);
|
struct divecomputer *dc = dive->get_dc(dcNr);
|
||||||
enum divemode_t divemode = dc->divemode;
|
|
||||||
|
|
||||||
set_gf(diveplan.gflow, diveplan.gfhigh);
|
set_gf(diveplan.gflow, diveplan.gfhigh);
|
||||||
set_vpmb_conservatism(diveplan.vpmb_conservatism);
|
set_vpmb_conservatism(diveplan.vpmb_conservatism);
|
||||||
|
@ -661,11 +662,9 @@ std::vector<decostop> plan(struct deco_state *ds, struct diveplan &diveplan, str
|
||||||
/* Keep time during the ascend */
|
/* Keep time during the ascend */
|
||||||
bottom_time = clock = previous_point_time = sample.time.seconds;
|
bottom_time = clock = previous_point_time = sample.time.seconds;
|
||||||
|
|
||||||
current_cylinder = get_cylinderid_at_time(dive, dc, sample.time);
|
|
||||||
// Find the divemode at the end of the dive
|
// Find the divemode at the end of the dive
|
||||||
divemode_loop loop(*dc);
|
[[maybe_unused]] auto [divemode, current_cylinder, gasmix] = get_dive_status_at(*dive, *dc, bottom_time);
|
||||||
divemode = loop.at(bottom_time);
|
gas = *gasmix;
|
||||||
gas = dive->get_cylinder(current_cylinder)->gasmix;
|
|
||||||
|
|
||||||
po2 = sample.setpoint.mbar;
|
po2 = sample.setpoint.mbar;
|
||||||
depth_t depth = sample.depth;
|
depth_t depth = sample.depth;
|
||||||
|
|
|
@ -588,7 +588,7 @@ void diveplan::add_plan_to_notes(struct dive &dive, bool show_disclaimer, planne
|
||||||
std::string temp;
|
std::string temp;
|
||||||
struct gasmix gasmix = dive.get_cylinder(dp.cylinderid)->gasmix;
|
struct gasmix gasmix = dive.get_cylinder(dp.cylinderid)->gasmix;
|
||||||
|
|
||||||
divemode_t current_divemode = loop.at(dp.time);
|
divemode_t current_divemode = loop.at(dp.time).first;
|
||||||
amb = dive.depth_to_atm(dp.depth);
|
amb = dive.depth_to_atm(dp.depth);
|
||||||
gas_pressures pressures = fill_pressures(amb, gasmix, (current_divemode == OC) ? 0.0 : amb * gasmix.o2.permille / 1000.0, current_divemode);
|
gas_pressures pressures = fill_pressures(amb, gasmix, (current_divemode == OC) ? 0.0 : amb * gasmix.o2.permille / 1000.0, current_divemode);
|
||||||
|
|
||||||
|
|
|
@ -865,8 +865,8 @@ static void calculate_deco_information(struct deco_state *ds, const struct deco_
|
||||||
if (decoMode(in_planner) == VPMB)
|
if (decoMode(in_planner) == VPMB)
|
||||||
ds->first_ceiling_pressure.mbar = dive->depth_to_mbar(first_ceiling);
|
ds->first_ceiling_pressure.mbar = dive->depth_to_mbar(first_ceiling);
|
||||||
|
|
||||||
gasmix_loop loop(*dive, *dc);
|
gasmix_loop loop_gas(*dive, *dc);
|
||||||
divemode_loop loop_d(*dc);
|
divemode_loop loop_mode(*dc);
|
||||||
for (i = 1; i < pi.nr; i++) {
|
for (i = 1; i < pi.nr; i++) {
|
||||||
struct plot_data &entry = pi.entry[i];
|
struct plot_data &entry = pi.entry[i];
|
||||||
struct plot_data &prev = pi.entry[i - 1];
|
struct plot_data &prev = pi.entry[i - 1];
|
||||||
|
@ -874,8 +874,8 @@ static void calculate_deco_information(struct deco_state *ds, const struct deco_
|
||||||
int time_stepsize = 20;
|
int time_stepsize = 20;
|
||||||
depth_t max_ceiling;
|
depth_t max_ceiling;
|
||||||
|
|
||||||
divemode_t current_divemode = loop_d.at(entry.sec);
|
[[maybe_unused]] auto [current_divemode, _cylinder_index, gasmix] = get_dive_status_at(*dive, *dc, entry.sec, &loop_mode, &loop_gas);
|
||||||
struct gasmix gasmix = loop.at(t1).first;
|
|
||||||
entry.ambpressure = dive->depth_to_bar(entry.depth);
|
entry.ambpressure = dive->depth_to_bar(entry.depth);
|
||||||
entry.gfline = get_gf(ds, entry.ambpressure, dive) * (100.0 - AMB_PERCENTAGE) + AMB_PERCENTAGE;
|
entry.gfline = get_gf(ds, entry.ambpressure, dive) * (100.0 - AMB_PERCENTAGE) + AMB_PERCENTAGE;
|
||||||
if (t0 > t1) {
|
if (t0 > t1) {
|
||||||
|
@ -887,7 +887,7 @@ static void calculate_deco_information(struct deco_state *ds, const struct deco_
|
||||||
for (int j = t0 + time_stepsize; j <= t1; j += time_stepsize) {
|
for (int j = t0 + time_stepsize; j <= t1; j += time_stepsize) {
|
||||||
depth_t new_depth = interpolate(prev.depth, entry.depth, j - t0, t1 - t0);
|
depth_t new_depth = interpolate(prev.depth, entry.depth, j - t0, t1 - t0);
|
||||||
add_segment(ds, dive->depth_to_bar(new_depth),
|
add_segment(ds, dive->depth_to_bar(new_depth),
|
||||||
gasmix, time_stepsize, entry.o2pressure.mbar, current_divemode, entry.sac, in_planner);
|
*gasmix, time_stepsize, entry.o2pressure.mbar, current_divemode, entry.sac, in_planner);
|
||||||
entry.icd_warning = ds->icd_warning;
|
entry.icd_warning = ds->icd_warning;
|
||||||
if ((t1 - j < time_stepsize) && (j < t1))
|
if ((t1 - j < time_stepsize) && (j < t1))
|
||||||
time_stepsize = t1 - j;
|
time_stepsize = t1 - j;
|
||||||
|
@ -987,7 +987,7 @@ static void calculate_deco_information(struct deco_state *ds, const struct deco_
|
||||||
/* We are going to mess up deco state, so store it for later restore */
|
/* We are going to mess up deco state, so store it for later restore */
|
||||||
deco_state_cache cache_data;
|
deco_state_cache cache_data;
|
||||||
cache_data.cache(ds);
|
cache_data.cache(ds);
|
||||||
calculate_ndl_tts(ds, dive, entry, gasmix, surface_pressure, current_divemode, in_planner);
|
calculate_ndl_tts(ds, dive, entry, *gasmix, surface_pressure, current_divemode, in_planner);
|
||||||
if (decoMode(in_planner) == VPMB && !in_planner && i == pi.nr - 1)
|
if (decoMode(in_planner) == VPMB && !in_planner && i == pi.nr - 1)
|
||||||
final_tts = entry.tts_calc;
|
final_tts = entry.tts_calc;
|
||||||
/* Restore "real" deco state for next real time step */
|
/* Restore "real" deco state for next real time step */
|
||||||
|
@ -1104,21 +1104,19 @@ static void calculate_gas_information_new(const struct dive *dive, const struct
|
||||||
int i;
|
int i;
|
||||||
double amb_pressure;
|
double amb_pressure;
|
||||||
|
|
||||||
gasmix_loop loop(*dive, *dc);
|
gasmix_loop loop_gas(*dive, *dc);
|
||||||
divemode_loop loop_d(*dc);
|
divemode_loop loop_mode(*dc);
|
||||||
for (i = 1; i < pi.nr; i++) {
|
for (i = 1; i < pi.nr; i++) {
|
||||||
double fn2, fhe;
|
double fn2, fhe;
|
||||||
struct plot_data &entry = pi.entry[i];
|
struct plot_data &entry = pi.entry[i];
|
||||||
|
|
||||||
auto gasmix = loop.at(entry.sec).first;
|
[[maybe_unused]] auto [current_divemode, _cylinder_index, gasmix] = get_dive_status_at(*dive, *dc, entry.sec, &loop_mode, &loop_gas);
|
||||||
amb_pressure = dive->depth_to_bar(entry.depth);
|
amb_pressure = dive->depth_to_bar(entry.depth);
|
||||||
divemode_t current_divemode = loop_d.at(entry.sec);
|
entry.pressures = fill_pressures(amb_pressure, *gasmix, (current_divemode == OC) ? 0.0 : entry.o2pressure.mbar / 1000.0, current_divemode);
|
||||||
entry.pressures = fill_pressures(amb_pressure, gasmix, (current_divemode == OC) ? 0.0 : entry.o2pressure.mbar / 1000.0, current_divemode);
|
|
||||||
fn2 = 1000.0 * entry.pressures.n2 / amb_pressure;
|
fn2 = 1000.0 * entry.pressures.n2 / amb_pressure;
|
||||||
fhe = 1000.0 * entry.pressures.he / amb_pressure;
|
fhe = 1000.0 * entry.pressures.he / amb_pressure;
|
||||||
if (dc->divemode == PSCR) { // OC pO2 is calulated for PSCR with or without external PO2 monitoring.
|
if (dc->divemode == PSCR) { // OC pO2 is calulated for PSCR with or without external PO2 monitoring.
|
||||||
struct gasmix gasmix2 = loop.at(entry.sec).first;
|
entry.scr_OC_pO2.mbar = (int) dive->depth_to_mbar(entry.depth) * get_o2(*gasmix) / 1000;
|
||||||
entry.scr_OC_pO2.mbar = (int) dive->depth_to_mbar(entry.depth) * get_o2(gasmix2) / 1000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate MOD, EAD, END and EADD based on partial pressures calculated before
|
/* Calculate MOD, EAD, END and EADD based on partial pressures calculated before
|
||||||
|
@ -1126,7 +1124,7 @@ static void calculate_gas_information_new(const struct dive *dive, const struct
|
||||||
* END takes O₂ + N₂ (air) into account ("Narcotic" for trimix dives)
|
* END takes O₂ + N₂ (air) into account ("Narcotic" for trimix dives)
|
||||||
* EAD just uses N₂ ("Air" for nitrox dives) */
|
* EAD just uses N₂ ("Air" for nitrox dives) */
|
||||||
pressure_t modpO2 = { .mbar = (int)(prefs.modpO2 * 1000) };
|
pressure_t modpO2 = { .mbar = (int)(prefs.modpO2 * 1000) };
|
||||||
entry.mod = dive->gas_mod(gasmix, modpO2, 1_mm);
|
entry.mod = dive->gas_mod(*gasmix, modpO2, 1_mm);
|
||||||
entry.end = dive->mbar_to_depth(lrint(dive->depth_to_mbarf(entry.depth) * (1000 - fhe) / 1000.0));
|
entry.end = dive->mbar_to_depth(lrint(dive->depth_to_mbarf(entry.depth) * (1000 - fhe) / 1000.0));
|
||||||
entry.ead = dive->mbar_to_depth(lrint(dive->depth_to_mbarf(entry.depth) * fn2 / (double)N2_IN_AIR));
|
entry.ead = dive->mbar_to_depth(lrint(dive->depth_to_mbarf(entry.depth) * fn2 / (double)N2_IN_AIR));
|
||||||
entry.eadd = dive->mbar_to_depth(lrint(dive->depth_to_mbarf(entry.depth) *
|
entry.eadd = dive->mbar_to_depth(lrint(dive->depth_to_mbarf(entry.depth) *
|
||||||
|
|
|
@ -373,7 +373,7 @@ static void save_samples(struct membuffer *b, const struct dive &dive, const str
|
||||||
save_sample(b, s, dummy, o2sensor);
|
save_sample(b, s, dummy, o2sensor);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void save_one_event(struct membuffer *b, const struct dive &dive, const struct event &ev)
|
static void save_one_event(struct membuffer *b, const struct dive &dive, const struct divecomputer &dc, const struct event &ev)
|
||||||
{
|
{
|
||||||
put_format(b, "event %d:%02d", FRACTION_TUPLE(ev.time.seconds, 60));
|
put_format(b, "event %d:%02d", FRACTION_TUPLE(ev.time.seconds, 60));
|
||||||
show_index(b, ev.type, "type=", "");
|
show_index(b, ev.type, "type=", "");
|
||||||
|
@ -385,7 +385,7 @@ static void save_one_event(struct membuffer *b, const struct dive &dive, const s
|
||||||
show_index(b, ev.value, "value=", "");
|
show_index(b, ev.value, "value=", "");
|
||||||
show_utf8(b, " name=", ev.name.c_str(), "");
|
show_utf8(b, " name=", ev.name.c_str(), "");
|
||||||
if (ev.is_gaschange()) {
|
if (ev.is_gaschange()) {
|
||||||
struct gasmix mix = dive.get_gasmix_from_event(ev);
|
struct gasmix mix = dive.get_gasmix_from_event(ev, dc).first;
|
||||||
if (ev.gas.index >= 0)
|
if (ev.gas.index >= 0)
|
||||||
show_integer(b, ev.gas.index, "cylinder=", "");
|
show_integer(b, ev.gas.index, "cylinder=", "");
|
||||||
put_gasmix(b, mix);
|
put_gasmix(b, mix);
|
||||||
|
@ -396,7 +396,7 @@ static void save_one_event(struct membuffer *b, const struct dive &dive, const s
|
||||||
static void save_events(struct membuffer *b, const struct dive &dive, const struct divecomputer &dc)
|
static void save_events(struct membuffer *b, const struct dive &dive, const struct divecomputer &dc)
|
||||||
{
|
{
|
||||||
for (auto &ev: dc.events)
|
for (auto &ev: dc.events)
|
||||||
save_one_event(b, dive, ev);
|
save_one_event(b, dive, dc, ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void save_dc(struct membuffer *b, const struct dive &dive, const struct divecomputer &dc)
|
static void save_dc(struct membuffer *b, const struct dive &dive, const struct divecomputer &dc)
|
||||||
|
|
|
@ -342,7 +342,7 @@ static void save_sample(struct membuffer *b, const struct sample &sample, struct
|
||||||
put_format(b, " />\n");
|
put_format(b, " />\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void save_one_event(struct membuffer *b, const struct dive &dive, const struct event &ev)
|
static void save_one_event(struct membuffer *b, const struct dive &dive, const struct divecomputer &dc, const struct event &ev)
|
||||||
{
|
{
|
||||||
put_format(b, " <event time='%d:%02d min'", FRACTION_TUPLE(ev.time.seconds, 60));
|
put_format(b, " <event time='%d:%02d min'", FRACTION_TUPLE(ev.time.seconds, 60));
|
||||||
show_index(b, ev.type, "type='", "'");
|
show_index(b, ev.type, "type='", "'");
|
||||||
|
@ -353,7 +353,7 @@ static void save_one_event(struct membuffer *b, const struct dive &dive, const s
|
||||||
show_index(b, ev.value, "value='", "'");
|
show_index(b, ev.value, "value='", "'");
|
||||||
show_utf8(b, ev.name.c_str(), " name='", "'", 1);
|
show_utf8(b, ev.name.c_str(), " name='", "'", 1);
|
||||||
if (ev.is_gaschange()) {
|
if (ev.is_gaschange()) {
|
||||||
struct gasmix mix = dive.get_gasmix_from_event(ev);
|
struct gasmix mix = dive.get_gasmix_from_event(ev, dc).first;
|
||||||
if (ev.gas.index >= 0)
|
if (ev.gas.index >= 0)
|
||||||
show_integer(b, ev.gas.index, "cylinder='", "'");
|
show_integer(b, ev.gas.index, "cylinder='", "'");
|
||||||
put_gasmix(b, mix);
|
put_gasmix(b, mix);
|
||||||
|
@ -365,7 +365,7 @@ static void save_one_event(struct membuffer *b, const struct dive &dive, const s
|
||||||
static void save_events(struct membuffer *b, const struct dive &dive, const struct divecomputer &dc)
|
static void save_events(struct membuffer *b, const struct dive &dive, const struct divecomputer &dc)
|
||||||
{
|
{
|
||||||
for (auto &ev: dc.events)
|
for (auto &ev: dc.events)
|
||||||
save_one_event(b, dive, ev);
|
save_one_event(b, dive, dc, ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void save_tags(struct membuffer *b, const tag_list &tags)
|
static void save_tags(struct membuffer *b, const tag_list &tags)
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
static int depthAtTime(const plot_info &pi, duration_t time);
|
static int depthAtTime(const plot_info &pi, duration_t time);
|
||||||
|
|
||||||
DiveEventItem::DiveEventItem(const struct dive *d, int idx, const struct event &ev, struct gasmix lastgasmix,
|
DiveEventItem::DiveEventItem(const struct dive *d, const struct divecomputer *dc, int idx, const struct event &ev, const struct gasmix lastgasmix, divemode_t lastdivemode,
|
||||||
const plot_info &pi, DiveCartesianAxis *hAxis, DiveCartesianAxis *vAxis,
|
const plot_info &pi, DiveCartesianAxis *hAxis, DiveCartesianAxis *vAxis,
|
||||||
int speed, const DivePixmaps &pixmaps, QGraphicsItem *parent) : DivePixmapItem(parent),
|
int speed, const DivePixmaps &pixmaps, QGraphicsItem *parent) : DivePixmapItem(parent),
|
||||||
vAxis(vAxis),
|
vAxis(vAxis),
|
||||||
|
@ -28,8 +28,8 @@ DiveEventItem::DiveEventItem(const struct dive *d, int idx, const struct event &
|
||||||
{
|
{
|
||||||
setFlag(ItemIgnoresTransformations);
|
setFlag(ItemIgnoresTransformations);
|
||||||
|
|
||||||
setupPixmap(lastgasmix, pixmaps);
|
setupPixmap(lastgasmix, lastdivemode, *dc, pixmaps);
|
||||||
setupToolTipString(lastgasmix);
|
setupToolTipString(lastgasmix, lastdivemode, *dc);
|
||||||
recalculatePos();
|
recalculatePos();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ DiveEventItem::~DiveEventItem()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiveEventItem::setupPixmap(struct gasmix lastgasmix, const DivePixmaps &pixmaps)
|
void DiveEventItem::setupPixmap(const struct gasmix lastgasmix, divemode_t lastdivemode, const struct divecomputer &dc, const DivePixmaps &pixmaps)
|
||||||
{
|
{
|
||||||
event_severity severity = ev.get_severity();
|
event_severity severity = ev.get_severity();
|
||||||
if (ev.name.empty()) {
|
if (ev.name.empty()) {
|
||||||
|
@ -51,10 +51,15 @@ void DiveEventItem::setupPixmap(struct gasmix lastgasmix, const DivePixmaps &pix
|
||||||
setPixmap(pixmaps.bookmark);
|
setPixmap(pixmaps.bookmark);
|
||||||
setOffset(QPointF(0.0, -pixmap().height()));
|
setOffset(QPointF(0.0, -pixmap().height()));
|
||||||
} else if (ev.is_gaschange()) {
|
} else if (ev.is_gaschange()) {
|
||||||
struct gasmix mix = dive->get_gasmix_from_event(ev);
|
auto [mix, divemode] = dive->get_gasmix_from_event(ev, dc);
|
||||||
struct icd_data icd_data;
|
struct icd_data icd_data;
|
||||||
bool icd = isobaric_counterdiffusion(lastgasmix, mix, &icd_data);
|
bool icd = isobaric_counterdiffusion(lastgasmix, mix, &icd_data);
|
||||||
if (mix.he.permille) {
|
if (divemode != lastdivemode) {
|
||||||
|
if (divemode == CCR)
|
||||||
|
setPixmap(pixmaps.onCCRLoop);
|
||||||
|
else
|
||||||
|
setPixmap(pixmaps.bailout);
|
||||||
|
} else if (mix.he.permille) {
|
||||||
if (icd)
|
if (icd)
|
||||||
setPixmap(pixmaps.gaschangeTrimixICD);
|
setPixmap(pixmaps.gaschangeTrimixICD);
|
||||||
else
|
else
|
||||||
|
@ -111,7 +116,7 @@ void DiveEventItem::setupPixmap(struct gasmix lastgasmix, const DivePixmaps &pix
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiveEventItem::setupToolTipString(struct gasmix lastgasmix)
|
void DiveEventItem::setupToolTipString(const struct gasmix lastgasmix, divemode_t lastdivemode, const struct divecomputer &dc)
|
||||||
{
|
{
|
||||||
// we display the event on screen - so translate
|
// we display the event on screen - so translate
|
||||||
QString name = gettextFromC::tr(ev.name.c_str());
|
QString name = gettextFromC::tr(ev.name.c_str());
|
||||||
|
@ -120,7 +125,7 @@ void DiveEventItem::setupToolTipString(struct gasmix lastgasmix)
|
||||||
|
|
||||||
if (ev.is_gaschange()) {
|
if (ev.is_gaschange()) {
|
||||||
struct icd_data icd_data;
|
struct icd_data icd_data;
|
||||||
struct gasmix mix = dive->get_gasmix_from_event(ev);
|
auto [mix, divemode] = dive->get_gasmix_from_event(ev, dc);
|
||||||
name += ": ";
|
name += ": ";
|
||||||
name += QString::fromStdString(mix.name());
|
name += QString::fromStdString(mix.name());
|
||||||
|
|
||||||
|
@ -135,6 +140,9 @@ void DiveEventItem::setupToolTipString(struct gasmix lastgasmix)
|
||||||
qPrintable(tr("ΔN₂")), icd_data.dN2 / 10.0,
|
qPrintable(tr("ΔN₂")), icd_data.dN2 / 10.0,
|
||||||
icd ? ">" : "<", lrint(-icd_data.dHe / 5.0) / 10.0);
|
icd ? ">" : "<", lrint(-icd_data.dHe / 5.0) / 10.0);
|
||||||
}
|
}
|
||||||
|
if (divemode != lastdivemode)
|
||||||
|
name += QString("\nmodechange: %1").arg(gettextFromC::tr(divemode_text_ui[divemode != OC]));
|
||||||
|
|
||||||
} else if (ev.name == "modechange") {
|
} else if (ev.name == "modechange") {
|
||||||
name += QString(": %1").arg(gettextFromC::tr(divemode_text_ui[ev.value]));
|
name += QString(": %1").arg(gettextFromC::tr(divemode_text_ui[ev.value]));
|
||||||
} else if (value) {
|
} else if (value) {
|
||||||
|
|
|
@ -13,7 +13,7 @@ struct plot_info;
|
||||||
class DiveEventItem : public DivePixmapItem {
|
class DiveEventItem : public DivePixmapItem {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
DiveEventItem(const struct dive *d, int idx, const struct event &ev, struct gasmix lastgasmix,
|
DiveEventItem(const struct dive *d, const struct divecomputer *dc, int idx, const struct event &ev, const struct gasmix lastgasmix, divemode_t lastdivemode,
|
||||||
const struct plot_info &pi, DiveCartesianAxis *hAxis, DiveCartesianAxis *vAxis,
|
const struct plot_info &pi, DiveCartesianAxis *hAxis, DiveCartesianAxis *vAxis,
|
||||||
int speed, const DivePixmaps &pixmaps, QGraphicsItem *parent = nullptr);
|
int speed, const DivePixmaps &pixmaps, QGraphicsItem *parent = nullptr);
|
||||||
~DiveEventItem();
|
~DiveEventItem();
|
||||||
|
@ -25,8 +25,8 @@ public:
|
||||||
int firstSecond, int lastSecond);
|
int firstSecond, int lastSecond);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupToolTipString(struct gasmix lastgasmix);
|
void setupToolTipString(struct gasmix lastgasmix, divemode_t lastdivemode, const struct divecomputer &dc);
|
||||||
void setupPixmap(struct gasmix lastgasmix, const DivePixmaps &pixmaps);
|
void setupPixmap(struct gasmix lastgasmix, divemode_t lastdivemode, const struct divecomputer &dc, const DivePixmaps &pixmaps);
|
||||||
void recalculatePos();
|
void recalculatePos();
|
||||||
DiveCartesianAxis *vAxis;
|
DiveCartesianAxis *vAxis;
|
||||||
DiveCartesianAxis *hAxis;
|
DiveCartesianAxis *hAxis;
|
||||||
|
|
|
@ -551,8 +551,17 @@ void ProfileScene::plotDive(const struct dive *dIn, int dcIn, DivePlannerPointsM
|
||||||
// while all other items are up there on the constructor.
|
// while all other items are up there on the constructor.
|
||||||
qDeleteAll(eventItems);
|
qDeleteAll(eventItems);
|
||||||
eventItems.clear();
|
eventItems.clear();
|
||||||
struct gasmix lastgasmix = d->get_gasmix_at_time(*currentdc, 1_sec);
|
const struct gasmix *lastgasmix;
|
||||||
|
divemode_t lastdivemode;
|
||||||
|
int cylinder_index = gasmix_loop(*d, *currentdc).next_cylinder_index().first;
|
||||||
|
if (cylinder_index == -1) {
|
||||||
|
lastgasmix = &gasmix_air;
|
||||||
|
lastdivemode = OC;
|
||||||
|
} else {
|
||||||
|
const cylinder_t *cylinder = d->get_cylinder(cylinder_index);
|
||||||
|
lastgasmix = &cylinder->gasmix;
|
||||||
|
lastdivemode = get_effective_divemode(*currentdc, *cylinder);
|
||||||
|
}
|
||||||
for (auto [idx, event]: enumerated_range(currentdc->events)) {
|
for (auto [idx, event]: enumerated_range(currentdc->events)) {
|
||||||
// if print mode is selected only draw headings, SP change, gas events or bookmark event
|
// if print mode is selected only draw headings, SP change, gas events or bookmark event
|
||||||
if (printMode) {
|
if (printMode) {
|
||||||
|
@ -560,18 +569,23 @@ void ProfileScene::plotDive(const struct dive *dIn, int dcIn, DivePlannerPointsM
|
||||||
!(event.name == "heading" ||
|
!(event.name == "heading" ||
|
||||||
(event.name == "SP change" && event.time.seconds == 0) ||
|
(event.name == "SP change" && event.time.seconds == 0) ||
|
||||||
event.is_gaschange() ||
|
event.is_gaschange() ||
|
||||||
|
event.is_divemodechange() ||
|
||||||
event.type == SAMPLE_EVENT_BOOKMARK))
|
event.type == SAMPLE_EVENT_BOOKMARK))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (DiveEventItem::isInteresting(d, currentdc, event, plotInfo, firstSecond, lastSecond)) {
|
if (DiveEventItem::isInteresting(d, currentdc, event, plotInfo, firstSecond, lastSecond)) {
|
||||||
auto item = new DiveEventItem(d, idx, event, lastgasmix, plotInfo,
|
auto item = new DiveEventItem(d, currentdc, idx, event, *lastgasmix, lastdivemode, plotInfo,
|
||||||
timeAxis, profileYAxis, animSpeed, *pixmaps);
|
timeAxis, profileYAxis, animSpeed, *pixmaps);
|
||||||
item->setZValue(2);
|
item->setZValue(2);
|
||||||
addItem(item);
|
addItem(item);
|
||||||
eventItems.push_back(item);
|
eventItems.push_back(item);
|
||||||
}
|
}
|
||||||
if (event.is_gaschange())
|
if (event.is_gaschange()) {
|
||||||
lastgasmix = d->get_gasmix_from_event(event);
|
auto [gasmix, divemode] = d->get_gasmix_from_event(event, *currentdc);
|
||||||
|
lastgasmix = &gasmix;
|
||||||
|
lastdivemode = divemode;
|
||||||
|
} else if (event.is_divemodechange())
|
||||||
|
lastdivemode = event.value ? CCR : OC;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString dcText = QString::fromStdString(get_dc_nickname(currentdc));
|
QString dcText = QString::fromStdString(get_dc_nickname(currentdc));
|
||||||
|
|
|
@ -529,10 +529,11 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
|
||||||
QMenu m;
|
QMenu m;
|
||||||
if (!d)
|
if (!d)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
const struct divecomputer *currentdc = d->get_dc(dc);
|
||||||
// figure out if we are ontop of the dive computer name in the profile
|
// figure out if we are ontop of the dive computer name in the profile
|
||||||
QGraphicsItem *sceneItem = itemAt(mapFromGlobal(event->globalPos()));
|
QGraphicsItem *sceneItem = itemAt(mapFromGlobal(event->globalPos()));
|
||||||
if (isDiveTextItem(sceneItem, profileScene->diveComputerText)) {
|
if (isDiveTextItem(sceneItem, profileScene->diveComputerText)) {
|
||||||
const struct divecomputer *currentdc = d->get_dc(dc);
|
|
||||||
if (!currentdc->deviceid && dc == 0 && d->number_of_computers() == 1)
|
if (!currentdc->deviceid && dc == 0 && d->number_of_computers() == 1)
|
||||||
// nothing to do, can't rename, delete or reorder
|
// nothing to do, can't rename, delete or reorder
|
||||||
return;
|
return;
|
||||||
|
@ -561,7 +562,6 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
|
||||||
addGasChangeMenu(m, tr("Edit gas change"), *d, dc, item->ev.time.seconds);
|
addGasChangeMenu(m, tr("Edit gas change"), *d, dc, item->ev.time.seconds);
|
||||||
} else if (d && d->cylinders.size() > 1) {
|
} else if (d && d->cylinders.size() > 1) {
|
||||||
// if we have more than one gas, offer to switch to another one
|
// if we have more than one gas, offer to switch to another one
|
||||||
const struct divecomputer *currentdc = d->get_dc(dc);
|
|
||||||
if (seconds == 0 || (!currentdc->samples.empty() && seconds <= currentdc->samples[0].time.seconds))
|
if (seconds == 0 || (!currentdc->samples.empty() && seconds <= currentdc->samples[0].time.seconds))
|
||||||
addGasChangeMenu(m, tr("Set initial gas"), *d, dc, 0);
|
addGasChangeMenu(m, tr("Set initial gas"), *d, dc, 0);
|
||||||
else
|
else
|
||||||
|
@ -571,18 +571,21 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
|
||||||
m.addAction(tr("Add bookmark"), [this, seconds]() { addBookmark(seconds); });
|
m.addAction(tr("Add bookmark"), [this, seconds]() { addBookmark(seconds); });
|
||||||
m.addAction(tr("Split dive into two"), [this, seconds]() { splitDive(seconds); });
|
m.addAction(tr("Split dive into two"), [this, seconds]() { splitDive(seconds); });
|
||||||
|
|
||||||
divemode_loop loop(*d->get_dc(dc));
|
[[maybe_unused]] auto [divemode, cylinder_index, _gasmix] = get_dive_status_at(*d, *currentdc, seconds);
|
||||||
divemode_t divemode = loop.at(seconds);
|
if (currentdc->divemode == PSCR || (currentdc->divemode == CCR && prefs.allowOcGasAsDiluent && (cylinder_index == -1 || d->get_cylinder(cylinder_index)->cylinder_use == OC_GAS))) {
|
||||||
QMenu *changeMode = m.addMenu(tr("Change divemode"));
|
QMenu *changeMode = m.addMenu(tr("Change divemode"));
|
||||||
if (divemode != OC)
|
if (divemode != OC) {
|
||||||
changeMode->addAction(gettextFromC::tr(divemode_text_ui[OC]),
|
changeMode->addAction(gettextFromC::tr(divemode_text_ui[OC]),
|
||||||
[this, seconds](){ addDivemodeSwitch(seconds, OC); });
|
[this, seconds](){ addDivemodeSwitch(seconds, OC); });
|
||||||
if (divemode != CCR)
|
} else {
|
||||||
changeMode->addAction(gettextFromC::tr(divemode_text_ui[CCR]),
|
if (currentdc->divemode == PSCR)
|
||||||
[this, seconds](){ addDivemodeSwitch(seconds, CCR); });
|
changeMode->addAction(gettextFromC::tr(divemode_text_ui[PSCR]),
|
||||||
if (divemode != PSCR)
|
[this, seconds](){ addDivemodeSwitch(seconds, PSCR); });
|
||||||
changeMode->addAction(gettextFromC::tr(divemode_text_ui[PSCR]),
|
else
|
||||||
[this, seconds](){ addDivemodeSwitch(seconds, PSCR); });
|
changeMode->addAction(gettextFromC::tr(divemode_text_ui[CCR]),
|
||||||
|
[this, seconds](){ addDivemodeSwitch(seconds, CCR); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (DiveEventItem *item = dynamic_cast<DiveEventItem *>(sceneItem)) {
|
if (DiveEventItem *item = dynamic_cast<DiveEventItem *>(sceneItem)) {
|
||||||
m.addAction(tr("Remove event"), [this,item] { removeEvent(item); });
|
m.addAction(tr("Remove event"), [this,item] { removeEvent(item); });
|
||||||
|
@ -639,7 +642,6 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
|
||||||
}
|
}
|
||||||
m2->addAction(tr("All event types"), this, &ProfileWidget2::unhideEventTypes);
|
m2->addAction(tr("All event types"), this, &ProfileWidget2::unhideEventTypes);
|
||||||
}
|
}
|
||||||
const struct divecomputer *currentdc = d->get_dc(dc);
|
|
||||||
if (currentdc && std::any_of(currentdc->events.begin(), currentdc->events.end(),
|
if (currentdc && std::any_of(currentdc->events.begin(), currentdc->events.end(),
|
||||||
[] (auto &ev) { return ev.hidden; }))
|
[] (auto &ev) { return ev.hidden; }))
|
||||||
m.addAction(tr("Unhide individually hidden events of this dive"), this, &ProfileWidget2::unhideEvents);
|
m.addAction(tr("Unhide individually hidden events of this dive"), this, &ProfileWidget2::unhideEvents);
|
||||||
|
|
|
@ -150,7 +150,8 @@ void DivePlannerPointsModel::loadFromDive(dive *dIn, int dcNrIn)
|
||||||
int j = 0;
|
int j = 0;
|
||||||
int cylinderid = 0;
|
int cylinderid = 0;
|
||||||
|
|
||||||
divemode_loop loop(*dc);
|
gasmix_loop loop_gas(*d, *dc);
|
||||||
|
divemode_loop loop_mode(*dc);
|
||||||
for (int i = 0; i < plansamples - 1; i++) {
|
for (int i = 0; i < plansamples - 1; i++) {
|
||||||
if (dc->last_manual_time.seconds && dc->last_manual_time.seconds > 120 && lasttime.seconds >= dc->last_manual_time.seconds)
|
if (dc->last_manual_time.seconds && dc->last_manual_time.seconds > 120 && lasttime.seconds >= dc->last_manual_time.seconds)
|
||||||
break;
|
break;
|
||||||
|
@ -172,7 +173,8 @@ void DivePlannerPointsModel::loadFromDive(dive *dIn, int dcNrIn)
|
||||||
if (newtime.seconds - lastrecordedtime.seconds > 10 || cylinderid == get_cylinderid_at_time(d, dc, nexttime)) {
|
if (newtime.seconds - lastrecordedtime.seconds > 10 || cylinderid == get_cylinderid_at_time(d, dc, nexttime)) {
|
||||||
if (newtime.seconds == lastrecordedtime.seconds)
|
if (newtime.seconds == lastrecordedtime.seconds)
|
||||||
newtime.seconds += 10;
|
newtime.seconds += 10;
|
||||||
divemode_t current_divemode = loop.at(newtime.seconds - 1);
|
|
||||||
|
[[maybe_unused]] auto [current_divemode, _cylinder_index, _gasmix] = get_dive_status_at(*d, *dc, newtime.seconds - 1, &loop_mode, &loop_gas);
|
||||||
addStop(depthsum / samplecount, newtime.seconds, cylinderid, last_sp.mbar, true, current_divemode);
|
addStop(depthsum / samplecount, newtime.seconds, cylinderid, last_sp.mbar, true, current_divemode);
|
||||||
lastrecordedtime = newtime;
|
lastrecordedtime = newtime;
|
||||||
}
|
}
|
||||||
|
@ -182,9 +184,9 @@ void DivePlannerPointsModel::loadFromDive(dive *dIn, int dcNrIn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// make sure we get the last point right so the duration is correct
|
// make sure we get the last point right so the duration is correct
|
||||||
divemode_t current_divemode = loop.at(dc->duration.seconds);
|
[[maybe_unused]] auto [current_divemode, _cylinder_index, _gasmix] = get_dive_status_at(*d, *dc, dc->duration.seconds, &loop_mode, &loop_gas);
|
||||||
if (!hasMarkedSamples && !dc->last_manual_time.seconds)
|
if (!hasMarkedSamples && !dc->last_manual_time.seconds)
|
||||||
addStop(0_m, dc->duration.seconds,cylinderid, last_sp.mbar, true, current_divemode);
|
addStop(0_m, dc->duration.seconds, cylinderid, last_sp.mbar, true, current_divemode);
|
||||||
preserved_until = d->duration;
|
preserved_until = d->duration;
|
||||||
|
|
||||||
updateDiveProfile();
|
updateDiveProfile();
|
||||||
|
|
Loading…
Add table
Reference in a new issue