From 1551f41434edc799b306d4dbffeac11846f6e727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?0hm=E2=98=98=EF=B8=8F?= <109351887+0hmX@users.noreply.github.com> Date: Thu, 25 Dec 2025 01:46:06 +0530 Subject: [PATCH] Respect board outlines for seed candidates --- .../RectDiffSeedingSolver/RectDiffSeedingSolver.ts | 2 ++ lib/solvers/RectDiffSeedingSolver/computeCandidates3D.ts | 9 +++++++++ .../RectDiffSeedingSolver/computeEdgeCandidates3D.ts | 8 ++++++++ 3 files changed, 19 insertions(+) diff --git a/lib/solvers/RectDiffSeedingSolver/RectDiffSeedingSolver.ts b/lib/solvers/RectDiffSeedingSolver/RectDiffSeedingSolver.ts index 129e459..622b0ba 100644 --- a/lib/solvers/RectDiffSeedingSolver/RectDiffSeedingSolver.ts +++ b/lib/solvers/RectDiffSeedingSolver/RectDiffSeedingSolver.ts @@ -165,6 +165,7 @@ export class RectDiffSeedingSolver extends BaseSolver { hardPlacedByLayer, obstacleIndexByLayer: this.input.obstacleIndexByLayer, placedIndexByLayer: this.placedIndexByLayer, + outline: this.srj.outline, }) this.totalSeedsThisGrid = this.candidates.length this.consumedSeedsThisGrid = 0 @@ -187,6 +188,7 @@ export class RectDiffSeedingSolver extends BaseSolver { obstacleIndexByLayer: this.input.obstacleIndexByLayer, placedIndexByLayer: this.placedIndexByLayer, hardPlacedByLayer, + outline: this.srj.outline, }) this.edgeAnalysisDone = true this.totalSeedsThisGrid = this.candidates.length diff --git a/lib/solvers/RectDiffSeedingSolver/computeCandidates3D.ts b/lib/solvers/RectDiffSeedingSolver/computeCandidates3D.ts index 7334ecd..99ec681 100644 --- a/lib/solvers/RectDiffSeedingSolver/computeCandidates3D.ts +++ b/lib/solvers/RectDiffSeedingSolver/computeCandidates3D.ts @@ -2,6 +2,7 @@ import type { Candidate3D, XYRect } from "../../rectdiff-types" import { EPS, distancePointToRectEdges } from "../../utils/rectdiff-geometry" import { isFullyOccupiedAtPoint } from "../../utils/isFullyOccupiedAtPoint" import { longestFreeSpanAroundZ } from "./longestFreeSpanAroundZ" +import { isPointInPolygon } from "./isPointInPolygon" import type RBush from "rbush" import type { RTreeRect } from "lib/types/capacity-mesh-types" @@ -15,6 +16,7 @@ export function computeCandidates3D(params: { obstacleIndexByLayer: Array | undefined> placedIndexByLayer: Array | undefined> hardPlacedByLayer: XYRect[][] + outline?: Array<{ x: number; y: number }> }): Candidate3D[] { const { bounds, @@ -23,6 +25,7 @@ export function computeCandidates3D(params: { obstacleIndexByLayer, placedIndexByLayer, hardPlacedByLayer, + outline, } = params const out = new Map() // key by (x,y) @@ -38,6 +41,12 @@ export function computeCandidates3D(params: { continue } + if (outline && outline.length > 2) { + if (!isPointInPolygon({ x, y }, outline)) { + continue + } + } + // New rule: Only drop if EVERY layer is occupied (by obstacle or node) if ( isFullyOccupiedAtPoint({ diff --git a/lib/solvers/RectDiffSeedingSolver/computeEdgeCandidates3D.ts b/lib/solvers/RectDiffSeedingSolver/computeEdgeCandidates3D.ts index 8ee055b..c12bd3a 100644 --- a/lib/solvers/RectDiffSeedingSolver/computeEdgeCandidates3D.ts +++ b/lib/solvers/RectDiffSeedingSolver/computeEdgeCandidates3D.ts @@ -2,6 +2,7 @@ import type { Candidate3D, XYRect } from "../../rectdiff-types" import { EPS, distancePointToRectEdges } from "../../utils/rectdiff-geometry" import { isFullyOccupiedAtPoint } from "../../utils/isFullyOccupiedAtPoint" import { longestFreeSpanAroundZ } from "./longestFreeSpanAroundZ" +import { isPointInPolygon } from "./isPointInPolygon" import type RBush from "rbush" import type { RTreeRect } from "lib/types/capacity-mesh-types" @@ -84,6 +85,7 @@ export function computeEdgeCandidates3D(params: { obstacleIndexByLayer: Array | undefined> placedIndexByLayer: Array | undefined> hardPlacedByLayer: XYRect[][] + outline?: Array<{ x: number; y: number }> }): Candidate3D[] { const { bounds, @@ -92,6 +94,7 @@ export function computeEdgeCandidates3D(params: { obstacleIndexByLayer, placedIndexByLayer, hardPlacedByLayer, + outline, } = params const out: Candidate3D[] = [] @@ -119,6 +122,11 @@ export function computeEdgeCandidates3D(params: { y > bounds.y + bounds.height - EPS ) return + if (outline && outline.length > 2) { + if (!isPointInPolygon({ x, y }, outline)) { + return + } + } if (fullyOcc({ x, y })) return // new rule: only drop if truly impossible // Distance uses obstacles + hard nodes (soft nodes ignored for ranking)