modern-path2d 1.5.6 → 1.6.1

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.
package/dist/index.d.cts CHANGED
@@ -308,6 +308,45 @@ interface NonzeroFillRuleResult {
308
308
  }
309
309
  declare function nonzeroFillRule(paths: number[][]): NonzeroFillRuleResult[];
310
310
 
311
+ /**
312
+ * Test whether a point lies inside a single polygon ring.
313
+ *
314
+ * `vertices` is a flat `[x0, y0, x1, y1, ...]` array and is treated as implicitly closed
315
+ * (the last vertex connects back to the first). A ring with fewer than 3 points has no
316
+ * area and always returns `false`.
317
+ *
318
+ * @param point The point to test.
319
+ * @param vertices Flat vertex array of the ring.
320
+ * @param fillRule `'nonzero'` (default, matches SVG/Canvas) or `'evenodd'`.
321
+ */
322
+ declare function pointInPolygon(point: Vector2Like, vertices: number[], fillRule?: FillRule): boolean;
323
+ /**
324
+ * Test whether a point lies inside a shape composed of multiple rings (sub-paths).
325
+ *
326
+ * This is the multi-ring counterpart of {@link pointInPolygon} and is what donut /
327
+ * hollow shapes need: every ring is evaluated together so holes are honored.
328
+ * - `'nonzero'`: sum the signed winding numbers of all rings, inside if the total ≠ 0.
329
+ * - `'evenodd'`: sum the ray-crossing counts of all rings, inside if the total is odd.
330
+ *
331
+ * @param point The point to test.
332
+ * @param polygons Array of flat vertex arrays, one per ring.
333
+ * @param fillRule `'nonzero'` (default) or `'evenodd'`.
334
+ */
335
+ declare function pointInPolygons(point: Vector2Like, polygons: number[][], fillRule?: FillRule): boolean;
336
+ /**
337
+ * Shortest distance from a point to a single line segment a→b.
338
+ */
339
+ declare function pointToSegmentDistance(point: Vector2Like, a: Vector2Like, b: Vector2Like): number;
340
+ /**
341
+ * Shortest distance from a point to a polyline.
342
+ *
343
+ * @param point The point to test.
344
+ * @param vertices Flat `[x0, y0, x1, y1, ...]` array of the polyline.
345
+ * @param closed When `true`, also considers the closing edge from the last vertex back
346
+ * to the first (use for closed paths, e.g. `z`/`Z` or `CurvePath.autoClose`).
347
+ */
348
+ declare function pointToPolylineDistance(point: Vector2Like, vertices: number[], closed?: boolean): number;
349
+
311
350
  declare function quadraticBezier(t: number, p0: number, p1: number, p2: number): number;
312
351
 
313
352
  type LineCap = 'butt' | 'round' | 'square';
@@ -333,6 +372,14 @@ interface LineStyle {
333
372
  }
334
373
  declare function strokeTriangulate(points: number[], options?: StrokeTriangulateOptions): StrokeTriangulatedResult;
335
374
 
375
+ interface IsPointInFillOptions {
376
+ fillRule?: FillRule;
377
+ }
378
+ interface IsPointInStrokeOptions {
379
+ strokeWidth?: number;
380
+ tolerance?: number;
381
+ closed?: boolean;
382
+ }
336
383
  declare abstract class Curve {
337
384
  arcLengthDivision: number;
338
385
  protected _lengths: number[];
@@ -363,6 +410,32 @@ declare abstract class Curve {
363
410
  max: Vector2;
364
411
  };
365
412
  getBoundingBox(): BoundingBox;
413
+ /**
414
+ * Test whether a point lies inside the area enclosed by this curve.
415
+ *
416
+ * The curve is sampled via {@link getAdaptiveVertices} into a single implicitly closed
417
+ * ring. This is purely geometric (it ignores any `fill`/`stroke` style), mirroring
418
+ * `CanvasRenderingContext2D.isPointInPath`.
419
+ *
420
+ * Composites that hold multiple sub-paths (e.g. {@link Path2D}) override this so holes
421
+ * are honored — a single `Curve` is always one ring.
422
+ */
423
+ isPointInFill(point: Vector2Like, options?: IsPointInFillOptions): boolean;
424
+ /**
425
+ * Test whether a point lies on this curve's stroke, i.e. within `strokeWidth / 2 + tolerance`
426
+ * of the sampled outline. The point must be in the same coordinate space as the curve.
427
+ *
428
+ * Options: `strokeWidth` (path units, default `1`), `tolerance` (extra hit slack in path
429
+ * units, default `0` — useful for thin strokes; no coordinate scaling is assumed, so convert
430
+ * pixel tolerance to path units upstream if your path is normalized), and `closed` (whether
431
+ * to include the closing edge from the last vertex back to the first).
432
+ */
433
+ isPointInStroke(point: Vector2Like, options?: IsPointInStrokeOptions): boolean;
434
+ /**
435
+ * Concise PathKit-style fill containment test: `contains(x, y)` is shorthand for
436
+ * {@link isPointInFill} with a `{ x, y }` point.
437
+ */
438
+ contains(x: number, y: number, options?: IsPointInFillOptions): boolean;
366
439
  getFillVertices(_options?: FillTriangulateOptions): number[];
367
440
  fillTriangulate(options?: FillTriangulateOptions): FillTriangulatedResult;
368
441
  strokeTriangulate(options?: StrokeTriangulateOptions): StrokeTriangulatedResult;
@@ -483,17 +556,17 @@ declare class LineCurve extends Curve {
483
556
  copyFrom(source: LineCurve): this;
484
557
  }
485
558
 
486
- declare class PloygonCurve extends CompositeCurve<LineCurve> {
559
+ declare class PolygonCurve extends CompositeCurve<LineCurve> {
487
560
  }
488
561
 
489
- declare class EquilateralPloygonCurve extends PloygonCurve {
562
+ declare class EquilateralPolygonCurve extends PolygonCurve {
490
563
  cx: number;
491
564
  cy: number;
492
565
  radius: number;
493
566
  sideCount: number;
494
567
  constructor(cx?: number, cy?: number, radius?: number, sideCount?: number);
495
568
  update(): this;
496
- copyFrom(source: EquilateralPloygonCurve): this;
569
+ copyFrom(source: EquilateralPolygonCurve): this;
497
570
  }
498
571
 
499
572
  declare class QuadraticBezierCurve extends Curve {
@@ -514,7 +587,7 @@ declare class QuadraticBezierCurve extends Curve {
514
587
  copyFrom(source: QuadraticBezierCurve): this;
515
588
  }
516
589
 
517
- declare class RectangleCurve extends PloygonCurve {
590
+ declare class RectangleCurve extends PolygonCurve {
518
591
  x: number;
519
592
  y: number;
520
593
  width: number;
@@ -559,6 +632,11 @@ declare class CurvePath extends CompositeCurve {
559
632
  getSpacedVertices(count?: number, output?: number[]): number[];
560
633
  getAdaptiveVertices(output?: number[]): number[];
561
634
  getFillVertices(options?: FillTriangulateOptions): number[];
635
+ /**
636
+ * Same as {@link Curve.isPointInStroke}, but `closed` defaults to this sub-path's actual
637
+ * closed-ness: explicitly `autoClose`, or geometrically closed (first vertex === last).
638
+ */
639
+ isPointInStroke(point: Vector2Like, options?: IsPointInStrokeOptions): boolean;
562
640
  protected _setCurrentPoint(point: Vector2Like): this;
563
641
  protected _connetLineTo(curve: Curve): this;
564
642
  closePath(): this;
@@ -617,6 +695,25 @@ declare class Path2D<T = any> extends CompositeCurve<CurvePath> {
617
695
  skew(ax: number, ay?: number, target?: Vector2Like): this;
618
696
  rotate(rad: number, target?: Vector2Like): this;
619
697
  bold(b: number): this;
698
+ /**
699
+ * Test whether a point lies inside the filled area of this path.
700
+ *
701
+ * Each sub-path ({@link CurvePath}) is sampled into its own ring and all rings are
702
+ * evaluated together via {@link pointInPolygons}, so holes (donut / hollow shapes) are
703
+ * honored. This is purely geometric and ignores `style.fill` — for the `fill: 'none'`
704
+ * fallback, gate the call upstream (see {@link Path2DSet.hitTest}).
705
+ *
706
+ * Defaults `fillRule` to `style.fillRule`, then `'nonzero'` (matching SVG/Canvas).
707
+ */
708
+ isPointInFill(point: Vector2Like, options?: IsPointInFillOptions): boolean;
709
+ /**
710
+ * Test whether a point lies on this path's stroke. A hit on any sub-path counts.
711
+ *
712
+ * Defaults `strokeWidth` to this path's own {@link strokeWidth} (which is `0` when
713
+ * `style.stroke` is `'none'`). Each sub-path infers its own closed-ness unless `closed`
714
+ * is given explicitly.
715
+ */
716
+ isPointInStroke(point: Vector2Like, options?: IsPointInStrokeOptions): boolean;
620
717
  getMinMax(min?: Vector2, max?: Vector2, withStyle?: boolean): {
621
718
  min: Vector2;
622
719
  max: Vector2;
@@ -641,6 +738,36 @@ declare class Path2DSet<T = any> {
641
738
  paths: Path2D<T>[];
642
739
  viewBox?: number[] | undefined;
643
740
  constructor(paths?: Path2D<T>[], viewBox?: number[] | undefined);
741
+ /**
742
+ * Test whether a point lies inside the filled area of any path in this set.
743
+ * Purely geometric (ignores `fill: 'none'`); use {@link hitTest} for style-aware hits.
744
+ */
745
+ isPointInFill(point: Vector2Like, options?: {
746
+ fillRule?: FillRule;
747
+ }): boolean;
748
+ /**
749
+ * Concise PathKit-style fill containment test across the whole set; shorthand for
750
+ * {@link isPointInFill} with a `{ x, y }` point.
751
+ */
752
+ contains(x: number, y: number, options?: {
753
+ fillRule?: FillRule;
754
+ }): boolean;
755
+ /**
756
+ * Find the topmost path hit by a point, or `undefined` if none.
757
+ *
758
+ * Paths are tested top-to-bottom (last drawn first). For each path a fill hit is checked
759
+ * first (skipped when `style.fill` is `'none'`), then — if `stroke` is enabled — a stroke
760
+ * hit (skipped when `style.stroke` is `'none'`). This honors the "fill: none falls back to
761
+ * stroke" rule; the coordinate space of `point` must match the paths (no scaling assumed).
762
+ *
763
+ * Options: `stroke` (also test strokes, default `true`), `tolerance` (extra stroke hit slack
764
+ * in path units, default `0`), and `fillRule` (overrides each path's own fill rule).
765
+ */
766
+ hitTest(point: Vector2Like, options?: {
767
+ stroke?: boolean;
768
+ tolerance?: number;
769
+ fillRule?: FillRule;
770
+ }): Path2D<T> | undefined;
644
771
  getBoundingBox(withStyle?: boolean): BoundingBox | undefined;
645
772
  toTriangulatedSvgString(result?: TriangulatedResult | TriangulatedResult[], padding?: number): string;
646
773
  toTriangulatedSvg(result?: TriangulatedResult | TriangulatedResult[], padding?: number): SVGElement;
@@ -694,5 +821,5 @@ declare function svgToDom(svg: string | SVGElement): SVGElement;
694
821
 
695
822
  declare function svgToPath2DSet(svg: string | SVGElement): Path2DSet;
696
823
 
697
- export { ArcCurve, BoundingBox, CompositeCurve, CubicBezierCurve, Curve, CurvePath, EllipseCurve, EquilateralPloygonCurve, FFDControlGrid, LineCurve, PI, PI_2, Path2D, Path2DSet, PloygonCurve, QuadraticBezierCurve, RectangleCurve, RoundRectangleCurve, SplineCurve, Transform2D, Vector2, applyFFD, catmullRom, cubicBezier, drawPoint, fillTriangulate, getAdaptiveCubicBezierCurvePoints, getAdaptiveQuadraticBezierCurvePoints, getDirectedArea, getIntersectionPoint, nonzeroFillRule, parseArcCommand, parseCssArg, parseCssArgs, parseCssFunctions, parsePathDataArgs, quadraticBezier, setCanvasContext, strokeTriangulate, svgPathCommandsAddToPath2D, svgPathCommandsToData, svgPathDataToCommands, svgToDom, svgToPath2DSet, toKebabCase };
698
- export type { CssFunction, CssFunctionArg, DrawPointOptions, FillRule, FillTriangulateOptions, FillTriangulatedResult, LineCap, LineJoin, LineStyle, ParseCssFunctionContext, Path2DCommand, Path2DData, Path2DDrawStyle, Path2DStyle, StrokeLinecap, StrokeLinejoin, StrokeTriangulateOptions, StrokeTriangulatedResult, TransformableObject, TriangulatedResult, Vector2Like };
824
+ export { ArcCurve, BoundingBox, CompositeCurve, CubicBezierCurve, Curve, CurvePath, EllipseCurve, EquilateralPolygonCurve, FFDControlGrid, LineCurve, PI, PI_2, Path2D, Path2DSet, PolygonCurve, QuadraticBezierCurve, RectangleCurve, RoundRectangleCurve, SplineCurve, Transform2D, Vector2, applyFFD, catmullRom, cubicBezier, drawPoint, fillTriangulate, getAdaptiveCubicBezierCurvePoints, getAdaptiveQuadraticBezierCurvePoints, getDirectedArea, getIntersectionPoint, nonzeroFillRule, parseArcCommand, parseCssArg, parseCssArgs, parseCssFunctions, parsePathDataArgs, pointInPolygon, pointInPolygons, pointToPolylineDistance, pointToSegmentDistance, quadraticBezier, setCanvasContext, strokeTriangulate, svgPathCommandsAddToPath2D, svgPathCommandsToData, svgPathDataToCommands, svgToDom, svgToPath2DSet, toKebabCase };
825
+ export type { CssFunction, CssFunctionArg, DrawPointOptions, FillRule, FillTriangulateOptions, FillTriangulatedResult, IsPointInFillOptions, IsPointInStrokeOptions, LineCap, LineJoin, LineStyle, ParseCssFunctionContext, Path2DCommand, Path2DData, Path2DDrawStyle, Path2DStyle, StrokeLinecap, StrokeLinejoin, StrokeTriangulateOptions, StrokeTriangulatedResult, TransformableObject, TriangulatedResult, Vector2Like };
package/dist/index.d.mts CHANGED
@@ -308,6 +308,45 @@ interface NonzeroFillRuleResult {
308
308
  }
309
309
  declare function nonzeroFillRule(paths: number[][]): NonzeroFillRuleResult[];
310
310
 
311
+ /**
312
+ * Test whether a point lies inside a single polygon ring.
313
+ *
314
+ * `vertices` is a flat `[x0, y0, x1, y1, ...]` array and is treated as implicitly closed
315
+ * (the last vertex connects back to the first). A ring with fewer than 3 points has no
316
+ * area and always returns `false`.
317
+ *
318
+ * @param point The point to test.
319
+ * @param vertices Flat vertex array of the ring.
320
+ * @param fillRule `'nonzero'` (default, matches SVG/Canvas) or `'evenodd'`.
321
+ */
322
+ declare function pointInPolygon(point: Vector2Like, vertices: number[], fillRule?: FillRule): boolean;
323
+ /**
324
+ * Test whether a point lies inside a shape composed of multiple rings (sub-paths).
325
+ *
326
+ * This is the multi-ring counterpart of {@link pointInPolygon} and is what donut /
327
+ * hollow shapes need: every ring is evaluated together so holes are honored.
328
+ * - `'nonzero'`: sum the signed winding numbers of all rings, inside if the total ≠ 0.
329
+ * - `'evenodd'`: sum the ray-crossing counts of all rings, inside if the total is odd.
330
+ *
331
+ * @param point The point to test.
332
+ * @param polygons Array of flat vertex arrays, one per ring.
333
+ * @param fillRule `'nonzero'` (default) or `'evenodd'`.
334
+ */
335
+ declare function pointInPolygons(point: Vector2Like, polygons: number[][], fillRule?: FillRule): boolean;
336
+ /**
337
+ * Shortest distance from a point to a single line segment a→b.
338
+ */
339
+ declare function pointToSegmentDistance(point: Vector2Like, a: Vector2Like, b: Vector2Like): number;
340
+ /**
341
+ * Shortest distance from a point to a polyline.
342
+ *
343
+ * @param point The point to test.
344
+ * @param vertices Flat `[x0, y0, x1, y1, ...]` array of the polyline.
345
+ * @param closed When `true`, also considers the closing edge from the last vertex back
346
+ * to the first (use for closed paths, e.g. `z`/`Z` or `CurvePath.autoClose`).
347
+ */
348
+ declare function pointToPolylineDistance(point: Vector2Like, vertices: number[], closed?: boolean): number;
349
+
311
350
  declare function quadraticBezier(t: number, p0: number, p1: number, p2: number): number;
312
351
 
313
352
  type LineCap = 'butt' | 'round' | 'square';
@@ -333,6 +372,14 @@ interface LineStyle {
333
372
  }
334
373
  declare function strokeTriangulate(points: number[], options?: StrokeTriangulateOptions): StrokeTriangulatedResult;
335
374
 
375
+ interface IsPointInFillOptions {
376
+ fillRule?: FillRule;
377
+ }
378
+ interface IsPointInStrokeOptions {
379
+ strokeWidth?: number;
380
+ tolerance?: number;
381
+ closed?: boolean;
382
+ }
336
383
  declare abstract class Curve {
337
384
  arcLengthDivision: number;
338
385
  protected _lengths: number[];
@@ -363,6 +410,32 @@ declare abstract class Curve {
363
410
  max: Vector2;
364
411
  };
365
412
  getBoundingBox(): BoundingBox;
413
+ /**
414
+ * Test whether a point lies inside the area enclosed by this curve.
415
+ *
416
+ * The curve is sampled via {@link getAdaptiveVertices} into a single implicitly closed
417
+ * ring. This is purely geometric (it ignores any `fill`/`stroke` style), mirroring
418
+ * `CanvasRenderingContext2D.isPointInPath`.
419
+ *
420
+ * Composites that hold multiple sub-paths (e.g. {@link Path2D}) override this so holes
421
+ * are honored — a single `Curve` is always one ring.
422
+ */
423
+ isPointInFill(point: Vector2Like, options?: IsPointInFillOptions): boolean;
424
+ /**
425
+ * Test whether a point lies on this curve's stroke, i.e. within `strokeWidth / 2 + tolerance`
426
+ * of the sampled outline. The point must be in the same coordinate space as the curve.
427
+ *
428
+ * Options: `strokeWidth` (path units, default `1`), `tolerance` (extra hit slack in path
429
+ * units, default `0` — useful for thin strokes; no coordinate scaling is assumed, so convert
430
+ * pixel tolerance to path units upstream if your path is normalized), and `closed` (whether
431
+ * to include the closing edge from the last vertex back to the first).
432
+ */
433
+ isPointInStroke(point: Vector2Like, options?: IsPointInStrokeOptions): boolean;
434
+ /**
435
+ * Concise PathKit-style fill containment test: `contains(x, y)` is shorthand for
436
+ * {@link isPointInFill} with a `{ x, y }` point.
437
+ */
438
+ contains(x: number, y: number, options?: IsPointInFillOptions): boolean;
366
439
  getFillVertices(_options?: FillTriangulateOptions): number[];
367
440
  fillTriangulate(options?: FillTriangulateOptions): FillTriangulatedResult;
368
441
  strokeTriangulate(options?: StrokeTriangulateOptions): StrokeTriangulatedResult;
@@ -483,17 +556,17 @@ declare class LineCurve extends Curve {
483
556
  copyFrom(source: LineCurve): this;
484
557
  }
485
558
 
486
- declare class PloygonCurve extends CompositeCurve<LineCurve> {
559
+ declare class PolygonCurve extends CompositeCurve<LineCurve> {
487
560
  }
488
561
 
489
- declare class EquilateralPloygonCurve extends PloygonCurve {
562
+ declare class EquilateralPolygonCurve extends PolygonCurve {
490
563
  cx: number;
491
564
  cy: number;
492
565
  radius: number;
493
566
  sideCount: number;
494
567
  constructor(cx?: number, cy?: number, radius?: number, sideCount?: number);
495
568
  update(): this;
496
- copyFrom(source: EquilateralPloygonCurve): this;
569
+ copyFrom(source: EquilateralPolygonCurve): this;
497
570
  }
498
571
 
499
572
  declare class QuadraticBezierCurve extends Curve {
@@ -514,7 +587,7 @@ declare class QuadraticBezierCurve extends Curve {
514
587
  copyFrom(source: QuadraticBezierCurve): this;
515
588
  }
516
589
 
517
- declare class RectangleCurve extends PloygonCurve {
590
+ declare class RectangleCurve extends PolygonCurve {
518
591
  x: number;
519
592
  y: number;
520
593
  width: number;
@@ -559,6 +632,11 @@ declare class CurvePath extends CompositeCurve {
559
632
  getSpacedVertices(count?: number, output?: number[]): number[];
560
633
  getAdaptiveVertices(output?: number[]): number[];
561
634
  getFillVertices(options?: FillTriangulateOptions): number[];
635
+ /**
636
+ * Same as {@link Curve.isPointInStroke}, but `closed` defaults to this sub-path's actual
637
+ * closed-ness: explicitly `autoClose`, or geometrically closed (first vertex === last).
638
+ */
639
+ isPointInStroke(point: Vector2Like, options?: IsPointInStrokeOptions): boolean;
562
640
  protected _setCurrentPoint(point: Vector2Like): this;
563
641
  protected _connetLineTo(curve: Curve): this;
564
642
  closePath(): this;
@@ -617,6 +695,25 @@ declare class Path2D<T = any> extends CompositeCurve<CurvePath> {
617
695
  skew(ax: number, ay?: number, target?: Vector2Like): this;
618
696
  rotate(rad: number, target?: Vector2Like): this;
619
697
  bold(b: number): this;
698
+ /**
699
+ * Test whether a point lies inside the filled area of this path.
700
+ *
701
+ * Each sub-path ({@link CurvePath}) is sampled into its own ring and all rings are
702
+ * evaluated together via {@link pointInPolygons}, so holes (donut / hollow shapes) are
703
+ * honored. This is purely geometric and ignores `style.fill` — for the `fill: 'none'`
704
+ * fallback, gate the call upstream (see {@link Path2DSet.hitTest}).
705
+ *
706
+ * Defaults `fillRule` to `style.fillRule`, then `'nonzero'` (matching SVG/Canvas).
707
+ */
708
+ isPointInFill(point: Vector2Like, options?: IsPointInFillOptions): boolean;
709
+ /**
710
+ * Test whether a point lies on this path's stroke. A hit on any sub-path counts.
711
+ *
712
+ * Defaults `strokeWidth` to this path's own {@link strokeWidth} (which is `0` when
713
+ * `style.stroke` is `'none'`). Each sub-path infers its own closed-ness unless `closed`
714
+ * is given explicitly.
715
+ */
716
+ isPointInStroke(point: Vector2Like, options?: IsPointInStrokeOptions): boolean;
620
717
  getMinMax(min?: Vector2, max?: Vector2, withStyle?: boolean): {
621
718
  min: Vector2;
622
719
  max: Vector2;
@@ -641,6 +738,36 @@ declare class Path2DSet<T = any> {
641
738
  paths: Path2D<T>[];
642
739
  viewBox?: number[] | undefined;
643
740
  constructor(paths?: Path2D<T>[], viewBox?: number[] | undefined);
741
+ /**
742
+ * Test whether a point lies inside the filled area of any path in this set.
743
+ * Purely geometric (ignores `fill: 'none'`); use {@link hitTest} for style-aware hits.
744
+ */
745
+ isPointInFill(point: Vector2Like, options?: {
746
+ fillRule?: FillRule;
747
+ }): boolean;
748
+ /**
749
+ * Concise PathKit-style fill containment test across the whole set; shorthand for
750
+ * {@link isPointInFill} with a `{ x, y }` point.
751
+ */
752
+ contains(x: number, y: number, options?: {
753
+ fillRule?: FillRule;
754
+ }): boolean;
755
+ /**
756
+ * Find the topmost path hit by a point, or `undefined` if none.
757
+ *
758
+ * Paths are tested top-to-bottom (last drawn first). For each path a fill hit is checked
759
+ * first (skipped when `style.fill` is `'none'`), then — if `stroke` is enabled — a stroke
760
+ * hit (skipped when `style.stroke` is `'none'`). This honors the "fill: none falls back to
761
+ * stroke" rule; the coordinate space of `point` must match the paths (no scaling assumed).
762
+ *
763
+ * Options: `stroke` (also test strokes, default `true`), `tolerance` (extra stroke hit slack
764
+ * in path units, default `0`), and `fillRule` (overrides each path's own fill rule).
765
+ */
766
+ hitTest(point: Vector2Like, options?: {
767
+ stroke?: boolean;
768
+ tolerance?: number;
769
+ fillRule?: FillRule;
770
+ }): Path2D<T> | undefined;
644
771
  getBoundingBox(withStyle?: boolean): BoundingBox | undefined;
645
772
  toTriangulatedSvgString(result?: TriangulatedResult | TriangulatedResult[], padding?: number): string;
646
773
  toTriangulatedSvg(result?: TriangulatedResult | TriangulatedResult[], padding?: number): SVGElement;
@@ -694,5 +821,5 @@ declare function svgToDom(svg: string | SVGElement): SVGElement;
694
821
 
695
822
  declare function svgToPath2DSet(svg: string | SVGElement): Path2DSet;
696
823
 
697
- export { ArcCurve, BoundingBox, CompositeCurve, CubicBezierCurve, Curve, CurvePath, EllipseCurve, EquilateralPloygonCurve, FFDControlGrid, LineCurve, PI, PI_2, Path2D, Path2DSet, PloygonCurve, QuadraticBezierCurve, RectangleCurve, RoundRectangleCurve, SplineCurve, Transform2D, Vector2, applyFFD, catmullRom, cubicBezier, drawPoint, fillTriangulate, getAdaptiveCubicBezierCurvePoints, getAdaptiveQuadraticBezierCurvePoints, getDirectedArea, getIntersectionPoint, nonzeroFillRule, parseArcCommand, parseCssArg, parseCssArgs, parseCssFunctions, parsePathDataArgs, quadraticBezier, setCanvasContext, strokeTriangulate, svgPathCommandsAddToPath2D, svgPathCommandsToData, svgPathDataToCommands, svgToDom, svgToPath2DSet, toKebabCase };
698
- export type { CssFunction, CssFunctionArg, DrawPointOptions, FillRule, FillTriangulateOptions, FillTriangulatedResult, LineCap, LineJoin, LineStyle, ParseCssFunctionContext, Path2DCommand, Path2DData, Path2DDrawStyle, Path2DStyle, StrokeLinecap, StrokeLinejoin, StrokeTriangulateOptions, StrokeTriangulatedResult, TransformableObject, TriangulatedResult, Vector2Like };
824
+ export { ArcCurve, BoundingBox, CompositeCurve, CubicBezierCurve, Curve, CurvePath, EllipseCurve, EquilateralPolygonCurve, FFDControlGrid, LineCurve, PI, PI_2, Path2D, Path2DSet, PolygonCurve, QuadraticBezierCurve, RectangleCurve, RoundRectangleCurve, SplineCurve, Transform2D, Vector2, applyFFD, catmullRom, cubicBezier, drawPoint, fillTriangulate, getAdaptiveCubicBezierCurvePoints, getAdaptiveQuadraticBezierCurvePoints, getDirectedArea, getIntersectionPoint, nonzeroFillRule, parseArcCommand, parseCssArg, parseCssArgs, parseCssFunctions, parsePathDataArgs, pointInPolygon, pointInPolygons, pointToPolylineDistance, pointToSegmentDistance, quadraticBezier, setCanvasContext, strokeTriangulate, svgPathCommandsAddToPath2D, svgPathCommandsToData, svgPathDataToCommands, svgToDom, svgToPath2DSet, toKebabCase };
825
+ export type { CssFunction, CssFunctionArg, DrawPointOptions, FillRule, FillTriangulateOptions, FillTriangulatedResult, IsPointInFillOptions, IsPointInStrokeOptions, LineCap, LineJoin, LineStyle, ParseCssFunctionContext, Path2DCommand, Path2DData, Path2DDrawStyle, Path2DStyle, StrokeLinecap, StrokeLinejoin, StrokeTriangulateOptions, StrokeTriangulatedResult, TransformableObject, TriangulatedResult, Vector2Like };
package/dist/index.d.ts CHANGED
@@ -308,6 +308,45 @@ interface NonzeroFillRuleResult {
308
308
  }
309
309
  declare function nonzeroFillRule(paths: number[][]): NonzeroFillRuleResult[];
310
310
 
311
+ /**
312
+ * Test whether a point lies inside a single polygon ring.
313
+ *
314
+ * `vertices` is a flat `[x0, y0, x1, y1, ...]` array and is treated as implicitly closed
315
+ * (the last vertex connects back to the first). A ring with fewer than 3 points has no
316
+ * area and always returns `false`.
317
+ *
318
+ * @param point The point to test.
319
+ * @param vertices Flat vertex array of the ring.
320
+ * @param fillRule `'nonzero'` (default, matches SVG/Canvas) or `'evenodd'`.
321
+ */
322
+ declare function pointInPolygon(point: Vector2Like, vertices: number[], fillRule?: FillRule): boolean;
323
+ /**
324
+ * Test whether a point lies inside a shape composed of multiple rings (sub-paths).
325
+ *
326
+ * This is the multi-ring counterpart of {@link pointInPolygon} and is what donut /
327
+ * hollow shapes need: every ring is evaluated together so holes are honored.
328
+ * - `'nonzero'`: sum the signed winding numbers of all rings, inside if the total ≠ 0.
329
+ * - `'evenodd'`: sum the ray-crossing counts of all rings, inside if the total is odd.
330
+ *
331
+ * @param point The point to test.
332
+ * @param polygons Array of flat vertex arrays, one per ring.
333
+ * @param fillRule `'nonzero'` (default) or `'evenodd'`.
334
+ */
335
+ declare function pointInPolygons(point: Vector2Like, polygons: number[][], fillRule?: FillRule): boolean;
336
+ /**
337
+ * Shortest distance from a point to a single line segment a→b.
338
+ */
339
+ declare function pointToSegmentDistance(point: Vector2Like, a: Vector2Like, b: Vector2Like): number;
340
+ /**
341
+ * Shortest distance from a point to a polyline.
342
+ *
343
+ * @param point The point to test.
344
+ * @param vertices Flat `[x0, y0, x1, y1, ...]` array of the polyline.
345
+ * @param closed When `true`, also considers the closing edge from the last vertex back
346
+ * to the first (use for closed paths, e.g. `z`/`Z` or `CurvePath.autoClose`).
347
+ */
348
+ declare function pointToPolylineDistance(point: Vector2Like, vertices: number[], closed?: boolean): number;
349
+
311
350
  declare function quadraticBezier(t: number, p0: number, p1: number, p2: number): number;
312
351
 
313
352
  type LineCap = 'butt' | 'round' | 'square';
@@ -333,6 +372,14 @@ interface LineStyle {
333
372
  }
334
373
  declare function strokeTriangulate(points: number[], options?: StrokeTriangulateOptions): StrokeTriangulatedResult;
335
374
 
375
+ interface IsPointInFillOptions {
376
+ fillRule?: FillRule;
377
+ }
378
+ interface IsPointInStrokeOptions {
379
+ strokeWidth?: number;
380
+ tolerance?: number;
381
+ closed?: boolean;
382
+ }
336
383
  declare abstract class Curve {
337
384
  arcLengthDivision: number;
338
385
  protected _lengths: number[];
@@ -363,6 +410,32 @@ declare abstract class Curve {
363
410
  max: Vector2;
364
411
  };
365
412
  getBoundingBox(): BoundingBox;
413
+ /**
414
+ * Test whether a point lies inside the area enclosed by this curve.
415
+ *
416
+ * The curve is sampled via {@link getAdaptiveVertices} into a single implicitly closed
417
+ * ring. This is purely geometric (it ignores any `fill`/`stroke` style), mirroring
418
+ * `CanvasRenderingContext2D.isPointInPath`.
419
+ *
420
+ * Composites that hold multiple sub-paths (e.g. {@link Path2D}) override this so holes
421
+ * are honored — a single `Curve` is always one ring.
422
+ */
423
+ isPointInFill(point: Vector2Like, options?: IsPointInFillOptions): boolean;
424
+ /**
425
+ * Test whether a point lies on this curve's stroke, i.e. within `strokeWidth / 2 + tolerance`
426
+ * of the sampled outline. The point must be in the same coordinate space as the curve.
427
+ *
428
+ * Options: `strokeWidth` (path units, default `1`), `tolerance` (extra hit slack in path
429
+ * units, default `0` — useful for thin strokes; no coordinate scaling is assumed, so convert
430
+ * pixel tolerance to path units upstream if your path is normalized), and `closed` (whether
431
+ * to include the closing edge from the last vertex back to the first).
432
+ */
433
+ isPointInStroke(point: Vector2Like, options?: IsPointInStrokeOptions): boolean;
434
+ /**
435
+ * Concise PathKit-style fill containment test: `contains(x, y)` is shorthand for
436
+ * {@link isPointInFill} with a `{ x, y }` point.
437
+ */
438
+ contains(x: number, y: number, options?: IsPointInFillOptions): boolean;
366
439
  getFillVertices(_options?: FillTriangulateOptions): number[];
367
440
  fillTriangulate(options?: FillTriangulateOptions): FillTriangulatedResult;
368
441
  strokeTriangulate(options?: StrokeTriangulateOptions): StrokeTriangulatedResult;
@@ -483,17 +556,17 @@ declare class LineCurve extends Curve {
483
556
  copyFrom(source: LineCurve): this;
484
557
  }
485
558
 
486
- declare class PloygonCurve extends CompositeCurve<LineCurve> {
559
+ declare class PolygonCurve extends CompositeCurve<LineCurve> {
487
560
  }
488
561
 
489
- declare class EquilateralPloygonCurve extends PloygonCurve {
562
+ declare class EquilateralPolygonCurve extends PolygonCurve {
490
563
  cx: number;
491
564
  cy: number;
492
565
  radius: number;
493
566
  sideCount: number;
494
567
  constructor(cx?: number, cy?: number, radius?: number, sideCount?: number);
495
568
  update(): this;
496
- copyFrom(source: EquilateralPloygonCurve): this;
569
+ copyFrom(source: EquilateralPolygonCurve): this;
497
570
  }
498
571
 
499
572
  declare class QuadraticBezierCurve extends Curve {
@@ -514,7 +587,7 @@ declare class QuadraticBezierCurve extends Curve {
514
587
  copyFrom(source: QuadraticBezierCurve): this;
515
588
  }
516
589
 
517
- declare class RectangleCurve extends PloygonCurve {
590
+ declare class RectangleCurve extends PolygonCurve {
518
591
  x: number;
519
592
  y: number;
520
593
  width: number;
@@ -559,6 +632,11 @@ declare class CurvePath extends CompositeCurve {
559
632
  getSpacedVertices(count?: number, output?: number[]): number[];
560
633
  getAdaptiveVertices(output?: number[]): number[];
561
634
  getFillVertices(options?: FillTriangulateOptions): number[];
635
+ /**
636
+ * Same as {@link Curve.isPointInStroke}, but `closed` defaults to this sub-path's actual
637
+ * closed-ness: explicitly `autoClose`, or geometrically closed (first vertex === last).
638
+ */
639
+ isPointInStroke(point: Vector2Like, options?: IsPointInStrokeOptions): boolean;
562
640
  protected _setCurrentPoint(point: Vector2Like): this;
563
641
  protected _connetLineTo(curve: Curve): this;
564
642
  closePath(): this;
@@ -617,6 +695,25 @@ declare class Path2D<T = any> extends CompositeCurve<CurvePath> {
617
695
  skew(ax: number, ay?: number, target?: Vector2Like): this;
618
696
  rotate(rad: number, target?: Vector2Like): this;
619
697
  bold(b: number): this;
698
+ /**
699
+ * Test whether a point lies inside the filled area of this path.
700
+ *
701
+ * Each sub-path ({@link CurvePath}) is sampled into its own ring and all rings are
702
+ * evaluated together via {@link pointInPolygons}, so holes (donut / hollow shapes) are
703
+ * honored. This is purely geometric and ignores `style.fill` — for the `fill: 'none'`
704
+ * fallback, gate the call upstream (see {@link Path2DSet.hitTest}).
705
+ *
706
+ * Defaults `fillRule` to `style.fillRule`, then `'nonzero'` (matching SVG/Canvas).
707
+ */
708
+ isPointInFill(point: Vector2Like, options?: IsPointInFillOptions): boolean;
709
+ /**
710
+ * Test whether a point lies on this path's stroke. A hit on any sub-path counts.
711
+ *
712
+ * Defaults `strokeWidth` to this path's own {@link strokeWidth} (which is `0` when
713
+ * `style.stroke` is `'none'`). Each sub-path infers its own closed-ness unless `closed`
714
+ * is given explicitly.
715
+ */
716
+ isPointInStroke(point: Vector2Like, options?: IsPointInStrokeOptions): boolean;
620
717
  getMinMax(min?: Vector2, max?: Vector2, withStyle?: boolean): {
621
718
  min: Vector2;
622
719
  max: Vector2;
@@ -641,6 +738,36 @@ declare class Path2DSet<T = any> {
641
738
  paths: Path2D<T>[];
642
739
  viewBox?: number[] | undefined;
643
740
  constructor(paths?: Path2D<T>[], viewBox?: number[] | undefined);
741
+ /**
742
+ * Test whether a point lies inside the filled area of any path in this set.
743
+ * Purely geometric (ignores `fill: 'none'`); use {@link hitTest} for style-aware hits.
744
+ */
745
+ isPointInFill(point: Vector2Like, options?: {
746
+ fillRule?: FillRule;
747
+ }): boolean;
748
+ /**
749
+ * Concise PathKit-style fill containment test across the whole set; shorthand for
750
+ * {@link isPointInFill} with a `{ x, y }` point.
751
+ */
752
+ contains(x: number, y: number, options?: {
753
+ fillRule?: FillRule;
754
+ }): boolean;
755
+ /**
756
+ * Find the topmost path hit by a point, or `undefined` if none.
757
+ *
758
+ * Paths are tested top-to-bottom (last drawn first). For each path a fill hit is checked
759
+ * first (skipped when `style.fill` is `'none'`), then — if `stroke` is enabled — a stroke
760
+ * hit (skipped when `style.stroke` is `'none'`). This honors the "fill: none falls back to
761
+ * stroke" rule; the coordinate space of `point` must match the paths (no scaling assumed).
762
+ *
763
+ * Options: `stroke` (also test strokes, default `true`), `tolerance` (extra stroke hit slack
764
+ * in path units, default `0`), and `fillRule` (overrides each path's own fill rule).
765
+ */
766
+ hitTest(point: Vector2Like, options?: {
767
+ stroke?: boolean;
768
+ tolerance?: number;
769
+ fillRule?: FillRule;
770
+ }): Path2D<T> | undefined;
644
771
  getBoundingBox(withStyle?: boolean): BoundingBox | undefined;
645
772
  toTriangulatedSvgString(result?: TriangulatedResult | TriangulatedResult[], padding?: number): string;
646
773
  toTriangulatedSvg(result?: TriangulatedResult | TriangulatedResult[], padding?: number): SVGElement;
@@ -694,5 +821,5 @@ declare function svgToDom(svg: string | SVGElement): SVGElement;
694
821
 
695
822
  declare function svgToPath2DSet(svg: string | SVGElement): Path2DSet;
696
823
 
697
- export { ArcCurve, BoundingBox, CompositeCurve, CubicBezierCurve, Curve, CurvePath, EllipseCurve, EquilateralPloygonCurve, FFDControlGrid, LineCurve, PI, PI_2, Path2D, Path2DSet, PloygonCurve, QuadraticBezierCurve, RectangleCurve, RoundRectangleCurve, SplineCurve, Transform2D, Vector2, applyFFD, catmullRom, cubicBezier, drawPoint, fillTriangulate, getAdaptiveCubicBezierCurvePoints, getAdaptiveQuadraticBezierCurvePoints, getDirectedArea, getIntersectionPoint, nonzeroFillRule, parseArcCommand, parseCssArg, parseCssArgs, parseCssFunctions, parsePathDataArgs, quadraticBezier, setCanvasContext, strokeTriangulate, svgPathCommandsAddToPath2D, svgPathCommandsToData, svgPathDataToCommands, svgToDom, svgToPath2DSet, toKebabCase };
698
- export type { CssFunction, CssFunctionArg, DrawPointOptions, FillRule, FillTriangulateOptions, FillTriangulatedResult, LineCap, LineJoin, LineStyle, ParseCssFunctionContext, Path2DCommand, Path2DData, Path2DDrawStyle, Path2DStyle, StrokeLinecap, StrokeLinejoin, StrokeTriangulateOptions, StrokeTriangulatedResult, TransformableObject, TriangulatedResult, Vector2Like };
824
+ export { ArcCurve, BoundingBox, CompositeCurve, CubicBezierCurve, Curve, CurvePath, EllipseCurve, EquilateralPolygonCurve, FFDControlGrid, LineCurve, PI, PI_2, Path2D, Path2DSet, PolygonCurve, QuadraticBezierCurve, RectangleCurve, RoundRectangleCurve, SplineCurve, Transform2D, Vector2, applyFFD, catmullRom, cubicBezier, drawPoint, fillTriangulate, getAdaptiveCubicBezierCurvePoints, getAdaptiveQuadraticBezierCurvePoints, getDirectedArea, getIntersectionPoint, nonzeroFillRule, parseArcCommand, parseCssArg, parseCssArgs, parseCssFunctions, parsePathDataArgs, pointInPolygon, pointInPolygons, pointToPolylineDistance, pointToSegmentDistance, quadraticBezier, setCanvasContext, strokeTriangulate, svgPathCommandsAddToPath2D, svgPathCommandsToData, svgPathDataToCommands, svgToDom, svgToPath2DSet, toKebabCase };
825
+ export type { CssFunction, CssFunctionArg, DrawPointOptions, FillRule, FillTriangulateOptions, FillTriangulatedResult, IsPointInFillOptions, IsPointInStrokeOptions, LineCap, LineJoin, LineStyle, ParseCssFunctionContext, Path2DCommand, Path2DData, Path2DDrawStyle, Path2DStyle, StrokeLinecap, StrokeLinejoin, StrokeTriangulateOptions, StrokeTriangulatedResult, TransformableObject, TriangulatedResult, Vector2Like };