| Scientific programming |
(Event-driven programming)
This program displays the plot for a cubic polynomial: C0 + C1 x + C2 x2 + C3 x3.
Subjects covered:
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 Polynomial.
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).
program Polynomial;
uses
Forms,
fPolynomial in 'fPolynomial.pas' {Form1};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
Normally you do not work with the program unit directly. It is automatically updated by Delphi. The program loads the necessary resources (*.res), creates form(s) and starts the execution.
unit fPolynomial;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs;
type
TForm1 = class(TForm)
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
end.
This is the only (so far) working unit. It consists of two parts: interface and implementation.
In the interface section of a unit the references to the other used units are listed and types, enumerations, classes and variables are declared. Interfaces correspond to headers in C++. Now, only one class, TForm1, is defined. It inherits from TForm declared in the Forms unit and introduces no new functionality. The variable Form1 of the type TForm1 is also declared. It could be renamed in the Object Inspector.
In the implementation section currently only the design information is loaded from fPolynomial.dfm.
This is a fully-functional program (although it does nothing useful) and you
can run it (click
or press F9).
Stop the program, click on the fPolynomial tab:
and press F12 to toggle code
design.
Drop Panel on the form and make it large enough for the following components. In the Object Inspector set
its Name to PanelBottom, Caption
empty string. Drop 8 Labels on the Panel, accept their default names and set the captions to
'X min', 'X max', 'C min', 'C max', 'C 0', 'C 1', 'C 2', 'C 3'.
Drop 4 ScrollBars and name them 'ScrollBarC0', 'ScrollBarC1', 'ScrollBarC2', 'ScrollBarC3'. Then drop 4 Edits and name them 'EditXmin', 'EditXmax', 'EditCmin', 'EditCmax'. Arrange all components according to the picture.
Change the Anchors properties of the scrollbars to [akLeft,akRight]. This make the scrollbars to resize automatically with resizing the form. Tip: by Shift-clicking select them all and change the properties at once. Select PanelBottom and set Align property to alBottom.
Drop another Panel on the form, assign Name to PanelPlot. Set Align property to alClient.
Then drop the PaintBox component on PanelPlot and set its Align property to alClient.
Take a look at the class TForm1 now. Note, that Delphi updates the TForm1 class declaration.
Try to run the program.
Add the following declaration to the private section of TForm1:
private
{ Private declarations }
c0, c1, c2, c3, Cmin, Cmax: double;
Xmin, Xmax, Ymin, Ymax: double;
procedure SetParameters;
function p3(x: double): double;
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:
uses math;
Add the following code into the functions:
// Cubic polynomial
function TForm1.p3(x: double): double;
begin
result := c0+x*(c1+x*(c2+x*c3));
end;
// Reads parameters from Edits and Scrollbars,
// Calculates Y-limits
procedure TForm1.SetParameters;
const
n = 50;
var
i: integer;
x: double;
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
Ymin := 1.0e+9;
Ymax :=-1.0e+9;
for i := 0 to n do
begin
x := Xmin+(Xmax-Xmin)*i/n;
Ymin := Min(Ymin, p3(x));
Ymax := Max(Ymax, p3(x));
end;
Ymax := Ymax + 0.1;
Ymin := Ymin - 0.1;
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 SetParameters; // initial parameters end;
Select PaintBox1 and select its OnPaint event. Create PaintBox1Paintprocedure by double clicking to the white field. Type the following code:
procedure TForm1.PaintBox1Paint(Sender: TObject);
const
n = 50;
var
i, mX, mY, ix, iy, OldWidth: integer;
x, y: double;
begin
SetParameters;
mX := PaintBox1.ClientWidth;
mY := PaintBox1.ClientHeight;
PaintBox1.Canvas.Brush.Color := clWhite; // makes white background
PaintBox1.Canvas.FillRect(PaintBox1.ClientRect); // fill PaintBox with Brush.Color
// zero line plot
ix := 0;
y := 0.0;
iy := round(mY*(Ymax-y)/(Ymax-Ymin));
PaintBox1.Canvas.MoveTo(ix, iy);
PaintBox1.Canvas.Pen.Color := clRed;
PaintBox1.Canvas.LineTo(mX, iy);
PaintBox1.Canvas.Pen.Color := clBlack;
// polynomial plot
ix := 0;
y := p3(Xmin);
iy := round(mY*(Ymax-y)/(Ymax-Ymin));
PaintBox1.Canvas.MoveTo(ix, iy); // the 1st point
OldWidth := PaintBox1.Canvas.Pen.Width; // remember
PaintBox1.Canvas.Pen.Width := 2;
for i := 0 to n do
begin
x := Xmin+(Xmax-Xmin)*i/n;
y := p3(x);
ix := round(i*mX/n);
iy := round(mY*(Ymax-y)/(Ymax-Ymin));
PaintBox1.Canvas.LineTo(ix, iy);
end;
PaintBox1.Canvas.Pen.Width := OldWidth; // restore
end;
OnPaint occurs when the PaintBox receives a Windows paint message. It happens, for example, when the PaintBox is resized.
In the code above, the (x, y) coordinates are transformed to the screen (pixel) coordinates (ix, iy). This is a linear transformation of the form
ix = x*Ax + Bx
iy = y*Ay + By
The point (ix = 0, iy = 0) is in the upper right corner of PaintBox. The ix-coordinate goes to the right. The iy-coordinate goes down. The transformation coefficients are determined from the following conditions:
0 = Xmax*Ax + Bx
mX = Xmin*Ax + Bx
0 = Ymax*Ay + By
mY = Ymin*Ay + By
Here mX and mY are width and height of the PaintBox. Finally, the transformation is
ix = mX*(x - Xmin)/(Xmax - Xmin)
iy = mY*(Xmax - y)/(Ymax - Ymin)
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 PaintBox1Paint(Sender); end;
Select the same procedure for the rest of the scrollbars:
Run the program:
The project code for Delphi 7 can be downloaded here.
(in preparation)
(in preparation)
| Scientific programming |
©Nikolai V. Shokhirev, 2004-2005