omSailSurface.pas 19 KB

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