GXS.Coordinates.pas 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189
  1. //
  2. // The graphics engine GXScene
  3. //
  4. unit GXS.Coordinates;
  5. (*
  6. Coordinate related classes and functions.
  7. The registered classes are:
  8. [TgxCoordinates2, TgxCoordinates3, TgxCoordinates4]
  9. *)
  10. interface
  11. {$I Stage.Defines.inc}
  12. uses
  13. System.Math,
  14. System.Classes,
  15. System.SysUtils,
  16. Stage.VectorGeometry,
  17. Stage.VectorTypes,
  18. GXS.BaseClasses;
  19. type
  20. (* Identifies the type of data stored within a TgxCustomCoordinates.
  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. TgxCoordinatesStyle = (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. TgxCustomCoordinates = class(TgxUpdateAbleObject)
  32. private
  33. FCoords: TGLVector;
  34. FStyle: TgxCoordinatesStyle; // 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: TgxCoordinatesStyle = 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 TgxCustomCoordinates for internal "assertion" checks
  64. to detect "misuses" or "misunderstandings" of what the homogeneous
  65. coordinates system implies. *)
  66. property Style: TgxCoordinatesStyle 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 TgxCustomCoordinates that publishes X, Y properties.
  121. TgxCoordinates2 = class(TgxCustomCoordinates)
  122. published
  123. property X stored False;
  124. property Y stored False;
  125. end;
  126. // A TgxCustomCoordinates that publishes X, Y, Z properties.
  127. TgxCoordinates3 = class(TgxCustomCoordinates)
  128. published
  129. property X stored False;
  130. property Y stored False;
  131. property Z stored False;
  132. end;
  133. // A TgxCustomCoordinates that publishes X, Y, Z, W properties.
  134. TgxCoordinates4 = class(TgxCustomCoordinates)
  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. TgxCoordinates = TgxCoordinates3;
  142. (* Actually Sender should be TgxCustomCoordinates, but that would require
  143. changes in a some other units and some other projects that use
  144. TgxCoordinatesUpdateAbleComponent *)
  145. IgxCoordinatesUpdateAble = interface(IInterface)
  146. ['{ACB98D20-8905-43A7-AFA5-225CF5FA6FF5}']
  147. procedure CoordinateChanged(Sender: TgxCustomCoordinates);
  148. end;
  149. TgxCoordinatesUpdateAbleComponent = class(TgxUpdateAbleComponent, IgxCoordinatesUpdateAble)
  150. public
  151. procedure CoordinateChanged(Sender: TgxCustomCoordinates); 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 TgxCustomCoordinates should allocate memory for
  293. their default values (ie. design-time) or not (run-time) *)
  294. VUseDefaultCoordinateSets: Boolean = False;
  295. implementation //-------------------------------------------------------------
  296. const
  297. csVectorHelp = 'When getting assertions here use the SetPoint procedure';
  298. csPointHelp = 'When getting assertions here use the SetVector procedure';
  299. csPoint2DHelp = 'When getting assertions here use one of the SetVector or SetPoint procedures';
  300. // ------------------
  301. // ------------------ TgxCustomCoordinates ------------------
  302. // ------------------
  303. constructor TgxCustomCoordinates.CreateInitialized(AOwner: TPersistent;
  304. const AValue: TGLVector; const AStyle: TgxCoordinatesStyle = CsUnknown);
  305. begin
  306. Create(AOwner);
  307. Initialize(AValue);
  308. FStyle := AStyle;
  309. end;
  310. destructor TgxCustomCoordinates.Destroy;
  311. begin
  312. if Assigned(FPDefaultCoords) then
  313. Dispose(FPDefaultCoords);
  314. inherited;
  315. end;
  316. procedure TgxCustomCoordinates.Initialize(const Value: TGLVector);
  317. begin
  318. FCoords := Value;
  319. if VUseDefaultCoordinateSets then
  320. begin
  321. if not Assigned(FPDefaultCoords) then
  322. New(FPDefaultCoords);
  323. FPDefaultCoords^ := Value;
  324. end;
  325. end;
  326. procedure TgxCustomCoordinates.Assign(Source: TPersistent);
  327. begin
  328. if Source is TgxCustomCoordinates then
  329. FCoords := TgxCustomCoordinates(Source).FCoords
  330. else
  331. inherited;
  332. end;
  333. procedure TgxCustomCoordinates.WriteToFiler(Writer: TWriter);
  334. var
  335. WriteCoords: Boolean;
  336. begin
  337. with Writer do
  338. begin
  339. WriteInteger(0); // Archive Version 0
  340. if VUseDefaultCoordinateSets then
  341. WriteCoords := not VectorEquals(FPDefaultCoords^, FCoords)
  342. else
  343. WriteCoords := True;
  344. WriteBoolean(WriteCoords);
  345. if WriteCoords then
  346. Write(FCoords.X, SizeOf(FCoords));
  347. end;
  348. end;
  349. procedure TgxCustomCoordinates.ReadFromFiler(Reader: TReader);
  350. var
  351. N: Integer;
  352. begin
  353. with Reader do
  354. begin
  355. ReadInteger; // Ignore ArchiveVersion
  356. if ReadBoolean then
  357. begin
  358. N := SizeOf(FCoords);
  359. Assert(N = 4 * SizeOf(Single));
  360. Read(FCoords.X, N);
  361. end
  362. else if Assigned(FPDefaultCoords) then
  363. FCoords := FPDefaultCoords^;
  364. end;
  365. end;
  366. procedure TgxCustomCoordinates.DefineProperties(Filer: TFiler);
  367. begin
  368. inherited;
  369. Filer.DefineBinaryProperty('Coordinates', ReadData, WriteData,
  370. not(Assigned(FPDefaultCoords) and VectorEquals(FPDefaultCoords^, FCoords)));
  371. end;
  372. procedure TgxCustomCoordinates.ReadData(Stream: TStream);
  373. begin
  374. Stream.Read(FCoords, SizeOf(FCoords));
  375. end;
  376. procedure TgxCustomCoordinates.WriteData(Stream: TStream);
  377. begin
  378. Stream.Write(FCoords, SizeOf(FCoords));
  379. end;
  380. procedure TgxCustomCoordinates.NotifyChange(Sender: TObject);
  381. var
  382. Int: IgxCoordinatesUpdateAble;
  383. begin
  384. if Supports(Owner, IgxCoordinatesUpdateAble, Int) then
  385. Int.CoordinateChanged(TgxCoordinates(Self));
  386. inherited NotifyChange(Sender);
  387. end;
  388. procedure TgxCustomCoordinates.Translate(const TranslationVector: TGLVector);
  389. begin
  390. FCoords.X := FCoords.X + TranslationVector.X;
  391. FCoords.Y := FCoords.Y + TranslationVector.Y;
  392. FCoords.Z := FCoords.Z + TranslationVector.Z;
  393. NotifyChange(Self);
  394. end;
  395. procedure TgxCustomCoordinates.Translate(const TranslationVector
  396. : TAffineVector);
  397. begin
  398. FCoords.X := FCoords.X + TranslationVector.X;
  399. FCoords.Y := FCoords.Y + TranslationVector.Y;
  400. FCoords.Z := FCoords.Z + TranslationVector.Z;
  401. NotifyChange(Self);
  402. end;
  403. procedure TgxCustomCoordinates.AddScaledVector(const Factor: Single;
  404. const TranslationVector: TGLVector);
  405. var
  406. F: Single;
  407. begin
  408. F := Factor;
  409. CombineVector(FCoords, TranslationVector, F);
  410. NotifyChange(Self);
  411. end;
  412. procedure TgxCustomCoordinates.AddScaledVector(const Factor: Single;
  413. const TranslationVector: TAffineVector);
  414. var
  415. F: Single;
  416. begin
  417. F := Factor;
  418. CombineVector(FCoords, TranslationVector, F);
  419. NotifyChange(Self);
  420. end;
  421. procedure TgxCustomCoordinates.Rotate(const AnAxis: TAffineVector;
  422. AnAngle: Single);
  423. begin
  424. RotateVector(FCoords, AnAxis, AnAngle);
  425. NotifyChange(Self);
  426. end;
  427. procedure TgxCustomCoordinates.Rotate(const AnAxis: TGLVector; AnAngle: Single);
  428. begin
  429. RotateVector(FCoords, AnAxis, AnAngle);
  430. NotifyChange(Self);
  431. end;
  432. procedure TgxCustomCoordinates.Normalize;
  433. begin
  434. NormalizeVector(FCoords);
  435. NotifyChange(Self);
  436. end;
  437. procedure TgxCustomCoordinates.Invert;
  438. begin
  439. NegateVector(FCoords);
  440. NotifyChange(Self);
  441. end;
  442. procedure TgxCustomCoordinates.Scale(Factor: Single);
  443. begin
  444. ScaleVector(PAffineVector(@FCoords)^, Factor);
  445. NotifyChange(Self);
  446. end;
  447. function TgxCustomCoordinates.VectorLength: Single;
  448. begin
  449. Result := Stage.VectorGeometry.VectorLength(FCoords);
  450. end;
  451. function TgxCustomCoordinates.VectorNorm: Single;
  452. begin
  453. Result := Stage.VectorGeometry.VectorNorm(FCoords);
  454. end;
  455. function TgxCustomCoordinates.MaxXYZ: Single;
  456. begin
  457. Result := MaxXYZComponent(FCoords);
  458. end;
  459. function TgxCustomCoordinates.Equals(const AVector: TGLVector): Boolean;
  460. begin
  461. Result := VectorEquals(FCoords, AVector);
  462. end;
  463. procedure TgxCustomCoordinates.SetVector(const X, Y: Single; Z: Single = 0);
  464. begin
  465. Assert(FStyle = csVector, csVectorHelp);
  466. Stage.VectorGeometry.SetVector(FCoords, X, Y, Z);
  467. NotifyChange(Self);
  468. end;
  469. procedure TgxCustomCoordinates.SetVector(const V: TAffineVector);
  470. begin
  471. Assert(FStyle = csVector, csVectorHelp);
  472. Stage.VectorGeometry.SetVector(FCoords, V);
  473. NotifyChange(Self);
  474. end;
  475. procedure TgxCustomCoordinates.SetVector(const V: TGLVector);
  476. begin
  477. Assert(FStyle = csVector, csVectorHelp);
  478. Stage.VectorGeometry.SetVector(FCoords, V);
  479. NotifyChange(Self);
  480. end;
  481. procedure TgxCustomCoordinates.SetVector(const X, Y, Z, W: Single);
  482. begin
  483. Assert(FStyle = csVector, csVectorHelp);
  484. Stage.VectorGeometry.SetVector(FCoords, X, Y, Z, W);
  485. NotifyChange(Self);
  486. end;
  487. procedure TgxCustomCoordinates.SetDirectCoordinate(const Index: Integer;
  488. const AValue: Single);
  489. begin
  490. FCoords.V[index] := AValue;
  491. end;
  492. procedure TgxCustomCoordinates.SetDirectVector(const V: TGLVector);
  493. begin
  494. FCoords.X := V.X;
  495. FCoords.Y := V.Y;
  496. FCoords.Z := V.Z;
  497. FCoords.W := V.W;
  498. end;
  499. procedure TgxCustomCoordinates.SetToZero;
  500. begin
  501. FCoords.X := 0;
  502. FCoords.Y := 0;
  503. FCoords.Z := 0;
  504. if FStyle = CsPoint then
  505. FCoords.W := 1
  506. else
  507. FCoords.W := 0;
  508. NotifyChange(Self);
  509. end;
  510. procedure TgxCustomCoordinates.SetPoint(const X, Y, Z: Single);
  511. begin
  512. Assert(FStyle = CsPoint, CsPointHelp);
  513. MakePoint(FCoords, X, Y, Z);
  514. NotifyChange(Self);
  515. end;
  516. procedure TgxCustomCoordinates.SetPoint(const V: TAffineVector);
  517. begin
  518. Assert(FStyle = CsPoint, CsPointHelp);
  519. MakePoint(FCoords, V);
  520. NotifyChange(Self);
  521. end;
  522. procedure TgxCustomCoordinates.SetPoint(const V: TGLVector);
  523. begin
  524. Assert(FStyle = CsPoint, CsPointHelp);
  525. MakePoint(FCoords, V);
  526. NotifyChange(Self);
  527. end;
  528. procedure TgxCustomCoordinates.SetPoint2D(const X, Y: Single);
  529. begin
  530. Assert(FStyle = CsPoint2D, CsPoint2DHelp);
  531. Stage.VectorGeometry.MakeVector(FCoords, X, Y, 0);
  532. NotifyChange(Self);
  533. end;
  534. procedure TgxCustomCoordinates.SetPoint2D(const Vector: TAffineVector);
  535. begin
  536. Assert(FStyle = CsPoint2D, CsPoint2DHelp);
  537. MakeVector(FCoords, Vector);
  538. NotifyChange(Self);
  539. end;
  540. procedure TgxCustomCoordinates.SetPoint2D(const Vector: TGLVector);
  541. begin
  542. Assert(FStyle = CsPoint2D, CsPoint2DHelp);
  543. MakeVector(FCoords, Vector);
  544. NotifyChange(Self);
  545. end;
  546. procedure TgxCustomCoordinates.SetPoint2D(const Vector: TVector2f);
  547. begin
  548. Assert(FStyle = CsPoint2D, CsPoint2DHelp);
  549. MakeVector(FCoords, Vector.X, Vector.Y, 0);
  550. NotifyChange(Self);
  551. end;
  552. function TgxCustomCoordinates.AsAddress: PSingle;
  553. begin
  554. Result := @FCoords;
  555. end;
  556. procedure TgxCustomCoordinates.SetAsVector(const Value: TGLVector);
  557. begin
  558. FCoords := Value;
  559. case FStyle of
  560. CsPoint2D:
  561. begin
  562. FCoords.Z := 0;
  563. FCoords.W := 0;
  564. end;
  565. CsPoint:
  566. FCoords.W := 1;
  567. CsVector:
  568. FCoords.W := 0;
  569. else
  570. Assert(False);
  571. end;
  572. NotifyChange(Self);
  573. end;
  574. procedure TgxCustomCoordinates.SetAsAffineVector(const Value: TAffineVector);
  575. begin
  576. case FStyle of
  577. CsPoint2D:
  578. MakeVector(FCoords, Value);
  579. CsPoint:
  580. MakePoint(FCoords, Value);
  581. CsVector:
  582. MakeVector(FCoords, Value);
  583. else
  584. Assert(False);
  585. end;
  586. NotifyChange(Self);
  587. end;
  588. procedure TgxCustomCoordinates.SetAsPoint2D(const Value: TVector2f);
  589. begin
  590. case FStyle of
  591. CsPoint2D, CsPoint, CsVector:
  592. begin
  593. FCoords.X := Value.X;
  594. FCoords.Y := Value.Y;
  595. FCoords.Z := 0;
  596. FCoords.W := 0;
  597. end;
  598. else
  599. Assert(False);
  600. end;
  601. NotifyChange(Self);
  602. end;
  603. function TgxCustomCoordinates.GetAsAffineVector: TAffineVector;
  604. begin
  605. Stage.VectorGeometry.SetVector(Result, FCoords);
  606. end;
  607. function TgxCustomCoordinates.GetAsPoint2D: TVector2f;
  608. begin
  609. Result.X := FCoords.X;
  610. Result.Y := FCoords.Y;
  611. end;
  612. procedure TgxCustomCoordinates.SetCoordinate(const AIndex: Integer;
  613. const AValue: Single);
  614. begin
  615. FCoords.V[AIndex] := AValue;
  616. NotifyChange(Self);
  617. end;
  618. function TgxCustomCoordinates.GetCoordinate(const AIndex: Integer): Single;
  619. begin
  620. Result := FCoords.V[AIndex];
  621. end;
  622. function TgxCustomCoordinates.GetDirectCoordinate(
  623. const Index: Integer): Single;
  624. begin
  625. Result := FCoords.V[index]
  626. end;
  627. function TgxCustomCoordinates.GetAsString: String;
  628. begin
  629. case Style of
  630. CsPoint2D:
  631. Result := Format('(%g; %g)', [FCoords.X, FCoords.Y]);
  632. CsPoint:
  633. Result := Format('(%g; %g; %g)', [FCoords.X, FCoords.Y, FCoords.Z]);
  634. CsVector:
  635. Result := Format('(%g; %g; %g; %g)', [FCoords.X, FCoords.Y, FCoords.Z,
  636. FCoords.W]);
  637. else
  638. Assert(False);
  639. end;
  640. end;
  641. // ----------------- Conversions of coordinates --------------------
  642. // ----------------- Cylindrical_Cartesian ----------------------
  643. procedure Cylindrical_Cartesian(const r, theta, z1: single; var x, y, z: single);
  644. begin
  645. SinCosine(theta, r, y, x);
  646. z := z1;
  647. end;
  648. // ----- Cylindrical_Cartesian -------------------------------------
  649. procedure Cylindrical_Cartesian(const r, theta, z1: double; var x, y, z: double);
  650. begin
  651. SinCosine(theta, r, y, x);
  652. z := z1;
  653. end;
  654. // ------------------ Cylindrical_Cartesian -----------------------
  655. procedure Cylindrical_Cartesian(const r, theta, z1: single; var x, y, z: single;
  656. var ierr: integer);
  657. begin
  658. // check input parameters
  659. if (r < 0.0) then
  660. ierr := 1
  661. else if ((theta < 0.0) or (theta >= 2 * pi)) then
  662. ierr := 2
  663. else
  664. ierr := 0;
  665. if (ierr = 0) then
  666. begin
  667. SinCosine(theta, r, y, x);
  668. z := z1;
  669. end;
  670. end;
  671. // ----- Cylindrical_Cartesian -------------------------------------------------
  672. procedure Cylindrical_Cartesian(const r, theta, z1: double; var x, y, z: double;
  673. var ierr: integer);
  674. begin
  675. // check input parameters
  676. if (r < 0.0) then
  677. ierr := 1
  678. else if ((theta < 0.0) or (theta >= 2 * pi)) then
  679. ierr := 2
  680. else
  681. ierr := 0;
  682. if (ierr = 0) then
  683. begin
  684. SinCosine(theta, r, y, x);
  685. z := z1;
  686. end;
  687. end;
  688. // ----- Cartesian_Cylindrical -------------------------------------------------
  689. procedure Cartesian_Cylindrical(const x, y, z1: single; var r, theta, z: single);
  690. begin
  691. r := sqrt(x * x + y * y);
  692. theta := ArcTan2(y, x);
  693. z := z1;
  694. end;
  695. // ----- Cartesian_Cylindrical -------------------------------------------------
  696. procedure Cartesian_Cylindrical(const x, y, z1: double; var r, theta, z: double);
  697. begin
  698. r := sqrt(x * x + y * y);
  699. theta := ArcTan2(y, x);
  700. z := z1;
  701. end;
  702. // ----- Spherical_Cartesian ---------------------------------------------------
  703. procedure Spherical_Cartesian(const r, theta, phi: single; var x, y, z: single);
  704. var
  705. a: single;
  706. begin
  707. SinCosine(phi, r, a, z); // z = r*cos(phi), a = r*sin(phi)
  708. SinCosine(theta, a, y, x); // x = a*cos(theta), y = a*sin(theta)}
  709. end;
  710. // ----- Spherical_Cartesian ---------------------------------------------------
  711. procedure Spherical_Cartesian(const r, theta, phi: double; var x, y, z: double);
  712. var
  713. a: double;
  714. begin
  715. SinCosine(phi, r, a, z); // z = r*cos(phi), a = r*sin(phi)
  716. SinCosine(theta, a, y, x); // x = a*cos(theta), y = a*sin(theta)}
  717. end;
  718. // ----- Spherical_Cartesian ---------------------------------------------------
  719. procedure Spherical_Cartesian(const r, theta, phi: single; var x, y, z: single;
  720. var ierr: integer);
  721. var
  722. a: single;
  723. begin
  724. if (r < 0.0) then
  725. ierr := 1
  726. else if ((theta < 0.0) or (theta >= 2 * pi)) then
  727. ierr := 2
  728. else if ((phi < 0.0) or (phi >= 2 * pi)) then
  729. ierr := 3
  730. else
  731. ierr := 0;
  732. if (ierr = 0) then
  733. begin
  734. SinCosine(phi, r, a, z); // z = r*cos(phi), a = r*sin(phi)
  735. SinCosine(theta, a, y, x); // x = a*cos(theta), y = a*sin(theta)}
  736. end;
  737. end;
  738. // ----- Spherical_Cartesian ---------------------------------------------------
  739. (* Convert Spherical to Cartesian with checks.
  740. ierr: [0] = ok,
  741. [1] = r out of bounds
  742. [2] = theta out of bounds
  743. [3] = phi out of bounds
  744. Ref: http://mathworld.wolfram.com/SphericalCoordinates.html *)
  745. procedure Spherical_Cartesian(const r, theta, phi: double; var x, y, z: double;
  746. var ierr: integer);
  747. var
  748. a: double;
  749. begin
  750. if (r < 0.0) then
  751. ierr := 1
  752. else if ((theta < 0.0) or (theta >= 2 * pi)) then
  753. ierr := 2
  754. else if ((phi < 0.0) or (phi >= 2 * pi)) then
  755. ierr := 3
  756. else
  757. ierr := 0;
  758. if (ierr = 0) then
  759. begin
  760. SinCosine(phi, r, a, z); // z = r*cos(phi), a=r*sin(phi)
  761. SinCosine(theta, a, y, x); // x = a*cos(theta), y = a*sin(theta)}
  762. end;
  763. end;
  764. // ----- Cartesian_Spherical ---------------------------------------------------
  765. procedure Cartesian_Spherical(const x, y, z: single; var r, theta, phi: single);
  766. begin
  767. r := sqrt((x * x) + (y * y) + (z * z));
  768. theta := ArcTan2(y, x);
  769. phi := ArcCosine(z / r);
  770. end;
  771. procedure Cartesian_Spherical(const v: TAffineVector; var r, theta, phi: single);
  772. begin
  773. r := VectorLength(v);
  774. theta := ArcTan2(v.y, v.x);
  775. phi := ArcCosine(v.z / r);
  776. end;
  777. // ----- Cartesian_Spherical ---------------------------------------------------
  778. procedure Cartesian_Spherical(const x, y, z: double; var r, theta, phi: double);
  779. begin
  780. r := sqrt((x * x) + (y * y) + (z * z));
  781. theta := ArcTan2(y, x);
  782. phi := ArcCosine(z / r);
  783. end;
  784. // ----- ProlateSpheroidal_Cartesian -------------------------------------------
  785. procedure ProlateSpheroidal_Cartesian(const xi, eta, phi, a: single; var x, y, z: single);
  786. var
  787. sn, cs, snphi, csphi, shx, chx: single;
  788. begin
  789. SinCosine(eta, a, sn, cs);
  790. SinCosine(phi, snphi, csphi);
  791. shx := sinh(xi);
  792. chx := cosh(xi);
  793. x := sn * shx * csphi; // x = a*sin(eta)*sinh(xi)*cos(phi)
  794. y := sn * shx * snphi; // y = a*sin(eta)*sinh(xi)*sin(phi)
  795. z := cs * chx; // z = a*cos(eta)*cosh(xi)
  796. end;
  797. // ----- ProlateSpheroidal_Cartesian -------------------------------------------
  798. procedure ProlateSpheroidal_Cartesian(const xi, eta, phi, a: double; var x, y, z: double);
  799. var
  800. sn, cs, snphi, csphi, shx, chx: double;
  801. begin
  802. SinCosine(eta, a, sn, cs);
  803. SinCosine(phi, snphi, csphi);
  804. shx := sinh(xi);
  805. chx := cosh(xi);
  806. x := sn * shx * csphi; // x = a*sin(eta)*sinh(xi)*cos(phi)
  807. y := sn * shx * snphi; // y = a*sin(eta)*sinh(xi)*sin(phi)
  808. z := cs * chx; // z = a*cos(eta)*cosh(xi)
  809. end;
  810. // ----- ProlateSpheroidal_Cartesian -------------------------------------------
  811. procedure ProlateSpheroidal_Cartesian(const xi, eta, phi, a: single;
  812. var x, y, z: single; var ierr: integer); overload;
  813. var
  814. sn, cs, snphi, csphi, shx, chx: single;
  815. begin
  816. if (xi < 0.0) then
  817. ierr := 1
  818. else if ((eta < 0.0) or (eta > pi)) then
  819. ierr := 2
  820. else if ((phi < 0.0) or (phi >= 2 * pi)) then
  821. ierr := 3
  822. else
  823. ierr := 0;
  824. if (ierr = 0) then
  825. begin
  826. SinCosine(eta, a, sn, cs);
  827. SinCosine(phi, snphi, csphi);
  828. shx := sinh(xi);
  829. chx := cosh(xi);
  830. x := sn * shx * csphi; // x = a*sin(eta)*sinh(xi)*cos(phi)
  831. y := sn * shx * snphi; // y = a*sin(eta)*sinh(xi)*sin(phi)
  832. z := cs * chx; // z = a*cos(eta)*cosh(xi)
  833. end;
  834. end;
  835. // ----- ProlateSpheroidal_Cartesian -------------------------------------------
  836. procedure ProlateSpheroidal_Cartesian(const xi, eta, phi, a: double;
  837. var x, y, z: double; var ierr: integer); overload;
  838. var
  839. sn, cs, snphi, csphi, shx, chx: double;
  840. begin
  841. if (xi < 0.0) then
  842. ierr := 1
  843. else if ((eta < 0.0) or (eta > pi)) then
  844. ierr := 2
  845. else if ((phi < 0.0) or (phi >= 2 * pi)) then
  846. ierr := 3
  847. else
  848. ierr := 0;
  849. if (ierr = 0) then
  850. begin
  851. SinCosine(eta, a, sn, cs);
  852. SinCosine(phi, snphi, csphi);
  853. shx := sinh(xi);
  854. chx := cosh(xi);
  855. x := sn * shx * csphi; // x = a*sin(eta)*sinh(xi)*cos(phi)
  856. y := sn * shx * snphi; // y = a*sin(eta)*sinh(xi)*sin(phi)
  857. z := cs * chx; // z = a*cos(eta)*cosh(xi)
  858. end;
  859. end;
  860. // ----- OblateSpheroidal_Cartesian -------------------------------------------
  861. (* Convert Oblate-Spheroidal to Cartesian with no checks.
  862. A system of curvilinear coordinates in which two sets of coordinate surfaces are
  863. obtained by revolving the curves of the elliptic cylindrical coordinates about
  864. the y-axis which is relabeled the z-axis. The third set of coordinates consists
  865. of planes passing through this axis.
  866. The coordinate system is parameterised by parameter a. A default value of a=1 is
  867. suggesed:
  868. http://documents.wolfram.com/v4/AddOns/StandardPackages/Calculus/VectorAnalysis.html
  869. Ref: http://mathworld.wolfram.com/OblateSpheroidalCoordinates.html *)
  870. procedure OblateSpheroidal_Cartesian(const xi, eta, phi, a: single; var x, y, z: single);
  871. var
  872. sn, cs, snphi, csphi, shx, chx: single;
  873. begin
  874. SinCosine(eta, a, sn, cs);
  875. SinCosine(phi, snphi, csphi);
  876. shx := sinh(xi);
  877. chx := cosh(xi);
  878. x := cs * chx * csphi; // x = a*cos(eta)*cosh(xi)*cos(phi)
  879. y := cs * chx * snphi; // y = a*cos(eta)*cosh(xi)*sin(phi)
  880. z := sn * shx; // z = a*sin(eta)*sinh(xi)
  881. end;
  882. // ----- OblateSpheroidal_Cartesian -------------------------------------------
  883. (* Convert Oblate-Spheroidal to Cartesian with no checks. Double Version.
  884. A system of curvilinear coordinates in which two sets of coordinate surfaces are
  885. obtained by revolving the curves of the elliptic cylindrical coordinates about
  886. the y-axis which is relabeled the z-axis. The third set of coordinates consists
  887. of planes passing through this axis.
  888. The coordinate system is parameterised by parameter a. A default value of a=1 is
  889. suggesed:
  890. http://documents.wolfram.com/v4/AddOns/StandardPackages/Calculus/VectorAnalysis.html
  891. Ref: http://mathworld.wolfram.com/OblateSpheroidalCoordinates.html *)
  892. procedure OblateSpheroidal_Cartesian(const xi, eta, phi, a: double; var x, y, z: double);
  893. var
  894. sn, cs, snphi, csphi, shx, chx: double;
  895. begin
  896. SinCosine(eta, a, sn, cs);
  897. SinCosine(phi, snphi, csphi);
  898. shx := sinh(xi);
  899. chx := cosh(xi);
  900. x := cs * chx * csphi; // x = a*cos(eta)*cosh(xi)*cos(phi)
  901. y := cs * chx * snphi; // y = a*cos(eta)*cosh(xi)*sin(phi)
  902. z := sn * shx; // z = a*sin(eta)*sinh(xi)
  903. end;
  904. // ----- OblateSpheroidal_Cartesian -------------------------------------------
  905. (* Convert Oblate-Spheroidal to Cartesian with checks.
  906. ierr: [0] = ok,
  907. [1] = xi out of bounds. Acceptable xi: [0,inf)
  908. [2] = eta out of bounds. Acceptable eta: [-0.5*pi,0.5*pi]
  909. [3] = phi out of bounds. Acceptable phi: [0,2*pi)
  910. Ref: http://mathworld.wolfram.com/ProlateSpheroidalCoordinates.html *)
  911. procedure OblateSpheroidal_Cartesian(const xi, eta, phi, a: single;
  912. var x, y, z: single; var ierr: integer); overload;
  913. var
  914. sn, cs, snphi, csphi, shx, chx: single;
  915. begin
  916. if (xi < 0.0) then
  917. ierr := 1
  918. else if ((eta < -0.5 * pi) or (eta > 0.5 * pi)) then
  919. ierr := 2
  920. else if ((phi < 0.0) or (phi >= 2 * pi)) then
  921. ierr := 3
  922. else
  923. ierr := 0;
  924. if (ierr = 0) then
  925. begin
  926. SinCosine(eta, a, sn, cs);
  927. SinCosine(phi, snphi, csphi);
  928. shx := sinh(xi);
  929. chx := cosh(xi);
  930. x := cs * chx * csphi; // x = a*cos(eta)*cosh(xi)*cos(phi)
  931. y := cs * chx * snphi; // y = a*cos(eta)*cosh(xi)*sin(phi)
  932. z := sn * shx; // z = a*sin(eta)*sinh(xi)
  933. end;
  934. end;
  935. // ----- OblateSpheroidal_Cartesian -------------------------------------------
  936. procedure OblateSpheroidal_Cartesian(const xi, eta, phi, a: double;
  937. var x, y, z: double; var ierr: integer); overload;
  938. var
  939. sn, cs, snphi, csphi, shx, chx: double;
  940. begin
  941. if (xi < 0.0) then
  942. ierr := 1
  943. else if ((eta < -0.5 * pi) or (eta > 0.5 * pi)) then
  944. ierr := 2
  945. else if ((phi < 0.0) or (phi >= 2 * pi)) then
  946. ierr := 3
  947. else
  948. ierr := 0;
  949. if (ierr = 0) then
  950. begin
  951. SinCosine(eta, a, sn, cs);
  952. SinCosine(phi, snphi, csphi);
  953. shx := sinh(xi);
  954. chx := cosh(xi);
  955. x := cs * chx * csphi; // x = a*cos(eta)*cosh(xi)*cos(phi)
  956. y := cs * chx * snphi; // y = a*cos(eta)*cosh(xi)*sin(phi)
  957. z := sn * shx; // z = a*sin(eta)*sinh(xi)
  958. end;
  959. end;
  960. // ----- BipolarCylindrical_Cartesian ------------------------------------------
  961. (* Convert BiPolarCylindrical to Cartesian with no checks.
  962. http://mathworld.wolfram.com/BipolarCylindricalCoordinates.html *)
  963. procedure BipolarCylindrical_Cartesian(const u, v, z1, a: single; var x, y, z: single);
  964. var
  965. cs, sn, shx, chx: single;
  966. begin
  967. SinCosine(u, sn, cs);
  968. shx := sinh(v);
  969. chx := cosh(v);
  970. x := a * shx / (chx - cs);
  971. y := a * sn / (chx - cs);
  972. z := z1;
  973. end;
  974. // ----- BipolarCylindrical_Cartesian ------------------------------------------
  975. procedure BipolarCylindrical_Cartesian(const u, v, z1, a: double; var x, y, z: double);
  976. var
  977. cs, sn, shx, chx: double;
  978. begin
  979. SinCosine(u, sn, cs);
  980. shx := sinh(v);
  981. chx := cosh(v);
  982. x := a * shx / (chx - cs);
  983. y := a * sn / (chx - cs);
  984. z := z1;
  985. end;
  986. // ----- BipolarCylindrical_Cartesian ------------------------------------------
  987. (* Convert Oblate-Spheroidal to Cartesian with checks.
  988. ierr: [0] = ok,
  989. [1] = u out of bounds. Acceptable u: [0,2*pi)
  990. [2] = v out of bounds. Acceptable v: (-inf,inf)
  991. [3] = z1 out of bounds. Acceptable z1: (-inf,inf)
  992. Ref: http://mathworld.wolfram.com/BiPolarCylindricalCoordinates.html *)
  993. procedure BipolarCylindrical_Cartesian(const u, v, z1, a: single;
  994. var x, y, z: single; var ierr: integer); overload;
  995. var
  996. cs, sn, shx, chx: single;
  997. begin
  998. if ((u < 0.0) or (u >= 2 * pi)) then
  999. ierr := 1
  1000. else
  1001. ierr := 0;
  1002. if (ierr = 0) then
  1003. begin
  1004. SinCosine(u, sn, cs);
  1005. shx := sinh(v);
  1006. chx := cosh(v);
  1007. x := a * shx / (chx - cs);
  1008. y := a * sn / (chx - cs);
  1009. z := z1;
  1010. end;
  1011. end;
  1012. // ----- BipolarCylindrical_Cartesian ------------------------------------------
  1013. procedure BipolarCylindrical_Cartesian(const u, v, z1, a: double;
  1014. var x, y, z: double; var ierr: integer); overload;
  1015. var
  1016. cs, sn, shx, chx: double;
  1017. begin
  1018. if ((u < 0.0) or (u >= 2 * pi)) then
  1019. ierr := 1
  1020. else
  1021. ierr := 0;
  1022. if (ierr = 0) then
  1023. begin
  1024. SinCosine(u, sn, cs);
  1025. shx := sinh(v);
  1026. chx := cosh(v);
  1027. x := a * shx / (chx - cs);
  1028. y := a * sn / (chx - cs);
  1029. z := z1;
  1030. end;
  1031. end;
  1032. function BarycentricCoordinates(const V1, V2, V3, p: TAffineVector;
  1033. var u, V: Single): Boolean;
  1034. var
  1035. a1, a2: Integer;
  1036. n, e1, e2, pt: TAffineVector;
  1037. begin
  1038. // calculate edges
  1039. VectorSubtract(V1, V3, e1);
  1040. VectorSubtract(V2, V3, e2);
  1041. // calculate p relative to v3
  1042. VectorSubtract(p, V3, pt);
  1043. // find the dominant axis
  1044. n := VectorCrossProduct(e1, e2);
  1045. AbsVector(n);
  1046. a1 := 0;
  1047. if n.Y > n.V[a1] then
  1048. a1 := 1;
  1049. if n.Z > n.V[a1] then
  1050. a1 := 2;
  1051. // use dominant axis for projection
  1052. case a1 of
  1053. 0:
  1054. begin
  1055. a1 := 1;
  1056. a2 := 2;
  1057. end;
  1058. 1:
  1059. begin
  1060. a1 := 0;
  1061. a2 := 2;
  1062. end;
  1063. else // 2:
  1064. a1 := 0;
  1065. a2 := 1;
  1066. end;
  1067. // solve for u and v
  1068. u := (pt.V[a2] * e2.V[a1] - pt.V[a1] * e2.V[a2]) /
  1069. (e1.V[a2] * e2.V[a1] - e1.V[a1] * e2.V[a2]);
  1070. V := (pt.V[a2] * e1.V[a1] - pt.V[a1] * e1.V[a2]) /
  1071. (e2.V[a2] * e1.V[a1] - e2.V[a1] * e1.V[a2]);
  1072. result := (u >= 0) and (V >= 0) and (u + V <= 1);
  1073. end;
  1074. initialization //------------------------------------------------------------
  1075. RegisterClasses([TgxCoordinates2, TgxCoordinates3, TgxCoordinates4]);
  1076. finalization //--------------------------------------------------------------
  1077. // UnRegisterClasses([TgxCoordinates2, TgxCoordinates3, TgxCoordinates4]);
  1078. end.