123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828 |
- #include "pch.h"
- #include "GraphView.h"
- #include <QDebug>
- #include <QPushButton>
- #include <QBrush>
- #include <random>
- #include <algorithm>
- #include <chrono>
- #include "util.h"
- #define X_AXIS_GAP_AMOUNT 5
- #define Y_AXIS_GAP_AMOUNT 10
- #define X_AXIS_NUMBER_LINE_LENGTH 5
- #define Y_AXIS_NUMBER_LINE_LENGTH 5
- #define X_AXIS_NUMBER_GAP_LENGTH 10
- #define Y_AXIS_NUMBER_GAP_LENGTH 30
- #define MARGIN_TOP 10
- #define MARGIN_BOTTOM 20
- #define MARGIN_LEFT 50
- #define MARGIN_RIGHT 10
- GraphView::GraphView(QWidget* parent, Bound fixedBound):QWidget(parent), fixedBound(fixedBound), linePen(Qt::blue), rectPen(QColor(255,255,255,255)), axisPen(Qt::black)
- {
-
- linePen.setJoinStyle(Qt::PenJoinStyle::RoundJoin);
- rectPen.setWidth(0);
- ////generate Random number for starting color
- //std::random_device rd; //Will be used to obtain a seed for the random number engine
- //std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd()
- //std::uniform_real_distribution<double> doubleDistr(0.0, 1.0);
- //hueoffset = doubleDistr(gen);
- hueoffset = 0.5;
- setFocusPolicy(Qt::ClickFocus);
- }
- GraphView::~GraphView()
- {
- }
- void GraphView::paintEvent(QPaintEvent* event)
- {
- std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
- QPainter painter(this);
- painter.setRenderHint(QPainter::RenderHint::HighQualityAntialiasing);
- if (graphSeriesVec.empty() && yDoubleDoubleValuesAmount == 0) {
- painter.setPen(axisPen);
- painter.setFont(QFont("Arial", 12, QFont::Bold));
- painter.drawText(rect(), Qt::AlignCenter, "No Data connected");
- return;
- }
- //Calculate LineRect
- QRect graphDisplayRect(rect());
- graphDisplayRect.setBottom(graphDisplayRect.bottom() - MARGIN_BOTTOM);
- graphDisplayRect.setLeft(graphDisplayRect.left() + MARGIN_LEFT);
- graphDisplayRect.setTop(graphDisplayRect.top() + MARGIN_TOP);
- graphDisplayRect.setRight(graphDisplayRect.right() - MARGIN_RIGHT);
- graphDisplayRect.setWidth(graphDisplayRect.width() - (graphDisplayRect.width() % X_AXIS_GAP_AMOUNT) + 1);
- graphDisplayRect.setHeight(graphDisplayRect.height() - (graphDisplayRect.height() % Y_AXIS_GAP_AMOUNT) + 1);
- painter.setBrush(rectPen.color());
- painter.drawRect(graphDisplayRect);
- painter.setBrush(Qt::BrushStyle::NoBrush);
- double stregth_factorX = graphDisplayRect.width() / rangeGraphX;
- double stregth_factorY = graphDisplayRect.height() / rangeGraphY;
- QPointF translation(graphDisplayRect.left(), graphDisplayRect.top());
- for (const GraphSeries& graphSeries : graphSeriesVec) {
- if (!graphSeries.data) {
- qDebug() << "Pointer to nothing pls help";
- }
- if (graphSeries.data->empty() || graphSeries.hide) continue;
- linePen.setColor(graphSeries.color);
- if (graphSeries.type == GraphSeries::SeriesType::Line || graphSeries.type == GraphSeries::SeriesType::LineDot) {
- linePen.setWidth(graphSeries.lineWidth + ((&graphSeries == highlightSeries) ? 5 : 0));
- painter.setPen(linePen);
- QPainterPath painterPath;
- QPointF oldpoint = graphSeries.data->at(0).toQPointF();
- painterPath.moveTo(transformGraphToView(oldpoint, stregth_factorX, stregth_factorY, translation));
- for (int i = 1; i < graphSeries.data->size(); i++) {
- QPointF newpoint = graphSeries.data->at(i).toQPointF();
- if (!inBoundX(oldpoint) && !inBoundX(newpoint)) {
-
- }
- else if (!inBoundX(oldpoint) && inBoundX(newpoint)) {
- painterPath.moveTo(transformGraphToView(oldpoint, stregth_factorX, stregth_factorY, translation));
- painterPath.lineTo(transformGraphToView(newpoint, stregth_factorX, stregth_factorY, translation));
- }
- else if (inBoundX(oldpoint) && inBoundX(newpoint)) {
- painterPath.lineTo(transformGraphToView(newpoint, stregth_factorX, stregth_factorY, translation));
- }
- else if (inBoundX(oldpoint) && !inBoundX(newpoint)) {
- painterPath.lineTo(transformGraphToView(newpoint, stregth_factorX, stregth_factorY, translation));
- break;
- }
- oldpoint = newpoint;
- }
- //painterPath.translate(translation);
- painter.drawPath(painterPath);
- }
- if (graphSeries.type == GraphSeries::SeriesType::Dot || graphSeries.type == GraphSeries::SeriesType::LineDot) {
- linePen.setWidth(2);
- painter.setPen(linePen);
- painter.setBrush(graphSeries.color);
- for (auto data: *graphSeries.data) {
- if (useInterval) {
- if (data.orginalPoint->iteration < minIter) {
- continue;
- }
- if (data.orginalPoint->iteration > maxIter) {
- break;
- }
- }
- if (graphSeries.useDataPointColor) {
- linePen.setColor(data.color);
- painter.setPen(linePen);
- painter.setBrush(data.color);
- }
- if (inBound(data.toQPointF())) {
- painter.drawEllipse(transformGraphToView(data.toQPointF(), stregth_factorX, stregth_factorY, translation), graphSeries.circleRadius, graphSeries.circleRadius);
- }
- }
- painter.setBrush(Qt::BrushStyle::NoBrush);
- }
- }
- if (yDoubleDoubleValuesAmount > 0) {
- linePen.setWidth(2);
- linePen.setColor(QColor(0,100,200, 0));
- painter.setPen(linePen);
- for (int i = 0; i < yDoubleDoubleValuesAmount; i++) {
- painter.setBrush(pointColors[i]);
- painter.drawEllipse(transformGraphToView(QPointF(yArray[2 * i], yArray[2 * i + 1]), stregth_factorX, stregth_factorY, translation), 3, 3);
- }
- painter.setBrush(Qt::BrushStyle::NoBrush);
- }
- if (drawTotalBound) {
- painter.setPen(axisPen);
- QRectF bounds(transformGraphToView(QPointF(totalBound.minX, totalBound.maxY), stregth_factorX, stregth_factorY, translation), transformGraphToView(QPointF(totalBound.maxX, totalBound.minY), stregth_factorX, stregth_factorY, translation));
- painter.drawRect(bounds);
- }
- //Draw White Rect for axis
- painter.setPen(rectPen);
- painter.setBrush(rectPen.color());
- QRect leftRect(rect().topLeft(), QPoint(graphDisplayRect.left() - 1, rect().bottom()));
- QRect topRect(rect().topLeft(), QPoint(rect().right(), graphDisplayRect.top() - 1));
- QRect bottomRect(QPoint(rect().left(), graphDisplayRect.bottom()), rect().bottomRight());
- QRect rightRect(QPoint(graphDisplayRect.right(), rect().top()), rect().bottomRight());
- painter.drawRect(leftRect);
- painter.drawRect(topRect);
- painter.drawRect(bottomRect);
- painter.drawRect(rightRect);
- painter.setBrush(Qt::BrushStyle::NoBrush);
-
- //painter.drawRect(yAxisRect);
-
-
-
-
-
- //Font for Axis;
- painter.setFont(QFont("Arial", 8));
- //draw X-Axis
- painter.setPen(axisPen);
- QRect xAxisRect(QPoint(graphDisplayRect.left(), graphDisplayRect.bottom()), QPoint(graphDisplayRect.right(), rect().bottom()));
- QPainterPath xAxisPath;
- xAxisPath.moveTo(xAxisRect.left(), xAxisRect.top());
- xAxisPath.lineTo(xAxisRect.right(), xAxisRect.top());
- int xGap = xAxisRect.width() / X_AXIS_GAP_AMOUNT;
- QRect textRect(0, 0, 40, 9);
- for (int i = 0; i < 11; i++) {
- xAxisPath.moveTo(xAxisRect.left() + i * xGap, xAxisRect.top() + X_AXIS_NUMBER_LINE_LENGTH);
- xAxisPath.lineTo(xAxisRect.left() + i * xGap, xAxisRect.top());
- textRect.moveCenter(QPoint(xAxisRect.left() + i * xGap, xAxisRect.top() + X_AXIS_NUMBER_GAP_LENGTH));
- painter.drawText(textRect, Qt::AlignCenter, xAxisNumbers[i]);
- }
- painter.drawPath(xAxisPath);
- //draw Y-Axis
- QRect yAxisRect(QPoint(rect().left(), graphDisplayRect.top()), QPoint(graphDisplayRect.left(), graphDisplayRect.bottom()));
- QPainterPath yAxisPath;
- yAxisPath.moveTo(yAxisRect.right(), yAxisRect.bottom());
- yAxisPath.lineTo(yAxisRect.right(), yAxisRect.top());
- int yGap = yAxisRect.height() / Y_AXIS_GAP_AMOUNT;
- for (int i = 0; i < 11; i++) {
- yAxisPath.moveTo(yAxisRect.right() - Y_AXIS_NUMBER_LINE_LENGTH, yAxisRect.bottom() - i * yGap);
- yAxisPath.lineTo(yAxisRect.right(), yAxisRect.bottom() - i * yGap);
- textRect.moveCenter(QPoint(yAxisRect.right() - Y_AXIS_NUMBER_GAP_LENGTH, yAxisRect.bottom() - i * yGap));
- painter.drawText(textRect, Qt::AlignRight | Qt::AlignVCenter, yAxisNumbers[i]);
- }
- painter.drawPath(yAxisPath);
- std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now();
- std::chrono::milliseconds time = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
- //Mouse:
- if (mousePressed) {
- QColor blue(0, 122, 204);
- QColor gray(120, 120, 120);
- //QPointF value = transformViewToGraph(oldPositionForMouseEvent);
- QPointF viewPoint = transformGraphToView(mousePressedValue, stregth_factorX, stregth_factorY, translation);
- if (graphDisplayRect.top() <= viewPoint.y() && viewPoint.y() <= graphDisplayRect.bottom()) {
- painter.setPen(gray);
- painter.drawLine(QPointF(graphDisplayRect.left() - Y_AXIS_NUMBER_LINE_LENGTH, viewPoint.y()), QPointF(graphDisplayRect.right(), viewPoint.y()));
- textRect.moveCenter(QPoint(graphDisplayRect.left() - Y_AXIS_NUMBER_GAP_LENGTH, viewPoint.y()));
- painter.fillRect(textRect, rectPen.color());
- painter.setPen(blue);
- painter.drawText(textRect, Qt::AlignRight | Qt::AlignVCenter, QString::number(mousePressedValue.y(), 'f', 1));
- }
- if (graphDisplayRect.left() <= viewPoint.x() && viewPoint.x() <= graphDisplayRect.right()) {
- painter.setPen(gray);
- painter.drawLine(QPointF(viewPoint.x(), graphDisplayRect.top()), QPointF(viewPoint.x(), graphDisplayRect.bottom() + X_AXIS_NUMBER_LINE_LENGTH));
- textRect.moveCenter(QPoint(viewPoint.x(), graphDisplayRect.bottom() + X_AXIS_NUMBER_GAP_LENGTH));
- painter.fillRect(textRect, rectPen.color());
- painter.setPen(blue);
- painter.drawText(textRect, Qt::AlignCenter, QString::number(mousePressedValue.x(), 'f', 1));
- }
- }
- qDebug() << "PaintTime: " << time.count() << "ms";
- /*for (GraphSeries& series : graphSeriesVec) {
- qDebug() << "BEGIN ---------";
- for (GraphDataPoint point : *series.data) {
- qDebug() << "QPoint(" << point.x << "," << point.y << ")";
- }
- qDebug() << "END ---------";
- }*/
- }
- QPointF GraphView::transformGraphToView(QPointF& point, double stregth_factorX, double stregth_factorY, QPointF& translation) const
- {
- return QPointF((point.x() - actualBound.minX) * stregth_factorX, (actualBound.maxY - point.y()) * stregth_factorY) + translation;
- }
- QPointF GraphView::transformViewToGraph(QPointF& point) const
- {
- QRect graphDisplayRect(rect());
- graphDisplayRect.setBottom(graphDisplayRect.bottom() - MARGIN_BOTTOM);
- graphDisplayRect.setLeft(graphDisplayRect.left() + MARGIN_LEFT);
- graphDisplayRect.setTop(graphDisplayRect.top() + MARGIN_TOP);
- graphDisplayRect.setRight(graphDisplayRect.right() - MARGIN_RIGHT);
- graphDisplayRect.setWidth(graphDisplayRect.width() - (graphDisplayRect.width() % X_AXIS_GAP_AMOUNT) + 1);
- graphDisplayRect.setHeight(graphDisplayRect.height() - (graphDisplayRect.height() % Y_AXIS_GAP_AMOUNT) + 1);
- QPointF translation(graphDisplayRect.left(), graphDisplayRect.top());
- double stregth_factorX = graphDisplayRect.width() / rangeGraphX;
- double stregth_factorY = graphDisplayRect.height() / rangeGraphY;
- return QPointF(((point.x()-translation.x())/stregth_factorX)+ actualBound.minX, actualBound.maxY - ((point.y()-translation.y())/stregth_factorY));
- }
- GraphDataPoint GraphView::findNearestGraphDataPointFromGraphCoordinate(QPointF& graphpoint)
- {
- if (graphSeriesVec.empty() || graphSeriesVec[0].data->empty()) {
- return GraphDataPoint();
- }
- GraphDataPoint min = graphSeriesVec[0].data->at(0);
- double minSqaredDistance = min.squaredDistance(graphpoint);
- for (GraphSeries& series : graphSeriesVec) {
- for (const GraphDataPoint point : *series.data) {
- double distance = point.squaredDistance(graphpoint);
- if (distance < minSqaredDistance) {
- minSqaredDistance = distance;
- min = point;
- highlightSeries = &series;
- }
- }
- }
- return min;
- }
- //Help Function:
- double sqaredDistance(const QPointF& a, const QPointF& b)
- {
- return std::pow(a.x() - b.x(), 2) + std::pow(a.y() - b.y(), 2);
- }
- GraphDataPoint GraphView::findNearestGraphDataPointFromViewCordinate(QPointF& viewpoint)
- {
- if (graphSeriesVec.empty()) {
- return GraphDataPoint();
- }
- QRect graphDisplayRect(rect());
- graphDisplayRect.setBottom(graphDisplayRect.bottom() - MARGIN_BOTTOM);
- graphDisplayRect.setLeft(graphDisplayRect.left() + MARGIN_LEFT);
- graphDisplayRect.setTop(graphDisplayRect.top() + MARGIN_TOP);
- graphDisplayRect.setRight(graphDisplayRect.right() - MARGIN_RIGHT);
- graphDisplayRect.setWidth(graphDisplayRect.width() - (graphDisplayRect.width() % X_AXIS_GAP_AMOUNT) + 1);
- graphDisplayRect.setHeight(graphDisplayRect.height() - (graphDisplayRect.height() % Y_AXIS_GAP_AMOUNT) + 1);
- QPointF translation(graphDisplayRect.left(), graphDisplayRect.top());
- double stregth_factorX = graphDisplayRect.width() / rangeGraphX;
- double stregth_factorY = graphDisplayRect.height() / rangeGraphY;
- GraphDataPoint min = graphSeriesVec[0].data->at(0);
- double minSqaredDistance = sqaredDistance(min.toQPointF(), viewpoint);
- std::vector<GraphSeries>::iterator actualBestSeries = graphSeriesVec.begin();
- for (auto seriesIter = graphSeriesVec.begin(); seriesIter != graphSeriesVec.end(); seriesIter++) {
- for (const GraphDataPoint point : *seriesIter->data) {
- double distance = sqaredDistance(transformGraphToView(point.toQPointF(), stregth_factorX, stregth_factorY, translation), viewpoint);
- if (distance < minSqaredDistance) {
- minSqaredDistance = distance;
- min = point;
- //highlightSeries = &*seriesIter;
- actualBestSeries = seriesIter;
- }
- }
- }
- std::rotate(graphSeriesVec.begin(), actualBestSeries + 1, graphSeriesVec.end());
- highlightSeries = &graphSeriesVec.back();
- return min;
- }
- bool GraphView::inBoundX(QPointF& point)
- {
- return point.x() >= actualBound.minX && point.x() <= actualBound.maxX;
- }
- bool GraphView::inBoundY(QPointF& point)
- {
- return point.y() >= actualBound.minY && point.y() <= actualBound.maxY;;
- }
- bool GraphView::inBound(QPointF& point)
- {
- return inBoundX(point) && inBoundY(point);
- }
- void GraphView::keyPressEvent(QKeyEvent* event)
- {
- switch (event->key()) {
- case Qt::Key_Up:
- fixedBound.move(this, Bound::Change::MoveUp);
- break;
- case Qt::Key_Right:
- fixedBound.move(this, Bound::Change::MoveRight);
- break;
- case Qt::Key_Left:
- fixedBound.move(this, Bound::Change::MoveLeft);
- break;
- case Qt::Key_Down:
- fixedBound.move(this, Bound::Change::MoveDown);
- break;
- case Qt::Key_PageUp:
- case Qt::Key_Plus:
- if (event->modifiers() & Qt::ShiftModifier) {
- fixedBound.move(this, Bound::Change::ZoomInY);
- }
- else if (event->modifiers() & Qt::ControlModifier) {
- fixedBound.move(this, Bound::Change::ZoomInX);
- }
- else {
- fixedBound.move(this, Bound::Change::ZoomIn);
- }
- break;
- case Qt::Key_PageDown:
- case Qt::Key_Minus:
- if (event->modifiers() & Qt::ShiftModifier) {
- fixedBound.move(this, Bound::Change::ZoomOutY);
- }
- else if (event->modifiers() & Qt::ControlModifier) {
- fixedBound.move(this, Bound::Change::ZoomOutX);
- }
- else {
- fixedBound.move(this, Bound::Change::ZoomOut);
- }
- break;
- case Qt::Key_R:
- resetBound();
- update();
- default:
- QWidget::keyPressEvent(event);
- }
- //If not reacted forward:
- QWidget::keyPressEvent(event);
- }
- void GraphView::resetBound()
- {
- calculateTotalMatrixBound();
- fixedBound = totalBound;
- calculateRangeXY();
- generateAxisNumberStrings();
- }
- void GraphView::wheelEvent(QWheelEvent* event)
- {
- QPoint numPixels = event->pixelDelta();
- QPoint numDegrees = event->angleDelta() / 8;
- if (!numPixels.isNull()) {
- //scrollWithPixels(numPixels);
- switch (numPixels.y()) {
- case -1:
- fixedBound.move(this, Bound::Change::ZoomIn);
- break;
- case 1:
- fixedBound.move(this, Bound::Change::ZoomOut);
- default:
- break;
- }
- }
- else if (!numDegrees.isNull()) {
- QPoint numSteps = numDegrees / 15;
- switch (numSteps.y()) {
- case 1:
- if (event->modifiers() & Qt::ShiftModifier) {
- fixedBound.move(this, Bound::Change::ZoomInY);
- }
- else if (event->modifiers() & Qt::ControlModifier) {
- fixedBound.move(this, Bound::Change::ZoomInX);
- }
- else {
- fixedBound.move(this, Bound::Change::ZoomIn);
- }
- break;
- case -1:
- if (event->modifiers() & Qt::ShiftModifier) {
- fixedBound.move(this, Bound::Change::ZoomOutY);
- }
- else if (event->modifiers() & Qt::ControlModifier) {
- fixedBound.move(this, Bound::Change::ZoomOutX);
- }
- else {
- fixedBound.move(this, Bound::Change::ZoomOut);
- }
- break;
- default:
- break;
- }
- }
- event->accept();
- }
- void GraphView::mouseMoveEvent(QMouseEvent* event)
- {
- //QToolTip::showText(event->globalPos(), "Hello", this);
- QPointF delta = event->pos() - oldPositionForMouseEvent;
- oldPositionForMouseEvent = event->pos();
- double rangeX = std::abs(actualBound.maxX - actualBound.minX);
- int width = (rect().right() - 10) - (rect().left() + 50);
- width -= (width % X_AXIS_GAP_AMOUNT) + 1;
- double pixelWidthX = rangeX / (double)width ;
- double rangeY = std::abs(actualBound.maxY - actualBound.minY);
- int height = (rect().bottom() - 20) - (rect().top() + 20);
- height -= (height % Y_AXIS_GAP_AMOUNT) + 1;
- double pixelWidthY = rangeY / (double)height;
- fixedBound.move(this, delta, pixelWidthX, pixelWidthY);
- }
- void GraphView::mousePressEvent(QMouseEvent* event)
- {
- mousePressed = true;
- //To calculate the delta for mouse move event
- oldPositionForMouseEvent = event->pos();
- mousePressedValue = transformViewToGraph(oldPositionForMouseEvent);
- GraphDataPoint nearestPoint = findNearestGraphDataPointFromViewCordinate(oldPositionForMouseEvent);
- QString metaFileName;
- if (highlightSeries && highlightSeries->run)
- {
- metaFileName = " " + QString::fromStdString(highlightSeries->run->name);
- }
- QString string =metaFileName;
- QToolTip::showText(event->globalPos() - QPoint(0, 35), string);
- }
- void GraphView::mouseReleaseEvent(QMouseEvent* event)
- {
- highlightSeries = nullptr;
- mousePressed = false;
- update();
- }
- void GraphView::update()
- {
- calculateRangeXY();
- generateAxisNumberStrings();
- QWidget::update();
- }
- void GraphView::setDrawBound(bool value)
- {
- drawTotalBound = value;
- }
- /**
- * Delete all series.
- *
- */
- void GraphView::reset()
- {
- graphSeriesVec.clear();
- }
- void GraphView::calculateTotalMatrixBound()
- {
- if (yDoubleDoubleValuesAmount > 0) {
- /*double maxX, maxY;
- double minX = maxX = yArray[0], minY = maxY = yArray[1];
- for (int i = 1; i < yDoubleDoubleValuesAmount; i++) {
-
- if (yArray[2 * i] < minX) {
- minX = yArray[2 * i];
- }else if (yArray[2 * i] > maxX) {
- maxX = yArray[2 * i];
- }
- if (yArray[2 * i + 1] < minY) {
- minY = yArray[2 * i + 1];
- }
- else if (yArray[2 * i + 1] > maxY) {
- maxY = yArray[2 * i + 1];
- }
- }
- totalBound.minX = minX;
- totalBound.minY = minY;
- totalBound.maxX = maxX;
- totalBound.maxY = maxY;*/
- // Calculate AveragePoint of Matrix
-
-
-
-
- }
- }
- void GraphView::calculateTotalGraphBound()
- {
- totalBound.minX = std::min_element(std::begin(graphSeriesVec), std::end(graphSeriesVec), [](const GraphSeries& a, const GraphSeries& b) -> bool {return a.minX < b.minX; })->minX;
- totalBound.maxX = std::max_element(std::begin(graphSeriesVec), std::end(graphSeriesVec), [](const GraphSeries& a, const GraphSeries& b) -> bool {return a.maxX < b.maxX; })->maxX;
- totalBound.minY = std::min_element(std::begin(graphSeriesVec), std::end(graphSeriesVec), [](const GraphSeries& a, const GraphSeries& b) -> bool {return a.minY < b.minY; })->minY;
- totalBound.maxY = std::max_element(std::begin(graphSeriesVec), std::end(graphSeriesVec), [](const GraphSeries& a, const GraphSeries& b) -> bool {return a.maxY < b.maxY; })->maxY;
-
- }
- void GraphView::calculateRangeXY()
- {
- actualBound = fixedBound;
- rangeGraphX = std::abs(actualBound.maxX - actualBound.minX);
- rangeGraphY = std::abs(actualBound.maxY - actualBound.minY);
- if (std::abs(rangeGraphX) < 0.0001) {
- actualBound.minX -= 1.0;
- actualBound.maxX += 1.0;
- rangeGraphX = 2;
- }
- if (std::abs(rangeGraphY) < 0.0001) {
- actualBound.minY -= 1.0;
- actualBound.maxY += 1.0;
- rangeGraphY = 2;
- }
- }
- //TODO: graphview
- void GraphView::calculateMinMaxXY(GraphSeries& lgs)
- {
- auto pairX = std::minmax_element(lgs.data->begin(), lgs.data->end(), [](const GraphDataPoint& a, const GraphDataPoint& b) -> bool {return a.x < b.x; });
- lgs.minX = pairX.first->x;
- lgs.maxX = pairX.second->x;
- auto pairY = std::minmax_element(lgs.data->begin(), lgs.data->end(), [](const GraphDataPoint& a, const GraphDataPoint& b) -> bool {return a.y < b.y; });
- lgs.minY = pairY.first->y;
- lgs.maxY = pairY.second->y;
- }
- void GraphView::addSeries(std::vector<GraphDataPoint>* line, RunData* run, QColor color, GraphSeries::SeriesType type)
- {
- if (line->empty()) {
- qDebug() << "Series is empty!";
- return;
- }
- GraphSeries lgs;
- lgs.run = run;
- lgs.data = line;
- lgs.type = type;
- calculateMinMaxXY(lgs);
- lgs.color = color;
- graphSeriesVec.push_back(lgs);
- calculateTotalGraphBound();
- if (!useFixedBound) calculateRangeXY();
- generateAxisNumberStrings();
- }
- QColor GraphView::generateNextColorForGraph()
- {
- /* http://devmag.org.za/2012/07/29/how-to-choose-colours-procedurally-algorithms/
- use golden ratio 0.618033988749895f
- */
- hueoffset = std::fmod(hueoffset + 0.618033988749895f, 1.0);
- return QColor::fromHsvF(hueoffset, 0.83, 1.0);
- }
- QColor interpolate(QColor& first, QColor& second, double alpha)
- {
- double firstH, firstS, firstL;
- double secondH, secondS, secondL;
- first.getHslF(&firstH, &firstS, &firstL);
- second.getHslF(&secondH, &secondS, &secondL);
- const double h = util::linearInterpolate(firstH, secondH, alpha);
- const double s = util::linearInterpolate(firstS, secondS, alpha);
- const double l = util::linearInterpolate(firstL, secondL, alpha);
- return QColor::fromHslF(h, s, l);
- }
- void GraphView::addYMatrix(double* yArray, int length, std::vector<SolutionPointData>& solVec)
- {
- this->yArray = yArray; yDoubleDoubleValuesAmount = length;
- this->solVec = &solVec;
- if (pointColors != nullptr) delete pointColors;
- pointColors = new QColor[length];
- }
- void GraphView::autoZoomOut()
- {
- if (yDoubleDoubleValuesAmount == 0) return;
- QPointF sumDistance(0, 0);
- for (int i = 0; i < yDoubleDoubleValuesAmount; i++) {
- sumDistance += QPointF(std::abs(yArray[2 * i]), std::abs(yArray[2 * i + 1]));
- }
- QPointF avgDistance(sumDistance.x() / yDoubleDoubleValuesAmount,
- sumDistance.y() / yDoubleDoubleValuesAmount);
- double scalar = 3;
- double addScalar = 1;
- if (fixedBound.maxX < avgDistance.x() * scalar) {
- fixedBound.minX = -avgDistance.x() * scalar * addScalar;
- fixedBound.maxX = avgDistance.x() * scalar * addScalar;
- fixedBound.minY = -avgDistance.y() * scalar * addScalar;
- fixedBound.maxY = avgDistance.y() * scalar * addScalar;
- }
- }
- void GraphView::updateGraphColors(ColorGradient& gradient)
- {
- if (yDoubleDoubleValuesAmount == 0) return;
- double bestValue = 0;
- double worstValue = 100;
- for (int i = 0; i < solVec->size(); i++) {
- pointColors[i] = gradient.getColor( std::clamp(util::inverseLinearInterpolation(bestValue, worstValue, solVec->at(i).objectiveFunction), 0.0, 1.0));
- }
- }
- void GraphView::generateAxisNumberStrings()
- {
- for (int i = 0; i < 11; i++) {
- xAxisNumbers[i] = QString::number(actualBound.minX + i * (rangeGraphX / (double)X_AXIS_GAP_AMOUNT), 'f', 1);
- yAxisNumbers[i] = QString::number(actualBound.minY + i * (rangeGraphY / (double)Y_AXIS_GAP_AMOUNT), 'f', 1);
- }
- }
- void GraphView::setUseFixedBound(bool value)
- {
- //if value == other update else do nothing
- if (useFixedBound != value) {
- useFixedBound = value;
- calculateRangeXY();
- actualBound = fixedBound;
- generateAxisNumberStrings();
- }
- }
- void GraphView::generateAndAddRandomLine()
- {
- std::random_device rd; //Will be used to obtain a seed for the random number engine
- std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd()
- std::uniform_real_distribution<double> realDistr(-30, 30);
- std::uniform_int_distribution<int> intScaleDistr(1, 3);
- for (int randomSeries = 0; randomSeries < 1; randomSeries++) {
- std::vector<GraphDataPoint> randomPointVec(101);
- int scale = intScaleDistr(gen);
- for (int i = 0; i < randomPointVec.size(); i++) {
- randomPointVec[i] = GraphDataPoint(i + 500, i * scale + realDistr(gen));
- }
- addLine(&randomPointVec, nullptr);
- }
- }
- void GraphView::addLine(std::vector<GraphDataPoint>* line, RunData* run)
- {
- addSeries(line, run,generateNextColorForGraph(), GraphSeries::SeriesType::Line);
- }
- void GraphView::addLine(std::vector<GraphDataPoint>* line, RunData* run, QColor color)
- {
- addSeries(line, run, color, GraphSeries::SeriesType::Line);
- }
- void GraphView::addDots(std::vector<GraphDataPoint>* dots, RunData* run)
- {
- addSeries(dots, run, generateNextColorForGraph(), GraphSeries::SeriesType::Dot);
- }
- void GraphView::addDots(std::vector<GraphDataPoint>* dots, RunData* run, QColor color)
- {
- addSeries(dots, run, color, GraphSeries::SeriesType::Dot);
- }
- void GraphView::removeAllSeriesWithRundata(RunData* run)
- {
- //TODO not implemented jet
- //std::for_each(graphSeriesVec);
- }
- void GraphView::removeAllSeries()
- {
- }
- void GraphView::setMinIter(int value)
- {
- minIter = value;
- update();
- }
- void GraphView::setMaxIter(int value)
- {
- maxIter = value;
- update();
- }
- void Bound::move(GraphView* widget,const Change& type, const double changePercentage)
- {
- double changeX = std::abs(minX - maxX) * changePercentage;
- double changeY = std::abs(minY - maxY) * changePercentage;
- switch (type) {
- case Change::MoveLeft:
- minX -= changeX;
- maxX -= changeX;
- break;
- case Change::MoveRight:
- minX += changeX;
- maxX += changeX;
- break;
- case Change::MoveUp:
- minY += changeY;
- maxY += changeY;
- break;
- case Change::MoveDown:
- minY -= changeY;
- maxY -= changeY;
- break;
- case Change::ZoomOut:
- minY -= changeY;
- maxY += changeY;
- minX -= changeX;
- maxX += changeX;
- break;
- case Change::ZoomIn:
- minY += changeY;
- maxY -= changeY;
- minX += changeX;
- maxX -= changeX;
- break;
- case Change::ZoomInX:
- minX += changeX;
- maxX -= changeX;
- break;
- case Change::ZoomInY:
- minY += changeY;
- maxY -= changeY;
- break;
- case Change::ZoomOutX:
- minX -= changeX;
- maxX += changeX;
- break;
- case Change::ZoomOutY:
- minY -= changeY;
- maxY += changeY;
- break;
- default:
- break;
- }
- //TODO: Move out of bound in calculate widget
- widget->update();
- }
- void Bound::move(GraphView* widget, QPointF& delta, double realPixelWidthX, double realPixelWidthY)
- {
- minX += -delta.x() * realPixelWidthX;
- maxX += -delta.x() * realPixelWidthX;
- minY += delta.y() * realPixelWidthY;
- maxY += delta.y() * realPixelWidthY;
- widget->update();
- }
- void Bound::move(GraphView* widget, QPointF& targetPoint)
- {
- //Calculate MiddlePoint
- QPointF actualMiddlePoint((maxX - minX) / 2.0, (maxY - minY) / 2.0);
- QPointF dif = targetPoint - actualMiddlePoint;
- minX += dif.x();
- maxX += dif.x();
- minY += dif.y();
- maxY += dif.y();
- }
|