Scientific programming with Delphi/Kylix

Up Scientific programming

Cubic Polynomial project

(Event-driven programming)

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 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 unit (Polynomial.dpr)

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. 

Form unit (fPolynomial.pas)

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).

Further design

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 some functionality

 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;

PaintBox.OnPaint event handler

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.  

Transformation to screen coordinates

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)

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
  PaintBox1Paint(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.

 

Kylix-specific notes

(in preparation)

Lazarus-specific notes

(in preparation)

Enhancement 

Delphi/Pascal projects

Other projects

 

Up Scientific programming
 

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

©Nikolai V. Shokhirev, 2004-2005