74 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import type { GutterNode } from '@pascal-app/core'
/**
* Shared outlet/profile geometry constants + math used by the gutter
* mesh builder, the outlet lookup the downspout mounts against, and the
* downspout's own routing. Kept in one place so the trough-floor probe
* and the collar dimensions can't drift between the three call sites
* (they did before this file — `profileFloorMidZ` was copied verbatim
* into both `geometry.ts` and `outlet-lookup.ts`).
*/
// Wall thickness of the drop-tube collar — 3 mm matches typical
// residential gauge. After the CSG drill the stub becomes a tube with
// outer radius = bore + wall and inner radius = bore.
export const OUTLET_WALL_THICKNESS = 0.003
// Collar length — how far the drop-tube stub hangs below the trough
// floor. 6 cm reads as "drop outlet" without poking conspicuously far
// below the eave; the downspout slip-fits up into this collar.
export const OUTLET_STUB_LENGTH = 0.06
/**
* Z (outward) coordinate of the trough floor's midpoint per profile —
* where a drop outlet drills through. k-style bottom is `wBot = 0.8 ·
* size` wide so its midpoint sits at `0.4 · size`; box bottom is `size`
* wide → `size / 2`; half-round's lowest point is the centre of the
* semicircle at Z = r = size.
*/
export function profileFloorMidZ(profile: GutterNode['profile'], size: number): number {
if (profile === 'half-round') return size
if (profile === 'box') return size / 2
return size * 0.4
}
// ─── Outlet cross-section shape ──────────────────────────────────────
export type OutletShape = 'round' | 'rect'
/**
* Which cross-section a gutter's drop outlet (and the downspout that
* plugs into it) takes. Half-round gutters use a round leader; the
* flat-bottomed profiles (k-style, box) use a rectangular one — matching
* real residential hardware (round leaders on half-round, 2×3 / 3×4
* rectangular leaders on k-style / commercial box).
*/
export function outletShapeForProfile(profile: GutterNode['profile']): OutletShape {
return (profile ?? 'k-style') === 'half-round' ? 'round' : 'rect'
}
// Outward (Z) depth of a rectangular outlet as a fraction of its
// along-length (X) width — a 2×3 leader is ~0.66; 0.7 reads cleanly and
// still fits inside the k-style trough floor.
export const RECT_OUTLET_DEPTH_RATIO = 0.7
export type OutletDims = {
shape: OutletShape
/** Half-extent along the gutter length (X). Round: = radius. */
halfX: number
/** Half-extent outward (Z). Round: = radius. */
halfZ: number
}
/**
* Cross-section half-extents for a `nominalDiameter`-sized outlet of the
* given shape. Round → a circle of that diameter (halfX = halfZ =
* radius); rect → that diameter wide along the run, `RECT_OUTLET_DEPTH_
* RATIO` as deep outward.
*/
export function outletDims(shape: OutletShape, nominalDiameter: number): OutletDims {
const half = Math.max(0.01, nominalDiameter / 2)
if (shape === 'round') return { shape, halfX: half, halfZ: half }
return { shape, halfX: half, halfZ: half * RECT_OUTLET_DEPTH_RATIO }
}