diff --git a/include/Signal.hpp b/include/Signal.hpp new file mode 100644 index 0000000..ffb4635 --- /dev/null +++ b/include/Signal.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +typedef std::complex CmplxDouble; + +typedef struct { + double t; + CmplxDouble val; + bool valid = true; +} Sample; + +static const Sample invalidSample{ 0.f, 0.f, false }; + +class Signal +{ +public: + Signal() = default; + ~Signal() = default; + + friend Signal& operator<<(Signal& sig, const Sample& sample); + friend Signal& operator>>(Signal& sig, Sample& sample); + +private: + std::deque buffer; +}; \ No newline at end of file diff --git a/include/screens/PlotScreen.hpp b/include/screens/PlotScreen.hpp new file mode 100644 index 0000000..211ef8e --- /dev/null +++ b/include/screens/PlotScreen.hpp @@ -0,0 +1,29 @@ +#pragma once +#include +#include +#include +#include "../Screen.hpp" +#include "Signal.hpp" + +typedef struct { + double x, y, w, h; +} fRect; + +class PlotScreen : public Screen +{ +public: + PlotScreen(SDL_Renderer* renderer, Signal* dataSource, + int x, int y, int w, int h, + double minX, double minY, double maxX, double maxY); + ~PlotScreen(); + + void Update() override; + void Render(SDL_Renderer* renderer) override; + +private: + void SignalToSampleList(std::vector& container, uint32_t maxSamples = 0); + void SampleListToPointList(const std::vector& source, std::vector& container); + + fRect plotRect; + Signal* dataSource; +}; \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8d07ce6..f95a364 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,7 @@ add_executable(fourier "main.cpp" "RenderWindow.cpp" - "Screen.cpp" "screens/DummyScreen.cpp") + "Screen.cpp" "screens/DummyScreen.cpp" "screens/PlotScreen.cpp" "Signal.cpp") target_include_directories(fourier PRIVATE ${CMAKE_SOURCE_DIR}/include diff --git a/src/Signal.cpp b/src/Signal.cpp new file mode 100644 index 0000000..fa2814a --- /dev/null +++ b/src/Signal.cpp @@ -0,0 +1,20 @@ +#include "Signal.hpp" + +Signal& operator<<(Signal& sig, const Sample& sample) +{ + sig.buffer.push_back(sample); + return sig; +} + +Signal& operator>>(Signal& sig, Sample& sample) +{ + if (sig.buffer.size() == 0) + sample = invalidSample; + else + { + sample = sig.buffer[0]; + sig.buffer.pop_front(); + } + + return sig; +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 8fc2bef..237dabf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,15 +1,19 @@ #include #include "RenderWindow.hpp" +#include "screens/PlotScreen.hpp" #include "screens/DummyScreen.hpp" +#include "Signal.hpp" int main(int argc, char** argv) { + Signal sig; + RenderWindow* window; - DummyScreen* dScreen; try { window = new RenderWindow(800, 800); - dScreen = new DummyScreen(window->renderer, 100, 100, 600, 600); + window->AddScreen(new DummyScreen(window->renderer, 0, 0, 800, 800)); + window->AddScreen(new PlotScreen(window->renderer, &sig, 50, 50, 700, 300, 0, -1.5f, 10, 1.5f)); } catch (const std::runtime_error& e) { @@ -17,7 +21,6 @@ int main(int argc, char** argv) return -1; } - window->AddScreen(dScreen); window->Run(); return 0; diff --git a/src/screens/DummyScreen.cpp b/src/screens/DummyScreen.cpp index bef682d..dff6988 100644 --- a/src/screens/DummyScreen.cpp +++ b/src/screens/DummyScreen.cpp @@ -14,7 +14,7 @@ void DummyScreen::Update() void DummyScreen::Render(SDL_Renderer* renderer) { SDL_SetRenderTarget(renderer, texture); - SDL_SetRenderDrawColor(renderer, 20, 40, 210, 255); + SDL_SetRenderDrawColor(renderer, 120, 120, 120, 255); SDL_RenderClear(renderer); SDL_SetRenderTarget(renderer, NULL); diff --git a/src/screens/PlotScreen.cpp b/src/screens/PlotScreen.cpp new file mode 100644 index 0000000..144d6b2 --- /dev/null +++ b/src/screens/PlotScreen.cpp @@ -0,0 +1,68 @@ +#include "screens/PlotScreen.hpp" +#include +#include +#include "Signal.hpp" + +#define MAP(A, B, a, b, val) ((val - A)*(b-a)/(B-A) + a) + +PlotScreen::PlotScreen(SDL_Renderer* renderer, Signal* dataSource, int x, int y, int w, int h, double minX, double minY, double maxX, double maxY) : + Screen(renderer, x, y, w, h), dataSource(dataSource), + plotRect{ minX, minY, maxX, maxY } +{ + +} + +PlotScreen::~PlotScreen() +{ +} + +void PlotScreen::Update() +{ +} + +void PlotScreen::Render(SDL_Renderer* renderer) +{ + std::vector samples; + SignalToSampleList(samples); + std::vector points; + SampleListToPointList(samples, points); + + SDL_SetRenderTarget(renderer, texture); + SDL_SetRenderDrawColor(renderer, 240, 240, 240, 255); + SDL_RenderClear(renderer); + + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_RenderDrawLines(renderer, points.data(), points.size()); + + SDL_SetRenderTarget(renderer, NULL); + SDL_RenderCopy(renderer, texture, NULL, screenSpace); + + for (int i = 0; i < 1000; i++) + { + (*dataSource) << Sample{ i / 10.0f, sin(i / 10.0f) }; + } +} + +void PlotScreen::SignalToSampleList(std::vector& container, uint32_t maxSamples) +{ + Sample s; + (*dataSource) >> s; + while (s.valid) + { + container.push_back(s); + if (container.size() == maxSamples) + return; + (*dataSource) >> s; + } +} + +void PlotScreen::SampleListToPointList(const std::vector& source, std::vector& container) +{ + for (const Sample& sample : source) + { + container.push_back({ + (int)std::floor((sample.t - plotRect.x) * screenSpace->w / (plotRect.w - plotRect.x)), + (int)std::floor(-(sample.val.real() + plotRect.y) * screenSpace->h / (plotRect.h - plotRect.y)) + }); + } +} \ No newline at end of file