Clipper.Minkowski.pas 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. unit Clipper.Minkowski;
  2. (*******************************************************************************
  3. * Author : Angus Johnson *
  4. * Date : 21 December 2023 *
  5. * Copyright : Angus Johnson 2010-2022 *
  6. * Purpose : Minkowski Addition and Difference *
  7. * License : http://www.boost.org/LICENSE_1_0.txt *
  8. *******************************************************************************)
  9. {$I Clipper.inc}
  10. interface
  11. uses
  12. Classes, Math, Clipper.Core;
  13. function MinkowskiSum(const Pattern, Path: TPath64;
  14. PathIsClosed: Boolean): TPaths64; overload;
  15. function MinkowskiSum(const Pattern, Path: TPathD;
  16. PathIsClosed: Boolean; decimalPlaces: integer = 2): TPathsD; overload;
  17. function MinkowskiDiff(const path1, path2: TPath64): TPaths64; overload;
  18. function MinkowskiDiff(const Pattern, Path: TPathD;
  19. PathIsClosed: Boolean; decimalPlaces: integer): TPathsD; overload;
  20. implementation
  21. uses
  22. Clipper;
  23. function AddPoints(val1, val2: TPoint64): TPoint64;
  24. {$IFDEF INLINING} inline; {$ENDIF}
  25. begin
  26. Result.X := val1.X + val2.X;
  27. Result.Y := val1.Y + val2.Y;
  28. end;
  29. //------------------------------------------------------------------------------
  30. function SubtractPoints(val1, val2: TPoint64): TPoint64;
  31. {$IFDEF INLINING} inline; {$ENDIF}
  32. begin
  33. Result.X := val1.X - val2.X;
  34. Result.Y := val1.Y - val2.Y;
  35. end;
  36. //------------------------------------------------------------------------------
  37. function Minkowski(const Base, Path: TPath64;
  38. IsSum: Boolean; IsClosed: Boolean): TPaths64;
  39. var
  40. i,j,k,g,h, delta, baseLen, pathLen: integer;
  41. tmp: TPaths64;
  42. quad: TPath64;
  43. begin
  44. delta := Iif(IsClosed, 0 , 1);
  45. baseLen := Length(Base);
  46. pathLen := Length(Path);
  47. setLength(tmp, pathLen);
  48. for i := 0 to pathLen -1 do
  49. begin
  50. setLength(tmp[i], baseLen);
  51. if IsSum then
  52. for j := 0 to baseLen -1 do
  53. tmp[i][j] := AddPoints(Path[i], Base[j])
  54. else
  55. for j := 0 to baseLen -1 do
  56. tmp[i][j] := SubtractPoints(Path[i], Base[j]);
  57. end;
  58. SetLength(quad, 4);
  59. SetLength(Result, (pathLen - delta) * baseLen);
  60. g := Iif(IsClosed, pathLen - 1, 0);
  61. for i := delta to pathLen - 1 do
  62. begin
  63. h := baseLen - 1;
  64. k := (i - delta) * baseLen;
  65. for j := 0 to baseLen - 1 do
  66. begin
  67. quad[0] := tmp[g][h];
  68. quad[1] := tmp[i][h];
  69. quad[2] := tmp[i][(j)];
  70. quad[3] := tmp[g][(j)];
  71. if not IsPositive(quad) then
  72. Result[k + j] := ReversePath(quad) else
  73. Result[k + j] := copy(quad, 0, 4);
  74. h := j;
  75. end;
  76. g := i;
  77. end;
  78. end;
  79. //------------------------------------------------------------------------------
  80. function MinkowskiSum(const Pattern, Path: TPath64; PathIsClosed: Boolean): TPaths64;
  81. begin
  82. Result := Union( Minkowski(Pattern, Path, true, PathIsClosed), frNonZero);
  83. end;
  84. //------------------------------------------------------------------------------
  85. function MinkowskiSum(const Pattern, Path: TPathD;
  86. PathIsClosed: Boolean; decimalPlaces: integer): TPathsD;
  87. var
  88. tmp: TPaths64;
  89. scale: double;
  90. begin
  91. scale := Power(10, decimalPlaces);
  92. tmp := Union( Minkowski(ScalePath(Pattern, scale),
  93. ScalePath(Path, scale), true, PathIsClosed), frNonZero);
  94. Result := ScalePathsD(tmp, 1/scale);
  95. end;
  96. //------------------------------------------------------------------------------
  97. function MinkowskiDiff(const path1, path2: TPath64): TPaths64;
  98. begin
  99. Result := Union( Minkowski(path1, path2, false, true), frNonZero);
  100. end;
  101. //------------------------------------------------------------------------------
  102. function MinkowskiDiff(const Pattern, Path: TPathD;
  103. PathIsClosed: Boolean; decimalPlaces: integer): TPathsD;
  104. var
  105. tmp: TPaths64;
  106. scale: double;
  107. begin
  108. scale := Power(10, decimalPlaces);
  109. tmp := Union( Minkowski(ScalePath(Pattern, scale),
  110. ScalePath(Path, scale), false, PathIsClosed), frNonZero);
  111. Result := ScalePathsD(tmp, 1/scale);
  112. end;
  113. //------------------------------------------------------------------------------
  114. end.