.


:




:

































 

 

 

 





. 3.4 .

 

 

3.4

 

, . . .

, , , .

. , . (. 3.5).

3.5

.


unit MainFm;

 

interface

 

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

Dialogs, StdCtrls, ExtCtrls, ActnList, Menus, Ball, XPMan, ComCtrls;

 

type

TMainForm = class(TForm)

WorkAreaPanel: TPanel;

LabMainMenu: TMainMenu;

FileMenuItem: TMenuItem;

ExitMenuItem: TMenuItem;

ParamMenuItem: TMenuItem;

AboutMenuItem: TMenuItem;

RestartMenuItem: TMenuItem;

ActionList1: TActionList;

ExitAction: TAction;

RestartAction: TAction;

AboutAction: TAction;

ManageGroupBox: TGroupBox;

RestartButton: TButton;

AnimateTimer: TTimer;

PauseButton: TButton;

XPManifest1: TXPManifest;

PauseAction: TAction;

PauseItem: TMenuItem;

SpeedEdit: TEdit;

SpeedUpDown: TUpDown;

RadiusEdit: TEdit;

RadiusUpDown: TUpDown;

AngleLabel: TLabel;

RadiusLabel: TLabel;

HideControlPanelAction: TAction;

HideControlPanelMenuItem: TMenuItem;

ButtonGroupBox: TGroupBox;

BallGroupBox: TGroupBox;

SurfaceGroupBox: TGroupBox;

AutoGenerateCheckBox: TCheckBox;

FirstSinLabel: TLabel;

FirstSinMEdit: TEdit;

FirstSinPiShiftEdit: TEdit;

OperationEdit: TEdit;

SecondSinMEdit: TEdit;

SecondSinLabel: TLabel;

SecondSinPiShiftEdit: TEdit;

Label1: TLabel;

AnglePiLabel: TLabel;

AngleEdit: TEdit;

RandomAngleCheckBox: TCheckBox;

FirstSinDividerEdit: TEdit;

SecondSinDividerEdit: TEdit;

procedure AboutActionExecute(Sender: TObject);

procedure RestartActionExecute(Sender: TObject);

procedure ExitActionExecute(Sender: TObject);

procedure AnimateTimerTimer(Sender: TObject);

procedure PauseButtonClick(Sender: TObject);

procedure FormPaint(Sender: TObject);

procedure PauseActionExecute(Sender: TObject);

procedure SpeedUpDownClick(Sender: TObject; Button: TUDBtnType);

procedure SpeedEditKeyDown(Sender: TObject; var Key: Word;

Shift: TShiftState);

procedure FormCreate(Sender: TObject);

procedure RadiusUpDownClick(Sender: TObject; Button: TUDBtnType);

procedure RadiusEditKeyDown(Sender: TObject; var Key: Word;

Shift: TShiftState);

procedure HideControlPanelActionExecute(Sender: TObject);

procedure WorkAreaPanelResize(Sender: TObject);

procedure AutoGenerateCheckBoxClick(Sender: TObject);

procedure RandomAngleCheckBoxClick(Sender: TObject);

private

FDrawInited: Boolean;

// .

procedure Restart;

end;

 

var

MainForm: TMainForm;

 

implementation

 

uses Math;

 

{$R *.dfm}

 

const

MAX_START_SPEED = 10000;

 

type

EWrongOperation = class(Exception);

 

procedure TMainForm.AboutActionExecute(Sender: TObject);

const

ABOUT_MESSAGE = ' 2011 .' + sLineBreak +

' . 01-784-1 - ..' + sLineBreak +

'( )';

begin

ShowMessage(ABOUT_MESSAGE);

end;

 

procedure TMainForm.RestartActionExecute(Sender: TObject);

begin

Restart;

end;

 

procedure TMainForm.ExitActionExecute(Sender: TObject);

begin

Close;

end;

 

procedure TMainForm.AnimateTimerTimer(Sender: TObject);

begin

AnimateTimer.Enabled:= False;

Ball.Iterate;

AnimateTimer.Enabled:= True;

end;

 

procedure TMainForm.PauseButtonClick(Sender: TObject);

begin

AnimateTimer.Enabled:= False;

end;

 

procedure TMainForm.FormPaint(Sender: TObject);

begin

if FDrawInited then

Ball.Draw;

end;

 

procedure TMainForm.PauseActionExecute(Sender: TObject);

const

PAUSE_CAPTION = '';

PLAY_CAPTION = '';

begin

AnimateTimer.Enabled:= not AnimateTimer.Enabled;

if AnimateTimer.Enabled then

PauseAction.Caption:= PAUSE_CAPTION

else

PauseAction.Caption:= PLAY_CAPTION;

end;

 

procedure TMainForm.SpeedUpDownClick(Sender: TObject; Button: TUDBtnType);

begin

SpeedEdit.Text:= FloatToStr(SpeedUpDown.Position / 10);

end;

 

procedure TMainForm.SpeedEditKeyDown(Sender: TObject; var Key: Word;

Shift: TShiftState);

var

Value: Double;

begin

if Key = VK_RETURN then

try

Value:= StrToFloat(SpeedEdit.Text);

if Value < 0 then

SpeedEdit.Text:= '0'

else

if Value > MAX_START_SPEED then

SpeedEdit.Text:= FloatToStr(MAX_START_SPEED);

SpeedUpDown.Position:= Round(StrToFloat(SpeedEdit.Text) * 10);

except

SpeedEdit.Text:= FloatToStr(SpeedUpDown.Position / 10);

end;

end;

 

procedure TMainForm.FormCreate(Sender: TObject);

begin

SpeedUpDown.Max:= High(SmallInt);

end;

 

procedure TMainForm.RadiusUpDownClick(Sender: TObject;

Button: TUDBtnType);

begin

RadiusEdit.Text:= FloatToStr(RadiusUpDown.Position / 10);

end;

 

procedure TMainForm.Restart;

const

PAUSE_CAPTION = '';

OPERATION_MINUS = '-';

OPERATION_PLUS = '+';

E_CONVERT_ERROR = '''%s'' ';

var

Buffer: String;

WrongFloatValue: String;

begin

try

if not FDrawInited then

begin

InitDrawing(WorkAreaPanel);

FDrawInited:= True;

end;

PauseAction.Enabled:= True;

PauseAction.Caption:= PAUSE_CAPTION;

AnimateTimer.Enabled:= False;

BallDefaultZeroSpeed:= SpeedUpDown.Position / 10;

BallVariable.Radius:= RadiusUpDown.Position * 10;

if not AutoGenerateCheckBox.Checked then

with SurfaceGenerationParams do

begin

FirstSinusoidMultiplier:= StrToFloat(FirstSinMEdit.Text);

FirstSinusoidPIShift:= StrToFloat(FirstSinPiShiftEdit.Text);

FirstSinusoidDivider:= StrToFloat(FirstSinDividerEdit.Text);

SecondSinusoidMultiplier:= StrToFloat(SecondSinMEdit.Text);

SecondSinusoidPIShift:= StrToFloat(SecondSinPiShiftEdit.Text);

SecondSinusoidDivider:= StrToFloat(SecondSinDividerEdit.Text);

if Trim(OperationEdit.Text) = OPERATION_PLUS then

SinOperation:= 1

else

if Trim(OperationEdit.Text) = OPERATION_MINUS then

SinOperation:= -1

else

raise EWrongOperation.Create(' + -');

end;

if not RandomAngleCheckBox.Checked then

MovementParams.Alpha:= Pi / StrToFloat(AngleEdit.Text);

Ball.Restart(WorkAreaPanel.ClientWidth, WorkAreaPanel.ClientHeight,

AutoGenerateCheckBox.Checked, RandomAngleCheckBox.Checked);

if AutoGenerateCheckBox.Checked then

with SurfaceGenerationParams do

begin

FirstSinMEdit.Text:= FloatToStr(FirstSinusoidMultiplier);

FirstSinPiShiftEdit.Text:= FloatToStr(FirstSinusoidPIShift);

FirstSinDividerEdit.Text:= FloatToStr(FirstSinusoidDivider);

SecondSinMEdit.Text:= FloatToStr(SecondSinusoidMultiplier);

SecondSinPiShiftEdit.Text:= FloatToStr(SecondSinusoidPIShift);

SecondSinDividerEdit.Text:= FloatToStr(SecondSinusoidDivider);

case SinOperation of

-1:

OperationEdit.Text:= OPERATION_MINUS;

1:

OperationEdit.Text:= OPERATION_PLUS;

end;

end;

if RandomAngleCheckBox.Checked then

AngleEdit.Text:= FloatToStr(Pi / MovementParams.Alpha);

AnimateTimer.Enabled:= True;

except

on E: EConvertError do

begin

Buffer:= Copy(E.Message, 2, Length(E.Message) - 1);

WrongFloatValue:= Copy(Buffer, 1, Pos('''', Buffer) - 1);

ShowMessage(Format(E_CONVERT_ERROR, [WrongFloatValue]));

end;

on E: EWrongOperation do

ShowMessage(E.Message);

end;

end;

 

procedure TMainForm.RadiusEditKeyDown(Sender: TObject; var Key: Word;

Shift: TShiftState);

var

Value: Double;

begin

if Key = VK_RETURN then

try

Value:= StrToFloat(RadiusEdit.Text);

if Value < 0 then

RadiusEdit.Text:= '0'

else

if Value > 0.5 then

RadiusEdit.Text:= '0.5';

RadiusUpDown.Position:= Round(StrToFloat(RadiusEdit.Text) * 10);

except

RadiusEdit.Text:= FloatToStr(RadiusUpDown.Position / 10);

end;

end;

 

procedure TMainForm.HideControlPanelActionExecute(Sender: TObject);

const

HIDE_ACTION_CAPTION = ' ';

SHOW_ACTION_CAPTION = ' ';

begin

ManageGroupBox.Visible:= not ManageGroupBox.Visible;

case ManageGroupBox.Visible of

True:

HideControlPanelAction.Caption:= HIDE_ACTION_CAPTION;

False:

HideControlPanelAction.Caption:= SHOW_ACTION_CAPTION;

end;

end;

 

procedure TMainForm.WorkAreaPanelResize(Sender: TObject);

begin

if FDrawInited then

ResizeBox(WorkAreaPanel.ClientWidth, WorkAreaPanel.ClientHeight);

end;

 

procedure TMainForm.AutoGenerateCheckBoxClick(Sender: TObject);

begin

FirstSinMEdit.Enabled:= not FirstSinMEdit.Enabled;

FirstSinPiShiftEdit.Enabled:= not FirstSinPiShiftEdit.Enabled;

OperationEdit.Enabled:= not OperationEdit.Enabled;

SecondSinMEdit.Enabled:= not SecondSinMEdit.Enabled;

SecondSinPiShiftEdit.Enabled:= not SecondSinPiShiftEdit.Enabled;

FirstSinLabel.Enabled:= not FirstSinLabel.Enabled;

SecondSinLabel.Enabled:= not SecondSinLabel.Enabled;

FirstSinDividerEdit.Enabled:= not FirstSinDividerEdit.Enabled;

SecondSinDividerEdit.Enabled:= not SecondSinDividerEdit.Enabled;

end;

 

procedure TMainForm.RandomAngleCheckBoxClick(Sender: TObject);

begin

AnglePiLabel.Enabled:= not AngleLabel.Enabled;

AngleEdit.Enabled:= not AngleEdit.Enabled;

end;

 

end.

unit Ball;

 

interface

 

uses

Windows, Graphics, Controls, VectoryAlgebra;

 

type

// .

TBall = record

// X .

X: Double;

// Y .

Y: Double;

// .

Radius: Double;

// .

Speed: Double;

end;

 

// .

TSurface = array of TPoint;

 

// .

TSurfaceGenerationParams = record

// .

FirstSinusoidMultiplier: Double;

// .

SecondSinusoidMultiplier: Double;

// .

FirstSinusoidDivider: Double;

// .

SecondSinusoidDivider: Double;

// .

FirstSinusoidPIShift: Double;

// .

SecondSinusoidPIShift: Double;

// .

SinOperation: Integer;

// Y .

SurfaceMinY: Integer;

end;

 

// .

TContactType = (

// .

ctBoxLeft,

// .

ctBoxRight,

// .

ctBoxTop,

// .

ctBoxBottom,

// .

ctSurface);

 

// .

TBallMovementParams = record

// .

TimeMoment: Double;

// .

Alpha: Double;

// .

PreviousPoint: TVector2R;

// 0- .

ZeroPoint: TVector2R;

// 0 .

ZeroPointSpeed: Double;

end;

 

// .

procedure Draw;

// .

procedure ResizeBox(

// .

const ABoxWidth: Integer;

// .

const ABoxHeight: Integer);

// .

procedure Restart(

// .

const ABoxWidth: Integer;

// .

const ABoxHeight: Integer;

// .

const AIsAutoGeneratedSurface: Boolean;

// .

const AIsRandomAngle: Boolean);

// .

procedure InitDrawing(

// .

const AWindow: TWinControl);

// .

procedure Iterate;

 

 

var

// 0 .

BallDefaultZeroSpeed: Double;

// .

EnegryTransmissionMultiplier: Double;

// .

BallVariable: TBall;

// .

SurfaceGenerationParams: TSurfaceGenerationParams;

// .

MovementParams: TBallMovementParams;

 

implementation

 

uses

Math, Types, SysUtils, Classes;

 

var

//

BoxHeight: Integer;

// .

BoxWidth: Integer;

// .

Surface: TSurface;

// .

DrawingWindow: TWinControl;

// .

Background: TBitmap;

 

function GetBallRect: TRect;

begin

Result.TopLeft.X:= Round(BallVariable.X - BallVariable.Radius);

Result.TopLeft.Y:= Round(BallVariable.Y + BallVariable.Radius);

Result.BottomRight.X:= Round(BallVariable.X + BallVariable.Radius);

Result.BottomRight.Y:= Round(BallVariable.Y - BallVariable.Radius);

end;

 

procedure CalculateAlpha(

const AContactType: TContactType; const ASurfacePointIndex: Integer);

var

ContactPoint, PreviousPointMove, Perpendicular: TVector2R;

BufferAlpha, Teta, AxisDifferenceAngle: Double;

begin

// .

case AContactType of

ctBoxLeft:

ContactPoint:= AddVect2R(Vector2R(BallVariable.X, BallVariable.Y), Vector2R(- BallVariable.Radius, 0));

ctBoxRight:

ContactPoint:= AddVect2R(Vector2R(BallVariable.X, BallVariable.Y), Vector2R(BallVariable.Radius, 0));

ctBoxTop:

ContactPoint:= AddVect2R(Vector2R(BallVariable.X, BallVariable.Y), Vector2R(0, BallVariable.Radius));

ctBoxBottom:

ContactPoint:= AddVect2R(Vector2R(BallVariable.X, BallVariable.Y), Vector2R(0, - BallVariable.Radius));

ctSurface:

ContactPoint:= Vector2R(Surface[ASurfacePointIndex].X, Surface[ASurfacePointIndex].Y);

end;

with MovementParams do

begin

PreviousPointMove:= SubVect2R(PreviousPoint,

Vector2R(BallVariable.X, BallVariable.Y));

Perpendicular:= RightPerpendicularVector2R(SubVect2R(Vector2R(BallVariable.X, BallVariable.Y), ContactPoint));

BufferAlpha:= AngelFromVectorToVector(Perpendicular, PreviousPointMove);

Teta:= Pi - BufferAlpha;

AxisDifferenceAngle:= AngelFromVectorToVector2Pi(Vector2R(1, 0), Perpendicular);

Alpha:= Teta + AxisDifferenceAngle;

TimeMoment:= 0;

ZeroPoint.X:= BallVariable.X;

ZeroPoint.Y:= BallVariable.Y;

ZeroPointSpeed:= BallVariable.Speed;

end;

end;

 

procedure CheckContact;

var

I, MinSurfaceDistanceIndex: Integer;

MinSurfaceDistance, Distance: Double;

begin

with MovementParams do

begin

// .

if (GetBallRect.Left <= 0) and (BallVariable.X <= PreviousPoint.X) then

CalculateAlpha(ctBoxLeft, 0) else

if (GetBallRect.Right >= BoxWidth) and (BallVariable.X >= PreviousPoint.X) then

CalculateAlpha(ctBoxRight, 0)else

if (GetBallRect.Top >= BoxHeight) and (BallVariable.Y >= PreviousPoint.Y) then

CalculateAlpha(ctBoxTop, 0)else

if (GetBallRect.Bottom <= 0) and (BallVariable.Y <= PreviousPoint.Y) then

CalculateAlpha(ctBoxBottom, 0)else

begin

// .

MinSurfaceDistance:= 1.7e308;

MinSurfaceDistanceIndex:= -1;

for I:= 0 to Length(Surface) - 1 do

begin

Distance:= DistBetweenPoints2R(Vector2R(Surface[I].X, Surface[I].Y),

Vector2R(BallVariable.X, BallVariable.Y));

if Distance < MinSurfaceDistance then

begin

MinSurfaceDistance:= Distance;

MinSurfaceDistanceIndex:= I;

end;

end;

if (MinSurfaceDistanceIndex <> -1) and (MinSurfaceDistance <= BallVariable.Radius) and

(MinSurfaceDistance < DistBetweenPoints2R(Vector2R(Surface[MinSurfaceDistanceIndex].X,

Surface[MinSurfaceDistanceIndex].Y), PreviousPoint)) then

CalculateAlpha(ctSurface, MinSurfaceDistanceIndex);

end;

end;

end;

 

procedure CalculateSurfaceMinY;

var

I, CalculatedValue: Integer;

begin

with SurfaceGenerationParams do

begin

SurfaceMinY:= High(Integer);

// [0; 2Pi].

for I:= 0 to 628 do

begin

CalculatedValue:= Round((FirstSinusoidMultiplier * Sin(I / FirstSinusoidDivider) -

pi / FirstSinusoidPIShift) + SinOperation * (SecondSinusoidMultiplier *

Sin(I / SecondSinusoidDivider) + pi / SecondSinusoidPIShift));

if CalculatedValue < SurfaceMinY then

SurfaceMinY:= CalculatedValue;

end;

SurfaceMinY:= Abs(SurfaceMinY) + 10;

end;

end;

 

procedure GenerateRandomSurfaceParams;

begin

with SurfaceGenerationParams do

begin

Randomize;

FirstSinusoidMultiplier:= 25 * (Random(5) + 1);

SecondSinusoidMultiplier:= 15 * (Random(3) + 1);

FirstSinusoidDivider:= 100;

SecondSinusoidDivider:= 50;

FirstSinusoidPIShift:= Random(3) + 1;

SecondSinusoidPIShift:= Random(6) + 1;

SinOperation:= Random(2) - 1;

if SinOperation = 0 then

Inc(SinOperation);

end;

end;

 

procedure GenerateSurface;

var

I: Integer;

begin

SetLength(Surface, 0);

SetLength(Surface, BoxWidth);

with SurfaceGenerationParams do

begin

for I:= 0 to BoxWidth - 1 do

begin

Surface[I].X:= I;

// 2 .

Surface[I].Y:= Round(

(FirstSinusoidMultiplier * Sin(I / FirstSinusoidDivider) - pi / FirstSinusoidPIShift) +

SinOperation * (SecondSinusoidMultiplier * Sin(I/ SecondSinusoidDivider) +

pi / SecondSinusoidPIShift));;

end;

// , .

for I:= 0 to BoxWidth - 1 do

Surface[I].Y:= Surface[I].Y + Abs(SurfaceMinY);

end;

end;

 

procedure Iterate;

 

var

I: Integer;

IterateCount: Integer;

begin

if BallVariable.Speed > 1 then

IterateCount:= Round(BallVariable.Speed) + 10

else

IterateCount:= 1;

with MovementParams do

for I:= 1 to IterateCount do

begin

TimeMoment:= TimeMoment + 0.01 / IterateCount;

PreviousPoint:= Vector2R(BallVariable.X, BallVariable.Y);

BallVariable.X:= ZeroPoint.X + Cos(Alpha) * ZeroPointSpeed * TimeMoment * 100;

BallVariable.Y:= ZeroPoint.Y + (Sin(Alpha) * ZeroPointSpeed * TimeMoment -

4.9 * Sqr(TimeMoment)) * 100;

BallVariable.Speed:= Sqrt(Sqr(ZeroPointSpeed * Cos(Alpha)) +

Sqr(ZeroPointSpeed * Sin(Alpha) - 9.8 * TimeMoment));

CheckContact;

end;

Draw;

end;

 

function InvertRect(ARect: TRect): TRect;

begin

Result:= ARect;

Result.TopLeft.Y:= BoxHeight - Result.TopLeft.Y;

Result.BottomRight.Y:= BoxHeight - Result.BottomRight.Y;

end;

 

function Invert(APoint: TPoint): TPoint;

begin

Result.X:= APoint.X;

Result.Y:= BoxHeight - APoint.Y;

end;

 

procedure GenerateBackground;

var

DrawableSurface: array of TPoint;

I: Integer;

begin

if not Assigned(Background) then

Background:= TBitmap.Create;

Background.Width:= BoxWidth;

Background.Height:= BoxHeight;

SetLength(DrawableSurface, Length(Surface) + 2);

try

for I:= 0 to Length(Surface) - 1 do

DrawableSurface[I]:= Invert(Surface[I]);

DrawableSurface[Length(Surface)].X:= BoxWidth;

DrawableSurface[Length(Surface)].Y:= BoxHeight;

DrawableSurface[Length(Surface) + 1].X:= 0;

DrawableSurface[Length(Surface) + 1].Y:= BoxHeight;

 

with Background.Canvas do

begin

Pen.Color:= clRed;

Brush.Color:= clWhite;

Rectangle(DrawingWindow.ClientRect);

Brush.Color:= clRed;

Polygon(DrawableSurface);

end;

finally

SetLength(DrawableSurface, 0);

end;

end;

 

procedure ResizeBox(const ABoxWidth,

ABoxHeight: Integer);

begin

BoxWidth:= ABoxWidth;

BoxHeight:= ABoxHeight;

GenerateSurface;

GenerateBackground;

end;

 

procedure Restart(const ABoxWidth,

ABoxHeight: Integer; const AIsAutoGeneratedSurface,

AIsRandomAngle: Boolean);

var

RandomAnglePart: Integer;

begin

BoxWidth:= ABoxWidth;

BoxHeight:= ABoxHeight;

if AIsAutoGeneratedSurface then

GenerateRandomSurfaceParams;

CalculateSurfaceMinY;

GenerateSurface;

BallVariable.X:= BoxWidth / 2;

BallVariable.Y:= BoxHeight * 3 / 4;

BallVariable.Speed:= 0;

with MovementParams do

begin

PreviousPoint:= Vector2R(BallVariable.X, BallVariable.Y);

ZeroPoint:= Vector2R(BallVariable.X, BallVariable.Y);

ZeroPointSpeed:= BallDefaultZeroSpeed;

TimeMoment:= 0;

if AIsRandomAngle then

begin

Randomize;

RandomAnglePart:= Random(11) - 5;

if InRange (RandomAnglePart, -1, 1) then

RandomAnglePart:= - 3;

Alpha:= pi / RandomAnglePart;

end;

end;

GenerateBackground;

Draw;

end;

 

procedure InitDrawing(

const AWindow: TWinControl);

begin

DrawingWindow:= AWindow;

end;

 

procedure Draw;

var

BufferBitmap: TBitmap;

DC: HDC;

begin

BufferBitmap:= TBitmap.Create;

try

BufferBitmap.Width:= BoxWidth;

BufferBitmap.Height:= BoxHeight;

if Assigned(Background) then

BitBlt(BufferBitmap.Canvas.Handle, 0, 0, BoxWidth, BoxHeight,

Background.Canvas.Handle, 0, 0, SRCCOPY);

with BufferBitmap.Canvas do

begin

Pen.Color:= clBlue;

Brush.Color:= clBlue;

Ellipse(Ball.InvertRect(GetBallRect));

end;

DC:= GetWindowDC(DrawingWindow.Handle);

try

BitBlt(DC, 0, 0, BoxWidth, BoxHeight,

BufferBitmap.Canvas.Handle, 0, 0, SRCCOPY);

finally

ReleaseDC(DrawingWindow.Handle, DC);

end;

finally

BufferBitmap.Free;

end;

end;

 

procedure FreeObjects;

begin

SetLength(Surface, 0);

FreeAndNil(Background);

end;

 

initialization

 

BallVariable.Radius:= 20.0;

BallDefaultZeroSpeed:= 0;

EnegryTransmissionMultiplier:= 1;

 

finalization

 

FreeObjects;

 

end.


, .

 


2

, 1, .

.

. .

.

function CheckContact: Integer;

var

Index: Integer;

MinSurfaceDistance: Double;

begin

Result:= 0;

with MovementParams do

begin

// .

if (GetBallRect.Left <= 0) and (BallVariable.X <= PreviousPoint.X) then

begin

Result:= 1;

CalculateAlpha(ctBoxLeft, 0);

end

else

if (GetBallRect.Right >= BoxWidth) and (BallVariable.X >= PreviousPoint.X) then

begin

Result:= 2;

CalculateAlpha(ctBoxRight, 0);

end

else

if (GetBallRect.Top >= BoxHeight) and (BallVariable.Y >= PreviousPoint.Y) then

begin

Result:= 3;

CalculateAlpha(ctBoxTop, 0);

end

else

if (GetBallRect.Bottom <= 0) and (BallVariable.Y <= PreviousPoint.Y) then

begin

Result:= 4;

CalculateAlpha(ctBoxBottom, 0)

end

else

begin

CalculateMinSurfaceDistance(Index, MinSurfaceDistance);

if (Index <> -1) and (MinSurfaceDistance <= BallVariable.Radius) and

(MinSurfaceDistance < DistBetweenPoints2R(Vector2R(Surface[Index].X,

Surface[Index].Y), PreviousPoint)) then

begin

Result:= 5;

CalculateAlpha(ctSurface, Index);

end;

end;

end;

end;

 

MovementParams, BallVariable, Surface.

3.1.

3.1 CheckContact,

5 , . , 1-2-3-12, 1-2-4-5-12, 1-2-4-6-7-12, 1-2-4-6-8-9-12, 1-2-4-6-8-10-11-12 1-2-4-6-8-10-12. 3.1 .

3.1.

1-2-3-12 BallVariable.Radius = 20; BallVariable.X = 20; PreviousPointX = 20  
1-2-4-5-12 BoxWidth = 600; BallVariable.Radius = 20; BallVariable.X = 581; PreviousPointX = 580  
1-2-4-6-7-12 BoxHeight = 480; BoxWidth = 600; BallVariable.Radius = 20; BallVariable.Y = 461; BallVariable.X = 300; PreviousPointY = 460; PreviousPointX = 300  
1-2-4-6-8-9-12 BoxHeight = 480; BoxWidth = 600; BallVariable.Radius = 20; BallVariable.Y = 20; BallVariable.X = 300; PreviousPointY = 21; PreviousPointX = 300  
1-2-4-6-8-10-11-12 BoxHeight = 480; BoxWidth = 600; BallVariable.Radius = 20; BallVariable.Y = 40; BallVariable.X = 300; PreviousPointY = 41; PreviousPointX = 300;Surface[0].X =300; Surface[0].Y =20;  
1-2-4-6-8-10-12 BoxHeight = 480; BoxWidth = 600; BallVariable.Radius = 20; BallVariable.Y = 40; BallVariable.X = 300; PreviousPointY = 20; PreviousPointX = 300;Surface[0].X =300; Surface[0].Y =20; Length(Surface) = 1;  

 

, , CheckContact, , . , CheckContact.

 

type

TTestSet = record

InputParams: TBallMovementParams;

InputBall: TBall;

SurfacePoint: TPoint;

ExpectedResult: Integer;

end;

 

const

TestData: array[0..5] of TTestSet = (

(InputParams: (PreviousPoint:(X: 20));

InputBall:(X: 20; Radius: 20); ExpectedResult: 1),

(InputParams: (PreviousPoint:(X: 580));

InputBall:(X: 581; Radius: 20); ExpectedResult: 2),

(InputParams: (PreviousPoint:(X: 300; Y:460));

InputBall:(X: 300; Y: 461; Radius: 20); ExpectedResult: 3),

(InputParams: (PreviousPoint:(X: 300; Y:21));

InputBall:(X: 300; Y: 20; Radius: 20); ExpectedResult: 4),

(InputParams: (PreviousPoint:(X: 300; Y:41));

InputBall:(X: 300; Y: 40; Radius: 20); SurfacePoint: (X: 300; Y: 20);

ExpectedResult: 5),

(InputParams: (PreviousPoint:(X: 300; Y:20));

InputBall:(X: 300; Y: 40; Radius: 20); SurfacePoint: (X: 300; Y: 20);

ExpectedResult: 0));

 

procedure CheckContactTest;

const

WINDOW_WIDTH = 600;

WINDOW_HEIGHT = 480;

LOG_NAME = 'CheckContactLog.txt';

RESULT_FORMAT = 'Result = %d and Expected result = %d => Test %s' + sLineBreak;

SUCCEED_RESULT = 'Succeed';

FAILED_RESULT = 'Failed';

var

I: Integer;

LogStream: TStringStream;

SaveStream: TFileStream;

CallResult: Integer;

begin

LogStream:= TStringStream.Create('');

try

Restart(WINDOW_WIDTH, WINDOW_HEIGHT, True, True);

for I:= 0 to Length(TestData) - 1 do

begin

MovementParams.PreviousPoint:= TestData[I].InputParams.PreviousPoint;

BallVariable.X:= TestData[I].InputBall.X;

BallVariable.Y:= TestData[I].InputBall.Y;

SetLength(Surface, 0);

SetLength(Surface, 1);

Surface[0]:= TestData[I].SurfacePoint;

CallResult:= CheckContact;

if CallResult = TestData[I].ExpectedResult then

LogStream.WriteString(Format(RESULT_FORMAT,

[CallResult, TestData[I].ExpectedResult, SUCCEED_RESULT]))

else

LogStream.WriteString(Format(RESULT_FORMAT,

[CallResult, TestData[I].ExpectedResult, FAILED_RESULT]));

end;

finally

SaveStream:= TFileStream.Create(LOG_NAME, fmCreate);

try

LogStream.Position:= 0;

SaveStream.CopyFrom(LogStream, LogStream.Size);

finally

SaveStream.Free;

end;

LogStream.Free;

end;

end;

 

.

Result = 1 and Expected result = 1 => Test Succeed

Result = 2 and Expected result = 2 => Test Succeed

Result = 3 and Expected result = 3 => Test Succeed

Result = 4 and Expected result = 4 => Test Succeed

Result = 5 and Expected result = 5 => Test Succeed

Result = 0 and Expected result = 0 => Test Succeed

 

CheckContact.

, , CheckContact.

 


3

, . - .

- . , .





:


: 2016-10-22; !; : 258 |


:

:

: , .
==> ...

2154 - | 1787 -


© 2015-2024 lektsii.org - -

: 0.507 .