calculate-packing 0.0.23 → 0.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +38 -16
- package/dist/index.js +207 -120
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -233,9 +233,16 @@ interface Point {
|
|
|
233
233
|
x: number;
|
|
234
234
|
y: number;
|
|
235
235
|
}
|
|
236
|
-
interface
|
|
237
|
-
|
|
238
|
-
|
|
236
|
+
interface OffsetPadPoint {
|
|
237
|
+
id: string;
|
|
238
|
+
offsetX: number;
|
|
239
|
+
offsetY: number;
|
|
240
|
+
}
|
|
241
|
+
interface MultiOffsetIrlsSolverParams {
|
|
242
|
+
/** Offset pad points relative to the current position */
|
|
243
|
+
offsetPadPoints: OffsetPadPoint[];
|
|
244
|
+
/** Map from offset pad ID to array of target points it should minimize distance to */
|
|
245
|
+
targetPointMap: Map<string, Point[]>;
|
|
239
246
|
/** Initial position for the algorithm */
|
|
240
247
|
initialPosition: Point;
|
|
241
248
|
/** Optional constraint function that maps a point to the nearest valid position */
|
|
@@ -248,22 +255,25 @@ interface IrlsSolverParams {
|
|
|
248
255
|
useSquaredDistance?: boolean;
|
|
249
256
|
}
|
|
250
257
|
/**
|
|
251
|
-
* IRLS (Iteratively Reweighted Least Squares) Solver
|
|
252
|
-
*
|
|
258
|
+
* Multi-Offset IRLS (Iteratively Reweighted Least Squares) Solver
|
|
259
|
+
* Extends the Weiszfeld algorithm to optimize a single position that minimizes
|
|
260
|
+
* the total distance from multiple offset pad points to their assigned target points.
|
|
253
261
|
*
|
|
254
|
-
*
|
|
255
|
-
*
|
|
262
|
+
* The offset pad points are positioned relative to the current position, and the
|
|
263
|
+
* algorithm finds the optimal position that minimizes the sum of distances from
|
|
264
|
+
* each offset pad to its assigned target points.
|
|
256
265
|
*/
|
|
257
|
-
declare class
|
|
258
|
-
|
|
266
|
+
declare class MultiOffsetIrlsSolver extends BaseSolver {
|
|
267
|
+
offsetPadPoints: OffsetPadPoint[];
|
|
268
|
+
targetPointMap: Map<string, Point[]>;
|
|
259
269
|
currentPosition: Point;
|
|
260
270
|
constraintFn?: (point: Point) => Point;
|
|
261
271
|
epsilon: number;
|
|
262
272
|
useSquaredDistance: boolean;
|
|
263
273
|
optimalPosition?: Point;
|
|
264
274
|
private readonly initialPosition;
|
|
265
|
-
constructor(params:
|
|
266
|
-
getConstructorParams():
|
|
275
|
+
constructor(params: MultiOffsetIrlsSolverParams);
|
|
276
|
+
getConstructorParams(): MultiOffsetIrlsSolverParams;
|
|
267
277
|
_setup(): void;
|
|
268
278
|
_step(): void;
|
|
269
279
|
/**
|
|
@@ -271,9 +281,21 @@ declare class IrlsSolver extends BaseSolver {
|
|
|
271
281
|
*/
|
|
272
282
|
getBestPosition(): Point;
|
|
273
283
|
/**
|
|
274
|
-
*
|
|
284
|
+
* Get the current absolute positions for all offset pad points
|
|
285
|
+
*/
|
|
286
|
+
getOffsetPadPositions(): Map<string, Point>;
|
|
287
|
+
/**
|
|
288
|
+
* Get the absolute position for a specific offset pad point
|
|
289
|
+
*/
|
|
290
|
+
getOffsetPadPosition(padId: string): Point | undefined;
|
|
291
|
+
/**
|
|
292
|
+
* Calculate total distance from current position to all assigned target points
|
|
275
293
|
*/
|
|
276
294
|
getTotalDistance(position?: Point): number;
|
|
295
|
+
/**
|
|
296
|
+
* Calculate total distance for a specific offset pad point
|
|
297
|
+
*/
|
|
298
|
+
getDistanceForPad(padId: string, position?: Point): number;
|
|
277
299
|
computeProgress(): number;
|
|
278
300
|
visualize(): GraphicsObject;
|
|
279
301
|
}
|
|
@@ -299,7 +321,7 @@ declare class OutlineSegmentCandidatePointSolver extends BaseSolver {
|
|
|
299
321
|
componentToPack: InputComponent;
|
|
300
322
|
viableBounds?: Bounds;
|
|
301
323
|
optimalPosition?: Point$3;
|
|
302
|
-
irlsSolver?:
|
|
324
|
+
irlsSolver?: MultiOffsetIrlsSolver;
|
|
303
325
|
constructor(params: {
|
|
304
326
|
outlineSegment: [Point$3, Point$3];
|
|
305
327
|
fullOutline: [Point$3, Point$3][];
|
|
@@ -310,15 +332,15 @@ declare class OutlineSegmentCandidatePointSolver extends BaseSolver {
|
|
|
310
332
|
componentToPack: InputComponent;
|
|
311
333
|
});
|
|
312
334
|
getConstructorParams(): ConstructorParameters<typeof OutlineSegmentCandidatePointSolver>[0];
|
|
313
|
-
|
|
335
|
+
_getOutlineBoundsWithMargin(params?: {
|
|
314
336
|
margin?: number;
|
|
315
337
|
}): Bounds;
|
|
316
338
|
_setup(): void;
|
|
317
339
|
_step(): void;
|
|
318
340
|
/**
|
|
319
|
-
* Get
|
|
341
|
+
* Get pad offset points and target point mappings for network connections
|
|
320
342
|
*/
|
|
321
|
-
private
|
|
343
|
+
private getNetworkTargetPointMappings;
|
|
322
344
|
/**
|
|
323
345
|
* Project a point onto the outline segment
|
|
324
346
|
*/
|
package/dist/index.js
CHANGED
|
@@ -1,43 +1,30 @@
|
|
|
1
1
|
// lib/PackSolver/checkOverlapWithPackedComponents.ts
|
|
2
|
+
import { computeDistanceBetweenBoxes } from "@tscircuit/math-utils";
|
|
2
3
|
function checkOverlapWithPackedComponents({
|
|
3
4
|
component,
|
|
4
5
|
packedComponents,
|
|
5
6
|
minGap
|
|
6
7
|
}) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (!xOverlap || !yOverlap) {
|
|
28
|
-
const xGap = xOverlap ? 0 : Math.min(
|
|
29
|
-
Math.abs(comp1Bounds.left - comp2Bounds.right),
|
|
30
|
-
Math.abs(comp2Bounds.left - comp1Bounds.right)
|
|
31
|
-
);
|
|
32
|
-
const yGap = yOverlap ? 0 : Math.min(
|
|
33
|
-
Math.abs(comp1Bounds.bottom - comp2Bounds.top),
|
|
34
|
-
Math.abs(comp2Bounds.bottom - comp1Bounds.top)
|
|
35
|
-
);
|
|
36
|
-
const actualGap = Math.max(xGap, yGap);
|
|
37
|
-
if (actualGap < minGap) {
|
|
38
|
-
return true;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
8
|
+
const allPackedPadBoxes = packedComponents.flatMap(
|
|
9
|
+
(c) => c.pads.map((p) => ({
|
|
10
|
+
center: { x: p.absoluteCenter.x, y: p.absoluteCenter.y },
|
|
11
|
+
width: p.size.x,
|
|
12
|
+
height: p.size.y
|
|
13
|
+
}))
|
|
14
|
+
);
|
|
15
|
+
const newComponentPadBoxes = component.pads.map((p) => ({
|
|
16
|
+
center: { x: p.absoluteCenter.x, y: p.absoluteCenter.y },
|
|
17
|
+
width: p.size.x,
|
|
18
|
+
height: p.size.y
|
|
19
|
+
}));
|
|
20
|
+
for (const newComponentPadBox of newComponentPadBoxes) {
|
|
21
|
+
for (const packedPadBox of allPackedPadBoxes) {
|
|
22
|
+
const { distance: boxDist } = computeDistanceBetweenBoxes(
|
|
23
|
+
newComponentPadBox,
|
|
24
|
+
packedPadBox
|
|
25
|
+
);
|
|
26
|
+
if (boxDist < minGap) {
|
|
27
|
+
return true;
|
|
41
28
|
}
|
|
42
29
|
}
|
|
43
30
|
}
|
|
@@ -1933,9 +1920,10 @@ var LargestRectOutsideOutlineFromPointSolver = class extends BaseSolver {
|
|
|
1933
1920
|
// lib/OutlineSegmentCandidatePointSolver/OutlineSegmentCandidatePointSolver.ts
|
|
1934
1921
|
import { clamp as clamp2 } from "@tscircuit/math-utils";
|
|
1935
1922
|
|
|
1936
|
-
// lib/solver-utils/
|
|
1937
|
-
var
|
|
1938
|
-
|
|
1923
|
+
// lib/solver-utils/MultiOffsetIrlsSolver.ts
|
|
1924
|
+
var MultiOffsetIrlsSolver = class extends BaseSolver {
|
|
1925
|
+
offsetPadPoints;
|
|
1926
|
+
targetPointMap;
|
|
1939
1927
|
currentPosition;
|
|
1940
1928
|
constraintFn;
|
|
1941
1929
|
epsilon;
|
|
@@ -1944,7 +1932,8 @@ var IrlsSolver = class extends BaseSolver {
|
|
|
1944
1932
|
initialPosition;
|
|
1945
1933
|
constructor(params) {
|
|
1946
1934
|
super();
|
|
1947
|
-
this.
|
|
1935
|
+
this.offsetPadPoints = [...params.offsetPadPoints];
|
|
1936
|
+
this.targetPointMap = new Map(params.targetPointMap);
|
|
1948
1937
|
this.initialPosition = { ...params.initialPosition };
|
|
1949
1938
|
this.currentPosition = { ...params.initialPosition };
|
|
1950
1939
|
this.constraintFn = params.constraintFn;
|
|
@@ -1954,7 +1943,8 @@ var IrlsSolver = class extends BaseSolver {
|
|
|
1954
1943
|
}
|
|
1955
1944
|
getConstructorParams() {
|
|
1956
1945
|
return {
|
|
1957
|
-
|
|
1946
|
+
offsetPadPoints: this.offsetPadPoints.map((pad) => ({ ...pad })),
|
|
1947
|
+
targetPointMap: new Map(this.targetPointMap),
|
|
1958
1948
|
initialPosition: this.initialPosition,
|
|
1959
1949
|
constraintFn: this.constraintFn,
|
|
1960
1950
|
epsilon: this.epsilon,
|
|
@@ -1965,30 +1955,43 @@ var IrlsSolver = class extends BaseSolver {
|
|
|
1965
1955
|
_setup() {
|
|
1966
1956
|
this.currentPosition = { ...this.initialPosition };
|
|
1967
1957
|
this.optimalPosition = void 0;
|
|
1968
|
-
|
|
1958
|
+
const hasTargets = Array.from(this.targetPointMap.values()).some(
|
|
1959
|
+
(targets) => targets.length > 0
|
|
1960
|
+
);
|
|
1961
|
+
if (!hasTargets || this.offsetPadPoints.length === 0) {
|
|
1969
1962
|
this.optimalPosition = { ...this.currentPosition };
|
|
1970
1963
|
this.solved = true;
|
|
1971
1964
|
}
|
|
1972
1965
|
}
|
|
1973
1966
|
_step() {
|
|
1974
|
-
if (this.
|
|
1967
|
+
if (this.offsetPadPoints.length === 0) return;
|
|
1975
1968
|
const { x: currentX, y: currentY } = this.currentPosition;
|
|
1976
1969
|
let weightedSumX = 0;
|
|
1977
1970
|
let weightedSumY = 0;
|
|
1978
1971
|
let totalWeight = 0;
|
|
1979
|
-
for (const
|
|
1980
|
-
const
|
|
1981
|
-
|
|
1982
|
-
const
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1972
|
+
for (const pad of this.offsetPadPoints) {
|
|
1973
|
+
const targetPoints = this.targetPointMap.get(pad.id) || [];
|
|
1974
|
+
if (targetPoints.length === 0) continue;
|
|
1975
|
+
const padX = currentX + pad.offsetX;
|
|
1976
|
+
const padY = currentY + pad.offsetY;
|
|
1977
|
+
for (const targetPoint of targetPoints) {
|
|
1978
|
+
const dx2 = padX - targetPoint.x;
|
|
1979
|
+
const dy2 = padY - targetPoint.y;
|
|
1980
|
+
const distance = Math.sqrt(dx2 * dx2 + dy2 * dy2);
|
|
1981
|
+
let weight;
|
|
1982
|
+
if (this.useSquaredDistance) {
|
|
1983
|
+
weight = 1;
|
|
1984
|
+
} else {
|
|
1985
|
+
weight = distance < this.epsilon ? 1e6 : 1 / distance;
|
|
1986
|
+
}
|
|
1987
|
+
const targetForCurrentPos = {
|
|
1988
|
+
x: targetPoint.x - pad.offsetX,
|
|
1989
|
+
y: targetPoint.y - pad.offsetY
|
|
1990
|
+
};
|
|
1991
|
+
weightedSumX += weight * targetForCurrentPos.x;
|
|
1992
|
+
weightedSumY += weight * targetForCurrentPos.y;
|
|
1993
|
+
totalWeight += weight;
|
|
1988
1994
|
}
|
|
1989
|
-
weightedSumX += weight * targetPoint.x;
|
|
1990
|
-
weightedSumY += weight * targetPoint.y;
|
|
1991
|
-
totalWeight += weight;
|
|
1992
1995
|
}
|
|
1993
1996
|
const newPosition = {
|
|
1994
1997
|
x: totalWeight > 0 ? weightedSumX / totalWeight : currentX,
|
|
@@ -2012,13 +2015,65 @@ var IrlsSolver = class extends BaseSolver {
|
|
|
2012
2015
|
return this.optimalPosition || this.currentPosition;
|
|
2013
2016
|
}
|
|
2014
2017
|
/**
|
|
2015
|
-
*
|
|
2018
|
+
* Get the current absolute positions for all offset pad points
|
|
2019
|
+
*/
|
|
2020
|
+
getOffsetPadPositions() {
|
|
2021
|
+
const currentPos = this.getBestPosition();
|
|
2022
|
+
const padPositions = /* @__PURE__ */ new Map();
|
|
2023
|
+
for (const pad of this.offsetPadPoints) {
|
|
2024
|
+
padPositions.set(pad.id, {
|
|
2025
|
+
x: currentPos.x + pad.offsetX,
|
|
2026
|
+
y: currentPos.y + pad.offsetY
|
|
2027
|
+
});
|
|
2028
|
+
}
|
|
2029
|
+
return padPositions;
|
|
2030
|
+
}
|
|
2031
|
+
/**
|
|
2032
|
+
* Get the absolute position for a specific offset pad point
|
|
2033
|
+
*/
|
|
2034
|
+
getOffsetPadPosition(padId) {
|
|
2035
|
+
const positions = this.getOffsetPadPositions();
|
|
2036
|
+
return positions.get(padId);
|
|
2037
|
+
}
|
|
2038
|
+
/**
|
|
2039
|
+
* Calculate total distance from current position to all assigned target points
|
|
2016
2040
|
*/
|
|
2017
2041
|
getTotalDistance(position) {
|
|
2018
|
-
const pos = position || this.
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
const
|
|
2042
|
+
const pos = position || this.getBestPosition();
|
|
2043
|
+
let totalDistance = 0;
|
|
2044
|
+
for (const pad of this.offsetPadPoints) {
|
|
2045
|
+
const padPosition = {
|
|
2046
|
+
x: pos.x + pad.offsetX,
|
|
2047
|
+
y: pos.y + pad.offsetY
|
|
2048
|
+
};
|
|
2049
|
+
const targetPoints = this.targetPointMap.get(pad.id) || [];
|
|
2050
|
+
for (const target of targetPoints) {
|
|
2051
|
+
const dx = padPosition.x - target.x;
|
|
2052
|
+
const dy = padPosition.y - target.y;
|
|
2053
|
+
if (this.useSquaredDistance) {
|
|
2054
|
+
totalDistance += dx * dx + dy * dy;
|
|
2055
|
+
} else {
|
|
2056
|
+
totalDistance += Math.sqrt(dx * dx + dy * dy);
|
|
2057
|
+
}
|
|
2058
|
+
}
|
|
2059
|
+
}
|
|
2060
|
+
return totalDistance;
|
|
2061
|
+
}
|
|
2062
|
+
/**
|
|
2063
|
+
* Calculate total distance for a specific offset pad point
|
|
2064
|
+
*/
|
|
2065
|
+
getDistanceForPad(padId, position) {
|
|
2066
|
+
const pos = position || this.getBestPosition();
|
|
2067
|
+
const pad = this.offsetPadPoints.find((p) => p.id === padId);
|
|
2068
|
+
if (!pad) return 0;
|
|
2069
|
+
const padPosition = {
|
|
2070
|
+
x: pos.x + pad.offsetX,
|
|
2071
|
+
y: pos.y + pad.offsetY
|
|
2072
|
+
};
|
|
2073
|
+
const targetPoints = this.targetPointMap.get(padId) || [];
|
|
2074
|
+
return targetPoints.reduce((sum, target) => {
|
|
2075
|
+
const dx = padPosition.x - target.x;
|
|
2076
|
+
const dy = padPosition.y - target.y;
|
|
2022
2077
|
if (this.useSquaredDistance) {
|
|
2023
2078
|
return sum + (dx * dx + dy * dy);
|
|
2024
2079
|
} else {
|
|
@@ -2027,7 +2082,7 @@ var IrlsSolver = class extends BaseSolver {
|
|
|
2027
2082
|
}, 0);
|
|
2028
2083
|
}
|
|
2029
2084
|
computeProgress() {
|
|
2030
|
-
if (this.
|
|
2085
|
+
if (this.offsetPadPoints.length === 0) return 1;
|
|
2031
2086
|
const initialDistance = this.getTotalDistance(this.initialPosition);
|
|
2032
2087
|
const currentDistance = this.getTotalDistance();
|
|
2033
2088
|
if (initialDistance === 0) return 1;
|
|
@@ -2041,26 +2096,52 @@ var IrlsSolver = class extends BaseSolver {
|
|
|
2041
2096
|
rects: [],
|
|
2042
2097
|
circles: []
|
|
2043
2098
|
};
|
|
2044
|
-
|
|
2099
|
+
const colors = [
|
|
2100
|
+
"#4CAF50",
|
|
2101
|
+
"#2196F3",
|
|
2102
|
+
"#FF9800",
|
|
2103
|
+
"#9C27B0",
|
|
2104
|
+
"#F44336",
|
|
2105
|
+
"#607D8B"
|
|
2106
|
+
];
|
|
2107
|
+
const currentPos = this.getBestPosition();
|
|
2108
|
+
for (let i = 0; i < this.offsetPadPoints.length; i++) {
|
|
2109
|
+
const pad = this.offsetPadPoints[i];
|
|
2110
|
+
if (!pad) continue;
|
|
2111
|
+
const color = colors[i % colors.length];
|
|
2112
|
+
const targetPoints = this.targetPointMap.get(pad.id) || [];
|
|
2113
|
+
const padPosition = {
|
|
2114
|
+
x: currentPos.x + pad.offsetX,
|
|
2115
|
+
y: currentPos.y + pad.offsetY
|
|
2116
|
+
};
|
|
2117
|
+
for (const point of targetPoints) {
|
|
2118
|
+
graphics.points.push({
|
|
2119
|
+
...point,
|
|
2120
|
+
color
|
|
2121
|
+
});
|
|
2122
|
+
}
|
|
2123
|
+
for (const point of targetPoints) {
|
|
2124
|
+
graphics.lines.push({
|
|
2125
|
+
points: [padPosition, point],
|
|
2126
|
+
strokeColor: color
|
|
2127
|
+
});
|
|
2128
|
+
}
|
|
2045
2129
|
graphics.points.push({
|
|
2046
|
-
|
|
2047
|
-
|
|
2130
|
+
x: padPosition.x,
|
|
2131
|
+
y: padPosition.y,
|
|
2132
|
+
color
|
|
2048
2133
|
});
|
|
2049
2134
|
}
|
|
2050
2135
|
graphics.points.push({
|
|
2051
2136
|
...this.currentPosition,
|
|
2052
2137
|
color: "#f44336"
|
|
2138
|
+
// Red like in IrlsSolver
|
|
2053
2139
|
});
|
|
2054
|
-
for (const point of this.targetPoints) {
|
|
2055
|
-
graphics.lines.push({
|
|
2056
|
-
points: [this.currentPosition, point],
|
|
2057
|
-
strokeColor: "#666"
|
|
2058
|
-
});
|
|
2059
|
-
}
|
|
2060
2140
|
if (this.optimalPosition) {
|
|
2061
2141
|
graphics.points.push({
|
|
2062
2142
|
...this.optimalPosition,
|
|
2063
2143
|
color: "rgba(76, 175, 80, 0.3)"
|
|
2144
|
+
// Semi-transparent green like in IrlsSolver
|
|
2064
2145
|
});
|
|
2065
2146
|
}
|
|
2066
2147
|
return graphics;
|
|
@@ -2232,31 +2313,27 @@ var OutlineSegmentCandidatePointSolver = class extends BaseSolver {
|
|
|
2232
2313
|
componentToPack: this.componentToPack
|
|
2233
2314
|
};
|
|
2234
2315
|
}
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
},
|
|
2246
|
-
{ minX: Infinity, minY: Infinity, maxX: -Infinity, maxY: -Infinity }
|
|
2247
|
-
);
|
|
2248
|
-
if (params?.margin) {
|
|
2249
|
-
return {
|
|
2250
|
-
minX: bounds.minX - params.margin,
|
|
2251
|
-
minY: bounds.minY - params.margin,
|
|
2252
|
-
maxX: bounds.maxX + params.margin,
|
|
2253
|
-
maxY: bounds.maxY + params.margin
|
|
2254
|
-
};
|
|
2316
|
+
_getOutlineBoundsWithMargin(params = {}) {
|
|
2317
|
+
let minX = Infinity;
|
|
2318
|
+
let minY = Infinity;
|
|
2319
|
+
let maxX = -Infinity;
|
|
2320
|
+
let maxY = -Infinity;
|
|
2321
|
+
for (const [p1, p2] of this.fullOutline) {
|
|
2322
|
+
minX = Math.min(minX, p1.x, p2.x);
|
|
2323
|
+
minY = Math.min(minY, p1.y, p2.y);
|
|
2324
|
+
maxX = Math.max(maxX, p1.x, p2.x);
|
|
2325
|
+
maxY = Math.max(maxY, p1.y, p2.y);
|
|
2255
2326
|
}
|
|
2256
|
-
|
|
2327
|
+
const margin = params.margin ?? 0;
|
|
2328
|
+
return {
|
|
2329
|
+
minX: minX - margin,
|
|
2330
|
+
minY: minY - margin,
|
|
2331
|
+
maxX: maxX + margin,
|
|
2332
|
+
maxY: maxY + margin
|
|
2333
|
+
};
|
|
2257
2334
|
}
|
|
2258
2335
|
_setup() {
|
|
2259
|
-
const
|
|
2336
|
+
const { offsetPadPoints, targetPointMap } = this.getNetworkTargetPointMappings();
|
|
2260
2337
|
const [p1, p2] = this.outlineSegment;
|
|
2261
2338
|
const constraintFn = (point) => {
|
|
2262
2339
|
const projectedPoint = this.projectPointOntoSegment(
|
|
@@ -2269,11 +2346,11 @@ var OutlineSegmentCandidatePointSolver = class extends BaseSolver {
|
|
|
2269
2346
|
const componentBounds = getInputComponentBounds(this.componentToPack, {
|
|
2270
2347
|
rotationDegrees: this.componentRotationDegrees
|
|
2271
2348
|
});
|
|
2272
|
-
const packedComponentBoundsWithMargin = this.
|
|
2349
|
+
const packedComponentBoundsWithMargin = this._getOutlineBoundsWithMargin({
|
|
2273
2350
|
margin: Math.max(
|
|
2274
2351
|
componentBounds.maxX - componentBounds.minX,
|
|
2275
2352
|
componentBounds.maxY - componentBounds.minY
|
|
2276
|
-
) * 2
|
|
2353
|
+
) * 2 + this.minGap * 2
|
|
2277
2354
|
});
|
|
2278
2355
|
const largestRectSolverParams = {
|
|
2279
2356
|
fullOutline: this.fullOutline.flatMap(([p]) => p),
|
|
@@ -2333,14 +2410,14 @@ var OutlineSegmentCandidatePointSolver = class extends BaseSolver {
|
|
|
2333
2410
|
x: (vp1.x + vp2.x) / 2,
|
|
2334
2411
|
y: (vp1.y + vp2.y) / 2
|
|
2335
2412
|
});
|
|
2336
|
-
this.irlsSolver = new
|
|
2337
|
-
|
|
2413
|
+
this.irlsSolver = new MultiOffsetIrlsSolver({
|
|
2414
|
+
offsetPadPoints,
|
|
2415
|
+
targetPointMap,
|
|
2338
2416
|
initialPosition,
|
|
2339
2417
|
constraintFn,
|
|
2340
2418
|
epsilon: 1e-6,
|
|
2341
2419
|
maxIterations: 50,
|
|
2342
|
-
useSquaredDistance:
|
|
2343
|
-
// this.packStrategy === "minimum_sum_squared_distance_to_network",
|
|
2420
|
+
useSquaredDistance: this.packStrategy === "minimum_sum_squared_distance_to_network"
|
|
2344
2421
|
});
|
|
2345
2422
|
}
|
|
2346
2423
|
_step() {
|
|
@@ -2359,20 +2436,28 @@ var OutlineSegmentCandidatePointSolver = class extends BaseSolver {
|
|
|
2359
2436
|
}
|
|
2360
2437
|
}
|
|
2361
2438
|
/**
|
|
2362
|
-
* Get
|
|
2439
|
+
* Get pad offset points and target point mappings for network connections
|
|
2363
2440
|
*/
|
|
2364
|
-
|
|
2365
|
-
const targetPoints = [];
|
|
2441
|
+
getNetworkTargetPointMappings() {
|
|
2366
2442
|
const rotatedPads = this.getRotatedComponentPads();
|
|
2367
|
-
const
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2443
|
+
const offsetPadPoints = rotatedPads.map((pad) => ({
|
|
2444
|
+
id: pad.padId,
|
|
2445
|
+
offsetX: pad.offset.x,
|
|
2446
|
+
offsetY: pad.offset.y
|
|
2447
|
+
}));
|
|
2448
|
+
const targetPointMap = /* @__PURE__ */ new Map();
|
|
2449
|
+
for (const pad of rotatedPads) {
|
|
2450
|
+
const targetPoints = [];
|
|
2451
|
+
for (const packedComponent of this.packedComponents) {
|
|
2452
|
+
for (const packedPad of packedComponent.pads) {
|
|
2453
|
+
if (packedPad.networkId === pad.networkId) {
|
|
2454
|
+
targetPoints.push(packedPad.absoluteCenter);
|
|
2455
|
+
}
|
|
2372
2456
|
}
|
|
2373
2457
|
}
|
|
2458
|
+
targetPointMap.set(pad.padId, targetPoints);
|
|
2374
2459
|
}
|
|
2375
|
-
return
|
|
2460
|
+
return { offsetPadPoints, targetPointMap };
|
|
2376
2461
|
}
|
|
2377
2462
|
/**
|
|
2378
2463
|
* Project a point onto the outline segment
|
|
@@ -2598,13 +2683,6 @@ var OutlineSegmentCandidatePointSolver = class extends BaseSolver {
|
|
|
2598
2683
|
}
|
|
2599
2684
|
}
|
|
2600
2685
|
if (this.irlsSolver) {
|
|
2601
|
-
const targetPoints = this.getNetworkTargetPoints();
|
|
2602
|
-
for (const point of targetPoints) {
|
|
2603
|
-
graphics.points.push({
|
|
2604
|
-
...point,
|
|
2605
|
-
color: "#4CAF50"
|
|
2606
|
-
});
|
|
2607
|
-
}
|
|
2608
2686
|
const currentPos = this.irlsSolver.currentPosition;
|
|
2609
2687
|
graphics.points.push({
|
|
2610
2688
|
...currentPos,
|
|
@@ -2719,6 +2797,7 @@ var SingleComponentPackSolver = class extends BaseSolver {
|
|
|
2719
2797
|
this.currentRotationIndex = 0;
|
|
2720
2798
|
}
|
|
2721
2799
|
executeSegmentCandidatePhase() {
|
|
2800
|
+
console.log("executeSegmentCandidatePhase");
|
|
2722
2801
|
if (this.activeSubSolver?.solved || this.activeSubSolver?.failed) {
|
|
2723
2802
|
const queuedSegment = this.queuedOutlineSegments[this.currentSegmentIndex];
|
|
2724
2803
|
const rotation = queuedSegment.availableRotations[this.currentRotationIndex];
|
|
@@ -2726,15 +2805,23 @@ var SingleComponentPackSolver = class extends BaseSolver {
|
|
|
2726
2805
|
let optimalPosition;
|
|
2727
2806
|
if (this.activeSubSolver.solved && this.activeSubSolver.optimalPosition) {
|
|
2728
2807
|
optimalPosition = this.activeSubSolver.optimalPosition;
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
optimalPosition,
|
|
2734
|
-
distance,
|
|
2735
|
-
segmentIndex: queuedSegment.segmentIndex,
|
|
2736
|
-
rotationIndex: this.currentRotationIndex
|
|
2808
|
+
const hasOverlap = checkOverlapWithPackedComponents({
|
|
2809
|
+
component: this.createPackedComponent(optimalPosition, rotation),
|
|
2810
|
+
packedComponents: this.packedComponents,
|
|
2811
|
+
minGap: this.minGap
|
|
2737
2812
|
});
|
|
2813
|
+
console.log("hasOverlap", hasOverlap);
|
|
2814
|
+
if (!hasOverlap) {
|
|
2815
|
+
distance = this.calculateDistance(optimalPosition, rotation);
|
|
2816
|
+
this.candidateResults.push({
|
|
2817
|
+
segment: queuedSegment.segment,
|
|
2818
|
+
rotation,
|
|
2819
|
+
optimalPosition,
|
|
2820
|
+
distance,
|
|
2821
|
+
segmentIndex: queuedSegment.segmentIndex,
|
|
2822
|
+
rotationIndex: this.currentRotationIndex
|
|
2823
|
+
});
|
|
2824
|
+
}
|
|
2738
2825
|
}
|
|
2739
2826
|
this.currentRotationIndex++;
|
|
2740
2827
|
this.activeSubSolver = void 0;
|
package/package.json
CHANGED