Clipper.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. unit Clipper;
  2. (*******************************************************************************
  3. * Author : Angus Johnson *
  4. * Date : 2 November 2022 *
  5. * Website : http://www.angusj.com *
  6. * Copyright : Angus Johnson 2010-2022 *
  7. * Purpose : This module provides a simple interface to the Clipper Library *
  8. * License : http://www.boost.org/LICENSE_1_0.txt *
  9. *******************************************************************************)
  10. interface
  11. {$I Clipper.inc}
  12. uses
  13. Math, SysUtils,
  14. Clipper.Core, Clipper.Engine, Clipper.Offset, Clipper.RectClip;
  15. // Redeclare here a number of structures defined in
  16. // other units so those units won't need to be declared
  17. // just to use the following functions.
  18. type
  19. TClipper = Clipper.Engine.TClipper64;
  20. TClipper64 = Clipper.Engine.TClipper64;
  21. TPoint64 = Clipper.Core.TPoint64;
  22. TRect64 = Clipper.Core.TRect64;
  23. TPath64 = Clipper.Core.TPath64;
  24. TPaths64 = Clipper.Core.TPaths64;
  25. TPointD = Clipper.Core.TPointD;
  26. TRectD = Clipper.Core.TRectD;
  27. TPathD = Clipper.Core.TPathD;
  28. TPathsD = Clipper.Core.TPathsD;
  29. TFillRule = Clipper.Core.TFillRule;
  30. TPolyTree64 = Clipper.Engine.TPolyTree64;
  31. TPolyTreeD = Clipper.Engine.TPolyTreeD;
  32. TJoinType = Clipper.Offset.TJoinType;
  33. TEndType = Clipper.Offset.TEndType;
  34. const
  35. frEvenOdd = Clipper.Core.frEvenOdd;
  36. frNonZero = Clipper.Core.frNonZero;
  37. frPositive = Clipper.Core.frPositive;
  38. frNegative = Clipper.Core.frNegative;
  39. jtSquare = Clipper.Offset.jtSquare;
  40. jtRound = Clipper.Offset.jtRound;
  41. jtMiter = Clipper.Offset.jtMiter;
  42. etPolygon = Clipper.Offset.etPolygon;
  43. etJoined = Clipper.Offset.etJoined;
  44. etButt = Clipper.Offset.etButt;
  45. etSquare = Clipper.Offset.etSquare;
  46. etRound = Clipper.Offset.etRound;
  47. ctNone = Clipper.Core.ctNone;
  48. ctIntersection = Clipper.Core.ctIntersection;
  49. ctUnion = Clipper.Core.ctUnion;
  50. ctDifference = Clipper.Core.ctDifference;
  51. ctXor = Clipper.Core.ctXor;
  52. function BooleanOp(clipType: TClipType;
  53. const subjects, clips: TPaths64; fillRule: TFillRule): TPaths64; overload;
  54. function BooleanOp(clipType: TClipType; const subjects, clips:
  55. TPathsD; fillRule: TFillRule; decimalPrec: integer = 2): TPathsD; overload;
  56. procedure BooleanOp(clipType: TClipType; const subjects, clips: TPaths64;
  57. fillRule: TFillRule; polytree: TPolyTree64); overload;
  58. function Intersect(const subjects, clips: TPaths64;
  59. fillRule: TFillRule): TPaths64; overload;
  60. function Union(const subjects, clips: TPaths64;
  61. fillRule: TFillRule): TPaths64; overload;
  62. function Union(const subjects: TPaths64;
  63. fillRule: TFillRule): TPaths64; overload;
  64. function Difference(const subjects, clips: TPaths64;
  65. fillRule: TFillRule): TPaths64; overload;
  66. function XOR_(const subjects, clips: TPaths64;
  67. fillRule: TFillRule): TPaths64; overload;
  68. function Intersect(const subjects, clips: TPathsD;
  69. fillRule: TFillRule; decimalPrec: integer = 2): TPathsD; overload;
  70. function Union(const subjects: TPathsD;
  71. fillRule: TFillRule; decimalPrec: integer = 2): TPathsD; overload;
  72. function Union(const subjects, clips: TPathsD;
  73. fillRule: TFillRule; decimalPrec: integer = 2): TPathsD; overload;
  74. function Difference(const subjects, clips: TPathsD;
  75. fillRule: TFillRule; decimalPrec: integer = 2): TPathsD; overload;
  76. function XOR_(const subjects, clips: TPathsD;
  77. fillRule: TFillRule; decimalPrec: integer = 2): TPathsD; overload;
  78. function InflatePaths(const paths: TPaths64; delta: Double;
  79. jt: TJoinType = jtRound; et: TEndType = etPolygon;
  80. MiterLimit: double = 2.0): TPaths64; overload;
  81. function InflatePaths(const paths: TPathsD; delta: Double;
  82. jt: TJoinType = jtRound; et: TEndType = etPolygon;
  83. miterLimit: double = 2.0; precision: integer = 2): TPathsD; overload;
  84. function RectClip(const rect: TRect64; const path: TPath64): TPath64; overload;
  85. function RectClip(const rect: TRect64; const paths: TPaths64): TPaths64; overload;
  86. function RectClip(const rect: TRectD; const path: TPathD;
  87. precision: integer = 2): TPathD; overload;
  88. function RectClip(const rect: TRectD; const paths: TPathsD;
  89. precision: integer = 2): TPathsD; overload;
  90. function RectClipLines(const rect: TRect64; const path: TPath64): TPaths64; overload;
  91. function RectClipLines(const rect: TRect64; const paths: TPaths64): TPaths64; overload;
  92. function RectClipLines(const rect: TRectD; const path: TPathD;
  93. precision: integer): TPathsD; overload;
  94. function RectClipLines(const rect: TRectD; const paths: TPathsD;
  95. precision: integer = 2): TPathsD; overload;
  96. function TranslatePath(const path: TPath64; dx, dy: Int64): TPath64; overload;
  97. function TranslatePath(const path: TPathD; dx, dy: double): TPathD; overload;
  98. function TranslatePaths(const paths: TPaths64; dx, dy: Int64): TPaths64; overload;
  99. function TranslatePaths(const paths: TPathsD; dx, dy: double): TPathsD; overload;
  100. function MinkowskiSum(const pattern, path: TPath64;
  101. pathIsClosed: Boolean): TPaths64;
  102. function PolyTreeToPaths64(PolyTree: TPolyTree64): TPaths64;
  103. function PolyTreeToPathsD(PolyTree: TPolyTreeD): TPathsD;
  104. function MakePath(const ints: TArrayOfInteger): TPath64; overload;
  105. function MakePath(const dbls: TArrayOfDouble): TPathD; overload;
  106. function TrimCollinear(const p: TPath64;
  107. isOpenPath: Boolean = false): TPath64; overload;
  108. function TrimCollinear(const path: TPathD;
  109. precision: integer; isOpenPath: Boolean = false): TPathD; overload;
  110. function PointInPolygon(const pt: TPoint64;
  111. const polygon: TPath64): TPointInPolygonResult;
  112. implementation
  113. uses
  114. Clipper.Minkowski;
  115. //------------------------------------------------------------------------------
  116. //------------------------------------------------------------------------------
  117. function MakePath(const ints: TArrayOfInteger): TPath64;
  118. var
  119. i, len: integer;
  120. begin
  121. len := length(ints) div 2;
  122. SetLength(Result, len);
  123. for i := 0 to len -1 do
  124. begin
  125. Result[i].X := ints[i*2];
  126. Result[i].Y := ints[i*2 +1];
  127. end;
  128. end;
  129. //------------------------------------------------------------------------------
  130. function MakePath(const dbls: TArrayOfDouble): TPathD; overload;
  131. var
  132. i, len: integer;
  133. begin
  134. len := length(dbls) div 2;
  135. SetLength(Result, len);
  136. for i := 0 to len -1 do
  137. begin
  138. Result[i].X := dbls[i*2];
  139. Result[i].Y := dbls[i*2 +1];
  140. end;
  141. end;
  142. //------------------------------------------------------------------------------
  143. procedure AddPolyNodeToPaths(Poly: TPolyPath64; var Paths: TPaths64);
  144. var
  145. i: Integer;
  146. begin
  147. if (Length(Poly.Polygon) > 0) then
  148. begin
  149. i := Length(Paths);
  150. SetLength(Paths, i +1);
  151. Paths[i] := Poly.Polygon;
  152. end;
  153. for i := 0 to Poly.Count - 1 do
  154. AddPolyNodeToPaths(Poly[i], Paths);
  155. end;
  156. //------------------------------------------------------------------------------
  157. function PolyTreeToPaths64(PolyTree: TPolyTree64): TPaths64;
  158. begin
  159. Result := nil;
  160. AddPolyNodeToPaths(PolyTree, Result);
  161. end;
  162. //------------------------------------------------------------------------------
  163. procedure AddPolyNodeToPathsD(Poly: TPolyPathD; var Paths: TPathsD);
  164. var
  165. i: Integer;
  166. begin
  167. if (Length(Poly.Polygon) > 0) then
  168. begin
  169. i := Length(Paths);
  170. SetLength(Paths, i +1);
  171. Paths[i] := Poly.Polygon;
  172. end;
  173. for i := 0 to Poly.Count - 1 do
  174. AddPolyNodeToPathsD(Poly[i], Paths);
  175. end;
  176. //------------------------------------------------------------------------------
  177. function PolyTreeToPathsD(PolyTree: TPolyTreeD): TPathsD;
  178. begin
  179. Result := nil;
  180. AddPolyNodeToPathsD(PolyTree, Result);
  181. end;
  182. //------------------------------------------------------------------------------
  183. //------------------------------------------------------------------------------
  184. function BooleanOp(clipType: TClipType;
  185. const subjects, clips: TPaths64; fillRule: TFillRule): TPaths64;
  186. begin
  187. with TClipper64.Create do
  188. try
  189. AddSubject(subjects);
  190. AddClip(clips);
  191. Execute(clipType, fillRule, Result);
  192. finally
  193. Free;
  194. end;
  195. end;
  196. //------------------------------------------------------------------------------
  197. function BooleanOp(clipType: TClipType; const subjects, clips: TPathsD;
  198. fillRule: TFillRule; decimalPrec: integer = 2): TPathsD;
  199. begin
  200. with TClipperD.Create(decimalPrec) do
  201. try
  202. AddSubject(subjects);
  203. AddClip(clips);
  204. Execute(clipType, fillRule, Result);
  205. finally
  206. Free;
  207. end;
  208. end;
  209. //------------------------------------------------------------------------------
  210. procedure BooleanOp(clipType: TClipType; const subjects, clips: TPaths64;
  211. fillRule: TFillRule; polytree: TPolyTree64);
  212. var
  213. dummy: TPaths64;
  214. begin
  215. with TClipper64.Create do
  216. try
  217. AddSubject(subjects);
  218. AddClip(clips);
  219. Execute(clipType, fillRule, polytree, dummy);
  220. finally
  221. Free;
  222. end;
  223. end;
  224. //------------------------------------------------------------------------------
  225. function Intersect(const subjects, clips: TPaths64; fillRule: TFillRule): TPaths64;
  226. begin
  227. Result := BooleanOp(ctIntersection, subjects, clips, fillRule);
  228. end;
  229. //------------------------------------------------------------------------------
  230. function Union(const subjects, clips: TPaths64; fillRule: TFillRule): TPaths64;
  231. begin
  232. Result := BooleanOp(ctUnion, subjects, clips, fillRule);
  233. end;
  234. //------------------------------------------------------------------------------
  235. function Union(const subjects: TPaths64; fillRule: TFillRule): TPaths64;
  236. begin
  237. Result := BooleanOp(ctUnion, subjects, nil, fillRule);
  238. end;
  239. //------------------------------------------------------------------------------
  240. function Difference(const subjects, clips: TPaths64; fillRule: TFillRule): TPaths64;
  241. begin
  242. Result := BooleanOp(ctDifference, subjects, clips, fillRule);
  243. end;
  244. //------------------------------------------------------------------------------
  245. function XOR_(const subjects, clips: TPaths64; fillRule: TFillRule): TPaths64;
  246. begin
  247. Result := BooleanOp(ctXor, subjects, clips, fillRule);
  248. end;
  249. //------------------------------------------------------------------------------
  250. function Intersect(const subjects, clips: TPathsD;
  251. fillRule: TFillRule; decimalPrec: integer = 2): TPathsD;
  252. begin
  253. Result := BooleanOp(ctIntersection, subjects, clips, fillRule, decimalPrec);
  254. end;
  255. //------------------------------------------------------------------------------
  256. function Union(const subjects, clips: TPathsD;
  257. fillRule: TFillRule; decimalPrec: integer = 2): TPathsD;
  258. begin
  259. Result := BooleanOp(ctUnion, subjects, clips, fillRule, decimalPrec);
  260. end;
  261. //------------------------------------------------------------------------------
  262. function Union(const subjects: TPathsD;
  263. fillRule: TFillRule; decimalPrec: integer = 2): TPathsD;
  264. begin
  265. Result := BooleanOp(ctUnion, subjects, nil, fillRule, decimalPrec);
  266. end;
  267. //------------------------------------------------------------------------------
  268. function Difference(const subjects, clips: TPathsD;
  269. fillRule: TFillRule; decimalPrec: integer = 2): TPathsD;
  270. begin
  271. Result := BooleanOp(ctDifference, subjects, clips, fillRule, decimalPrec);
  272. end;
  273. //------------------------------------------------------------------------------
  274. function XOR_(const subjects, clips: TPathsD;
  275. fillRule: TFillRule; decimalPrec: integer = 2): TPathsD;
  276. begin
  277. Result := BooleanOp(ctXor, subjects, clips, fillRule, decimalPrec);
  278. end;
  279. //------------------------------------------------------------------------------
  280. //------------------------------------------------------------------------------
  281. function InflatePaths(const paths: TPaths64; delta: Double;
  282. jt: TJoinType; et: TEndType; MiterLimit: double): TPaths64;
  283. var
  284. co: TClipperOffset;
  285. begin
  286. co := TClipperOffset.Create(MiterLimit);
  287. try
  288. co.MergeGroups := true;
  289. co.AddPaths(paths, jt, et);
  290. Result := co.Execute(delta);
  291. finally
  292. co.free;
  293. end;
  294. end;
  295. //------------------------------------------------------------------------------
  296. function InflatePaths(const paths: TPathsD; delta: Double;
  297. jt: TJoinType; et: TEndType; miterLimit: double;
  298. precision: integer): TPathsD;
  299. var
  300. pp: TPaths64;
  301. scale, invScale: double;
  302. begin
  303. CheckPrecisionRange(precision);
  304. scale := Power(10, precision);
  305. invScale := 1/scale;
  306. pp := ScalePaths(paths, scale, scale);
  307. with TClipperOffset.Create(miterLimit) do
  308. try
  309. AddPaths(pp, jt, et);
  310. pp := Execute(delta * scale);
  311. finally
  312. free;
  313. end;
  314. Result := ScalePathsD(pp, invScale, invScale);
  315. end;
  316. //------------------------------------------------------------------------------
  317. function RectClip(const rect: TRect64; const path: TPath64): TPath64;
  318. begin
  319. Result := nil;
  320. if rect.IsEmpty or (Length(path) = 0) or
  321. not rect.Intersects(GetBounds(path)) then Exit;
  322. with TRectClip.Create(rect) do
  323. try
  324. Result := Execute(path);
  325. finally
  326. Free;
  327. end;
  328. end;
  329. //------------------------------------------------------------------------------
  330. function RectClip(const rect: TRect64; const paths: TPaths64): TPaths64;
  331. var
  332. i,j, len: integer;
  333. pathRec: TRect64;
  334. begin
  335. Result := nil;
  336. len := Length(paths);
  337. if rect.IsEmpty or (len = 0) then Exit;
  338. SetLength(Result, len);
  339. j := 0;
  340. with TRectClip.Create(rect) do
  341. try
  342. for i := 0 to len -1 do
  343. begin
  344. pathRec := GetBounds(paths[i]);
  345. if not rect.Intersects(pathRec) then
  346. Continue
  347. else if rect.Contains(pathRec) then
  348. Result[j] := Copy(paths[i], 0, MaxInt)
  349. else
  350. begin
  351. Result[j] := Execute(paths[i]);
  352. if Result[j] = nil then Continue;
  353. end;
  354. inc(j);
  355. end;
  356. finally
  357. Free;
  358. end;
  359. SetLength(Result, j);
  360. end;
  361. //------------------------------------------------------------------------------
  362. function RectClip(const rect: TRectD; const path: TPathD;
  363. precision: integer): TPathD;
  364. var
  365. scale: double;
  366. tmpPath: TPath64;
  367. rec: TRect64;
  368. begin
  369. Result := nil;
  370. if not rect.Intersects(GetBounds(path)) then Exit;
  371. CheckPrecisionRange(precision);
  372. scale := Math.Power(10, precision);
  373. rec := Rect64(ScaleRect(rect, scale));
  374. tmpPath := ScalePath(path, scale);
  375. tmpPath := RectClip(rec, tmpPath);
  376. Result := ScalePathD(tmpPath, 1/scale);
  377. end;
  378. //------------------------------------------------------------------------------
  379. function RectClip(const rect: TRectD;
  380. const paths: TPathsD; precision: integer): TPathsD;
  381. var
  382. i,j, len: integer;
  383. scale: double;
  384. tmpPath: TPath64;
  385. rec: TRect64;
  386. pathRec: TRectD;
  387. begin
  388. CheckPrecisionRange(precision);
  389. scale := Math.Power(10, precision);
  390. rec := Rect64(ScaleRect(rect, scale));
  391. j := 0;
  392. len := Length(paths);
  393. SetLength(Result, len);
  394. with TRectClip.Create(rec) do
  395. try
  396. for i := 0 to len -1 do
  397. begin
  398. pathRec := GetBounds(paths[i]);
  399. if not rect.Intersects(pathRec) then
  400. Continue
  401. else if rect.Contains(pathRec) then
  402. Result[j] := Copy(paths[i], 0, MaxInt)
  403. else
  404. begin
  405. tmpPath := ScalePath(paths[i], scale);
  406. tmpPath := Execute(tmpPath);
  407. if tmpPath = nil then Continue;
  408. Result[j] := ScalePathD(tmpPath, 1/scale);
  409. end;
  410. inc(j);
  411. end;
  412. finally
  413. Free;
  414. end;
  415. SetLength(Result, j);
  416. end;
  417. //------------------------------------------------------------------------------
  418. function RectClipLines(const rect: TRect64; const path: TPath64): TPaths64; overload;
  419. begin
  420. Result := nil;
  421. if rect.IsEmpty or (Length(path) = 0) or
  422. not rect.Intersects(GetBounds(path)) then Exit;
  423. with TRectClipLines.Create(rect) do
  424. try
  425. Result := Execute(path);
  426. finally
  427. Free;
  428. end;
  429. end;
  430. //------------------------------------------------------------------------------
  431. function RectClipLines(const rect: TRect64; const paths: TPaths64): TPaths64; overload;
  432. var
  433. i,len: integer;
  434. pathRec: TRect64;
  435. tmp: TPaths64;
  436. begin
  437. Result := nil;
  438. len := Length(paths);
  439. if rect.IsEmpty or (len = 0) then Exit;
  440. SetLength(Result, len);
  441. with TRectClipLines.Create(rect) do
  442. try
  443. for i := 0 to len -1 do
  444. begin
  445. pathRec := GetBounds(paths[i]);
  446. if not rect.Intersects(pathRec) then
  447. Continue
  448. else if rect.Contains(pathRec) then
  449. AppendPath(Result, paths[i])
  450. else
  451. begin
  452. tmp := Execute(paths[i]);
  453. AppendPaths(Result, tmp);
  454. end;
  455. end;
  456. finally
  457. Free;
  458. end;
  459. end;
  460. //------------------------------------------------------------------------------
  461. function RectClipLines(const rect: TRectD; const path: TPathD;
  462. precision: integer): TPathsD;
  463. var
  464. scale: double;
  465. tmpPath: TPath64;
  466. tmpPaths: TPaths64;
  467. rec: TRect64;
  468. begin
  469. Result := nil;
  470. if not rect.Intersects(GetBounds(path)) then Exit;
  471. CheckPrecisionRange(precision);
  472. scale := Math.Power(10, precision);
  473. rec := Rect64(ScaleRect(rect, scale));
  474. tmpPath := ScalePath(path, scale);
  475. tmpPaths := RectClipLines(rec, tmpPath);
  476. Result := ScalePathsD(tmpPaths, 1/scale);
  477. end;
  478. //------------------------------------------------------------------------------
  479. function RectClipLines(const rect: TRectD; const paths: TPathsD;
  480. precision: integer = 2): TPathsD;
  481. var
  482. i: integer;
  483. scale: double;
  484. tmpPath: TPath64;
  485. tmpPaths: TPaths64;
  486. rec: TRect64;
  487. pathRec: TRectD;
  488. begin
  489. Result := nil;
  490. if rect.IsEmpty then Exit;
  491. CheckPrecisionRange(precision);
  492. scale := Math.Power(10, precision);
  493. rec := Rect64(ScaleRect(rect, scale));
  494. with TRectClipLines.Create(rec) do
  495. try
  496. for i := 0 to High(paths) do
  497. begin
  498. pathRec := GetBounds(paths[i]);
  499. if not rect.Intersects(pathRec) then
  500. Continue
  501. else if rect.Contains(pathRec) then
  502. AppendPath(Result, paths[i])
  503. else
  504. begin
  505. tmpPath := ScalePath(paths[i], scale);
  506. tmpPaths := Execute(tmpPath);
  507. if tmpPaths = nil then Continue;
  508. AppendPaths(Result, ScalePathsD(tmpPaths, 1/scale));
  509. end;
  510. end;
  511. finally
  512. Free;
  513. end;
  514. end;
  515. //------------------------------------------------------------------------------
  516. function TranslatePath(const path: TPath64; dx, dy: Int64): TPath64;
  517. var
  518. i, len: integer;
  519. begin
  520. len := length(path);
  521. setLength(result, len);
  522. for i := 0 to len -1 do
  523. begin
  524. result[i].x := path[i].x + dx;
  525. result[i].y := path[i].y + dy;
  526. end;
  527. end;
  528. //------------------------------------------------------------------------------
  529. function TranslatePath(const path: TPathD; dx, dy: double): TPathD;
  530. var
  531. i, len: integer;
  532. begin
  533. len := length(path);
  534. setLength(result, len);
  535. for i := 0 to len -1 do
  536. begin
  537. result[i].x := path[i].x + dx;
  538. result[i].y := path[i].y + dy;
  539. end;
  540. end;
  541. //------------------------------------------------------------------------------
  542. function TranslatePaths(const paths: TPaths64; dx, dy: Int64): TPaths64;
  543. var
  544. i, len: integer;
  545. begin
  546. len := length(paths);
  547. setLength(result, len);
  548. for i := 0 to len -1 do
  549. begin
  550. result[i] := TranslatePath(paths[i], dx, dy);
  551. end;
  552. end;
  553. //------------------------------------------------------------------------------
  554. function TranslatePaths(const paths: TPathsD; dx, dy: double): TPathsD;
  555. var
  556. i, len: integer;
  557. begin
  558. len := length(paths);
  559. setLength(result, len);
  560. for i := 0 to len -1 do
  561. begin
  562. result[i] := TranslatePath(paths[i], dx, dy);
  563. end;
  564. end;
  565. //------------------------------------------------------------------------------
  566. function MinkowskiSum(const pattern, path: TPath64;
  567. pathIsClosed: Boolean): TPaths64;
  568. begin
  569. Result := Clipper.Minkowski.MinkowskiSum(pattern, path, pathIsClosed);
  570. end;
  571. //------------------------------------------------------------------------------
  572. function TrimCollinear(const p: TPath64; isOpenPath: Boolean = false): TPath64;
  573. var
  574. i,j, len: integer;
  575. begin
  576. len := Length(p);
  577. i := 0;
  578. if not isOpenPath then
  579. begin
  580. while (i < len -1) and
  581. (CrossProduct(p[len -1], p[i], p[i+1]) = 0) do inc(i);
  582. while (i < len -1) and
  583. (CrossProduct(p[len -2], p[len -1], p[i]) = 0) do dec(len);
  584. end;
  585. if (len - i < 3) then
  586. begin
  587. if not isOpenPath or (len < 2) or PointsEqual(p[0], p[1]) then
  588. Result := nil else
  589. Result := p;
  590. Exit;
  591. end;
  592. SetLength(Result, len -i);
  593. Result[0] := p[i];
  594. j := 0;
  595. for i := i+1 to len -2 do
  596. if CrossProduct(result[j], p[i], p[i+1]) <> 0 then
  597. begin
  598. inc(j);
  599. result[j] := p[i];
  600. end;
  601. if isOpenPath then
  602. begin
  603. inc(j);
  604. result[j] := p[len-1];
  605. end
  606. else if CrossProduct(result[j], p[len-1], result[0]) <> 0 then
  607. begin
  608. inc(j);
  609. result[j] := p[len-1];
  610. end else
  611. begin
  612. while (j > 1) and
  613. (CrossProduct(result[j-1], result[j], result[0]) = 0) do dec(j);
  614. if j < 2 then j := -1;
  615. end;
  616. SetLength(Result, j +1);
  617. end;
  618. //------------------------------------------------------------------------------
  619. function TrimCollinear(const path: TPathD;
  620. precision: integer; isOpenPath: Boolean = false): TPathD;
  621. var
  622. p: TPath64;
  623. scale: double;
  624. begin
  625. scale := power(10, precision);
  626. p := ScalePath(path, scale);
  627. p := TrimCollinear(p, isOpenPath);
  628. Result := ScalePathD(p, 1/scale);
  629. end;
  630. //------------------------------------------------------------------------------
  631. function PointInPolygon(const pt: TPoint64;
  632. const polygon: TPath64): TPointInPolygonResult;
  633. begin
  634. Result := Clipper.Core.PointInPolygon(pt, polygon);
  635. end;
  636. //------------------------------------------------------------------------------
  637. end.