Clipper.Minkowski.pas 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. unit Clipper.Minkowski;
  2. (*******************************************************************************
  3. * Author : Angus Johnson *
  4. * Date : 15 October 2022 *
  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. if IsClosed then
  45. delta := 0 else
  46. delta := 1;
  47. baseLen := Length(Base);
  48. pathLen := Length(Path);
  49. setLength(tmp, pathLen);
  50. for i := 0 to pathLen -1 do
  51. begin
  52. setLength(tmp[i], baseLen);
  53. if IsSum then
  54. for j := 0 to baseLen -1 do
  55. tmp[i][j] := AddPoints(Path[i], Base[j])
  56. else
  57. for j := 0 to baseLen -1 do
  58. tmp[i][j] := SubtractPoints(Path[i], Base[j]);
  59. end;
  60. SetLength(quad, 4);
  61. SetLength(Result, (pathLen - delta) * baseLen);
  62. if IsClosed then
  63. g := pathLen - 1 else
  64. g := 0;
  65. for i := delta to pathLen - 1 do
  66. begin
  67. h := baseLen - 1;
  68. k := (i - delta) * baseLen;
  69. for j := 0 to baseLen - 1 do
  70. begin
  71. quad[0] := tmp[g][h];
  72. quad[1] := tmp[i][h];
  73. quad[2] := tmp[i][(j)];
  74. quad[3] := tmp[g][(j)];
  75. if not IsPositive(quad) then
  76. Result[k + j] := ReversePath(quad) else
  77. Result[k + j] := copy(quad, 0, 4);
  78. h := j;
  79. end;
  80. g := i;
  81. end;
  82. end;
  83. //------------------------------------------------------------------------------
  84. function MinkowskiSum(const Pattern, Path: TPath64; PathIsClosed: Boolean): TPaths64;
  85. begin
  86. Result := Union( Minkowski(Pattern, Path, true, PathIsClosed), frNonZero);
  87. end;
  88. //------------------------------------------------------------------------------
  89. function MinkowskiSum(const Pattern, Path: TPathD;
  90. PathIsClosed: Boolean; decimalPlaces: integer): TPathsD;
  91. var
  92. tmp: TPaths64;
  93. scale: double;
  94. begin
  95. scale := Power(10, decimalPlaces);
  96. tmp := Union( Minkowski(ScalePath(Pattern, scale),
  97. ScalePath(Path, scale), true, PathIsClosed), frNonZero);
  98. Result := ScalePathsD(tmp, 1/scale);
  99. end;
  100. //------------------------------------------------------------------------------
  101. function MinkowskiDiff(const path1, path2: TPath64): TPaths64;
  102. begin
  103. Result := Union( Minkowski(path1, path2, false, true), frNonZero);
  104. end;
  105. //------------------------------------------------------------------------------
  106. function MinkowskiDiff(const Pattern, Path: TPathD;
  107. PathIsClosed: Boolean; decimalPlaces: integer): TPathsD;
  108. var
  109. tmp: TPaths64;
  110. scale: double;
  111. begin
  112. scale := Power(10, decimalPlaces);
  113. tmp := Union( Minkowski(ScalePath(Pattern, scale),
  114. ScalePath(Path, scale), false, PathIsClosed), frNonZero);
  115. Result := ScalePathsD(tmp, 1/scale);
  116. end;
  117. //------------------------------------------------------------------------------
  118. end.