GLS.Coordinates.pas 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194
  1. //
  2. // The graphics engine GLScene https://github.com/glscene
  3. //
  4. unit GLS.Coordinates;
  5. (*
  6. Coordinate related classes and functions.
  7. The registered classes are:
  8. [TGLCoordinates2, TGLCoordinates3, TGLCoordinates4]
  9. *)
  10. interface
  11. {$I GLScene.Defines.inc}
  12. uses
  13. System.Math,
  14. System.Classes,
  15. System.SysUtils,
  16. GLScene.VectorGeometry,
  17. GLS.BaseClasses,
  18. GLScene.VectorTypes;
  19. type
  20. (* Identifies the type of data stored within a TGLCustomCoordinates.
  21. csPoint2D : a simple 2D point (Z=0, W=0)
  22. csPoint : a point (W=1)
  23. csVector : a vector (W=0)
  24. csUnknown : no constraint *)
  25. TGLCoordinatesStyle = (csPoint2D, csPoint, csVector, csUnknown);
  26. (* Stores any homogeneous vector.
  27. This class is basicly a container for a TGLVector, allowing proper use of
  28. property editors and editing in the IDE. Vector/Coordinates
  29. manipulation methods are only minimal.
  30. Handles dynamic default values to save resource file space. *)
  31. TGLCustomCoordinates = class(TGLUpdateAbleObject)
  32. private
  33. FCoords: TGLVector;
  34. FStyle: TGLCoordinatesStyle; // NOT Persistent
  35. FPDefaultCoords: PGLVector;
  36. procedure SetAsPoint2D(const Value: TVector2f);
  37. procedure SetAsVector(const Value: TGLVector);
  38. procedure SetAsAffineVector(const Value: TAffineVector);
  39. function GetAsAffineVector: TAffineVector; inline;
  40. function GetAsPoint2D: TVector2f;
  41. function GetAsString: String;
  42. function GetCoordinate(const AIndex: Integer): Single; inline;
  43. procedure SetCoordinate(const AIndex: Integer; const AValue: Single); inline;
  44. function GetDirectCoordinate(const Index: Integer): Single; inline;
  45. procedure SetDirectCoordinate(const Index: Integer; const AValue: Single);
  46. protected
  47. procedure SetDirectVector(const V: TGLVector); inline;
  48. procedure DefineProperties(Filer: TFiler); override;
  49. procedure ReadData(Stream: TStream);
  50. procedure WriteData(Stream: TStream);
  51. public
  52. constructor CreateInitialized(AOwner: TPersistent; const AValue: TGLVector;
  53. const AStyle: TGLCoordinatesStyle = CsUnknown);
  54. destructor Destroy; override;
  55. procedure Assign(Source: TPersistent); override;
  56. procedure WriteToFiler(Writer: TWriter);
  57. procedure ReadFromFiler(Reader: TReader);
  58. procedure Initialize(const Value: TGLVector);
  59. procedure NotifyChange(Sender: TObject); override;
  60. (* Identifies the coordinates styles.
  61. The property is NOT persistent, csUnknown by default, and should be
  62. managed by owner object only (internally).
  63. It is used by the TGLCustomCoordinates for internal "assertion" checks
  64. to detect "misuses" or "misunderstandings" of what the homogeneous
  65. coordinates system implies. *)
  66. property Style: TGLCoordinatesStyle read FStyle write FStyle;
  67. procedure Translate(const TranslationVector: TGLVector); overload;
  68. procedure Translate(const TranslationVector: TAffineVector); overload;
  69. procedure AddScaledVector(const Factor: Single; const TranslationVector: TGLVector); overload;
  70. procedure AddScaledVector(const Factor: Single; const TranslationVector: TAffineVector); overload;
  71. procedure Rotate(const AnAxis: TAffineVector; AnAngle: Single); overload;
  72. procedure Rotate(const AnAxis: TGLVector; AnAngle: Single); overload;
  73. procedure Normalize; inline;
  74. procedure Invert;
  75. procedure Scale(Factor: Single);
  76. function VectorLength: Single;
  77. function VectorNorm: Single;
  78. function MaxXYZ: Single;
  79. function Equals(const AVector: TGLVector): Boolean; reintroduce;
  80. procedure SetVector(const X, Y: Single; Z: Single = 0); overload;
  81. procedure SetVector(const X, Y, Z, W: Single); overload;
  82. procedure SetVector(const V: TAffineVector); overload;
  83. procedure SetVector(const V: TGLVector); overload;
  84. procedure SetPoint(const X, Y, Z: Single); overload;
  85. procedure SetPoint(const V: TAffineVector); overload;
  86. procedure SetPoint(const V: TGLVector); overload;
  87. procedure SetPoint2D(const X, Y: Single); overload;
  88. procedure SetPoint2D(const Vector: TAffineVector); overload;
  89. procedure SetPoint2D(const Vector: TGLVector); overload;
  90. procedure SetPoint2D(const Vector: TVector2f); overload;
  91. procedure SetToZero;
  92. function AsAddress: PSingle; inline;
  93. (* The coordinates viewed as a vector.
  94. Assigning a value to this property will trigger notification events,
  95. if you don't want so, use DirectVector instead. *)
  96. property AsVector: TGLVector read FCoords write SetAsVector;
  97. (* The coordinates viewed as an affine vector.
  98. Assigning a value to this property will trigger notification events,
  99. if you don't want so, use DirectVector instead.
  100. The W component is automatically adjustes depending on style. *)
  101. property AsAffineVector: TAffineVector read GetAsAffineVector write SetAsAffineVector;
  102. (* The coordinates viewed as a 2D point.
  103. Assigning a value to this property will trigger notification events,
  104. if you don't want so, use DirectVector instead. *)
  105. property AsPoint2D: TVector2f read GetAsPoint2D write SetAsPoint2D;
  106. property X: Single index 0 read GetCoordinate write SetCoordinate;
  107. property Y: Single index 1 read GetCoordinate write SetCoordinate;
  108. property Z: Single index 2 read GetCoordinate write SetCoordinate;
  109. property W: Single index 3 read GetCoordinate write SetCoordinate;
  110. property Coordinate[const AIndex: Integer]: Single read GetCoordinate write SetCoordinate; default;
  111. // The coordinates, in-between brackets, separated by semi-colons.
  112. property AsString: String read GetAsString;
  113. // Similar to AsVector but does not trigger notification events
  114. property DirectVector: TGLVector read FCoords write SetDirectVector;
  115. property DirectX: Single index 0 read GetDirectCoordinate write SetDirectCoordinate;
  116. property DirectY: Single index 1 read GetDirectCoordinate write SetDirectCoordinate;
  117. property DirectZ: Single index 2 read GetDirectCoordinate write SetDirectCoordinate;
  118. property DirectW: Single index 3 read GetDirectCoordinate write SetDirectCoordinate;
  119. end;
  120. // A TGLCustomCoordinates that publishes X, Y properties.
  121. TGLCoordinates2 = class(TGLCustomCoordinates)
  122. published
  123. property X stored False;
  124. property Y stored False;
  125. end;
  126. // A TGLCustomCoordinates that publishes X, Y, Z properties.
  127. TGLCoordinates3 = class(TGLCustomCoordinates)
  128. published
  129. property X stored False;
  130. property Y stored False;
  131. property Z stored False;
  132. end;
  133. // A TGLCustomCoordinates that publishes X, Y, Z, W properties.
  134. TGLCoordinates4 = class(TGLCustomCoordinates)
  135. published
  136. property X stored False;
  137. property Y stored False;
  138. property Z stored False;
  139. property W stored False;
  140. end;
  141. TGLCoordinates = TGLCoordinates3;
  142. (* Actually Sender should be TGLCustomCoordinates, but that would require
  143. changes in a some other GLScene units and some other projects that use
  144. TGLCoordinatesUpdateAbleComponent *)
  145. IGLCoordinatesUpdateAble = interface(IInterface)
  146. ['{ACB98D20-8905-43A7-AFA5-225CF5FA6FF5}']
  147. procedure CoordinateChanged(Sender: TGLCustomCoordinates);
  148. end;
  149. TGLCoordinatesUpdateAbleComponent = class(TGLUpdateAbleComponent, IGLCoordinatesUpdateAble)
  150. public
  151. procedure CoordinateChanged(Sender: TGLCustomCoordinates); virtual; abstract;
  152. end;
  153. (* Calculates the barycentric coordinates for the point p on the triangle
  154. defined by the vertices v1, v2 and v3. That is, solves
  155. p = u * v1 + v * v2 + (1-u-v) * v3
  156. for u,v.
  157. Returns true if the point is inside the triangle, false otherwise.
  158. NOTE: This function assumes that the point lies on the plane defined by the triangle.
  159. If this is not the case, the function will not work correctly!
  160. https://mathworld.wolfram.com/BarycentricCoordinates.html *)
  161. function BarycentricCoordinates(const V1, V2, V3, p: TAffineVector; var u, V: Single): Boolean;
  162. //-------------------- Conversions of Coordinates --------------------
  163. (*
  164. Helper functions to convert between different three dimensional coordinate
  165. systems. Room for optimisations.
  166. *)
  167. (* Convert Cylindrical to Cartesian [single] with no checks, theta in rad
  168. Ref: http://mathworld.wolfram.com/CylindricalCoordinates.html *)
  169. procedure Cylindrical_Cartesian(const r, theta, z1: single; var x, y, z: single); overload;
  170. (* Convert Cylindrical to Cartesian with no checks. Double version, theta in rads
  171. Ref: http://mathworld.wolfram.com/CylindricalCoordinates.html *)
  172. procedure Cylindrical_Cartesian(const r, theta, z1: double; var x, y, z: double); overload;
  173. (* Convert Cylindrical to Cartesian with checks. [single], theta in rad
  174. ierr: [0] = ok,
  175. [1] = r out of bounds. Acceptable r: [0,inf)
  176. [2] = theta out of bounds. Acceptable theta: [0,2pi)
  177. [3] = z1 out of bounds. Acceptable z1 : (-inf,inf)
  178. Ref: http://mathworld.wolfram.com/CylindricalCoordinates.html *)
  179. procedure Cylindrical_Cartesian(const r, theta, z1: single; var x, y, z: single;
  180. var ierr: integer); overload;
  181. (* Convert Cylindrical to Cartesian with checks. [double], theta in rad
  182. ierr: [0] = ok,
  183. [1] = r out of bounds. Acceptable r: [0,inf)
  184. [2] = theta out of bounds. Acceptable theta: [0,2pi)
  185. [3] = z1 out of bounds. Acceptable z1 : (-inf,inf)
  186. Ref: http://mathworld.wolfram.com/CylindricalCoordinates.html *)
  187. procedure Cylindrical_Cartesian(const r, theta, z1: double; var x, y, z: double;
  188. var ierr: integer); overload;
  189. (* Convert Cartesian to Cylindrical no checks. Single *)
  190. procedure Cartesian_Cylindrical(const x, y, z1: single; var r, theta, z: single); overload;
  191. (* Convert Cartesian to Cylindrical no checks. Duoble *)
  192. procedure Cartesian_Cylindrical(const x, y, z1: double; var r, theta, z: double); overload;
  193. (* Convert Spherical to Cartesian with no checks. [single] theta,phi in rads
  194. Ref: http://mathworld.wolfram.com/SphericalCoordinates.html *)
  195. procedure Spherical_Cartesian(const r, theta, phi: single; var x, y, z: single); overload;
  196. (* Convert Spherical to Cartesian with no checks. Double version. theta,phi in rads *)
  197. procedure Spherical_Cartesian(const r, theta, phi: double; var x, y, z: double); overload;
  198. (* Convert Spherical to Cartesian [single] (with error check).theta,phi in rad
  199. ierr: [0] = ok,
  200. [1] = r out of bounds
  201. [2] = theta out of bounds
  202. [3] = phi out of bounds
  203. Ref: http://mathworld.wolfram.com/SphericalCoordinates.html *)
  204. procedure Spherical_Cartesian(const r, theta, phi: single; var x, y, z: single;
  205. var ierr: integer); overload;
  206. // Convert spherical to cartesian [double] (with error check).theta,phi in rad
  207. procedure Spherical_Cartesian(const r, theta, phi: double; var x, y, z: double;
  208. var ierr: integer); overload;
  209. (* Convert Cartesian to Spherical, no checks, single
  210. Ref: http://mathworld.wolfram.com/SphericalCoordinates.html
  211. NB: Could be optimised by using jclmath.pas unit *)
  212. procedure Cartesian_Spherical(const x, y, z: single; var r, theta, phi: single); overload;
  213. (* Convert Cartesian to Spherical, no checks, single
  214. Ref: http://mathworld.wolfram.com/SphericalCoordinates.html
  215. NB: Could be optimised by using fastmath.pas unit *)
  216. procedure Cartesian_Spherical(const v: TAffineVector; var r, theta, phi: single); overload;
  217. (* convert Cartesian to Spherical, no checks, double
  218. Ref: http://mathworld.wolfram.com/SphericalCoordinates.html
  219. NB: Could be optimised by using jclmath.pas unit? *)
  220. procedure Cartesian_Spherical(const x, y, z: double; var r, theta, phi: double); overload;
  221. (* Convert Prolate-Spheroidal to Cartesian with no checks. [single] eta, phi in rad
  222. A system of curvilinear coordinates in which two sets of coordinate surfaces are
  223. obtained by revolving the curves of the elliptic cylindrical coordinates about
  224. the x-axis, which is relabeled the z-axis. The third set of coordinates
  225. consists of planes passing through this axis.
  226. The coordinate system is parameterised by parameter a.
  227. A default value of a=1 is suggesed:
  228. Ref: http://mathworld.wolfram.com/ProlateSpheroidalCoordinates.html *)
  229. procedure ProlateSpheroidal_Cartesian(const xi, eta, phi, a: single;
  230. var x, y, z: single); overload;
  231. (* Convert Prolate-Spheroidal to Cartesian [double] eta,phi in rad
  232. A system of curvilinear coordinates in which two sets of coordinate surfaces are
  233. obtained by revolving the curves of the elliptic cylindrical coordinates about
  234. the x-axis, which is relabeled the z-axis. The third set of coordinates
  235. consists of planes passing through this axis.
  236. The coordinate system is parameterised by parameter a. A default value of a=1 is
  237. suggesed: Ref: http://mathworld.wolfram.com/ProlateSpheroidalCoordinates.html *)
  238. procedure ProlateSpheroidal_Cartesian(const xi, eta, phi, a: double;
  239. var x, y, z: double); overload;
  240. (* Convert Prolate-Spheroidal to Cartesian [single](with error check). eta,phi in rad
  241. ierr: [0] = ok,
  242. [1] = xi out of bounds. Acceptable xi: [0,inf)
  243. [2] = eta out of bounds. Acceptable eta: [0,pi]
  244. [3] = phi out of bounds. Acceptable phi: [0,2pi)
  245. Ref: http://mathworld.wolfram.com/ProlateSpheroidalCoordinates.html *)
  246. procedure ProlateSpheroidal_Cartesian(const xi, eta, phi, a: single;
  247. var x, y, z: single; var ierr: integer); overload;
  248. (* Convert Prolate-Spheroidal to Cartesian [double](with error check). eta,phi in rad
  249. ierr: [0] = ok,
  250. [1] = xi out of bounds. Acceptable xi: [0,inf)
  251. [2] = eta out of bounds. Acceptable eta: [0,pi]
  252. [3] = phi out of bounds. Acceptable phi: [0,2pi)
  253. Ref: http://mathworld.wolfram.com/ProlateSpheroidalCoordinates.html *)
  254. procedure ProlateSpheroidal_Cartesian(const xi, eta, phi, a: double;
  255. var x, y, z: double; var ierr: integer); overload;
  256. // Convert Oblate-Spheroidal to Cartesian. [Single] eta, phi in rad
  257. procedure OblateSpheroidal_Cartesian(const xi, eta, phi, a: single;
  258. var x, y, z: single); overload;
  259. // Convert Oblate-Spheroidal to Cartesian. [Double] eta, phi in rad
  260. procedure OblateSpheroidal_Cartesian(const xi, eta, phi, a: double;
  261. var x, y, z: double); overload;
  262. // Convert Oblate-Spheroidal to Cartesian (with error check). eta,phi in rad
  263. procedure OblateSpheroidal_Cartesian(const xi, eta, phi, a: single;
  264. var x, y, z: single; var ierr: integer); overload;
  265. (* Convert Oblate-Spheroidal to Cartesian with checks. [Double] eta,phi in rad
  266. ierr: [0] = ok,
  267. [1] = xi out of bounds. Acceptable xi: [0,inf)
  268. [2] = eta out of bounds. Acceptable eta: [-0.5*pi,0.5*pi]
  269. [3] = phi out of bounds. Acceptable phi: [0,2*pi)
  270. Ref: http://mathworld.wolfram.com/ProlateSpheroidalCoordinates.html *)
  271. procedure OblateSpheroidal_Cartesian(const xi, eta, phi, a: double;
  272. var x, y, z: double; var ierr: integer); overload;
  273. // Convert Bipolar to Cartesian. u in rad
  274. procedure BipolarCylindrical_Cartesian(const u, v, z1, a: single;
  275. var x, y, z: single); overload;
  276. (* Convert BiPolarCylindrical to Cartesian with no checks. Double, u in rad
  277. http://mathworld.wolfram.com/BipolarCylindricalCoordinates.html *)
  278. procedure BipolarCylindrical_Cartesian(const u, v, z1, a: double;
  279. var x, y, z: double); overload;
  280. // Convert Bipolar to Cartesian (with error check). u in rad
  281. procedure BipolarCylindrical_Cartesian(const u, v, z1, a: single;
  282. var x, y, z: single; var ierr: integer); overload;
  283. (* Convert Oblate-Spheroidal to Cartesian with checks. Double, u in rad
  284. ierr: [0] = ok,
  285. [1] = u out of bounds. Acceptable u: [0,2*pi)
  286. [2] = v out of bounds. Acceptable v: (-inf,inf)
  287. [3] = z1 out of bounds. Acceptable z1: (-inf,inf)
  288. Ref: https://mathworld.wolfram.com/BipolarCylindricalCoordinates.html *)
  289. procedure BipolarCylindrical_Cartesian(const u, v, z1, a: double;
  290. var x, y, z: double; var ierr: integer); overload;
  291. var
  292. (* Specifies if TGLCustomCoordinates should allocate memory for
  293. their default values (ie. design-time) or not (run-time) *)
  294. VUseDefaultCoordinateSets: Boolean = False;
  295. //==================================================================
  296. implementation
  297. //==================================================================
  298. const
  299. csVectorHelp = 'When getting assertions here use the SetPoint procedure';
  300. csPointHelp = 'When getting assertions here use the SetVector procedure';
  301. csPoint2DHelp = 'When getting assertions here use one of the SetVector or SetPoint procedures';
  302. // ------------------
  303. // ------------------ TGLCustomCoordinates ------------------
  304. // ------------------
  305. constructor TGLCustomCoordinates.CreateInitialized(AOwner: TPersistent;
  306. const AValue: TGLVector; const AStyle: TGLCoordinatesStyle = CsUnknown);
  307. begin
  308. Create(AOwner);
  309. Initialize(AValue);
  310. FStyle := AStyle;
  311. end;
  312. destructor TGLCustomCoordinates.Destroy;
  313. begin
  314. if Assigned(FPDefaultCoords) then
  315. Dispose(FPDefaultCoords);
  316. inherited;
  317. end;
  318. procedure TGLCustomCoordinates.Initialize(const Value: TGLVector);
  319. begin
  320. FCoords := Value;
  321. if VUseDefaultCoordinateSets then
  322. begin
  323. if not Assigned(FPDefaultCoords) then
  324. New(FPDefaultCoords);
  325. FPDefaultCoords^ := Value;
  326. end;
  327. end;
  328. procedure TGLCustomCoordinates.Assign(Source: TPersistent);
  329. begin
  330. if Source is TGLCustomCoordinates then
  331. FCoords := TGLCustomCoordinates(Source).FCoords
  332. else
  333. inherited;
  334. end;
  335. procedure TGLCustomCoordinates.WriteToFiler(Writer: TWriter);
  336. var
  337. WriteCoords: Boolean;
  338. begin
  339. with Writer do
  340. begin
  341. WriteInteger(0); // Archive Version 0
  342. if VUseDefaultCoordinateSets then
  343. WriteCoords := not VectorEquals(FPDefaultCoords^, FCoords)
  344. else
  345. WriteCoords := True;
  346. WriteBoolean(WriteCoords);
  347. if WriteCoords then
  348. Write(FCoords.X, SizeOf(FCoords));
  349. end;
  350. end;
  351. procedure TGLCustomCoordinates.ReadFromFiler(Reader: TReader);
  352. var
  353. N: Integer;
  354. begin
  355. with Reader do
  356. begin
  357. ReadInteger; // Ignore ArchiveVersion
  358. if ReadBoolean then
  359. begin
  360. N := SizeOf(FCoords);
  361. Assert(N = 4 * SizeOf(Single));
  362. Read(FCoords.X, N);
  363. end
  364. else if Assigned(FPDefaultCoords) then
  365. FCoords := FPDefaultCoords^;
  366. end;
  367. end;
  368. procedure TGLCustomCoordinates.DefineProperties(Filer: TFiler);
  369. begin
  370. inherited;
  371. Filer.DefineBinaryProperty('Coordinates', ReadData, WriteData,
  372. not(Assigned(FPDefaultCoords) and VectorEquals(FPDefaultCoords^, FCoords)));
  373. end;
  374. procedure TGLCustomCoordinates.ReadData(Stream: TStream);
  375. begin
  376. Stream.Read(FCoords, SizeOf(FCoords));
  377. end;
  378. procedure TGLCustomCoordinates.WriteData(Stream: TStream);
  379. begin
  380. Stream.Write(FCoords, SizeOf(FCoords));
  381. end;
  382. procedure TGLCustomCoordinates.NotifyChange(Sender: TObject);
  383. var
  384. Int: IGLCoordinatesUpdateAble;
  385. begin
  386. if Supports(Owner, IGLCoordinatesUpdateAble, Int) then
  387. Int.CoordinateChanged(TGLCoordinates(Self));
  388. inherited NotifyChange(Sender);
  389. end;
  390. procedure TGLCustomCoordinates.Translate(const TranslationVector: TGLVector);
  391. begin
  392. FCoords.X := FCoords.X + TranslationVector.X;
  393. FCoords.Y := FCoords.Y + TranslationVector.Y;
  394. FCoords.Z := FCoords.Z + TranslationVector.Z;
  395. NotifyChange(Self);
  396. end;
  397. procedure TGLCustomCoordinates.Translate(const TranslationVector
  398. : TAffineVector);
  399. begin
  400. FCoords.X := FCoords.X + TranslationVector.X;
  401. FCoords.Y := FCoords.Y + TranslationVector.Y;
  402. FCoords.Z := FCoords.Z + TranslationVector.Z;
  403. NotifyChange(Self);
  404. end;
  405. procedure TGLCustomCoordinates.AddScaledVector(const Factor: Single;
  406. const TranslationVector: TGLVector);
  407. var
  408. F: Single;
  409. begin
  410. F := Factor;
  411. CombineVector(FCoords, TranslationVector, F);
  412. NotifyChange(Self);
  413. end;
  414. procedure TGLCustomCoordinates.AddScaledVector(const Factor: Single;
  415. const TranslationVector: TAffineVector);
  416. var
  417. F: Single;
  418. begin
  419. F := Factor;
  420. CombineVector(FCoords, TranslationVector, F);
  421. NotifyChange(Self);
  422. end;
  423. procedure TGLCustomCoordinates.Rotate(const AnAxis: TAffineVector;
  424. AnAngle: Single);
  425. begin
  426. RotateVector(FCoords, AnAxis, AnAngle);
  427. NotifyChange(Self);
  428. end;
  429. procedure TGLCustomCoordinates.Rotate(const AnAxis: TGLVector; AnAngle: Single);
  430. begin
  431. RotateVector(FCoords, AnAxis, AnAngle);
  432. NotifyChange(Self);
  433. end;
  434. procedure TGLCustomCoordinates.Normalize;
  435. begin
  436. NormalizeVector(FCoords);
  437. NotifyChange(Self);
  438. end;
  439. procedure TGLCustomCoordinates.Invert;
  440. begin
  441. NegateVector(FCoords);
  442. NotifyChange(Self);
  443. end;
  444. procedure TGLCustomCoordinates.Scale(Factor: Single);
  445. begin
  446. ScaleVector(PAffineVector(@FCoords)^, Factor);
  447. NotifyChange(Self);
  448. end;
  449. function TGLCustomCoordinates.VectorLength: Single;
  450. begin
  451. Result := GLScene.VectorGeometry.VectorLength(FCoords);
  452. end;
  453. function TGLCustomCoordinates.VectorNorm: Single;
  454. begin
  455. Result := GLScene.VectorGeometry.VectorNorm(FCoords);
  456. end;
  457. function TGLCustomCoordinates.MaxXYZ: Single;
  458. begin
  459. Result := MaxXYZComponent(FCoords);
  460. end;
  461. function TGLCustomCoordinates.Equals(const AVector: TGLVector): Boolean;
  462. begin
  463. Result := VectorEquals(FCoords, AVector);
  464. end;
  465. procedure TGLCustomCoordinates.SetVector(const X, Y: Single; Z: Single = 0);
  466. begin
  467. Assert(FStyle = csVector, csVectorHelp);
  468. GLScene.VectorGeometry.SetVector(FCoords, X, Y, Z);
  469. NotifyChange(Self);
  470. end;
  471. procedure TGLCustomCoordinates.SetVector(const V: TAffineVector);
  472. begin
  473. Assert(FStyle = csVector, csVectorHelp);
  474. GLScene.VectorGeometry.SetVector(FCoords, V);
  475. NotifyChange(Self);
  476. end;
  477. procedure TGLCustomCoordinates.SetVector(const V: TGLVector);
  478. begin
  479. Assert(FStyle = csVector, csVectorHelp);
  480. GLScene.VectorGeometry.SetVector(FCoords, V);
  481. NotifyChange(Self);
  482. end;
  483. procedure TGLCustomCoordinates.SetVector(const X, Y, Z, W: Single);
  484. begin
  485. Assert(FStyle = csVector, csVectorHelp);
  486. GLScene.VectorGeometry.SetVector(FCoords, X, Y, Z, W);
  487. NotifyChange(Self);
  488. end;
  489. procedure TGLCustomCoordinates.SetDirectCoordinate(const Index: Integer;
  490. const AValue: Single);
  491. begin
  492. FCoords.V[index] := AValue;
  493. end;
  494. procedure TGLCustomCoordinates.SetDirectVector(const V: TGLVector);
  495. begin
  496. FCoords.X := V.X;
  497. FCoords.Y := V.Y;
  498. FCoords.Z := V.Z;
  499. FCoords.W := V.W;
  500. end;
  501. procedure TGLCustomCoordinates.SetToZero;
  502. begin
  503. FCoords.X := 0;
  504. FCoords.Y := 0;
  505. FCoords.Z := 0;
  506. if FStyle = CsPoint then
  507. FCoords.W := 1
  508. else
  509. FCoords.W := 0;
  510. NotifyChange(Self);
  511. end;
  512. procedure TGLCustomCoordinates.SetPoint(const X, Y, Z: Single);
  513. begin
  514. Assert(FStyle = CsPoint, CsPointHelp);
  515. MakePoint(FCoords, X, Y, Z);
  516. NotifyChange(Self);
  517. end;
  518. procedure TGLCustomCoordinates.SetPoint(const V: TAffineVector);
  519. begin
  520. Assert(FStyle = CsPoint, CsPointHelp);
  521. MakePoint(FCoords, V);
  522. NotifyChange(Self);
  523. end;
  524. procedure TGLCustomCoordinates.SetPoint(const V: TGLVector);
  525. begin
  526. Assert(FStyle = CsPoint, CsPointHelp);
  527. MakePoint(FCoords, V);
  528. NotifyChange(Self);
  529. end;
  530. procedure TGLCustomCoordinates.SetPoint2D(const X, Y: Single);
  531. begin
  532. Assert(FStyle = CsPoint2D, CsPoint2DHelp);
  533. GLScene.VectorGeometry.MakeVector(FCoords, X, Y, 0);
  534. NotifyChange(Self);
  535. end;
  536. procedure TGLCustomCoordinates.SetPoint2D(const Vector: TAffineVector);
  537. begin
  538. Assert(FStyle = CsPoint2D, CsPoint2DHelp);
  539. MakeVector(FCoords, Vector);
  540. NotifyChange(Self);
  541. end;
  542. procedure TGLCustomCoordinates.SetPoint2D(const Vector: TGLVector);
  543. begin
  544. Assert(FStyle = CsPoint2D, CsPoint2DHelp);
  545. MakeVector(FCoords, Vector);
  546. NotifyChange(Self);
  547. end;
  548. procedure TGLCustomCoordinates.SetPoint2D(const Vector: TVector2f);
  549. begin
  550. Assert(FStyle = CsPoint2D, CsPoint2DHelp);
  551. MakeVector(FCoords, Vector.X, Vector.Y, 0);
  552. NotifyChange(Self);
  553. end;
  554. function TGLCustomCoordinates.AsAddress: PSingle;
  555. begin
  556. Result := @FCoords;
  557. end;
  558. procedure TGLCustomCoordinates.SetAsVector(const Value: TGLVector);
  559. begin
  560. FCoords := Value;
  561. case FStyle of
  562. CsPoint2D:
  563. begin
  564. FCoords.Z := 0;
  565. FCoords.W := 0;
  566. end;
  567. CsPoint:
  568. FCoords.W := 1;
  569. CsVector:
  570. FCoords.W := 0;
  571. else
  572. Assert(False);
  573. end;
  574. NotifyChange(Self);
  575. end;
  576. procedure TGLCustomCoordinates.SetAsAffineVector(const Value: TAffineVector);
  577. begin
  578. case FStyle of
  579. CsPoint2D:
  580. MakeVector(FCoords, Value);
  581. CsPoint:
  582. MakePoint(FCoords, Value);
  583. CsVector:
  584. MakeVector(FCoords, Value);
  585. else
  586. Assert(False);
  587. end;
  588. NotifyChange(Self);
  589. end;
  590. procedure TGLCustomCoordinates.SetAsPoint2D(const Value: TVector2f);
  591. begin
  592. case FStyle of
  593. CsPoint2D, CsPoint, CsVector:
  594. begin
  595. FCoords.X := Value.X;
  596. FCoords.Y := Value.Y;
  597. FCoords.Z := 0;
  598. FCoords.W := 0;
  599. end;
  600. else
  601. Assert(False);
  602. end;
  603. NotifyChange(Self);
  604. end;
  605. function TGLCustomCoordinates.GetAsAffineVector: TAffineVector;
  606. begin
  607. GLScene.VectorGeometry.SetVector(Result, FCoords);
  608. end;
  609. function TGLCustomCoordinates.GetAsPoint2D: TVector2f;
  610. begin
  611. Result.X := FCoords.X;
  612. Result.Y := FCoords.Y;
  613. end;
  614. procedure TGLCustomCoordinates.SetCoordinate(const AIndex: Integer;
  615. const AValue: Single);
  616. begin
  617. FCoords.V[AIndex] := AValue;
  618. NotifyChange(Self);
  619. end;
  620. function TGLCustomCoordinates.GetCoordinate(const AIndex: Integer): Single;
  621. begin
  622. Result := FCoords.V[AIndex];
  623. end;
  624. function TGLCustomCoordinates.GetDirectCoordinate(
  625. const Index: Integer): Single;
  626. begin
  627. Result := FCoords.V[index]
  628. end;
  629. function TGLCustomCoordinates.GetAsString: String;
  630. begin
  631. case Style of
  632. CsPoint2D:
  633. Result := Format('(%g; %g)', [FCoords.X, FCoords.Y]);
  634. CsPoint:
  635. Result := Format('(%g; %g; %g)', [FCoords.X, FCoords.Y, FCoords.Z]);
  636. CsVector:
  637. Result := Format('(%g; %g; %g; %g)', [FCoords.X, FCoords.Y, FCoords.Z,
  638. FCoords.W]);
  639. else
  640. Assert(False);
  641. end;
  642. end;
  643. // ----------------- Conversions of coordinates --------------------
  644. // ----------------- Cylindrical_Cartesian ----------------------
  645. procedure Cylindrical_Cartesian(const r, theta, z1: single; var x, y, z: single);
  646. begin
  647. SinCosine(theta, r, y, x);
  648. z := z1;
  649. end;
  650. // ----- Cylindrical_Cartesian -------------------------------------
  651. procedure Cylindrical_Cartesian(const r, theta, z1: double; var x, y, z: double);
  652. begin
  653. SinCosine(theta, r, y, x);
  654. z := z1;
  655. end;
  656. // ------------------ Cylindrical_Cartesian -----------------------
  657. procedure Cylindrical_Cartesian(const r, theta, z1: single; var x, y, z: single;
  658. var ierr: integer);
  659. begin
  660. // check input parameters
  661. if (r < 0.0) then
  662. ierr := 1
  663. else if ((theta < 0.0) or (theta >= 2 * pi)) then
  664. ierr := 2
  665. else
  666. ierr := 0;
  667. if (ierr = 0) then
  668. begin
  669. SinCosine(theta, r, y, x);
  670. z := z1;
  671. end;
  672. end;
  673. // ----- Cylindrical_Cartesian -------------------------------------------------
  674. procedure Cylindrical_Cartesian(const r, theta, z1: double; var x, y, z: double;
  675. var ierr: integer);
  676. begin
  677. // check input parameters
  678. if (r < 0.0) then
  679. ierr := 1
  680. else if ((theta < 0.0) or (theta >= 2 * pi)) then
  681. ierr := 2
  682. else
  683. ierr := 0;
  684. if (ierr = 0) then
  685. begin
  686. SinCosine(theta, r, y, x);
  687. z := z1;
  688. end;
  689. end;
  690. // ----- Cartesian_Cylindrical -------------------------------------------------
  691. procedure Cartesian_Cylindrical(const x, y, z1: single; var r, theta, z: single);
  692. begin
  693. r := sqrt(x * x + y * y);
  694. theta := ArcTan2(y, x);
  695. z := z1;
  696. end;
  697. // ----- Cartesian_Cylindrical -------------------------------------------------
  698. procedure Cartesian_Cylindrical(const x, y, z1: double; var r, theta, z: double);
  699. begin
  700. r := sqrt(x * x + y * y);
  701. theta := ArcTan2(y, x);
  702. z := z1;
  703. end;
  704. // ----- Spherical_Cartesian ---------------------------------------------------
  705. procedure Spherical_Cartesian(const r, theta, phi: single; var x, y, z: single);
  706. var
  707. a: single;
  708. begin
  709. SinCosine(phi, r, a, z); // z = r*cos(phi), a = r*sin(phi)
  710. SinCosine(theta, a, y, x); // x = a*cos(theta), y = a*sin(theta)}
  711. end;
  712. // ----- Spherical_Cartesian ---------------------------------------------------
  713. procedure Spherical_Cartesian(const r, theta, phi: double; var x, y, z: double);
  714. var
  715. a: double;
  716. begin
  717. SinCosine(phi, r, a, z); // z = r*cos(phi), a = r*sin(phi)
  718. SinCosine(theta, a, y, x); // x = a*cos(theta), y = a*sin(theta)}
  719. end;
  720. // ----- Spherical_Cartesian ---------------------------------------------------
  721. procedure Spherical_Cartesian(const r, theta, phi: single; var x, y, z: single;
  722. var ierr: integer);
  723. var
  724. a: single;
  725. begin
  726. if (r < 0.0) then
  727. ierr := 1
  728. else if ((theta < 0.0) or (theta >= 2 * pi)) then
  729. ierr := 2
  730. else if ((phi < 0.0) or (phi >= 2 * pi)) then
  731. ierr := 3
  732. else
  733. ierr := 0;
  734. if (ierr = 0) then
  735. begin
  736. SinCosine(phi, r, a, z); // z = r*cos(phi), a = r*sin(phi)
  737. SinCosine(theta, a, y, x); // x = a*cos(theta), y = a*sin(theta)}
  738. end;
  739. end;
  740. // ----- Spherical_Cartesian ---------------------------------------------------
  741. (* Convert Spherical to Cartesian with checks.
  742. ierr: [0] = ok,
  743. [1] = r out of bounds
  744. [2] = theta out of bounds
  745. [3] = phi out of bounds
  746. Ref: http://mathworld.wolfram.com/SphericalCoordinates.html *)
  747. procedure Spherical_Cartesian(const r, theta, phi: double; var x, y, z: double;
  748. var ierr: integer);
  749. var
  750. a: double;
  751. begin
  752. if (r < 0.0) then
  753. ierr := 1
  754. else if ((theta < 0.0) or (theta >= 2 * pi)) then
  755. ierr := 2
  756. else if ((phi < 0.0) or (phi >= 2 * pi)) then
  757. ierr := 3
  758. else
  759. ierr := 0;
  760. if (ierr = 0) then
  761. begin
  762. SinCosine(phi, r, a, z); // z = r*cos(phi), a=r*sin(phi)
  763. SinCosine(theta, a, y, x); // x = a*cos(theta), y = a*sin(theta)}
  764. end;
  765. end;
  766. // ----- Cartesian_Spherical ---------------------------------------------------
  767. procedure Cartesian_Spherical(const x, y, z: single; var r, theta, phi: single);
  768. begin
  769. r := sqrt((x * x) + (y * y) + (z * z));
  770. theta := ArcTan2(y, x);
  771. phi := ArcCosine(z / r);
  772. end;
  773. procedure Cartesian_Spherical(const v: TAffineVector; var r, theta, phi: single);
  774. begin
  775. r := VectorLength(v);
  776. theta := ArcTan2(v.y, v.x);
  777. phi := ArcCosine(v.z / r);
  778. end;
  779. // ----- Cartesian_Spherical ---------------------------------------------------
  780. procedure Cartesian_Spherical(const x, y, z: double; var r, theta, phi: double);
  781. begin
  782. r := sqrt((x * x) + (y * y) + (z * z));
  783. theta := ArcTan2(y, x);
  784. phi := ArcCosine(z / r);
  785. end;
  786. // ----- ProlateSpheroidal_Cartesian -------------------------------------------
  787. procedure ProlateSpheroidal_Cartesian(const xi, eta, phi, a: single; var x, y, z: single);
  788. var
  789. sn, cs, snphi, csphi, shx, chx: single;
  790. begin
  791. SinCosine(eta, a, sn, cs);
  792. SinCosine(phi, snphi, csphi);
  793. shx := sinh(xi);
  794. chx := cosh(xi);
  795. x := sn * shx * csphi; // x = a*sin(eta)*sinh(xi)*cos(phi)
  796. y := sn * shx * snphi; // y = a*sin(eta)*sinh(xi)*sin(phi)
  797. z := cs * chx; // z = a*cos(eta)*cosh(xi)
  798. end;
  799. // ----- ProlateSpheroidal_Cartesian -------------------------------------------
  800. procedure ProlateSpheroidal_Cartesian(const xi, eta, phi, a: double; var x, y, z: double);
  801. var
  802. sn, cs, snphi, csphi, shx, chx: double;
  803. begin
  804. SinCosine(eta, a, sn, cs);
  805. SinCosine(phi, snphi, csphi);
  806. shx := sinh(xi);
  807. chx := cosh(xi);
  808. x := sn * shx * csphi; // x = a*sin(eta)*sinh(xi)*cos(phi)
  809. y := sn * shx * snphi; // y = a*sin(eta)*sinh(xi)*sin(phi)
  810. z := cs * chx; // z = a*cos(eta)*cosh(xi)
  811. end;
  812. // ----- ProlateSpheroidal_Cartesian -------------------------------------------
  813. procedure ProlateSpheroidal_Cartesian(const xi, eta, phi, a: single;
  814. var x, y, z: single; var ierr: integer); overload;
  815. var
  816. sn, cs, snphi, csphi, shx, chx: single;
  817. begin
  818. if (xi < 0.0) then
  819. ierr := 1
  820. else if ((eta < 0.0) or (eta > pi)) then
  821. ierr := 2
  822. else if ((phi < 0.0) or (phi >= 2 * pi)) then
  823. ierr := 3
  824. else
  825. ierr := 0;
  826. if (ierr = 0) then
  827. begin
  828. SinCosine(eta, a, sn, cs);
  829. SinCosine(phi, snphi, csphi);
  830. shx := sinh(xi);
  831. chx := cosh(xi);
  832. x := sn * shx * csphi; // x = a*sin(eta)*sinh(xi)*cos(phi)
  833. y := sn * shx * snphi; // y = a*sin(eta)*sinh(xi)*sin(phi)
  834. z := cs * chx; // z = a*cos(eta)*cosh(xi)
  835. end;
  836. end;
  837. // ----- ProlateSpheroidal_Cartesian -------------------------------------------
  838. procedure ProlateSpheroidal_Cartesian(const xi, eta, phi, a: double;
  839. var x, y, z: double; var ierr: integer); overload;
  840. var
  841. sn, cs, snphi, csphi, shx, chx: double;
  842. begin
  843. if (xi < 0.0) then
  844. ierr := 1
  845. else if ((eta < 0.0) or (eta > pi)) then
  846. ierr := 2
  847. else if ((phi < 0.0) or (phi >= 2 * pi)) then
  848. ierr := 3
  849. else
  850. ierr := 0;
  851. if (ierr = 0) then
  852. begin
  853. SinCosine(eta, a, sn, cs);
  854. SinCosine(phi, snphi, csphi);
  855. shx := sinh(xi);
  856. chx := cosh(xi);
  857. x := sn * shx * csphi; // x = a*sin(eta)*sinh(xi)*cos(phi)
  858. y := sn * shx * snphi; // y = a*sin(eta)*sinh(xi)*sin(phi)
  859. z := cs * chx; // z = a*cos(eta)*cosh(xi)
  860. end;
  861. end;
  862. // ----- OblateSpheroidal_Cartesian -------------------------------------------
  863. (* Convert Oblate-Spheroidal to Cartesian with no checks.
  864. A system of curvilinear coordinates in which two sets of coordinate surfaces are
  865. obtained by revolving the curves of the elliptic cylindrical coordinates about
  866. the y-axis which is relabeled the z-axis. The third set of coordinates consists
  867. of planes passing through this axis.
  868. The coordinate system is parameterised by parameter a. A default value of a=1 is
  869. suggesed:
  870. http://documents.wolfram.com/v4/AddOns/StandardPackages/Calculus/VectorAnalysis.html
  871. Ref: http://mathworld.wolfram.com/OblateSpheroidalCoordinates.html *)
  872. procedure OblateSpheroidal_Cartesian(const xi, eta, phi, a: single; var x, y, z: single);
  873. var
  874. sn, cs, snphi, csphi, shx, chx: single;
  875. begin
  876. SinCosine(eta, a, sn, cs);
  877. SinCosine(phi, snphi, csphi);
  878. shx := sinh(xi);
  879. chx := cosh(xi);
  880. x := cs * chx * csphi; // x = a*cos(eta)*cosh(xi)*cos(phi)
  881. y := cs * chx * snphi; // y = a*cos(eta)*cosh(xi)*sin(phi)
  882. z := sn * shx; // z = a*sin(eta)*sinh(xi)
  883. end;
  884. // ----- OblateSpheroidal_Cartesian -------------------------------------------
  885. (* Convert Oblate-Spheroidal to Cartesian with no checks. Double Version.
  886. A system of curvilinear coordinates in which two sets of coordinate surfaces are
  887. obtained by revolving the curves of the elliptic cylindrical coordinates about
  888. the y-axis which is relabeled the z-axis. The third set of coordinates consists
  889. of planes passing through this axis.
  890. The coordinate system is parameterised by parameter a. A default value of a=1 is
  891. suggesed:
  892. http://documents.wolfram.com/v4/AddOns/StandardPackages/Calculus/VectorAnalysis.html
  893. Ref: http://mathworld.wolfram.com/OblateSpheroidalCoordinates.html *)
  894. procedure OblateSpheroidal_Cartesian(const xi, eta, phi, a: double; var x, y, z: double);
  895. var
  896. sn, cs, snphi, csphi, shx, chx: double;
  897. begin
  898. SinCosine(eta, a, sn, cs);
  899. SinCosine(phi, snphi, csphi);
  900. shx := sinh(xi);
  901. chx := cosh(xi);
  902. x := cs * chx * csphi; // x = a*cos(eta)*cosh(xi)*cos(phi)
  903. y := cs * chx * snphi; // y = a*cos(eta)*cosh(xi)*sin(phi)
  904. z := sn * shx; // z = a*sin(eta)*sinh(xi)
  905. end;
  906. // ----- OblateSpheroidal_Cartesian -------------------------------------------
  907. (* Convert Oblate-Spheroidal to Cartesian with checks.
  908. ierr: [0] = ok,
  909. [1] = xi out of bounds. Acceptable xi: [0,inf)
  910. [2] = eta out of bounds. Acceptable eta: [-0.5*pi,0.5*pi]
  911. [3] = phi out of bounds. Acceptable phi: [0,2*pi)
  912. Ref: http://mathworld.wolfram.com/ProlateSpheroidalCoordinates.html *)
  913. procedure OblateSpheroidal_Cartesian(const xi, eta, phi, a: single;
  914. var x, y, z: single; var ierr: integer); overload;
  915. var
  916. sn, cs, snphi, csphi, shx, chx: single;
  917. begin
  918. if (xi < 0.0) then
  919. ierr := 1
  920. else if ((eta < -0.5 * pi) or (eta > 0.5 * pi)) then
  921. ierr := 2
  922. else if ((phi < 0.0) or (phi >= 2 * pi)) then
  923. ierr := 3
  924. else
  925. ierr := 0;
  926. if (ierr = 0) then
  927. begin
  928. SinCosine(eta, a, sn, cs);
  929. SinCosine(phi, snphi, csphi);
  930. shx := sinh(xi);
  931. chx := cosh(xi);
  932. x := cs * chx * csphi; // x = a*cos(eta)*cosh(xi)*cos(phi)
  933. y := cs * chx * snphi; // y = a*cos(eta)*cosh(xi)*sin(phi)
  934. z := sn * shx; // z = a*sin(eta)*sinh(xi)
  935. end;
  936. end;
  937. // ----- OblateSpheroidal_Cartesian -------------------------------------------
  938. procedure OblateSpheroidal_Cartesian(const xi, eta, phi, a: double;
  939. var x, y, z: double; var ierr: integer); overload;
  940. var
  941. sn, cs, snphi, csphi, shx, chx: double;
  942. begin
  943. if (xi < 0.0) then
  944. ierr := 1
  945. else if ((eta < -0.5 * pi) or (eta > 0.5 * pi)) then
  946. ierr := 2
  947. else if ((phi < 0.0) or (phi >= 2 * pi)) then
  948. ierr := 3
  949. else
  950. ierr := 0;
  951. if (ierr = 0) then
  952. begin
  953. SinCosine(eta, a, sn, cs);
  954. SinCosine(phi, snphi, csphi);
  955. shx := sinh(xi);
  956. chx := cosh(xi);
  957. x := cs * chx * csphi; // x = a*cos(eta)*cosh(xi)*cos(phi)
  958. y := cs * chx * snphi; // y = a*cos(eta)*cosh(xi)*sin(phi)
  959. z := sn * shx; // z = a*sin(eta)*sinh(xi)
  960. end;
  961. end;
  962. // ----- BipolarCylindrical_Cartesian ------------------------------------------
  963. (* Convert BiPolarCylindrical to Cartesian with no checks.
  964. http://mathworld.wolfram.com/BipolarCylindricalCoordinates.html *)
  965. procedure BipolarCylindrical_Cartesian(const u, v, z1, a: single; var x, y, z: single);
  966. var
  967. cs, sn, shx, chx: single;
  968. begin
  969. SinCosine(u, sn, cs);
  970. shx := sinh(v);
  971. chx := cosh(v);
  972. x := a * shx / (chx - cs);
  973. y := a * sn / (chx - cs);
  974. z := z1;
  975. end;
  976. // ----- BipolarCylindrical_Cartesian ------------------------------------------
  977. procedure BipolarCylindrical_Cartesian(const u, v, z1, a: double; var x, y, z: double);
  978. var
  979. cs, sn, shx, chx: double;
  980. begin
  981. SinCosine(u, sn, cs);
  982. shx := sinh(v);
  983. chx := cosh(v);
  984. x := a * shx / (chx - cs);
  985. y := a * sn / (chx - cs);
  986. z := z1;
  987. end;
  988. // ----- BipolarCylindrical_Cartesian ------------------------------------------
  989. (* Convert Oblate-Spheroidal to Cartesian with checks.
  990. ierr: [0] = ok,
  991. [1] = u out of bounds. Acceptable u: [0,2*pi)
  992. [2] = v out of bounds. Acceptable v: (-inf,inf)
  993. [3] = z1 out of bounds. Acceptable z1: (-inf,inf)
  994. Ref: http://mathworld.wolfram.com/BiPolarCylindricalCoordinates.html *)
  995. procedure BipolarCylindrical_Cartesian(const u, v, z1, a: single;
  996. var x, y, z: single; var ierr: integer); overload;
  997. var
  998. cs, sn, shx, chx: single;
  999. begin
  1000. if ((u < 0.0) or (u >= 2 * pi)) then
  1001. ierr := 1
  1002. else
  1003. ierr := 0;
  1004. if (ierr = 0) then
  1005. begin
  1006. SinCosine(u, sn, cs);
  1007. shx := sinh(v);
  1008. chx := cosh(v);
  1009. x := a * shx / (chx - cs);
  1010. y := a * sn / (chx - cs);
  1011. z := z1;
  1012. end;
  1013. end;
  1014. // ----- BipolarCylindrical_Cartesian ------------------------------------------
  1015. procedure BipolarCylindrical_Cartesian(const u, v, z1, a: double;
  1016. var x, y, z: double; var ierr: integer); overload;
  1017. var
  1018. cs, sn, shx, chx: double;
  1019. begin
  1020. if ((u < 0.0) or (u >= 2 * pi)) then
  1021. ierr := 1
  1022. else
  1023. ierr := 0;
  1024. if (ierr = 0) then
  1025. begin
  1026. SinCosine(u, sn, cs);
  1027. shx := sinh(v);
  1028. chx := cosh(v);
  1029. x := a * shx / (chx - cs);
  1030. y := a * sn / (chx - cs);
  1031. z := z1;
  1032. end;
  1033. end;
  1034. function BarycentricCoordinates(const V1, V2, V3, p: TAffineVector;
  1035. var u, V: Single): Boolean;
  1036. var
  1037. a1, a2: Integer;
  1038. n, e1, e2, pt: TAffineVector;
  1039. begin
  1040. // calculate edges
  1041. VectorSubtract(V1, V3, e1);
  1042. VectorSubtract(V2, V3, e2);
  1043. // calculate p relative to v3
  1044. VectorSubtract(p, V3, pt);
  1045. // find the dominant axis
  1046. n := VectorCrossProduct(e1, e2);
  1047. AbsVector(n);
  1048. a1 := 0;
  1049. if n.Y > n.V[a1] then
  1050. a1 := 1;
  1051. if n.Z > n.V[a1] then
  1052. a1 := 2;
  1053. // use dominant axis for projection
  1054. case a1 of
  1055. 0:
  1056. begin
  1057. a1 := 1;
  1058. a2 := 2;
  1059. end;
  1060. 1:
  1061. begin
  1062. a1 := 0;
  1063. a2 := 2;
  1064. end;
  1065. else // 2:
  1066. a1 := 0;
  1067. a2 := 1;
  1068. end;
  1069. // solve for u and v
  1070. u := (pt.V[a2] * e2.V[a1] - pt.V[a1] * e2.V[a2]) /
  1071. (e1.V[a2] * e2.V[a1] - e1.V[a1] * e2.V[a2]);
  1072. V := (pt.V[a2] * e1.V[a1] - pt.V[a1] * e1.V[a2]) /
  1073. (e2.V[a2] * e1.V[a1] - e2.V[a1] * e1.V[a2]);
  1074. result := (u >= 0) and (V >= 0) and (u + V <= 1);
  1075. end;
  1076. //=====================================================================
  1077. initialization
  1078. //=====================================================================
  1079. RegisterClasses([TGLCoordinates2, TGLCoordinates3, TGLCoordinates4]);
  1080. end.