ellipses.pp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2003 by the Free Pascal development team
  4. Drawing of ellipses and arcs, and filling ellipses and pies.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$mode objfpc}
  12. unit Ellipses;
  13. interface
  14. uses classes, FPImage, FPCanvas;
  15. procedure DrawSolidEllipse (Canv:TFPCustomCanvas; const Bounds:TRect; const c:TFPColor);
  16. procedure DrawSolidEllipse (Canv:TFPCustomCanvas; const Bounds:TRect; Width:integer; const c:TFPColor);
  17. procedure DrawPatternEllipse (Canv:TFPCustomCanvas; const Bounds:TRect; Pattern:TPenPattern; const c:TFPColor);
  18. procedure FillEllipseColor (Canv:TFPCustomCanvas; const Bounds:TRect; const c:TFPColor);
  19. procedure FillEllipsePattern (Canv:TFPCustomCanvas; const Bounds:TRect; Pattern:TBrushPattern; const c:TFPColor);
  20. procedure FillEllipseHashHorizontal (Canv:TFPCustomCanvas; const Bounds:TRect; width:integer; const c:TFPColor);
  21. procedure FillEllipseHashVertical (Canv:TFPCustomCanvas; const Bounds:TRect; width:integer; const c:TFPColor);
  22. procedure FillEllipseHashDiagonal (Canv:TFPCustomCanvas; const Bounds:TRect; width:integer; const c:TFPColor);
  23. procedure FillEllipseHashBackDiagonal (Canv:TFPCustomCanvas; const Bounds:TRect; width:integer; const c:TFPColor);
  24. procedure FillEllipseHashDiagCross (Canv:TFPCustomCanvas; const Bounds:TRect; width:integer; const c:TFPColor);
  25. procedure FillEllipseHashCross (Canv:TFPCustomCanvas; const Bounds:TRect; width:integer; const c:TFPColor);
  26. procedure FillEllipseImage (Canv:TFPCustomCanvas; const Bounds:TRect; const Image:TFPCustomImage);
  27. procedure FillEllipseImageRel (Canv:TFPCustomCanvas; const Bounds:TRect; const Image:TFPCustomImage);
  28. type
  29. PEllipseInfoData = ^TEllipseInfoData;
  30. TEllipseInfoData = record
  31. x, ytopmax, ytopmin, ybotmax, ybotmin : integer;
  32. OnlyTop : boolean;
  33. end;
  34. TEllipseInfo = class
  35. private
  36. fcx, fcy, frx,fry : double;
  37. InfoList : TList;
  38. procedure FreeList;
  39. procedure ClearList;
  40. function FindXIndex (x:integer) : integer;
  41. procedure PrepareCalculation (out np:integer; out delta:real);
  42. function NewInfoRec (anX:integer) : PEllipseInfoData;
  43. procedure CalculateCircular (const b:TRect; out x,y,rx,ry:real);
  44. public
  45. constructor create;
  46. destructor destroy; override;
  47. function GetInfoForX (x:integer; var ytopmax,ytopmin,ybotmax,ybotmin:integer):boolean;
  48. function GetInfoForX (x:integer; var Info:PEllipseInfoData):boolean;
  49. procedure GatherEllipseInfo (const bounds:TRect);
  50. property cx : double read fcx; // center point
  51. property cy : double read fcy;
  52. property rhor : double read frx; // radius
  53. property rver : double read fry;
  54. { only usable when created with GatherArcInfo }
  55. end;
  56. implementation
  57. constructor TEllipseInfo.Create;
  58. begin
  59. inherited;
  60. InfoList := TList.Create;
  61. end;
  62. destructor TEllipseInfo.Destroy;
  63. begin
  64. FreeList;
  65. inherited;
  66. end;
  67. procedure TEllipseInfo.ClearList;
  68. var r : integer;
  69. d : PEllipseInfoData;
  70. begin
  71. if assigned (InfoList) then
  72. begin
  73. for r := 0 to infolist.count-1 do
  74. begin
  75. d := PEllipseInfoData(InfoList[r]);
  76. dispose (d);
  77. end;
  78. InfoList.clear;
  79. end;
  80. end;
  81. procedure TEllipseInfo.FreeList;
  82. begin
  83. if assigned (InfoList) then
  84. begin
  85. ClearList;
  86. InfoList.Free;
  87. InfoList := nil;
  88. end;
  89. end;
  90. function TEllipseInfo.GetInfoForX (x:integer; var ytopmax,ytopmin,ybotmax,ybotmin:integer):boolean;
  91. var r : PEllipseInfoData;
  92. begin
  93. R:=Nil;
  94. result := GetInfoForX (x, r);
  95. if assigned(r) then
  96. begin
  97. ytopmax := ytopmax;
  98. ytopmin := ytopmin;
  99. ybotmax := ybotmax;
  100. ybotmin := ybotmin;
  101. end;
  102. end;
  103. function TEllipseInfo.FindXIndex (x : integer) : integer;
  104. begin
  105. result := InfoList.Count;
  106. repeat
  107. dec (result);
  108. until (result < 0) or (x = PEllipseInfoData(InfoList[result])^.x);
  109. end;
  110. function TEllipseInfo.GetInfoForX (x:integer; var Info:PEllipseInfoData):boolean;
  111. var r : integer;
  112. begin
  113. r := FindXIndex (x);
  114. result := (r >= 0);
  115. if result then
  116. Info := PEllipseInfoData(InfoList[r])
  117. end;
  118. procedure TEllipseInfo.PrepareCalculation (out np:integer; out delta:real);
  119. begin
  120. np := round(1.5708 * sqrt(sqr(frx)+sqr(fry)) );
  121. // number of pixel in quarter circel to calculate without gaps in drawing
  122. delta := pi / (2 * np);
  123. end;
  124. function TEllipseInfo.NewInfoRec (anX:integer) : PEllipseInfoData;
  125. begin
  126. new (result);
  127. result^.x := anX;
  128. infolist.Add (result);
  129. with result^ do
  130. begin
  131. ytopmax := -1;
  132. ytopmin := maxint;
  133. ybotmax := -1;
  134. ybotmin := maxint;
  135. end;
  136. end;
  137. procedure TEllipseInfo.CalculateCircular (const b:TRect; out x,y,rx,ry:real);
  138. begin
  139. with b do
  140. begin
  141. x := (right+left) / 2;
  142. y := (top+bottom) / 2;
  143. rx := abs(right-left) / 2;
  144. ry := abs(bottom-top) / 2;
  145. end;
  146. end;
  147. procedure TEllipseInfo.GatherEllipseInfo (const bounds:TRect);
  148. var infoP, infoM : PEllipseInfoData;
  149. halfnumber,
  150. r, NumberPixels, xtemp,yt,yb : integer;
  151. pPy, pMy, x,y, rx,ry, xd,yd,ra, rdelta : real;
  152. begin
  153. ClearList;
  154. CalculateCircular (bounds, x,y,rx,ry);
  155. with bounds do
  156. fcx := x;
  157. fcy := y;
  158. frx := rx;
  159. fry := ry;
  160. if (rx < 0.5) and (ry < 0.5) then
  161. with NewInfoRec (round(x))^ do
  162. begin
  163. ytopmax := round(y);
  164. ytopmin := ytopmax;
  165. ybotmax := ytopmax;
  166. ybotmin := ytopmax;
  167. end
  168. else
  169. begin
  170. PrepareCalculation (NumberPixels, rdelta);
  171. halfnumber := NumberPixels div 2;
  172. pPy := maxint;
  173. pMy := maxint;
  174. ra := 0;
  175. infoP := NewInfoRec (round(x + rx));
  176. infoM := NewInfoRec (round(x - rx));
  177. for r := 0 to NumberPixels do
  178. begin
  179. xd := rx * cos(ra);
  180. yd := ry * sin(ra);
  181. // take all 4 quarters
  182. yt := round(y - yd);
  183. yb := round(y + yd);
  184. xtemp := round (x + xd);
  185. // quarter 1 and 4 at the same x line
  186. if infoP^.x <> xtemp then // has correct record ?
  187. begin
  188. with infoP^ do // ensure single width
  189. begin
  190. if r < halfnumber then
  191. begin
  192. if ytopmin = yt then
  193. begin
  194. inc (ytopmin);
  195. dec (ybotmax);
  196. end;
  197. end
  198. else
  199. begin
  200. if (ytopmax = pPy) and (ytopmax <> ytopmin) then
  201. begin
  202. dec (ytopmax);
  203. inc (ybotmin);
  204. end;
  205. end;
  206. pPy := ytopmin;
  207. end;
  208. if not GetInfoForX (xtemp, infoP) then // record exists already ?
  209. infoP := NewInfoRec (xtemp); // create a new recod
  210. end;
  211. // lower y is top, min is lowest
  212. with InfoP^ do
  213. begin
  214. if yt < ytopmin then
  215. ytopmin := yt;
  216. if yb < ybotmin then
  217. ybotmin := yb;
  218. if yt > ytopmax then
  219. ytopmax := yt;
  220. if yb > ybotmax then
  221. ybotmax := yb;
  222. end;
  223. // quarter 2 and 3 on the same x line
  224. xtemp := round(x - xd);
  225. if infoM^.x <> xtemp then // has correct record ?
  226. begin
  227. with infoM^ do // ensure single width
  228. begin
  229. if r < halfnumber then
  230. begin
  231. if ytopmin = yt then
  232. begin
  233. inc (ytopmin);
  234. dec (ybotmax);
  235. end;
  236. end
  237. else
  238. begin
  239. if (ytopmax = pMy) and (ytopmax <> ytopmin) then
  240. begin
  241. dec (ytopmax);
  242. inc (ybotmin);
  243. end;
  244. end;
  245. pMy := ytopmin;
  246. end;
  247. if not GetInfoForX (xtemp, infoM) then // record exists already ?
  248. infoM := NewInfoRec (xtemp); // create a new recod
  249. end;
  250. // lower y is top, min is lowest
  251. with InfoM^ do
  252. begin
  253. if yt < ytopmin then
  254. ytopmin := yt;
  255. if yb < ybotmin then
  256. ybotmin := yb;
  257. if yt > ytopmax then
  258. ytopmax := yt;
  259. if yb > ybotmax then
  260. ybotmax := yb;
  261. end;
  262. ra := ra + rdelta;
  263. end;
  264. end;
  265. end;
  266. { The drawing routines }
  267. type
  268. TPutPixelProc = procedure (Canv:TFPCustomCanvas; x,y:integer; const color:TFPColor);
  269. TLinePoints = array[0..PatternBitCount-1] of boolean;
  270. PLinePoints = ^TLinePoints;
  271. procedure PatternToPoints (const APattern:TPenPattern; LinePoints:PLinePoints);
  272. var r : integer;
  273. i : longword;
  274. begin
  275. i := 1;
  276. for r := PatternBitCount-1 downto 1 do
  277. begin
  278. LinePoints^[r] := (APattern and i) <> 0;
  279. i := i shl 1;
  280. end;
  281. LinePoints^[0] := (APattern and i) <> 0;
  282. end;
  283. procedure PutPixelCopy(Canv:TFPCustomCanvas; x,y:integer; const color:TFPColor);
  284. begin
  285. with Canv do
  286. DrawPixel(x,y,color);
  287. end;
  288. procedure PutPixelXor(Canv:TFPCustomCanvas; x,y:integer; const color:TFPColor);
  289. begin
  290. with Canv do
  291. Colors[x,y] := Colors[x,y] xor color;
  292. end;
  293. procedure PutPixelOr(Canv:TFPCustomCanvas; x,y:integer; const color:TFPColor);
  294. begin
  295. with Canv do
  296. Colors[x,y] := Colors[x,y] or color;
  297. end;
  298. procedure PutPixelAnd(Canv:TFPCustomCanvas; x,y:integer; const color:TFPColor);
  299. begin
  300. with Canv do
  301. Colors[x,y] := Colors[x,y] and color;
  302. end;
  303. procedure DrawSolidEllipse (Canv:TFPCustomCanvas; const Bounds:TRect; const c:TFPColor);
  304. var info : TEllipseInfo;
  305. r, y : integer;
  306. MyPutPix : TPutPixelProc;
  307. begin
  308. with canv.pen do
  309. case mode of
  310. pmMask : MyPutPix := @PutPixelAnd;
  311. pmMerge : MyPutPix := @PutPixelOr;
  312. pmXor : MyPutPix := @PutPixelXor;
  313. else MyPutPix := @PutPixelCopy;
  314. end;
  315. info := TEllipseInfo.Create;
  316. with Canv, info do
  317. try
  318. GatherEllipseInfo (bounds);
  319. for r := 0 to InfoList.count-1 do
  320. with PEllipseInfoData(InfoList[r])^ do
  321. begin
  322. for y := ytopmin to ytopmax do
  323. MyPutPix (Canv, x,y, c);
  324. for y := ybotmin to ybotmax do
  325. MyPutPix (Canv, x,y, c);
  326. end;
  327. finally
  328. info.Free;
  329. end;
  330. end;
  331. procedure DrawSolidEllipse (Canv:TFPCustomCanvas; const Bounds:TRect; Width:integer; const c:TFPColor);
  332. var infoOut, infoIn : TEllipseInfo;
  333. r, y : integer;
  334. id : PEllipseInfoData;
  335. MyPutPix : TPutPixelProc;
  336. begin
  337. with canv.pen do
  338. case mode of
  339. pmMask : MyPutPix := @PutPixelAnd;
  340. pmMerge : MyPutPix := @PutPixelOr;
  341. pmXor : MyPutPix := @PutPixelXor;
  342. else MyPutPix := @PutPixelCopy;
  343. end;
  344. infoIn := TEllipseInfo.Create;
  345. infoOut := TEllipseInfo.Create;
  346. dec (width);
  347. id:=Nil;
  348. try
  349. infoOut.GatherEllipseInfo(bounds);
  350. with bounds do
  351. infoIn.GatherEllipseInfo (Rect(left+width,top+width,right-width,bottom-width));
  352. with Canv do
  353. for r := 0 to infoOut.infolist.count-1 do
  354. with PEllipseInfoData (infoOut.infolist[r])^ do
  355. begin
  356. if infoIn.GetInfoForX (x, id) then
  357. begin
  358. for y := ytopmin to id^.ytopmax do
  359. MyPutPix (canv, x,y, c);
  360. for y := id^.ybotmin to ybotmax do
  361. MyPutPix (canv, x,y, c);
  362. end
  363. else
  364. begin // no inner circle found: draw all points between top and bottom
  365. for y := ytopmin to ybotmax do
  366. MyPutPix (canv, x,y, c);
  367. end;
  368. end;
  369. finally
  370. infoOut.Free;
  371. infoIn.Free;
  372. end;
  373. end;
  374. procedure DrawPatternEllipse (Canv:TFPCustomCanvas; const Bounds:TRect; Pattern:TPenPattern; const c:TFPColor);
  375. var info : TEllipseInfo;
  376. xx, y : integer;
  377. LinePoints : TLinePoints;
  378. MyPutPix : TPutPixelProc;
  379. id : PEllipseInfoData;
  380. CountDown, CountUp, half : integer;
  381. begin
  382. id:=Nil;
  383. with canv.pen do
  384. case mode of
  385. pmMask : MyPutPix := @PutPixelAnd;
  386. pmMerge : MyPutPix := @PutPixelOr;
  387. pmXor : MyPutPix := @PutPixelXor;
  388. else MyPutPix := @PutPixelCopy;
  389. end;
  390. PatternToPoints (pattern, @LinePoints);
  391. info := TEllipseInfo.Create;
  392. with Canv, info do
  393. try
  394. GatherEllipseInfo (bounds);
  395. CountUp := 0;
  396. CountDown := PatternBitCount - 1;
  397. half := round (cx);
  398. for xx := bounds.left to half do
  399. if GetInfoForX (xx, id) then
  400. begin
  401. with id^ do
  402. begin
  403. for y := ytopmax downto ytopmin do
  404. begin
  405. if LinePoints[CountUp mod PatternBitCount] then
  406. MyPutPix (Canv, xx,y, c);
  407. inc (CountUp);
  408. end;
  409. for y := ybotmin to ybotmax do
  410. begin
  411. if LinePoints[PatternBitCount - (CountDown mod PatternBitCount) - 1] then
  412. MyPutPix (Canv, xx,y, c);
  413. inc (CountDown);
  414. end;
  415. end;
  416. end;
  417. for xx := half+1 to bounds.right do
  418. if GetInfoForX (xx, id) then
  419. begin
  420. with id^ do
  421. begin
  422. for y := ytopmin to ytopmax do
  423. begin
  424. if LinePoints[CountUp mod PatternBitCount] then
  425. MyPutPix (Canv, xx,y, c);
  426. inc (CountUp);
  427. end;
  428. for y := ybotmax downto ybotmin do
  429. begin
  430. if LinePoints[Patternbitcount - (CountDown mod PatternBitCount) - 1] then
  431. MyPutPix (Canv, xx,y, c);
  432. inc (CountDown);
  433. end;
  434. end;
  435. end;
  436. finally
  437. info.Free;
  438. end;
  439. end;
  440. procedure FillEllipseColor (Canv:TFPCustomCanvas; const Bounds:TRect; const c:TFPColor);
  441. var info : TEllipseInfo;
  442. r, y : integer;
  443. begin
  444. info := TEllipseInfo.Create;
  445. try
  446. info.GatherEllipseInfo(bounds);
  447. with Canv do
  448. for r := 0 to info.infolist.count-1 do
  449. with PEllipseInfoData (info.infolist[r])^ do
  450. for y := ytopmin to ybotmax do
  451. DrawPixel(x,y,c);
  452. finally
  453. info.Free;
  454. end;
  455. end;
  456. procedure FillEllipsePattern (Canv:TFPCustomCanvas; const Bounds:TRect; Pattern:TBrushPattern; const c:TFPColor);
  457. begin
  458. end;
  459. procedure FillEllipseHashHorizontal (Canv:TFPCustomCanvas; const Bounds:TRect; width:integer; const c:TFPColor);
  460. var info : TEllipseInfo;
  461. r, y : integer;
  462. begin
  463. info := TEllipseInfo.Create;
  464. try
  465. info.GatherEllipseInfo(bounds);
  466. for r := 0 to info.infolist.count-1 do
  467. with PEllipseInfoData (info.infolist[r])^ do
  468. for y := ytopmin to ybotmax do
  469. if (y mod width) = 0 then
  470. canv.DrawPixel(x,y,c);
  471. finally
  472. info.Free;
  473. end;
  474. end;
  475. procedure FillEllipseHashVertical (Canv:TFPCustomCanvas; const Bounds:TRect; width:integer; const c:TFPColor);
  476. var info : TEllipseInfo;
  477. r, y : integer;
  478. begin
  479. info := TEllipseInfo.Create;
  480. try
  481. info.GatherEllipseInfo(bounds);
  482. for r := 0 to info.infolist.count-1 do
  483. with PEllipseInfoData (info.infolist[r])^ do
  484. if (x mod width) = 0 then
  485. for y := ytopmin to ybotmax do
  486. canv.DrawPixel(x,y,c);
  487. finally
  488. info.Free;
  489. end;
  490. end;
  491. procedure FillEllipseHashDiagonal (Canv:TFPCustomCanvas; const Bounds:TRect; width:integer; const c:TFPColor);
  492. var info : TEllipseInfo;
  493. r, y : integer;
  494. w : integer;
  495. begin
  496. info := TEllipseInfo.Create;
  497. try
  498. info.GatherEllipseInfo(bounds);
  499. for r := 0 to info.infolist.count-1 do
  500. with PEllipseInfoData (info.infolist[r])^ do
  501. begin
  502. w := width - 1 - (x mod width);
  503. for y := ytopmin to ybotmax do
  504. if (y mod width) = w then
  505. canv.DrawPixel(x,y,c);
  506. end;
  507. finally
  508. info.Free;
  509. end;
  510. end;
  511. procedure FillEllipseHashBackDiagonal (Canv:TFPCustomCanvas; const Bounds:TRect; width:integer; const c:TFPColor);
  512. var info : TEllipseInfo;
  513. r, y : integer;
  514. w : integer;
  515. begin
  516. info := TEllipseInfo.Create;
  517. try
  518. info.GatherEllipseInfo(bounds);
  519. for r := 0 to info.infolist.count-1 do
  520. with PEllipseInfoData (info.infolist[r])^ do
  521. begin
  522. w := (x mod width);
  523. for y := ytopmin to ybotmax do
  524. if (y mod width) = w then
  525. canv.DrawPixel(x,y,c);
  526. end;
  527. finally
  528. info.Free;
  529. end;
  530. end;
  531. procedure FillEllipseHashDiagCross (Canv:TFPCustomCanvas; const Bounds:TRect; width:integer; const c:TFPColor);
  532. var info : TEllipseInfo;
  533. r, y : integer;
  534. wy,w1,w2 : integer;
  535. begin
  536. info := TEllipseInfo.Create;
  537. try
  538. info.GatherEllipseInfo(bounds);
  539. for r := 0 to info.infolist.count-1 do
  540. with PEllipseInfoData (info.infolist[r])^ do
  541. begin
  542. w1 := (x mod width);
  543. w2 := width - 1 - (x mod width);
  544. for y := ytopmin to ybotmax do
  545. begin
  546. wy := y mod width;
  547. if (wy = w1) or (wy = w2) then
  548. canv.DrawPixel(x,y,c);
  549. end;
  550. end;
  551. finally
  552. info.Free;
  553. end;
  554. end;
  555. procedure FillEllipseHashCross (Canv:TFPCustomCanvas; const Bounds:TRect; width:integer; const c:TFPColor);
  556. var info : TEllipseInfo;
  557. r, y : integer;
  558. begin
  559. info := TEllipseInfo.Create;
  560. try
  561. info.GatherEllipseInfo(bounds);
  562. for r := 0 to info.infolist.count-1 do
  563. with PEllipseInfoData (info.infolist[r])^ do
  564. if (x mod width) = 0 then
  565. for y := ytopmin to ybotmax do
  566. canv.DrawPixel(x,y,c)
  567. else
  568. for y := ytopmin to ybotmax do
  569. if (y mod width) = 0 then
  570. canv.DrawPixel(x,y,c);
  571. finally
  572. info.Free;
  573. end;
  574. end;
  575. procedure FillEllipseImage (Canv:TFPCustomCanvas; const Bounds:TRect; const Image:TFPCustomImage);
  576. var info : TEllipseInfo;
  577. r, y : integer;
  578. w : integer;
  579. begin
  580. info := TEllipseInfo.Create;
  581. try
  582. info.GatherEllipseInfo(bounds);
  583. for r := 0 to info.infolist.count-1 do
  584. with PEllipseInfoData (info.infolist[r])^ do
  585. begin
  586. w := (x mod image.width);
  587. for y := ytopmin to ybotmax do
  588. canv.DrawPixel(x,y,Image.colors[w, (y mod image.height)]);
  589. end;
  590. finally
  591. info.Free;
  592. end;
  593. end;
  594. procedure FillEllipseImageRel (Canv:TFPCustomCanvas; const Bounds:TRect; const Image:TFPCustomImage);
  595. var info : TEllipseInfo;
  596. r, y : integer;
  597. xo,yo, xi,yi : integer;
  598. begin
  599. info := TEllipseInfo.Create;
  600. try
  601. with info do
  602. begin
  603. GatherEllipseInfo(bounds);
  604. xo := round(cx) - (image.width div 2);
  605. yo := round(cy) - (image.height div 2);
  606. end;
  607. for r := 0 to info.infolist.count-1 do
  608. with PEllipseInfoData (info.infolist[r])^ do
  609. begin
  610. xi := (x - xo) mod image.width;
  611. if xi < 0 then
  612. inc (xi, image.width);
  613. for y := ytopmin to ybotmax do
  614. begin
  615. yi := (y - yo) mod image.height;
  616. if yi < 0 then
  617. inc (yi, image.height);
  618. canv.DrawPixel(x,y,Image.colors[xi, yi]);
  619. end;
  620. end;
  621. finally
  622. info.Free;
  623. end;
  624. end;
  625. end.