diff options
Diffstat (limited to 'scatterplot.cpp')
-rw-r--r-- | scatterplot.cpp | 281 |
1 files changed, 59 insertions, 222 deletions
diff --git a/scatterplot.cpp b/scatterplot.cpp index 460e738..fc31daa 100644 --- a/scatterplot.cpp +++ b/scatterplot.cpp @@ -2,62 +2,37 @@ #include <algorithm> #include <cmath> -#include <limits> - -#include <QSGGeometryNode> -#include <QSGSimpleRectNode> #include "continuouscolorscale.h" #include "geometry.h" // Glyphs settings -static const QColor DEFAULT_GLYPH_COLOR(255, 255, 255); +static const Color DEFAULT_GLYPH_COLOR(255, 255, 255); static const float DEFAULT_GLYPH_SIZE = 8.0f; -static const qreal GLYPH_OPACITY = 1.0; -static const qreal GLYPH_OPACITY_SELECTED = 1.0; +static const float GLYPH_OPACITY = 1.0f; +static const float GLYPH_OPACITY_SELECTED = 1.0f; static const float GLYPH_OUTLINE_WIDTH = 2.0f; -static const QColor GLYPH_OUTLINE_COLOR(0, 0, 0); -static const QColor GLYPH_OUTLINE_COLOR_SELECTED(20, 255, 225); +static const Color GLYPH_OUTLINE_COLOR(0, 0, 0); +static const Color GLYPH_OUTLINE_COLOR_SELECTED(20, 255, 225); // Brush settings -static const float BRUSHING_MAX_DIST = 20.0f; +// BRUSHING_MAX_DIST in quadtree.cpp static const float CROSSHAIR_LENGTH = 8.0f; static const float CROSSHAIR_THICKNESS1 = 1.0f; static const float CROSSHAIR_THICKNESS2 = 0.5f; -static const QColor CROSSHAIR_COLOR1(255, 255, 255); -static const QColor CROSSHAIR_COLOR2(0, 0, 0); +static const Color CROSSHAIR_COLOR1(255, 255, 255); +static const Color CROSSHAIR_COLOR2(0, 0, 0); // Selection settings -static const QColor SELECTION_COLOR(128, 128, 128, 96); +static const Color SELECTION_COLOR(128, 128, 128, 96); // Mouse buttons -static const Qt::MouseButton NORMAL_BUTTON = Qt::LeftButton; -static const Qt::MouseButton SPECIAL_BUTTON = Qt::RightButton; +// static const Qt::MouseButton NORMAL_BUTTON = Qt::LeftButton; +// static const Qt::MouseButton SPECIAL_BUTTON = Qt::RightButton; -class QuadTree -{ -public: - QuadTree(const QRectF &bounds); - ~QuadTree(); - bool insert(float x, float y, int value); - int query(float x, float y) const; - void query(const QRectF &rect, std::vector<int> &result) const; - int nearestTo(float x, float y) const; - -private: - bool subdivide(); - void nearestTo(float x, float y, int &nearest, float &dist) const; - - QRectF m_bounds; - float m_x, m_y; - int m_value; - QuadTree *m_nw, *m_ne, *m_sw, *m_se; -}; - -Scatterplot::Scatterplot(QQuickItem *parent) - : QQuickItem(parent) - , m_glyphSize(DEFAULT_GLYPH_SIZE) +Scatterplot::Scatterplot() + : m_glyphSize(DEFAULT_GLYPH_SIZE) , m_colorScale(0) , m_autoScale(true) , m_sx(0, 1, 0, 1) @@ -68,20 +43,10 @@ Scatterplot::Scatterplot(QQuickItem *parent) , m_dragEnabled(false) , m_shouldUpdateGeometry(false) , m_shouldUpdateMaterials(false) - , m_quadtree(0) { - setClip(true); - setFlag(QQuickItem::ItemHasContents); } -Scatterplot::~Scatterplot() -{ - if (m_quadtree) { - delete m_quadtree; - } -} - -void Scatterplot::setColorScale(const ColorScale *colorScale) +void Scatterplot::setColorScale(std::shared_ptr<const ColorScale> colorScale) { m_colorScale = colorScale; if (m_colorData.n_elem > 0) { @@ -102,7 +67,7 @@ void Scatterplot::setXY(const arma::mat &xy) } m_xy = xy; - emit xyChanged(m_xy); + xyChanged(m_xy); if (m_autoScale) { autoScale(); @@ -118,7 +83,7 @@ void Scatterplot::setXY(const arma::mat &xy) // Reset opacity data m_opacityData.resize(xy.n_rows); m_opacityData.fill(GLYPH_OPACITY); - emit opacityDataChanged(m_opacityData); + opacityDataChanged(m_opacityData); } m_shouldUpdateGeometry = true; @@ -133,7 +98,7 @@ void Scatterplot::setColorData(const arma::vec &colorData) } m_colorData = colorData; - emit colorDataChanged(m_colorData); + colorDataChanged(m_colorData); m_shouldUpdateMaterials = true; update(); @@ -146,7 +111,7 @@ void Scatterplot::setOpacityData(const arma::vec &opacityData) } m_opacityData = opacityData; - emit opacityDataChanged(m_opacityData); + opacityDataChanged(m_opacityData); update(); } @@ -154,7 +119,7 @@ void Scatterplot::setScale(const LinearScale<float> &sx, const LinearScale<float { m_sx = sx; m_sy = sy; - emit scaleChanged(m_sx, m_sy); + scaleChanged(m_sx, m_sy); updateQuadTree(); @@ -174,7 +139,7 @@ void Scatterplot::autoScale() { m_sx.setDomain(m_xy.col(0).min(), m_xy.col(0).max()); m_sy.setDomain(m_xy.col(1).min(), m_xy.col(1).max()); - emit scaleChanged(m_sx, m_sy); + scaleChanged(m_sx, m_sy); } void Scatterplot::setGlyphSize(float glyphSize) @@ -184,12 +149,17 @@ void Scatterplot::setGlyphSize(float glyphSize) } m_glyphSize = glyphSize; - emit glyphSizeChanged(m_glyphSize); + glyphSizeChanged(m_glyphSize); m_shouldUpdateGeometry = true; update(); } +void Scatterplot::update() +{ +} + +/* QSGNode *Scatterplot::newSceneGraph() { // NOTE: @@ -235,7 +205,9 @@ QSGNode *Scatterplot::newSceneGraph() return root; } +*/ +/* QSGNode *Scatterplot::newGlyphTree() { // NOTE: @@ -282,7 +254,9 @@ QSGNode *Scatterplot::newGlyphTree() return node; } +*/ +/* QSGNode *Scatterplot::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) { QSGNode *root = oldNode ? oldNode : newSceneGraph(); @@ -321,7 +295,9 @@ QSGNode *Scatterplot::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) return root; } +*/ +/* void Scatterplot::updateGlyphs(QSGNode *glyphsNode) { qreal x, y, tx, ty, moveTranslationF; @@ -388,7 +364,9 @@ void Scatterplot::updateGlyphs(QSGNode *glyphsNode) // though. glyphsNode->markDirty(QSGNode::DirtyForceUpdate); } +*/ +/* void Scatterplot::updateBrush(QSGNode *node) { QMatrix4x4 transform; @@ -404,7 +382,9 @@ void Scatterplot::updateBrush(QSGNode *node) QSGTransformNode *brushNode = static_cast<QSGTransformNode *>(node); brushNode->setMatrix(transform); } +*/ +/* void Scatterplot::mousePressEvent(QMouseEvent *event) { switch (m_interactionState) { @@ -425,7 +405,7 @@ void Scatterplot::mousePressEvent(QMouseEvent *event) case SPECIAL_BUTTON: m_interactionState = StateNone; m_selection.assign(m_selection.size(), false); - emit selectionInteractivelyChanged(m_selection); + selectionInteractivelyChanged(m_selection); m_shouldUpdateMaterials = true; update(); break; @@ -438,7 +418,9 @@ void Scatterplot::mousePressEvent(QMouseEvent *event) break; } } +*/ +/* void Scatterplot::mouseMoveEvent(QMouseEvent *event) { switch (m_interactionState) { @@ -461,7 +443,9 @@ void Scatterplot::mouseMoveEvent(QMouseEvent *event) break; } } +*/ +/* void Scatterplot::mouseReleaseEvent(QMouseEvent *event) { bool mergeSelection = (event->modifiers() == Qt::ControlModifier); @@ -478,7 +462,7 @@ void Scatterplot::mouseReleaseEvent(QMouseEvent *event) m_interactionState = StateNone; if (m_anySelected && !mergeSelection) { m_anySelected = false; - emit selectionInteractivelyChanged(m_selection); + selectionInteractivelyChanged(m_selection); m_shouldUpdateMaterials = true; update(); } @@ -489,7 +473,7 @@ void Scatterplot::mouseReleaseEvent(QMouseEvent *event) m_anySelected = true; } - emit selectionInteractivelyChanged(m_selection); + selectionInteractivelyChanged(m_selection); m_shouldUpdateMaterials = true; update(); } @@ -503,7 +487,7 @@ void Scatterplot::mouseReleaseEvent(QMouseEvent *event) QPoint pos = event->pos(); m_brushedItem = m_quadtree->nearestTo(pos.x(), pos.y()); - emit itemInteractivelyBrushed(m_brushedItem); + itemInteractivelyBrushed(m_brushedItem); m_shouldUpdateMaterials = true; update(); } @@ -522,32 +506,39 @@ void Scatterplot::mouseReleaseEvent(QMouseEvent *event) break; } } +*/ +/* void Scatterplot::hoverEnterEvent(QHoverEvent *event) { QPointF pos = event->posF(); m_brushedItem = m_quadtree->nearestTo(pos.x(), pos.y()); - emit itemInteractivelyBrushed(m_brushedItem); + itemInteractivelyBrushed(m_brushedItem); update(); } +*/ +/* void Scatterplot::hoverMoveEvent(QHoverEvent *event) { QPointF pos = event->posF(); m_brushedItem = m_quadtree->nearestTo(pos.x(), pos.y()); - emit itemInteractivelyBrushed(m_brushedItem); + itemInteractivelyBrushed(m_brushedItem); update(); } +*/ +/* void Scatterplot::hoverLeaveEvent(QHoverEvent *event) { m_brushedItem = -1; - emit itemInteractivelyBrushed(m_brushedItem); + itemInteractivelyBrushed(m_brushedItem); update(); } +*/ void Scatterplot::interactiveSelection(bool mergeSelection) { @@ -556,7 +547,7 @@ void Scatterplot::interactiveSelection(bool mergeSelection) } std::vector<int> selected; - m_quadtree->query(QRectF(m_dragOriginPos, m_dragCurrentPos), selected); + m_quadtree->query(RectF(m_dragOriginPos, m_dragCurrentPos), selected); for (auto i: selected) { m_selection[i] = true; } @@ -568,7 +559,7 @@ void Scatterplot::interactiveSelection(bool mergeSelection) } } - emit selectionInteractivelyChanged(m_selection); + selectionInteractivelyChanged(m_selection); } void Scatterplot::setSelection(const std::vector<bool> &selection) @@ -578,7 +569,7 @@ void Scatterplot::setSelection(const std::vector<bool> &selection) } m_selection = selection; - emit selectionChanged(m_selection); + selectionChanged(m_selection); m_shouldUpdateMaterials = true; update(); @@ -613,7 +604,7 @@ void Scatterplot::applyManipulation() updateQuadTree(); - emit xyInteractivelyChanged(m_xy); + xyInteractivelyChanged(m_xy); } void Scatterplot::updateQuadTree() @@ -621,163 +612,9 @@ void Scatterplot::updateQuadTree() m_sx.setRange(PADDING, width() - PADDING); m_sy.setRange(height() - PADDING, PADDING); - if (m_quadtree) { - delete m_quadtree; - } - - m_quadtree = new QuadTree(QRectF(x(), y(), width(), height())); + m_quadtree.reset(new QuadTree(RectF(x(), y(), width(), height()))); for (arma::uword i = 0; i < m_xy.n_rows; i++) { const arma::rowvec &row = m_xy.row(i); m_quadtree->insert(m_sx(row[0]), m_sy(row[1]), (int) i); } } - -QuadTree::QuadTree(const QRectF &bounds) - : m_bounds(bounds) - , m_value(-1) - , m_nw(0), m_ne(0), m_sw(0), m_se(0) -{ -} - -QuadTree::~QuadTree() -{ - if (m_nw) { - delete m_nw; - delete m_ne; - delete m_sw; - delete m_se; - } -} - -bool QuadTree::subdivide() -{ - float halfWidth = m_bounds.width() / 2; - float halfHeight = m_bounds.height() / 2; - - m_nw = new QuadTree(QRectF(m_bounds.x(), - m_bounds.y(), - halfWidth, - halfHeight)); - m_ne = new QuadTree(QRectF(m_bounds.x() + halfWidth, - m_bounds.y(), - halfWidth, - halfHeight)); - m_sw = new QuadTree(QRectF(m_bounds.x(), - m_bounds.y() + halfHeight, - halfWidth, - halfHeight)); - m_se = new QuadTree(QRectF(m_bounds.x() + halfWidth, - m_bounds.y() + halfHeight, - halfWidth, - halfHeight)); - - int value = m_value; - m_value = -1; - return m_nw->insert(m_x, m_y, value) - || m_ne->insert(m_x, m_y, value) - || m_sw->insert(m_x, m_y, value) - || m_se->insert(m_x, m_y, value); -} - -bool QuadTree::insert(float x, float y, int value) -{ - if (!m_bounds.contains(x, y)) { - return false; - } - - if (m_nw) { - return m_nw->insert(x, y, value) - || m_ne->insert(x, y, value) - || m_sw->insert(x, y, value) - || m_se->insert(x, y, value); - } - - if (m_value >= 0) { - subdivide(); - return insert(x, y, value); - } - - m_x = x; - m_y = y; - m_value = value; - return true; -} - -int QuadTree::nearestTo(float x, float y) const -{ - if (!m_bounds.contains(x, y)) { - return -1; - } - - int q; - if (m_nw) { - q = m_nw->nearestTo(x, y); - if (q >= 0) return q; - q = m_ne->nearestTo(x, y); - if (q >= 0) return q; - q = m_sw->nearestTo(x, y); - if (q >= 0) return q; - q = m_se->nearestTo(x, y); - if (q >= 0) return q; - } - - float dist = std::numeric_limits<float>::infinity(); - nearestTo(x, y, q, dist); - if (dist < BRUSHING_MAX_DIST * BRUSHING_MAX_DIST) - return q; - return -1; -} - -void QuadTree::nearestTo(float x, float y, int &nearest, float &dist) const -{ - if (m_nw) { - m_nw->nearestTo(x, y, nearest, dist); - m_ne->nearestTo(x, y, nearest, dist); - m_sw->nearestTo(x, y, nearest, dist); - m_se->nearestTo(x, y, nearest, dist); - } else if (m_value >= 0) { - float d = (m_x - x)*(m_x - x) + (m_y - y)*(m_y - y); - if (d < dist) { - nearest = m_value; - dist = d; - } - } -} - -int QuadTree::query(float x, float y) const -{ - if (!m_bounds.contains(x, y)) { - // There is no way we could find the point - return -1; - } - - if (m_nw) { - int q = -1; - q = m_nw->query(x, y); - if (q >= 0) return q; - q = m_ne->query(x, y); - if (q >= 0) return q; - q = m_sw->query(x, y); - if (q >= 0) return q; - q = m_se->query(x, y); - return q; - } - - return m_value; -} - -void QuadTree::query(const QRectF &rect, std::vector<int> &result) const -{ - if (!m_bounds.intersects(rect)) { - return; - } - - if (m_nw) { - m_nw->query(rect, result); - m_ne->query(rect, result); - m_sw->query(rect, result); - m_se->query(rect, result); - } else if (rect.contains(m_x, m_y) && m_value != -1) { - result.push_back(m_value); - } -} |