MainUnit.pas 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  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 Clipper grow example
  23. *
  24. * The Initial Developer of the Original Code is
  25. * Angus Johnson (http://www.angusj.com)
  26. *
  27. * Portions created by the Initial Developer are Copyright (C) 2000-2005
  28. * the Initial Developer. All Rights Reserved.
  29. *
  30. * ***** END LICENSE BLOCK ***** *)
  31. interface
  32. {$include GR32.inc}
  33. uses
  34. {$IFDEF FPC}LCLIntf, LResources, {$ENDIF}
  35. Windows, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls,
  36. ExtCtrls, Math, Vcl.ExtDlgs, Vcl.Menus, System.Actions, Vcl.ActnList,
  37. GR32,
  38. GR32_Polygons,
  39. GR32_VectorUtils,
  40. GR32_Image;
  41. type
  42. TFormGrow = class(TForm)
  43. Image: TImage32;
  44. MainMenu: TMainMenu;
  45. MenuItemFile: TMenuItem;
  46. N1: TMenuItem;
  47. MenuItemExit: TMenuItem;
  48. MenuItemRefresh: TMenuItem;
  49. MenuItemOptions: TMenuItem;
  50. MenuItemOptionsInflatePolygon: TMenuItem;
  51. MenuItemOptionsInflatePolyLine: TMenuItem;
  52. ActionList: TActionList;
  53. ActionRefresh: TAction;
  54. ActionFileExit: TAction;
  55. ActionOptionShapePolygon: TAction;
  56. ActionOptionShapePolyLine: TAction;
  57. Joinstyle1: TMenuItem;
  58. N2: TMenuItem;
  59. Endstyle1: TMenuItem;
  60. Miterjoin1: TMenuItem;
  61. Beveljoin1: TMenuItem;
  62. Beveljoin2: TMenuItem;
  63. RoundExjoin1: TMenuItem;
  64. ActionOptionJoinMiter: TAction;
  65. ActionOptionJoinBevel: TAction;
  66. ActionOptionJoinRound: TAction;
  67. ActionOptionJoinSquare: TAction;
  68. ActionOptionEndButt: TAction;
  69. ActionOptionEndSquare: TAction;
  70. ActionOptionEndRound: TAction;
  71. Action51: TMenuItem;
  72. Action52: TMenuItem;
  73. Action71: TMenuItem;
  74. ActionOptionJoinStyle: TAction;
  75. ActionOptionEndStyle: TAction;
  76. ActionOptionGrowClipper: TAction;
  77. ActionOptionGrowGraphics32: TAction;
  78. N3: TMenuItem;
  79. Growusing1: TMenuItem;
  80. Graphics321: TMenuItem;
  81. Clipper1: TMenuItem;
  82. ActionOptionGrowAngus: TAction;
  83. Image321: TMenuItem;
  84. ActionOptionJoinRoundEx: TAction;
  85. RoundExjoin2: TMenuItem;
  86. procedure ImageClick(Sender: TObject);
  87. procedure ImageResize(Sender: TObject);
  88. procedure ActionFileExitExecute(Sender: TObject);
  89. procedure ActionOptionShapeExecute(Sender: TObject);
  90. procedure ActionOptionJoinStyleExecute(Sender: TObject);
  91. procedure ActionOptionEndStyleExecute(Sender: TObject);
  92. procedure ActionDummyExecute(Sender: TObject);
  93. procedure ActionOptionEndStylesUpdate(Sender: TObject);
  94. procedure ActionOptionJoinStyleUpdate(Sender: TObject);
  95. procedure ActionOptionEndStyleUpdate(Sender: TObject);
  96. procedure ActionRefreshExecute(Sender: TObject);
  97. procedure ActionRedrawExecute(Sender: TObject);
  98. private
  99. FJoinStyle: TJoinStyle;
  100. FEndStyle: TEndStyle;
  101. FPolyPoints: TArrayOfArrayOfFloatPoint;
  102. function GeneratePolygon(MaxWidth, MaxHeight, EdgeCount: integer): TArrayOfFloatPoint;
  103. procedure ApplyOptionsAndRedraw;
  104. procedure CreateNewPolygonAndApplyOptions;
  105. function PolyLineBuilderClass: TPolyLineBuilderClass;
  106. public
  107. end;
  108. var
  109. FormGrow: TFormGrow;
  110. implementation
  111. {$IFDEF FPC}
  112. {$R *.lfm}
  113. {$ELSE}
  114. {$R *.dfm}
  115. {$ENDIF}
  116. uses
  117. GR32_Clipper,
  118. GR32_Paths,
  119. GR32_VectorUtils.Reference,
  120. GR32_VectorUtils.Angus,
  121. GR32_VectorUtils.Clipper2;
  122. const
  123. MARGIN = 40;
  124. //------------------------------------------------------------------------------
  125. function Area(const Path: TArrayOfFloatPoint): Single;
  126. var
  127. i, j, HighI: Integer;
  128. d: Single;
  129. begin
  130. Result := 0.0;
  131. HighI := High(Path);
  132. if (HighI < 2) then Exit;
  133. j := HighI;
  134. for i := 0 to HighI do
  135. begin
  136. d := (Path[j].X + Path[i].X);
  137. Result := Result + d * (Path[j].Y - Path[i].Y);
  138. j := i;
  139. end;
  140. Result := -Result * 0.5;
  141. end;
  142. //------------------------------------------------------------------------------
  143. function MakeRandomPath(MaxWidth, MaxHeight, Count: Integer): TArrayOfFloatPoint;
  144. var
  145. i: Integer;
  146. begin
  147. Setlength(Result, Count);
  148. for i := 0 to Count -1 do
  149. begin
  150. Result[i].X := MARGIN + Random(MaxWidth - MARGIN * 2);
  151. Result[i].Y := MARGIN + Random(MaxHeight - MARGIN * 2);
  152. end;
  153. end;
  154. //------------------------------------------------------------------------------
  155. function TFormGrow.GeneratePolygon(MaxWidth, MaxHeight, EdgeCount: integer): TArrayOfFloatPoint;
  156. function Union(const Paths: TArrayOfArrayOfFloatPoint; FillRule: TFillRule = frEvenOdd): TArrayOfArrayOfFloatPoint;
  157. var
  158. Clipper: TClipper;
  159. begin
  160. Clipper := TClipper.Create;
  161. try
  162. Clipper.AddPaths(Paths, ptSubject, False);
  163. Clipper.Execute(ctUnion, FillRule, Result);
  164. finally
  165. Clipper.Free;
  166. end;
  167. end;
  168. var
  169. PolyPts: TArrayOfArrayOfFloatPoint;
  170. i,j: integer;
  171. Area, a: Single;
  172. begin
  173. Setlength(PolyPts, 1);
  174. PolyPts[0] := MakeRandomPath(MaxWidth, MaxHeight, EdgeCount);
  175. // NOTE: INFLATEPATHS WILL BEHAVE IN AN UNDETERMINED FASHION
  176. // WHENEVER SELF-INTERSECTING POLYGONS ARE ENCOUNTERED.
  177. // so, remove self-intersections
  178. PolyPts := Union(PolyPts);
  179. if (Length(PolyPts) = 0) then
  180. // Most likely user has resized window to zero size
  181. Abort;
  182. // and find the largest polygon ...
  183. j := 0;
  184. Area := Abs(MainUnit.Area(PolyPts[0]));
  185. for i := 1 to high(PolyPts) do
  186. begin
  187. a := Abs(MainUnit.Area(PolyPts[i]));
  188. if a <= Area then
  189. Continue;
  190. j := i;
  191. Area := a;
  192. end;
  193. Result := PolyPts[j];
  194. end;
  195. //------------------------------------------------------------------------------
  196. function TFormGrow.PolyLineBuilderClass: TPolyLineBuilderClass;
  197. begin
  198. if (ActionOptionGrowClipper.Checked) then
  199. Result := PolyLineBuilderClipper
  200. else
  201. if (ActionOptionGrowAngus.Checked) then
  202. Result := PolyLineBuilderAngus
  203. else
  204. Result := PolyLineBuilderReference;
  205. end;
  206. //------------------------------------------------------------------------------
  207. procedure TFormGrow.ActionOptionEndStylesUpdate(Sender: TObject);
  208. begin
  209. TAction(Sender).Enabled := not ActionOptionShapePolygon.Checked;
  210. end;
  211. procedure TFormGrow.ActionDummyExecute(Sender: TObject);
  212. begin
  213. //
  214. end;
  215. procedure TFormGrow.ActionFileExitExecute(Sender: TObject);
  216. begin
  217. Close;
  218. end;
  219. procedure TFormGrow.ActionOptionEndStyleUpdate(Sender: TObject);
  220. begin
  221. TAction(Sender).Enabled := (TEndStyle(TAction(Sender).Tag) in PolyLineBuilderClass.SupportedEndStyles);
  222. TAction(Sender).Checked := (FEndStyle = TEndStyle(TAction(Sender).Tag));
  223. end;
  224. procedure TFormGrow.ActionOptionEndStyleExecute(Sender: TObject);
  225. begin
  226. FEndStyle := TEndStyle(TAction(Sender).Tag);
  227. ApplyOptionsAndRedraw;
  228. end;
  229. procedure TFormGrow.ActionOptionShapeExecute(Sender: TObject);
  230. begin
  231. CreateNewPolygonAndApplyOptions;
  232. end;
  233. procedure TFormGrow.ActionOptionJoinStyleUpdate(Sender: TObject);
  234. begin
  235. TAction(Sender).Enabled := (TJoinStyle(TAction(Sender).Tag) in PolyLineBuilderClass.SupportedJoinStyles);
  236. TAction(Sender).Checked := (FJoinStyle = TJoinStyle(TAction(Sender).Tag));
  237. end;
  238. procedure TFormGrow.ActionRedrawExecute(Sender: TObject);
  239. begin
  240. ApplyOptionsAndRedraw;
  241. end;
  242. procedure TFormGrow.ActionRefreshExecute(Sender: TObject);
  243. begin
  244. CreateNewPolygonAndApplyOptions;
  245. end;
  246. procedure TFormGrow.ActionOptionJoinStyleExecute(Sender: TObject);
  247. begin
  248. FJoinStyle := TJoinStyle(TAction(Sender).Tag);
  249. ApplyOptionsAndRedraw;
  250. end;
  251. procedure TFormGrow.ApplyOptionsAndRedraw;
  252. var
  253. PolyPts: TArrayOfArrayOfFloatPoint;
  254. Closed: boolean;
  255. Builder: TPolyLineBuilderClass;
  256. begin
  257. // Apply options to existing polyline/polygon and repaint
  258. Closed := not ActionOptionShapePolyLine.Checked;
  259. Image.Bitmap.Clear(clWhite32);
  260. if (Closed) then
  261. PolyPolygonFS(image.Bitmap, FPolyPoints, $100000FF, pfNonZero);
  262. PolyPolylineFS(image.Bitmap, FPolyPoints, clBlack32, Closed, 1);
  263. Builder := PolyLineBuilderClass;
  264. PolyPts := Builder.BuildPolyPolyLine(FPolyPoints, Closed, 20, FJoinStyle, FEndStyle);
  265. PolyPolylineFS(image.Bitmap, PolyPts, clRed32, True, 1);
  266. PolyPolygonFS(image.Bitmap, PolyPts, $10FF0000, pfNonZero);
  267. end;
  268. procedure TFormGrow.ImageResize(Sender: TObject);
  269. begin
  270. Image.Bitmap.SetSize(Image.ClientWidth, Image.ClientHeight);
  271. CreateNewPolygonAndApplyOptions;
  272. end;
  273. procedure TFormGrow.CreateNewPolygonAndApplyOptions;
  274. begin
  275. if (Image.Bitmap.Width < 2*MARGIN) or (Image.Bitmap.Height < 2*MARGIN) then
  276. begin
  277. Image.Bitmap.Clear(clRed32);
  278. exit;
  279. end;
  280. Caption := IntToStr(RandSeed);
  281. Setlength(FPolyPoints, 1);
  282. if ActionOptionShapePolyLine.Checked then
  283. // Generate a polyline
  284. FPolyPoints[0] := MakeRandomPath(Image.Bitmap.Width, Image.Bitmap.Height, 7)
  285. else
  286. // Generate a closed polygon
  287. repeat
  288. FPolyPoints[0] := GeneratePolygon(Image.Bitmap.Width, Image.Bitmap.Height, 5);
  289. until Length(FPolyPoints[0]) > 3;
  290. ApplyOptionsAndRedraw;
  291. end;
  292. procedure TFormGrow.ImageClick(Sender: TObject);
  293. begin
  294. CreateNewPolygonAndApplyOptions;
  295. end;
  296. end.