From 4faf936a218ca5e9038d707d814e1307bfee45c3 Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 18 Jan 2024 01:01:54 +0100 Subject: [PATCH] First actual disk visualisations! --- lib/decoders/decoders.cc | 1 + lib/flux.h | 1 + src/gui2/fluxcomponent.cc | 12 +- src/gui2/fluxcomponent.h | 4 + src/gui2/fluxvisualiserwidget.cc | 169 ++++++++++++++++++++++++++--- src/gui2/fluxvisualiserwidget.h | 3 - src/gui2/globals.h | 5 + src/gui2/mainwindow.cc | 21 ++-- src/gui2/userinterface.ui | 181 ++++++++++++------------------- 9 files changed, 256 insertions(+), 141 deletions(-) diff --git a/lib/decoders/decoders.cc b/lib/decoders/decoders.cc index 446f438c..bdfa53c7 100644 --- a/lib/decoders/decoders.cc +++ b/lib/decoders/decoders.cc @@ -70,6 +70,7 @@ std::shared_ptr Decoder::decodeToSectors( _trackdata = std::make_shared(); _trackdata->fluxmap = fluxmap; _trackdata->trackInfo = trackInfo; + _trackdata->rotationalPeriod = globalConfig()->drive().rotational_period_ms() * 1e6; FluxmapReader fmr(*fluxmap); _fmr = &fmr; diff --git a/lib/flux.h b/lib/flux.h index eed9365e..01d024ef 100644 --- a/lib/flux.h +++ b/lib/flux.h @@ -23,6 +23,7 @@ struct TrackDataFlux std::shared_ptr fluxmap; std::vector> records; std::vector> sectors; + nanoseconds_t rotationalPeriod; }; struct TrackFlux diff --git a/src/gui2/fluxcomponent.cc b/src/gui2/fluxcomponent.cc index a689dbf8..69deaa5f 100644 --- a/src/gui2/fluxcomponent.cc +++ b/src/gui2/fluxcomponent.cc @@ -21,7 +21,6 @@ public: _fluxVisualiserWidget = FluxVisualiserWidget::create(); _mainWindow->fluxViewContainer->layout()->addWidget( _fluxVisualiserWidget); - _fluxVisualiserWidget->refresh(); connect(_mainWindow->fluxSideComboBox, QOverload::of(&QComboBox::activated), @@ -29,6 +28,17 @@ public: &FluxVisualiserWidget::setVisibleSide); } +public: + void setTrackData(std::shared_ptr track) + { + _fluxVisualiserWidget->setTrackData(track); + } + + void setDiskData(std::shared_ptr disk) + { + _fluxVisualiserWidget->setDiskData(disk); + } + private: MainWindow* _mainWindow; FluxVisualiserWidget* _fluxVisualiserWidget; diff --git a/src/gui2/fluxcomponent.h b/src/gui2/fluxcomponent.h index 337e7464..57ec50b5 100644 --- a/src/gui2/fluxcomponent.h +++ b/src/gui2/fluxcomponent.h @@ -4,6 +4,10 @@ class MainWindow; class FluxComponent { +public: + virtual void setTrackData(std::shared_ptr track) = 0; + virtual void setDiskData(std::shared_ptr disk) = 0; + public: static FluxComponent* create(MainWindow* mainWindow); }; diff --git a/src/gui2/fluxvisualiserwidget.cc b/src/gui2/fluxvisualiserwidget.cc index eb29df7d..565ed907 100644 --- a/src/gui2/fluxvisualiserwidget.cc +++ b/src/gui2/fluxvisualiserwidget.cc @@ -3,21 +3,26 @@ #include "lib/fluxmap.h" #include "lib/flux.h" #include "lib/layout.h" +#include "lib/decoders/fluxmapreader.h" #include "globals.h" #include "fluxvisualiserwidget.h" #include #include +#include +#include W_OBJECT_IMPL(FluxVisualiserWidget) class DiskFlux; class TrackFlux; -static const int TRACKS = 82; +static constexpr int SIDES = 2; +static constexpr int TRACKS = 82; +static constexpr int SLOTS = 300; -static const float VBORDER = 1.0; -static const float VOUTER_RADIUS = 50.0; -static const float VINNER_RADIUS = 10.0; +static constexpr float VBORDER = 1.0; +static constexpr float VOUTER_RADIUS = 50.0; +static constexpr float VINNER_RADIUS = 10.0; class FluxVisualiserWidgetImpl : public FluxVisualiserWidget { @@ -36,6 +41,8 @@ public: setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setFrameShape(QFrame::NoFrame); setScene(_scene); + + recompute(); } public: @@ -48,7 +55,7 @@ public: void setVisibleSide(int mode) { _viewMode = mode; - refresh(); + redraw(); } void setTrackData(std::shared_ptr track) @@ -56,35 +63,46 @@ public: key_t key = { track->trackInfo->physicalTrack, track->trackInfo->physicalSide}; _tracks[key] = track; + + recompute( + track->trackInfo->physicalSide, track->trackInfo->physicalTrack); } void setDiskData(std::shared_ptr disk) { + _tracks.clear(); for (const auto& track : disk->tracks) { key_t key = {track->trackInfo->physicalTrack, track->trackInfo->physicalSide}; _tracks[key] = track; } + + recompute(); } -public: - void refresh() override +private: + void redraw() { _scene->clear(); switch (_viewMode) { case SIDE_0: + drawSide(VOUTER_RADIUS, VOUTER_RADIUS, 0); + _scene->setSceneRect( + 0.0, 0.0, VOUTER_RADIUS * 2, VOUTER_RADIUS * 2); + break; + case SIDE_1: - drawSide(VOUTER_RADIUS, VOUTER_RADIUS); + drawSide(VOUTER_RADIUS, VOUTER_RADIUS, 1); _scene->setSceneRect( 0.0, 0.0, VOUTER_RADIUS * 2, VOUTER_RADIUS * 2); break; case BOTH_SIDES: - drawSide(VOUTER_RADIUS, VOUTER_RADIUS); - drawSide(VOUTER_RADIUS, VOUTER_RADIUS * 3 + VBORDER); + drawSide(VOUTER_RADIUS, VOUTER_RADIUS, 0); + drawSide(VOUTER_RADIUS, VOUTER_RADIUS * 3 + VBORDER, 1); _scene->setSceneRect( 0.0, 0.0, VOUTER_RADIUS * 2, VOUTER_RADIUS * 4 + VBORDER); @@ -94,26 +112,145 @@ public: fitInView(sceneRect(), Qt::KeepAspectRatio); } -private: - void drawSide(float x, float y) + void drawSide(float x, float y, int side) { - QPen black(QColorConstants::Black); - black.setWidth(0); - float step = (VOUTER_RADIUS - VINNER_RADIUS) / TRACKS; for (int track = 0; track < 82; track++) { + QConicalGradient gradient(x, y, 0); + gradient.setStops(_viewData[side][track].gradientStops); + QBrush brush(gradient); + QPen pen(brush, step * 1.15); + float r = VOUTER_RADIUS - track * step; - _scene->addEllipse(x - r, y - r, r * 2, r * 2, black); + _scene->addEllipse(x - r, y - r, r * 2, r * 2, pen); } } + void recompute() + { + for (int side = 0; side < SIDES; side++) + for (int track = 0; track < TRACKS; track++) + recompute(side, track); + } + + void recompute(int side, int track) + { + VData& vdata = _viewData[side][track]; + QGradientStops& stops = vdata.gradientStops; + stops.clear(); + ranges::fill(vdata.slot, VSlot()); + + auto it = _tracks.find(key_t(track, side)); + if (it != _tracks.end()) + { + const TrackFlux& trackFlux = *it->second; + for (auto& trackDataFlux : trackFlux.trackDatas) + { + nanoseconds_t rotationalPeriod = + trackDataFlux->rotationalPeriod; + if (rotationalPeriod == 0.0) + rotationalPeriod = 200e6; + const Fluxmap& fm = *trackDataFlux->fluxmap; + FluxmapReader fmr(fm); + + fmr.seekToIndexMark(); + nanoseconds_t indexTimeNs = fmr.tell().ns(); + fmr.rewind(); + + int slotIndex = -1; + for (;;) + { + int event; + unsigned ticks; + fmr.getNextEvent(event, ticks); + + if (event & F_BIT_PULSE) + { + nanoseconds_t ns = fmr.tell().ns(); + while (ns < indexTimeNs) + ns += rotationalPeriod; + ns = fmod(ns - indexTimeNs, rotationalPeriod); + + int newIndex = (ns / rotationalPeriod) * SLOTS; + if (slotIndex != -1) + { + while ( + (slotIndex < newIndex) && (slotIndex < SLOTS)) + { + vdata.slot[slotIndex].count++; + slotIndex++; + } + } + + vdata.slot[newIndex].pulses++; + slotIndex = newIndex; + } + + if (event & F_EOF) + break; + } + + if (slotIndex != -1) + vdata.slot[slotIndex].count++; + } + + float maxDensity = 0.0; + for (int i = 0; i < SLOTS; i++) + { + VSlot& slot = vdata.slot[i]; + if (slot.count != 0) + { + float factor = (float)slot.pulses / (float)slot.count; + maxDensity = std::max(maxDensity, factor); + } + } + maxDensity = 300; + + for (int i = 0; i < SLOTS; i++) + { + VSlot& slot = vdata.slot[i]; + if (slot.count == 0) + stops.append( + QPair((float)i / SLOTS, QColorConstants::LightGray)); + else + { + float factor = + (float)slot.pulses / (float)slot.count / maxDensity; + int c = factor * 255.0; + stops.append(QPair((float)i / SLOTS, QColor(c, c, c))); + } + } + } + + if (stops.empty()) + { + stops.append(QPair(0.0, QColorConstants::LightGray)); + stops.append(QPair(1.0, QColorConstants::LightGray)); + } + + redraw(); + } + private: typedef std::pair key_t; + struct VSlot + { + int count; + int pulses; + }; + + struct VData + { + QGradientStops gradientStops; + VSlot slot[SLOTS]; + }; + QGraphicsScene* _scene; std::map> _tracks; int _viewMode = BOTH_SIDES; + VData _viewData[SIDES][TRACKS]; }; FluxVisualiserWidget* FluxVisualiserWidget::create() diff --git a/src/gui2/fluxvisualiserwidget.h b/src/gui2/fluxvisualiserwidget.h index 403980ff..ba33761c 100644 --- a/src/gui2/fluxvisualiserwidget.h +++ b/src/gui2/fluxvisualiserwidget.h @@ -7,9 +7,6 @@ class FluxVisualiserWidget : public QGraphicsView W_OBJECT(FluxVisualiserWidget) public: - virtual void refresh() = 0; - W_SLOT(refresh) - virtual void setVisibleSide(int mode) = 0; W_SLOT(setVisibleSide) diff --git a/src/gui2/globals.h b/src/gui2/globals.h index 251abd8c..1e16e019 100644 --- a/src/gui2/globals.h +++ b/src/gui2/globals.h @@ -9,7 +9,12 @@ #include #include +class TrackFlux; +class DiskFlux; + Q_DECLARE_METATYPE(const ConfigProto*) +W_REGISTER_ARGTYPE(std::shared_ptr) +W_REGISTER_ARGTYPE(std::shared_ptr) extern QThreadPool workerThreadPool; diff --git a/src/gui2/mainwindow.cc b/src/gui2/mainwindow.cc index 4ee5b8e5..a964c7a7 100644 --- a/src/gui2/mainwindow.cc +++ b/src/gui2/mainwindow.cc @@ -37,15 +37,6 @@ public: &QAbstractButton::clicked, this, &MainWindowImpl::readDisk); - - connect(revolutionsSlider, - &QSlider::valueChanged, - revolutionsSpinBox, - &QSpinBox::setValue); - connect(revolutionsSpinBox, - QOverload::of(&QSpinBox::valueChanged), - revolutionsSlider, - &QSlider::setValue); } public: @@ -56,6 +47,18 @@ public: { }, + /* A track has been read. */ + [&](const TrackReadLogMessage& m) + { + _fluxComponent->setTrackData(m.track); + }, + + /* A complete disk has been read. */ + [&](const DiskReadLogMessage& m) + { + _fluxComponent->setDiskData(m.disk); + }, + /* Large-scale operation start. */ [this](const BeginOperationLogMessage& m) { diff --git a/src/gui2/userinterface.ui b/src/gui2/userinterface.ui index e4ae95cd..01559793 100644 --- a/src/gui2/userinterface.ui +++ b/src/gui2/userinterface.ui @@ -347,118 +347,6 @@ Flux view - - - - 0 - - - - - - 0 - 0 - - - - By index pulse - - - - - - - - 0 - 0 - - - - By sector number - - - - - - - - - Revolution: - - - - - - - 0 - - - - - - 0 - 0 - - - - Qt::Horizontal - - - QSlider::TicksAbove - - - 1 - - - - - - - - 0 - 0 - - - - - - - - - - - 0 - 0 - - - - Alignment: - - - - - - - - 0 - 0 - - - - QFrame { -background: white; -} - - - - QFrame::StyledPanel - - - QFrame::Sunken - - - - @@ -498,6 +386,75 @@ background: white; + + + + + 0 + 0 + + + + QFrame { +background: white; +} + + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + + + + + + 0 + 0 + + + + Alignment: + + + + + + + 0 + + + + + + 0 + 0 + + + + By index pulse + + + + + + + + 0 + 0 + + + + By sector number + + + + +