Scientific programming with Delphi/Kylix

Up Scientific programming

 

Cubic Polynomial Project 2

(Event-driven programming)

This is the enhancement of the project Cubic polynomial plot. The project uses an interface-based mathematical library PasMatLib

This program displays the plot for a cubic polynomial: C0 + C1 x + C2 x2 + C3 x3.

Subjects covered:

Initial design

Start Delphi. An empty form is created by default. Select File Save Project As, and in Delphi Project directory create the directory SciProg as well as the subdirectory CubicPolinomial. Save Unit1 as fPolynomial and Project1 as Polynomial2.

You can open and view Polynomial.dpr (program unit) and fPolynomial.pas (form unit). Delphi also generates several files with IDE settings and resources (see "Delphi generated files" in Delphi Help).

Follow all the steps from the previous project, but do not drop the PaintBox component on PanelPlot. Instead of this we will create the component TPlotBox2D dynamically.

Further design

Add to the uses section the following units

  uMatTypes,    // General types
  uDynArrays,   // Dynamic interface-based arrays
  uDynArrUtils, // Dynamic arrays utilities
  uGraph2D;     // 2D plot

Before type add

const
  n = 50;

Add to the private section of TForm1 the following code:

  private
    { Private declarations }
    c0, c1, c2, c3, Cmin, Cmax: TFloat;
    Xmin, Xmax, Ymin, Ymax: TFloat;
    PlotBox2D: TPlotBox2D;
    xa, ya: IFArr1D;
    dx: TFloat;
    function p3(x: TFloat): TFloat;
    procedure Plotting(Sender: TObject);
    procedure SetParameters; 

TFloat is set to double in the unit uMatTypes but can be reset to single or extended if necessary. TInt is set to integer (longint in earlier versions).

Select PanelPlot and set its BevelInner property to bvLowered. Press Ctrl-SHIFT-c and Delphi creates the empty functions in the implementation section. Add the reference to the Math unit right after the implementation

Add the following code into the created functions.

// Cubic polynomial
function TForm1.p3(x: TFloat): TFloat;
begin
  result := c0+x*(c1+x*(c2+x*c3));
end;

// Reads parameters from Edits and Scrollbars,
// Calculates arrays
procedure TForm1.SetParameters;
var
  i: TInt;
  x: TFloat;
begin
  Xmin := StrToFloat(EditXmin.Text);
  Xmax := StrToFloat(EditXmax.Text);
  Cmin := StrToFloat(EditCmin.Text);
  Cmax := StrToFloat(EditCmax.Text);
  
  c0 := Cmin + (Cmax-Cmin)*ScrollBarC0.Position/ScrollBarC0.Max; // Min = 0
  c1 := Cmin + (Cmax-Cmin)*ScrollBarC1.Position/ScrollBarC1.Max; // Min = 0
  c2 := Cmin + (Cmax-Cmin)*ScrollBarC2.Position/ScrollBarC2.Max; // Min = 0
  c3 := Cmin + (Cmax-Cmin)*ScrollBarC3.Position/ScrollBarC3.Max; // Min = 0
  
  for i := xa.Lo1 to xa.Hi1 do
  begin
    xa[i] := x;
    ya[i] := p3(x);
    x := x + dx;
  end;
end;

Form.OnCreate event handler

Select Form1 from the drop-down box in the Object Inspector and flip to the Events tab. Select OnCreate and double-click on the white field to the right. It creates the procedure FormCreate in the implementation section. Add the call to SetParameters:

procedure  TForm1.FormCreate(Sender: TObject);
begin
  xa := TFArr1D.Create(n); // Creation of arrays [1..n]
  ya := TFArr1D.Create(n); // they will automatically destroyed
  SetParameters;
  // plot creation
  PlotBox2D := TPlotBox2D.Create(self, PanelPlot); // PanelPlot is the parent of PlotBox2D
               // self (Form1) is the owner and it will take care of the destruction of PlotBox2D
  PlotBox2D.NXTicks := 5;
  PlotBox2D.NYTicks := 5;
  PlotBox2D.XTitle := 'x';
  PlotBox2D.YTitle := 'F(x)';
  PlotBox2D.OnPaint := Plotting; // event handler assignment 
                       // Set to nil to disconnect the event handler 
end;

PlotBox2D.OnPaint event handler

Now PlotBox automatically rescale axes and transforms physical to screen coordinates. It makes the code much simpler.

procedure TForm1.Plotting(Sender: TObject);
var
  i: TInt;
  OldColor: TColor;
begin
  MinMaxVec(ya, Ymin, Ymax); // for several functions use 2D array and MinMaxMat
  if Ymax = Ymin then   // just in case ...
    Ymax := Ymax +0.1;
  // incluse zero line in limits
  Ymin := min(Ymin, 0);
  Ymax := max(Ymax, 0);

  PlotBox2D.SetLimits(Xmin, Xmax, Ymin, Ymax);
  PlotBox2D.PlotFrame;

  OldColor := PlotBox2D.PenColor;
  PlotBox2D.PenColor := clBlue;
  PlotBox2D.PenWidth := 2;
  i := xa.Lo1;
  PlotBox2D.MoveToF(xa[i],ya[i]);
  for i := xa.Lo1+1 to xa.Hi1 do
  begin
    PlotBox2D.LineToF(xa[i],ya[i]);
  end;
  PlotBox2D.PenColor := clRed;
  PlotBox2D.PenWidth := 1;
  PlotBox2D.LineF(Xmin, 0, Xmax, 0);

  PlotBox2D.PenColor := OldColor; // restore
end;

OnPaint occurs when the PaintBox receives a Windows paint message. It happens, for example, when the PaintBox is resized.  

ScrollBar.OnChange event handler

The last event handler processes the scrollbars' movement. Select e.g. ScrollBarC0 and its OnChange event. Create the ScrollBarC0Change procedure:

procedure TForm1.ScrollBarC0Change(Sender: TObject);
begin
  SetParameters;
  Plotting(Sender);
end;

Select the same procedure for the rest of the scrollbars.

 Run the program:

Download

The project code for Delphi 7 can be downloaded here.

 

Further enhanecements

The picture (plot) can be saved as a bitmap or JPEG file using the methods SaveToBMP and SaveToJPEG respectively.

The object TFormPlot can be used for plotting a function (see the project TestGraph2D in \PasMatLib\Tests\TestGraph2D).

Kylix-specific notes

(in preparation)

Lazarus-specific notes

(in preparation)

Delphi/Pascal projects

Other projects

 

Up Scientific programming
 

Home | Resumé |  Shokhirev.com |  Computing |  Links |  Publications

©Nikolai V. Shokhirev, 2004-2005