|
|
ec1092 |
unit Unit1;
|
|
|
ec1092 |
|
|
|
ec1092 |
{$mode objfpc}{$H+}
|
|
|
ec1092 |
|
|
|
ec1092 |
interface
|
|
|
ec1092 |
|
|
|
ec1092 |
uses
|
|
|
ec1092 |
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
|
|
|
ec1092 |
ExtCtrls, Math;
|
|
|
ec1092 |
|
|
|
ec1092 |
type
|
|
|
ec1092 |
|
|
|
ec1092 |
{ TForm1 }
|
|
|
ec1092 |
|
|
|
ec1092 |
TForm1 = class(TForm)
|
|
|
ec1092 |
Label1: TLabel;
|
|
|
ec1092 |
Label2: TLabel;
|
|
|
ec1092 |
Timer1: TTimer;
|
|
|
ec1092 |
procedure FormCreate(Sender: TObject);
|
|
|
ec1092 |
procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
|
|
|
ec1092 |
procedure FormPaint(Sender: TObject);
|
|
|
ec1092 |
procedure Timer1Timer(Sender: TObject);
|
|
|
ec1092 |
private
|
|
|
ec1092 |
{ private declarations }
|
|
|
ec1092 |
public
|
|
|
ec1092 |
{ public declarations }
|
|
|
ec1092 |
end;
|
|
|
ec1092 |
|
|
|
ec1092 |
const
|
|
|
ec1092 |
ballR = 20;
|
|
|
ec1092 |
pointR = 5;
|
|
|
ec1092 |
|
|
|
ec1092 |
var
|
|
|
ec1092 |
Form1: TForm1;
|
|
|
ec1092 |
points: array of TPoint;
|
|
|
ec1092 |
count: integer;
|
|
|
ec1092 |
ball: TPoint;
|
|
|
ec1092 |
maxLen: single = 200;
|
|
|
ec1092 |
len: single;
|
|
|
ec1092 |
|
|
|
ec1092 |
lenLabel, maxlenLabel: integer;
|
|
|
ec1092 |
|
|
|
ec1092 |
implementation
|
|
|
ec1092 |
|
|
|
ec1092 |
{$R *.lfm}
|
|
|
ec1092 |
|
|
|
ec1092 |
function getLen: single;
|
|
|
ec1092 |
var
|
|
|
ec1092 |
i: integer;
|
|
|
ec1092 |
begin
|
|
|
ec1092 |
Result := 0;
|
|
|
ec1092 |
for i:=1 to count-1 do
|
|
|
ec1092 |
Result := Result + sqrt(sqr(points[i].x-points[i-1].x) + sqr(points[i].y-points[i-1].y));
|
|
|
ec1092 |
len := Result;
|
|
|
ec1092 |
end;
|
|
|
ec1092 |
|
|
|
ec1092 |
function IntersectsCircles(p1, p2: TPoint; r1, r2: single): boolean;
|
|
|
ec1092 |
begin
|
|
|
ec1092 |
Result := sqr(p1.x-p2.x) + sqr(p1.Y-p2.y) < sqr(r1+r2);
|
|
|
ec1092 |
end;
|
|
|
ec1092 |
|
|
|
ec1092 |
function IntersectsLines(a1, a2, b1, b2: TPoint): boolean;
|
|
|
ec1092 |
var
|
|
|
ec1092 |
x1, y1, x2, y2, r, d2, d1: single;
|
|
|
ec1092 |
begin
|
|
|
ec1092 |
Result := false;
|
|
|
ec1092 |
|
|
|
ec1092 |
r := sqr(a2.x-a1.x) + sqr(a2.y-a1.y);
|
|
|
ec1092 |
if r = 0 then exit;
|
|
|
ec1092 |
x1 := ((a2.x-a1.x)*(b1.x-a1.x) + (a2.y-a1.y)*(b1.y-a1.y))/r;
|
|
|
ec1092 |
y1 := ((a1.y-a2.y)*(b1.x-a1.x) + (a2.x-a1.x)*(b1.y-a1.y))/r;
|
|
|
ec1092 |
x2 := ((a2.x-a1.x)*(b2.x-a1.x) + (a2.y-a1.y)*(b2.y-a1.y))/r;
|
|
|
ec1092 |
y2 := ((a1.y-a2.y)*(b2.x-a1.x) + (a2.x-a1.x)*(b2.y-a1.y))/r;
|
|
|
ec1092 |
|
|
|
ec1092 |
if y1 = y2 then exit;
|
|
|
ec1092 |
|
|
|
ec1092 |
d2 := y1/(y1-y2);
|
|
|
ec1092 |
if (d2 <= 0) or (d2 > 1) then exit;
|
|
|
ec1092 |
d1 := d2*(x2-x1) + x1;
|
|
|
ec1092 |
if (d1 <= 0) or (d1 > 1) then exit;
|
|
|
ec1092 |
Result := true;
|
|
|
ec1092 |
end;
|
|
|
ec1092 |
|
|
|
ec1092 |
procedure GenerateBall;
|
|
|
ec1092 |
var
|
|
|
ec1092 |
i: integer;
|
|
|
ec1092 |
retry: boolean;
|
|
|
ec1092 |
begin
|
|
|
ec1092 |
retry := true;
|
|
|
ec1092 |
while retry do begin
|
|
|
ec1092 |
ball.x := RandomRange(ballR, Form1.ClientWidth-ballR);
|
|
|
ec1092 |
ball.y := RandomRange(ballR, Form1.ClientHeight-ballR);
|
|
|
ec1092 |
retry := false;
|
|
|
ec1092 |
for i := 0 to count - 1 do
|
|
|
ec1092 |
if IntersectsCircles(ball, points[i], ballR, pointR) then
|
|
|
ec1092 |
retry := true;
|
|
|
ec1092 |
end;
|
|
|
ec1092 |
end;
|
|
|
ec1092 |
|
|
|
ec1092 |
procedure RemovePoints(cnt: integer);
|
|
|
ec1092 |
var
|
|
|
ec1092 |
i: integer;
|
|
|
ec1092 |
begin
|
|
|
ec1092 |
with Form1 do begin
|
|
|
ec1092 |
Canvas.Pen.Color := Color;
|
|
|
ec1092 |
Canvas.Pen.Width := 2*pointR;
|
|
|
ec1092 |
Canvas.MoveTo(points[0].x, points[0].y);
|
|
|
ec1092 |
for i := 0 to min(cnt, count-1) do Canvas.LineTo(points[i].x, points[i].y);
|
|
|
ec1092 |
for i := cnt to count-1 do points[i-cnt] := points[i];
|
|
|
ec1092 |
count := count - cnt;
|
|
|
ec1092 |
setLength(points, count);
|
|
|
ec1092 |
FormPaint(nil);
|
|
|
ec1092 |
end;
|
|
|
ec1092 |
end;
|
|
|
ec1092 |
|
|
|
ec1092 |
procedure AddPoint(p: TPoint);
|
|
|
ec1092 |
var
|
|
|
ec1092 |
i: integer;
|
|
|
ec1092 |
len: single;
|
|
|
ec1092 |
begin
|
|
|
ec1092 |
if count > 0 then begin
|
|
|
ec1092 |
len := sqrt(sqr(points[count-1].x-p.x) + sqr(points[count-1].y-p.y));
|
|
|
ec1092 |
if len < pointR then exit;
|
|
|
ec1092 |
end;
|
|
|
ec1092 |
|
|
|
ec1092 |
while getLen > maxLen do RemovePoints(1);
|
|
|
ec1092 |
|
|
|
ec1092 |
count := count + 1;
|
|
|
ec1092 |
setLength(points, count);
|
|
|
ec1092 |
points[count-1] := p;
|
|
|
ec1092 |
|
|
|
ec1092 |
for i := count-10 downto 1 do begin
|
|
|
ec1092 |
if IntersectsLines(points[count-1], points[count-2], points[i], points[i-1]) then begin
|
|
|
ec1092 |
RemovePoints(i);
|
|
|
ec1092 |
maxLen := getLen;
|
|
|
ec1092 |
break;
|
|
|
ec1092 |
end;
|
|
|
ec1092 |
end;
|
|
|
ec1092 |
|
|
|
ec1092 |
if IntersectsCircles(p, ball, pointR, ballR) then begin
|
|
|
ec1092 |
GenerateBall;
|
|
|
ec1092 |
maxLen := maxLen + 2*ballR;
|
|
|
ec1092 |
end;
|
|
|
ec1092 |
|
|
|
ec1092 |
Form1.Refresh();
|
|
|
ec1092 |
end;
|
|
|
ec1092 |
|
|
|
ec1092 |
procedure TForm1.FormCreate(Sender: TObject);
|
|
|
ec1092 |
begin
|
|
|
ec1092 |
Randomize;
|
|
|
ec1092 |
GenerateBall;
|
|
|
ec1092 |
end;
|
|
|
ec1092 |
|
|
|
ec1092 |
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
|
|
|
ec1092 |
Y: Integer);
|
|
|
ec1092 |
begin
|
|
|
ec1092 |
AddPoint(Point(x, y));
|
|
|
ec1092 |
end;
|
|
|
ec1092 |
|
|
|
ec1092 |
procedure TForm1.FormPaint(Sender: TObject);
|
|
|
ec1092 |
begin
|
|
|
ec1092 |
Canvas.Pen.Color := clBlack;
|
|
|
ec1092 |
Canvas.Pen.Width := 2*pointR;
|
|
|
ec1092 |
Canvas.Polyline(points);
|
|
|
ec1092 |
|
|
|
ec1092 |
Canvas.Pen.Color := clBlue;
|
|
|
ec1092 |
Canvas.Pen.Width := 2*ballR;
|
|
|
ec1092 |
Canvas.MoveTo(round(ball.x), round(ball.y));
|
|
|
ec1092 |
Canvas.LineTo(round(ball.x), round(ball.y));
|
|
|
ec1092 |
end;
|
|
|
ec1092 |
|
|
|
ec1092 |
procedure TForm1.Timer1Timer(Sender: TObject);
|
|
|
ec1092 |
begin
|
|
|
ec1092 |
if round(len) <> lenLabel then begin
|
|
|
ec1092 |
lenLabel := round(len);
|
|
|
ec1092 |
Label1.Caption := 'length ' + IntToStr(lenLabel);
|
|
|
ec1092 |
Label2.Caption := 'max length ' + IntToStr(maxlenLabel);
|
|
|
ec1092 |
end;
|
|
|
ec1092 |
if round(len) > maxlenLabel then begin
|
|
|
ec1092 |
maxlenLabel := round(len);
|
|
|
ec1092 |
Label2.Caption := 'max length ' + IntToStr(maxlenLabel);
|
|
|
ec1092 |
end;
|
|
|
ec1092 |
end;
|
|
|
ec1092 |
|
|
|
ec1092 |
end.
|
|
|
ec1092 |
|