GraphPlott.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. #include "pch.h"
  2. #include "GraphPlott.h"
  3. #include <QDebug>
  4. #include <QPen>
  5. #include <QPushButton>
  6. #include <QLayout>
  7. #include <QHBoxLayout>
  8. #include <QVBoxLayout>
  9. #include "HoverButton.h"
  10. #include <QApplication>
  11. #include <QDesktopWidget>
  12. GraphPlott::GraphPlott(QWidget* parent, bool showSettingsButton, bool showInformationButton, bool showGridButton)
  13. : Plott(parent)
  14. {
  15. QVBoxLayout* layoutOuter = new QVBoxLayout(this);
  16. buttonPanel = new QHBoxLayout();
  17. dialog = new GraphViewSettingDialog(this, "Settings");
  18. this->setMouseTracking(true);
  19. buttonPanel->insertStretch(0);
  20. displayLabel = new QLabel("");
  21. buttonPanel->addWidget(displayLabel);
  22. HoverButton* frameButton = new HoverButton();
  23. frameButton->setMinimumSize(20, 20);
  24. frameButton->setMaximumSize(20, 20);
  25. frameButton->setIcon(QIcon(":/metavis/Resources/frame.svg"));
  26. frameButton->setHoveredIcon(QIcon(":/metavis/Resources/frame_hovered.svg"));
  27. frameButton->setAttribute(Qt::WA_TranslucentBackground);
  28. frameButton->setStyleSheet(frameButton->styleSheet() + "border: none;");
  29. frameButton->setToolTip("Frame");
  30. buttonPanel->addWidget(frameButton);
  31. connect(frameButton, &QPushButton::released, this, &GraphPlott::frameGraphInView);
  32. if (showGridButton) {
  33. HoverButton* gridButton = new HoverButton();
  34. gridButton->setMinimumSize(20, 20);
  35. gridButton->setMaximumSize(20, 20);
  36. gridButton->setIcon(QIcon(":/metavis/Resources/gridIcon.svg"));
  37. gridButton->setHoveredIcon(QIcon(":/metavis/Resources/gridIcon_hovered.svg"));
  38. gridButton->setAttribute(Qt::WA_TranslucentBackground);
  39. gridButton->setStyleSheet(gridButton->styleSheet() + "border: none;");
  40. gridButton->setToolTip("Toggle Grid");
  41. buttonPanel->addWidget(gridButton);
  42. connect(gridButton, &QPushButton::released, this, [this]() {this->enableGrid = !this->enableGrid; update(); });
  43. }
  44. if (showInformationButton) {
  45. informationButton->setMinimumSize(20, 20);
  46. informationButton->setMaximumSize(20, 20);
  47. informationButton->setIcon(QIcon(":/metavis/Resources/information_icon.svg"));
  48. informationButton->setHoveredIcon(QIcon(":/metavis/Resources/information_icon_hovered.svg"));
  49. informationButton->setAttribute(Qt::WA_TranslucentBackground);
  50. informationButton->setStyleSheet(informationButton->styleSheet() + "border: none;");
  51. informationButton->setToolTip("Information");
  52. connect(informationButton, &QPushButton::released, this, &GraphPlott::showInformation);
  53. buttonPanel->addWidget(informationButton);
  54. }
  55. if (showSettingsButton) {
  56. HoverButton* settingsButton = new HoverButton();
  57. settingsButton->setMinimumSize(20, 20);
  58. settingsButton->setMaximumSize(20, 20);
  59. settingsButton->setIcon(QIcon(":/metavis/Resources/settingIcon.svg"));
  60. settingsButton->setHoveredIcon(QIcon(":/metavis/Resources/settingIcon_hovered.svg"));
  61. settingsButton->setAttribute(Qt::WA_TranslucentBackground);
  62. settingsButton->setStyleSheet(settingsButton->styleSheet() + "border: none;");
  63. settingsButton->setToolTip("Settings");
  64. buttonPanel->addWidget(settingsButton);
  65. connect(settingsButton, &QPushButton::released, dialog, &GraphViewSettingDialog::openDialog);
  66. }
  67. buttonPanel->setSpacing(0);
  68. buttonPanel->setContentsMargins(0, 0, 0, 0);
  69. layoutOuter->addLayout(buttonPanel);
  70. layoutOuter->insertStretch(1);
  71. layoutOuter->setContentsMargins(0, 0, 0, 0);
  72. //QMenu
  73. selectMenu->addAction(displayAreaAction);
  74. selectMenu->addAction(scratchpadAction);
  75. displayAreaAction->setShortcut(QKeySequence(Qt::CTRL));
  76. scratchpadAction->setShortcut(QKeySequence(Qt::ALT));
  77. scratchpadAction->setEnabled(false);
  78. //setUpTimer
  79. timer->setSingleShot(true);
  80. connect(timer, &QTimer::timeout, this, &GraphPlott::searchForPointUnderCursor);
  81. }
  82. GraphPlott::~GraphPlott()
  83. {
  84. }
  85. void GraphPlott::addSeries(std::vector<GraphDataPoint>* line, std::string runName, QString description, QColor color, GraphPlottSeries::SeriesType type)
  86. {
  87. if (line->empty()) {
  88. qDebug() << "Series is empty!";
  89. return;
  90. }
  91. GraphPlottSeries lgs;
  92. lgs.runName = runName;
  93. lgs.description = description;
  94. lgs.data = line;
  95. lgs.type = type;
  96. lgs.color = color;
  97. //set min max x y
  98. auto pairX = std::minmax_element(lgs.data->begin(), lgs.data->end(), [](const GraphDataPoint& a, const GraphDataPoint& b) -> bool {return a.x < b.x; });
  99. lgs.xMin = pairX.first->x;
  100. lgs.xMax = pairX.second->x;
  101. auto pairY = std::minmax_element(lgs.data->begin(), lgs.data->end(), [](const GraphDataPoint& a, const GraphDataPoint& b) -> bool {return a.y < b.y; });
  102. lgs.yMin = pairY.first->y;
  103. lgs.yMax = pairY.second->y;
  104. seriesVec.push_back(lgs);
  105. }
  106. void GraphPlott::removeRunData(RunData* run)
  107. {
  108. //Remove all series with this rundata
  109. auto iter = std::remove_if(seriesVec.begin(), seriesVec.end(), [run](GraphPlottSeries& series) {return (run->name == series.runName); });
  110. seriesVec.erase(iter, seriesVec.end());
  111. displayLabel->setText("");
  112. }
  113. void GraphPlott::removeAll()
  114. {
  115. seriesVec.clear();
  116. }
  117. void GraphPlott::setInformation(QString information)
  118. {
  119. this->informationButtonString = information;
  120. popupWidget->setInformation(information);
  121. }
  122. std::vector<GraphPlottSeries>& GraphPlott::getSeriesVector()
  123. {
  124. return seriesVec;
  125. }
  126. void GraphPlott::resetToDefaultWindow()
  127. {
  128. frameGraphInView();
  129. }
  130. void GraphPlott::frameGraphInView()
  131. {
  132. if(seriesVec.empty()) return;
  133. window.xMin = std::min_element(std::begin(seriesVec), std::end(seriesVec), [](const GraphPlottSeries& a, const GraphPlottSeries& b) -> bool {return a.xMin < b.xMin; })->xMin;
  134. window.xMax = std::max_element(std::begin(seriesVec), std::end(seriesVec), [](const GraphPlottSeries& a, const GraphPlottSeries& b) -> bool {return a.xMax < b.xMax; })->xMax;
  135. window.yMin = std::min_element(std::begin(seriesVec), std::end(seriesVec), [](const GraphPlottSeries& a, const GraphPlottSeries& b) -> bool {return a.yMin < b.yMin; })->yMin;
  136. window.yMax = std::max_element(std::begin(seriesVec), std::end(seriesVec), [](const GraphPlottSeries& a, const GraphPlottSeries& b) -> bool {return a.yMax < b.yMax; })->yMax;
  137. window.ZoomOut(0.05);
  138. update();
  139. }
  140. void GraphPlott::setDisplayLabel(QString file)
  141. {
  142. displayLabel->setText("\"" + file + "\" ");
  143. }
  144. void GraphPlott::setScratchpad(Scratchpad* pad)
  145. {
  146. this->pad = pad;
  147. scratchpadAction->setEnabled(true);
  148. }
  149. void GraphPlott::showInformation()
  150. {
  151. QPoint position = QCursor::pos();
  152. popupWidget->setInformation(informationButtonString + graphplottInformation);
  153. popupWidget->width();
  154. QRect screen = QApplication::desktop()->screenGeometry();
  155. if (position.x() + popupWidget->width() > screen.width()) {
  156. popupWidget->move(screen.width() - popupWidget->width(), position.y());
  157. }
  158. else {
  159. popupWidget->move(position.x(), position.y());
  160. }
  161. popupWidget->show();
  162. }
  163. void GraphPlott::drawData(QPainter& painter)
  164. {
  165. QPen linePen;
  166. QRect graphDisplayRect = getDisplayRect();
  167. QPointF translation(graphDisplayRect.left(), graphDisplayRect.top());
  168. double stregth_factorX = graphDisplayRect.width() / std::abs(window.xMax - window.xMin);
  169. double stregth_factorY = graphDisplayRect.height() / std::abs(window.yMax - window.yMin);
  170. for (const GraphPlottSeries& graphSeries : seriesVec) {
  171. if (!graphSeries.data) {
  172. qDebug() << "Pointer to nothing pls help";
  173. }
  174. if (graphSeries.data->empty() || graphSeries.hide) continue;
  175. linePen.setColor(graphSeries.color);
  176. if (graphSeries.type == GraphPlottSeries::SeriesType::Line || graphSeries.type == GraphPlottSeries::SeriesType::LineDot) {
  177. linePen.setWidth(graphSeries.lineWidth/* + ((&graphSeries == highlightSeries) ? 5 : 0)*/);
  178. painter.setPen(linePen);
  179. QPainterPath painterPath;
  180. QPointF oldpoint = graphSeries.data->at(0).toQPointF();
  181. painterPath.moveTo(transformGraphToView(oldpoint, stregth_factorX, stregth_factorY, translation));
  182. for (int i = 1; i < graphSeries.data->size(); i++) {
  183. QPointF newpoint = graphSeries.data->at(i).toQPointF();
  184. bool inBoundOldPoint = window.inBoundX(oldpoint);
  185. bool inBoundNewPoint = window.inBoundX(newpoint);
  186. if (!inBoundOldPoint && !inBoundNewPoint) {
  187. }
  188. else if (!inBoundOldPoint && inBoundNewPoint) {
  189. painterPath.moveTo(transformGraphToView(oldpoint, stregth_factorX, stregth_factorY, translation));
  190. painterPath.lineTo(transformGraphToView(newpoint, stregth_factorX, stregth_factorY, translation));
  191. }
  192. else if (inBoundOldPoint && inBoundNewPoint) {
  193. painterPath.lineTo(transformGraphToView(newpoint, stregth_factorX, stregth_factorY, translation));
  194. }
  195. else if (inBoundOldPoint && !inBoundNewPoint) {
  196. painterPath.lineTo(transformGraphToView(newpoint, stregth_factorX, stregth_factorY, translation));
  197. break;
  198. }
  199. oldpoint = newpoint;
  200. }
  201. //painterPath.translate(translation);
  202. painter.drawPath(painterPath);
  203. }
  204. if (graphSeries.type == GraphPlottSeries::SeriesType::Dot || graphSeries.type == GraphPlottSeries::SeriesType::LineDot) {
  205. linePen.setWidth(2);
  206. linePen.setColor(Qt::transparent);
  207. painter.setPen(linePen);
  208. painter.setBrush(graphSeries.color);
  209. const bool useColor = graphSeries.useDataPointColor;
  210. for (auto data : *graphSeries.data) {
  211. if (useColor){
  212. linePen.setColor(data.color);
  213. painter.setPen(linePen);
  214. painter.setBrush(data.color);
  215. }
  216. if (window.inBound(data.toQPointF())) {
  217. painter.drawEllipse(transformGraphToView(data.toQPointF(), stregth_factorX, stregth_factorY, translation), graphSeries.circleRadius, graphSeries.circleRadius);
  218. }
  219. }
  220. painter.setBrush(Qt::BrushStyle::NoBrush);
  221. }
  222. }
  223. }
  224. void GraphPlott::mouseMoveEvent(QMouseEvent* event)
  225. {
  226. Plott::mouseMoveEvent(event);
  227. lastPosition = event->pos();
  228. timer->start(stayStillTimeMS);
  229. QToolTip::hideText();
  230. }
  231. void GraphPlott::handleSelectedWindow(VisibleWindow& window, QMouseEvent* event)
  232. {
  233. if (event->modifiers() & Qt::ControlModifier) {
  234. setWindow(window);
  235. }
  236. else if (event->modifiers() & Qt::AltModifier) {
  237. addPointsInWindowToScratchPad(window);
  238. }
  239. else {
  240. QAction* used = selectMenu->exec(this->mapToGlobal(event->pos()));
  241. if(used == displayAreaAction){
  242. setWindow(window);
  243. }
  244. else if (used == scratchpadAction) {
  245. addPointsInWindowToScratchPad(window);
  246. }
  247. }
  248. }
  249. void GraphPlott::searchForPointUnderCursor()
  250. {
  251. //check if mouse stayed still
  252. QPoint globalPosition = QCursor::pos();
  253. QPointF pos = this->mapFromGlobal(globalPosition);
  254. if (pos != lastPosition) {
  255. return;
  256. }
  257. if (seriesVec.empty() || seriesVec[0].data->empty()) {
  258. return;
  259. }
  260. QRect graphDisplayRect = getDisplayRect();
  261. QPointF translation(graphDisplayRect.left(), graphDisplayRect.top());
  262. double stregth_factorX = graphDisplayRect.width() / std::abs(window.xMax - window.xMin);
  263. double stregth_factorY = graphDisplayRect.height() / std::abs(window.yMax - window.yMin);
  264. const GraphDataPoint* min = &seriesVec[0].data->at(0);
  265. double minSqaredDistance = sqaredDistance(transformGraphToView(min->toQPointF(), stregth_factorX, stregth_factorY, translation), pos);
  266. std::vector<GraphPlottSeries>::iterator actualBestSeries = seriesVec.begin();
  267. for (auto seriesIter = seriesVec.begin(); seriesIter != seriesVec.end(); seriesIter++) {
  268. for (const GraphDataPoint& point : *seriesIter->data) {
  269. double distance = sqaredDistance(transformGraphToView(point.toQPointF(), stregth_factorX, stregth_factorY, translation), pos);
  270. if (distance <= minSqaredDistance) {
  271. minSqaredDistance = distance;
  272. min = &point;
  273. actualBestSeries = seriesIter;
  274. }
  275. }
  276. }
  277. if (minSqaredDistance <= 20) {
  278. QPointF pointInWidget = transformGraphToView(min->toQPointF(), stregth_factorX, stregth_factorY, translation);
  279. QToolTip::showText(this->mapToGlobal(QPoint(pointInWidget.x(), pointInWidget.y())) - QPoint(0, 35), actualBestSeries->description);
  280. }
  281. }
  282. double GraphPlott::sqaredDistance(const QPointF& a, const QPointF& b)
  283. {
  284. return std::pow(a.x() - b.x(), 2) + std::pow(a.y() - b.y(), 2);
  285. }
  286. void GraphPlott::addPointsInWindowToScratchPad(VisibleWindow& window)
  287. {
  288. if (!pad) {
  289. qDebug() << "NoPad";
  290. return;
  291. }
  292. for (auto seriesIter = seriesVec.begin(); seriesIter != seriesVec.end(); seriesIter++) {
  293. if (seriesIter->hide) continue;
  294. for (const GraphDataPoint& point : *seriesIter->data) {
  295. if (window.inBound(point.toQPointF()) && point.existLink()) {
  296. pad->addPoint(*point.orginalPoint);
  297. }
  298. }
  299. }
  300. }
  301. void GraphPlott::keyPressEvent(QKeyEvent* event)
  302. {
  303. Plott::keyPressEvent(event);
  304. switch (event->key()) {
  305. case Qt::Key_T:
  306. frameGraphInView();
  307. break;
  308. default:
  309. break;
  310. }
  311. }