GR32_VectorUtils.Clipper2.pas 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. unit GR32_VectorUtils.Clipper2;
  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 Polyline builder for Graphics32
  23. *
  24. * The Initial Developer of the Original Code is
  25. * Anders Melander <[email protected]>
  26. *
  27. * Portions created by the Initial Developer are Copyright (C) 2008-2012
  28. * the Initial Developer. All Rights Reserved.
  29. *
  30. * ***** END LICENSE BLOCK ***** *)
  31. interface
  32. {$include GR32.inc}
  33. {$BOOLEVAL OFF}
  34. uses
  35. Math,
  36. Types,
  37. GR32,
  38. GR32_VectorUtils,
  39. GR32_Polygons;
  40. //------------------------------------------------------------------------------
  41. //
  42. // Grow and BuildPoly*line replacements using Clipper2
  43. //
  44. //------------------------------------------------------------------------------
  45. // Note: Clipper miters using square joins instead of bevel joins.
  46. //------------------------------------------------------------------------------
  47. type
  48. PolyLineBuilderClipper = class(TPolyLineBuilder)
  49. protected
  50. // Float
  51. class function Grow(const Points: TArrayOfFloatPoint; const Normals: TArrayOfFloatPoint; const Delta: TFloat; JoinStyle: TJoinStyle = jsMiter; Closed: Boolean = True; MiterLimit: TFloat = DEFAULT_MITER_LIMIT): TArrayOfFloatPoint; overload; override;
  52. // Fixed
  53. class function Grow(const Points: TArrayOfFixedPoint; const Normals: TArrayOfFixedPoint; const Delta: TFixed; JoinStyle: TJoinStyle = jsMiter; Closed: Boolean = True; MiterLimit: TFixed = DEFAULT_MITER_LIMIT_FIXED): TArrayOfFixedPoint; overload; override;
  54. public
  55. class function SupportedJoinStyles: TJoinStyles; override;
  56. class function SupportedEndStyles: TEndStyles; override;
  57. // Float
  58. class function Grow(const Points: TArrayOfFloatPoint; const Delta: TFloat; JoinStyle: TJoinStyle; Closed: Boolean; MiterLimit: TFloat): TArrayOfFloatPoint; overload; override;
  59. // Fixed
  60. class function Grow(const Points: TArrayOfFixedPoint; const Delta: TFixed; JoinStyle: TJoinStyle; Closed: Boolean; MiterLimit: TFixed): TArrayOfFixedPoint; overload; override;
  61. // Float
  62. class function BuildPolyLine(const Points: TArrayOfFloatPoint; StrokeWidth: TFloat; JoinStyle: TJoinStyle = jsMiter; EndStyle: TEndStyle = esButt; MiterLimit: TFloat = DEFAULT_MITER_LIMIT): TArrayOfFloatPoint; overload; override;
  63. class function BuildPolyPolyLine(const Points: TArrayOfArrayOfFloatPoint; Closed: Boolean; StrokeWidth: TFloat; JoinStyle: TJoinStyle = jsMiter; EndStyle: TEndStyle = esButt; MiterLimit: TFloat = DEFAULT_MITER_LIMIT): TArrayOfArrayOfFloatPoint; overload; override;
  64. // Fixed
  65. class function BuildPolyLine(const Points: TArrayOfFixedPoint; StrokeWidth: TFixed; JoinStyle: TJoinStyle; EndStyle: TEndStyle; MiterLimit: TFixed): TArrayOfFixedPoint; overload; override;
  66. class function BuildPolyPolyLine(const Points: TArrayOfArrayOfFixedPoint; Closed: Boolean; StrokeWidth: TFixed; JoinStyle: TJoinStyle; EndStyle: TEndStyle; MiterLimit: TFixed): TArrayOfArrayOfFixedPoint; overload; override;
  67. end;
  68. //------------------------------------------------------------------------------
  69. //------------------------------------------------------------------------------
  70. //------------------------------------------------------------------------------
  71. implementation
  72. uses
  73. Clipper,
  74. Clipper.Core,
  75. Clipper.Offset,
  76. GR32_Clipper2,
  77. GR32_Math,
  78. GR32_Geometry,
  79. GR32_LowLevel;
  80. const
  81. JoinStyleToJoinType: array[TJoinStyle] of TJoinType = (jtMiter, jtBevel, jtRound, jtRound, jtSquare);
  82. EndStyleToEndType: array[TEndStyle] of TEndType = (etButt, etSquare, etRound);
  83. //------------------------------------------------------------------------------
  84. class function PolyLineBuilderClipper.SupportedEndStyles: TEndStyles;
  85. begin
  86. Result := [esButt, esSquare, esRound];
  87. end;
  88. class function PolyLineBuilderClipper.SupportedJoinStyles: TJoinStyles;
  89. begin
  90. Result := [jsMiter, jsBevel, jsRound, jsSquare];
  91. end;
  92. //------------------------------------------------------------------------------
  93. function GrowClipper(const Points: TPaths64; const Delta: TFloat; JoinStyle: TJoinStyle; Closed: Boolean; MiterLimit: TFloat): TPaths64; overload;
  94. var
  95. EndType: TEndType;
  96. begin
  97. if (Closed) then
  98. EndType := etPolygon
  99. else
  100. EndType := etJoined;
  101. Result := Clipper.InflatePaths(Points, Delta, JoinStyleToJoinType[JoinStyle], EndType, MiterLimit);
  102. Result := Clipper.Core.RamerDouglasPeucker(Result, 1);
  103. end;
  104. //------------------------------------------------------------------------------
  105. // Grow
  106. //------------------------------------------------------------------------------
  107. class function PolyLineBuilderClipper.Grow(const Points, Normals: TArrayOfFloatPoint; const Delta: TFloat; JoinStyle: TJoinStyle; Closed: Boolean; MiterLimit: TFloat): TArrayOfFloatPoint;
  108. begin
  109. Result := Grow(Points, Delta, JoinStyle, Closed, MiterLimit);
  110. end;
  111. class function PolyLineBuilderClipper.Grow(const Points: TArrayOfFloatPoint; const Delta: TFloat; JoinStyle: TJoinStyle; Closed: Boolean; MiterLimit: TFloat): TArrayOfFloatPoint;
  112. var
  113. Points64, Result64: TPaths64;
  114. Res: TArrayOfArrayOfFloatPoint;
  115. begin
  116. Points64 := [GR32_Clipper2.FloatPointsToPath64(Points)];
  117. Result64 := GrowClipper(Points64, Delta * GR32_Clipper2.ClipperFloat.GrowScale, JoinStyle, Closed, MiterLimit);
  118. Res := GR32_Clipper2.Paths64ToFloatPoints(Result64);
  119. if (Length(Res) > 0) then
  120. Result := Res[0]
  121. else
  122. SetLength(Result, 0);
  123. end;
  124. class function PolyLineBuilderClipper.Grow(const Points, Normals: TArrayOfFixedPoint; const Delta: TFixed; JoinStyle: TJoinStyle; Closed: Boolean; MiterLimit: TFixed): TArrayOfFixedPoint;
  125. begin
  126. Result := Grow(Points, Delta, JoinStyle, Closed, MiterLimit);
  127. end;
  128. class function PolyLineBuilderClipper.Grow(const Points: TArrayOfFixedPoint; const Delta: TFixed; JoinStyle: TJoinStyle; Closed: Boolean; MiterLimit: TFixed): TArrayOfFixedPoint;
  129. var
  130. Points64, Result64: TPaths64;
  131. Res: TArrayOfArrayOfFixedPoint;
  132. begin
  133. Points64 := [GR32_Clipper2.FixedPointsToPath64(Points)];
  134. Result64 := GrowClipper(Points64, Delta * FixedToFloat, JoinStyle, Closed, MiterLimit);
  135. Res := GR32_Clipper2.Paths64ToFixedPoints(Result64);
  136. if (Length(Res) > 0) then
  137. Result := Res[0]
  138. else
  139. SetLength(Result, 0);
  140. end;
  141. //------------------------------------------------------------------------------
  142. // BuildPoly*line
  143. //------------------------------------------------------------------------------
  144. class function PolyLineBuilderClipper.BuildPolyline(const Points: TArrayOfFloatPoint; StrokeWidth: TFloat; JoinStyle: TJoinStyle; EndStyle: TEndStyle; MiterLimit: TFloat): TArrayOfFloatPoint;
  145. var
  146. Paths64: TPaths64;
  147. EndType: TEndType;
  148. Result64: TPaths64;
  149. Res: TArrayOfArrayOfFloatPoint;
  150. begin
  151. Paths64 := [GR32_Clipper2.FloatPointsToPath64(Points)];
  152. EndType := EndStyleToEndType[EndStyle];
  153. Result64 := Clipper.InflatePaths(Paths64, StrokeWidth * GR32_Clipper2.ClipperFloat.GrowScale, JoinStyleToJoinType[JoinStyle], EndType, MiterLimit);
  154. Result64 := Clipper.Core.RamerDouglasPeucker(Result64, 1);
  155. Res := GR32_Clipper2.Paths64ToFloatPoints(Result64);
  156. if (Length(Res) > 0) then
  157. Result := Res[0]
  158. else
  159. SetLength(Result, 0);
  160. end;
  161. class function PolyLineBuilderClipper.BuildPolyPolyLine(const Points: TArrayOfArrayOfFloatPoint; Closed: Boolean; StrokeWidth: TFloat; JoinStyle: TJoinStyle; EndStyle: TEndStyle; MiterLimit: TFloat): TArrayOfArrayOfFloatPoint;
  162. var
  163. Paths64: TPaths64;
  164. EndType: TEndType;
  165. Result64: TPaths64;
  166. begin
  167. Paths64 := GR32_Clipper2.FloatPointsToPaths64(Points);
  168. if (Closed) then
  169. EndType := etJoined
  170. else
  171. EndType := EndStyleToEndType[EndStyle];
  172. Result64 := Clipper.InflatePaths(Paths64, StrokeWidth * GR32_Clipper2.ClipperFloat.GrowScale, JoinStyleToJoinType[JoinStyle], EndType, MiterLimit);
  173. Result64 := Clipper.Core.RamerDouglasPeucker(Result64, 1);
  174. Result := GR32_Clipper2.Paths64ToFloatPoints(Result64);
  175. end;
  176. class function PolyLineBuilderClipper.BuildPolyline(const Points: TArrayOfFixedPoint; StrokeWidth: TFixed; JoinStyle: TJoinStyle; EndStyle: TEndStyle; MiterLimit: TFixed): TArrayOfFixedPoint;
  177. var
  178. Paths64: TPaths64;
  179. Result64: TPaths64;
  180. Res: TArrayOfArrayOfFixedPoint;
  181. begin
  182. Paths64 := [GR32_Clipper2.FixedPointsToPath64(Points)];
  183. Result64 := Clipper.InflatePaths(Paths64, StrokeWidth * GR32_Clipper2.ClipperFloat.GrowScale, JoinStyleToJoinType[JoinStyle], EndStyleToEndType[EndStyle], MiterLimit);
  184. Result64 := Clipper.Core.RamerDouglasPeucker(Result64, 1);
  185. Res := GR32_Clipper2.Paths64ToFixedPoints(Result64);
  186. if (Length(Res) > 0) then
  187. Result := Res[0]
  188. else
  189. SetLength(Result, 0);
  190. end;
  191. class function PolyLineBuilderClipper.BuildPolyPolyLine(const Points: TArrayOfArrayOfFixedPoint; Closed: Boolean; StrokeWidth: TFixed; JoinStyle: TJoinStyle; EndStyle: TEndStyle; MiterLimit: TFixed): TArrayOfArrayOfFixedPoint;
  192. var
  193. Paths64: TPaths64;
  194. EndType: TEndType;
  195. Result64: TPaths64;
  196. begin
  197. Paths64 := GR32_Clipper2.FixedPointsToPaths64(Points);
  198. if (Closed) then
  199. EndType := etJoined
  200. else
  201. EndType := EndStyleToEndType[EndStyle];
  202. Result64 := Clipper.InflatePaths(Paths64, StrokeWidth * GR32_Clipper2.ClipperFloat.GrowScale, JoinStyleToJoinType[JoinStyle], EndType, MiterLimit);
  203. Result64 := Clipper.Core.RamerDouglasPeucker(Result64, 1);
  204. Result := GR32_Clipper2.Paths64ToFixedPoints(Result64);
  205. end;
  206. end.