обратное преобразование
All checks were successful
CMake on a single platform / build (push) Successful in 21s
All checks were successful
CMake on a single platform / build (push) Successful in 21s
This commit is contained in:
parent
8fbbf0afcf
commit
42e7ac4d58
@ -5,6 +5,28 @@
|
|||||||
#include <ranges>
|
#include <ranges>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <Wt/WBootstrap5Theme.h>
|
||||||
|
|
||||||
|
#include <Wt/Chart/WAbstractChartModel.h>
|
||||||
|
#include <Wt/Chart/WAxisSliderWidget.h>
|
||||||
|
#include <Wt/Chart/WCartesianChart.h>
|
||||||
|
#include <Wt/Chart/WDataSeries.h>
|
||||||
|
#include <Wt/WApplication.h>
|
||||||
|
#include <Wt/WContainerWidget.h>
|
||||||
|
#include <Wt/WObject.h>
|
||||||
|
#include <Wt/WShadow.h>
|
||||||
|
|
||||||
|
#include <Wt/WSpinBox.h>
|
||||||
|
#include <Wt/WDoubleSpinBox.h>
|
||||||
|
#include <Wt/WLabel.h>
|
||||||
|
#include <Wt/WPushButton.h>
|
||||||
|
#include <Wt/WColorPicker.h>
|
||||||
|
#include <Wt/WCheckBox.h>
|
||||||
|
#include <Wt/WStandardItemModel.h>
|
||||||
|
|
||||||
|
#include <Wt/WPanel.h>
|
||||||
|
|
||||||
|
|
||||||
class SinModel : public Chart::WAbstractChartModel
|
class SinModel : public Chart::WAbstractChartModel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -23,6 +45,7 @@ public:
|
|||||||
sinuses | views::transform([x](Sin s){return s.get(x);}),
|
sinuses | views::transform([x](Sin s){return s.get(x);}),
|
||||||
std::plus<double>()
|
std::plus<double>()
|
||||||
).value_or(0);
|
).value_or(0);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
try { return sinuses.at(column-2).get(x); }
|
try { return sinuses.at(column-2).get(x); }
|
||||||
catch (out_of_range e){ return 0; }
|
catch (out_of_range e){ return 0; }
|
||||||
@ -45,13 +68,14 @@ private:
|
|||||||
class FourierModel : public Chart::WAbstractChartModel
|
class FourierModel : public Chart::WAbstractChartModel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FourierModel(shared_ptr<SinModel> dm)
|
FourierModel(shared_ptr<SinModel> dm, vector<pair<double, double>>& fd)
|
||||||
: Chart::WAbstractChartModel{}
|
: Chart::WAbstractChartModel{}
|
||||||
, discreteModel{dm}
|
, discreteModel{dm}
|
||||||
|
, fourier_data{fd}
|
||||||
{
|
{
|
||||||
dm->changed().connect([this](){
|
dm->changed().connect([this](){
|
||||||
data_.clear();
|
fourier_data.clear();
|
||||||
data_.reserve(rowCount());
|
fourier_data.reserve(rowCount());
|
||||||
|
|
||||||
for ( int k = 0; k < rowCount(); k++ ) {
|
for ( int k = 0; k < rowCount(); k++ ) {
|
||||||
double x = 0,
|
double x = 0,
|
||||||
@ -64,7 +88,7 @@ public:
|
|||||||
y-=v*sin(e);
|
y-=v*sin(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
data_[k] = {sqrt(x*x+y*y)/rowCount(), atan2(y,x)};
|
fourier_data.push_back({x, y});
|
||||||
}
|
}
|
||||||
|
|
||||||
changed().emit();
|
changed().emit();
|
||||||
@ -74,38 +98,45 @@ public:
|
|||||||
virtual double data(int row, int column) const override {
|
virtual double data(int row, int column) const override {
|
||||||
switch ( column ) {
|
switch ( column ) {
|
||||||
case 0: return row;
|
case 0: return row;
|
||||||
case 1: return data_[row].first;
|
case 1: return sqrt(pow(fourier_data[row].first,2)+pow(fourier_data[row].second,2))/rowCount();
|
||||||
case 2: return data_[row].second;
|
case 2: return atan2(fourier_data[row].second, fourier_data[row].first);
|
||||||
|
|
||||||
default: return 0;
|
default: return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual int columnCount() const override { return 3; };
|
virtual int columnCount() const override { return 3; };
|
||||||
virtual int rowCount() const override { return discreteModel->rowCount()/2; }
|
virtual int rowCount() const override { return discreteModel->rowCount(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
shared_ptr<SinModel> discreteModel;
|
shared_ptr<SinModel> discreteModel;
|
||||||
vector<pair<double, double>> data_;
|
vector<pair<double, double>>& fourier_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
#include <Wt/WBootstrap5Theme.h>
|
class RestoreModel : public Chart::WAbstractChartModel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RestoreModel(vector<pair<double, double>>& fd)
|
||||||
|
: fourier_data{fd}
|
||||||
|
{}
|
||||||
|
|
||||||
#include <Wt/Chart/WAbstractChartModel.h>
|
virtual double data(int row, int column) const override {
|
||||||
#include <Wt/Chart/WAxisSliderWidget.h>
|
if ( column == 0 ) return -M_PI + row * 2*M_PI / (rowCount() - 1);;
|
||||||
#include <Wt/Chart/WCartesianChart.h>
|
if (fourier_data.size()==0) return 0;
|
||||||
#include <Wt/Chart/WDataSeries.h>
|
double y = 0;
|
||||||
#include <Wt/WApplication.h>
|
for (int k = 0; k < fourier_data.size(); k++) {
|
||||||
#include <Wt/WContainerWidget.h>
|
double theta = (2 * M_PI * k * (row+1)) / fourier_data.size();
|
||||||
#include <Wt/WObject.h>
|
y += fourier_data.at(k).first * cos(theta) + fourier_data.at(k).second * sin(theta);
|
||||||
#include <Wt/WShadow.h>
|
}
|
||||||
|
return y / fourier_data.size();
|
||||||
|
}
|
||||||
|
|
||||||
#include <Wt/WSpinBox.h>
|
virtual int columnCount() const override { return 2; };
|
||||||
#include <Wt/WDoubleSpinBox.h>
|
virtual int rowCount() const override { return fourier_data.size(); }
|
||||||
#include <Wt/WLabel.h>
|
|
||||||
#include <Wt/WPushButton.h>
|
private:
|
||||||
#include <Wt/WColorPicker.h>
|
int rows_ = 0;
|
||||||
#include <Wt/WCheckBox.h>
|
vector<pair<double, double>>& fourier_data;
|
||||||
#include <Wt/WStandardItemModel.h>
|
};
|
||||||
|
|
||||||
|
|
||||||
MyApplication::MyApplication(const WEnvironment& env)
|
MyApplication::MyApplication(const WEnvironment& env)
|
||||||
@ -157,6 +188,26 @@ MyApplication::MyApplication(const WEnvironment& env)
|
|||||||
pointsDS->setLabelColor(StandardColor::Black);
|
pointsDS->setLabelColor(StandardColor::Black);
|
||||||
chart->addSeries(std::move(pointsDSPtr));
|
chart->addSeries(std::move(pointsDSPtr));
|
||||||
|
|
||||||
|
restoreModel = make_shared<RestoreModel>(fourier_data);
|
||||||
|
auto restoredSignal = make_unique<Chart::WDataSeries>(1, Chart::SeriesType::Curve);
|
||||||
|
restoredDS = restoredSignal.get();
|
||||||
|
restoredDS->setModel(restoreModel);
|
||||||
|
restoredDS->setXSeriesColumn(0);
|
||||||
|
restoredDS->setHidden(true);
|
||||||
|
restoredDS->setPen({StandardColor::Yellow});
|
||||||
|
restoredDS->setShadow(WShadow(3, 3, WColor(0, 0, 0, 127), 3));
|
||||||
|
chart->addSeries(std::move(restoredSignal));
|
||||||
|
|
||||||
|
auto restoredSignal_p = make_unique<Chart::WDataSeries>(1, Chart::SeriesType::Point);
|
||||||
|
restoredDS_points = restoredSignal_p.get();
|
||||||
|
restoredDS_points->setModel(restoreModel);
|
||||||
|
restoredDS_points->setXSeriesColumn(0);
|
||||||
|
restoredDS_points->setHidden(true);
|
||||||
|
restoredDS_points->setPen({StandardColor::Yellow});
|
||||||
|
restoredDS_points->setShadow(WShadow(3, 3, WColor(0, 0, 0, 127), 3));
|
||||||
|
restoredDS_points->setLabelsEnabled(Chart::Axis::Y);
|
||||||
|
restoredDS_points->setLabelColor(StandardColor::Black);
|
||||||
|
chart->addSeries(std::move(restoredSignal_p));
|
||||||
|
|
||||||
chart->axis(Chart::Axis::X).setMaximumZoomRange( 2*M_PI+1 );
|
chart->axis(Chart::Axis::X).setMaximumZoomRange( 2*M_PI+1 );
|
||||||
chart->axis(Chart::Axis::X).setMinimumZoomRange( M_PI / 16.0 );
|
chart->axis(Chart::Axis::X).setMinimumZoomRange( M_PI / 16.0 );
|
||||||
@ -172,7 +223,7 @@ MyApplication::MyApplication(const WEnvironment& env)
|
|||||||
chart->axis(Chart::Axis::Y).setGridLinesEnabled(true);
|
chart->axis(Chart::Axis::Y).setGridLinesEnabled(true);
|
||||||
|
|
||||||
|
|
||||||
chart->resize(800, 600);
|
chart->resize(800, 500);
|
||||||
|
|
||||||
chart->setPanEnabled(true);
|
chart->setPanEnabled(true);
|
||||||
chart->setZoomEnabled(true);
|
chart->setZoomEnabled(true);
|
||||||
@ -208,11 +259,13 @@ MyApplication::MyApplication(const WEnvironment& env)
|
|||||||
chart->update();
|
chart->update();
|
||||||
});
|
});
|
||||||
|
|
||||||
form->addNew<WText>("a=");
|
form->addNew<WText>("α=");
|
||||||
auto a = form->addNew<WDoubleSpinBox>();
|
auto a = form->addNew<WDoubleSpinBox>();
|
||||||
form->addNew<WText>("w=");
|
a->setValue(1);
|
||||||
|
form->addNew<WText>("ω=");
|
||||||
auto w = form->addNew<WDoubleSpinBox>();
|
auto w = form->addNew<WDoubleSpinBox>();
|
||||||
form->addNew<WText>("f=");
|
w->setValue(1);
|
||||||
|
form->addNew<WText>("φ=");
|
||||||
auto f = form->addNew<WDoubleSpinBox>();
|
auto f = form->addNew<WDoubleSpinBox>();
|
||||||
|
|
||||||
for ( auto i : {a,w,f} ) {
|
for ( auto i : {a,w,f} ) {
|
||||||
@ -233,12 +286,13 @@ MyApplication::MyApplication(const WEnvironment& env)
|
|||||||
right->setOverflow(Overflow::Hidden, Orientation::Horizontal);
|
right->setOverflow(Overflow::Hidden, Orientation::Horizontal);
|
||||||
{ // дискретизация
|
{ // дискретизация
|
||||||
auto form = right->addNew<WContainerWidget>();
|
auto form = right->addNew<WContainerWidget>();
|
||||||
form->addStyleClass("d-flex flex-row gap-3");
|
form->addStyleClass("d-flex flex-row gap-3 align-items-center my-1");
|
||||||
|
|
||||||
auto show = form->addNew<WCheckBox>("дискретизация");
|
form->addNew<WText>("частота дискретизации");
|
||||||
auto freq = form->addNew<WSpinBox>();
|
auto freq = form->addNew<WSpinBox>();
|
||||||
freq->setWidth(120);
|
freq->setWidth(120);
|
||||||
freq->setRange(0, 1000);
|
freq->setRange(0, 1000);
|
||||||
|
auto show = form->addNew<WCheckBox>("показать точки");
|
||||||
|
|
||||||
show->clicked().connect([=,this](){
|
show->clicked().connect([=,this](){
|
||||||
pointsDS->setHidden(!show->isChecked());
|
pointsDS->setHidden(!show->isChecked());
|
||||||
@ -248,27 +302,18 @@ MyApplication::MyApplication(const WEnvironment& env)
|
|||||||
|
|
||||||
freq->changed().connect([=,this](){
|
freq->changed().connect([=,this](){
|
||||||
discreteModel->setRows(freq->value());
|
discreteModel->setRows(freq->value());
|
||||||
});
|
restoredDS->setHidden( freq->value()==0 || !lineCheck->isChecked() );
|
||||||
|
restoredDS_points->setHidden(freq->value()==0 || !pointsCheck->isChecked() );
|
||||||
discreteModel->changed().connect([this](){
|
chart->update();
|
||||||
vals->clear();
|
|
||||||
|
|
||||||
for ( int i = 0; i < discreteModel->rowCount(); i++ ) {
|
|
||||||
auto x = discreteModel->data(i,1);
|
|
||||||
vals->addNew<WText>(format("{:.2f}", x))
|
|
||||||
->addStyleClass("border rounded-3 p-1");
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
vals = right->addNew<WContainerWidget>();
|
|
||||||
vals->setOverflow(Overflow::Auto, Orientation::Horizontal);
|
|
||||||
vals->addStyleClass("d-flex gap-1 p-1 text-nowrap");
|
|
||||||
|
|
||||||
fourierChart = right->addNew<Chart::WCartesianChart>();
|
fourierChart = right->addNew<Chart::WCartesianChart>();
|
||||||
fourierChart->setPlotAreaPadding(100);
|
fourierChart->setPlotAreaPadding(100, Side::Right | Side::Left);
|
||||||
|
fourierChart->setPlotAreaPadding(50, Side::Top | Side::Bottom);
|
||||||
fourierChart->setType(Chart::ChartType::Scatter);
|
fourierChart->setType(Chart::ChartType::Scatter);
|
||||||
fourierModel = make_shared<FourierModel>(discreteModel);
|
fourierModel = make_shared<FourierModel>(discreteModel, fourier_data);
|
||||||
|
fourierModel->changed().connect([this](){restoreModel->changed().emit();});
|
||||||
fourierChart->setModel(static_pointer_cast<Chart::WAbstractChartModel>(fourierModel));
|
fourierChart->setModel(static_pointer_cast<Chart::WAbstractChartModel>(fourierModel));
|
||||||
|
|
||||||
auto seriesPtr = make_unique<Chart::WDataSeries>(2, Chart::SeriesType::Point);
|
auto seriesPtr = make_unique<Chart::WDataSeries>(2, Chart::SeriesType::Point);
|
||||||
@ -300,7 +345,52 @@ MyApplication::MyApplication(const WEnvironment& env)
|
|||||||
fourierChart->setZoomEnabled(true);
|
fourierChart->setZoomEnabled(true);
|
||||||
fourierChart->setCrosshairEnabled(true);
|
fourierChart->setCrosshairEnabled(true);
|
||||||
|
|
||||||
fourierChart->resize(800, 600);
|
fourierChart->resize(800, 400);
|
||||||
|
fourierChart->axis(Chart::Axis::X).setMinimumZoomRange(0.1);
|
||||||
|
auto sliderWidget = right->addNew<Chart::WAxisSliderWidget>(ampSeries);
|
||||||
|
sliderWidget->resize(800, 80);
|
||||||
|
sliderWidget->setSelectionAreaPadding(40, Side::Left | Side::Right);
|
||||||
|
fourierChart->axis(Chart::Axis::X).setZoom(2);
|
||||||
|
fourierChart->axis(Chart::Axis::X).setPan(0);
|
||||||
|
|
||||||
|
|
||||||
|
auto restoreControls = right->addNew<WPanel>();
|
||||||
|
restoreControls->setTitle("Восстановленный сигнал");
|
||||||
|
restoreControls->setCentralWidget(make_unique<WContainerWidget>());
|
||||||
|
auto c = (WContainerWidget*)restoreControls->centralWidget();
|
||||||
|
|
||||||
|
{
|
||||||
|
auto line = c->addNew<WContainerWidget>();
|
||||||
|
line->addStyleClass("d-flex flex-row align-items-center gap-1 p-3");
|
||||||
|
lineCheck = line->addNew<WCheckBox>("показывать график");
|
||||||
|
lineCheck->clicked().connect([this](){
|
||||||
|
restoredDS->setHidden(!lineCheck->isChecked());
|
||||||
|
chart->update();
|
||||||
|
});
|
||||||
|
auto lineColor = line->addNew<WColorPicker>(WColor{StandardColor::Yellow});
|
||||||
|
lineColor->setWidth(50);
|
||||||
|
lineColor->changed().connect([lineColor,this](){
|
||||||
|
restoredDS->setPen(WPen{lineColor->color()});
|
||||||
|
chart->update();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto points = c->addNew<WContainerWidget>();
|
||||||
|
points->addStyleClass("d-flex flex-row align-items-center gap-1 p-3");
|
||||||
|
pointsCheck = points->addNew<WCheckBox>("показывать точки");
|
||||||
|
pointsCheck->clicked().connect([this](){
|
||||||
|
restoredDS_points->setHidden(!pointsCheck->isChecked());
|
||||||
|
chart->update();
|
||||||
|
});
|
||||||
|
auto pointsColor = points->addNew<WColorPicker>(WColor{StandardColor::Yellow});
|
||||||
|
pointsColor->setWidth(50);
|
||||||
|
pointsColor->changed().connect([pointsColor,this](){
|
||||||
|
WPen p{pointsColor->color()};
|
||||||
|
restoredDS_points->setPen(p);
|
||||||
|
chart->update();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyApplication::addSin(Sin s) {
|
void MyApplication::addSin(Sin s) {
|
||||||
|
@ -30,6 +30,7 @@ typedef struct sin Sin;
|
|||||||
|
|
||||||
class SinModel;
|
class SinModel;
|
||||||
class FourierModel;
|
class FourierModel;
|
||||||
|
class RestoreModel;
|
||||||
|
|
||||||
class MyApplication : public WApplication
|
class MyApplication : public WApplication
|
||||||
{
|
{
|
||||||
@ -43,6 +44,14 @@ private:
|
|||||||
shared_ptr<SinModel> discreteModel;
|
shared_ptr<SinModel> discreteModel;
|
||||||
Chart::WDataSeries* pointsDS;
|
Chart::WDataSeries* pointsDS;
|
||||||
|
|
||||||
|
shared_ptr<RestoreModel> restoreModel;
|
||||||
|
vector<pair<double, double>> fourier_data;
|
||||||
|
Chart::WDataSeries* restoredDS;
|
||||||
|
Chart::WDataSeries* restoredDS_points;
|
||||||
|
|
||||||
|
WCheckBox* lineCheck;
|
||||||
|
WCheckBox* pointsCheck;
|
||||||
|
|
||||||
Chart::WCartesianChart* fourierChart;
|
Chart::WCartesianChart* fourierChart;
|
||||||
shared_ptr<FourierModel> fourierModel;
|
shared_ptr<FourierModel> fourierModel;
|
||||||
|
|
||||||
@ -51,8 +60,6 @@ private:
|
|||||||
WCheckBox* showAll;
|
WCheckBox* showAll;
|
||||||
size_t checkCount = 0;
|
size_t checkCount = 0;
|
||||||
|
|
||||||
WContainerWidget* vals;
|
|
||||||
|
|
||||||
vector<Sin> sinuses;
|
vector<Sin> sinuses;
|
||||||
|
|
||||||
void addSin(Sin s);
|
void addSin(Sin s);
|
||||||
|
Loading…
Reference in New Issue
Block a user