GXS.SailSurface.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. unit GXS.SailSurface;
  2. (*
  3. TgxSailSurface - Sail surface 3d object by oMAR
  4. *)
  5. interface
  6. uses
  7. System.SysUtils,
  8. System.Classes,
  9. System.Math.Vectors,
  10. System.Threading,
  11. System.Types,
  12. System.Generics.Collections,
  13. System.RTLConsts,
  14. FMX.Types3D,
  15. FMX.Types,
  16. FMX.Controls3D,
  17. FMX.Objects3D,
  18. FMX.MaterialSources;
  19. type
  20. TSailShape = (ShapeMain, ShapeSimetric, ShapeJib); // sail plans
  21. (* --------------------------------------------------------------------------
  22. Sail construction params
  23. ^ h ^ h ^ h
  24. | Main | Simetric | Jib
  25. Ht +----+ Ht +---+ Lt Ht +---+
  26. | Lt \ / | \ |Lt \
  27. | \ / | \ | \
  28. | \ / | \ | \
  29. | \ / | \ | \
  30. | \ / | \ | \
  31. | \ / | \ | \
  32. +-----------+ +-----------------+ +----------+
  33. | Lm \ / | Lm \ | Lm \
  34. | | | | | | \
  35. | \ | | | | Lx \
  36. | | \ | / Hx +--------------+ <-- h of max chord
  37. | \ | | | | ____/
  38. 0 | Lb | | 0 | Lb | 0 | ____/
  39. ----+--------------+--> L -+--------+--------+--> L ----+___/-------------> L
  40. Lb
  41. nh subdivisions in height
  42. nl subdivisions in chord
  43. ---------------------------------------------------------------------------
  44. *)
  45. TPointF_Array = array of TPointF;
  46. TSailParams = record // Sail w/ quadratic leech
  47. Lb: Single; // sail chord at the bottom
  48. Lt: Single; // chord at the top
  49. Lm: Single; // chord at the middle ( for a quadratic leech )
  50. Ht: Single; // sail height
  51. // for Jib Shape only
  52. Hx: Single; // height of Jib max chord
  53. Lx: Single; // Jib max chord
  54. // NsubH:integer; // subdivisions in height default = 16hx8w
  55. // NsubL:integer; // subdivisions in chord
  56. // chord at a certain height ( H between 0 and Ht )
  57. function GetSailChord(aType: TSailShape; const H: Single): Single;
  58. end;
  59. (*
  60. TgxSailSurface morphs a TPlane grid into a triangular sail with camber
  61. ( or any other polygonal Shape)
  62. *)
  63. TgxSailSurface = class(TPlane)
  64. private
  65. fSailShape: TSailShape;
  66. fVersion: integer;
  67. function GetChordBottom: Single;
  68. function GetChordMid: Single;
  69. function GetChordTop: Single;
  70. function GetSailHeight: Single;
  71. procedure SetChordBottom(const Value: Single);
  72. procedure SetChordMid(const Value: Single);
  73. procedure SetChordTop(const Value: Single);
  74. procedure SetSailHeight(const Value: Single);
  75. procedure SetSailShape(const Value: TSailShape);
  76. procedure CalcSailSurfaceMesh;
  77. function GetChordX: Single;
  78. function GetHeightX: Single;
  79. procedure SetChordX(const Value: Single);
  80. procedure SetHeightX(const Value: Single);
  81. procedure setVersion(const Value: integer);
  82. protected
  83. fTime: Single; // Om: movd stuff to protected
  84. fNbMesh: integer; // number of tiles in the mesh
  85. fSailParams: TSailParams;
  86. fShowlines, fUseTasks: boolean;
  87. fMaterialLignes: TColorMaterialSource;
  88. fCenter: TPoint3D;
  89. fCamberRight: boolean; // true = sail camber to the right
  90. procedure SetDepth(const Value: Single); override;
  91. public
  92. constructor Create(AOwner: TComponent); override;
  93. destructor Destroy; override;
  94. procedure Render; override;
  95. // Property Data; //om: publica
  96. function Altura(P: TPoint3D): Single; // Om: calc wave amplitude on a point
  97. procedure SetSailParams(aSailParams: TSailParams);
  98. procedure SetMeshWith2Dline(aPtArray: TPointF_Array);
  99. published
  100. property ShowLines: boolean read fShowlines write fShowlines;
  101. property UseTasks: boolean read fUseTasks write fUseTasks;
  102. property MaterialLines: TColorMaterialSource read fMaterialLignes
  103. write fMaterialLignes;
  104. property SailShape: TSailShape read fSailShape write SetSailShape
  105. default ShapeMain; // main sail, jib or simetric shape
  106. property CamberRight: boolean read fCamberRight write fCamberRight;
  107. property SailHeight: Single read GetSailHeight write SetSailHeight;
  108. property ChordTop: Single read GetChordTop write SetChordTop;
  109. property ChordMid: Single read GetChordMid write SetChordMid;
  110. property ChordBottom: Single read GetChordBottom write SetChordBottom;
  111. // Jib style only
  112. property HeightX: Single read GetHeightX write SetHeightX;
  113. property ChordX: Single read GetChordX write SetChordX;
  114. property version: integer read fVersion write setVersion;
  115. end;
  116. // Quadratic interpolation with 3 points
  117. function CalcQuadraticInterpolation(const x0, y0, x1, y1, x2, y2: Single;
  118. const x: Single; { out: } var y: Single): boolean;
  119. procedure Register;
  120. implementation // ------------------------------------------------------------
  121. // quadratic interpolation w/ 3 points
  122. // from: https://slideplayer.com/slide/4897028/ search Quadratic interpolation slide
  123. //
  124. // y | --*--
  125. // | / 1 \
  126. // | *0 *2
  127. // | / \ x
  128. // +------------------>
  129. //
  130. // y(x) = b0+b1(x-x0)+b2(x-x0)(x-x1)
  131. // b0 = y0
  132. // b1 = (y1-y0)/(x1-x0)
  133. // b2 = ((y2-y1)/(x2-x1)-(y1-y0)/(x1-x0)) / (x2-x0)
  134. function CalcQuadraticInterpolation(const x0, y0, x1, y1, x2, y2: Single;
  135. const x: Single; var y: Single): boolean;
  136. var
  137. b0, b1, b2, dx10, dx21, dx20: Single;
  138. begin
  139. dx10 := (x1 - x0);
  140. dx21 := (x2 - x1);
  141. dx20 := (x2 - x0);
  142. Result := (dx10 <> 0) and (dx21 <> 0) and (dx20 <> 0);
  143. // sanity test. Cannot calc if two of the points have same x
  144. if Result then
  145. begin
  146. b0 := y0;
  147. b1 := (y1 - y0) / dx10;
  148. b2 := ((y2 - y1) / dx21 - (y1 - y0) / dx10) / dx20;
  149. y := b0 + b1 * (x - x0) + b2 * (x - x0) * (x - x1); // return y
  150. end;
  151. end;
  152. { TSailParams }
  153. // calc chord at a certain height, using a quadratic leech
  154. function TSailParams.GetSailChord(aType: TSailShape; const H: Single): Single;
  155. // in m
  156. var
  157. y: Single;
  158. begin
  159. Result := 0;
  160. if (Ht <= 0) or (H < 0) or (H > Ht) then
  161. exit; // sanity test
  162. case aType of
  163. ShapeMain:
  164. begin
  165. // was Result := Lb-(Lb-Lt)*H/Ht // was: linear leech from bot to top
  166. // quadratic interpolation of L in H using points Lt,Lm,Lb ( top, mid, bottom chords)
  167. if CalcQuadraticInterpolation( { 0: } 0, Lb, { 1: } Ht / 2, Lm,
  168. { 2: } Ht, Lt, { H: } H, { out: } y) then
  169. Result := y // quadratic leech
  170. else
  171. Result := 0;
  172. end;
  173. ShapeJib:
  174. begin // 'jibs' have max sail width at a certain height 'x'
  175. if (H < Hx) then
  176. Result := Lb - (Lb - Lx) * H / Hx // below Hx linear from Lb to Lx
  177. else
  178. begin
  179. if CalcQuadraticInterpolation( { 0: } Hx, Lx, { 1: } Ht / 2, Lm,
  180. { 2: } Ht, Lt, { H: } H, { out: } y) then
  181. Result := y // quadratic leech
  182. else
  183. Result := 0;
  184. end;
  185. end;
  186. ShapeSimetric:
  187. begin
  188. // quadratic interpolation of L in H using points Lt,Lm,Lb ( top, mid, bottom chords)
  189. if CalcQuadraticInterpolation( { 0: } 0, Lb, { 1: } Ht / 2, Lm,
  190. { {2: } Ht, Lt, { H: } H, { out: } y) then
  191. Result := y // quadratic leech
  192. else
  193. Result := 0;
  194. end;
  195. else
  196. Result := 0; // wtf ??
  197. end;
  198. end;
  199. // TgxSailSurface
  200. constructor TgxSailSurface.Create(AOwner: TComponent);
  201. begin
  202. inherited;
  203. fSailShape := ShapeMain; // default sail type = main sail
  204. // set default sail params ( see diagrams on the top )
  205. // chords
  206. fSailParams.Lt := 0.8; // Lt:sail chord at the top
  207. fSailParams.Lm := 2.65; // Lm chord at mid (0.8+3.5)/2+0.5=2.65
  208. fSailParams.Lb := 3.5; // Lb:sail chord at the bottom
  209. // sail height
  210. fSailParams.Ht := 10.0; // Ht:sail height
  211. // params for Jibs only
  212. fSailParams.Hx := 1.0;
  213. fSailParams.Lx := 3.5;
  214. // number of subds more or less to have square sail "tiles"
  215. // fSailParams.NsubH := 10; // 1x1 aspect sail
  216. // fSailParams.NsubL := 10;
  217. // set plane subdivisions
  218. // self.Width := fSailParams.Lb; // dont mess with original size
  219. // self.Height := fSailParams.Ht;
  220. // self.Depth := 5; //??
  221. // h=10 w=16 comes from OPYC simulation
  222. // actually OPYC sails have varied number of segments, according to sail size ( from 8 jib to 16 spinaker )
  223. self.SubdivisionsHeight := 10; // set plane subdivisions
  224. self.SubdivisionsWidth := 16;
  225. fNbMesh := (SubdivisionsWidth + 1) * (SubdivisionsHeight + 1);
  226. // mesh number of vertices
  227. // what fCenter center means is a question
  228. // = NSubDiv/Width --> unit = subdiv/m
  229. fCenter := Point3D(SubdivisionsWidth / self.Width,
  230. SubdivisionsHeight / self.Height, 0);
  231. fCamberRight := true; // side of the fake sail canvas
  232. fUseTasks := true; // default= using tasks
  233. fVersion := 1;
  234. end;
  235. destructor TgxSailSurface.Destroy;
  236. begin
  237. inherited;
  238. end;
  239. function TgxSailSurface.GetChordBottom: Single;
  240. begin
  241. Result := fSailParams.Lb;
  242. end;
  243. function TgxSailSurface.GetChordMid: Single;
  244. begin
  245. Result := fSailParams.Lm;
  246. end;
  247. function TgxSailSurface.GetChordTop: Single;
  248. begin
  249. Result := fSailParams.Lt;
  250. end;
  251. function TgxSailSurface.GetChordX: Single;
  252. begin
  253. Result := fSailParams.Lx;
  254. end;
  255. function TgxSailSurface.GetHeightX: Single;
  256. begin
  257. Result := fSailParams.Hx;
  258. end;
  259. function TgxSailSurface.GetSailHeight: Single;
  260. begin
  261. Result := fSailParams.ht;
  262. end;
  263. procedure TgxSailSurface.SetDepth(const Value: Single);
  264. // override TPlane tendency to set Depth to 0.01
  265. begin
  266. if (self.fDepth <> Value) then // this copies what TPlane removed
  267. begin
  268. self.fDepth := Value;
  269. Resize3D;
  270. if (fDepth < 0) and (csDesigning in ComponentState) then
  271. begin
  272. fDepth := abs(fDepth);
  273. FScale.Z := -FScale.Z;
  274. end;
  275. if not(csLoading in ComponentState) then
  276. Repaint;
  277. end;
  278. end;
  279. // Calc sail surface mesh based on a line of points in 2D (planta)
  280. Procedure TgxSailSurface.SetMeshWith2Dline(aPtArray: TPointF_Array);
  281. var
  282. M: TMeshData;
  283. x, y, np: integer;
  284. somme: Single;
  285. front, back: PPoint3D;
  286. h, hinM, Dh, chord, chordFrac, L, Z, maxChord, sh2, sw2, ax, ay,
  287. aSailWidth: Single;
  288. aPt: PPointF;
  289. begin
  290. // sail params sanity test
  291. if (SubdivisionsHeight <= 0) or (SubdivisionsWidth <= 0) then
  292. exit; // invalid subdiv values
  293. if Width = 0 then
  294. exit;
  295. M := self.Data; // use default TPlane mesh
  296. fNbMesh := (SubdivisionsWidth + 1) * (SubdivisionsHeight + 1);
  297. // recalc mesh number of vertices
  298. // mesh is calculated to fit into [-0.5,-0.5..0.5,0.5] interval. Actual sail dimensions are set with objects Width,Height,Depth
  299. if (fSailParams.Lm > fSailParams.Lb) then
  300. aSailWidth := fSailParams.Lm // get max width
  301. else
  302. aSailWidth := fSailParams.Lb;
  303. sh2 := fSailParams.Ht / 2;
  304. sw2 := aSailWidth / 2;
  305. h := -0.5; // start at the foot
  306. Dh := 1.0 / SubdivisionsHeight; // was Dh := fSailParams.Ht/fSailParams.NsubH;
  307. np := Length(aPtArray); // number of pts received
  308. // set maxChord ( max sail width )
  309. case fSailShape of
  310. ShapeMain:
  311. maxChord := fSailParams.Lb;
  312. ShapeJib:
  313. maxChord := fSailParams.Lx;
  314. ShapeSimetric:
  315. maxChord := fSailParams.Lm; // or Lb?
  316. else
  317. maxChord := 1;
  318. end;
  319. for y := 0 to SubdivisionsHeight do
  320. begin
  321. // calc DL
  322. hinM := (h + 0.5) * fSailParams.Ht; // h in m
  323. chord := fSailParams.GetSailChord(fSailShape, hinM);
  324. // sail chord for h in m
  325. // if (chord<=0) then continue; //??
  326. chordFrac := chord / maxChord; // frac of maxChord in m
  327. // sail simetry is controlled by where the mesh line starts
  328. case fSailShape of // x of sail mesh start
  329. ShapeMain, ShapeJib:
  330. L := 0;
  331. ShapeSimetric:
  332. L := -chord / 2; // 0 is the sail middle. Start line at x=0-chord/2
  333. else
  334. L := -0.5; // wtf ??
  335. end;
  336. for x := 0 to SubdivisionsWidth do
  337. begin
  338. front := M.VertexBuffer.VerticesPtr[x + (y * (SubdivisionsWidth + 1))];
  339. back := M.VertexBuffer.VerticesPtr
  340. [fNbMesh + x + (y * (SubdivisionsWidth + 1))];
  341. if (x < np) then
  342. aPt := @aPtArray[x]
  343. // np-1 must be = to SubdivisionsWidth ( remesh if necessary )
  344. else
  345. aPt := @aPtArray[np - 1];
  346. ax := L - aPt^.y * chordFrac; // x <--> y scale conversion
  347. ay := L - aPt^.x * chordFrac; // y negative means sail pointing backw
  348. front^.x := ax; // x,y of the mesh always in -0.5,-0.5 .. 0.5,0.5
  349. front^.y := h;
  350. front^.Z := ay; // x,y of the mesh always in -0.5,-0.5 .. 0.5,0.5
  351. back^.x := ax;
  352. back^.y := h;
  353. back^.Z := ay;
  354. end;
  355. h := h + Dh; // inc h
  356. end;
  357. M.CalcTangentBinormals;
  358. end;
  359. procedure TgxSailSurface.CalcSailSurfaceMesh; // create default sail mesh
  360. var
  361. M: TMeshData;
  362. x, y: integer;
  363. somme: Single;
  364. front, back: PPoint3D;
  365. h, hinM, L, Dh, DL, chord, chordFrac, maxChord, Z, ah, al: Single;
  366. aSailHeight, aSailWidth, sh2, sw2: Single;
  367. begin
  368. // sail params sanity test
  369. if (SubdivisionsHeight <= 0) or (SubdivisionsWidth <= 0) then
  370. exit; // invalid subdiv values
  371. M := self.Data; // use default TPlane mesh
  372. fNbMesh := (SubdivisionsWidth + 1) * (SubdivisionsHeight + 1);
  373. // recalc mesh number of vertices
  374. // mesh is calculated to fit into [-0.5,-0.5..0.5,0.5] interval. Actual sail dimensions are set with objects Width,Height,Depth
  375. aSailHeight := fSailParams.Ht; // Height = H top
  376. // set maxChord ( max sail width ) and SailWidth
  377. case fSailShape of
  378. ShapeMain:
  379. begin
  380. maxChord := fSailParams.Lb;
  381. aSailWidth := fSailParams.Lb;
  382. end;
  383. ShapeJib:
  384. begin
  385. maxChord := fSailParams.Lx;
  386. aSailWidth := fSailParams.Lx;
  387. end;
  388. ShapeSimetric:
  389. begin
  390. maxChord := fSailParams.Lb;
  391. aSailWidth := fSailParams.Lb;
  392. end; // or Lb?
  393. else
  394. maxChord := 1;
  395. aSailWidth := 1;
  396. end;
  397. if (fSailParams.Lm > maxChord) then
  398. begin
  399. maxChord := fSailParams.Lm;
  400. aSailWidth := maxChord;
  401. end;
  402. sh2 := aSailHeight / 2;
  403. sw2 := aSailWidth / 2;
  404. h := -0.5; // start at the foot
  405. Dh := 1.0 / SubdivisionsHeight;
  406. // was Dh := fSailParams.ht/fSailParams.NsubH; // subd h increment
  407. // this will create a mesh in h range -0.5 .. 0.5
  408. for y := 0 to SubdivisionsHeight do
  409. begin
  410. // calc DL
  411. hinM := (h + 0.5) * aSailHeight; // hinM = h in meters
  412. chord := fSailParams.GetSailChord(fSailShape, hinM);
  413. // sail chord for h ( in 0..1 range )
  414. chordFrac := chord / maxChord;
  415. if (chord <= 0) then
  416. continue; // ??
  417. DL := 0.5 * chordFrac / SubdivisionsWidth;
  418. // subd horizontal chord increment
  419. // sail simetry is controlled by where the mesh line starts
  420. case fSailShape of // x of sail mesh start
  421. ShapeMain, ShapeJib:
  422. L := 0;
  423. ShapeSimetric:
  424. L := -chord / 2; // 0 is the sail middle. Start line at x=0-chord/2
  425. else
  426. L := 0; // wtf ??
  427. end;
  428. for x := 0 to SubdivisionsWidth do
  429. begin
  430. front := M.VertexBuffer.VerticesPtr[x + (y * (SubdivisionsWidth + 1))];
  431. back := M.VertexBuffer.VerticesPtr
  432. [fNbMesh + x + (y * (SubdivisionsWidth + 1))];
  433. al := L;
  434. ah := h;
  435. front^.x := al;
  436. front^.y := ah;
  437. back^.x := al;
  438. back^.y := ah;
  439. // add some sail side movement ( camber )
  440. Z := x * (SubdivisionsWidth - x) * DL * 0.10;
  441. // (Random(10)-5)*0.003; // test...
  442. if fCamberRight then
  443. Z := -Z;
  444. front^.Z := Z;
  445. back^.Z := Z;
  446. L := L + DL; // inc L
  447. end;
  448. h := h + Dh; // inc h
  449. end;
  450. M.CalcTangentBinormals;
  451. // fTime := fTime + 0.01; //??
  452. end;
  453. function TgxSailSurface.Altura(P: TPoint3D): Single; // Om:
  454. var
  455. M: TMeshData;
  456. x, y: integer;
  457. front, back: PPoint3D;
  458. begin
  459. M := self.Data;
  460. x := Round(P.x);
  461. y := Round(P.y);
  462. if (x >= 0) and (x < SubdivisionsWidth) and (y > 0) and
  463. (y < SubdivisionsHeight) then
  464. begin
  465. fNbMesh := (SubdivisionsWidth + 1) * (SubdivisionsHeight + 1);
  466. // recalc mesh number of vertices
  467. front := M.VertexBuffer.VerticesPtr[x + (y * (SubdivisionsWidth + 1))];
  468. back := M.VertexBuffer.VerticesPtr
  469. [fNbMesh + x + (y * (SubdivisionsWidth + 1))];
  470. Result := (front^.Z + back^.Z) / 2; // ??
  471. end
  472. else
  473. Result := 0;
  474. end;
  475. procedure TgxSailSurface.SetSailParams(aSailParams: TSailParams);
  476. begin
  477. fSailParams.Lb := aSailParams.Lb;
  478. fSailParams.Lt := aSailParams.Lt;
  479. fSailParams.Ht := aSailParams.Ht;
  480. // fSailParams.NsubH := aSailParams.NsubH;
  481. // fSailParams.NsubL := aSailParams.NsubL;
  482. // set plane subdivisions
  483. // self.SubdivisionsHeight := fSailParams.NsubH; // plane subdivisions
  484. // self.SubdivisionsWidth := fSailParams.NsubL;
  485. fNbMesh := (SubdivisionsWidth + 1) * (SubdivisionsHeight + 1);
  486. fCenter := Point3D(SubdivisionsWidth / self.Width,
  487. SubdivisionsHeight / self.Height, 0);
  488. // CalcSailSurfaceMesh;
  489. end;
  490. procedure TgxSailSurface.SetSailShape(const Value: TSailShape);
  491. begin
  492. if fSailShape <> Value then
  493. begin
  494. fSailShape := Value;
  495. // should remesh here..
  496. end;
  497. end;
  498. procedure TgxSailSurface.setVersion(const Value: integer);
  499. begin
  500. if (fVersion <> Value) then
  501. begin
  502. fVersion := Value;
  503. CalcSailSurfaceMesh; // recalc default mesh, based on fSailParams
  504. end;
  505. end;
  506. procedure TgxSailSurface.Render;
  507. begin
  508. inherited;
  509. // each render recalcs the mesh !
  510. if fUseTasks then
  511. begin
  512. TTask.Create(
  513. procedure
  514. begin
  515. // CalcSailSurfaceMesh; // recalc mesh
  516. end).start;
  517. end
  518. else
  519. begin
  520. // CalcSailSurfaceMesh;
  521. end;
  522. if ShowLines then
  523. Context.DrawLines(self.Data.VertexBuffer, self.Data.IndexBuffer,
  524. TMaterialSource.ValidMaterial(fMaterialLignes), 1);
  525. end;
  526. procedure TgxSailSurface.SetChordBottom(const Value: Single);
  527. begin
  528. if fSailParams.Lb <> Value then
  529. begin
  530. fSailParams.Lb := Value;
  531. // CalcSailSurfaceMesh; // remesh
  532. end;
  533. end;
  534. procedure TgxSailSurface.SetChordMid(const Value: Single);
  535. begin
  536. if fSailParams.Lm <> Value then
  537. begin
  538. fSailParams.Lm := Value;
  539. // CalcSailSurfaceMesh; // remesh
  540. end;
  541. end;
  542. procedure TgxSailSurface.SetChordTop(const Value: Single);
  543. begin
  544. if fSailParams.Lt <> Value then
  545. begin
  546. fSailParams.Lt := Value;
  547. // CalcSailSurfaceMesh; // remesh
  548. end;
  549. end;
  550. procedure TgxSailSurface.SetChordX(const Value: Single);
  551. begin
  552. if fSailParams.Lx <> Value then
  553. begin
  554. fSailParams.Lx := Value;
  555. // CalcSailSurfaceMesh; // remesh
  556. end;
  557. end;
  558. procedure TgxSailSurface.SetHeightX(const Value: Single);
  559. begin
  560. if fSailParams.Hx <> Value then
  561. begin
  562. fSailParams.Hx := Value;
  563. // CalcSailSurfaceMesh; // remesh
  564. end;
  565. end;
  566. procedure TgxSailSurface.SetSailHeight(const Value: Single);
  567. begin
  568. if fSailParams.ht <> Value then
  569. begin
  570. fSailParams.ht := Value;
  571. // CalcSailSurfaceMesh; // remesh
  572. end;
  573. end;
  574. //----------------------------------------------------------------------------
  575. procedure Register;
  576. begin
  577. RegisterComponents('GLXEngine', [TgxSailSurface]);
  578. end;
  579. end.