Skip to content

Commit

Permalink
feat: add fractal hilbert plot
Browse files Browse the repository at this point in the history
  • Loading branch information
hello-adam committed Apr 22, 2020
1 parent ce5737b commit 727a6f1
Show file tree
Hide file tree
Showing 11 changed files with 330 additions and 0 deletions.
13 changes: 13 additions & 0 deletions src/hobbits-core/bitarray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,19 @@ bool BitArray::at(qint64 i) const
}


char BitArray::byteAt(qint64 i) const
{
if (i < 0 || i >= sizeInBytes()) {
throw std::invalid_argument(QString("Invalid byte index '%1'").arg(i).toStdString());
}
qint64 cacheIdx = i / CACHE_CHUNK_BYTE_SIZE;
if (!m_dataCaches[cacheIdx]) {
loadCacheAt(i);
}
int index = int(i - cacheIdx * CACHE_CHUNK_BYTE_SIZE);
return m_dataCaches[cacheIdx][index];
}

quint64 BitArray::getWordValue(qint64 bitOffset, int wordBitSize) const
{
quint64 word = 0;
Expand Down
1 change: 1 addition & 0 deletions src/hobbits-core/bitarray.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class HOBBITSCORESHARED_EXPORT BitArray
~BitArray();

bool at(qint64 i) const;
char byteAt(qint64 i) const;
qint64 sizeInBits() const;
qint64 sizeInBytes() const;
quint64 getWordValue(qint64 bitOffset, int wordBitSize) const;
Expand Down
58 changes: 58 additions & 0 deletions src/hobbits-plugins/displays/HilbertPlot/HilbertPlot.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#-------------------------------------------------
#
# Project created by QtCreator 2020-04-21T21:34:06.622Z
#
#-------------------------------------------------

QT += widgets

QT -= gui

TARGET = HilbertPlot
TEMPLATE = lib

DEFINES += HILBERTPLOT_LIBRARY

CONFIG += c++11 plugin
CONFIG -= debug_and_release_target

# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0

SOURCES += hilbertplot.cpp hilbertplotwidget.cpp hilbertplotcontrols.cpp

HEADERS += hilbertplot.h hilbertplotwidget.h hilbertplotcontrols.h

FORMS += hilbertplotcontrols.ui

DISTFILES +=

RESOURCES +=

LIBS += -L$$OUT_PWD/../../../hobbits-core/ -lhobbits-core

INCLUDEPATH += $$PWD/../../../hobbits-core
DEPENDPATH += $$PWD/../../../hobbits-core

unix:!mac {
QMAKE_LFLAGS_RPATH=
QMAKE_LFLAGS += "-Wl,-rpath,'$$ORIGIN/../../lib:$$ORIGIN'"
}

mac {
QMAKE_LFLAGS_RPATH=
QMAKE_LFLAGS += "-Wl,-rpath,'@executable_path/../Frameworks'"
}

unix {
target.path = $$(HOME)/.local/share/hobbits/plugins/displays
INSTALLS += target
}
40 changes: 40 additions & 0 deletions src/hobbits-plugins/displays/HilbertPlot/hilbertplot.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include "hilbertplot.h"

HilbertPlot::HilbertPlot() :
m_displayWidget(nullptr),
m_controlsWidget(nullptr)
{

}

DisplayInterface* HilbertPlot::createDefaultDisplay()
{
return new HilbertPlot();
}

QString HilbertPlot::getName()
{
return "Hilbert Plot";
}

QWidget* HilbertPlot::getDisplayWidget(QSharedPointer<DisplayHandle> displayHandle)
{
initialize(displayHandle);
return m_displayWidget;
}

QWidget* HilbertPlot::getControlsWidget(QSharedPointer<DisplayHandle> displayHandle)
{
initialize(displayHandle);
return m_controlsWidget;
}

void HilbertPlot::initialize(QSharedPointer<DisplayHandle> displayHandle)
{
if (!m_displayWidget) {
m_displayWidget = new HilbertPlotWidget(displayHandle, this);
m_controlsWidget = new HilbertPlotControls();

// make necessary connections here
}
}
30 changes: 30 additions & 0 deletions src/hobbits-plugins/displays/HilbertPlot/hilbertplot.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#ifndef HILBERTPLOT_H
#define HILBERTPLOT_H

#include "displayinterface.h"
#include "hilbertplotcontrols.h"
#include "hilbertplotwidget.h"

class HilbertPlot : public QObject, DisplayInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "hobbits.DisplayInterface.HilbertPlot")
Q_INTERFACES(DisplayInterface)

public:
HilbertPlot();

DisplayInterface* createDefaultDisplay();

QString getName();

QWidget* getDisplayWidget(QSharedPointer<DisplayHandle> displayHandle);
QWidget* getControlsWidget(QSharedPointer<DisplayHandle> displayHandle);

private:
void initialize(QSharedPointer<DisplayHandle> displayHandle);
HilbertPlotWidget* m_displayWidget;
HilbertPlotControls* m_controlsWidget;
};

#endif // HILBERTPLOT_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#include "hilbertplotcontrols.h"
#include "ui_hilbertplotcontrols.h"


HilbertPlotControls::HilbertPlotControls() :
ui(new Ui::HilbertPlotControls())
{
ui->setupUi(this);
}
22 changes: 22 additions & 0 deletions src/hobbits-plugins/displays/HilbertPlot/hilbertplotcontrols.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#ifndef HILBERTPLOTCONTROLS_H
#define HILBERTPLOTCONTROLS_H

#include <QWidget>

namespace Ui
{
class HilbertPlotControls;
}

class HilbertPlotControls : public QWidget
{
Q_OBJECT

public:
HilbertPlotControls();

private:
Ui::HilbertPlotControls *ui;
};

#endif // HILBERTPLOTCONTROLS_H
21 changes: 21 additions & 0 deletions src/hobbits-plugins/displays/HilbertPlot/hilbertplotcontrols.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>HilbertPlotControls</class>
<widget class="QWidget" name="HilbertPlotControls">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>500</width>
<height>100</height>
</rect>
</property>

<layout class="QVBoxLayout" name="verticalLayout">

</layout>

</widget>
<resources/>
<connections/>
</ui>
107 changes: 107 additions & 0 deletions src/hobbits-plugins/displays/HilbertPlot/hilbertplotwidget.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#include "hilbertplotwidget.h"

#include <QPainter>
#include <QImage>
#include "displayhelper.h"

HilbertPlotWidget::HilbertPlotWidget(
QSharedPointer<DisplayHandle> displayHandle,
DisplayInterface *pluginRef,
QWidget *parent) :
DisplayBase(displayHandle, pluginRef, parent)
{
for (int i = 1; i < 6; i++) {
m_hilbertPoints.insert(i, getPointsForOrder(i));
}
m_hilbertRecursionOrders = {4, 4, 2};
}

void HilbertPlotWidget::paintEvent(QPaintEvent*) {
if (m_displayHandle->getContainer().isNull()) {
return;
}
if (m_displayHandle->getFrameOffset() >= m_displayHandle->getContainer()->bitInfo()->frames().size()) {
return;
}

int rasterLength = 1;
for (int order : m_hilbertRecursionOrders) {
rasterLength *= 1 << order;
}

QImage raster(rasterLength, rasterLength, QImage::Format_ARGB32);
raster.fill(qRgba(0, 0, 0, 0));

auto bits = m_displayHandle->getContainer()->bits();
qint64 byteOffset = m_displayHandle->getContainer()->bitInfo()->frames().at(m_displayHandle->getFrameOffset()).start() / 8;
for (int i = 0; i + byteOffset < bits->sizeInBytes() && i < rasterLength * rasterLength; i++) {
int chunkLength = 1;
int chunk = i;
QPoint p(0, 0);
for (int order : m_hilbertRecursionOrders) {
auto points = m_hilbertPoints.value(order);
QPoint pChunk = points.at(chunk % points.size());
p.setX(p.x() + (pChunk.x() * chunkLength));
p.setY(p.y() + (pChunk.y() * chunkLength));
chunk = chunk / points.size();
chunkLength *= 1 << order;
}
char value = bits->byteAt(i+byteOffset);
if (value == 0x00) {
raster.setPixel(p, qRgba(0, 0, 0, 255));
}
else if (value == -128) {
raster.setPixel(p, qRgba(255, 255, 255, 255));
}
else if (isascii(value)) {
raster.setPixel(p, qRgba(100, 160, 255, 255));
}
else {
raster.setPixel(p, qRgba(255, 130, 130, 255));
}
}

QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, false);
painter.drawImage(0, 0, raster);
}

void HilbertPlotWidget::mouseMoveEvent(QMouseEvent *event) {
sendHoverUpdate(event, 1, 1, 1, 1, QPoint(0, 0));
}

void HilbertPlotWidget::rotate(QPoint &p, int n, bool rx, bool ry) {
if (!ry) {
if (rx) {
p.setX((n - 1) - p.x());
p.setY((n - 1) - p.y());
}
int x = p.y();
p.setY(p.x());
p.setX(x);
}
}

QPoint HilbertPlotWidget::toHilbertCoordinate(int n, int idx) {
QPoint p(0, 0);
bool rx, ry;
int t = idx;
for (int s = 1; s < n; s <<= 1) {
rx = ((t & 2) != 0);
ry = (((t ^ (rx ? 1 : 0)) & 1) != 0);
rotate(p, s, rx, ry);
p.setX(p.x() + (rx ? s : 0));
p.setY(p.y() + (ry ? s : 0));
t >>= 2;
}
return p;
}

QVector<QPoint> HilbertPlotWidget::getPointsForOrder(int order) {
QVector<QPoint> points;
int n = 1 << order;
for (int d = 0; d < n * n; ++d) {
points.push_back(toHilbertCoordinate(n, d));
}
return points;
}
28 changes: 28 additions & 0 deletions src/hobbits-plugins/displays/HilbertPlot/hilbertplotwidget.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#ifndef HILBERTPLOTWIDGET_H
#define HILBERTPLOTWIDGET_H

#include "displaybase.h"

class HilbertPlotWidget : public DisplayBase
{
Q_OBJECT

public:
HilbertPlotWidget(
QSharedPointer<DisplayHandle> displayHandle,
DisplayInterface *pluginRef,
QWidget *parent = nullptr);

void paintEvent(QPaintEvent*) override;
void mouseMoveEvent(QMouseEvent *event) override;

private:
void rotate(QPoint &p, int n, bool rx, bool ry);
QPoint toHilbertCoordinate(int n, int idx);
QVector<QPoint> getPointsForOrder(int order);

QMap<int, QVector<QPoint>> m_hilbertPoints;
QList<int> m_hilbertRecursionOrders;
};

#endif // HILBERTPLOTWIDGET_H
1 change: 1 addition & 0 deletions src/hobbits-plugins/displays/displays.pro
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ SUBDIRS += \
DotPlot \
FrequencyPlot \
HexView \
HilbertPlot \
SymbolRaster

0 comments on commit 727a6f1

Please sign in to comment.