Physics.SPIForces.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. //
  2. // The multimedia graphics platform GLScene https://github.com/glscene
  3. //
  4. unit Physics.SPIForces;
  5. interface
  6. uses
  7. System.Classes,
  8. Vcl.Dialogs,
  9. GLS.VectorTypes,
  10. GLS.XCollection,
  11. GLS.Scene,
  12. GLS.VectorGeometry,
  13. GLS.Behaviours,
  14. GLS.Coordinates,
  15. GLS.Strings;
  16. type
  17. TGLForce = class;
  18. TGLForceType = (ftHookes, ftGravitation, ftCustom);
  19. TOnCustomForce = procedure() of object;
  20. TGLForce = class(TXCollectionItem)
  21. private
  22. fObject1: TGLBaseSceneObject;
  23. fObject2: TGLBaseSceneObject;
  24. fposition1: TGLCoordinates;
  25. fposition2: TGLCoordinates;
  26. object1Name: String;
  27. object2Name: String;
  28. // fOnCustomForce: TOnCustomForce;
  29. protected
  30. procedure Loaded; override;
  31. procedure SetName(const val: String); override;
  32. (* Returns the TGLBaseSceneObject on which the behaviour should be applied.
  33. Does NOT check for nil owners *)
  34. // function OwnerBaseSceneObject : TGLBaseSceneObject;
  35. public
  36. (* constructor Create(Collection: TCollection);override; *)
  37. // Override this function to write subclass data.
  38. procedure WriteToFiler(writer: TWriter); override;
  39. // Override this function to read subclass data.
  40. procedure ReadFromFiler(reader: TReader); override;
  41. constructor Create(aOwner: TXCollection); override;
  42. destructor Destroy; override;
  43. procedure Assign(Source: TPersistent); override;
  44. class function FriendlyName: String; override;
  45. class function FriendlyDescription: String; override;
  46. class function UniqueItem: Boolean; override;
  47. procedure SetObject1(const val: TGLBaseSceneObject);
  48. procedure SetObject2(const val: TGLBaseSceneObject);
  49. procedure SetPosition1(const val: TGLCoordinates);
  50. procedure SetPosition2(const val: TGLCoordinates);
  51. function CalculateForce(): TAffineVector; virtual;
  52. published
  53. property Object1: TGLBaseSceneObject read fObject1 write SetObject1;
  54. property Object2: TGLBaseSceneObject read fObject2 write SetObject2;
  55. property Position1: TGLCoordinates read fposition1 write SetPosition1;
  56. property Position2: TGLCoordinates read fposition2 write SetPosition2;
  57. // property OnCustomForce:TOnCustomForce read fOnCustomForce write fOnCustomForce;
  58. end;
  59. TGLHookesSpring = class(TGLForce)
  60. private
  61. fNaturalLength: Real;
  62. fElasticity: Real;
  63. fLength: Real;
  64. fExtension: Real;
  65. fDamping: TGLDamping;
  66. public
  67. procedure WriteToFiler(writer: TWriter); override;
  68. procedure ReadFromFiler(reader: TReader); override;
  69. constructor Create(aOwner: TXCollection); override;
  70. destructor Destroy; override;
  71. class function FriendlyName: String; override;
  72. class function FriendlyDescription: String; override;
  73. class function UniqueItem: Boolean; override;
  74. procedure SetDamping(const val: TGLDamping);
  75. function CalculateForce(): TAffineVector; override;
  76. published
  77. property NaturalLength: Real read fNaturalLength write fNaturalLength;
  78. property Elasticity: Real read fElasticity write fElasticity;
  79. property Damping: TGLDamping read fDamping write SetDamping;
  80. // property Name;
  81. end;
  82. TGLHookesString = class(TGLHookesSpring)
  83. protected
  84. // procedure WriteToFiler(writer : TWriter); override;
  85. // procedure ReadFromFiler(reader : TReader); override;
  86. public
  87. constructor Create(aOwner: TXCollection); override;
  88. destructor Destroy; override;
  89. class function FriendlyName: String; override;
  90. class function FriendlyDescription: String; override;
  91. class function UniqueItem: Boolean; override;
  92. function CalculateForce(): TAffineVector; override;
  93. end;
  94. // --------------------------------------------------------------
  95. implementation
  96. // --------------------------------------------------------------
  97. uses
  98. Physics.SPIInertias,
  99. Physics.SPIManager;
  100. constructor TGLForce.Create(aOwner: TXCollection);
  101. begin
  102. inherited; // Create(aOwner)
  103. fposition1 := TGLCoordinates.CreateInitialized(Self, NullHmgVector, csVector);
  104. fposition2 := TGLCoordinates.CreateInitialized(Self, NullHmgVector, csVector);
  105. // fObject1:=TGLBaseSceneObject.Create(Self);
  106. // fObject2:=TGLBaseSceneObject.Create(Self);
  107. end;
  108. destructor TGLForce.Destroy;
  109. begin
  110. fposition1.Free();
  111. fposition2.Free();
  112. // SetObject1(nil);
  113. // SetObject2(nil);
  114. // fObject1.Free();
  115. // fObject2.Free();
  116. inherited Destroy;
  117. end;
  118. procedure TGLForce.Assign(Source: TPersistent);
  119. begin
  120. // inherited Assign(Source);
  121. fposition1.Assign(TGLForce(Source).fposition1);
  122. fposition2.Assign(TGLForce(Source).fposition2);
  123. Object1 := TGLForce(Source).Object1;
  124. Object2 := TGLForce(Source).Object2;
  125. inherited Assign(Source);
  126. end;
  127. procedure TGLForce.SetObject1(const val: TGLBaseSceneObject);
  128. begin
  129. // if val.Behaviours.IndexOfClass(TGLBaseInertia) >=0 then
  130. fObject1 := val
  131. // else
  132. // messagedlg('Object1 does not have an inertia behaviour',mtWarning,[mbOk],0);
  133. end;
  134. procedure TGLForce.SetObject2(const val: TGLBaseSceneObject);
  135. begin
  136. // if val.Behaviours.IndexOfClass(TGLBaseInertia) >=0 then
  137. fObject2 := val
  138. // else
  139. // messagedlg('Object2 does not have an inertia behaviour',mtWarning,[mbOk],0);
  140. end;
  141. procedure TGLForce.SetPosition1(const val: TGLCoordinates);
  142. begin
  143. fposition1.Assign(val); // DB101
  144. end;
  145. procedure TGLForce.SetPosition2(const val: TGLCoordinates);
  146. begin
  147. fposition2.Assign(val);
  148. end;
  149. procedure TGLForce.Loaded;
  150. var
  151. PhysMan: TGLSPIManager;
  152. begin
  153. inherited Loaded;
  154. // not nice, not nice at all!!!!!!
  155. // assumes owner is TGLForces belonging to TGLPhysicsManager
  156. PhysMan := TGLSPIManager(Self.Owner.Owner);
  157. if (object1Name <> '') then
  158. begin
  159. // PhysMan:=TGLPhysicsManager(Self.Owner.Owner);
  160. fObject1 := PhysMan.FindObjectByName(object1Name);
  161. // fObject1:=TGLBaseSceneObject(FindComponent(Object1Name));
  162. // Object1Name:='';
  163. end;
  164. if object2Name <> '' then
  165. begin
  166. fObject2 := PhysMan.FindObjectByName(object2Name);
  167. // Object2Name:='';
  168. end;
  169. end;
  170. class function TGLForce.FriendlyName: String;
  171. begin
  172. Result := 'Force';
  173. end;
  174. class function TGLForce.FriendlyDescription: String;
  175. begin
  176. Result := 'Physics Force';
  177. end;
  178. class function TGLForce.UniqueItem: Boolean;
  179. begin
  180. Result := false;
  181. end;
  182. procedure TGLForce.WriteToFiler(writer: TWriter);
  183. begin
  184. inherited WriteToFiler(writer);
  185. // messagedlg('Writing to filer'+GetNamePath,mtInformation,[mbOk],0);
  186. with writer do
  187. begin
  188. fposition1.WriteToFiler(writer);
  189. fposition2.WriteToFiler(writer);
  190. if Assigned(fObject1) then
  191. WriteString(fObject1.GetNamePath)
  192. else
  193. WriteString('');
  194. if Assigned(fObject2) then
  195. WriteString(fObject2.GetNamePath)
  196. else
  197. WriteString('');
  198. // WriteString(Object2Name);
  199. end;
  200. end;
  201. procedure TGLForce.ReadFromFiler(reader: TReader);
  202. begin
  203. // messagedlg('Reading from filer'+GetNamePath,mtInformation,[mbOk],0);
  204. inherited ReadFromFiler(reader);
  205. with reader do
  206. begin
  207. fposition1.ReadFromFiler(reader);
  208. fposition2.ReadFromFiler(reader);
  209. object1Name := ReadString;
  210. fObject1 := nil;
  211. object2Name := ReadString;
  212. fObject2 := nil;
  213. end;
  214. // Loaded;
  215. end;
  216. procedure TGLForce.SetName(const val: String);
  217. begin
  218. inherited SetName(val);
  219. // if Assigned(vGLBehaviourNameChangeEvent) then
  220. // vGLBehaviourNameChangeEvent(Self);
  221. end;
  222. function TGLForce.CalculateForce(): TAffineVector;
  223. begin
  224. //
  225. end;
  226. constructor TGLHookesSpring.Create(aOwner: TXCollection);
  227. begin
  228. inherited Create(aOwner);
  229. fNaturalLength := 1;
  230. fElasticity := 1;
  231. fDamping := TGLDamping.Create(Self);
  232. end;
  233. destructor TGLHookesSpring.Destroy;
  234. begin
  235. fDamping.Free;
  236. inherited Destroy;
  237. end;
  238. procedure TGLHookesSpring.WriteToFiler(writer: TWriter);
  239. begin
  240. inherited;
  241. with writer do
  242. begin
  243. WriteFloat(fNaturalLength); // :Real;
  244. WriteFloat(fElasticity); // :Real;
  245. WriteFloat(fLength); // :Real;
  246. WriteFloat(fExtension); // :Real;
  247. fDamping.WriteToFiler(writer);
  248. end;
  249. end;
  250. procedure TGLHookesSpring.ReadFromFiler(reader: TReader);
  251. begin
  252. inherited;
  253. with reader do
  254. begin
  255. fNaturalLength := ReadFloat(); // :Real;
  256. fElasticity := ReadFloat(); // :Real;
  257. fLength := ReadFloat(); // :Real;
  258. fExtension := ReadFloat(); // :Real;
  259. fDamping.ReadFromFiler(reader);
  260. end;
  261. end;
  262. procedure TGLHookesSpring.SetDamping(const val: TGLDamping);
  263. begin
  264. fDamping.Assign(val);
  265. end;
  266. function TGLHookesSpring.CalculateForce(): TAffineVector;
  267. var
  268. rvector, vvector: TAffineVector;
  269. Inertia1, Inertia2: TGLParticleInertia;
  270. begin
  271. if (fObject1 = nil) or (fObject2 = nil) then
  272. Exit;
  273. Inertia2 := TGLParticleInertia
  274. (Object2.Behaviours.GetByClass(TGLParticleInertia));
  275. Inertia1 := TGLParticleInertia
  276. (Object1.Behaviours.GetByClass(TGLParticleInertia));
  277. // rvector:=VectorSubtract({VectorAdd(Object2.Position.asAffineVector,}VectorTransform(Position2.AsAffineVector,Object2.Matrix{)}),
  278. // {VectorAdd(Object1.Position.asAffineVector,}VectorTransform(Position1.AsAffineVector,Object1.Matrix){)});
  279. rvector := VectorSubtract(Object2.LocalToAbsolute(Position2.AsAffineVector),
  280. Object1.LocalToAbsolute(Position1.AsAffineVector));
  281. (*
  282. rvector:=VectorSubtract(VectorAdd(Object2.Position.asAffineVector,VectorTransform(Position2.AsAffineVector,Object2.Matrix)),
  283. VectorAdd(Object1.Position.asAffineVector,VectorTransform(Position1.AsAffineVector,Object1.Matrix)));
  284. *)
  285. fLength := VectorLength(rvector);
  286. NormalizeVector(rvector);
  287. fExtension := fLength - fNaturalLength;
  288. // fDamping.Calculate();
  289. Result := VectorScale(rvector, fElasticity * fExtension / fNaturalLength);
  290. if Assigned(Inertia2) then
  291. Inertia2.ApplyForce(Position2.AsAffineVector, VectorNegate(Result));
  292. if Assigned(Inertia1) then
  293. Inertia1.ApplyForce(Position1.AsAffineVector, Result);
  294. // TGLInertia(Object1.Behaviours.GetByClass(TGLInertia)).ApplyForce(Position1.AsAffineVector,Result);
  295. end;
  296. class function TGLHookesSpring.FriendlyName: String;
  297. begin
  298. Result := 'Hookes Spring';
  299. end;
  300. class function TGLHookesSpring.FriendlyDescription: String;
  301. begin
  302. Result := 'A spring obeying Hookes Law';
  303. end;
  304. class function TGLHookesSpring.UniqueItem: Boolean;
  305. begin
  306. Result := false;
  307. end;
  308. constructor TGLHookesString.Create(aOwner: TXCollection);
  309. begin
  310. inherited Create(aOwner);
  311. end;
  312. destructor TGLHookesString.Destroy;
  313. begin
  314. inherited Destroy;
  315. end;
  316. class function TGLHookesString.FriendlyName: String;
  317. begin
  318. Result := 'Hookes String';
  319. end;
  320. class function TGLHookesString.FriendlyDescription: String;
  321. begin
  322. Result := 'A string (that can go slack) obeying Hookes Law';
  323. end;
  324. class function TGLHookesString.UniqueItem: Boolean;
  325. begin
  326. Result := false;
  327. end;
  328. function TGLHookesString.CalculateForce(): TAffineVector;
  329. var
  330. rvector: TAffineVector;
  331. Inertia1, Inertia2: TGLParticleInertia;
  332. begin
  333. if (Object1 = nil) or (Object2 = nil) then
  334. Exit;
  335. rvector := VectorSubtract(Object2.LocalToAbsolute(Position2.AsAffineVector),
  336. Object1.LocalToAbsolute(Position1.AsAffineVector));
  337. // VectorAdd(Object2.Position.asAffineVector,VectorTransform(Object2.Position2.AsAffineVector,Object2.Matrix)),
  338. // VectorAdd(Object1.Position.asAffineVector,VectorTransform(Position1.AsAffineVector,Object1.Matrix)));
  339. fLength := VectorLength(rvector);
  340. if (fLength < fNaturalLength) then
  341. Result := NullVector
  342. else
  343. begin
  344. NormalizeVector(rvector);
  345. fExtension := fLength - fNaturalLength;
  346. Result := VectorScale(rvector, fElasticity * fExtension / fNaturalLength);
  347. // TGLInertia(Object2.Behaviours.GetByClass(TGLInertia)).ApplyForce(Position2.AsAffineVector,VectorNegate(Result));
  348. // TGLInertia(Object1.Behaviours.GetByClass(TGLInertia)).ApplyForce(Position1.AsAffineVector,Result);
  349. Inertia2 := TGLParticleInertia
  350. (Object2.Behaviours.GetByClass(TGLParticleInertia));
  351. Inertia1 := TGLParticleInertia
  352. (Object1.Behaviours.GetByClass(TGLParticleInertia));
  353. if Assigned(Inertia2) then
  354. Inertia2.ApplyForce(Position2.AsAffineVector, VectorNegate(Result));
  355. if Assigned(Inertia1) then
  356. Inertia1.ApplyForce(Position1.AsAffineVector, Result);
  357. end;
  358. // Result:= inherited CalculateForce();
  359. // if (fLength < fNaturalLength) then Result:=NullVector;
  360. end;
  361. // =================================================================
  362. initialization
  363. // =================================================================
  364. RegisterXCollectionItemClass(TGLHookesSpring);
  365. RegisterXCollectionItemClass(TGLHookesString);
  366. end.