MainUnit.pas 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. unit MainUnit;
  2. (* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1 or LGPL 2.1 with linking exception
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * Alternatively, the contents of this file may be used under the terms of the
  16. * Free Pascal modified version of the GNU Lesser General Public License
  17. * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
  18. * of this license are applicable instead of those above.
  19. * Please see the file LICENSE.txt for additional information concerning this
  20. * license.
  21. *
  22. * The Original Code is Lion Example
  23. *
  24. * The Initial Developer(s) of the Original Code is:
  25. * Christian-W. Budde <[email protected]>
  26. *
  27. * Portions created by the Initial Developer are Copyright (C) 2000-2012
  28. * the Initial Developer. All Rights Reserved.
  29. *
  30. *
  31. * ***** END LICENSE BLOCK ***** *)
  32. interface
  33. {$include GR32.inc}
  34. uses
  35. {$IFDEF FPC} LCLIntf, {$ENDIF} Classes, ComCtrls, Controls, Forms,
  36. GR32,
  37. GR32_Image,
  38. GR32_Paths,
  39. GR32_Brushes;
  40. type
  41. TFrmLineSimplification = class(TForm)
  42. PaintBox32: TPaintBox32;
  43. procedure FormCreate(Sender: TObject);
  44. procedure FormDestroy(Sender: TObject);
  45. procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  46. procedure PaintBox32PaintBuffer(Sender: TObject);
  47. procedure PaintBox32MouseDown(Sender: TObject; Button: TMouseButton;
  48. Shift: TShiftState; X, Y: Integer);
  49. procedure PaintBox32MouseUp(Sender: TObject; Button: TMouseButton;
  50. Shift: TShiftState; X, Y: Integer);
  51. procedure PaintBox32MouseMove(Sender: TObject; Shift: TShiftState; X,
  52. Y: Integer);
  53. private
  54. FPoints: TArrayOfFloatPoint;
  55. FSimplifiedPoints: TArrayOfFloatPoint;
  56. FEpsilon: TFloat;
  57. FCanvas: TCanvas32;
  58. FSourceBrush: TStrokeBrush;
  59. FSimplifiedBrush: TStrokeBrush;
  60. end;
  61. var
  62. FrmLineSimplification: TFrmLineSimplification;
  63. implementation
  64. {$R *.dfm}
  65. uses
  66. Types,
  67. SysUtils,
  68. Windows,
  69. GR32_VectorUtils;
  70. const
  71. StartEpsilon = 1;
  72. MinEpsilon = 0.01;
  73. MaxEpsilon = 500;
  74. resourcestring
  75. sHelp = 'Use the mouse to draw an arbitrary polyline.'+#13#13+
  76. 'Use the + and - keys to control how aggresively the line is simplified.';
  77. sInfo = 'Source points: %.0n'#13+
  78. 'Simplified points: %.0n'#13+
  79. 'Epsilon: %.2n';
  80. { TFrmLineSimplification }
  81. procedure TFrmLineSimplification.FormCreate(Sender: TObject);
  82. begin
  83. FCanvas := TCanvas32.Create(PaintBox32.Buffer);
  84. FSourceBrush := FCanvas.Brushes.Add(TStrokeBrush) as TStrokeBrush;
  85. FSourceBrush.FillColor := clTrRed32;
  86. FSourceBrush.StrokeWidth := 5;
  87. FSimplifiedBrush := FCanvas.Brushes.Add(TStrokeBrush) as TStrokeBrush;
  88. FSimplifiedBrush.FillColor := clTrBlack32;
  89. FSimplifiedBrush.StrokeWidth := 1;
  90. FEpsilon := StartEpsilon;
  91. end;
  92. procedure TFrmLineSimplification.FormDestroy(Sender: TObject);
  93. begin
  94. FCanvas.Free;
  95. end;
  96. procedure TFrmLineSimplification.FormKeyDown(Sender: TObject; var Key: Word;
  97. Shift: TShiftState);
  98. begin
  99. case Key of
  100. VK_ADD, VK_SUBTRACT:
  101. begin
  102. case Key of
  103. VK_SUBTRACT:
  104. begin
  105. if (FEpsilon <= MinEpsilon) then
  106. exit;
  107. FEpsilon := FEpsilon / 2;
  108. end;
  109. VK_ADD:
  110. begin
  111. if (FEpsilon >= MaxEpsilon) then
  112. exit;
  113. FEpsilon := FEpsilon * 2;
  114. end;
  115. end;
  116. if Length(FPoints) > 0 then
  117. FSimplifiedPoints := VertexReduction(FPoints, FEpsilon);
  118. PaintBox32.Invalidate;
  119. end;
  120. VK_ESCAPE: // Escape
  121. Close;
  122. end;
  123. end;
  124. procedure TFrmLineSimplification.PaintBox32MouseDown(Sender: TObject;
  125. Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  126. begin
  127. SetLength(FSimplifiedPoints, 0);
  128. SetLength(FPoints, 1);
  129. FPoints[0] := FloatPoint(X, Y);
  130. PaintBox32.OnMouseMove := PaintBox32MouseMove;
  131. end;
  132. procedure TFrmLineSimplification.PaintBox32MouseMove(Sender: TObject;
  133. Shift: TShiftState; X, Y: Integer);
  134. var
  135. Index: Integer;
  136. begin
  137. Index := High(FPoints);
  138. if (FPoints[Index].X <> X) and (FPoints[Index].Y <> Y) then
  139. begin
  140. SetLength(FPoints, Length(FPoints)+1);
  141. FPoints[High(FPoints)] := FloatPoint(X, Y);
  142. PaintBox32.Invalidate;
  143. end;
  144. end;
  145. procedure TFrmLineSimplification.PaintBox32MouseUp(Sender: TObject;
  146. Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  147. var
  148. Index: Integer;
  149. begin
  150. Index := High(FPoints);
  151. if (FPoints[Index].X <> X) and (FPoints[Index].Y <> Y) then
  152. begin
  153. SetLength(FPoints, Length(FPoints)+1);
  154. FPoints[High(FPoints)] := FloatPoint(X, Y);
  155. end;
  156. // Enable the next line to close the polyline (i.e. a polygon). See issue #87
  157. // FPoints[High(FPoints)] := FPoints[0];
  158. // Simplify the polyline
  159. FSimplifiedPoints := VertexReduction(FPoints, FEpsilon);
  160. PaintBox32.Invalidate;
  161. PaintBox32.OnMouseMove := nil;
  162. end;
  163. procedure TFrmLineSimplification.PaintBox32PaintBuffer(Sender: TObject);
  164. var
  165. Index: Integer;
  166. r: TRect;
  167. rf: TFloatRect;
  168. ColorPoint: TColor32;
  169. begin
  170. PaintBox32.Buffer.Clear(clWhite32);
  171. r := PaintBox32.Buffer.BoundsRect;
  172. if (Length(FPoints) = 0) then
  173. begin
  174. PaintBox32.Buffer.Textout(r, DT_CENTER or DT_NOPREFIX or DT_CALCRECT, sHelp);
  175. GR32.OffsetRect(r, r.Left + (PaintBox32.Buffer.Width - r.Width) div 2, r.Top + (PaintBox32.Buffer.Height - r.Height) div 2);
  176. PaintBox32.Buffer.Textout(r, DT_CENTER or DT_NOPREFIX, sHelp);
  177. exit;
  178. end;
  179. PaintBox32.Buffer.Textout(r, 0, Format(sInfo, [Length(FPoints)*1.0, Length(FSimplifiedPoints)*1.0, FEpsilon]));
  180. if (Length(FPoints) > 0) then
  181. begin
  182. FSourceBrush.Visible := True;
  183. FSimplifiedBrush.Visible := False;
  184. FCanvas.PolyLine(FPoints);
  185. FCanvas.EndPath;
  186. ColorPoint := SetAlpha(FSourceBrush.FillColor, 255);
  187. for Index := 0 to High(FPoints) do
  188. begin
  189. rf := FloatRect(FPoints[Index], FPoints[Index]);
  190. rf.Inflate(1.0, 1.0);
  191. r := MakeRect(rf, rrClosest);
  192. PaintBox32.Buffer.FillRectTS(r, ColorPoint);
  193. end;
  194. end;
  195. if (Length(FSimplifiedPoints) > 0) then
  196. begin
  197. FSourceBrush.Visible := False;
  198. FSimplifiedBrush.Visible := True;
  199. FCanvas.PolyLine(FSimplifiedPoints);
  200. FCanvas.EndPath;
  201. ColorPoint := SetAlpha(FSimplifiedBrush.FillColor, 255);
  202. for Index := 0 to High(FSimplifiedPoints) do
  203. begin
  204. rf := FloatRect(FSimplifiedPoints[Index], FSimplifiedPoints[Index]);
  205. rf.Inflate(4.0, 4.0);
  206. r := MakeRect(rf, rrClosest);
  207. PaintBox32.Buffer.FrameRectTS(r, ColorPoint);
  208. end;
  209. end;
  210. end;
  211. end.