WMGraphicsSmooth.Mod 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722
  1. (**
  2. AUTHOR: "Alexey Morozov";
  3. PURPOSE: "Smooth (antialiased) graphics";
  4. *)
  5. MODULE WMGraphicsSmooth;
  6. IMPORT SYSTEM, Raster, Strings, WMGraphics;
  7. CONST
  8. (** Line cap types *)
  9. CapButt* = 0; (** A flat edge is added to each end of the line; *)
  10. CapRound* = 1; (** A rounded end cap is added to each end of the line; *)
  11. CapSquare* = 2; (** A square end cap is added to each end of the line; *)
  12. TYPE
  13. Real* = WMGraphics.Real;
  14. (**
  15. Cancas used for smooth (antialiased) graphics
  16. *)
  17. Canvas* = OBJECT(WMGraphics.BufferCanvas)
  18. VAR
  19. lineWidth-: Real; (** line width in pixels *)
  20. capType-: LONGINT; (** line cap type *)
  21. srcOverDstMode: Raster.Mode;
  22. pixAlphaMap: ARRAY 256 OF Raster.Pixel;
  23. PROCEDURE &New(img : Raster.Image);
  24. VAR firstTime: BOOLEAN;
  25. BEGIN
  26. firstTime := generator = NIL;
  27. New^(img);
  28. IF firstTime THEN (*! for cases when the same canvas is reused with another image *)
  29. generator := Strings.NewString("WMGraphicsSmooth.GenCanvas");
  30. SetLineWidth(1.0);
  31. SetLineCap(CapButt);
  32. SetColor(WMGraphics.Blue);
  33. Raster.InitMode(srcOverDstMode,Raster.srcOverDst);
  34. END;
  35. END New;
  36. PROCEDURE SetColor(x: WMGraphics.Color);
  37. VAR
  38. i: LONGINT;
  39. s: LONGINT;
  40. r, g, b, a: LONGINT;
  41. BEGIN
  42. SetColor^(x);
  43. WMGraphics.ColorToRGBA(color,r,g,b,a);
  44. s := (256 * a) DIV 255;
  45. FOR i := 0 TO 255 DO Raster.SetRGBA(pixAlphaMap[i],r,g,b,a - (s*i+128) DIV 256); END;
  46. END SetColor;
  47. (**
  48. Set line width in pixels
  49. *)
  50. PROCEDURE SetLineWidth*(w: Real);
  51. BEGIN
  52. IF w < 0.5 THEN w := 0.5; END;
  53. lineWidth := w;
  54. END SetLineWidth;
  55. (**
  56. Setup line cap type
  57. *)
  58. (*! REMARK: currently onle CapButt is implemented! *)
  59. PROCEDURE SetLineCap*(lineCap: LONGINT);
  60. BEGIN
  61. capType := MIN(CapSquare,MAX(CapButt,lineCap));
  62. END SetLineCap;
  63. PROCEDURE Line(x0, y0, x1, y1: LONGINT; lineColor: WMGraphics.Color; mode: LONGINT);
  64. VAR xr0, yr0, xr1, yr1: Real;
  65. BEGIN
  66. IF lineColor # color THEN SetColor(lineColor); END;
  67. (* transform local coordinates to the global coordinate system *)
  68. xr0 := x0 + dx; yr0 := y0 + dy;
  69. xr1 := x1 + dx; yr1 := y1 + dy;
  70. IF lineWidth = 1 THEN
  71. (* does the line cross the canvas rectangle? *)
  72. IF ~ClipLineReal(limits.l,limits.t,limits.r-1,limits.b-1, xr0,yr0,xr1,yr1) THEN RETURN; END;
  73. ThinSmoothLineReal(img, xr0,yr0, xr1,yr1, pixAlphaMap, srcOverDstMode);
  74. ELSE
  75. (* does the line cross the canvas rectangle with account of the line width? *)
  76. IF ~ClipLineReal(limits.l-lineWidth,limits.t-lineWidth,limits.r-1+lineWidth,limits.b-1+lineWidth, xr0,yr0,xr1,yr1) THEN RETURN; END;
  77. ThickSmoothLineReal(img, xr0,yr0, xr1,yr1, pixAlphaMap, srcOverDstMode, lineWidth);
  78. END;
  79. END Line;
  80. (**
  81. Draw an antialiased line represented by real-valued coordinates of the starting and ending points
  82. *)
  83. PROCEDURE LineReal*(x0, y0, x1, y1: Real; lineColor: WMGraphics.Color; mode: LONGINT);
  84. VAR
  85. dx, dy, g: Real;
  86. x01, y01, x02, y02: Real;
  87. x11, y11, x12, y12: Real;
  88. points : ARRAY 4 OF WMGraphics.Point2d;
  89. BEGIN
  90. IF lineColor # color THEN SetColor(lineColor); END;
  91. (* transform local coordinates to the global coordinate system *)
  92. x0 := x0 + dx; y0 := y0 + dy;
  93. x1 := x1 + dx; y1 := y1 + dy;
  94. IF lineWidth <= 1 THEN
  95. (* does the line cross the canvas rectangle? *)
  96. IF ~ClipLineReal(limits.l,limits.t,limits.r-1,limits.b-1, x0,y0,x1,y1) THEN RETURN; END;
  97. ThinSmoothLineReal(img, x0,y0, x1,y1, pixAlphaMap, srcOverDstMode);
  98. ELSE
  99. (* does the line cross the canvas rectangle with account of the line width? *)
  100. IF ~ClipLineReal(limits.l-lineWidth,limits.t-lineWidth,limits.r-1+lineWidth,limits.b-1+lineWidth, x0,y0,x1,y1) THEN RETURN; END;
  101. ThickSmoothLineReal(img, x0,y0, x1,y1, pixAlphaMap, srcOverDstMode, lineWidth);
  102. (*! an alternative way based on FillPolygonFlat - potentially faster than the current implementation of ThickSmoothLineReal; *)
  103. (*
  104. dx := x1 - x0;
  105. dy := y1 - y0;
  106. g := (0.5*lineWidth) * InvSqrt(dx*dx + dy*dy);
  107. x01 := x0 + dy*g;
  108. y01 := y0 - dx*g;
  109. x11 := x1 + dy*g;
  110. y11 := y1 - dx*g;
  111. x02 := x01 - 2*dy*g;
  112. y02 := y01 + 2*dx*g;
  113. x12 := x11 - 2*dy*g;
  114. y12 := y11 + 2*dx*g;
  115. points[0].x := Round(x01); points[0].y := Round(y01);
  116. points[1].x := Round(x02); points[1].y := Round(y02);
  117. points[2].x := Round(x12); points[2].y := Round(y12);
  118. points[3].x := Round(x11); points[3].y := Round(y11);
  119. FillPolygonFlat(points,4,lineColor,WMGraphics.ModeCopy);
  120. ThinSmoothLineReal(img, x01,y01, x11,y11, pixAlphaMap, srcOverDstMode);
  121. ThinSmoothLineReal(img, x02,y02, x12,y12, pixAlphaMap, srcOverDstMode);
  122. ThinSmoothLineReal(img, x01,y01, x02,y02, pixAlphaMap, srcOverDstMode);
  123. ThinSmoothLineReal(img, x11,y11, x12,y12, pixAlphaMap, srcOverDstMode);
  124. *)
  125. END;
  126. END LineReal;
  127. END Canvas;
  128. PROCEDURE GenCanvas*(img:Raster.Image):WMGraphics.BufferCanvas; (* generator procedure *)
  129. VAR c:Canvas;
  130. BEGIN
  131. NEW(c,img); RETURN c (* img is NIL, needs a call of c.New(img) later on *)
  132. END GenCanvas;
  133. (**
  134. Fast inverse square root (1 / sqrt(x))
  135. Based on the "0x5f3759df" algorithm described in Wikipedia ( https://en.wikipedia.org/wiki/Fast_inverse_square_root )
  136. *)
  137. PROCEDURE InvSqrt(x: REAL): REAL;
  138. VAR y: Real;
  139. BEGIN
  140. y := SYSTEM.VAL(REAL,0x5f3759df - SYSTEM.VAL(LONGINT,x) DIV 2); (* ~4% of error *)
  141. RETURN y * ( 1.5E0 - y * y * (x * 0.5E0) ); (* ~0.15% of error *)
  142. END InvSqrt;
  143. (**
  144. Draw a thin (<=1 pixel wide) antialiased line defined by starting and ending points with real coordinates
  145. img: raster image object
  146. x0, y0: starting line position
  147. x1, y1: ending line position
  148. pixAlphaMap: pixel map for 256 alpha values for a given line color
  149. srcOverDstMode: raster mode corresponding to source over destination transfer (use Raster.InitMode(srcOverDstMode,Raster.srcOverDst);)
  150. REMARK:
  151. In this code the signed distance function is defined as: sdist(x,y) = (dx*(y-y0) - dy*(x-x0)) / sqrt(dx*dx+dy*dy), where dx = x1-x0, dy = y1-y0
  152. POSSIBLE COMPILER BUG: if "CONST pixAlphaMap: ARRAY 256 OF Raster.Pixel" is replaced by "CONST pixAlphaMap: ARRAY OF Raster.Pixel" the generated code traps with an access violation!!!
  153. *)
  154. (*!TODO: optimize the code for performance; consider to use fixed point arithmetics *)
  155. PROCEDURE ThinSmoothLineReal(
  156. img: Raster.Image;
  157. x0, y0, x1, y1: Real;
  158. CONST pixAlphaMap: ARRAY 256 OF Raster.Pixel;
  159. VAR srcOverDstMode: Raster.Mode
  160. );
  161. VAR
  162. swapped: BOOLEAN;
  163. a, i, incx, incy, x, y, yy, xend: LONGINT;
  164. dx, dy, sdx, sdy, dc, dm, dd, d0, d1, v, v0, v1, w: Real;
  165. x0p, y0p, x1p: Real;
  166. BEGIN
  167. dx := x1 - x0;
  168. dy := y1 - y0;
  169. IF dx < 0 THEN
  170. x0 := x0 + dx; x1 := x1 - dx;
  171. y0 := y0 + dy; y1 := y1 - dy;
  172. dx := -dx; dy := -dy;
  173. END;
  174. IF ABS(dy) > ABS(dx) THEN (* slope > 1 *)
  175. v := x0; x0 := y0; y0 := v;
  176. v := x1; x1 := y1; y1 := v;
  177. v := dx; dx := dy; dy := v;
  178. swapped := TRUE;
  179. END;
  180. IF dx >= 0 THEN incx := 1; ELSE incx := -1; END;
  181. IF dy >= 0 THEN incy := 1; ELSE incy := -1; END;
  182. (* normalize ranges by the distance between the point- will be used for computing the signed distance to the line *)
  183. v := InvSqrt(dx*dx + dy*dy);
  184. dx := dx*v; dy := dy*v;
  185. sdx := dx; sdy := dy; (* differences used for lines perpendicular to the original line *)
  186. (* account for the signs of the coordinate differences *)
  187. IF ~((dx >= 0) & (dy >= 0)) OR (((dx < 0) & (dy < 0))) THEN
  188. dx := -dx; dy := -dy;
  189. END;
  190. (* move start and end points to the left and right accordingly by 2 units along the line *)
  191. x0p := x0 - 2.0*sdx;
  192. y0p := y0 - 2.0*sdy;
  193. x1p := x1 + 2.0*sdx;
  194. x := ENTIER(x0p);
  195. y := ENTIER(y0p);
  196. dm := dx*(y + 0.5*incy - y0) - dy*((x+incx) - x0); (* signed distance at the midpoint dm = sdist(x+incx,y+0.5*incy) *)
  197. d0 := sdy*(y - y0) + sdx*(x - x0); (* signed distance for the line, which goes through (x0,y0) and perpendicular to the original line (sdist0) *)
  198. d1 := sdy*(y - y1) + sdx*(x - x1); (* signed distance for the line, which goes through (x0,y0) and perpendicular to the original line (sdist1) *)
  199. dd := dx*0.5*incy - dy*incx; (* offset for computing signed distance at the current point (x,y-incy) *)
  200. (* account for the signs of the increments *)
  201. IF incx < 0 THEN dy := -dy; sdx := -sdx; END;
  202. IF incy < 0 THEN dx := -dx; sdy := -sdy; END;
  203. xend := ENTIER(x1p);
  204. WHILE x # xend DO
  205. dc := dm - dd; (* dc = sdist(x,y) *)
  206. w := ABS(dc);
  207. IF w < 1.0 THEN
  208. w := MAX(MAX(-d0,d1),w);
  209. IF w < 1.0 THEN
  210. IF swapped THEN Raster.Put(img,y,x,pixAlphaMap[ENTIER(255*w)],srcOverDstMode); ELSE Raster.Put(img,x,y,pixAlphaMap[ENTIER(255*w)],srcOverDstMode); END;
  211. END;
  212. END;
  213. yy := y;
  214. v := dc - dx; w := ABS(v);
  215. IF w < 1.0 THEN
  216. (* y - incy *)
  217. DEC(yy,incy); v0 := d0 - sdy; v1 := d1 - sdy;
  218. w := MAX(MAX(-v0,v1),w);
  219. IF w < 1.0 THEN
  220. IF swapped THEN Raster.Put(img,yy,x,pixAlphaMap[ENTIER(255*w)],srcOverDstMode); ELSE Raster.Put(img,x,yy,pixAlphaMap[ENTIER(255*w)],srcOverDstMode); END;
  221. END;
  222. (* y - 2*incy *)
  223. v := v - dx; w := ABS(v);
  224. IF w < 1.0 THEN
  225. DEC(yy,incy); v0 := v0 - sdy; v1 := v1 - sdy;
  226. w := MAX(MAX(-v0,v1),w);
  227. IF w < 1.0 THEN
  228. IF swapped THEN Raster.Put(img,yy,x,pixAlphaMap[ENTIER(255*w)],srcOverDstMode); ELSE Raster.Put(img,x,yy,pixAlphaMap[ENTIER(255*w)],srcOverDstMode); END;
  229. END;
  230. END;
  231. END;
  232. yy := y;
  233. v := dc + dx; w := ABS(v);
  234. IF w < 1.0 THEN
  235. (* y + incy *)
  236. INC(yy,incy); v0 := d0 + sdy; v1 := d1 + sdy;
  237. w := MAX(MAX(-v0,v1),w);
  238. IF w < 1.0 THEN
  239. IF swapped THEN Raster.Put(img,yy,x,pixAlphaMap[ENTIER(255*w)],srcOverDstMode); ELSE Raster.Put(img,x,yy,pixAlphaMap[ENTIER(255*w)],srcOverDstMode); END;
  240. END;
  241. (* y + 2*incy *)
  242. v := v + dx; w := ABS(v);
  243. IF w < 1.0 THEN
  244. INC(yy,incy); v0 := v0 + sdy; v1 := v1 + sdy;
  245. w := MAX(MAX(-v0,v1),w);
  246. IF w < 1.0 THEN
  247. IF swapped THEN Raster.Put(img,yy,x,pixAlphaMap[ENTIER(255*w)],srcOverDstMode); ELSE Raster.Put(img,x,yy,pixAlphaMap[ENTIER(255*w)],srcOverDstMode); END;
  248. END;
  249. END;
  250. END;
  251. IF dm < 0 THEN
  252. INC(y,incy);
  253. dm := dm + dx;
  254. d0 := d0 + sdy; d1 := d1 + sdy;
  255. END;
  256. dm := dm - dy;
  257. d0 := d0 + sdx; d1 := d1 + sdx;
  258. INC(x,incx);
  259. END;
  260. END ThinSmoothLineReal;
  261. (**
  262. Draw a thick (>1 pixel wide) antialiased line defined by starting and ending points with real coordinates
  263. img: raster image object
  264. x0, y0: starting line position
  265. x1, y1: ending line position
  266. pixAlphaMap: pixel map for 256 alpha values for a given line color
  267. srcOverDstMode: raster mode corresponding to source over destination transfer (use Raster.InitMode(srcOverDstMode,Raster.srcOverDst);)
  268. lineWidth: real-value line width
  269. REMARK:
  270. In this code the signed distance function is defined as: sdist(x,y) = (dx*(y-y0) - dy*(x-x0)) / sqrt(dx*dx+dy*dy), where dx = x1-x0, dy = y1-y0
  271. POSSIBLE COMPILER BUG: if "CONST pixAlphaMap: ARRAY 256 OF Raster.Pixel" is replaced by "CONST pixAlphaMap: ARRAY OF Raster.Pixel" the generated code traps with an access violation!!!
  272. *)
  273. (*!TODO: optimize the code for performance; consider to use fixed point arithmetics *)
  274. PROCEDURE ThickSmoothLineReal(img: Raster.Image; x0, y0, x1, y1: Real; CONST pixAlphaMap: ARRAY 256 OF Raster.Pixel; VAR srcOverDstMode: Raster.Mode; lineWidth: Real);
  275. VAR
  276. swapped: BOOLEAN;
  277. a, i, incx, incy, x, y, yy, xend: LONGINT;
  278. dx, dy, sdx, sdy, dc, dm, dd, d0, d1, v, v0, v1, w: Real;
  279. x0p, y0p, x1p: Real;
  280. halfWidth: Real;
  281. BEGIN
  282. halfWidth := 0.5*lineWidth;
  283. dx := x1 - x0;
  284. dy := y1 - y0;
  285. IF dx < 0 THEN
  286. x0 := x0 + dx; x1 := x1 - dx;
  287. y0 := y0 + dy; y1 := y1 - dy;
  288. dx := -dx; dy := -dy;
  289. END;
  290. IF ABS(dy) > ABS(dx) THEN (* slope > 1 *)
  291. v := x0; x0 := y0; y0 := v;
  292. v := x1; x1 := y1; y1 := v;
  293. v := dx; dx := dy; dy := v;
  294. swapped := TRUE;
  295. END;
  296. IF dx >= 0 THEN incx := 1; ELSE incx := -1; END;
  297. IF dy >= 0 THEN incy := 1; ELSE incy := -1; END;
  298. (* normalize ranges by the distance between the point- will be used for computing the signed distance to the line *)
  299. v := InvSqrt(dx*dx + dy*dy);
  300. dx := dx*v; dy := dy*v;
  301. sdx := dx; sdy := dy; (* differences used for lines perpendicular to the original line *)
  302. (* account for the signs of the coordinate differences *)
  303. IF ~((dx >= 0) & (dy >= 0)) OR (((dx < 0) & (dy < 0))) THEN
  304. dx := -dx; dy := -dy;
  305. END;
  306. (* move start and end points to the left and right accordingly by 2 units along the line *)
  307. x0p := x0 - lineWidth*sdx;
  308. y0p := y0 - lineWidth*sdy;
  309. x1p := x1 + lineWidth*sdx;
  310. x := ENTIER(x0p);
  311. y := ENTIER(y0p);
  312. dm := dx*(y + 0.5*incy - y0) - dy*((x+incx) - x0); (* signed distance at the midpoint dm = sdist(x+incx,y+0.5*incy) *)
  313. d0 := sdy*(y - y0) + sdx*(x - x0); (* signed distance for the line, which goes through (x0,y0) and perpendicular to the original line (sdist0) *)
  314. d1 := sdy*(y - y1) + sdx*(x - x1); (* signed distance for the line, which goes through (x0,y0) and perpendicular to the original line (sdist1) *)
  315. dd := dx*0.5*incy - dy*incx; (* offset for computing signed distance at the current point (x,y-incy) *)
  316. (* account for the signs of the increments *)
  317. IF incx < 0 THEN dy := -dy; sdx := -sdx; END;
  318. IF incy < 0 THEN dx := -dx; sdy := -sdy; END;
  319. xend := ENTIER(x1p);
  320. WHILE x # xend DO
  321. dc := dm - dd; (* dc = sdist(x,y) *)
  322. w := MAX(MAX(-d0,d1),ABS(dc));
  323. IF (d0 >= 0) & (d1 <= 0) THEN
  324. IF swapped THEN Raster.Put(img,y,x,pixAlphaMap[0],srcOverDstMode); ELSE Raster.Put(img,x,y,pixAlphaMap[0],srcOverDstMode); END;
  325. ELSIF w < 1 THEN
  326. IF swapped THEN Raster.Put(img,y,x,pixAlphaMap[ENTIER(255*w)],srcOverDstMode); ELSE Raster.Put(img,x,y,pixAlphaMap[ENTIER(255*w)],srcOverDstMode); END;
  327. END;
  328. yy := y;
  329. v := dc - dx; v0 := d0; v1 := d1;
  330. w := -v - halfWidth;
  331. WHILE w < 1 DO
  332. DEC(yy,incy); v0 := v0 - sdy; v1 := v1 - sdy;
  333. w := MAX(MAX(-v0,v1),w);
  334. IF w < 0 THEN
  335. IF swapped THEN Raster.Put(img,yy,x,pixAlphaMap[0],srcOverDstMode); ELSE Raster.Put(img,x,yy,pixAlphaMap[0],srcOverDstMode); END;
  336. ELSIF w < 1 THEN
  337. IF swapped THEN Raster.Put(img,yy,x,pixAlphaMap[ENTIER(255*w)],srcOverDstMode); ELSE Raster.Put(img,x,yy,pixAlphaMap[ENTIER(255*w)],srcOverDstMode); END;
  338. END;
  339. v := v - dx; w := -v - halfWidth;
  340. END;
  341. yy := y;
  342. v := dc + dx; v0 := d0; v1 := d1;
  343. w := v - halfWidth;
  344. WHILE w < 1 DO
  345. INC(yy,incy); v0 := v0 + sdy; v1 := v1 + sdy;
  346. w := MAX(MAX(-v0,v1),w);
  347. IF w < 0 THEN
  348. IF swapped THEN Raster.Put(img,yy,x,pixAlphaMap[0],srcOverDstMode); ELSE Raster.Put(img,x,yy,pixAlphaMap[0],srcOverDstMode); END;
  349. ELSIF w < 1 THEN
  350. IF swapped THEN Raster.Put(img,yy,x,pixAlphaMap[ENTIER(255*w)],srcOverDstMode); ELSE Raster.Put(img,x,yy,pixAlphaMap[ENTIER(255*w)],srcOverDstMode); END;
  351. END;
  352. v := v + dx; w := v - halfWidth;
  353. END;
  354. IF dm < 0 THEN
  355. INC(y,incy);
  356. dm := dm + dx;
  357. d0 := d0 + sdy; d1 := d1 + sdy;
  358. END;
  359. dm := dm - dy;
  360. d0 := d0 + sdx; d1 := d1 + sdx;
  361. INC(x,incx);
  362. END;
  363. (*VAR
  364. dx, dy, ig: Real;
  365. x01, y01, x02, y02: Real;
  366. x11, y11, x12, y12: Real;
  367. BEGIN
  368. dx := x1 - x0;
  369. dy := y1 - y0;
  370. ig := halfWidth * InvSqrt(dx*dx + dy*dy);
  371. dx := dx*ig; dy := dy*ig;
  372. x01 := x0 + dy;
  373. y01 := y0 - dx;
  374. x11 := x1 + dy;
  375. y11 := y1 - dx;
  376. x02 := x01 - 2*dy;
  377. y02 := y01 + 2*dx;
  378. x12 := x11 - 2*dy;
  379. y12 := y11 + 2*dx;
  380. ThinSmoothLineReal(img, x01,y01, x11,y11, pixAlphaMap, srcOverDstMode);
  381. ThinSmoothLineReal(img, x02,y02, x12,y12, pixAlphaMap, srcOverDstMode);
  382. ThinSmoothLineReal(img, x01,y01, x02,y02, pixAlphaMap, srcOverDstMode);
  383. ThinSmoothLineReal(img, x11,y11, x12,y12, pixAlphaMap, srcOverDstMode);*)
  384. END ThickSmoothLineReal;
  385. PROCEDURE Round(x: Real): LONGINT;
  386. BEGIN
  387. IF x >= 0 THEN
  388. RETURN ENTIER(x+0.5);
  389. ELSE
  390. RETURN -ENTIER(-x+0.5);
  391. END;
  392. END Round;
  393. (*
  394. Find intersection of a line with a given rectangle
  395. l, r, t, b: left,right,top,bottom coordinates of the rectangle
  396. x0, y0: starting line point
  397. x1, y1: end line point
  398. Intersection points are returned in x0, y0, x1, y1
  399. *)
  400. PROCEDURE ClipLineReal(l, t, r, b: Real; VAR x0, y0, x1, y1: Real): BOOLEAN;
  401. VAR
  402. dy, dx, x00, y00: Real;
  403. BEGIN
  404. dx := x1 - x0;
  405. dy := y1 - y0;
  406. IF dy = 0 THEN (* horizontal line *)
  407. IF (y0 >= t) & (y0 <= b) THEN
  408. IF x0 <= x1 THEN
  409. RETURN (x0 <= r) & (x1 >= l);
  410. ELSE
  411. RETURN (x1 <= r) & (x0 >= l);
  412. END;
  413. ELSE
  414. RETURN FALSE;
  415. END;
  416. ELSIF dx = 0 THEN (* vertical line *)
  417. IF (x0 >= l) & (x0 <= r) THEN
  418. IF y0 <= y1 THEN
  419. RETURN (y0 <= b) & (y1 >= t);
  420. ELSE
  421. RETURN (y1 <= b) & (y0 >= t);
  422. END;
  423. ELSE
  424. RETURN FALSE;
  425. END;
  426. ELSE
  427. IF x0 < x1 THEN
  428. IF (x0 <= r) & (x1 >= l) THEN
  429. IF y0 <= y1 THEN
  430. IF (y0 <= b) & (y1 >= t) THEN
  431. x00 := x0;
  432. y00 := y0;
  433. IF x0 < l THEN
  434. (* intersection with x = left *)
  435. y0 := y00 + (dy*(l-x00)) / dx; x0 := l;
  436. IF y0 < t THEN
  437. (* intersection with y = tody *)
  438. x0 := x00 + (dx*(t-y00)) / dy; y0 := t;
  439. END;
  440. ELSIF y0 < t THEN
  441. (* intersection with y = tody *)
  442. x0 := x00 + (dx*(t-y00)) / dy; y0 := t;
  443. IF x0 < l THEN
  444. (* intersection with x = left *)
  445. y0 := y00 + (dy*(l-x00)) / dx; x0 := l;
  446. END;
  447. END;
  448. IF x1 > r THEN
  449. (* intersection with x = right *)
  450. y1 := y00 + (dy*(r-x00)) / dx; x1 := r;
  451. IF y1 > b THEN
  452. (* intersection with y = bottom *)
  453. x1 := x00 + (dx*(b-y00)) / dy; y1 := b;
  454. END;
  455. ELSIF y1 > b THEN
  456. (* intersection with y = bottom *)
  457. x1 := x00 + (dx*(b-y00)) / dy; y1 := b;
  458. IF x1 > r THEN
  459. (* intersection with x = right *)
  460. y1 := y00 + (dy*(r-x00)) / dx; x1 := r;
  461. END;
  462. END;
  463. ASSERT(x0 >= l);
  464. ASSERT(y0 >= t);
  465. ASSERT(x1 <= r);
  466. ASSERT(y1 <= b);
  467. ELSE
  468. RETURN FALSE;
  469. END;
  470. ELSIF (y1 <= b) & (y0 >= t) THEN (* y0 > y1, dy < 0 *)
  471. x00 := x0;
  472. y00 := y0;
  473. dy := -dy;
  474. IF x0 < l THEN
  475. (* intersection with x = left *)
  476. y0 := y00 - (dy*(l-x00)) / dx; x0 := l;
  477. IF y0 > b THEN
  478. (* intersection with y = bottom *)
  479. x0 := x00 - (dx*(b-y00)) / dy; y0 := b;
  480. END;
  481. ELSIF y0 > b THEN
  482. (* intersection with y = bottom *)
  483. x0 := x00 - (dx*(b-y00)) / dy; y0 := b;
  484. IF x0 < l THEN
  485. (* intersection with x = left *)
  486. y0 := y00 - (dy*(l-x00)) / dx; x0 := l;
  487. END;
  488. END;
  489. IF x1 > r THEN
  490. (* intersection with x = right *)
  491. y1 := y00 - (dy*(r-x00)) / dx; x1 := r;
  492. IF y1 < t THEN
  493. (* intersection with y = tody *)
  494. x1 := x00 - (dx*(t-y00)) / dy; y1 := t;
  495. END;
  496. ELSIF y1 < t THEN
  497. (* intersection with y = tody *)
  498. x1 := x00 - (dx*(t-y00)) / dy; y1 := t;
  499. IF x1 > r THEN
  500. (* intersection with x = right *)
  501. y1 := y00 - (dy*(r-x00)) / dx; x1 := r;
  502. END;
  503. END;
  504. ASSERT(x0 >= l);
  505. ASSERT(y0 <= b);
  506. ASSERT(x1 <= r);
  507. ASSERT(y1 >= t);
  508. ELSE
  509. RETURN FALSE;
  510. END;
  511. ELSE
  512. RETURN FALSE;
  513. END;
  514. ELSE (* x0 >= x1 *)
  515. IF (x1 <= r) & (x0 >= l) THEN
  516. IF y0 <= y1 THEN
  517. IF (y0 <= b) & (y1 >= t) THEN
  518. x00 := x0;
  519. y00 := y0;
  520. dx := -dx;
  521. IF x0 > r THEN
  522. (* intersection with x = right *)
  523. y0 := y00 - (dy*(r-x00)) / dx; x0 := r;
  524. IF y0 < t THEN
  525. (* intersection with y = tody *)
  526. x0 := x00 - (dx*(t-y00)) / dy; y0 := t;
  527. END;
  528. ELSIF y0 < t THEN
  529. (* intersection with y = tody *)
  530. x0 := x00 - (dx*(t-y00)) / dy; y0 := t;
  531. IF x0 > r THEN
  532. (* intersection with x = right *)
  533. y0 := y00 - (dy*(r-x00)) / dx; x0 := r;
  534. END;
  535. END;
  536. IF x1 < l THEN
  537. (* intersection with x = left *)
  538. y1 := y00 - (dy*(l-x00)) / dx; x1 := l;
  539. IF y1 > b THEN
  540. (* intersection with y = bottom *)
  541. x1 := x00 - (dx*(b-y00)) / dy; y1 := b;
  542. END;
  543. ELSIF y1 > b THEN
  544. (* intersection with y = bottom *)
  545. x1 := x00 - (dx*(b-y00)) / dy; y1 := b;
  546. IF x1 < l THEN
  547. (* intersection with x = left *)
  548. y1 := y00 - (dy*(l-x00)) / dx; x1 := l;
  549. END;
  550. END;
  551. ASSERT(x0 <= r);
  552. ASSERT(y0 >= t);
  553. ASSERT(x1 >= l);
  554. ASSERT(y1 <= b);
  555. ELSE
  556. RETURN FALSE;
  557. END;
  558. ELSIF (y1 <= b) & (y0 >= t) THEN (* dy < 0, dx < 0 *)
  559. x00 := x0;
  560. y00 := y0;
  561. dy := -dy;
  562. dx := -dx;
  563. IF x0 > r THEN
  564. (* intersection with x = right *)
  565. y0 := y00 + (dy*(r-x00)) / dx; x0 := r;
  566. IF y0 > b THEN
  567. (* intersection with y = bottom *)
  568. x0 := x00 + (dx*(b-y00)) / dy; y0 := b;
  569. END;
  570. ELSIF y0 > b THEN
  571. (* intersection with y = bottom *)
  572. x0 := x00 + (dx*(b-y00)) / dy; y0 := b;
  573. IF x0 > r THEN
  574. (* intersection with x = right *)
  575. y0 := y00 + (dy*(r-x00)) / dx; x0 := r;
  576. END;
  577. END;
  578. IF x1 < l THEN
  579. (* intersection with x = left *)
  580. y1 := y00 + (dy*(l-x00)) / dx; x1 := l;
  581. IF y1 < t THEN
  582. (* intersection with y = tody *)
  583. x1 := x00 + (dx*(t-y00)) / dy; y1 := t;
  584. END;
  585. ELSIF y1 < t THEN
  586. (* intersection with y = tody *)
  587. x1 := x00 + (dx*(t-y00)) / dy; y1 := t;
  588. IF x1 < l THEN
  589. (* intersection with x = left *)
  590. y1 := y00 + (dy*(l-x00)) / dx; x1 := l;
  591. END;
  592. END;
  593. ASSERT(x0 <= r);
  594. ASSERT(y0 <= b);
  595. ASSERT(x1 >= l);
  596. ASSERT(y1 >= t);
  597. ELSE
  598. RETURN FALSE;
  599. END;
  600. ELSE
  601. RETURN FALSE;
  602. END;
  603. END;
  604. END;
  605. RETURN TRUE
  606. END ClipLineReal;
  607. END WMGraphicsSmooth.