Lower the axial body threshold while retaining fringe rejection, minimize length-only tip inset, and make sheet sensitivity curves testable and conservative at zero.
This commit is contained in:
@@ -82,7 +82,13 @@ export interface OverlayPlanInput {
|
||||
}
|
||||
|
||||
/**
|
||||
* Axial tip stations from across-width profile (#71).
|
||||
* Min across-width as a fraction of max bin width for an axial bin to count as a tip.
|
||||
* #71 used 0.32 (excluded fringe); #73 lowers to ~0.15 so tapered live-edge tips remain.
|
||||
*/
|
||||
export const BODY_WIDTH_FRAC = 0.15;
|
||||
|
||||
/**
|
||||
* Axial tip stations from across-width profile (#71/#73).
|
||||
* Thin fringe whiskers past the visible body survive 0.2%/99.8% percentiles;
|
||||
* require each axial bin to have meaningful across-width before it counts as a tip.
|
||||
*/
|
||||
@@ -121,8 +127,8 @@ function widthAwareAxialRange(
|
||||
widths.push({ bin, width });
|
||||
if (width > maxWidth) maxWidth = width;
|
||||
}
|
||||
// Body threshold: exclude narrow fringe; keep natural mild tapers.
|
||||
const thresh = Math.max(4, maxWidth * 0.32);
|
||||
// Body threshold: exclude ~10% fringe whiskers; keep 15–25% live-edge tapers (#73).
|
||||
const thresh = Math.max(4, maxWidth * BODY_WIDTH_FRAC);
|
||||
widths.sort((a, b) => a.bin - b.bin);
|
||||
let tipLo = widths[0].bin;
|
||||
let tipHi = widths[widths.length - 1].bin;
|
||||
@@ -282,7 +288,10 @@ export function buildOverlayPlan(input: OverlayPlanInput): OverlayPlan {
|
||||
// Inset for stroke + arrowhead so visual tips sit on/inside edges (#71).
|
||||
const lineW = Math.max(2, Math.round(fontPx / 10));
|
||||
const arrowHead = Math.max(7, fontPx * 0.32);
|
||||
const edgeInset = Math.max(lineW / 2 + 0.5, arrowHead * 0.15);
|
||||
// Width tips retain stroke/arrowhead protection. Length endpoints need only
|
||||
// half-stroke protection: larger arrowhead-derived inset visibly under-reached tips (#73).
|
||||
const widthEdgeInset = Math.max(lineW / 2 + 0.5, arrowHead * 0.15);
|
||||
const lengthEdgeInset = Math.max(0.5, lineW / 2);
|
||||
const pad = Math.max(10, Math.min(28, fontPx * 1.1));
|
||||
const stations = overlayWidthStations(lengthIn);
|
||||
const widths: OverlayWidthMark[] = [];
|
||||
@@ -300,8 +309,8 @@ export function buildOverlayPlan(input: OverlayPlanInput): OverlayPlan {
|
||||
const wlen = Math.hypot(wdx, wdy) || 1;
|
||||
const wux = wdx / wlen;
|
||||
const wuy = wdy / wlen;
|
||||
const left: [number, number] = [leftMapped[0] + wux * edgeInset, leftMapped[1] + wuy * edgeInset];
|
||||
const right: [number, number] = [rightMapped[0] - wux * edgeInset, rightMapped[1] - wuy * edgeInset];
|
||||
const left: [number, number] = [leftMapped[0] + wux * widthEdgeInset, leftMapped[1] + wuy * widthEdgeInset];
|
||||
const right: [number, number] = [rightMapped[0] - wux * widthEdgeInset, rightMapped[1] - wuy * widthEdgeInset];
|
||||
// Width number sits axis-left outside the slab (past left tip).
|
||||
const labelOff = extent.minP - pad - fontPx * 0.85;
|
||||
const labelSrcW: [number, number] = [ox + rx * labelOff, oy + ry * labelOff];
|
||||
@@ -337,8 +346,8 @@ export function buildOverlayPlan(input: OverlayPlanInput): OverlayPlan {
|
||||
const llen0 = Math.hypot(ldx0, ldy0) || 1;
|
||||
const lux = ldx0 / llen0;
|
||||
const luy = ldy0 / llen0;
|
||||
const aInv: [number, number] = [aMapped[0] + lux * edgeInset, aMapped[1] + luy * edgeInset];
|
||||
const bInv: [number, number] = [bMapped[0] - lux * edgeInset, bMapped[1] - luy * edgeInset];
|
||||
const aInv: [number, number] = [aMapped[0] + lux * lengthEdgeInset, aMapped[1] + luy * lengthEdgeInset];
|
||||
const bInv: [number, number] = [bMapped[0] - lux * lengthEdgeInset, bMapped[1] - luy * lengthEdgeInset];
|
||||
const midInv: [number, number] = [(aInv[0] + bInv[0]) / 2, (aInv[1] + bInv[1]) / 2];
|
||||
// Length label further axis-right of dim line so glyphs stay off the wood (#71).
|
||||
const mapOrigin = mapToInventory(0, 0);
|
||||
|
||||
Reference in New Issue
Block a user