profile: reimplement DivePercentageItem

The tissue percentages were realized as 16 independent polygons.
That didn't work at all with the new absolute scaling.

Reimplement the item and blast it onto a pixmap. Not only is
this artifact-free, it also should (hopefully) be quite a bit
more efficient than painting numerous lines.

In contrast to the old code, this does access the plot_info
structure directly instead of using the model. Not so much
for performance reason, but rather to make things more robust:
We have a strongly typed language. Why would we shoehorn data
through the weakly typed QVariant and mess with wierd
index-arithmetics. Makes no sense to me. Qt-model have to
be used for interfacing with Qt. They are terrible for
intra-application data transfer.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2021-08-29 22:13:26 +02:00 committed by Dirk Hohndel
parent 24cf6709e3
commit 505e4e47eb
10 changed files with 177 additions and 89 deletions

View file

@ -233,74 +233,6 @@ void DiveHeartrateItem::paint(QPainter *painter, const QStyleOptionGraphicsItem*
painter->restore();
}
DivePercentageItem::DivePercentageItem(const DivePlotDataModel &model, const DiveCartesianAxis &hAxis, int hColumn,
const DiveCartesianAxis &vAxis, int vColumn, int i, double dpr) :
AbstractProfilePolygonItem(model, hAxis, hColumn, vAxis, vColumn, dpr),
tissueIndex(i)
{
}
void DivePercentageItem::replot(const dive *d, bool)
{
// Ignore empty values. a heart rate of 0 would be a bad sign.
QPolygonF poly;
colors.clear();
for (int i = 0, modelDataCount = dataModel.rowCount(); i < modelDataCount; i++) {
int sec = dataModel.index(i, hDataColumn).data().toInt();
QPointF point(hAxis.posAtValue(sec), vAxis.posAtValue(64 - 4 * tissueIndex));
poly.append(point);
double value = dataModel.index(i, vDataColumn).data().toDouble();
struct gasmix gasmix = gasmix_air;
const struct event *ev = NULL;
gasmix = get_gasmix(d, get_dive_dc_const(d, dc_number), sec, &ev, gasmix);
int inert = get_n2(gasmix) + get_he(gasmix);
colors.push_back(ColorScale(value, inert));
}
setPolygon(poly);
}
QColor DivePercentageItem::ColorScale(double value, int inert)
{
QColor color;
double scaledValue = value / (AMB_PERCENTAGE * inert) * 1000.0;
if (scaledValue < 0.8) // grade from cyan to blue to purple
color.setHsvF(0.5 + 0.25 * scaledValue / 0.8, 1.0, 1.0);
else if (scaledValue < 1.0) // grade from magenta to black
color.setHsvF(0.75, 1.0, (1.0 - scaledValue) / 0.2);
else if (value < AMB_PERCENTAGE) // grade from black to bright green
color.setHsvF(0.333, 1.0, (value - AMB_PERCENTAGE * inert / 1000.0) / (AMB_PERCENTAGE - AMB_PERCENTAGE * inert / 1000.0));
else if (value < 65) // grade from bright green (0% M) to yellow-green (30% M)
color.setHsvF(0.333 - 0.133 * (value - AMB_PERCENTAGE) / (65.0 - AMB_PERCENTAGE), 1.0, 1.0);
else if (value < 85) // grade from yellow-green (30% M) to orange (70% M)
color.setHsvF(0.2 - 0.1 * (value - 65.0) / 20.0, 1.0, 1.0);
else if (value < 100) // grade from orange (70% M) to red (100% M)
color.setHsvF(0.1 * (100.0 - value) / 15.0, 1.0, 1.0);
else if (value < 120) // M value exceeded - grade from red to white
color.setHsvF(0.0, 1 - (value - 100.0) / 20.0, 1.0);
else // white
color.setHsvF(0.0, 0.0, 1.0);
return color;
}
void DivePercentageItem::paint(QPainter *painter, const QStyleOptionGraphicsItem*, QWidget*)
{
if (polygon().isEmpty())
return;
painter->save();
QPen mypen;
mypen.setCapStyle(Qt::FlatCap);
mypen.setCosmetic(false);
QPolygonF poly = polygon();
for (int i = 1; i < poly.count(); i++) {
mypen.setBrush(QBrush(colors[i]));
painter->setPen(mypen);
painter->drawLine(poly[i - 1], poly[i]);
}
painter->restore();
}
DiveTemperatureItem::DiveTemperatureItem(const DivePlotDataModel &model, const DiveCartesianAxis &hAxis, int hColumn,
const DiveCartesianAxis &vAxis, int vColumn, double dpr) :
AbstractProfilePolygonItem(model, hAxis, hColumn, vAxis, vColumn, dpr)