From 02e2ebf10c30ca278dc8a85649c6a7db87858cde Mon Sep 17 00:00:00 2001 From: Samuel Fadel Date: Tue, 19 May 2015 18:54:20 -0300 Subject: Initial selection implementation. --- scatterplot.cpp | 150 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 125 insertions(+), 25 deletions(-) (limited to 'scatterplot.cpp') diff --git a/scatterplot.cpp b/scatterplot.cpp index a3a0dfc..414f46a 100644 --- a/scatterplot.cpp +++ b/scatterplot.cpp @@ -16,9 +16,22 @@ const float PI = 3.1415f; Scatterplot::Scatterplot(QQuickItem *parent) : QQuickItem(parent) - , m_colorScale{QColor("red"), QColor("green"), QColor("blue")} + , m_dragOriginPos(-1.0, -1.0) + , m_colorScale{ + QColor("#1f77b4"), + QColor("#ff7f0e"), + QColor("#2ca02c"), + QColor("#d62728"), + QColor("#9467bd"), + QColor("#8c564b"), + QColor("#e377c2"), + QColor("#7f7f7f"), + QColor("#bcbd22"), + } { + setClip(true); setFlag(QQuickItem::ItemHasContents); + setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton); } Scatterplot::~Scatterplot() @@ -71,51 +84,138 @@ void updateSquareGeometry(QSGGeometry *geometry, float size, float cx, float cy) vertexData[3].set(cx - r, cy + r); } +void updateSelectionGeometry(QSGGeometry *geometry, const QPointF &p1, const QPointF &p2) +{ + QSGGeometry::Point2D *vertexData = geometry->vertexDataAsPoint2D(); + vertexData[0].set(p1.x(), p1.y()); + vertexData[1].set(p2.x(), p1.y()); + vertexData[2].set(p2.x(), p2.y()); + vertexData[3].set(p1.x(), p2.y()); +} + +QSGNode *Scatterplot::newGlyphNodeTree() { + QSGNode *node = new QSGNode; + int vertexCount = calculateCircleVertexCount(GLYPH_SIZE / 2); + + for (arma::uword i = 0; i < m_data.n_rows; i++) { + QSGGeometryNode *glyphNode = new QSGGeometryNode; + + QSGGeometry *geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), vertexCount); + geometry->setDrawingMode(GL_POLYGON); + glyphNode->setGeometry(geometry); + glyphNode->setFlag(QSGNode::OwnsGeometry); + + QSGFlatColorMaterial *material = new QSGFlatColorMaterial; + material->setColor(m_colorScale.color(m_data(i, 2))); + glyphNode->setMaterial(material); + glyphNode->setFlag(QSGNode::OwnsMaterial); + + node->appendChildNode(glyphNode); + } + + return node; +} + QSGNode *Scatterplot::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) { if (m_data.n_rows < 1) return 0; - QSGNode *node = 0; - int vertexCount = calculateCircleVertexCount(GLYPH_SIZE / 2); qreal xmin = m_data.col(0).min(), xmax = m_data.col(0).max(), ymin = m_data.col(1).min(), ymax = m_data.col(1).max(), x, y; + QSGNode *root = 0; if (!oldNode) { - node = new QSGNode; - for (arma::uword i = 0; i < m_data.n_rows; i++) { - QSGGeometryNode *childNode = new QSGGeometryNode; - - QSGGeometry *geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), vertexCount); - geometry->setDrawingMode(GL_POLYGON); - childNode->setGeometry(geometry); - childNode->setFlag(QSGNode::OwnsGeometry); - - QSGFlatColorMaterial *material = new QSGFlatColorMaterial; - material->setColor(m_colorScale.color(m_data(i, 2))); - childNode->setMaterial(material); - childNode->setFlag(QSGNode::OwnsMaterial); - - node->appendChildNode(childNode); - } + root = new QSGNode; + root->appendChildNode(newGlyphNodeTree()); } else { - node = oldNode; + root = oldNode; } - QSGNode *childNode = node->firstChild(); + QSGNode *glyphNode = root->firstChild()->firstChild(); for (arma::uword i = 0; i < m_data.n_rows; i++) { arma::rowvec row = m_data.row(i); x = PADDING + (row[0] - xmin) / (xmax - xmin) * (width() - 2*PADDING); y = PADDING + (row[1] - ymin) / (ymax - ymin) * (height() - 2*PADDING); - QSGGeometry *geometry = static_cast(childNode)->geometry(); + QSGGeometry *geometry = static_cast(glyphNode)->geometry(); updateCircleGeometry(geometry, GLYPH_SIZE, x, y); - childNode->markDirty(QSGNode::DirtyGeometry); - childNode = childNode->nextSibling(); + glyphNode->markDirty(QSGNode::DirtyGeometry); + glyphNode = glyphNode->nextSibling(); } - return node; + // Draw selection + if (m_currentState == INTERACTION_SELECTING) { + QSGGeometryNode *selectionNode = 0; + if (!root->firstChild()->nextSibling()) { + selectionNode = new QSGGeometryNode; + QSGGeometry *geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 4); + geometry->setDrawingMode(GL_POLYGON); + selectionNode->setGeometry(geometry); + selectionNode->setFlag(QSGNode::OwnsGeometry); + + QSGFlatColorMaterial *material = new QSGFlatColorMaterial; + material->setColor(QColor(128, 128, 128, 128)); + selectionNode->setMaterial(material); + selectionNode->setFlag(QSGNode::OwnsMaterial); + + root->appendChildNode(selectionNode); + } else { + selectionNode = static_cast(root->firstChild()->nextSibling()); + } + + updateSelectionGeometry(selectionNode->geometry(), m_dragOriginPos, m_dragCurrentPos); + selectionNode->markDirty(QSGNode::DirtyGeometry); + } else if (m_currentState == INTERACTION_NONE) { + if (root->firstChild()->nextSibling()) { + root->firstChild()->nextSibling()->markDirty(QSGNode::DirtyGeometry); + root->removeChildNode(root->firstChild()->nextSibling()); + } + } + + return root; +} + +void Scatterplot::mousePressEvent(QMouseEvent *event) +{ + switch (m_currentState) { + case INTERACTION_NONE: + m_currentState = INTERACTION_SELECTING; + m_dragOriginPos = event->localPos(); + break; + case INTERACTION_SELECTED: + m_currentState = INTERACTION_MOVING; + break; // TODO + case INTERACTION_SELECTING: + case INTERACTION_MOVING: + return; // should not be reached + } +} + +void Scatterplot::mouseMoveEvent(QMouseEvent *event) +{ + if (m_currentState != INTERACTION_SELECTING) + return; + + m_dragCurrentPos = event->localPos(); + update(); +} + +void Scatterplot::mouseReleaseEvent(QMouseEvent *event) +{ + switch (m_currentState) { + case INTERACTION_SELECTING: + m_currentState = INTERACTION_NONE; + update(); + break; + + case INTERACTION_MOVING: + break; + case INTERACTION_NONE: + case INTERACTION_SELECTED: + return; // should not be reached + } } -- cgit v1.2.3