SPRING.BAK 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. {$N+}
  2. Uses Graph,CRT;
  3. type
  4. float = double;
  5. tVec = record
  6. x,y,z : float;
  7. end;
  8. const
  9. ZeroVec : tVec = (X:0.0;Y:0.0;Z:0.0);
  10. MaxSpr = 250;
  11. Distance_Thresh = 1e-5;
  12. CurID : word = 1;
  13. type
  14. tID = 1..MaxSpr;
  15. pDistArr = ^tDistArr;
  16. tDistArr = array [1..10] of float;
  17. pSpring = ^tSpring;
  18. pSprArr = ^tSprArr;
  19. tSpring = record
  20. ID : tID;
  21. Already : array [1..MaxSpr] of boolean;
  22. pos,vel,Force : tVec;
  23. mass : float;
  24. dists : pDistArr;
  25. Ks : pDistArr;
  26. neibs : pSprArr;
  27. neib_count : word;
  28. end;
  29. tSprArr = array [1..10] of pSpring;
  30. pAnchor = ^tAnchor;
  31. tAnchor = record
  32. pos : tVec;
  33. Node : pSpring;
  34. end;
  35. tAnchArr = array [1..10] of pAnchor;
  36. pAnchArr = ^tAnchArr;
  37. pModel = ^tModel;
  38. tModel = record
  39. Springs : pSprArr;
  40. SprNum : tID;
  41. Anchors : pAnchArr;
  42. AnchNum : tID;
  43. Glob_Force : tVec;
  44. Gravity : tVec;
  45. Pos : tVec;
  46. energy_loss : float;
  47. end;
  48. {----------------------------------------}
  49. Procedure VecAdd(var aC:tVec;aA,aB:tVec);
  50. begin
  51. aC.x := aA.x + aB.x;
  52. aC.y := aA.y + aB.y;
  53. aC.z := aA.z + aB.z;
  54. end;{VecAdd}
  55. {-------------------------------}
  56. Procedure VecSub(var aC:tVec;aA,aB:tVec);
  57. begin
  58. aC.x := aA.x - aB.x;
  59. aC.y := aA.y - aB.y;
  60. aC.z := aA.z - aB.z;
  61. end;{VecAdd}
  62. {-------------------------------}
  63. Procedure VecNeg(var aV:tVec);
  64. begin
  65. aV.X := -aV.x;
  66. aV.y := -aV.y;
  67. aV.z := -aV.z;
  68. end;{NegVec}
  69. {-------------------------------}
  70. Procedure VecMul(var aV:tVec;aC:float);
  71. begin
  72. aV.x := aV.x * aC;
  73. aV.y := aV.y * aC;
  74. aV.z := aV.z * aC;
  75. end;{MulScal}
  76. {-------------------------------}
  77. Function NewSpring(ax,ay,az:float;aNeib_count:word):pSpring;
  78. var
  79. mNew : pSpring;
  80. begin
  81. New(mNew);
  82. with mNew^ do begin
  83. ID := CurID;Inc(CurID);
  84. Pos.x := ax;
  85. Pos.y := ay;
  86. Pos.z := aZ;
  87. Vel := ZeroVec; Force := ZeroVec;
  88. neib_Count := aNeib_Count;
  89. GetMem(neibs,neib_Count*SizeOf(pSpring));
  90. GetMem(dists,neib_Count*SizeOf(float));
  91. GetMem(ks,neib_Count*SizeOf(float));
  92. FillChar(neibs^,neib_Count*SizeOf(pSpring),0);
  93. FillChar(dists^,neib_Count*SizeOf(float),0);
  94. FillChar(ks^,neib_Count*SizeOf(float),0);
  95. end;
  96. NewSpring := mNew;
  97. end;{NewSpring}
  98. {----------------------------------------}
  99. Procedure DelSpring(var aSpr:pSpring);
  100. begin
  101. if aSpr = nil then exit;
  102. FreeMem(aSpr^.Dists,aSpr^.neib_count*sizeof(float));
  103. FreeMem(aSpr^.Ks,aSpr^.neib_count*sizeof(float));
  104. FreeMem(aSpr^.neibs,aSpr^.neib_count*sizeof(pSpring));
  105. Dispose(aSpr);
  106. aSpr := nil;
  107. end;{DelSpring}
  108. {----------------------------------------}
  109. Procedure CalcSingleSpring(aA:pSpring);
  110. var
  111. mDist : float;
  112. mB : pSpring;
  113. mForce: tVec;
  114. i : word;
  115. begin
  116. for i := 1 to aA^.neib_count do
  117. begin
  118. mB := aA^.neibs^[i]; {Get cur neigbour}
  119. if aA^.Already[mB^.ID] then continue; {If we calculated force, in B's loop
  120. so do next :) }
  121. aA^.Already[mB^.ID] := true; {Just for US}
  122. VecSub(mForce,mB^.pos,aA^.pos); {Calculate delta vector}
  123. with mForce do mDist := sqrt(x*x+y*y+z*z); {Calc distance}
  124. if mDist < Distance_Thresh then {Why so close ?}
  125. mForce := ZeroVec {This is'n true, but don't creates errornous effects}
  126. else
  127. begin
  128. VecMul(mForce,1/mDist); {Normalize force}
  129. mDist := mDist - aA^.dists^[i]; {Calc dX in F=k*dX}
  130. VecMul(mForce,mDist*aA^.kS^[i]); {Calc force}
  131. end;
  132. VecAdd(aA^.Force,aA^.Force,mForce); {Add our force}
  133. mB^.Already[aA^.ID] := true; {So we calc-ed 2 forces}
  134. VecNeg(mForce); {differs by sign}
  135. VecAdd(mB^.Force,mB^.Force,mForce); {so add it too}
  136. end;
  137. end;{CalcSingleSpring}
  138. {-----------------------------------}
  139. Procedure ModelCalcForces(aM:pModel);
  140. var
  141. i : tID;
  142. begin
  143. for i := 1 to aM^.SprNum do
  144. begin
  145. aM^.Springs^[i]^.Force := ZeroVec;
  146. FillChar(aM^.Springs^[i]^.Already,MaxSpr*SizeOf(Boolean),0);
  147. end;
  148. for i := 1 to aM^.SprNum do CalcSingleSpring(aM^.Springs^[i]);
  149. end;{ModelCalcForces}
  150. {----------------------------------}
  151. Procedure ModelApplyForces(aM:pModel;aTime:float);
  152. var
  153. mAccel : tVec;
  154. mC : pSpring;
  155. dX : tVec;
  156. i : tID;
  157. begin
  158. for i := 1 to aM^.SprNum do
  159. begin
  160. mC := aM^.Springs^[i];
  161. mAccel := mC^.Force; {So our new acceleration is formed from force}
  162. VecMul(mAccel,1/mC^.Mass); {dividing by mass}
  163. VecAdd(mAccel,mAccel,aM^.Gravity); {Add the 'g'}
  164. VecMul(mAccel,aTime); {For modeling time}
  165. VecAdd(mC^.Vel,mC^.Vel,mAccel);
  166. dX := mC^.Vel; {delta X is Speed}
  167. VecMul(dx,aTime); {multiplyed by time}
  168. VecAdd(mC^.Pos,mC^.Pos,dx); {That's all with pos folks}
  169. if mC^.Pos.X < 0 then
  170. begin
  171. mC^.Vel.X := -mC^.Vel.X;
  172. mC^.Pos.X := 1;
  173. end;
  174. if mC^.Pos.Y < 0 then begin
  175. mC^.Vel.Y := -mC^.Vel.Y;
  176. mC^.Pos.Y := 1;
  177. end;
  178. if mC^.Pos.X > 638 then
  179. begin
  180. mC^.Vel.X := -mC^.Vel.X;
  181. mC^.Pos.X := 637;
  182. end;
  183. if mC^.Pos.Y > 478 then
  184. begin
  185. mC^.Vel.Y := -mC^.Vel.Y;
  186. mC^.Pos.Y := 477;
  187. end;
  188. VecMul(mC^.Vel,aM^.Energy_Loss); {Loss some speed in time}
  189. end;
  190. end;{ModelApplyForces}
  191. {----------------------------------}
  192. Procedure ModelCheckAnchors(aM:pModel);
  193. var
  194. i : tID;
  195. begin
  196. for i := 1 to aM^.AnchNum do
  197. aM^.Anchors^[i]^.Node^.Pos := aM^.Anchors^[i]^.Pos;
  198. end;{ModelCheckAnchors}
  199. {----------------------------------}
  200. Procedure RenderStringSpring(aM:pModel);
  201. var
  202. i : tID;
  203. gx,gy : float;
  204. Procedure LineCross(aV:tVec);
  205. begin
  206. Line(round(aV.x+gx)-3,
  207. round(aV.y+gy),
  208. round(aV.x+gx)+3,
  209. round(aV.y+gy));
  210. Line(round(aV.x+gx),
  211. round(aV.y+gy)-3,
  212. round(aV.x+gx),
  213. round(aV.y+gy)+3);
  214. end;
  215. begin
  216. gx := aM^.Pos.X;
  217. gy := aM^.Pos.Y;
  218. for i := 1 to aM^.SprNum-1 do
  219. begin
  220. SetColor(Green);
  221. Line(round(gx+aM^.Springs^[i]^.pos.x),
  222. round(gy+aM^.Springs^[i]^.pos.y),
  223. round(gx+aM^.Springs^[i+1]^.pos.x),
  224. round(gy+aM^.Springs^[i+1]^.pos.y));
  225. SetColor(Red);
  226. LineCross(aM^.Springs^[i]^.pos);
  227. end;
  228. LineCross(aM^.Springs^[i+1]^.Pos);
  229. end;{RenderStringSpring}
  230. {----------------------------------}
  231. Function InitMouse:boolean;assembler;
  232. asm
  233. mov ax, 00
  234. int 33h
  235. cmp ax, 0ffffh
  236. jnz @@1
  237. mov ax, 7
  238. mov cx, 0
  239. mov dx, 639
  240. int 33h
  241. mov ax, 08
  242. mov cx, 0
  243. mov dx, 479
  244. int 33h
  245. mov ax, 1
  246. @@1:
  247. ret
  248. end;{InitMouse}
  249. Procedure MoveMouse(x,y:word);assembler;
  250. asm
  251. mov cx, x
  252. mov dx, y
  253. mov ax, 4
  254. int 33h
  255. end;{ModeMouse}
  256. Procedure MousePosition(var x,y:word);assembler;
  257. asm
  258. mov ax, 3
  259. int 33h
  260. les di, x
  261. mov es:[di], cx
  262. les di, y
  263. mov es:[di], dx
  264. end;{MousePosition}
  265. Procedure HideMouse;assembler;
  266. asm
  267. mov ax, 2
  268. int 33h
  269. end;
  270. {-------------------------}
  271. var
  272. mString : pModel;
  273. i : tID;
  274. mx,my : word;
  275. j : longint;
  276. gD,gM : integer;
  277. SizeX : float;
  278. BEGIN
  279. New(mString);
  280. with mString^ do begin
  281. SprNum := 15;
  282. AnchNum := 1;
  283. SizeX := 600;
  284. GetMem(Springs,SprNum*SizeOf(pSpring));
  285. GetMem(Anchors,AnchNum*SizeOf(pAnchor));
  286. Springs^[1] := NewSpring(0,0,0,1);
  287. Springs^[SprNum] := NewSpring(SizeX*0.9,0,0,1);
  288. for i := 1 to SprNum-2 do
  289. Springs^[i+1] := NewSpring(i*SizeX/SprNum,0,0,2);
  290. Springs^[1]^.Neibs^[1] := Springs^[2];
  291. Springs^[1]^.Dists^[1] := SizeX/SprNum;
  292. Springs^[1]^.Mass := 1;
  293. Springs^[1]^.Ks^[1] := 0.25;
  294. Springs^[SprNum]^.Neibs^[1] := Springs^[SprNum-1];
  295. Springs^[SprNum]^.Dists^[1] := 0.5*SizeX/SprNum;
  296. Springs^[SprNum]^.Mass := 1;
  297. Springs^[SprNum]^.Ks^[1] := 0.25;
  298. for i := 2 to SprNum-1 do begin
  299. Springs^[i]^.Neibs^[1] := Springs^[i-1];
  300. Springs^[i]^.Neibs^[2] := Springs^[i+1];
  301. Springs^[i]^.Dists^[1] := 0.5*SizeX/SprNum;
  302. Springs^[i]^.Dists^[2] := 0.5*SizeX/SprNum;
  303. Springs^[i]^.Ks^[1] := 0.08;
  304. Springs^[i]^.Ks^[2] := 0.08;
  305. Springs^[i]^.Mass := 1;
  306. end;
  307. New(Anchors^[1]);
  308. Anchors^[1]^.Node := Springs^[1];
  309. Anchors^[1]^.Pos := ZeroVec;
  310. {
  311. New(Anchors^[2]);
  312. Anchors^[2]^.Node := Springs^[SprNum];
  313. Anchors^[2]^.Pos.X := 600;
  314. Anchors^[2]^.Pos.Y := 100;
  315. Anchors^[2]^.Pos.Z := 0;
  316. }
  317. Pos.x := 0;
  318. pos.y := 0;
  319. pos.z := 0;
  320. Gravity := ZeroVec;
  321. Gravity.Y := 0.09;
  322. Energy_Loss := 0.98;
  323. gD:=Detect;
  324. InitGraph(gD,gM,'');
  325. InitMouse;
  326. MoveMouse(10,5);
  327. while not keypressed do
  328. begin
  329. MousePosition(mx,my);
  330. Anchors^[1]^.pos.x := mx;
  331. Anchors^[1]^.pos.y := my;
  332. ModelCalcForces(mString);
  333. ModelApplyForces(mString,1);
  334. ModelCheckAnchors(mString);
  335. repeat until (Port[$03DA] and 8) <> 8;
  336. repeat until (Port[$03DA] and 8) = 8;
  337. ClearDevice;
  338. RenderStringSpring(mString);
  339. end;
  340. Dispose(Anchors^[1]);
  341. For i := 1 To SprNum Do DelSpring(Springs^[i]);
  342. FreeMem(Springs, SprNum*SizeOf(pSpring));
  343. FreeMem(Anchors,AnchNum*SizeOf(pAnchor));
  344. CloseGraph;
  345. end;
  346. END.