aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--forceScheme.cpp13
-rw-r--r--glyph.cpp103
-rw-r--r--glyph.h42
-rw-r--r--main.cpp1
-rw-r--r--mp.h2
-rw-r--r--pm.pro4
-rw-r--r--scatterplot.cpp94
7 files changed, 85 insertions, 174 deletions
diff --git a/forceScheme.cpp b/forceScheme.cpp
index 3683c10..de856ba 100644
--- a/forceScheme.cpp
+++ b/forceScheme.cpp
@@ -11,15 +11,14 @@ arma::mat mp::forceScheme(const arma::mat &D,
double tol,
double fraction)
{
-
- arma::uword n = (arma::uword) Y.n_rows;
+ arma::uword n = Y.n_rows;
V i(n), j(n);
for (arma::uword k = 0; k < n; k++)
i[k] = j[k] = k;
- double prev_delta_sum = 1. / 0.;
+ double prevDeltaSum = 1. / 0.;
for (size_t iter = 0; iter < maxIter; iter++) {
- double delta_sum = 0;
+ double deltaSum = 0;
arma::shuffle(i);
for (V::iterator a = i.begin(); a != i.end(); a++) {
@@ -31,14 +30,14 @@ arma::mat mp::forceScheme(const arma::mat &D,
arma::rowvec direction(Y.row(*b) - Y.row(*a));
double d2 = std::max(arma::norm(direction, 2), mp::EPSILON);
double delta = (D(*a, *b) - d2) / fraction;
- delta_sum += fabs(delta);
+ deltaSum += fabs(delta);
Y.row(*b) += delta * (direction / d2);
}
}
- if (fabs(prev_delta_sum - delta_sum) < tol)
+ if (fabs(prevDeltaSum - deltaSum) < tol)
break;
- prev_delta_sum = delta_sum;
+ prevDeltaSum = deltaSum;
}
return Y;
diff --git a/glyph.cpp b/glyph.cpp
deleted file mode 100644
index f143ee8..0000000
--- a/glyph.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-#include "glyph.h"
-
-#include <cmath>
-#include <QSGGeometry>
-#include <QSGGeometryNode>
-#include <QSGMaterial>
-#include <QSGFlatColorMaterial>
-
-const float PI = 3.1415f;
-
-Glyph::Glyph(QQuickItem *parent)
- : QQuickItem(parent)
- , m_size(0)
-{
- setFlag(QQuickItem::ItemHasContents);
-}
-
-void Glyph::setSize(qreal size)
-{
- if (size == m_size)
- return;
-
- m_size = size;
- setWidth(size);
- setHeight(size);
- emit sizeChanged();
- update();
-}
-
-void Glyph::setColor(const QColor &color)
-{
- if (color == m_color)
- return;
-
- m_color = color;
- emit colorChanged();
- update();
-}
-
-int calculateCircleVertexCount(qreal radius)
-{
- // 10 * sqrt(r) \approx 2*pi / acos(1 - 1 / (4*r))
- return (int) (10.0 * sqrt(radius));
-}
-
-void updateCircleGeometry(QSGGeometry *geometry, const QRectF &bounds)
-{
- int vertexCount = geometry->vertexCount();
- float cy = bounds.center().x();
- float cx = bounds.center().y();
-
- float theta = 2 * PI / float(vertexCount);
- float c = cosf(theta);
- float s = sinf(theta);
- float x = bounds.width() / 2;
- float y = 0;
-
- QSGGeometry::Point2D *vertexData = geometry->vertexDataAsPoint2D();
- for (int i = 0; i < vertexCount; i++) {
- vertexData[i].set(x + cx, y + cy);
-
- float t = x;
- x = c*x - s*y;
- y = s*t + c*y;
- }
-}
-
-QSGNode *Glyph::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
-{
- QSGGeometryNode *node = 0;
- QSGGeometry *geometry = 0;
- QSGFlatColorMaterial *material = 0;
- int vertexCount = calculateCircleVertexCount(m_size / 2);
-
- if (!oldNode) {
- node = new QSGGeometryNode;
-
- geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), vertexCount);
- geometry->setDrawingMode(GL_POLYGON);
- node->setGeometry(geometry);
- node->setFlag(QSGNode::OwnsGeometry);
-
- material = new QSGFlatColorMaterial;
- material->setColor(m_color);
- node->setMaterial(material);
- node->setFlag(QSGNode::OwnsMaterial);
- } else {
- node = static_cast<QSGGeometryNode *>(oldNode);
- geometry = node->geometry();
- geometry->allocate(vertexCount);
- }
-
- updateCircleGeometry(geometry, boundingRect());
- node->markDirty(QSGNode::DirtyGeometry);
-
- material = static_cast<QSGFlatColorMaterial *>(node->material());
- if (material->color() != m_color) {
- material->setColor(m_color);
- node->markDirty(QSGNode::DirtyMaterial);
- }
-
- return node;
-}
diff --git a/glyph.h b/glyph.h
deleted file mode 100644
index 7532d04..0000000
--- a/glyph.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef GLYPH_H
-#define GLYPH_H
-
-#include <QColor>
-#include <QtQuick/QQuickItem>
-
-class Glyph : public QQuickItem
-{
- Q_OBJECT
- Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
- Q_PROPERTY(qreal size READ size WRITE setSize NOTIFY sizeChanged)
-
-public:
- enum GlyphType {
- GLYPH_CIRCLE,
- GLYPH_SQUARE,
- GLYPH_STAR,
- GLYPH_CROSS
- };
-
- Glyph(QQuickItem *parent = 0);
-
- QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *);
-
- QColor color() const { return m_color; }
- void setColor(const QColor &color);
-
- qreal size() const { return m_size; }
- void setSize(qreal size);
-
-signals:
- void colorChanged();
- void sizeChanged();
-
-public slots:
-
-private:
- QColor m_color;
- qreal m_size;
-};
-
-#endif // GLYPH_H
diff --git a/main.cpp b/main.cpp
index 863a20d..794cbc1 100644
--- a/main.cpp
+++ b/main.cpp
@@ -25,7 +25,6 @@ int main(int argc, char **argv)
QGuiApplication app(argc, argv);
qmlRegisterType<Scatterplot>("PM", 1, 0, "Scatterplot");
- qmlRegisterType<Glyph>("PM", 1, 0, "Glyph");
QQuickView view;
QSurfaceFormat format = view.format();
diff --git a/mp.h b/mp.h
index b3f9c75..6508d9d 100644
--- a/mp.h
+++ b/mp.h
@@ -6,6 +6,6 @@ static const double EPSILON = 1e-3;
double euclidean(const arma::rowvec &x1, const arma::rowvec &x2);
arma::mat dist(const arma::mat &X, double (*distCalc)(const arma::rowvec &, const arma::rowvec &) = euclidean);
arma::mat lamp(const arma::mat &X, const arma::uvec &sampleIndices, const arma::mat &Ys);
-arma::mat forceScheme(const arma::mat &D, arma::mat &Y, size_t maxIter = 20, double tol = 1e-3, double fraction = 0.25);
+arma::mat forceScheme(const arma::mat &D, arma::mat &Y, size_t maxIter = 20, double tol = 1e-3, double fraction = 8);
} // namespace mp
diff --git a/pm.pro b/pm.pro
index a8d87d7..2ba534d 100644
--- a/pm.pro
+++ b/pm.pro
@@ -1,11 +1,9 @@
QT += qml quick
QMAKE_LIBS += -larmadillo
-HEADERS += glyph.h \
- scatterplot.h \
+HEADERS += scatterplot.h \
mp.h
SOURCES += main.cpp \
- glyph.cpp \
scatterplot.cpp \
lamp.cpp \
forceScheme.cpp \
diff --git a/scatterplot.cpp b/scatterplot.cpp
index e775661..b5e8261 100644
--- a/scatterplot.cpp
+++ b/scatterplot.cpp
@@ -1,11 +1,16 @@
#include "scatterplot.h"
+#include <cmath>
#include <cstdio>
-#include "glyph.h"
#include <QSGNode>
+#include <QSGGeometry>
#include <QSGGeometryNode>
+#include <QSGMaterial>
+#include <QSGFlatColorMaterial>
-const int GLYPH_SIZE = 10;
+const int GLYPH_SIZE = 4;
+const float PADDING = 5;
+const float PI = 3.1415f;
Scatterplot::Scatterplot()
{
@@ -22,38 +27,93 @@ void Scatterplot::setData(const arma::mat &data)
return;
m_data = data;
- 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();
+ update();
+}
- for (arma::uword i = 0; i < m_data.n_rows; i++) {
- arma::rowvec row = m_data.row(i);
+int calculateCircleVertexCount(qreal radius)
+{
+ // 10 * sqrt(r) \approx 2*pi / acos(1 - 1 / (4*r))
+ return (int) (10.0 * sqrt(radius));
+}
+
+void updateCircleGeometry(QSGGeometry *geometry, float size, float cx, float cy)
+{
+ int vertexCount = geometry->vertexCount();
- Glyph *glyph = new Glyph();
+ float theta = 2 * PI / float(vertexCount);
+ float c = cosf(theta);
+ float s = sinf(theta);
+ float x = size / 2;
+ float y = 0;
- glyph->setSize(5);
- glyph->setX((row[0] - xmin) / (xmax - xmin) * width());
- glyph->setY((row[1] - ymin) / (ymax - ymin) * height());
+ QSGGeometry::Point2D *vertexData = geometry->vertexDataAsPoint2D();
+ for (int i = 0; i < vertexCount; i++) {
+ vertexData[i].set(x + cx, y + cy);
- glyph->setParent(this);
+ float t = x;
+ x = c*x - s*y;
+ y = s*t + c*y;
}
+}
- update();
+void updateSquareGeometry(QSGGeometry *geometry, float size, float cx, float cy)
+{
+ float r = size / 2;
+ QSGGeometry::Point2D *vertexData = geometry->vertexDataAsPoint2D();
+ vertexData[0].set(cx - r, cy - r);
+ vertexData[1].set(cx + r, cy - r);
+ vertexData[2].set(cx + r, cy + r);
+ vertexData[3].set(cx - r, cy + r);
}
QSGNode *Scatterplot::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
QSGNode *node = 0;
+ QSGGeometryNode *childNode = 0;
+ QSGGeometry *geometry = 0;
+ QSGFlatColorMaterial *material = 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;
if (!oldNode) {
node = new QSGNode;
- for (QObjectList::const_iterator it = children().begin(); it != children().end(); it++)
- node->appendChildNode(static_cast<Glyph *>(*it)->updatePaintNode(0, 0));
+ for (arma::uword i = 0; i < m_data.n_rows; i++) {
+ arma::rowvec row = m_data.row(i);
+ x = (row[0] - xmin) / (xmax - xmin) * width();
+ y = (row[1] - ymin) / (ymax - ymin) * height();
+
+ childNode = new QSGGeometryNode;
+
+ geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), vertexCount);
+ geometry->setDrawingMode(GL_POLYGON);
+ childNode->setGeometry(geometry);
+ childNode->setFlag(QSGNode::OwnsGeometry);
+
+ material = new QSGFlatColorMaterial;
+ material->setColor(QColor());
+ childNode->setMaterial(material);
+ childNode->setFlag(QSGNode::OwnsMaterial);
+
+ node->appendChildNode(childNode);
+ }
} else {
- node = static_cast<QSGNode *>(oldNode);
+ node = oldNode;
}
+ childNode = static_cast<QSGGeometryNode *>(node->firstChild());
+ for (arma::uword i = 0; i < m_data.n_rows; i++) {
+ arma::rowvec row = m_data.row(i);
+ x = (row[0] - xmin) / (xmax - xmin) * width();
+ y = (row[1] - ymin) / (ymax - ymin) * height();
+
+ geometry = childNode->geometry();
+ updateCircleGeometry(geometry, GLYPH_SIZE, x, y);
+ childNode = static_cast<QSGGeometryNode *>(childNode->nextSibling());
+ }
node->markDirty(QSGNode::DirtyGeometry);
return node;