Commit graph

71 commits

Author SHA1 Message Date
Berthold Stoeger
409f159e1d statistics: convert box-and-whiskers plot to QSG
This is lazy: Derive from the bar chart item and add whiskers
in the subclassed render() function. The code is ugly, because
the base class function clears the dirty flags and therefore
the derived class has to remember them. Oh well.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-20 08:47:18 +01:00
Berthold Stoeger
5d5ebfcf3c statistics: implement showing / hiding of items in QSG
To replace the QGraphicsScene, we need the possibility of
showing and hiding items.

Turns out, the QSG API is completely insane.

Whether an item should be shown is queried by the virtual
function isSubtreeBlocked(), which is supposed to be
overriden by the derived classes.

However, the common nodes for rectangles and pixmaps are
supposed to be created by QQuickWindow, for hardware
optimization. This gives nodes that cannot be derived
from and therefore whether the item is shown or not cannot
be controlled.

There are therefore two distinct cases to consider: The
node is allocated by the code directly or indirectly by
QQuickWindow.

In the latter case, we use a proxy node with the only
purpose of having a "visible" flag and add the obtained
node as a child.

This madness is performed with template trickery to get
unified code.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-20 08:47:18 +01:00
Berthold Stoeger
b42e19e36b statistics: convert bar series to QSGNodes
To this end, two new ChartItems were added: A "bar" (a rectangle
with a border) and a "text" (multiple lines of text).

It turns out that the text on the bars now looks atrocious.
The reason appears to be that the antialiasing of the font-rendering
does not blend into the alpha channel, but into a supposed
background color? This will have to be investigated.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-20 08:47:18 +01:00
Berthold Stoeger
2008857660 statistics: render regression item using QSGNode
Render the confidence area and the regression line into a pixmap
and show that using a QSGNode.

It is unclear whether it is preferred to do it this way or to
triangulate the confidence area into triangles to be drawn by
the shader.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-20 08:47:18 +01:00
Berthold Stoeger
faf3e7079d statistics: keep track of dirty items in double-linked list
So far the items to be recalculated in the drawing thread
had a "dirty" flag and were kept in one array par z-level.

Once the series are implemented in terms of QSGNodes, there
may lots of these items. To make this more efficient when
only one or two of these items change (e.g. highlighting due
to mouseover), keep the dirty items in a linked list.

Of course, this makes the draw first version of the chart
less efficient.

There are more fancy ways of implementing the double-linked
list, but the few ns gained in the render thread are hardly
worth it.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-20 08:47:18 +01:00
Berthold Stoeger
ada5e8a49d statistics: turn axes into QSGNode
Render the labels and the title into a pixmap and render
the ticks and the base line using individual QSGNodes.
Attempting to render the ticks likewise into the pixmap
gave horrible results, because (quite obviously) rendering
with QPainter and the QSG shader gives non-matching ticks
and grid lines.

The memory management had to be changed a bit: The ChartItems
were collected in the root QSGNode. However, the axes are added
before the first plotting, so this node might not exist.
Therefore, store the axes in the StatsView object.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-20 08:47:18 +01:00
Berthold Stoeger
9b7565e81a statistics: turn ChartGrid into QSGNodes
Turn the background grid into QSGNodes. Each grid line is
represented by a QSG line item. An alternative would be
drawing the grid into a QImage and blasting that onto the
screen. It is unclear which one is preferred.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-20 08:47:18 +01:00
Berthold Stoeger
c74975632e statistics: draw background using a QSGRectangle node
Currently, the background was drawn as solid color onto
the chart-scene. This is of course incompatible with doing
the grid as QSGNodes. Therefore, make the scene image
transparent and use a QSGRectangle as background color.

We could also simply omit the background and show the
widget's background. However, that would mean setting
the background color in two seperate code paths
(desktop and mobile). I found no way of directly setting
the background of the QQuickItem.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-20 08:47:18 +01:00
Berthold Stoeger
218c844ad4 statistics: convert HistogramMarkers to QSGNodes
This is in analogy to the quartile markers.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-20 08:47:18 +01:00
Berthold Stoeger
790d2b2ddb statistics: convert QuartileMarkers to QSGNodes
Slowly converting the QGraphicsScene items to QSGNodes to
avoid full replot of the scene.

This adds a new abstraction for line-nodes. Since the render()
function here is fundamentally different from the pixmap-nodes
we had so far, this has to be made virtual.

Also, move the quartile markers to their own source file,
since the StatsView source file is quite huge already.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-20 08:47:18 +01:00
Berthold Stoeger
b1c0d42408 statistics: remember position of legend when resizing
The position of the legend was reset when resizing. This was
OK as long as the legend wasn't movable.

To avoid resetting the position, store the center position
of the legend relatively to the size of the canvas. On
resize restore the center to the same relative size.

To avoid code duplication, move the sanitizing of the
coordinates from the StatsView to the Legend.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-20 08:47:18 +01:00
Berthold Stoeger
e1c0cace95 statistics: add notion of Z-value to chart items
The chart items were drawn in order of creation. To control this,
add a notion of Z-value. In contrast to QGraphicsScene, make
this a small integer value.

To controll order of drawing, a plain QSGNode is created for
every possible Z-Value and items are added to these nodes.
Thus, items are rendered by Z-value and if the Z-value is equal
by order of creation.

Likewise split the list of chart-items into Z-values, so that
items can be quickly unregistered: The items that will be
removed individually will usuall be part of Z-levels with only
few items (e.g. legend, infobox). Z-levels with many items
(notably the series) will always be fully rebuilt.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-20 08:47:18 +01:00
Berthold Stoeger
785d5189f6 statistics: turn infobox into a QSGNode
A small step in converting from QGraphicsScene to QQuickItem.
This is the second item to be converted (after the legend)
and for now items are drawn in order of creation, which means
that the infobox is on top of the legend. This will have
to be made deterministic in follow-up commits.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-20 08:47:18 +01:00
Berthold Stoeger
d7878dad36 statistics: pass view to series
The series were passed a pointer to the QGraphicsScene to add
their item. In the future these items will be replaced by
QSGNodes. To add these, the series need a reference to the StatsView.
Therefore pass it in the constructor. Once everything is
replaces by QSGNodes, remove the QGraphicsScene member.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-20 08:47:18 +01:00
Berthold Stoeger
1a869833d8 statistics: implement moving of legend
Catch mouse move events and move the legend accordingly.
Currently, this is the only item that can be dragged and
therefore there is no need of doing some kind of fancy
interface. Simply keep a pointer to the legend if it is
dragged.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-20 08:47:18 +01:00
Berthold Stoeger
2b961414d7 statistics: draw legend as a QSGNode
In order not to waste CPU by constantly rerendering the chart,
we must use these weird OpenGL QSGNode things. The interface
is appallingly low-level and unfriendly.

As a first test, try to convert the legend. Create a wrapper
class that represents a rectangular item with a texture
and that will certainly need some (lots of) optimization.

Make sure that all low-level QSG-objects are only accessed
in the rendering thread. This means that the wrapper has
to maintain a notion of "dirtiness" of the state. I.e.
which part of the QSG-objects have to be modified.

From the low-level wrapper derive a class that draws a rounded
rectangle for every resize. The child class of that must then
paint on the rectangle after every resize.

That looks all not very fortunate, but it displays a
legend and will make it possible to move the legend
without and drawing operations, only shifting around
an OpenGL surface.

The render thread goes through all chart-items and
rerenders them if dirty. Currently, on deletion
of these items, this list is not reset. I.e. currently
it is not supported to remove individual items.
Only the full scene can be cleared!

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-20 08:47:18 +01:00
Dirk Hohndel
ecf3ac12eb mobile/statistics: make icons available in mobile app
They were bundled via the desktop qrc, but they need a shared qrc that
can be used in both apps.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-01-19 12:35:29 -08:00
Robert C. Helling
25cfd852b9 Add back central line for linear regression
Signed-off-by: Robert C. Helling <helling@atdotde.de>
2021-01-14 20:51:23 +01:00
Robert C. Helling
d6712bc5ac Plot proper confidence regions
I was coninced that that rather than doing an order of
magnitude estimate of the confidence region it's better
to have the correct concave shapes that indicate the
95% confidence level for the regression line.

It also turned out that the previous expression was
missing a factor of 1/sqrt(n).

Signed-off-by: Robert C. Helling <helling@atdotde.de>
2021-01-14 20:51:23 +01:00
Robert C. Helling
5775bd7b27 Silence some compiler warnings
This is what clang suggested in compiler warnings.

Signed-off-by: Robert C. Helling <helling@atdotde.de>
2021-01-14 20:51:23 +01:00
Robert C. Helling
d83c9b5246 Indicate goodness of fit of regression line
The goodness of fit of a regression line is the percentage
of the variance of the y values that is explained by the
dependence on the x values.

Set the alpha value of the regression line to this goodness
of fit.

Further, set the width of the regression line to a standard
deviation of the values from the regression line valies.

Signed-off-by: Robert C. Helling <helling@atdotde.de>
2021-01-14 20:51:23 +01:00
Dirk Hohndel
e610fb2481 statistics: add count property to chart list
In order to be able to correctly size the chart type popup, we'll need
access to the total count or rows as a property that signals changes to
QML.

The hack to use rowCount() as the READ function requires that rowCount()
can be called without argument, therefore the addition of a default
parent.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-01-13 11:39:36 -08:00
Berthold Stoeger
46bb242c69 mobile/statistics: export ChartListModel to QML
For QML, the roles have to be associated dynamically with
name. Moreover, the model has to be registered as a QML
type to make it accessible from QML.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-13 11:39:36 -08:00
Berthold Stoeger
108f6fed2f statistics: print ellipsis in case of too little space
In categorical axes all labels were printed leading to a big
tohu wa-bohu for two many bins. Therefore, if a label is
larger than the space between two ticks, replace by an ellipsis.

Adjust the size of the ellipsis (".", ".." or "...") to the
available space.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-11 13:29:15 +01:00
Berthold Stoeger
bdecd98ef5 statistics: consider overhang of horizontal axes
The old code didn't consider that labels can peak out of
horizontal axes if labels are under ticks.

This commit takes this into account. However, it must be
noted that this is only heuristics: Before setting the
size of the axes, the actual minimum and maximum label are
not known, because we round to "nice" numbers. But the
size of the axis can only be set after knowing the overhang,
leading to a circular dependency. Therefore, the code
currently simply uses the minimum and maximum value of
the data, hoping that the "nice" values will not format
to something significantly larger. We could do a multi-pass
scheme, but let's not for now.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-11 12:59:17 +01:00
Berthold Stoeger
233e686b92 statistics: split people binner
The people binner (called "buddies") is too coarse. Split into
buddies, dive guide and people (the old "buddies", which is
a combination of buddies and dive guide).

Reported-by: Peter Zaal <peter.zaal@gmail.com>
Reported-by: Rick Walsh <rickmwalsh@gmail.com>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-10 15:56:40 -08:00
Dirk Hohndel
b40354c7f2 build-system: compile stats code on mobile OSs
Android and iOS use qmake, so add the code to the .pro file.
This also removes all remnants of QCharts includes and uses and all the
references to QCharts in our various build systems.

That was a brief but extremely useful detour.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-01-10 15:16:52 -08:00
Berthold Stoeger
e7907c494f statistics: convert chart to QQuickItem
It turns out that the wrong base class was used for the chart.
QQuickWidget can only be used on desktop, not in a mobile UI.

Therefore, turn this into a QQuickItem and move the container
QQuickWidget into desktop-only code.

Currently, this code is insane: The chart is rendered onto a
QGraphicsScene (as it was before), which is then rendered into
a QImage, which is transformed into a QSGTexture, which is then
projected onto the device. This is performed on every mouse
move event, since these events in general change the position
of the info-box.

The plan is to slowly convert elements such as the info-box into
QQuickItems. Browsing the QtQuick documentation, this will
not be much fun.

Also note that the rendering currently tears, flickers and has
antialiasing artifacts, most likely owing to integer (QImage)
to floating point (QGraphicsScene, QQuickItem) conversion
problems. The data flow is
QGraphicsScene (float) -> QImage (int) -> QQuickItem (float).

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-10 15:16:52 -08:00
Berthold Stoeger
f6b857b8fe statistics: fix 20 m binner
Copy&paste error: the 20 m binner binned to 10 m.

Reported-by: Peter Zaal <peter.zaal@gmail.com>
Reported-by: Rick Walsh <rickmwalsh@gmail.com>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-10 14:45:12 -08:00
Berthold Stoeger
bbdd34d069 statistics: add count to box and whisker plots
When calculating the quartiles, we need the count of dives
anyway, which makes it trivial to export this value to
the frontend.

Fixes an erroneous "mean", which should be "median".

Suggested-by: Peter Zaal <peter.zaal@gmail.com>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-10 14:45:12 -08:00
Berthold Stoeger
de62638b73 statistics: add tags variable
Trivially a copy of the "buddies" code.

Suggested-by: Peter Zaal <peter.zaal@gmail.com>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-10 13:42:48 -08:00
Berthold Stoeger
2d864c3e9d statistics: sort dive sites
The dive sites where sorted by location in RAM, which is just
silly. Add a DiveSiteWrapper that sorts by name, though that
should probably be improved.

Suggested-by: Peter Zaal <peter.zaal@gmail.com>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-10 13:42:48 -08:00
Berthold Stoeger
0efcbb0eb6 statistics: add min and max operations for numerical types
This makes sense and is easy to implement.

Suggested-by: Peter Zaal <peter.zaal@gmail.com>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-10 13:42:48 -08:00
Berthold Stoeger
b5c8d0dbb4 statistics: fix range in categorical axes
The range for a one-bin chart is [-0.5,0.5], thus the range
in an n-bin chart is [-0.5,n-0.5], not [-0.5,n+0.5].

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-09 14:25:02 -08:00
Berthold Stoeger
83848fb2a8 statistics: add a dive-# variable
This was requested on the mailing list and it makes sense to
have it. Of course, not all charts make sense: e.g. a plot dive-#
vs. count is a bit redundant...

Sadly, this can't use the generic IntRangeBinner, because dive-#s
start at 1, not 0.

Suggested-by: Christof Arnosti <charno@charno.ch>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-09 14:17:56 -08:00
Berthold Stoeger
b00009ef4e statistics: add a mean depth variable
This was requested on the mailing list. Reduce code size somewhat
by deriving the binner and the variable classes from common
base classes with a mean-vs-max flag.

Suggested-by: Christof Arnosti <charno@charno.ch>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-09 14:17:56 -08:00
Berthold Stoeger
2a850025b2 statistics: add ticks at beginning and end of the axis
The grid is based on the axis ticks. If labels in histogram
axes were skipped (because there are too many bins), it could
happen that the grid was incomplete, because the first and/or
last tick were missing. Add these explicitly.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-07 10:39:52 -08:00
Berthold Stoeger
cad00032fc statistics: improve placement of info-box
The info box was placed either above or below the mouse-pointer.
If the pointer is at the center and the infobox higher than
half the chart, it would cross the border. Detect this case
and place the info box at the center.

Same logic for right/left, though that should typically not
happen.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-06 12:31:22 -08:00
Berthold Stoeger
405e6b6b69 statistics: fix chart features: regression line and median/mean
The coordinates of these were calculated when creating the feature.
This is wrong, because the min/max values of the axes can change
on resize to get "nice" number. Therefore, recalculate after resizing.
This means that the general "LineMarker" class has to be split into
two classes, one for regression lines and one for median/mean
markers.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-06 12:31:22 -08:00
Berthold Stoeger
ab324ed769 statistics: paint custom grid
With removal of QtCharts' axes, the grid was lost. Readd it.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-06 12:31:22 -08:00
Berthold Stoeger
8dfa3f6db3 statistics: draw title of axes
Easy enough to implement, but one weirdness:
To get the height of the rotated text, one has to access the
width() member of the boundingRect. I'm not sure if that makes
sense, but so be it.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-06 12:31:22 -08:00
Berthold Stoeger
4ab9f1c6b0 statistics: replace QtCharts' axes
Replace by custom implementation, with the ultimate goal to
remove the QtCharts module. This doesn't yet display axis
titles or a grid.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-01-06 12:31:22 -08:00
Berthold Stoeger
598058e21e statistics: set correct z-value for bars
The bars were set to the z-value of the labels. Not an issue,
since the labels are generated after the bars and therefore
plot later. Still, do the right thing.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-06 12:31:22 -08:00
Berthold Stoeger
90129aa26f statistics: render title
Since we want to get rid of QtCharts, we have to render our own
title. Simply keep around a QGraphicsSimpleTextItem and put in
the center of the chart. Define the borders to the scene as
constants.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-01-06 12:31:22 -08:00
Berthold Stoeger
ccc95f938a statistics: save axis with series
In the future we want to use our own axis implementation to
convert from/to screen coordinates. For this purpose, we
need to save the axes with the series. Especially if we want
to support multiple series on different axes.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-06 12:31:22 -08:00
Berthold Stoeger
23d781deba statistics: save chart in axis class
The chart was passed as argument to the function recalculating
the axis labels. Instead, pass the chart in the constructor of
the axes and save it. This gains us flexibility for the future:
There will be more functions that need to access the chart (e.g.
resizing of the axes).

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-06 12:31:22 -08:00
Robert C. Helling
b181c011cc Add dive rating and visibility to statistics variables
Signed-off-by: Robert C. Helling <helling@atdotde.de>
2021-01-05 00:34:14 +01:00
Dirk Hohndel
ce0f64df2e stats: fix line segment intersection math
Linear algebra class was a while ago, but somehow this does look more
logical to me.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-01-04 11:20:51 -08:00
Dirk Hohndel
1f1d82b1b3 statistics: don't crash if the QCharts QML modules aren't found
We don't really give a user visible error message which is kind of a problem,
but at least we don't crash anymore.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-01-03 16:58:01 -08:00
Berthold Stoeger
6a6dd0888a statistics: don't reset binner if binner is set
Recently code was added to reset variable 1 binner if the second
variable does not support an unbinned first variable.

It forgot to check whether a binner was already set. Do this.
But validate the old binner first!

This code is extremely fragile and will have to be redone.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-03 15:41:36 -08:00