| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 |
- {$N+}
- Uses Graph,CRT;
- type
- float = double;
- tVec = record
- x,y,z : float;
- end;
- const
- ZeroVec : tVec = (X:0.0;Y:0.0;Z:0.0);
- MaxSpr = 250;
- Distance_Thresh = 1e-5;
- CurID : word = 1;
- type
- tID = 1..MaxSpr;
- pDistArr = ^tDistArr;
- tDistArr = array [1..10] of float;
- pSpring = ^tSpring;
- pSprArr = ^tSprArr;
- tSpring = record
- ID : tID;
- Already : array [1..MaxSpr] of boolean;
- pos,vel,Force : tVec;
- mass : float;
- dists : pDistArr;
- Ks : pDistArr;
- neibs : pSprArr;
- neib_count : word;
- end;
- tSprArr = array [1..10] of pSpring;
- pAnchor = ^tAnchor;
- tAnchor = record
- pos : tVec;
- Node : pSpring;
- end;
- tAnchArr = array [1..10] of pAnchor;
- pAnchArr = ^tAnchArr;
- pModel = ^tModel;
- tModel = record
- Springs : pSprArr;
- SprNum : tID;
- Anchors : pAnchArr;
- AnchNum : tID;
- Glob_Force : tVec;
- Gravity : tVec;
- Pos : tVec;
- energy_loss : float;
- end;
- {----------------------------------------}
- Procedure VecAdd(var aC:tVec;aA,aB:tVec);
- begin
- aC.x := aA.x + aB.x;
- aC.y := aA.y + aB.y;
- aC.z := aA.z + aB.z;
- end;{VecAdd}
- {-------------------------------}
- Procedure VecSub(var aC:tVec;aA,aB:tVec);
- begin
- aC.x := aA.x - aB.x;
- aC.y := aA.y - aB.y;
- aC.z := aA.z - aB.z;
- end;{VecAdd}
- {-------------------------------}
- Procedure VecNeg(var aV:tVec);
- begin
- aV.X := -aV.x;
- aV.y := -aV.y;
- aV.z := -aV.z;
- end;{NegVec}
- {-------------------------------}
- Procedure VecMul(var aV:tVec;aC:float);
- begin
- aV.x := aV.x * aC;
- aV.y := aV.y * aC;
- aV.z := aV.z * aC;
- end;{MulScal}
- {-------------------------------}
- Function NewSpring(ax,ay,az:float;aNeib_count:word):pSpring;
- var
- mNew : pSpring;
- begin
- New(mNew);
- with mNew^ do begin
- ID := CurID;Inc(CurID);
- Pos.x := ax;
- Pos.y := ay;
- Pos.z := aZ;
- Vel := ZeroVec; Force := ZeroVec;
- neib_Count := aNeib_Count;
- GetMem(neibs,neib_Count*SizeOf(pSpring));
- GetMem(dists,neib_Count*SizeOf(float));
- GetMem(ks,neib_Count*SizeOf(float));
- FillChar(neibs^,neib_Count*SizeOf(pSpring),0);
- FillChar(dists^,neib_Count*SizeOf(float),0);
- FillChar(ks^,neib_Count*SizeOf(float),0);
- end;
- NewSpring := mNew;
- end;{NewSpring}
- {----------------------------------------}
- Procedure DelSpring(var aSpr:pSpring);
- begin
- if aSpr = nil then exit;
- FreeMem(aSpr^.Dists,aSpr^.neib_count*sizeof(float));
- FreeMem(aSpr^.Ks,aSpr^.neib_count*sizeof(float));
- FreeMem(aSpr^.neibs,aSpr^.neib_count*sizeof(pSpring));
- Dispose(aSpr);
- aSpr := nil;
- end;{DelSpring}
- {----------------------------------------}
- Procedure CalcSingleSpring(aA:pSpring);
- var
- mDist : float;
- mB : pSpring;
- mForce: tVec;
- i : word;
- begin
- for i := 1 to aA^.neib_count do
- begin
- mB := aA^.neibs^[i]; {Get cur neigbour}
- if aA^.Already[mB^.ID] then continue; {If we calculated force, in B's loop
- so do next :) }
- aA^.Already[mB^.ID] := true; {Just for US}
- VecSub(mForce,mB^.pos,aA^.pos); {Calculate delta vector}
- with mForce do mDist := sqrt(x*x+y*y+z*z); {Calc distance}
- if mDist < Distance_Thresh then {Why so close ?}
- mForce := ZeroVec {This is'n true, but don't creates errornous effects}
- else
- begin
- VecMul(mForce,1/mDist); {Normalize force}
- mDist := mDist - aA^.dists^[i]; {Calc dX in F=k*dX}
- VecMul(mForce,mDist*aA^.kS^[i]); {Calc force}
- end;
- VecAdd(aA^.Force,aA^.Force,mForce); {Add our force}
- mB^.Already[aA^.ID] := true; {So we calc-ed 2 forces}
- VecNeg(mForce); {differs by sign}
- VecAdd(mB^.Force,mB^.Force,mForce); {so add it too}
- end;
- end;{CalcSingleSpring}
- {-----------------------------------}
- Procedure ModelCalcForces(aM:pModel);
- var
- i : tID;
- begin
- for i := 1 to aM^.SprNum do
- begin
- aM^.Springs^[i]^.Force := ZeroVec;
- FillChar(aM^.Springs^[i]^.Already,MaxSpr*SizeOf(Boolean),0);
- end;
- for i := 1 to aM^.SprNum do CalcSingleSpring(aM^.Springs^[i]);
- end;{ModelCalcForces}
- {----------------------------------}
- Procedure ModelApplyForces(aM:pModel;aTime:float);
- var
- mAccel : tVec;
- mC : pSpring;
- dX : tVec;
- i : tID;
- begin
- for i := 1 to aM^.SprNum do
- begin
- mC := aM^.Springs^[i];
- mAccel := mC^.Force; {So our new acceleration is formed from force}
- VecMul(mAccel,1/mC^.Mass); {dividing by mass}
- VecAdd(mAccel,mAccel,aM^.Gravity); {Add the 'g'}
- VecMul(mAccel,aTime); {For modeling time}
- VecAdd(mC^.Vel,mC^.Vel,mAccel);
- dX := mC^.Vel; {delta X is Speed}
- VecMul(dx,aTime); {multiplyed by time}
- VecAdd(mC^.Pos,mC^.Pos,dx); {That's all with pos folks}
- if mC^.Pos.X < 0 then
- begin
- mC^.Vel.X := -mC^.Vel.X;
- mC^.Pos.X := 1;
- end;
- if mC^.Pos.Y < 0 then begin
- mC^.Vel.Y := -mC^.Vel.Y;
- mC^.Pos.Y := 1;
- end;
- if mC^.Pos.X > 638 then
- begin
- mC^.Vel.X := -mC^.Vel.X;
- mC^.Pos.X := 637;
- end;
- if mC^.Pos.Y > 478 then
- begin
- mC^.Vel.Y := -mC^.Vel.Y;
- mC^.Pos.Y := 477;
- end;
- VecMul(mC^.Vel,aM^.Energy_Loss); {Loss some speed in time}
- end;
- end;{ModelApplyForces}
- {----------------------------------}
- Procedure ModelCheckAnchors(aM:pModel);
- var
- i : tID;
- begin
- for i := 1 to aM^.AnchNum do
- aM^.Anchors^[i]^.Node^.Pos := aM^.Anchors^[i]^.Pos;
- end;{ModelCheckAnchors}
- {----------------------------------}
- Procedure RenderStringSpring(aM:pModel);
- var
- i : tID;
- gx,gy : float;
- Procedure LineCross(aV:tVec);
- begin
- Line(round(aV.x+gx)-3,
- round(aV.y+gy),
- round(aV.x+gx)+3,
- round(aV.y+gy));
- Line(round(aV.x+gx),
- round(aV.y+gy)-3,
- round(aV.x+gx),
- round(aV.y+gy)+3);
- end;
- begin
- gx := aM^.Pos.X;
- gy := aM^.Pos.Y;
- for i := 1 to aM^.SprNum-1 do
- begin
- SetColor(Green);
- Line(round(gx+aM^.Springs^[i]^.pos.x),
- round(gy+aM^.Springs^[i]^.pos.y),
- round(gx+aM^.Springs^[i+1]^.pos.x),
- round(gy+aM^.Springs^[i+1]^.pos.y));
- SetColor(Red);
- LineCross(aM^.Springs^[i]^.pos);
- end;
- LineCross(aM^.Springs^[i+1]^.Pos);
- end;{RenderStringSpring}
- {----------------------------------}
- Function InitMouse:boolean;assembler;
- asm
- mov ax, 00
- int 33h
- cmp ax, 0ffffh
- jnz @@1
- mov ax, 7
- mov cx, 0
- mov dx, 639
- int 33h
- mov ax, 08
- mov cx, 0
- mov dx, 479
- int 33h
- mov ax, 1
- @@1:
- ret
- end;{InitMouse}
- Procedure MoveMouse(x,y:word);assembler;
- asm
- mov cx, x
- mov dx, y
- mov ax, 4
- int 33h
- end;{ModeMouse}
- Procedure MousePosition(var x,y:word);assembler;
- asm
- mov ax, 3
- int 33h
- les di, x
- mov es:[di], cx
- les di, y
- mov es:[di], dx
- end;{MousePosition}
- Procedure HideMouse;assembler;
- asm
- mov ax, 2
- int 33h
- end;
- {-------------------------}
- var
- mString : pModel;
- i : tID;
- mx,my : word;
- j : longint;
- gD,gM : integer;
- SizeX : float;
- BEGIN
- New(mString);
- with mString^ do begin
- SprNum := 15;
- AnchNum := 1;
- SizeX := 600;
- GetMem(Springs,SprNum*SizeOf(pSpring));
- GetMem(Anchors,AnchNum*SizeOf(pAnchor));
- Springs^[1] := NewSpring(0,0,0,1);
- Springs^[SprNum] := NewSpring(SizeX*0.9,0,0,1);
- for i := 1 to SprNum-2 do
- Springs^[i+1] := NewSpring(i*SizeX/SprNum,0,0,2);
- Springs^[1]^.Neibs^[1] := Springs^[2];
- Springs^[1]^.Dists^[1] := SizeX/SprNum;
- Springs^[1]^.Mass := 1;
- Springs^[1]^.Ks^[1] := 0.25;
- Springs^[SprNum]^.Neibs^[1] := Springs^[SprNum-1];
- Springs^[SprNum]^.Dists^[1] := 0.5*SizeX/SprNum;
- Springs^[SprNum]^.Mass := 1;
- Springs^[SprNum]^.Ks^[1] := 0.25;
- for i := 2 to SprNum-1 do begin
- Springs^[i]^.Neibs^[1] := Springs^[i-1];
- Springs^[i]^.Neibs^[2] := Springs^[i+1];
- Springs^[i]^.Dists^[1] := 0.5*SizeX/SprNum;
- Springs^[i]^.Dists^[2] := 0.5*SizeX/SprNum;
- Springs^[i]^.Ks^[1] := 0.08;
- Springs^[i]^.Ks^[2] := 0.08;
- Springs^[i]^.Mass := 1;
- end;
- New(Anchors^[1]);
- Anchors^[1]^.Node := Springs^[1];
- Anchors^[1]^.Pos := ZeroVec;
- {
- New(Anchors^[2]);
- Anchors^[2]^.Node := Springs^[SprNum];
- Anchors^[2]^.Pos.X := 600;
- Anchors^[2]^.Pos.Y := 100;
- Anchors^[2]^.Pos.Z := 0;
- }
- Pos.x := 0;
- pos.y := 0;
- pos.z := 0;
- Gravity := ZeroVec;
- Gravity.Y := 0.09;
- Energy_Loss := 0.98;
- gD:=Detect;
- InitGraph(gD,gM,'');
- InitMouse;
- MoveMouse(10,5);
- while not keypressed do
- begin
- MousePosition(mx,my);
- Anchors^[1]^.pos.x := mx;
- Anchors^[1]^.pos.y := my;
- ModelCalcForces(mString);
- ModelApplyForces(mString,1);
- ModelCheckAnchors(mString);
- repeat until (Port[$03DA] and 8) <> 8;
- repeat until (Port[$03DA] and 8) = 8;
- ClearDevice;
- RenderStringSpring(mString);
- end;
- Dispose(Anchors^[1]);
- For i := 1 To SprNum Do DelSpring(Springs^[i]);
- FreeMem(Springs, SprNum*SizeOf(pSpring));
- FreeMem(Anchors,AnchNum*SizeOf(pAnchor));
- CloseGraph;
- end;
- END.
|