profile: C++-ify plot_info

Use more C++ style memory management for plot_info: Use std::vector
for array data. Return the plot_info instead of filling an output
parameter. Add a constructor/destructor pair so that the caller
isn't bothered with memory management.

The bulk of the commit is replacement of pointers with references,
which is kind of gratuitous. But I started and then went on...

Default initializiation of gas_pressures made it necessary to convert
gas.c to c++, though with minimal changes to the code.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2024-05-03 18:51:03 +02:00 committed by bstoeger
parent aaab5157d4
commit 48f7828d10
14 changed files with 635 additions and 670 deletions

View file

@ -3,6 +3,7 @@
#include "profile-widget/divecartesianaxis.h"
#include "profile-widget/divepixmapcache.h"
#include "profile-widget/animationfunctions.h"
#include "core/dive.h"
#include "core/event.h"
#include "core/eventtype.h"
#include "core/format.h"
@ -177,9 +178,9 @@ void DiveEventItem::eventVisibilityChanged(const QString&, bool)
static int depthAtTime(const plot_info &pi, duration_t time)
{
// Do a binary search for the timestamp
auto it = std::lower_bound(pi.entry, pi.entry + pi.nr, time,
auto it = std::lower_bound(pi.entry.begin(), pi.entry.end(), time,
[](const plot_data &d1, duration_t t) { return d1.sec < t.seconds; });
if (it == pi.entry + pi.nr || it->sec != time.seconds) {
if (it == pi.entry.end() || it->sec != time.seconds) {
qWarning("can't find a spot in the dataModel");
return DEPTH_NOT_FOUND;
}

View file

@ -49,7 +49,7 @@ void AbstractProfilePolygonItem::clipStop(double &x, double &y, double prev_x, d
std::pair<double, double> AbstractProfilePolygonItem::getPoint(int i) const
{
const struct plot_data *data = pInfo.entry;
const auto &data = pInfo.entry;
double x = data[i].sec;
double y = accessor(data[i]);
@ -121,7 +121,7 @@ void DiveProfileItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *o
pen.setCosmetic(true);
pen.setWidth(2);
QPolygonF poly = polygon();
const struct plot_data *data = pInfo.entry;
const auto &data = pInfo.entry;
// This paints the colors of the velocities.
for (int i = from + 1; i < to; i++) {
QColor color = getColor((color_index_t)(VELOCITY_COLORS_START_IDX + data[i].velocity));
@ -150,7 +150,7 @@ void DiveProfileItem::replot(const dive *d, int from, int to, bool in_planner)
/* Show any ceiling we may have encountered */
if (prefs.dcceiling && !prefs.redceiling) {
QPolygonF p = polygon();
plot_data *entry = pInfo.entry + to - 1;
auto entry = pInfo.entry.begin() + (to - 1);
for (int i = to - 1; i >= from; i--, entry--) {
if (!entry->in_deco) {
/* not in deco implies this is a safety stop, no ceiling */
@ -176,7 +176,7 @@ void DiveProfileItem::replot(const dive *d, int from, int to, bool in_planner)
const int half_interval = vAxis.getMinLabelDistance(hAxis);
const int min_depth = 2000; // in mm
const int min_prominence = 2000; // in mm (should this adapt to depth range?)
const plot_data *data = pInfo.entry;
const auto &data = pInfo.entry;
const int max_peaks = (data[to - 1].sec - data[from].sec) / half_interval + 1;
struct Peak {
int range_from;
@ -185,7 +185,7 @@ void DiveProfileItem::replot(const dive *d, int from, int to, bool in_planner)
};
std::vector<Peak> stack;
stack.reserve(max_peaks);
int highest_peak = std::max_element(data + from, data + to, comp_depth) - data;
int highest_peak = std::max_element(data.begin() + from, data.begin() + to, comp_depth) - data.begin();
if (data[highest_peak].depth < min_depth)
return;
stack.push_back(Peak{ from, to, highest_peak });
@ -210,7 +210,7 @@ void DiveProfileItem::replot(const dive *d, int from, int to, bool in_planner)
// Continue search until peaks reach the minimum prominence (height from valley).
for ( ; new_from + 3 < act_peak.range_to; ++new_from) {
if (data[new_from].depth >= data[valley].depth + min_prominence) {
int new_peak = std::max_element(data + new_from, data + act_peak.range_to, comp_depth) - data;
int new_peak = std::max_element(data.begin() + new_from, data.begin() + act_peak.range_to, comp_depth) - data.begin();
if (data[new_peak].depth < min_depth)
break;
stack.push_back(Peak{ new_from, act_peak.range_to, new_peak });
@ -236,7 +236,7 @@ void DiveProfileItem::replot(const dive *d, int from, int to, bool in_planner)
// Continue search until peaks reach the minimum prominence (height from valley).
for ( ; new_to >= act_peak.range_from + 3; --new_to) {
if (data[new_to].depth >= data[valley].depth + min_prominence) {
int new_peak = std::max_element(data + act_peak.range_from, data + new_to, comp_depth) - data;
int new_peak = std::max_element(data.begin() + act_peak.range_from, data.begin() + new_to, comp_depth) - data.begin();
if (data[new_peak].depth < min_depth)
break;
stack.push_back(Peak{ act_peak.range_from, new_to, new_peak });
@ -533,17 +533,17 @@ void DiveGasPressureItem::replot(const dive *d, int fromIn, int toIn, bool in_pl
segments.clear();
for (int i = from; i < to; i++) {
const struct plot_data *entry = pInfo.entry + i;
auto entry = pInfo.entry.begin() + i;
for (int cyl = 0; cyl < pInfo.nr_cylinders; cyl++) {
double mbar = static_cast<double>(get_plot_pressure(&pInfo, i, cyl));
double mbar = static_cast<double>(get_plot_pressure(pInfo, i, cyl));
double time = static_cast<double>(entry->sec);
if (mbar < 1.0)
continue;
if (i == from && i < to - 1) {
double mbar2 = static_cast<double>(get_plot_pressure(&pInfo, i+1, cyl));
double mbar2 = static_cast<double>(get_plot_pressure(pInfo, i+1, cyl));
double time2 = static_cast<double>(entry[1].sec);
if (mbar2 < 1.0)
continue;
@ -551,7 +551,7 @@ void DiveGasPressureItem::replot(const dive *d, int fromIn, int toIn, bool in_pl
}
if (i == to - 1 && i > from) {
double mbar2 = static_cast<double>(get_plot_pressure(&pInfo, i-1, cyl));
double mbar2 = static_cast<double>(get_plot_pressure(pInfo, i-1, cyl));
double time2 = static_cast<double>(entry[-1].sec);
if (mbar2 < 1.0)
continue;

View file

@ -212,7 +212,7 @@ void ToolTipItem::setPlotInfo(const plot_info &plot)
void ToolTipItem::clearPlotInfo()
{
memset(&pInfo, 0, sizeof(pInfo));
pInfo = plot_info();
}
void ToolTipItem::setTimeAxis(DiveCartesianAxis *axis)
@ -231,7 +231,7 @@ void ToolTipItem::refresh(const dive *d, const QPointF &pos, bool inPlanner)
lastTime = time;
clear();
auto [idx, lines] = get_plot_details_new(d, &pInfo, time);
auto [idx, lines] = get_plot_details_new(d, pInfo, time);
tissues.fill();
painter.setPen(QColor(0, 0, 0, 0));

View file

@ -7,6 +7,7 @@
#include "diveprofileitem.h"
#include "divetextitem.h"
#include "tankitem.h"
#include "core/dive.h"
#include "core/device.h"
#include "core/divecomputer.h"
#include "core/event.h"
@ -151,8 +152,6 @@ ProfileScene::ProfileScene(double dpr, bool printMode, bool isGrayscale) :
tankItem(new TankItem(*timeAxis, dpr)),
pixmaps(getDivePixmaps(dpr))
{
init_plot_info(&plotInfo);
setSceneRect(0, 0, 100, 100);
setItemIndexMethod(QGraphicsScene::NoIndex);
@ -188,7 +187,6 @@ ProfileScene::ProfileScene(double dpr, bool printMode, bool isGrayscale) :
ProfileScene::~ProfileScene()
{
free_plot_info_data(&plotInfo);
}
void ProfileScene::clear()
@ -201,7 +199,7 @@ void ProfileScene::clear()
// the DiveEventItems
qDeleteAll(eventItems);
eventItems.clear();
free_plot_info_data(&plotInfo);
plotInfo = plot_info();
empty = true;
}
@ -454,7 +452,7 @@ void ProfileScene::plotDive(const struct dive *dIn, int dcIn, DivePlannerPointsM
* create_plot_info_new() automatically frees old plot data.
*/
if (!keepPlotInfo)
create_plot_info_new(d, currentdc, &plotInfo, planner_ds);
plotInfo = create_plot_info_new(d, currentdc, planner_ds);
bool hasHeartBeat = plotInfo.maxhr;
// For mobile we might want to turn of some features that are normally shown.
@ -466,7 +464,7 @@ void ProfileScene::plotDive(const struct dive *dIn, int dcIn, DivePlannerPointsM
updateVisibility(hasHeartBeat, simplified);
updateAxes(hasHeartBeat, simplified);
int newMaxtime = get_maxtime(&plotInfo);
int newMaxtime = get_maxtime(plotInfo);
if (calcMax || newMaxtime > maxtime)
maxtime = newMaxtime;
@ -474,7 +472,7 @@ void ProfileScene::plotDive(const struct dive *dIn, int dcIn, DivePlannerPointsM
* when we are dragging the handler to plan / add dive.
* otherwhise, update normally.
*/
int newMaxDepth = get_maxdepth(&plotInfo);
int newMaxDepth = get_maxdepth(plotInfo);
if (!calcMax) {
if (maxdepth < newMaxDepth)
maxdepth = newMaxDepth;
@ -509,18 +507,18 @@ void ProfileScene::plotDive(const struct dive *dIn, int dcIn, DivePlannerPointsM
// Find first and last plotInfo entry
int firstSecond = lrint(timeAxis->minimum());
int lastSecond = lrint(timeAxis->maximum());
auto it1 = std::lower_bound(plotInfo.entry, plotInfo.entry + plotInfo.nr, firstSecond,
auto it1 = std::lower_bound(plotInfo.entry.begin(), plotInfo.entry.end(), firstSecond,
[](const plot_data &d, int s)
{ return d.sec < s; });
auto it2 = std::lower_bound(it1, plotInfo.entry + plotInfo.nr, lastSecond,
auto it2 = std::lower_bound(it1, plotInfo.entry.end(), lastSecond,
[](const plot_data &d, int s)
{ return d.sec < s; });
if (it1 > plotInfo.entry && it1->sec > firstSecond)
if (it1 > plotInfo.entry.begin() && it1->sec > firstSecond)
--it1;
if (it2 < plotInfo.entry + plotInfo.nr)
if (it2 < plotInfo.entry.end())
++it2;
int from = it1 - plotInfo.entry;
int to = it2 - plotInfo.entry;
int from = it1 - plotInfo.entry.begin();
int to = it2 - plotInfo.entry.begin();
timeAxis->updateTicks(animSpeed);
animatedAxes.push_back(timeAxis);

View file

@ -113,7 +113,7 @@ void RulerItem2::recalculate()
setLine(line);
QString text;
for (const std::string &s: compare_samples(dive, pInfo, source->idx, dest->idx, 1)) {
for (const std::string &s: compare_samples(dive, *pInfo, source->idx, dest->idx, 1)) {
if (!text.isEmpty())
text += '\n';
text += QString::fromStdString(s);