particles simulation (gravity and collision) bug - simulation

1.The particles seems to have an excess y-direction movement, but i didn't add a background gravity for them.
2.The particles seems to move too fast when they're getting closer and closer, (because I don't know how to handle the issue of collision?)
I calculate the location by adding the corresponding force it experienced , how can i know if they collided with other? for example:
stage 1
particle1 [1,1]
particle2 [1,9]
stage 2
particle1 [9,9]
particle2 [1,9]
If I plot a graph of the path belonging to each particle, I can see if the graph of paths intercept with other, but the path intercept doesn't 100% means they'll collide, as they can have different speed.
I've tried to debug but just cannot find out where is going wrong.
in version 0 they tend to fail down (not my wish)
in version 1 they tend to fail to the right (i swap the x y) (simplified version)
here is the url of the bin and source (in pascal): stack_exchange_particle_gravity_collision.zip
here is the source code of version 0 in case you do not want to download the zip:
program ParticlesV0;
uses
graph;
const
pi=3.14159265358979;
n=500;
defaultSpeed=1;
defaultRadius=2;
defaultDensity=1e4;
energyLoss=0.50;
dotStyle=1;
backGroundLevel=0;
type
ParticleType=record
x,y,dr,dd,dx,dy,dfr,dfd:real;
color:word;
radius,mass:real;
end;
var
gd,gm:smallint;
PathToDriver:string;
l:longint;
particle:array[1..n]of ParticleType;
////////////////////////////////////////////////////////////////
procedure backGround(i:smallint);
var
y:smallint;
s,t:string;
w,ori:word;
begin
ori:=GetColor;
SetColor(10);
while i>0 do begin
for y:=0 to (GetMaxY div 10) do begin
s:='';
for w:=0 to 255 do begin
str(random(10),t);
s:=s+t;
end;
OutTextXY(5,y*10,s);
end;
dec(i);
end;
SetColor(ori);
end;
procedure line(x1,y1,x2,y2:smallint);
var
x,y:smallint;
begin
x:=getx;
y:=gety;
moveto(x1,y1);
lineto(x2,y2);
moveto(x,y);
end;
function rx(x:real):real;
begin
rx:=x+(GetMaxX div 2);
end;
function ry(y:real):real;
begin
ry:=y+(GetMaxY div 2);
end;
function s(r:real):smallint;
begin
s:=round(r);
end;
function distance(p1,p2:ParticleType):real;
var
x,y:real;
begin
x:=p1.x-p2.x;
y:=p1.y-p2.y;
distance:=sqrt(x*x+y*y);
end;
function degree(p1,p2:ParticleType):real;
var
x,y,d:real;
begin
x:=p2.x-p1.x;
y:=p2.y-p1.y;
if x0 then d:=arctan(y/x)
else if (yGetMaxX) then begin
dx:=-dx;
x:=GetMaxX-(x-GetMaxX);
end;
if (xGetMaxY) then begin
dy:=-dy;
y:=GetMaxY-(y-GetMaxY);
end;
if (y0) then begin
tfr:=G*p.mass*particle[l].mass/sqr(r);
tfd:=degree(p,particle[l]);
tdx:=tfr*cos(tfd);
tdy:=tfr*sin(tfd);
dx:=dx+tdx;
dy:=dy+tdy;
// tdx:=
end;
p.dx:=p.dx+dx;
p.dy:=p.dy+dy;
end;
end;
//++++++++++++++++++++++++++++++//
////////////////////////////////////////////////////////////////
begin
gd:=detect; { highest possible resolution }
gm:=0; { not needed, auto detection }
PathToDriver:=' '; { path to BGI fonts, drivers aren't needed }
InitGraph(gd,gm,PathToDriver);
if (GraphResult=grok) then begin
writeln('gd ',gd);
writeln('GetMaxX ',GetMaxX);
writeln('GetMaxY ',GetMaxY);
writeln('GetMaxColor ',GetMaxColor);
backGround(backGroundLevel);
line(0, 0, GetMaxX, GetMaxY);
SetFillStyle(HatchFill,13);
FillEllipse(s(rx(0)),s(ry(0)),10,10);
for l:=1 to n do initp(particle[l]);
repeat
for l:=1 to n do begin
calp(particle[l]);
movep(particle[l]);
end;
until false;
readln;
CloseGraph; { restores the old graphics mode }
end else writeln('Graphic not supported.');
readln;
end.
sorry for the poor formatting

If you want to remove a particle when it get too close, this line should do the job:
procedure calp(var p:ParticleType);
...
e:=*put a number here witch scales with mass or something esle, you can even use defaultradius constant*;
if (r>e) then begin
...
else mass:=0 <- this now means it won't pull others particles, and won't be pulled either, ideally now you need to check everywhere for 0-os, alternatively
you can place the particle randomly on the screen again, but it can cause some funny stuff, becouse of leftover vectors.

Related

Delphi - Indy close all the forms that related to client

I'm trying to close all the forms that related to client once he disconnected form the server
This action will be on the server side.
I have ( the known for me at run time ) partial unique caption for each client for example
Form caption 1:
ServiceA - ClientABC
Form caption 2:
ServiceB - ClientABC
What i already know is the - ClientABC part only.
So when the client ClientABC disconnected form my server i want to close all the related opened form in the server side.
procedure TIdServer.ClientRemove(const AContext: TIdContext);
var
sTitle: string;
function CloseChildForm(Wnd: HWND; Param: LPARAM): BOOL; stdcall;
begin
if Pos(sTitle, _GetWindowTitle(Wnd)) <> 0 then
PostMessage(Wnd, WM_CLOSE, 0, 0);
Result := True;
end;
begin
sTitle := TMyContext(AContext).Uniquename {ClientABC}
if Assigned(FListView) then begin
TThread.Queue(nil,
procedure
var
i: Integer;
begin
EnumWindows(#CloseChildForm, 0);
.......
end;
end
);
end;
end;
My problem is the string sTitle inside the CloseChildForm function always empty.
I call ClientRemove on the IdServerDisconnect procedure
procedure TIdServer.IdServerDisconnect(AContext: TIdContext);
begin
TMyContext(AContext).Queue.Clear;
........
ClientRemove(AContext);
end;
Can anyone tell me what wrong please ?
There are quite a few things wrong here:
You must not use a nested function as your callback. That is not allowed by the language and your code only compiles because the RTL declaration of EnumWindows uses an untyped pointer for the callback parameter.
Asynchronous execution with TThread.Queue means that the enclosing stack frame can be finished before the call to EnumWindows completes.
You are in danger of closing windows that do not belong in your process.
Were I faced with this problem I would solve it using Screen.Forms[]. Something like this:
for i := Screen.FormCount-1 downto 0 do
if CaptionMatches(Screen.Forms[i]) then
Screen.Forms[i].Close;
This is just an outline. I'm sure you can understand the concept. The key point is not to use EnumWindows and instead use the VCL's own mechanism to enumerate your forms.

ERROR at line 8: PL/SQL: Statement ignored

ERROR at line 8: PL/SQL: Statement ignored
CREATE OR REPLACE PROCEDURE POS(A IN NUMBER,M IN NUMBER,TOTAL OUT NUMBER)
AS
BEGIN
TOTAL:=0;
WHILE A>0 LOOP
M:=MOD(A,10);
TOTAL:=TOTAL+M;
A:=(A/10);//statement ignored error
END LOOP;
DBMS_OUTPUT.PUT_LINE(TOTAL);
END;
DECLARE
X NUMBER;
Y NUMBER:=5;
Z NUMBER;
BEGIN
POA(X,Y,Z);
END;
OK, I've had a look at your procedure and tried to resolve the issues you are having with it.
You haven't explained much (or indeed anything) about what you are trying to achieve which makes it really difficult to get you an answer.
People on here really want to help but you have to at least give us the tools with witch to provide that help.
Anyhow, with a host of assumptions, here is my version of your procedure with the following assumptions:
Your procedure is names POS (you name it POS in the procedure definition but then try to execute it as POA).
Your main issue was trying to assign a new value to input parameter "a" within the loop. As it is an input parameter it is immutable and you cannot assign new values to it. I have got round this by declaring a local variable "v_iter" and assigning that the value of "a" and then using it to control the loop.
I have added an "exception" section to handle any unexpected errors and output that error via DBMS_OUTPUT. You might want to make this more robust.
You do not test to check if the input parameter "a" is null or a valid number (i.e. not negative), you might want to do this to make your procedure more robust.
Here is the changed code:
CREATE OR REPLACE
PROCEDURE POS (
a IN NUMBER,
m IN NUMBER,
total OUT NUMBER
)
AS
— Declare variables
v_iter NUMBER := a;
BEGIN
— Initialise total
total := 0;
— Loop through “v_iter”
WHILE v_iter > 0
LOOP
m := MOD(v_iter,10);
total := total + m;
v_iter := (v_iter/10);
END LOOP;
DBMS_OUTPUT.put_line(total);
EXCEPTION
WHEN others
THEN
— Output and raise an error;
DBMS_OUTPUT.put_line(sqlerrm);
RAISE;
END POS;
/
To call it:
DECLARE
X NUMBER;
Y NUMBER:=5;
Z NUMBER;
BEGIN
POS(X,Y,Z);
END;
/
Hope it helps.

How do I check if numbers are repeating in pascal?

I want to make a program which I will check if here are any Armstron numbers (numbers which are equal to the cubes of it's figures, for example 153).
Which are also perfect numbers (numbers equal to the sum of it's divisors, not including itself, for example 28 (1+2+4+7+14))
below 1000. So I made a program to see if a number is Armstrong number and to see if it's perfect number.
program Armstrong;
var i,n,j,d,s,p:integer;
begin
for i:=1 to 1000 do
begin
j:=i mod 10;
d:=i div 10 mod 10;
s:=i div 100;
n:=j*j*j+d*d*d+s*s*s;
if n=i then
writeln(i);
end;
end.
And for perfect numbers it's
program Perfect;
var n,s,i:integer;
begin
for n:=1 to 1000 do
begin
s:=0;
for i:=1 to n do
begin
if n mod i = 0 then
s:=s+i;
end;
if s=n then
writeln(n);
end;
end.
So I don't know how to merge them and see if any number I get from the first program appears in the second as well.
I did Pascal long time back. So assume I have used pseudo code for this answer.
Remove your loop from Armstrong and put the code in this function.
function Armstrong(i: integer): integer;
(* code goes here. And return 0 or 1 based on Armstrong *)
Remove your loop from Perfect, and put this code in this function
function Perfect(i: integer): integer;
(* code goes here. And return 0 or 1 based on Perfect *)
Then call it from a loop like this way:
for i:=1 to 1000 do
x = Armstrong(i);
y = Perfect(i);
if(x == 1 and y == 1) then
(* do something *)
end;

How can we define a 3-dimensional array of geometry?

I want to write a code for postgis in pgAdmin that is based on postgresql. It defines a 3-dimensional array of geometry.
I used this code for it:
DECLARE
G geometry[9][9][9];
BEGIN
for i IN 1..9 LOOP
for j IN 1..9 LOOP
for k IN 1..9 LOOP
G[i][j][k] := [value that I want];
END LOOP;
END LOOP;
END LOOP;
But it returned this error:
"array subscript out of range"
I used this instead:
DECLARE
G geometry[9][9][9];
BEGIN
for i IN array_lower(G, 1)..array_upper(G, 1) LOOP
for j IN array_lower(G, 1)..array_upper(G, 1) LOOP
for k IN array_lower(G, 1)..array_upper(G, 1) LOOP
G[i][j][k] := [value that I want];
END LOOP;
END LOOP;
END LOOP;
I have a different error this time:
"lower bound of FOR loop cannot be null"
I used this in BEGIN Part and solved all the errors:
G[1][1][1] := '01010000200400000000000000000000000000000000000000';
But I think this is not true and doesn't calculate all of the iterations for loops. I think this takes in account only the G[1][1][1]. What should I do now?
In PostgreSQL, simply declaring the array dimensions does not initialize or pre-allocate anything. The array is dynamic in all its dimensions. That differs significantly from the multi-dimensional array implementations found in general programming language like C.
To mimic the logic of these languages, you may first initialize the 9x9x9 array with a statement like this:
G:=array_fill('point(0 0)'::geometry, array[9,9,9]);
Then the rest of the code will just work when refering to G[i][j][k] either as source or destination of assignments.

How can I do This effect?

I'm Trying to do, in delphi, that when you press a button, I display a drop-down panel with options like this:
Does anyone know how to make this effect with VCL?
Now I have a form with 2 panels, the main is always showing and has a side button, and when I press the button the side panel is shown, but I would like to make the effect.
Thank you
I dont know your application in detail, with the transparency and other things. However, I think you will have to animate your panels/windows in some sort of loop on your own. I dont know of any VCL function for that.
Here is an example which animates a Window (its quick and dirty though):
Code:
procedure TForm1.Button1Click(Sender: TObject);
var
I, X: Integer;
begin
Form2.Width := 1;
Form2.Height := Form1.Height;
Form2.Left := Form1.Left + Form1.Width;
Form2.Top := Form1.Top;
Form2.Show;
Timer1.Enabled := true;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
if I < 500 then
begin
I := I + 1;
Form2.Width := I;
end
else
begin
Timer1.Enabled := false;
end;
end;
Not perfect, but hopefully good enough to give you an idea.
Andy
you can use TJvRollOut from Jedi JVCL.
It acts like a panel which colapse and expand. Also you can take a look at Delphi: sliding (animated) panel and
Hide, Slide And Fade Away Controls On A Delphi Form
Finally, I managed to make the effect. I put a panel and I have added a picture. then I used animatedwindows in buton click process.
procedure TFTelefonoSIP.Button1Click(Sender: TObject);
begin
if GDPanelLlamadasHidden = False then
begin
AnimateWindow(Panel1.Handle, 200, AW_SLIDE or AW_HOR_POSITIVE or AW_HIDE);
GDPanelLlamadasHidden := True;
end
else
begin
AnimateWindow(Panel1.Handle, 200, AW_SLIDE or AW_HOR_NEGATIVE or AW_ACTIVATE);
GDPanelLlamadasHidden := False;
end;
end;
But the effect is not quite what I wanted, sometimes the image shows a flash, not very aesthetic.
you should enable the "Double Buffered" property at the application form's... this should prevent the flashing..