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.
Files changed (3) hide show
  1. package/dist/index.d.ts +38 -16
  2. package/dist/index.js +207 -120
  3. 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 IrlsSolverParams {
237
- /** Target points to minimize distance to */
238
- targetPoints: Point[];
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 using the Weiszfeld algorithm
252
- * to find the geometric median (point that minimizes sum of distances to target points).
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
- * This solver can be used as a subsolver in other optimization problems where
255
- * you need to find the optimal position that minimizes total distance to a set of points.
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 IrlsSolver extends BaseSolver {
258
- targetPoints: Point[];
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: IrlsSolverParams);
266
- getConstructorParams(): IrlsSolverParams;
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
- * Calculate total distance from current position to all target points
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?: 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
- _getPackedComponentBounds(params?: {
335
+ _getOutlineBoundsWithMargin(params?: {
314
336
  margin?: number;
315
337
  }): Bounds;
316
338
  _setup(): void;
317
339
  _step(): void;
318
340
  /**
319
- * Get target points from network connections, considering the component's rotation
341
+ * Get pad offset points and target point mappings for network connections
320
342
  */
321
- private getNetworkTargetPoints;
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
- for (const componentPad of component.pads) {
8
- for (const packedComponent of packedComponents) {
9
- for (const packedPad of packedComponent.pads) {
10
- const comp1Bounds = {
11
- left: componentPad.absoluteCenter.x - componentPad.size.x / 2,
12
- right: componentPad.absoluteCenter.x + componentPad.size.x / 2,
13
- bottom: componentPad.absoluteCenter.y - componentPad.size.y / 2,
14
- top: componentPad.absoluteCenter.y + componentPad.size.y / 2
15
- };
16
- const comp2Bounds = {
17
- left: packedPad.absoluteCenter.x - packedPad.size.x / 2,
18
- right: packedPad.absoluteCenter.x + packedPad.size.x / 2,
19
- bottom: packedPad.absoluteCenter.y - packedPad.size.y / 2,
20
- top: packedPad.absoluteCenter.y + packedPad.size.y / 2
21
- };
22
- const xOverlap = comp1Bounds.right > comp2Bounds.left && comp2Bounds.right > comp1Bounds.left;
23
- const yOverlap = comp1Bounds.top > comp2Bounds.bottom && comp2Bounds.top > comp1Bounds.bottom;
24
- if (xOverlap && yOverlap) {
25
- return true;
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/IrlsSolver.ts
1937
- var IrlsSolver = class extends BaseSolver {
1938
- targetPoints;
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.targetPoints = params.targetPoints;
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
- targetPoints: this.targetPoints,
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
- if (this.targetPoints.length === 0) {
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.targetPoints.length === 0) return;
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 targetPoint of this.targetPoints) {
1980
- const dx2 = currentX - targetPoint.x;
1981
- const dy2 = currentY - targetPoint.y;
1982
- const distance = Math.sqrt(dx2 * dx2 + dy2 * dy2);
1983
- let weight;
1984
- if (this.useSquaredDistance) {
1985
- weight = 1;
1986
- } else {
1987
- weight = distance < this.epsilon ? 1e6 : 1 / distance;
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
- * Calculate total distance from current position to all target points
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.currentPosition;
2019
- return this.targetPoints.reduce((sum, target) => {
2020
- const dx = pos.x - target.x;
2021
- const dy = pos.y - target.y;
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.targetPoints.length === 0) return 1;
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
- for (const point of this.targetPoints) {
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
- ...point,
2047
- color: "#4CAF50"
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
- _getPackedComponentBounds(params = {}) {
2236
- const bounds = this.packedComponents.reduce(
2237
- (acc, component) => {
2238
- const componentBounds = getComponentBounds(component, 0);
2239
- return {
2240
- minX: Math.min(acc.minX, componentBounds.minX),
2241
- minY: Math.min(acc.minY, componentBounds.minY),
2242
- maxX: Math.max(acc.maxX, componentBounds.maxX),
2243
- maxY: Math.max(acc.maxY, componentBounds.maxY)
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
- return bounds;
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 targetPoints = this.getNetworkTargetPoints();
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._getPackedComponentBounds({
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 IrlsSolver({
2337
- targetPoints,
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: true
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 target points from network connections, considering the component's rotation
2439
+ * Get pad offset points and target point mappings for network connections
2363
2440
  */
2364
- getNetworkTargetPoints() {
2365
- const targetPoints = [];
2441
+ getNetworkTargetPointMappings() {
2366
2442
  const rotatedPads = this.getRotatedComponentPads();
2367
- const componentNetworkIds = new Set(rotatedPads.map((pad) => pad.networkId));
2368
- for (const packedComponent of this.packedComponents) {
2369
- for (const pad of packedComponent.pads) {
2370
- if (componentNetworkIds.has(pad.networkId)) {
2371
- targetPoints.push(pad.absoluteCenter);
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 targetPoints;
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
- distance = this.calculateDistance(optimalPosition, rotation);
2730
- this.candidateResults.push({
2731
- segment: queuedSegment.segment,
2732
- rotation,
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
@@ -2,7 +2,7 @@
2
2
  "name": "calculate-packing",
3
3
  "main": "dist/index.js",
4
4
  "type": "module",
5
- "version": "0.0.23",
5
+ "version": "0.0.24",
6
6
  "description": "Calculate a packing layout with support for different strategy configurations",
7
7
  "scripts": {
8
8
  "start": "cosmos",