The old animation was weird: it would reuse the labels
based on the index, not on the value. Thus, with the
new scaling code, sometimes there was no animation at all,
if the value, but not the position changed.
Consider the values instead and let labels appear/disappear.
This makes things slightly more complex.
While changing this code, create our own animation-class.
Thus, we can avoid having the dive axes being QObjects.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This function was just needlessly complicated. For one, it
considered the position of the line, but that is never changed
since redoing the positioning code. Moreover, it does in
lots of lines what is a very idiomatic operation: a
one-dimensional affine transformation. Let's shorten the
actual calculation to two lines.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This label is put to the right of the corresponding curve,
so it should arguably be centered vertically. At least to
me this looks more natural.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The time axis might need some space and the average depth item
puts a formatted depth at to right of the profile. Consider
these when calculating the right border.
Since I found no way to turn of the average depth, this creates
a permanent border, which might or might not be a good thing.
Contains some refactoring of the label-size functions provided
by DiveTextItem.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The usual increments (leading 1, 2, 4 or 5) don't look
natural for the time axis. Therefore special case the
time axis and to increments in 1, 2, 3, 4, 5, 6 or 12
parts of a minute or second.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This function was used to check wether a screen-point
is located on the profile. Bizzarely, this was done by
transforming into local coordinates and checking
min/max value. Simply check the screen coordinates
directly. Moreover, make the function return whether
the point is inside the region, not outside the region,
to make logic more straight forward.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Hide thumbnails, which are out of the shown range. This became
necessary when converting to absolute scaling.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
When changing from relative to absolute scaling of the char
elements, positioning of the picture thumbnails was broken.
To emulate the old behavior, add a function to DiveCartesianAxis,
that allows positioning with respect to the axis on the screen.
To simplify tuning of the poctuire positions, name a few
constants explicitly.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The picture thumbnails were recreated on every profile render,
even when zooming / scrolling. In that case, we should only change
the positions.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This is a potentially expensive operation (e.g. interpolation of
pressure values), so don't recalculate the plot data for every
redraw.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Positional bool parameters to control the rendering of the plot
have been a pain. We are down to one parameter (instant),
but more will be readded, so let's use the opportunity to
control rendering with a flags parameter.
Sadly, C++ has no reasonable way of defining flags that I know
of. Either the identifiers leak (enum), or can't be trivially
ORed (enum class) or are weakly typed (int). Let's just use an
integer for now.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
These were the minimum and maximum of a 9-min window.
The profile now uses an adaptive peak-search, so this is not
used anymore.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The old code used the maximum / minimum values of nine-minute
intervals to indicate maximum / minimum depths. This does not
work well when zooming, since the labels will get sparse.
Instead implement a primitive peak finding algorithm, that
searches for the deepest peak in the whole plot and then
repeats the procedure for the right and left sides, leaving
out a certain distance to the origninal peak. This is repeated
until there are no more peaks found.
Only peaks of a certain prominence are considered, which
conveniently gives us the valleys.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Use variable intervals for printing temperature and heart
beat labels. Obviously, so that the labels don't become
sparse on zooming, but also to make them not too crowded
on mobile / small screens.
This doesn't work for depth labels, because these labels
use data provided from the profile.c core that doesn't
know about the size of the chart.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
There was a bunch of conditionally compiled code on mobile
that had special hiding/unhiding rules.
Try to unify that with the desktop code by introducing a
"simplified" flag. This certainly breaks and will have to
be finetuned. In particular, I can't test CCR dives, which
are treated specially on mobile.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Avoid "overshooting" of the profile items by linearly clipping
the first and last segment to the boundaries of the time-axis.
Sadly, quite a lot of code, because every profile item is
slightly different.
In particular the pressure-segment handling was rewritten.
It now stores the begin and end of each segment to draw
the appropriate text items.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Due to bit-rot the gas pressure and gas type were displayed on top
of each other. I don't understand the meaning of the old code
[log10(log10(axisRange))] (!). Therefore let's just add the height
of the label to separate the labels.
Probably needs some fine-tuning.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This was a rather trivial change: simply pass in the first
and the last second to the plot function.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
That variable was only used in a single function and
always reset at the beginning of the function. No point
in being a member variable.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Only plot the zoomed range. Currently this passes the sample
before and after the range, so it generally "overshoots" by
one sample in each direction. The plan is to do clipping
on the first and last polygon segment later on.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
We were using the QGraphicsScene machinery to zoom into the
plot. This not only zoomed into the dive, but into the whole
thing. In general, one couldn't see the axes anymore.
Instead, adjust the range of the time-axis according to the
zoom-level and position.
Of course, the code isn't adapted to that and the result
is comical. The chart features will have to be fixed
one-by-one. Oh joy.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Currently, the zoomLevel is reset for every plotDive() call,
because the zooming is done via the QGraphicsScene. However,
this does not work well (e.g. axes are likewise zoomed) and
in the future a change of the zoom level will cause a replot.
Thus, remove the zoom-reset in plotDive() and do it explicitly
when switching dives.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This is a constant, no point in keeping it as a member variable.
Contains removal of a pointless #ifdef (guarding against mobile,
but code not compiled on mobile), a typo-fix in a comment and
replacement of Qt's idiosyncratic qreal by double.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
There were two somewhat redundant flags for the axes: the position
(left, right, bottom) and the orientation (up-down, left-right, etc).
Replace the latter by an inverted flag: if true, the axis is
up-down or right-left, i.e. the opposite of what one would expect
for a normal graph.
Set the flag in the constructor and remove the setOrientation()
function.
Sadly, the code is a bit complex, because screen coordinates are
top-to-bottom. Who thought that would be a good idea?
Note: this also fixes the placement of the ticks of the time
axis.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
There were virtual functions to calculate the label colors
based on the value of the label. However, these functions
only returned constant values. Therefore, just set these
in the constructors.
Thuse, a few virtual functions and derived classes can be
removed.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This was only used in the constructor to create the pen for
the grid lines. Not need to keep it around.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The visibility of axis text / lines is never changed, so set
in axis constructor.
Moreover, instead of rendering the lines/text and then setting
them invisible, do not render them if invisible.
The whole thing appears superfluous, since the proper way to
not show lines/text is to just not call updateTicks on the
axis. But in the future we might want to have axes with text
but no lines, so keep for now.
Since this means breaking out the text / line rendering
into their own function, we might rename some variables to
make them (at least somewhat) more clear.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Rounding the axes dimensions to "nice" number may have been a
good idea, but for the time-axis it feels weird.
Therefore revert the time axis to the previous behavior:
range is set according to the data. To differentiate between
time an other axes, use the position: the time axis is the
only axis at the bottom. Yes, that's ugly but pragmatic.
Since we have that flag also use it for the special casing
of the text-display. Spares us one virtual function dispatch.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The integers were simply rounded to integers, which might give
ugly intervals (e.g. multiples of 3). Use the code of the
statistics tab, with one modification: take care not to
use intervals below the given precision. The statistics work
differently: there, the precision is adjusted according to
the interval size, not the other way around.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The ticks were recalculated twice per plotDive() call:
1) When updating the position of the axes in updateChangeLine()
2) After setting the bounds in plotDive() via setBounds()
Remove the first instance. updateChangeLine() is called in
only one place [from plotDive()] and therefore, the recalculation
is always redundant. Moreover, rename the function to setPosition(),
since it doesn't do any animation at all.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This was used to animate the position of the dive event items
when the size of the axis changed. However, that doesn't work
since quite some time. The axes size are changed when
1) switching dives
2) resizing the drawing area
In the first case, the dive event items are fully recalculated.
In the second case, animation speed is set to instant, since
resizing of windows is done continuously on any reasonably
modern desktop anyway. It might make sense on mobile, where
size changes are discontinuous, but there we use static
profiles anyway. Moreover, I checked a few applications and
none of them had animations when switching orientation of
my tablet.
Let's just remove this disfunctional thing and replace it
later, should someone complain.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The partial-pressure-axis was the only DiveCartesianAxis
child that had its own code to set the bounds. The bounds
of all other axes were set in plotDive().
For consistency, do this here as well. Thus, the whole
class can be removed.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The number of ticks was generated for each axis with custom
code. This code was not aware of the size of the profile and
could result in overly dense or sparse ticks.
Generalize the generation of the ticks. For now, round tick
values to integers. In the future, try to use more "nice"
looking values as we do for the statistics tab.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Instead of a host of virtual functions, let the base class
(DiveCartesianAxis) do the formatting of the axis labels.
To do so, it needs to know how to convert the internal
representation (e.g. mm) into the displayed value (e.g. feet).
Moreover, this transformation has to be adapted when changing
the locale-setting, therefore do it for every plot() call.
The transformation itself cannot be a simple linear translation,
because we have non-absolute display units, namely °C and °F.
Thankfully affine transformations are enough though.
Only one custom formatter remains: the time axis. It might
be a good idea to remove the virtual function and do this
via a flag.
This is all done not so much for code simplification, but
because for a general layout of the axis labels, the
axis has to understand the values of the labels and not
only handle them as opaque texts.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Dive data are stored internally using integral types using
appropriately fine units (mm, mbar, mkelvin, etc.). These
are converted with functions defined in units.h for display
(m, bar, C, etc.). Usually floating points are returned by
these functions, to retain the necessary precision. There
is one exception: the to_PSI() and mbar_to_PSI() functions.
For consistency, make these functions likewise return floats.
This will be needed for the rework of the profile-axes.
The plan is to use the conversion functions to make the
axes aware of the displayed values. This in turn will be
necessary to place the ticks at sensible distances. However,
the conversions need to be precise, which is not the
case for the current to_PSI() functions.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Instead of calculating the label sizes of the axes when
relayouting the chart, calculate them at construction time.
To do so, pass the digits before and after the decimal comma
to the constructor.
This is not so much an optimization thing, but rather an
first stab at more general label rendering. Time, of course,
will always be an exception. But hopefully the remaining
values can be done more generally.
Note that currently this code is a total mess. For example,
the labels for the temperature axes are not converted to
F if needed. And therefore also not shown. This will need
some major rethinking.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
All this did was setting changed to true. Obviously an
artifact, since that is done in the constructor of the
base class anyway. Remove.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This is bike-shedding: Instead of two setMinimum()/setMaximum()
calls, use a single setBounds() call. A few axes (notably depth
and time) always have a 0 as lower bound. However, this will
change once there is a proper zooming functionality.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The placement of the axes was done independently of the
plotting, e.g. when settings changed. Presumably,
for performance reasons. However, since the axes may
depend on whether a dive has heart-rate data or not,
this simply is not viable. To make this work, one
would have to remember whether the previous dive
showed the heart-rate, etc. Not worth it - always
reposition the axes. It should not matte performance-
wise.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
I doubt that this is necessary, but since most of the rest
of the profile code passes "isGrayscale" to "getColor()",
do the same here for consistency.
To avoid storing the isGrayscale flag, just create the pens
at construction time and store those.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
There is no more reason to render the profile in printMode.
DPR is also supported in normal mode.
Moreover, don't scale the DPR down by fontScale. If we
have to scale down the fonts, we'll have to do this
differently without squeezing the rest of the profile
features.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The event-icons are positioned according to the top-left
corner (as is usual in computer circles). For the flag
icon it seems more natural to use the bottom of the pole.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The DivePlotDataModel was saved with every event to access the
depth. However, since the depth never changes, we can simply
save the depth instead.
Also, since we only need the model to access the plot_info,
pass the plot_info directly. As noted in a previous commit
message, I believe that Qt models are a very bad choice
for intra-application data transfer. They should only ever
be used to interface with Qt.
And since touching this code, pass duration_t instead of int
to depthAtTime() to make the callers less cluttered.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>