GLS.Coordinates.pas 38 KB

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