UNPKG

@countertype/clipper2-ts

Version:

TypeScript port of Clipper2 polygon clipping and offsetting library

131 lines 4.92 kB
"use strict"; /******************************************************************************* * Author : Angus Johnson * * Date : 10 October 2024 * * Website : https://www.angusj.com * * Copyright : Angus Johnson 2010-2024 * * Purpose : Minkowski Sum and Difference * * License : https://www.boost.org/LICENSE_1_0.txt * *******************************************************************************/ Object.defineProperty(exports, "__esModule", { value: true }); exports.Minkowski = void 0; const Core_1 = require("./Core"); const Engine_1 = require("./Engine"); var Minkowski; (function (Minkowski) { function minkowskiInternal(pattern, path, isSum, isClosed) { const delta = isClosed ? 0 : 1; const patLen = pattern.length; const pathLen = path.length; const tmp = []; for (const pathPt of path) { const path2 = []; if (isSum) { for (const basePt of pattern) { path2.push(Core_1.Point64Utils.add(pathPt, basePt)); } } else { for (const basePt of pattern) { path2.push(Core_1.Point64Utils.subtract(pathPt, basePt)); } } tmp.push(path2); } const result = []; let g = isClosed ? pathLen - 1 : 0; let h = patLen - 1; for (let i = delta; i < pathLen; i++) { for (let j = 0; j < patLen; j++) { const quad = [ tmp[g][h], tmp[i][h], tmp[i][j], tmp[g][j] ]; if (!isPositive(quad)) { result.push(reversePath(quad)); } else { result.push(quad); } h = j; } g = i; } return result; } function sum(pattern, path, isClosed) { return union(minkowskiInternal(pattern, path, true, isClosed), Core_1.FillRule.NonZero); } Minkowski.sum = sum; function sumD(pattern, path, isClosed, decimalPlaces = 2) { const scale = Math.pow(10, decimalPlaces); const tmp = union(minkowskiInternal(scalePath64(pattern, scale), scalePath64(path, scale), true, isClosed), Core_1.FillRule.NonZero); return scalePathsD(tmp, 1 / scale); } Minkowski.sumD = sumD; function diff(pattern, path, isClosed) { return union(minkowskiInternal(pattern, path, false, isClosed), Core_1.FillRule.NonZero); } Minkowski.diff = diff; function diffD(pattern, path, isClosed, decimalPlaces = 2) { const scale = Math.pow(10, decimalPlaces); const tmp = union(minkowskiInternal(scalePath64(pattern, scale), scalePath64(path, scale), false, isClosed), Core_1.FillRule.NonZero); return scalePathsD(tmp, 1 / scale); } Minkowski.diffD = diffD; // Helper functions (these would typically be imported from the main Clipper class) function isPositive(path) { return area(path) >= 0; } function area(path) { // https://en.wikipedia.org/wiki/Shoelace_formula let a = 0.0; const cnt = path.length; if (cnt < 3) return 0.0; let prevPt = path[cnt - 1]; for (const pt of path) { a += (prevPt.y + pt.y) * (prevPt.x - pt.x); prevPt = pt; } return a * 0.5; } function reversePath(path) { return [...path].reverse(); } function scalePath64(path, scale) { const result = []; for (const pt of path) { result.push({ x: Core_1.InternalClipper.roundToEven(pt.x * scale), y: Core_1.InternalClipper.roundToEven(pt.y * scale) }); } return result; } function scalePathsD(paths, scale) { const result = []; for (const path of paths) { const pathD = []; for (const pt of path) { pathD.push({ x: pt.x * scale, y: pt.y * scale }); } result.push(pathD); } return result; } // Local union implementation to avoid circular dependency function union(paths, fillRule) { const solution = []; const c = new Engine_1.Clipper64(); c.addPaths(paths, Core_1.PathType.Subject); c.execute(Core_1.ClipType.Union, fillRule, solution); return solution; } })(Minkowski || (exports.Minkowski = Minkowski = {})); //# sourceMappingURL=Minkowski.js.map