Voronoi diagram on chart

.. The diagram now displays on a chart, but there are a few issues.
   Will work through them as more testing done.
This commit is contained in:
Mark Liversedge
2021-09-30 19:00:35 +01:00
parent 4f005d4491
commit 70ed4e36e0
9 changed files with 214 additions and 11 deletions

View File

@@ -8,9 +8,21 @@
Voronoi::Voronoi()
{
// old controls essentially in main.c
triangulate = 0;
plot = 0;
debug = 0;
//
// the original source was written in such a way that you could
// update the "plotting functions" (line, circle etc) with your
// own code to implement a plot.
//
// we have adapted the "line" function to record lines in the
// output vector, so we can draw them on a plot
//
// testing has suggested that these kinds of diagrams only work
// well when there are lots of cells ie, running kmeans with
// 30 or even 100 clusters.
//
triangulate = 0; // tesselate (we don't support this)
plot = 1; // call "plotting functions" - we use this
debug = 0; // set to 1 to get lots of debug
// malloc lists are maintained and zapped in constructors
freeinit(&sfl, sizeof(Site));
@@ -98,6 +110,7 @@ Voronoi::run(QRectF /* boundingRect */)
// was done in main.c previously
geominit();
plotinit();
// now into the original sources
Site *newsite, * bot, * top, * temp, * p, * v ;
@@ -755,11 +768,13 @@ Voronoi::myalloc(unsigned n)
void
Voronoi::openpl(void)
{
output.clear();
}
void
Voronoi::line(float ax, float ay, float bx, float by)
{
output << QLineF(QPointF(ax,ay), QPointF(bx,by));
}
void

View File

@@ -3,6 +3,7 @@
#include <QList>
#include <QRectF>
#include <QPointF>
#include <QLineF>
#ifndef __VDEFS_H
#define __VDEFS_H 1
@@ -76,6 +77,9 @@ class Voronoi {
void addSite(QPointF point);
void run(QRectF boundingRect);
// the output is a vector of lines to draw
QList<QLineF> &lines() { return output; }
private:
// original global variables
@@ -99,6 +103,7 @@ class Voronoi {
// refactoring to Qt containers
QList<void *> malloclist; // keep tabs on all the malloc'ed memory
QList<Site*> sites;
QList<QLineF> output;
/*** implicit parameters: nsites, sqrt_nsites, xmin, xmax, ymin, ymax,
: deltax, deltay (can all be estimates).

View File

@@ -439,7 +439,7 @@ GenericChart::finaliseChart()
}
// did we have a voronoi diagram?
if (p.voronoix.count() >= 2) newPlots[i].plot->addVoronoi(p.voronoix, p.voronoiy);
if (p.voronoix.count() >= 2) newPlots[i].plot->addVoronoi(p.name, p.voronoix, p.voronoiy);
}
// set axis

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 2021 Mark Liversedge (liversedge@gmail.com)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <QChart>
#include "GenericLines.h"
GenericLines::GenericLines(GenericPlot *plot) : QGraphicsItem(NULL), plot(plot), curve(NULL)
{
}
GenericLines::~GenericLines() {}
void
GenericLines::paint(QPainter*painter, const QStyleOptionGraphicsItem *, QWidget*)
{
if (curve == NULL) return;
QPen pen(Qt::lightGray);
painter->setPen(pen);
painter->setClipRect(plot->qchart->plotArea());
foreach(QLineF line, lines) {
QPointF from = plot->qchart->mapToPosition(line.p1(), curve);
QPointF to = plot->qchart->mapToPosition(line.p2(), curve);
painter->drawLine(from, to);
}
}
void
GenericLines::prepare()
{
prepareGeometryChange();
}
QRectF GenericLines::boundingRect() const
{
// we cover the entire plot area generally
return plot->qchart->plotArea();
}

56
src/Charts/GenericLines.h Normal file
View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 2021 Mark Liversedge (liversedge@gmail.com)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _GC_GenericLines_h
#define _GC_GenericLines_h 1
#include <QPointF>
#include <QtCharts>
#include <QGraphicsItem>
#include "GenericPlot.h"
// for painting lines on a chart
class GenericLines : public QGraphicsItem
{
Q_INTERFACES(QGraphicsItem)
public:
GenericLines(GenericPlot *);
~GenericLines();
void setCurve(QAbstractSeries *curve) { this->curve=curve; }
void setLines(QList<QLineF> lines) { this->lines = lines; update(); }
void paint(QPainter*, const QStyleOptionGraphicsItem *, QWidget*);
QRectF boundingRect() const;
void prepare();
private:
// lines to draw
QList<QLineF> lines;
GenericPlot *plot;
QAbstractSeries *curve;
};
#endif

View File

@@ -28,6 +28,9 @@
#include "ChartSpace.h"
#include "UserChartOverviewItem.h"
#include "Voronoi.h"
#include "GenericLines.h"
#include <limits>
// used to format dates/times on axes
@@ -47,6 +50,7 @@ GenericPlot::GenericPlot(QWidget *parent, Context *context, QGraphicsItem *item)
barseries=NULL;
stackbarseries=NULL;
percentbarseries=NULL;
voronoidiagram=NULL;
bottom=left=true;
mainLayout = new QVBoxLayout(this);
@@ -316,12 +320,11 @@ GenericPlot::addAnnotation(AnnotationType, QString string, QColor color)
}
void
GenericPlot::addVoronoi(QVector<double>x, QVector<double>y)
GenericPlot::addVoronoi(QString name, QVector<double>x, QVector<double>y)
{
vname = name;
vx = x;
vy = y;
fprintf(stderr, "generic plot: add voronoi diagram\n"); fflush(stderr);
}
void
@@ -456,6 +459,8 @@ GenericPlot::plotAreaChanged()
bool
GenericPlot::initialiseChart(QString title, int type, bool animate, int legpos, double scale)
{
clearVoronoi();
// if we changed the type, all series must go
if (charttype != type) {
qchart->removeAllSeries();
@@ -466,6 +471,7 @@ GenericPlot::initialiseChart(QString title, int type, bool animate, int legpos,
percentbarseries=NULL;
}
foreach(QLabel *label, labels) delete label;
labels.clear();
@@ -919,6 +925,9 @@ GenericPlot::finaliseChart()
{
if (!qchart) return;
// remove voronoix if present
clearVoronoi();
// clear ALL axes
foreach(QAbstractAxis *axis, qchart->axes(Qt::Vertical)) {
qchart->removeAxis(axis);
@@ -1246,6 +1255,9 @@ GenericPlot::finaliseChart()
// add labels after legend items
foreach(QLabel *label, labels) legend->addLabel(label);
// add voronoi if need to
plotVoronoi();
plotAreaChanged(); // make sure get updated before paint
}
@@ -1357,3 +1369,46 @@ GenericPlot::seriesColor(QAbstractSeries* series)
default: return GColor(CPLOTMARKER);
}
}
void
GenericPlot::plotVoronoi()
{
// if there is one there already, lets remove it
clearVoronoi();
if (vx.count() < 2) return;
Voronoi v;
for(int i=0; i<vx.count(); i++) v.addSite(QPointF(vx[i],vy[i]));
v.run(QRectF());
#if 0
// how many lines?
fprintf(stderr, "voronoi diagram curve '%s' has %d lines\n", vname.toStdString().c_str(),v.lines().count()); fflush(stderr);
foreach(QLineF line, v.lines()) {
fprintf(stderr, "from %f,%f to %f,%f\n", line.p1().x(), line.p1().y(), line.p2().x(), line.p2().y());
}
#endif
// create a new diagram
voronoidiagram = new GenericLines(this);
voronoidiagram->setCurve(curves.value(vname,NULL));
voronoidiagram->setLines(v.lines());
chartview->scene()->addItem(voronoidiagram);
voronoidiagram->update();
}
void
GenericPlot::clearVoronoi()
{
if (voronoidiagram) {
voronoidiagram->setCurve(NULL);
voronoidiagram->setLines(QList<QLineF>());
voronoidiagram->prepare();
chartview->scene()->removeItem(voronoidiagram);
//delete voronoidiagram; // CRASH!
voronoidiagram = NULL;
}
}

View File

@@ -58,6 +58,7 @@ class GenericPlot;
class GenericLegend;
class GenericSelectTool;
class GenericAxisInfo;
class GenericLines; // draw lines
// the chart
class ChartSpace;
@@ -72,6 +73,7 @@ class GenericPlot : public QWidget {
static QString gl_timeformat;
friend class GenericSelectTool;
friend class GenericLines;
friend class GenericLegend;
GenericPlot(QWidget *parent, Context *context, QGraphicsItem *item);
@@ -107,7 +109,7 @@ class GenericPlot : public QWidget {
// adding annotations
void addAnnotation(AnnotationType, QAbstractSeries*, double yvalue); // LINE
void addAnnotation(AnnotationType, QString, QColor=QColor(Qt::gray)); // LABEL
void addVoronoi(QVector<double>, QVector<double>); // VORONOI
void addVoronoi(QString name, QVector<double>, QVector<double>); // VORONOI
// configure axis, after curves added
bool configureAxis(QString name, bool visible, int align, double min, double max,
@@ -119,6 +121,10 @@ class GenericPlot : public QWidget {
// do we want to see this series?
void setSeriesVisible(QString name, bool visible);
// adding and clearing a voronoi diagram from the chart
void clearVoronoi();
void plotVoronoi();
// watching scene events and managing interaction
void seriesClicked(QAbstractSeries*series, GPointF point);
bool eventHandler(int eventsource, void *obj, QEvent *event);
@@ -126,6 +132,9 @@ class GenericPlot : public QWidget {
void plotAreaChanged();
void pieHover(QPieSlice *slice, bool state);
// access structures
QAbstractSeries *curve(QString name) { return curves.value(name, NULL); }
protected:
// legend and selector need acces to these
@@ -153,7 +162,10 @@ class GenericPlot : public QWidget {
// annotations
QList<QLabel *> labels;
QString vname;
QVector<double> vx, vy; //voronoi digram
GenericLines *voronoidiagram; // draws the lines on the chart
private:
Context *context;

View File

@@ -180,6 +180,10 @@ UserChart::setRide(const RideItem *item)
// clear old annotations for this series
annotations.clear();
// any old voronoi diagram centers
series.voronoix.clear();
series.voronoiy.clear();
// re-create program (may be edited)
if (series.user1 != NULL) delete static_cast<UserChartData*>(series.user1);
series.user1 = new UserChartData(context, this, series.string1, rangemode);
@@ -534,7 +538,7 @@ UserChart::annotateVoronoi(QVector<double>x, QVector<double>y)
UserChartData *ucd = static_cast<UserChartData*>(seriesinfo[i].user1);
if (ucd->program == from) {
seriesinfo[i].voronoix = x;
seriesinfo[i].voronoiy = x;
seriesinfo[i].voronoiy = y;
}
}
}

View File

@@ -655,9 +655,9 @@ greaterThan(QT_MAJOR_VERSION, 4) {
# generic chart
DEFINES += GC_HAVE_GENERIC
HEADERS += Charts/UserChartWindow.h Charts/UserChartOverviewItem.h Charts/UserChart.h Charts/UserChartData.h \
Charts/GenericChart.h Charts/GenericPlot.h Charts/GenericSelectTool.h Charts/GenericLegend.h
Charts/GenericChart.h Charts/GenericPlot.h Charts/GenericSelectTool.h Charts/GenericLegend.h Charts/GenericLines.h
SOURCES += Charts/UserChartWindow.cpp Charts/UserChartOverviewItem.cpp Charts/UserChart.cpp Charts/UserChartData.cpp \
Charts/GenericChart.cpp Charts/GenericPlot.cpp Charts/GenericSelectTool.cpp Charts/GenericLegend.cpp
Charts/GenericChart.cpp Charts/GenericPlot.cpp Charts/GenericSelectTool.cpp Charts/GenericLegend.cpp Charts/GenericLines.cpp
}
}