@ -5,6 +5,28 @@
# include <ranges>
# 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
{
public :
@ -23,6 +45,7 @@ public:
sinuses | views : : transform ( [ x ] ( Sin s ) { return s . get ( x ) ; } ) ,
std : : plus < double > ( )
) . value_or ( 0 ) ;
default :
try { return sinuses . at ( column - 2 ) . get ( x ) ; }
catch ( out_of_range e ) { return 0 ; }
@ -45,13 +68,14 @@ private:
class FourierModel : public Chart : : WAbstractChartModel
{
public :
FourierModel ( shared_ptr < SinModel > dm )
FourierModel ( shared_ptr < SinModel > dm , vector < pair < double , double > > & fd )
: Chart : : WAbstractChartModel { }
, discreteModel { dm }
, fourier_data { fd }
{
dm - > changed ( ) . connect ( [ this ] ( ) {
data_ . clear ( ) ;
data_ . reserve ( rowCount ( ) ) ;
fourier_ data. clear ( ) ;
fourier_ data. reserve ( rowCount ( ) ) ;
for ( int k = 0 ; k < rowCount ( ) ; k + + ) {
double x = 0 ,
@ -64,7 +88,7 @@ public:
y - = v * sin ( e ) ;
}
data_[ k ] = { sqrt ( x * x + y * y ) / rowCount ( ) , atan2 ( y , x ) } ;
fourier_data. push_back ( { x , y } ) ;
}
changed ( ) . emit ( ) ;
@ -74,38 +98,54 @@ public:
virtual double data ( int row , int column ) const override {
switch ( column ) {
case 0 : return row ;
case 1 : return data_ [ row ] . first ;
case 2 : return data_ [ row ] . second ;
case 1 : return sqrt( pow ( fourier_ data[ row ] . first , 2 ) + pow ( fourier_data [ row ] . second , 2 ) ) / rowCount ( ) ;
case 2 : return atan2( fourier_ data[ row ] . second , fourier_data [ row ] . first ) ;
default : return 0 ;
}
}
virtual WString displayData ( int row , int column ) const override {
if ( column = = 0 ) {
if ( row = = rowCount ( ) / 2 ) return " π " ;
if ( row = = rowCount ( ) - 1 ) return " 2π " ;
}
return Chart : : WAbstractChartModel : : displayData ( row , column ) ;
}
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 :
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>
# 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>
virtual double data ( int row , int column ) const override {
if ( column = = 0 ) return - M_PI + row * 2 * M_PI / ( rowCount ( ) - 1 ) ; ;
if ( fourier_data . size ( ) = = 0 ) return 0 ;
double y = 0 ;
for ( int k = 0 ; k < fourier_data . size ( ) ; k + + ) {
double theta = ( 2 * M_PI * k * ( row + 1 ) ) / fourier_data . size ( ) ;
y + = fourier_data . at ( k ) . first * cos ( theta ) + fourier_data . at ( k ) . second * sin ( theta ) ;
}
return y / fourier_data . size ( ) ;
}
# 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>
virtual int columnCount ( ) const override { return 2 ; } ;
virtual int rowCount ( ) const override { return fourier_data . size ( ) ; }
private :
int rows_ = 0 ;
vector < pair < double , double > > & fourier_data ;
} ;
MyApplication : : MyApplication ( const WEnvironment & env )
@ -157,6 +197,26 @@ MyApplication::MyApplication(const WEnvironment& env)
pointsDS - > setLabelColor ( StandardColor : : Black ) ;
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 ) . setMinimumZoomRange ( M_PI / 16.0 ) ;
@ -172,7 +232,7 @@ MyApplication::MyApplication(const WEnvironment& env)
chart - > axis ( Chart : : Axis : : Y ) . setGridLinesEnabled ( true ) ;
chart - > resize ( 800 , 6 00) ;
chart - > resize ( 800 , 5 00) ;
chart - > setPanEnabled ( true ) ;
chart - > setZoomEnabled ( true ) ;
@ -208,11 +268,13 @@ MyApplication::MyApplication(const WEnvironment& env)
chart - > update ( ) ;
} ) ;
form - > addNew < WText > ( " a =" ) ;
form - > addNew < WText > ( " α =" ) ;
auto a = form - > addNew < WDoubleSpinBox > ( ) ;
form - > addNew < WText > ( " w= " ) ;
a - > setValue ( 1 ) ;
form - > addNew < WText > ( " ω= " ) ;
auto w = form - > addNew < WDoubleSpinBox > ( ) ;
form - > addNew < WText > ( " f= " ) ;
w - > setValue ( 1 ) ;
form - > addNew < WText > ( " φ= " ) ;
auto f = form - > addNew < WDoubleSpinBox > ( ) ;
for ( auto i : { a , w , f } ) {
@ -233,12 +295,13 @@ MyApplication::MyApplication(const WEnvironment& env)
right - > setOverflow ( Overflow : : Hidden , Orientation : : Horizontal ) ;
{ // дискретизация
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 < W CheckBox> ( " дискретизация " ) ;
form - > addNew < W Text> ( " частота дискретизации " ) ;
auto freq = form - > addNew < WSpinBox > ( ) ;
freq - > setWidth ( 120 ) ;
freq - > setRange ( 0 , 1000 ) ;
auto show = form - > addNew < WCheckBox > ( " показать точки " ) ;
show - > clicked ( ) . connect ( [ = , this ] ( ) {
pointsDS - > setHidden ( ! show - > isChecked ( ) ) ;
@ -248,33 +311,25 @@ MyApplication::MyApplication(const WEnvironment& env)
freq - > changed ( ) . connect ( [ = , this ] ( ) {
discreteModel - > setRows ( freq - > value ( ) ) ;
} ) ;
discreteModel - > changed ( ) . connect ( [ this ] ( ) {
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 " ) ;
}
restoredDS - > setHidden ( freq - > value ( ) = = 0 | | ! lineCheck - > isChecked ( ) ) ;
restoredDS_points - > setHidden ( freq - > value ( ) = = 0 | | ! pointsCheck - > isChecked ( ) ) ;
chart - > update ( ) ;
} ) ;
}
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 - > setPlotAreaPadding ( 100 ) ;
fourierChart - > setPlotAreaPadding ( 100 , Side : : Right | Side : : Left ) ;
fourierChart - > setPlotAreaPadding ( 50 , Side : : Top | Side : : Bottom ) ;
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 - > setXSeriesColumn ( 0 ) ;
auto seriesPtr = make_unique < Chart : : WDataSeries > ( 2 , Chart : : SeriesType : : Point ) ;
auto phaseSeries = seriesPtr . get ( ) ;
phaseSeries - > setModel ( fourierChart - > model ( ) ) ;
phaseSeries - > setXSeriesColumn ( 0 ) ;
//phaseSeries->setXSeriesColumn(0);
phaseSeries - > setShadow ( WShadow ( 3 , 3 , WColor ( 0 , 0 , 0 , 127 ) , 3 ) ) ;
fourierChart - > addSeries ( std : : move ( seriesPtr ) ) ;
@ -282,7 +337,7 @@ MyApplication::MyApplication(const WEnvironment& env)
seriesPtr = make_unique < Chart : : WDataSeries > ( 1 , Chart : : SeriesType : : Line ) ;
auto ampSeries = seriesPtr . get ( ) ;
ampSeries - > setModel ( fourierChart - > model ( ) ) ;
ampSeries - > setXSeriesColumn ( 0 ) ;
//ampSeries->setXSeriesColumn(0);
ampSeries - > setShadow ( WShadow ( 3 , 3 , WColor ( 0 , 0 , 0 , 127 ) , 3 ) ) ;
fourierChart - > addSeries ( std : : move ( seriesPtr ) ) ;
auto id = fourierChart - > addYAxis ( make_unique < Chart : : WAxis > ( ) ) ;
@ -300,7 +355,52 @@ MyApplication::MyApplication(const WEnvironment& env)
fourierChart - > setZoomEnabled ( 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 ) {