{"version":3,"file":"interval2d-AtneyI45.mjs","names":["isInterval2d","make","fromCorners","Interval.fromMinMax","fromVectors","containsVector","Interval.contains","containsInterval2d","Interval.containsInterval","size","Vector2.make","union","Interval.union","equals","Interval.equals","minDistance","maxDistance","internal.isInterval2d","internal.make","internal.fromCorners","internal.fromVectors","internal.containsVector","internal.containsInterval2d","internal.size","internal.union","internal.equals","internal.minDistance","internal.maxDistance"],"sources":["../../src/interval/interval2d.internal.ts","../../src/interval/interval2d.ts"],"sourcesContent":["import { dual, invariant, Pipeable } from '../utils.ts'\nimport * as Vector2 from '../vector/vector2.ts'\nimport * as Interval from './interval.ts'\nimport type { Bounds2d, Interval2d } from './interval2d.ts'\n\nexport const Interval2dTypeId: unique symbol = Symbol('curvy/interval/interval2d')\nexport type Interval2dTypeId = typeof Interval2dTypeId\n\nclass Interval2dImpl<X extends Interval.Interval, Y extends Interval.Interval>\n  extends Pipeable\n  implements Interval2d<X, Y>\n{\n  readonly [Interval2dTypeId]: Interval2dTypeId = Interval2dTypeId\n\n  readonly x: X\n  readonly y: Y\n\n  constructor(x: X, y: Y) {\n    super()\n    this.x = x\n    this.y = y\n  }\n\n  get [Symbol.toStringTag]() {\n    return `Interval2d(${String(this.x)} × ${String(this.y)})`\n  }\n\n  get [Symbol.for('nodejs.util.inspect.custom')]() {\n    return this[Symbol.toStringTag]\n  }\n}\n\n/** @internal */\nexport const isInterval2d = (v: unknown): v is Interval2d =>\n  typeof v === 'object' && v !== null && Interval2dTypeId in v\n\n/** @internal */\nexport const make = <X extends Interval.Interval, Y extends Interval.Interval>(\n  x: X,\n  y: Y,\n): Interval2d<X, Y> => new Interval2dImpl(x, y)\n\n/** @internal */\nexport const fromCorners = (\n  p0: Vector2.Vector2,\n  p1: Vector2.Vector2,\n): Interval2d<Interval.Closed, Interval.Closed> =>\n  new Interval2dImpl(Interval.fromMinMax(p0.x, p1.x), Interval.fromMinMax(p0.y, p1.y))\n\n/** @internal */\nexport const fromVectors = (\n  ...points: ReadonlyArray<Vector2.Vector2>\n): Interval2d<Interval.Closed, Interval.Closed> => {\n  invariant(points.length > 0, 'fromVectors requires at least one point')\n  const xs: Array<number> = []\n  const ys: Array<number> = []\n  for (const p of points) {\n    xs.push(p.x)\n    ys.push(p.y)\n  }\n  return new Interval2dImpl(Interval.fromMinMax(...xs), Interval.fromMinMax(...ys))\n}\n\n/** @internal */\nexport const containsVector = dual<\n  (v: Vector2.Vector2) => (box: Interval2d) => boolean,\n  (box: Interval2d, v: Vector2.Vector2) => boolean\n>(\n  2,\n  (box: Interval2d, v: Vector2.Vector2): boolean =>\n    Interval.contains(box.x, v.x) && Interval.contains(box.y, v.y),\n)\n\n/** @internal */\nexport const containsInterval2d = dual<\n  (inner: Interval2d) => (outer: Interval2d) => boolean,\n  (outer: Interval2d, inner: Interval2d) => boolean\n>(\n  2,\n  (outer: Interval2d, inner: Interval2d): boolean =>\n    Interval.containsInterval(outer.x, inner.x) && Interval.containsInterval(outer.y, inner.y),\n)\n\n// Accepts the structural minimum because size doesn't read kind.\n/** @internal */\nexport const size = (box: Bounds2d): Vector2.Vector2 =>\n  Vector2.make(Math.abs(box.x.end - box.x.start), Math.abs(box.y.end - box.y.start))\n\n// Per-axis union — the runtime delegates to `Interval.union`, which is\n// kind-correct (the resulting endpoint openness reflects which input\n// contributed each side). The conditional return type collapses to the\n// shared kind when both inputs match on an axis and falls back to `Interval`\n// when they differ — at runtime the result genuinely could be any of the four\n// kinds depending on which endpoint wins.\n/** @internal */\nexport const union: {\n  <\n    AX extends Interval.Interval,\n    AY extends Interval.Interval,\n    BX extends Interval.Interval,\n    BY extends Interval.Interval,\n  >(\n    a: Interval2d<AX, AY>,\n    b: Interval2d<BX, BY>,\n  ): Interval2d<\n    AX extends BX ? (BX extends AX ? AX : Interval.Interval) : Interval.Interval,\n    AY extends BY ? (BY extends AY ? AY : Interval.Interval) : Interval.Interval\n  >\n  <BX extends Interval.Interval, BY extends Interval.Interval>(\n    b: Interval2d<BX, BY>,\n  ): <AX extends Interval.Interval, AY extends Interval.Interval>(\n    a: Interval2d<AX, AY>,\n  ) => Interval2d<\n    AX extends BX ? (BX extends AX ? AX : Interval.Interval) : Interval.Interval,\n    AY extends BY ? (BY extends AY ? AY : Interval.Interval) : Interval.Interval\n  >\n} = dual(\n  2,\n  (a: Interval2d, b: Interval2d) =>\n    new Interval2dImpl(Interval.union(a.x, b.x), Interval.union(a.y, b.y)),\n) as never\n\n/** @internal */\nexport const equals = dual<\n  (b: Interval2d) => (a: Interval2d) => boolean,\n  (a: Interval2d, b: Interval2d) => boolean\n>(\n  2,\n  (a: Interval2d, b: Interval2d): boolean => Interval.equals(a.x, b.x) && Interval.equals(a.y, b.y),\n)\n\n// For two axis-aligned 2D intervals the closest-pair and farthest-pair\n// distances decompose per-axis: the closest pair has the per-axis minimum\n// gap on each axis, the farthest pair has the per-axis maximum gap on each\n// axis. Combining via `hypot` gives the 2D distance because the per-axis\n// extrema are independently achievable at the corresponding box corners.\n//\n// Inputs are normalized with `min`/`max` so callers can pass `Bounds`-shaped\n// values whose `start`/`end` may not be ordered.\n\n/** @internal */\nexport const minDistance = dual<\n  (b: Bounds2d) => (a: Bounds2d) => number,\n  (a: Bounds2d, b: Bounds2d) => number\n>(2, (a: Bounds2d, b: Bounds2d): number => {\n  const aXLo = Math.min(a.x.start, a.x.end)\n  const aXHi = Math.max(a.x.start, a.x.end)\n  const aYLo = Math.min(a.y.start, a.y.end)\n  const aYHi = Math.max(a.y.start, a.y.end)\n  const bXLo = Math.min(b.x.start, b.x.end)\n  const bXHi = Math.max(b.x.start, b.x.end)\n  const bYLo = Math.min(b.y.start, b.y.end)\n  const bYHi = Math.max(b.y.start, b.y.end)\n  const dx = Math.max(0, Math.max(aXLo, bXLo) - Math.min(aXHi, bXHi))\n  const dy = Math.max(0, Math.max(aYLo, bYLo) - Math.min(aYHi, bYHi))\n  return Math.hypot(dx, dy)\n})\n\n/** @internal */\nexport const maxDistance = dual<\n  (b: Bounds2d) => (a: Bounds2d) => number,\n  (a: Bounds2d, b: Bounds2d) => number\n>(2, (a: Bounds2d, b: Bounds2d): number => {\n  const aXLo = Math.min(a.x.start, a.x.end)\n  const aXHi = Math.max(a.x.start, a.x.end)\n  const aYLo = Math.min(a.y.start, a.y.end)\n  const aYHi = Math.max(a.y.start, a.y.end)\n  const bXLo = Math.min(b.x.start, b.x.end)\n  const bXHi = Math.max(b.x.start, b.x.end)\n  const bYLo = Math.min(b.y.start, b.y.end)\n  const bYHi = Math.max(b.y.start, b.y.end)\n  const dx = Math.max(aXHi, bXHi) - Math.min(aXLo, bXLo)\n  const dy = Math.max(aYHi, bYHi) - Math.min(aYLo, bYLo)\n  return Math.hypot(dx, dy)\n})\n","import type { Pipeable } from '../utils.ts'\nimport type { Vector2 } from '../vector/vector2.ts'\nimport type { Bounds, Closed, Interval } from './interval.ts'\nimport type { Interval2dTypeId } from './interval2d.internal.ts'\nimport * as internal from './interval2d.internal.ts'\n\n/**\n * An axis-aligned 2D interval — the Cartesian product of two 1D intervals.\n * Used as a bounding box for curves and paths, and as a region for\n * containment tests.\n *\n * The two type parameters carry the per-axis interval subtype so that a value\n * built from closed intervals stays `Interval2d<Closed, Closed>` and a value\n * with mixed openness preserves that information at the type level.\n *\n * All fields are readonly and immutable, and all operations create new instances.\n *\n * @since 2.0.0\n */\nexport interface Interval2d<\n  X extends Interval = Interval,\n  Y extends Interval = Interval,\n> extends Pipeable {\n  readonly [Interval2dTypeId]: Interval2dTypeId\n  readonly x: X\n  readonly y: Y\n}\n\n/**\n * The structural minimum: any value with `x` and `y` fields shaped like\n * {@link Bounds}. Operations that don't read endpoint inclusivity (e.g.\n * {@link size}) accept `Bounds2d` so the signature itself documents what the\n * operation depends on. Mirrors the {@link Bounds}/{@link Interval} split in 1D.\n *\n * @since 2.0.0\n */\nexport interface Bounds2d {\n  readonly x: Bounds\n  readonly y: Bounds\n}\n\n/**\n * Checks if a value is an `Interval2d`.\n *\n * @param v - The value to check.\n * @returns `true` if the value is an `Interval2d`, `false` otherwise.\n * @since 2.0.0\n */\nexport const isInterval2d: (v: unknown) => v is Interval2d = internal.isInterval2d\n\n/**\n * Creates a new `Interval2d` from two intervals — one for the x axis, one\n * for the y axis. Preserves both interval subtypes at the type level.\n *\n * @param x - The x-axis interval.\n * @param y - The y-axis interval.\n * @returns A new `Interval2d` instance.\n * @since 2.0.0\n */\nexport const make: <X extends Interval, Y extends Interval>(x: X, y: Y) => Interval2d<X, Y> =\n  internal.make\n\n/**\n * Creates a closed `Interval2d` from two corner points. The corners can be in\n * any order — each axis is built from the min and max of the coordinate.\n *\n * @param p0 - The first corner.\n * @param p1 - The second corner.\n * @returns A new `Interval2d<Closed, Closed>` enclosing both corners.\n * @since 2.0.0\n */\nexport const fromCorners: (p0: Vector2, p1: Vector2) => Interval2d<Closed, Closed> =\n  internal.fromCorners\n\n/**\n * Creates the smallest closed `Interval2d` enclosing the given points. Useful\n * for computing a bounding box from sampled points.\n *\n * @param points - One or more points to enclose.\n * @returns A new `Interval2d<Closed, Closed>` enclosing all input points.\n * @throws When called with zero points.\n * @since 2.0.0\n */\nexport const fromVectors: (...points: ReadonlyArray<Vector2>) => Interval2d<Closed, Closed> =\n  internal.fromVectors\n\nexport const containsVector: {\n  /**\n   * Checks if a vector lies within the 2D interval. Per-axis endpoint\n   * inclusivity follows each axis interval's `kind`.\n   *\n   * @param box - The 2D interval to test against.\n   * @param v - The vector to test.\n   * @returns `true` when the vector lies within the box on both axes.\n   * @since 2.0.0\n   */\n  (box: Interval2d, v: Vector2): boolean\n  /**\n   * @param v - The vector to test.\n   * @returns A function that takes a 2D interval and returns the containment result.\n   * @since 2.0.0\n   */\n  (v: Vector2): (box: Interval2d) => boolean\n} = internal.containsVector\n\nexport const containsInterval2d: {\n  /**\n   * Checks if `inner` is a subset of `outer`. The check is per-axis interval\n   * containment — for each axis, every point of the inner interval must also\n   * be in the outer interval, respecting endpoint inclusivity on both sides.\n   *\n   * @param outer - The enclosing 2D interval.\n   * @param inner - The candidate inner 2D interval.\n   * @returns `true` when every point of `inner` is also in `outer`.\n   * @since 2.0.0\n   */\n  (outer: Interval2d, inner: Interval2d): boolean\n  /**\n   * @param inner - The candidate inner 2D interval.\n   * @returns A function that takes the outer 2D interval and returns the containment result.\n   * @since 2.0.0\n   */\n  (inner: Interval2d): (outer: Interval2d) => boolean\n} = internal.containsInterval2d\n\n/**\n * Returns the size as a vector `(width, height)`. Accepts the broader\n * {@link Bounds2d} type because size does not depend on endpoint inclusivity.\n *\n * @param box - The 2D interval (or bounds-shaped value) to measure.\n * @returns The size as a `Vector2`.\n * @since 2.0.0\n */\nexport const size: (box: Bounds2d) => Vector2 = internal.size\n\nexport const union: {\n  /**\n   * Returns the smallest 2D interval enclosing both inputs.\n   *\n   * The per-axis return kind is determined by which input's endpoint wins on\n   * each side, with the contributor's openness preserved (or unioned to\n   * \"closed\" when endpoints are numerically equal and either is closed at\n   * that point).\n   *\n   * When both inputs share the same kind on an axis, the result collapses\n   * back to that kind. Otherwise the axis falls back to the open\n   * {@link Interval} type since the runtime kind depends on the values.\n   *\n   * @param a - The first 2D interval.\n   * @param b - The second 2D interval.\n   * @returns A new `Interval2d` enclosing both inputs.\n   * @since 2.0.0\n   */\n  <AX extends Interval, AY extends Interval, BX extends Interval, BY extends Interval>(\n    a: Interval2d<AX, AY>,\n    b: Interval2d<BX, BY>,\n  ): Interval2d<\n    AX extends BX ? (BX extends AX ? AX : Interval) : Interval,\n    AY extends BY ? (BY extends AY ? AY : Interval) : Interval\n  >\n  /**\n   * @param b - The second 2D interval.\n   * @returns A function that takes the first 2D interval and returns the union.\n   * @since 2.0.0\n   */\n  <BX extends Interval, BY extends Interval>(\n    b: Interval2d<BX, BY>,\n  ): <AX extends Interval, AY extends Interval>(\n    a: Interval2d<AX, AY>,\n  ) => Interval2d<\n    AX extends BX ? (BX extends AX ? AX : Interval) : Interval,\n    AY extends BY ? (BY extends AY ? AY : Interval) : Interval\n  >\n} = internal.union\n\nexport const equals: {\n  /**\n   * Checks if two `Interval2d` values are approximately equal within the\n   * default absolute tolerance ({@link EPSILON}). Both the numeric endpoints\n   * AND the per-axis kinds must match.\n   *\n   * @param a - The first 2D interval.\n   * @param b - The second 2D interval.\n   * @returns `true` when both axes are equal.\n   * @since 2.0.0\n   */\n  (a: Interval2d, b: Interval2d): boolean\n  /**\n   * @param b - The second 2D interval.\n   * @returns A function that takes the first 2D interval and returns the comparison result.\n   * @since 2.0.0\n   */\n  (b: Interval2d): (a: Interval2d) => boolean\n} = internal.equals\n\nexport const minDistance: {\n  /**\n   * Euclidean distance between the two closest points of two axis-aligned 2D\n   * intervals. Returns `0` when the boxes overlap (including edge or corner\n   * touching). Accepts the broader {@link Bounds2d} type — endpoint\n   * inclusivity is not consulted, so a \"touching\" pair of open intervals still\n   * returns `0` because the closest *points* coincide geometrically.\n   *\n   * @param a - The first 2D interval.\n   * @param b - The second 2D interval.\n   * @returns The minimum Euclidean distance between any point of `a` and any point of `b`.\n   * @since 2.0.0\n   */\n  (a: Bounds2d, b: Bounds2d): number\n  /**\n   * @param b - The second 2D interval.\n   * @returns A function that takes the first 2D interval and returns the minimum distance.\n   * @since 2.0.0\n   */\n  (b: Bounds2d): (a: Bounds2d) => number\n} = internal.minDistance\n\nexport const maxDistance: {\n  /**\n   * Euclidean distance between the two farthest points of two axis-aligned 2D\n   * intervals. Equals the diagonal of the union AABB enclosing both inputs.\n   * Accepts the broader {@link Bounds2d} type — endpoint inclusivity is not\n   * consulted.\n   *\n   * @param a - The first 2D interval.\n   * @param b - The second 2D interval.\n   * @returns The maximum Euclidean distance between any point of `a` and any point of `b`.\n   * @since 2.0.0\n   */\n  (a: Bounds2d, b: Bounds2d): number\n  /**\n   * @param b - The second 2D interval.\n   * @returns A function that takes the first 2D interval and returns the maximum distance.\n   * @since 2.0.0\n   */\n  (b: Bounds2d): (a: Bounds2d) => number\n} = internal.maxDistance\n"],"mappings":"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"}