fpvtocanvas.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. unit fpvtocanvas;
  2. {$mode objfpc}{$H+}
  3. interface
  4. {.$define USE_LCL_CANVAS}
  5. uses
  6. Classes, SysUtils, Math,
  7. {$ifdef USE_LCL_CANVAS}
  8. Graphics, LCLIntf,
  9. {$endif}
  10. fpcanvas,
  11. fpimage,
  12. fpvectorial;
  13. procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument;
  14. ADest: TFPCustomCanvas;
  15. ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
  16. procedure DrawFPVPathToCanvas(ASource: TvVectorialDocument; CurPath: TPath;
  17. ADest: TFPCustomCanvas;
  18. ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
  19. procedure DrawFPVEntityToCanvas(ASource: TvVectorialDocument; CurEntity: TvEntity;
  20. ADest: TFPCustomCanvas;
  21. ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
  22. procedure DrawFPVTextToCanvas(ASource: TvVectorialDocument; CurText: TvText;
  23. ADest: TFPCustomCanvas;
  24. ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
  25. implementation
  26. {$ifndef Windows}
  27. {$define FPVECTORIALDEBUG}
  28. {$endif}
  29. function Rotate2DPoint(P,Fix :TPoint; alpha:double): TPoint;
  30. var
  31. sinus, cosinus : Extended;
  32. begin
  33. SinCos(alpha, sinus, cosinus);
  34. P.x := P.x - Fix.x;
  35. P.y := P.y - Fix.y;
  36. result.x := Round(p.x*cosinus + p.y*sinus) + fix.x ;
  37. result.y := Round(-p.x*sinus + p.y*cosinus) + Fix.y;
  38. end;
  39. procedure DrawRotatedEllipse(
  40. ADest: TFPCustomCanvas;
  41. CurEllipse: TvEllipse;
  42. ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
  43. var
  44. PointList: array[0..6] of TPoint;
  45. f: TPoint;
  46. dk, x1, x2, y1, y2: Integer;
  47. {$ifdef USE_LCL_CANVAS}
  48. ALCLDest: TCanvas absolute ADest;
  49. {$endif}
  50. begin
  51. {$ifdef USE_LCL_CANVAS}
  52. CurEllipse.CalculateBoundingRectangle();
  53. x1 := CurEllipse.BoundingRect.Left;
  54. x2 := CurEllipse.BoundingRect.Right;
  55. y1 := CurEllipse.BoundingRect.Top;
  56. y2 := CurEllipse.BoundingRect.Bottom;
  57. dk := Round(0.654 * Abs(y2-y1));
  58. f.x := Round(CurEllipse.CenterX);
  59. f.y := Round(CurEllipse.CenterY - 1);
  60. PointList[0] := Rotate2DPoint(Point(x1, f.y), f, CurEllipse.Angle) ; // Startpoint
  61. PointList[1] := Rotate2DPoint(Point(x1, f.y - dk), f, CurEllipse.Angle);
  62. //Controlpoint of Startpoint first part
  63. PointList[2] := Rotate2DPoint(Point(x2- 1, f.y - dk), f, CurEllipse.Angle);
  64. //Controlpoint of secondpoint first part
  65. PointList[3] := Rotate2DPoint(Point(x2 -1 , f.y), f, CurEllipse.Angle);
  66. // Firstpoint of secondpart
  67. PointList[4] := Rotate2DPoint(Point(x2-1 , f.y + dk), f, CurEllipse.Angle);
  68. // Controllpoint of secondpart firstpoint
  69. PointList[5] := Rotate2DPoint(Point(x1, f.y + dk), f, CurEllipse.Angle);
  70. // Conrollpoint of secondpart endpoint
  71. PointList[6] := PointList[0]; // Endpoint of
  72. // Back to the startpoint
  73. ALCLDest.PolyBezier(Pointlist[0]);
  74. {$endif}
  75. end;
  76. {@@
  77. This function draws a FPVectorial vectorial image to a TFPCustomCanvas
  78. descendent, such as TCanvas from the LCL.
  79. Be careful that by default this routine does not execute coordinate transformations,
  80. and that FPVectorial works with a start point in the bottom-left corner, with
  81. the X growing to the right and the Y growing to the top. This will result in
  82. an image in TFPCustomCanvas mirrored in the Y axis in relation with the document
  83. as seen in a PDF viewer, for example. This can be easily changed with the
  84. provided parameters. To have the standard view of an image viewer one could
  85. use this function like this:
  86. DrawFPVectorialToCanvas(ASource, ADest, 0, ASource.Height, 1.0, -1.0);
  87. }
  88. {.$define FPVECTORIAL_TOCANVAS_DEBUG}
  89. procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument;
  90. ADest: TFPCustomCanvas;
  91. ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
  92. var
  93. i: Integer;
  94. CurEntity: TvEntity;
  95. begin
  96. {$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
  97. WriteLn(':>DrawFPVectorialToCanvas');
  98. {$endif}
  99. for i := 0 to ASource.GetEntitiesCount - 1 do
  100. begin
  101. CurEntity := ASource.GetEntity(i);
  102. if CurEntity is TPath then DrawFPVPathToCanvas(ASource, TPath(CurEntity), ADest, ADestX, ADestY, AMulX, AMulY)
  103. else if CurEntity is TvText then DrawFPVTextToCanvas(ASource, TvText(CurEntity), ADest, ADestX, ADestY, AMulX, AMulY)
  104. else DrawFPVEntityToCanvas(ASource, CurEntity, ADest, ADestX, ADestY, AMulX, AMulY);
  105. end;
  106. {$ifdef FPVECTORIALDEBUG}
  107. WriteLn(':<DrawFPVectorialToCanvas');
  108. {$endif}
  109. end;
  110. procedure DrawFPVPathToCanvas(ASource: TvVectorialDocument; CurPath: TPath;
  111. ADest: TFPCustomCanvas;
  112. ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
  113. function CoordToCanvasX(ACoord: Double): Integer;
  114. begin
  115. Result := Round(ADestX + AmulX * ACoord);
  116. end;
  117. function CoordToCanvasY(ACoord: Double): Integer;
  118. begin
  119. Result := Round(ADestY + AmulY * ACoord);
  120. end;
  121. var
  122. j, k: Integer;
  123. PosX, PosY: Integer; // Not modified by ADestX, etc
  124. CurSegment: TPathSegment;
  125. Cur2DSegment: T2DSegment absolute CurSegment;
  126. Cur2DBSegment: T2DBezierSegment absolute CurSegment;
  127. // For bezier
  128. CurX, CurY: Integer; // Not modified by ADestX, etc
  129. CurveLength: Integer;
  130. t: Double;
  131. begin
  132. PosX := 0;
  133. PosY := 0;
  134. ADest.Brush.Style := bsClear;
  135. ADest.MoveTo(ADestX, ADestY);
  136. CurPath.PrepareForSequentialReading;
  137. // Set the path Pen and Brush options
  138. ADest.Pen.Style := CurPath.Pen.Style;
  139. ADest.Pen.Width := CurPath.Pen.Width;
  140. ADest.Brush.Style := CurPath.Brush.Style;
  141. ADest.Pen.FPColor := CurPath.Pen.Color;
  142. ADest.Brush.FPColor := CurPath.Brush.Color;
  143. {$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
  144. Write(Format('[Path] ID=%d', [i]));
  145. {$endif}
  146. for j := 0 to CurPath.Len - 1 do
  147. begin
  148. //WriteLn('j = ', j);
  149. CurSegment := TPathSegment(CurPath.Next());
  150. case CurSegment.SegmentType of
  151. stMoveTo:
  152. begin
  153. ADest.MoveTo(CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y));
  154. {$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
  155. Write(Format(' M%d,%d', [CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y)]));
  156. {$endif}
  157. end;
  158. // This element can override temporarely the Pen
  159. st2DLineWithPen:
  160. begin
  161. ADest.Pen.FPColor := T2DSegmentWithPen(Cur2DSegment).Pen.Color;
  162. ADest.LineTo(CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y));
  163. ADest.Pen.FPColor := CurPath.Pen.Color;
  164. {$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
  165. Write(Format(' L%d,%d', [CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y)]));
  166. {$endif}
  167. end;
  168. st2DLine, st3DLine:
  169. begin
  170. ADest.LineTo(CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y));
  171. {$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
  172. Write(Format(' L%d,%d', [CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y)]));
  173. {$endif}
  174. end;
  175. { To draw a bezier we need to divide the interval in parts and make
  176. lines between this parts }
  177. st2DBezier, st3DBezier:
  178. begin
  179. CurveLength :=
  180. Round(sqrt(sqr(Cur2DBSegment.X3 - PosX) + sqr(Cur2DBSegment.Y3 - PosY))) +
  181. Round(sqrt(sqr(Cur2DBSegment.X2 - Cur2DBSegment.X3) + sqr(Cur2DBSegment.Y2 - Cur2DBSegment.Y3))) +
  182. Round(sqrt(sqr(Cur2DBSegment.X - Cur2DBSegment.X3) + sqr(Cur2DBSegment.Y - Cur2DBSegment.Y3)));
  183. for k := 1 to CurveLength do
  184. begin
  185. t := k / CurveLength;
  186. CurX := Round(sqr(1 - t) * (1 - t) * PosX + 3 * t * sqr(1 - t) * Cur2DBSegment.X2 + 3 * t * t * (1 - t) * Cur2DBSegment.X3 + t * t * t * Cur2DBSegment.X);
  187. CurY := Round(sqr(1 - t) * (1 - t) * PosY + 3 * t * sqr(1 - t) * Cur2DBSegment.Y2 + 3 * t * t * (1 - t) * Cur2DBSegment.Y3 + t * t * t * Cur2DBSegment.Y);
  188. ADest.LineTo(CoordToCanvasX(CurX), CoordToCanvasY(CurY));
  189. end;
  190. PosX := Round(Cur2DBSegment.X);
  191. PosY := Round(Cur2DBSegment.Y);
  192. end;
  193. end;
  194. end;
  195. {$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
  196. WriteLn('');
  197. {$endif}
  198. end;
  199. procedure DrawFPVEntityToCanvas(ASource: TvVectorialDocument; CurEntity: TvEntity;
  200. ADest: TFPCustomCanvas;
  201. ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
  202. function CoordToCanvasX(ACoord: Double): Integer;
  203. begin
  204. Result := Round(ADestX + AmulX * ACoord);
  205. end;
  206. function CoordToCanvasY(ACoord: Double): Integer;
  207. begin
  208. Result := Round(ADestY + AmulY * ACoord);
  209. end;
  210. var
  211. i: Integer;
  212. {$ifdef USE_LCL_CANVAS}
  213. ALCLDest: TCanvas;
  214. {$endif}
  215. // For entities
  216. CurCircle: TvCircle;
  217. CurEllipse: TvEllipse;
  218. //
  219. CurArc: TvCircularArc;
  220. FinalStartAngle, FinalEndAngle: double;
  221. BoundsLeft, BoundsTop, BoundsRight, BoundsBottom,
  222. IntStartAngle, IntAngleLength, IntTmp: Integer;
  223. //
  224. CurDim: TvAlignedDimension;
  225. Points: array of TPoint;
  226. UpperDim, LowerDim: T3DPoint;
  227. begin
  228. {$ifdef USE_LCL_CANVAS}
  229. ALCLDest := TCanvas(ADest);
  230. {$endif}
  231. ADest.Brush.Style := CurEntity.Brush.Style;
  232. ADest.Pen.Style := CurEntity.Pen.Style;
  233. ADest.Pen.FPColor := CurEntity.Pen.Color;
  234. ADest.Brush.FPColor := CurEntity.Brush.Color;
  235. if CurEntity is TvCircle then
  236. begin
  237. CurCircle := CurEntity as TvCircle;
  238. ADest.Ellipse(
  239. CoordToCanvasX(CurCircle.CenterX - CurCircle.Radius),
  240. CoordToCanvasY(CurCircle.CenterY - CurCircle.Radius),
  241. CoordToCanvasX(CurCircle.CenterX + CurCircle.Radius),
  242. CoordToCanvasY(CurCircle.CenterY + CurCircle.Radius)
  243. );
  244. end
  245. else if CurEntity is TvEllipse then
  246. begin
  247. CurEllipse := CurEntity as TvEllipse;
  248. DrawRotatedEllipse(ADest, CurEllipse);
  249. end
  250. else if CurEntity is TvCircularArc then
  251. begin
  252. CurArc := CurEntity as TvCircularArc;
  253. {$ifdef USE_LCL_CANVAS}
  254. // ToDo: Consider a X axis inversion
  255. // If the Y axis is inverted, then we need to mirror our angles as well
  256. BoundsLeft := CoordToCanvasX(CurArc.CenterX - CurArc.Radius);
  257. BoundsTop := CoordToCanvasY(CurArc.CenterY - CurArc.Radius);
  258. BoundsRight := CoordToCanvasX(CurArc.CenterX + CurArc.Radius);
  259. BoundsBottom := CoordToCanvasY(CurArc.CenterY + CurArc.Radius);
  260. {if AMulY > 0 then
  261. begin}
  262. FinalStartAngle := CurArc.StartAngle;
  263. FinalEndAngle := CurArc.EndAngle;
  264. {end
  265. else // AMulY is negative
  266. begin
  267. // Inverting the angles generates the correct result for Y axis inversion
  268. if CurArc.EndAngle = 0 then FinalStartAngle := 0
  269. else FinalStartAngle := 360 - 1* CurArc.EndAngle;
  270. if CurArc.StartAngle = 0 then FinalEndAngle := 0
  271. else FinalEndAngle := 360 - 1* CurArc.StartAngle;
  272. end;}
  273. IntStartAngle := Round(16*FinalStartAngle);
  274. IntAngleLength := Round(16*(FinalEndAngle - FinalStartAngle));
  275. // On Gtk2 and Carbon, the Left really needs to be to the Left of the Right position
  276. // The same for the Top and Bottom
  277. // On Windows it works fine either way
  278. // On Gtk2 if the positions are inverted then the arcs are screwed up
  279. // In Carbon if the positions are inverted, then the arc is inverted
  280. if BoundsLeft > BoundsRight then
  281. begin
  282. IntTmp := BoundsLeft;
  283. BoundsLeft := BoundsRight;
  284. BoundsRight := IntTmp;
  285. end;
  286. if BoundsTop > BoundsBottom then
  287. begin
  288. IntTmp := BoundsTop;
  289. BoundsTop := BoundsBottom;
  290. BoundsBottom := IntTmp;
  291. end;
  292. // Arc(ALeft, ATop, ARight, ABottom, Angle16Deg, Angle16DegLength: Integer);
  293. {$ifdef FPVECTORIALDEBUG}
  294. WriteLn(Format('Drawing Arc Center=%f,%f Radius=%f StartAngle=%f AngleLength=%f',
  295. [CurArc.CenterX, CurArc.CenterY, CurArc.Radius, IntStartAngle/16, IntAngleLength/16]));
  296. {$endif}
  297. ADest.Pen.FPColor := CurArc.Pen.Color;
  298. ALCLDest.Arc(
  299. BoundsLeft, BoundsTop, BoundsRight, BoundsBottom,
  300. IntStartAngle, IntAngleLength
  301. );
  302. ADest.Pen.FPColor := colBlack;
  303. // Debug info
  304. // {$define FPVECTORIALDEBUG}
  305. // {$ifdef FPVECTORIALDEBUG}
  306. // WriteLn(Format('Drawing Arc x1y1=%d,%d x2y2=%d,%d start=%d end=%d',
  307. // [BoundsLeft, BoundsTop, BoundsRight, BoundsBottom, IntStartAngle, IntAngleLength]));
  308. // {$endif}
  309. { ADest.TextOut(CoordToCanvasX(CurArc.CenterX), CoordToCanvasY(CurArc.CenterY),
  310. Format('R=%d S=%d L=%d', [Round(CurArc.Radius*AMulX), Round(FinalStartAngle),
  311. Abs(Round((FinalEndAngle - FinalStartAngle)))]));
  312. ADest.Pen.Color := TColor($DDDDDD);
  313. ADest.Rectangle(
  314. BoundsLeft, BoundsTop, BoundsRight, BoundsBottom);
  315. ADest.Pen.Color := clBlack;}
  316. {$endif}
  317. end
  318. else if CurEntity is TvAlignedDimension then
  319. begin
  320. CurDim := CurEntity as TvAlignedDimension;
  321. //
  322. // Draws this shape:
  323. // vertical horizontal
  324. // ___
  325. // | | or ---| X cm
  326. // | --|
  327. // Which marks the dimension
  328. ADest.MoveTo(CoordToCanvasX(CurDim.BaseRight.X), CoordToCanvasY(CurDim.BaseRight.Y));
  329. ADest.LineTo(CoordToCanvasX(CurDim.DimensionRight.X), CoordToCanvasY(CurDim.DimensionRight.Y));
  330. ADest.LineTo(CoordToCanvasX(CurDim.DimensionLeft.X), CoordToCanvasY(CurDim.DimensionLeft.Y));
  331. ADest.LineTo(CoordToCanvasX(CurDim.BaseLeft.X), CoordToCanvasY(CurDim.BaseLeft.Y));
  332. // Now the arrows
  333. // horizontal
  334. SetLength(Points, 3);
  335. if CurDim.DimensionRight.Y = CurDim.DimensionLeft.Y then
  336. begin
  337. ADest.Brush.FPColor := colBlack;
  338. ADest.Brush.Style := bsSolid;
  339. // Left arrow
  340. Points[0] := Point(CoordToCanvasX(CurDim.DimensionLeft.X), CoordToCanvasY(CurDim.DimensionLeft.Y));
  341. Points[1] := Point(Points[0].X + 7, Points[0].Y - 3);
  342. Points[2] := Point(Points[0].X + 7, Points[0].Y + 3);
  343. ADest.Polygon(Points);
  344. // Right arrow
  345. Points[0] := Point(CoordToCanvasX(CurDim.DimensionRight.X), CoordToCanvasY(CurDim.DimensionRight.Y));
  346. Points[1] := Point(Points[0].X - 7, Points[0].Y - 3);
  347. Points[2] := Point(Points[0].X - 7, Points[0].Y + 3);
  348. ADest.Polygon(Points);
  349. ADest.Brush.Style := bsClear;
  350. // Dimension text
  351. Points[0].X := CoordToCanvasX((CurDim.DimensionLeft.X+CurDim.DimensionRight.X)/2);
  352. Points[0].Y := CoordToCanvasY(CurDim.DimensionLeft.Y);
  353. LowerDim.X := CurDim.DimensionRight.X-CurDim.DimensionLeft.X;
  354. ADest.Font.Size := 10;
  355. ADest.TextOut(Points[0].X, Points[0].Y, Format('%.1f', [LowerDim.X]));
  356. end
  357. else
  358. begin
  359. ADest.Brush.FPColor := colBlack;
  360. ADest.Brush.Style := bsSolid;
  361. // There is no upper/lower preference for DimensionLeft/Right, so we need to check
  362. if CurDim.DimensionLeft.Y > CurDim.DimensionRight.Y then
  363. begin
  364. UpperDim := CurDim.DimensionLeft;
  365. LowerDim := CurDim.DimensionRight;
  366. end
  367. else
  368. begin
  369. UpperDim := CurDim.DimensionRight;
  370. LowerDim := CurDim.DimensionLeft;
  371. end;
  372. // Upper arrow
  373. Points[0] := Point(CoordToCanvasX(UpperDim.X), CoordToCanvasY(UpperDim.Y));
  374. Points[1] := Point(Points[0].X + Round(AMulX), Points[0].Y - Round(AMulY*3));
  375. Points[2] := Point(Points[0].X - Round(AMulX), Points[0].Y - Round(AMulY*3));
  376. ADest.Polygon(Points);
  377. // Lower arrow
  378. Points[0] := Point(CoordToCanvasX(LowerDim.X), CoordToCanvasY(LowerDim.Y));
  379. Points[1] := Point(Points[0].X + Round(AMulX), Points[0].Y + Round(AMulY*3));
  380. Points[2] := Point(Points[0].X - Round(AMulX), Points[0].Y + Round(AMulY*3));
  381. ADest.Polygon(Points);
  382. ADest.Brush.Style := bsClear;
  383. // Dimension text
  384. Points[0].X := CoordToCanvasX(CurDim.DimensionLeft.X);
  385. Points[0].Y := CoordToCanvasY((CurDim.DimensionLeft.Y+CurDim.DimensionRight.Y)/2);
  386. LowerDim.Y := CurDim.DimensionRight.Y-CurDim.DimensionLeft.Y;
  387. if LowerDim.Y < 0 then LowerDim.Y := -1 * LowerDim.Y;
  388. ADest.Font.Size := 10;
  389. ADest.TextOut(Points[0].X, Points[0].Y, Format('%.1f', [LowerDim.Y]));
  390. end;
  391. SetLength(Points, 0);
  392. { // Debug info
  393. ADest.TextOut(CoordToCanvasX(CurDim.BaseRight.X), CoordToCanvasY(CurDim.BaseRight.Y), 'BR');
  394. ADest.TextOut(CoordToCanvasX(CurDim.DimensionRight.X), CoordToCanvasY(CurDim.DimensionRight.Y), 'DR');
  395. ADest.TextOut(CoordToCanvasX(CurDim.DimensionLeft.X), CoordToCanvasY(CurDim.DimensionLeft.Y), 'DL');
  396. ADest.TextOut(CoordToCanvasX(CurDim.BaseLeft.X), CoordToCanvasY(CurDim.BaseLeft.Y), 'BL');}
  397. end;
  398. end;
  399. procedure DrawFPVTextToCanvas(ASource: TvVectorialDocument; CurText: TvText;
  400. ADest: TFPCustomCanvas;
  401. ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
  402. function CoordToCanvasX(ACoord: Double): Integer;
  403. begin
  404. Result := Round(ADestX + AmulX * ACoord);
  405. end;
  406. function CoordToCanvasY(ACoord: Double): Integer;
  407. begin
  408. Result := Round(ADestY + AmulY * ACoord);
  409. end;
  410. var
  411. i: Integer;
  412. {$ifdef USE_LCL_CANVAS}
  413. ALCLDest: TCanvas;
  414. {$endif}
  415. //
  416. LowerDim: T3DPoint;
  417. begin
  418. {$ifdef USE_LCL_CANVAS}
  419. ALCLDest := TCanvas(ADest);
  420. {$endif}
  421. ADest.Font.Size := Round(AmulX * CurText.Font.Size);
  422. ADest.Pen.Style := psSolid;
  423. ADest.Pen.FPColor := colBlack;
  424. ADest.Brush.Style := bsClear;
  425. {$ifdef USE_LCL_CANVAS}
  426. ALCLDest.Font.Orientation := Round(CurText.Font.Orientation * 16);
  427. {$endif}
  428. LowerDim.Y := CurText.Y + CurText.Font.Size;
  429. ADest.TextOut(CoordToCanvasX(CurText.X), CoordToCanvasY(LowerDim.Y), CurText.Value);
  430. end;
  431. end.