@weasel-js/geom 1.10.1 → 1.11.0
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/README.md +9 -1
- package/dist/3d/index.d.ts +29 -2
- package/dist/3d/index.js +49 -1
- package/dist/3d/index.js.map +1 -1
- package/dist/booleans/index.d.ts +15 -10
- package/dist/booleans/index.js +306 -353
- package/dist/booleans/index.js.map +1 -1
- package/dist/{chunk-7WFFCHRL.js → chunk-6XSJY3TC.js} +6 -37
- package/dist/chunk-6XSJY3TC.js.map +1 -0
- package/dist/chunk-7KLJZFBY.js +573 -0
- package/dist/chunk-7KLJZFBY.js.map +1 -0
- package/dist/chunk-B53BERKG.js +386 -0
- package/dist/chunk-B53BERKG.js.map +1 -0
- package/dist/chunk-CE7IY7TB.js +104 -0
- package/dist/chunk-CE7IY7TB.js.map +1 -0
- package/dist/chunk-HGF5OVEN.js +129 -0
- package/dist/chunk-HGF5OVEN.js.map +1 -0
- package/dist/chunk-J2O2B54M.js +800 -0
- package/dist/chunk-J2O2B54M.js.map +1 -0
- package/dist/chunk-Q66NA2FU.js +174 -0
- package/dist/chunk-Q66NA2FU.js.map +1 -0
- package/dist/chunk-SASMXDBE.js +443 -0
- package/dist/chunk-SASMXDBE.js.map +1 -0
- package/dist/chunk-UI3FUWXM.js +533 -0
- package/dist/chunk-UI3FUWXM.js.map +1 -0
- package/dist/curvature-PkoLduGc.d.ts +454 -0
- package/dist/curves/index.d.ts +14 -5
- package/dist/curves/index.js +33 -111
- package/dist/curves/index.js.map +1 -1
- package/dist/index.d.ts +1468 -284
- package/dist/index.js +5450 -2672
- package/dist/index.js.map +1 -1
- package/dist/nd/index.d.ts +91 -27
- package/dist/nd/index.js +282 -0
- package/dist/nd/index.js.map +1 -1
- package/dist/path-BW8d_2RY.d.ts +157 -0
- package/dist/portCurve-C5HDWuuV.d.ts +30 -0
- package/dist/tessellate/index.d.ts +15 -4
- package/dist/tessellate/index.js +21 -277
- package/dist/tessellate/index.js.map +1 -1
- package/dist/warp/index.d.ts +252 -0
- package/dist/warp/index.js +1316 -0
- package/dist/warp/index.js.map +1 -0
- package/package.json +5 -1
- package/dist/chunk-7WFFCHRL.js.map +0 -1
- package/dist/chunk-IDXY2NCA.js +0 -177
- package/dist/chunk-IDXY2NCA.js.map +0 -1
- package/dist/chunk-NJ3IGAKR.js +0 -16
- package/dist/chunk-NJ3IGAKR.js.map +0 -1
- package/dist/chunk-OXH3NOXC.js +0 -62
- package/dist/chunk-OXH3NOXC.js.map +0 -1
- package/dist/chunk-URQMDR6Q.js +0 -80
- package/dist/chunk-URQMDR6Q.js.map +0 -1
- package/dist/cubicMath-BW-HJrCE.d.ts +0 -16
- package/dist/path-ljHxobyu.d.ts +0 -44
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export {
|
|
1
|
+
import { c as PathOpenFill, P as PolygonPath, d as PathFillRule, a as Path, R as RectPath, b as Point, C as CornerSpec, e as CornerPiece } from './path-BW8d_2RY.js';
|
|
2
|
+
export { f as CORNER_FIT_TOLERANCE, g as CORNER_KEYWORDS, h as CornerKeyword, i as CornerShape, j as CornerShapeFrame, k as compactCorners, l as cornerAt, m as cornerCenter, n as cornerKeywordOf, o as cornerShapeK, p as cornerShapePieces, q as cornerShapePoint, r as cornerSpecAt, s as cubicPointAt, t as hasCorners, u as isCornerShape, v as lerpCorners, w as nextCornerShape, x as scaleCorners, y as splitCubicAtT, z as withCorner, A as withoutCorners } from './path-BW8d_2RY.js';
|
|
3
|
+
import { A as AnchorSet, P as PenAnchor, a as SpiroPoint, S as SpiroKind, b as Scale2 } from './curvature-PkoLduGc.js';
|
|
4
|
+
export { c as AnchorRect, d as CombTooth, e as CurvatureCombOptions, C as CurvatureSource, E as EulerFit, f as EulerSegment, g as SPIRO_KINDS, h as SegmentComb, i as SegmentHit, j as SpiroSegment, k as anchorAt, l as anchorCount, m as anchorsInRect, n as anchorsToPath, o as combTeeth, p as countPathAnchors, q as cubicCurvatureAt, r as cubicCurvatureSource, s as cubicDerivativeAt, t as curvatureComb, u as deleteAnchorsAt, v as editAnchorSet, w as eulerAngleAt, x as eulerCurvatureAt, y as eulerCurvatureDerivativesAt, z as eulerPointAt, B as fitEulerSegment, D as flatAnchorIndex, F as insertAnchorOnSegment, G as isAnchorSmooth, H as isSpiroKind, I as isStraightSegment, J as locateAnchor, K as moveHandleTo, L as nearestSegmentT, M as openSubpathAt, N as pathToAnchors, O as placeEulerSegment, Q as pxExtent, R as scaleDelta, T as screenAngleOf, U as segmentAt, V as segmentEnds, W as solveSpiro, X as standoff, Y as translateAnchorBy, Z as withinPxBox, _ as withinPxRadius } from './curvature-PkoLduGc.js';
|
|
5
|
+
export { P as PORT_REACH } from './portCurve-C5HDWuuV.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Scalar / 2-vector primitives and the kernel-wide epsilon policy.
|
|
@@ -203,6 +204,9 @@ declare function cubicEvalAt(x0: number, y0: number, x1: number, y1: number, x2:
|
|
|
203
204
|
* quadratic endpoints. c1 = q0 + 2/3(ctrl-q0), c2 = q1 + 2/3(ctrl-q1).
|
|
204
205
|
*/
|
|
205
206
|
declare function elevateQuadraticToCubic(q0x: number, q0y: number, cx: number, cy: number, q1x: number, q1y: number): [number, number, number, number];
|
|
207
|
+
/** The parameters in (0, 1) where one coordinate of a cubic, with control
|
|
208
|
+
* values `p0..p3`, turns: the roots of its derivative. */
|
|
209
|
+
declare function cubicAxisExtremaTs(p0: number, p1: number, p2: number, p3: number): number[];
|
|
206
210
|
/** Tight AABB of a cubic, evaluating only extrema that lie on the curve. */
|
|
207
211
|
declare function cubicBounds(x0: number, y0: number, x1: number, y1: number, x2: number, y2: number, x3: number, y3: number): Box;
|
|
208
212
|
/** Quadratic Bezier point at parameter t (Bernstein form). */
|
|
@@ -375,6 +379,9 @@ declare class PathBuilder {
|
|
|
375
379
|
}
|
|
376
380
|
/** Construct a `RectPath` (the fast-path subtype). */
|
|
377
381
|
declare function rectPath(x: number, y: number, width: number, height: number): RectPath;
|
|
382
|
+
/** `path` as a command stream drawing the same outline. A rect becomes its four
|
|
383
|
+
* corners clockwise from `(x, y)`, the order `countPathAnchors` numbers them in. */
|
|
384
|
+
declare function asPolygonPath(path: Path): PolygonPath;
|
|
378
385
|
/** Build an open polyline from a flat list of points — the same geometry as
|
|
379
386
|
* {@link polygonFromPoints} without the closing edge. A freehand stroke and a
|
|
380
387
|
* measurement line want this; a region wants the closed one. */
|
|
@@ -421,10 +428,133 @@ declare function linePath(a: {
|
|
|
421
428
|
/**
|
|
422
429
|
* AABB of a `Path`, returned as a `RectPath` for direct reuse with rect-fast-path machinery.
|
|
423
430
|
* Control points are NOT included directly; they're used only to compute extrema that actually
|
|
424
|
-
* lie on the curve. Empty paths (no commands) return a zero-size rect anchored at the origin.
|
|
431
|
+
* lie on the curve. Corner shapes are bounded as they are drawn, expanded. Empty paths (no commands) return a zero-size rect anchored at the origin.
|
|
425
432
|
*/
|
|
426
433
|
declare function boundsOfPath(path: Path): RectPath;
|
|
427
434
|
|
|
435
|
+
/**
|
|
436
|
+
* Corner expansion: a path's corner specs turned into the plain geometry
|
|
437
|
+
* that every reader draws, hits, bounds, and exports.
|
|
438
|
+
*/
|
|
439
|
+
|
|
440
|
+
/** Where and how a corner anchor can be cut. */
|
|
441
|
+
interface CornerFrame {
|
|
442
|
+
/** Flat anchor index. */
|
|
443
|
+
index: number;
|
|
444
|
+
/** The anchor. */
|
|
445
|
+
x: number;
|
|
446
|
+
y: number;
|
|
447
|
+
/** Unit direction from the anchor into the wedge the cut is taken from. */
|
|
448
|
+
bisector: Point;
|
|
449
|
+
/** Half the angle between the two edges at the anchor. */
|
|
450
|
+
halfAngle: number;
|
|
451
|
+
/** How far along each edge the stored spec cuts, its setback, after clamping. */
|
|
452
|
+
trim: number;
|
|
453
|
+
/** The longest cut the edges allow while the neighbors keep theirs. */
|
|
454
|
+
maxTrim: number;
|
|
455
|
+
}
|
|
456
|
+
/** Every anchor of `path` that can take a corner, with the cut its spec
|
|
457
|
+
* makes now. */
|
|
458
|
+
declare function cornerFrames(path: PolygonPath): CornerFrame[];
|
|
459
|
+
/** The frame of the corner at flat anchor `index`, or null when that anchor
|
|
460
|
+
* cannot take one. */
|
|
461
|
+
declare function cornerFrameAt(path: PolygonPath, index: number): CornerFrame | null;
|
|
462
|
+
/** A path with its corners expanded, and where its anchors came from. */
|
|
463
|
+
interface ResolvedCorners {
|
|
464
|
+
path: PolygonPath;
|
|
465
|
+
/**
|
|
466
|
+
* For each anchor of `path` (each M, L, C, or Q, as `countPathAnchors`
|
|
467
|
+
* counts them), the anchor of the source path it belongs to, in the same
|
|
468
|
+
* numbering. Every point a corner's cut adds belongs to that corner's
|
|
469
|
+
* anchor. Null when the expansion added none.
|
|
470
|
+
*/
|
|
471
|
+
anchorSources: Uint32Array | null;
|
|
472
|
+
}
|
|
473
|
+
/** {@link resolveCorners}, also answering which source anchor each anchor of
|
|
474
|
+
* the result came from, so an array kept per anchor (`vertexColors`) can be
|
|
475
|
+
* carried onto it with {@link remapPerAnchor}. */
|
|
476
|
+
declare function resolveCornersWithSources(path: PolygonPath): ResolvedCorners;
|
|
477
|
+
/**
|
|
478
|
+
* `path` with its corner specs expanded into plain geometry and dropped: each
|
|
479
|
+
* corner is cut `radius` along both edges and spans the cut with its shape's
|
|
480
|
+
* superellipse (`cornerShapePieces`). Each cut is clamped so the cuts on
|
|
481
|
+
* either end of a segment never overlap. A path with no corners comes back
|
|
482
|
+
* as itself, and so does a rect.
|
|
483
|
+
*/
|
|
484
|
+
declare function resolveCorners<P extends Path>(path: P): P;
|
|
485
|
+
/** `values`, `stride` numbers per source anchor, as `stride` per anchor of
|
|
486
|
+
* the expanded path that `sources` describes. */
|
|
487
|
+
declare function remapPerAnchor<T>(values: readonly T[], sources: Uint32Array, stride: number): T[];
|
|
488
|
+
/** One corner of a path as its expansion draws it. */
|
|
489
|
+
interface CornerCut {
|
|
490
|
+
/** Flat anchor index. */
|
|
491
|
+
index: number;
|
|
492
|
+
anchor: Point;
|
|
493
|
+
spec: CornerSpec;
|
|
494
|
+
/** Where the cut leaves the edge into the anchor, and where it rejoins the edge out of it. */
|
|
495
|
+
start: Point;
|
|
496
|
+
end: Point;
|
|
497
|
+
/** The outline from `start` to `end`. */
|
|
498
|
+
pieces: CornerPiece[];
|
|
499
|
+
}
|
|
500
|
+
/** Every corner `path` cuts, in path order. */
|
|
501
|
+
declare function cornerCuts(path: PolygonPath): CornerCut[];
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Putting corner specs back on a path an operation rebuilt from expanded
|
|
505
|
+
* geometry. Booleans, trims and cuts work on what a path draws, its corners
|
|
506
|
+
* cut and spanned (`resolveCorners`); wherever a corner's cut comes through
|
|
507
|
+
* whole, it folds back into its anchor and spec, and only a corner the
|
|
508
|
+
* operation cut into or moved stays expanded.
|
|
509
|
+
*/
|
|
510
|
+
|
|
511
|
+
/** A corner a rebuilt path may hold expanded: the anchor and spec it folds
|
|
512
|
+
* back into, and the cut it is drawn as, from `start` to `end`. */
|
|
513
|
+
interface CornerTrace {
|
|
514
|
+
anchor: Point;
|
|
515
|
+
spec: CornerSpec;
|
|
516
|
+
start: Point;
|
|
517
|
+
end: Point;
|
|
518
|
+
pieces: readonly CornerPiece[];
|
|
519
|
+
}
|
|
520
|
+
/** How far a point may sit from where a corner draws it and still count as on it. */
|
|
521
|
+
declare const CORNER_RESTORE_TOLERANCE = 0.001;
|
|
522
|
+
/** The corners `path` cuts, as {@link restoreCorners} looks for them. */
|
|
523
|
+
declare function cornerTraces(path: Path): CornerTrace[];
|
|
524
|
+
/**
|
|
525
|
+
* `result` with the corners of `sources` folded back in wherever it still
|
|
526
|
+
* draws them whole: an operation's output, rebuilt from what the sources
|
|
527
|
+
* draw. A corner the operation cut into, or whose edges it moved, stays as
|
|
528
|
+
* the plain geometry it already is.
|
|
529
|
+
*/
|
|
530
|
+
declare function keepCorners(sources: readonly Path[], result: PolygonPath, tolerance?: number): PolygonPath;
|
|
531
|
+
/**
|
|
532
|
+
* `result` with each of `traces` it draws whole folded back into its anchor
|
|
533
|
+
* and spec. A trace counts as drawn when a run of anchors goes from one end
|
|
534
|
+
* of its cut to the other along it, the edges either side carry on to its
|
|
535
|
+
* anchor, and the folded corner cuts the same again. Specs `result` already
|
|
536
|
+
* holds are kept.
|
|
537
|
+
*/
|
|
538
|
+
declare function restoreCorners(result: PolygonPath, traces: readonly CornerTrace[], tolerance?: number): PolygonPath;
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* The corners an offset outline would hold as corners: each of the source's,
|
|
542
|
+
* moved to where its offset edges meet and resized so its cut keeps the
|
|
543
|
+
* same center.
|
|
544
|
+
*/
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Where the corners of `path` would sit on its outline grown by `distance`
|
|
548
|
+
* (shrunk by a negative one), for `restoreCorners` to look for. A corner
|
|
549
|
+
* moves with its edges and keeps its center, so its setback changes by
|
|
550
|
+
* `distance / tan(half the corner's angle)`: a round corner at a right angle
|
|
551
|
+
* grows its radius by exactly `distance`, and is then exactly what the offset
|
|
552
|
+
* draws. A shape whose offset is no longer that shape, or a corner between
|
|
553
|
+
* curved edges, draws differently from its trace, so `restoreCorners` leaves
|
|
554
|
+
* it expanded. A corner shrunk to nothing has no trace.
|
|
555
|
+
*/
|
|
556
|
+
declare function offsetCornerTraces(path: Path, distance: number): CornerTrace[];
|
|
557
|
+
|
|
428
558
|
/**
|
|
429
559
|
* AABB union over a heterogeneous set of `Path` poses. Returns the
|
|
430
560
|
* envelope as a `RectPath`, or `null` for empty input — analog of
|
|
@@ -486,7 +616,8 @@ declare function decomposePath(parent: Path, world: Path): Path;
|
|
|
486
616
|
/** Split a path into one path per subpath, cutting at each `M`. A path with a
|
|
487
617
|
* single subpath comes back as a one-element array. `fillRule` is propagated
|
|
488
618
|
* unchanged, so even-odd compound paths with interior "holes" lose the hole
|
|
489
|
-
* semantics — each subpath becomes its own filled region.
|
|
619
|
+
* semantics — each subpath becomes its own filled region. Each subpath keeps
|
|
620
|
+
* the corner specs of its own anchors. */
|
|
490
621
|
declare function splitSubpaths(path: PolygonPath): PolygonPath[];
|
|
491
622
|
|
|
492
623
|
/** Whether any subpath of `path` lacks the `Z` that closes it. */
|
|
@@ -521,7 +652,7 @@ declare function pathSignedArea(path: Path): number;
|
|
|
521
652
|
/**
|
|
522
653
|
* `path` with every contour traversed backwards: same region, same curves,
|
|
523
654
|
* opposite winding. A closed contour keeps its starting point; an open one
|
|
524
|
-
* starts from where it used to end.
|
|
655
|
+
* starts from where it used to end. Corner specs stay on their anchors.
|
|
525
656
|
*/
|
|
526
657
|
declare function reversePath(path: PolygonPath): PolygonPath;
|
|
527
658
|
|
|
@@ -545,6 +676,48 @@ declare function reversePath(path: PolygonPath): PolygonPath;
|
|
|
545
676
|
*/
|
|
546
677
|
declare function pathFromD(d: string, onWarn?: (message: string) => void): ReturnType<PathBuilder['build']>;
|
|
547
678
|
|
|
679
|
+
/**
|
|
680
|
+
* A path measured once by arc length, so many stations along it cost a binary
|
|
681
|
+
* search each rather than a fresh flatten: what `pointAlongPath` answers one
|
|
682
|
+
* fraction at a time, and what anything placing or bending geometry along a
|
|
683
|
+
* path reads many times over.
|
|
684
|
+
*/
|
|
685
|
+
|
|
686
|
+
/** A point on a path and its heading there. */
|
|
687
|
+
interface PathStation {
|
|
688
|
+
point: Point;
|
|
689
|
+
/** Unit vector along the path at `point`, pointing toward the end. */
|
|
690
|
+
tangent: Point;
|
|
691
|
+
}
|
|
692
|
+
/** Options for {@link measurePath}. */
|
|
693
|
+
interface MeasurePathOptions {
|
|
694
|
+
/** Curve flattening tolerance, in world units. Default 0.5. */
|
|
695
|
+
flattenTolerance?: number;
|
|
696
|
+
}
|
|
697
|
+
/** A measured path: its length, and the station at any distance along it. */
|
|
698
|
+
interface PathMeasure {
|
|
699
|
+
/** Total arc length, every subpath counted in order. */
|
|
700
|
+
readonly length: number;
|
|
701
|
+
/** True when the path is a single closed contour, so a distance past the
|
|
702
|
+
* end can wrap round to the start. */
|
|
703
|
+
readonly closed: boolean;
|
|
704
|
+
/**
|
|
705
|
+
* The station `s` along the path, `s` clamped to `0..length`.
|
|
706
|
+
*
|
|
707
|
+
* The tangent is the heading of the flattened segment under `s`. With
|
|
708
|
+
* `smooth`, it is instead blended across each segment from the heading at
|
|
709
|
+
* one vertex to the next, so geometry bent along it turns without facets.
|
|
710
|
+
*/
|
|
711
|
+
at(s: number, smooth?: boolean): PathStation;
|
|
712
|
+
}
|
|
713
|
+
/**
|
|
714
|
+
* Measure `path` by arc length. Subpaths are measured in order and treated as
|
|
715
|
+
* one run, the way a browser measures a whole `<path>`. Returns `null` for a
|
|
716
|
+
* path with no points; a path of zero length answers at its single point,
|
|
717
|
+
* heading along +X.
|
|
718
|
+
*/
|
|
719
|
+
declare function measurePath(path: Path, opts?: MeasurePathOptions): PathMeasure | null;
|
|
720
|
+
|
|
548
721
|
/**
|
|
549
722
|
* A station along a path: where it is at a fraction of its length, and which
|
|
550
723
|
* way it is heading there.
|
|
@@ -552,20 +725,12 @@ declare function pathFromD(d: string, onWarn?: (message: string) => void): Retur
|
|
|
552
725
|
* For anything positioned *along* geometry rather than beside it — a label on a
|
|
553
726
|
* routed edge, a tick on a curve, a badge near an arrowhead. Curves are
|
|
554
727
|
* flattened first, so the fraction is arc length along the drawn shape rather
|
|
555
|
-
* than a curve parameter, which is what makes 0.5 look like the middle.
|
|
728
|
+
* than a curve parameter, which is what makes 0.5 look like the middle. For
|
|
729
|
+
* many stations along one path, measure it once with `measurePath`.
|
|
556
730
|
*/
|
|
557
731
|
|
|
558
|
-
/** The answer `pointAlongPath` gives: a point on the path and its heading there. */
|
|
559
|
-
interface PathStation {
|
|
560
|
-
point: Point$1;
|
|
561
|
-
/** Unit vector along the path at `point`, pointing toward the end. */
|
|
562
|
-
tangent: Point$1;
|
|
563
|
-
}
|
|
564
732
|
/** Options for `pointAlongPath`. */
|
|
565
|
-
|
|
566
|
-
/** Curve flattening tolerance, in world units. Default 0.5. */
|
|
567
|
-
flattenTolerance?: number;
|
|
568
|
-
}
|
|
733
|
+
type PointAlongPathOptions = MeasurePathOptions;
|
|
569
734
|
/**
|
|
570
735
|
* Where `path` is at `t` of its total length, and its heading there.
|
|
571
736
|
*
|
|
@@ -576,6 +741,144 @@ interface PointAlongPathOptions {
|
|
|
576
741
|
*/
|
|
577
742
|
declare function pointAlongPath(path: Path, t: number, opts?: PointAlongPathOptions): PathStation | null;
|
|
578
743
|
|
|
744
|
+
/** One cubic segment, `[x0, y0, x1, y1, x2, y2, x3, y3]`, and whether it was
|
|
745
|
+
* drawn straight. A straight one keeps its controls at its thirds, so it
|
|
746
|
+
* interpolates and warps as a line would. */
|
|
747
|
+
interface CubicSegment {
|
|
748
|
+
c: [number, number, number, number, number, number, number, number];
|
|
749
|
+
line: boolean;
|
|
750
|
+
}
|
|
751
|
+
/** One contour of segments, each starting where the one before it ends. */
|
|
752
|
+
interface CubicContour {
|
|
753
|
+
segs: CubicSegment[];
|
|
754
|
+
closed: boolean;
|
|
755
|
+
}
|
|
756
|
+
/**
|
|
757
|
+
* `path`'s contours as cubic segments. A closed contour whose last point
|
|
758
|
+
* stops short of its first gains the straight closing edge it is drawn with;
|
|
759
|
+
* zero-length straight segments are dropped. A contour with no segments is a
|
|
760
|
+
* lone point and is left out. Corner specs are expanded first.
|
|
761
|
+
*/
|
|
762
|
+
declare function pathToCubicContours(path: Path): CubicContour[];
|
|
763
|
+
/** The path drawing `contours`: a straight segment as `L`, the rest as `C`. */
|
|
764
|
+
declare function cubicContoursToPath(contours: readonly CubicContour[], fillRule?: PathFillRule): PolygonPath;
|
|
765
|
+
|
|
766
|
+
/**
|
|
767
|
+
* Shape interpolation between two paths: the steps of a blend, or the frames
|
|
768
|
+
* of a morph.
|
|
769
|
+
*
|
|
770
|
+
* The two shapes are matched once — contour to contour, then segment to
|
|
771
|
+
* segment — and every step is a straight lerp of the matched control points.
|
|
772
|
+
* Where one contour has fewer segments, its longest ones are split in half
|
|
773
|
+
* until the counts agree, which adds anchors without moving the outline.
|
|
774
|
+
*/
|
|
775
|
+
|
|
776
|
+
/** How a blend matches the second shape's anchors to the first's. */
|
|
777
|
+
interface BlendPathsOptions {
|
|
778
|
+
/**
|
|
779
|
+
* Choose, for each pair of contours, the start point (and, when `reverse`
|
|
780
|
+
* is unset, the direction) of the second that keeps matched anchors
|
|
781
|
+
* closest, with both contours centered on their own middles first so that
|
|
782
|
+
* where the shapes sit does not decide it. Default `true`.
|
|
783
|
+
*/
|
|
784
|
+
autoAlign?: boolean;
|
|
785
|
+
/**
|
|
786
|
+
* Turn the second shape's start point this many anchors further round each
|
|
787
|
+
* closed contour, after any `autoAlign` choice. Negative turns it back.
|
|
788
|
+
* Default 0.
|
|
789
|
+
*/
|
|
790
|
+
startOffset?: number;
|
|
791
|
+
/** Run the second shape's contours backwards. Unset, `autoAlign` decides;
|
|
792
|
+
* without it, they run as drawn. */
|
|
793
|
+
reverse?: boolean;
|
|
794
|
+
}
|
|
795
|
+
/** Two shapes matched for interpolation. */
|
|
796
|
+
interface PathBlend {
|
|
797
|
+
/** The shape `t` of the way from the first to the second: exactly the
|
|
798
|
+
* first at 0 and the second at 1, up to the anchors matching added. */
|
|
799
|
+
at(t: number): PolygonPath;
|
|
800
|
+
/** Segments per matched pair of contours. */
|
|
801
|
+
readonly segmentCounts: readonly number[];
|
|
802
|
+
}
|
|
803
|
+
/** The shape `t` of the way from `a` to `b`. Matching once with
|
|
804
|
+
* {@link prepareBlend} is cheaper when several steps are wanted. */
|
|
805
|
+
declare function blendPaths(a: Path, b: Path, t: number, opts?: BlendPathsOptions): PolygonPath;
|
|
806
|
+
/** Match `a` to `b` for interpolation. */
|
|
807
|
+
declare function prepareBlend(a: Path, b: Path, opts?: BlendPathsOptions): PathBlend;
|
|
808
|
+
|
|
809
|
+
/**
|
|
810
|
+
* Bend a shape along a spine: the shape's x becomes distance along the spine
|
|
811
|
+
* and its y distance off it, along the spine's normal. A straight edge of the
|
|
812
|
+
* shape comes out curved wherever the spine bends, so each segment is
|
|
813
|
+
* sampled through the warp and refit to cubics within a tolerance; anchors
|
|
814
|
+
* stay where they were, so a corner of the shape stays a corner.
|
|
815
|
+
*/
|
|
816
|
+
|
|
817
|
+
/** How a shape is laid along its spine. */
|
|
818
|
+
interface BendAlongPathOptions {
|
|
819
|
+
/**
|
|
820
|
+
* `'stretch'`, the default, spreads the shape's width over the spine's
|
|
821
|
+
* whole length. `'natural'` keeps its width: one unit across the shape is
|
|
822
|
+
* one unit along the spine, starting at the spine's start, and a shape
|
|
823
|
+
* longer than the spine runs on straight past its end.
|
|
824
|
+
*/
|
|
825
|
+
fit?: 'stretch' | 'natural';
|
|
826
|
+
/** Where across the shape's height the spine runs, 0 at its top and 1 at
|
|
827
|
+
* its bottom. Default 0.5, the middle. */
|
|
828
|
+
baseline?: number;
|
|
829
|
+
/** Lay the shape on the other side of the spine, mirrored across it. */
|
|
830
|
+
flip?: boolean;
|
|
831
|
+
/** How far the refit curves may stray from the exact bend, in world
|
|
832
|
+
* units. Default 0.5. */
|
|
833
|
+
tolerance?: number;
|
|
834
|
+
}
|
|
835
|
+
/**
|
|
836
|
+
* `shape` bent along `spine`. A spine heading left to right keeps the shape
|
|
837
|
+
* upright; one heading the other way turns it over, as a road sign painted
|
|
838
|
+
* along a lane does. Returns `null` when the spine has no length or the shape
|
|
839
|
+
* nothing to bend.
|
|
840
|
+
*/
|
|
841
|
+
declare function bendAlongPath(shape: Path, spine: Path, opts?: BendAlongPathOptions): PolygonPath | null;
|
|
842
|
+
|
|
843
|
+
/** How copies are spaced along a path. */
|
|
844
|
+
interface RepeatAlongPathOptions {
|
|
845
|
+
/**
|
|
846
|
+
* How many copies. With no `spacing`, they spread evenly over the whole
|
|
847
|
+
* path — end to end on an open one, evenly round a closed one — and the
|
|
848
|
+
* default is 5. With a `spacing`, it caps the run; unset, as many as fit.
|
|
849
|
+
*/
|
|
850
|
+
count?: number;
|
|
851
|
+
/** Distance along the path from one copy's center to the next. */
|
|
852
|
+
spacing?: number;
|
|
853
|
+
/** Where a spaced run that is shorter than the path sits on it. Default
|
|
854
|
+
* `'start'`. */
|
|
855
|
+
align?: 'start' | 'center' | 'end';
|
|
856
|
+
/** Slide every copy this far along the path. On an open path a copy slid
|
|
857
|
+
* off either end is dropped; round a closed one it wraps. Default 0. */
|
|
858
|
+
offset?: number;
|
|
859
|
+
/** Turn each copy to the path's heading where it sits. Default `true`. */
|
|
860
|
+
orient?: boolean;
|
|
861
|
+
/** Curve flattening tolerance for measuring the path. Default 0.5. */
|
|
862
|
+
flattenTolerance?: number;
|
|
863
|
+
}
|
|
864
|
+
/** Where one copy sits. */
|
|
865
|
+
interface RepeatStation {
|
|
866
|
+
point: Point;
|
|
867
|
+
/** The path's heading there, radians clockwise from +X in a y-down frame. */
|
|
868
|
+
angle: number;
|
|
869
|
+
/** Arc length from the path's start. */
|
|
870
|
+
distance: number;
|
|
871
|
+
}
|
|
872
|
+
/** The stations copies sit at along `path`, in order. Empty for a path with
|
|
873
|
+
* no points. */
|
|
874
|
+
declare function stationsAlongPath(path: Path, opts?: RepeatAlongPathOptions): RepeatStation[];
|
|
875
|
+
/**
|
|
876
|
+
* Copies of `shape`, each centered on a station along `path` — its bounding
|
|
877
|
+
* box's middle on the path — and, with `orient`, turned to the heading
|
|
878
|
+
* there. The shape's own +X runs along the path.
|
|
879
|
+
*/
|
|
880
|
+
declare function repeatAlongPath(shape: Path, path: Path, opts?: RepeatAlongPathOptions): Path[];
|
|
881
|
+
|
|
579
882
|
/**
|
|
580
883
|
* Pure-geometry distance from a point to a path's boundary (stroke), with
|
|
581
884
|
* no fill-side logic. Used by pickers that want to know "how close is this
|
|
@@ -593,88 +896,312 @@ declare function pointAlongPath(path: Path, t: number, opts?: PointAlongPathOpti
|
|
|
593
896
|
* combine with `pathContainsPoint` at the call site. */
|
|
594
897
|
declare function pathDistanceToPoint(path: Path, px: number, py: number): number;
|
|
595
898
|
|
|
899
|
+
/** Where two Bézier segments cross, by subdivision then Newton refinement. */
|
|
900
|
+
|
|
901
|
+
/** One crossing of segments `a` and `b`: the parameter on each, and the point. */
|
|
902
|
+
interface SegmentCrossing {
|
|
903
|
+
ta: number;
|
|
904
|
+
tb: number;
|
|
905
|
+
x: number;
|
|
906
|
+
y: number;
|
|
907
|
+
}
|
|
596
908
|
/**
|
|
597
|
-
*
|
|
598
|
-
*
|
|
599
|
-
*
|
|
600
|
-
*
|
|
601
|
-
*
|
|
602
|
-
*
|
|
603
|
-
* Consumers use this to size their per-anchor color array; the renderer
|
|
604
|
-
* uses it to validate the array length in dev builds.
|
|
909
|
+
* Every point where segment `a` crosses or touches segment `b` — each a line,
|
|
910
|
+
* quadratic or cubic given by its control points — with the parameter on
|
|
911
|
+
* each. Two lines are solved exactly; a curve is subdivided until its pieces
|
|
912
|
+
* are flat, their chords crossed, and the answer refined against the curves.
|
|
913
|
+
* Segments that overlap along a stretch report at most a few points of it.
|
|
914
|
+
* Sorted by `ta`.
|
|
605
915
|
*/
|
|
916
|
+
declare function intersectSegments(a: Point[], b: Point[]): SegmentCrossing[];
|
|
917
|
+
|
|
918
|
+
/** A path's stroke as a flat list of segments, each knowing where it sits. */
|
|
606
919
|
|
|
607
|
-
/** One
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
920
|
+
/** One segment of a path's stroke, in the order the path draws them. */
|
|
921
|
+
interface PathSegment {
|
|
922
|
+
/** Control points: 2 for a line, 3 for a quadratic, 4 for a cubic. */
|
|
923
|
+
pts: Point[];
|
|
924
|
+
/** Index of its subpath among the path's subpaths. */
|
|
925
|
+
sub: number;
|
|
926
|
+
/** Index within its subpath. */
|
|
927
|
+
index: number;
|
|
928
|
+
/** Segments in its subpath. */
|
|
929
|
+
count: number;
|
|
930
|
+
/** Whether its subpath is closed, so its last segment meets its first. */
|
|
931
|
+
closed: boolean;
|
|
932
|
+
/** Axis-aligned box of the control points, which holds the segment. */
|
|
933
|
+
box: {
|
|
934
|
+
x0: number;
|
|
935
|
+
y0: number;
|
|
936
|
+
x1: number;
|
|
937
|
+
y1: number;
|
|
938
|
+
};
|
|
939
|
+
}
|
|
940
|
+
/** `path`'s stroke as segments: a closed subpath includes its closing edge,
|
|
941
|
+
* an open one does not, and a zero-length line is left out. */
|
|
942
|
+
declare function pathSegments(path: Path): PathSegment[];
|
|
943
|
+
|
|
944
|
+
/** Where paths cross one another and themselves. */
|
|
945
|
+
|
|
946
|
+
/** A place on a path's stroke: which segment, and how far along it. */
|
|
947
|
+
interface PathStop {
|
|
948
|
+
/** Index of the path in the list it came from. */
|
|
949
|
+
path: number;
|
|
950
|
+
sub: number;
|
|
951
|
+
/** Segment index within the subpath. */
|
|
952
|
+
index: number;
|
|
953
|
+
/** Parameter on that segment, in [0, 1]. */
|
|
954
|
+
t: number;
|
|
955
|
+
}
|
|
956
|
+
/** A point where two strokes cross or touch, and where it falls on each. */
|
|
957
|
+
interface PathCrossing {
|
|
611
958
|
x: number;
|
|
612
959
|
y: number;
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
960
|
+
a: PathStop;
|
|
961
|
+
b: PathStop;
|
|
962
|
+
}
|
|
963
|
+
/**
|
|
964
|
+
* Every crossing among `paths`: between each pair, and — unless `self` is
|
|
965
|
+
* false — of a path with itself, leaving out the joint where one segment
|
|
966
|
+
* meets the next. Points where strokes merely touch count too. With `of`,
|
|
967
|
+
* only the crossings involving that one path.
|
|
968
|
+
*/
|
|
969
|
+
declare function pathCrossings(paths: readonly Path[], opts?: {
|
|
970
|
+
self?: boolean;
|
|
971
|
+
of?: number;
|
|
972
|
+
}): PathCrossing[];
|
|
973
|
+
|
|
974
|
+
/**
|
|
975
|
+
* Geometric snapping onto paths: the points on a set of strokes a drawn or
|
|
976
|
+
* dragged point can lock to, and which of them a probe lands on.
|
|
977
|
+
*/
|
|
978
|
+
|
|
979
|
+
/**
|
|
980
|
+
* What a snap target is.
|
|
981
|
+
*
|
|
982
|
+
* - `anchor` — an end of a segment: a path's anchors, a box's corners.
|
|
983
|
+
* - `center` — a point a caller names as the middle of something: a text or
|
|
984
|
+
* image box's center, given to {@link createPathSnapIndex} as a target.
|
|
985
|
+
* - `intersection` — where two strokes cross, or one crosses itself.
|
|
986
|
+
* - `tangent` — where a line from the query's origin touches a curve.
|
|
987
|
+
* - `perpendicular` — where a line from the origin meets a stroke square on.
|
|
988
|
+
* - `midpoint` — the middle of a segment by length.
|
|
989
|
+
* - `extremum` — on a curve, where its tangent turns horizontal or vertical.
|
|
990
|
+
* - `quadrant` — where a closed subpath crosses the horizontal and vertical
|
|
991
|
+
* lines through the center of its box: a circle's four compass points.
|
|
992
|
+
* - `nearest` — the closest point on any stroke, when nothing else is in range.
|
|
993
|
+
*/
|
|
994
|
+
type PathSnapKind = 'anchor' | 'center' | 'intersection' | 'tangent' | 'perpendicular' | 'midpoint' | 'extremum' | 'quadrant' | 'nearest';
|
|
995
|
+
/** Every snap kind, in the order a picker lists them. */
|
|
996
|
+
declare const PATH_SNAP_KINDS: readonly PathSnapKind[];
|
|
997
|
+
/** The kinds whose targets stand whatever the probe. */
|
|
998
|
+
type StaticPathSnapKind = 'anchor' | 'center' | 'intersection' | 'midpoint' | 'extremum' | 'quadrant';
|
|
999
|
+
/** A target the probe landed on. */
|
|
1000
|
+
interface PathSnapHit {
|
|
1001
|
+
kind: PathSnapKind;
|
|
1002
|
+
x: number;
|
|
1003
|
+
y: number;
|
|
1004
|
+
/** Distance from the probe, in the query's `radius` units. */
|
|
1005
|
+
distance: number;
|
|
1006
|
+
/** Indices of the paths that make the target: two for a crossing between
|
|
1007
|
+
* paths, one otherwise. */
|
|
1008
|
+
paths: readonly number[];
|
|
1009
|
+
}
|
|
1010
|
+
/** A query for {@link findPathSnap}. */
|
|
1011
|
+
interface PathSnapQuery {
|
|
1012
|
+
/** How far from the probe a target may be, in the paths' units times
|
|
1013
|
+
* `scale`. */
|
|
1014
|
+
radius: number;
|
|
1015
|
+
/** Per-axis scale from the paths' units to the units `radius` is in — a
|
|
1016
|
+
* view's, to measure the radius in screen pixels under any zoom. Default
|
|
1017
|
+
* `{ x: 1, y: 1 }`. */
|
|
1018
|
+
scale?: {
|
|
618
1019
|
x: number;
|
|
619
1020
|
y: number;
|
|
620
1021
|
};
|
|
1022
|
+
/** Kinds to consider. Absent, all of them. */
|
|
1023
|
+
kinds?: Iterable<PathSnapKind>;
|
|
1024
|
+
/** Where the line being drawn starts. Tangent and perpendicular targets are
|
|
1025
|
+
* measured from it, and there are none without it. */
|
|
1026
|
+
origin?: Point;
|
|
1027
|
+
/** Paths by index that offer no targets — the ones a drag is moving. */
|
|
1028
|
+
skip?: (path: number) => boolean;
|
|
1029
|
+
}
|
|
1030
|
+
/** A target that stands whatever the probe: an anchor, a center, a crossing,
|
|
1031
|
+
* a midpoint, an extremum or a quadrant point. */
|
|
1032
|
+
interface PathSnapTarget {
|
|
1033
|
+
kind: StaticPathSnapKind;
|
|
1034
|
+
x: number;
|
|
1035
|
+
y: number;
|
|
1036
|
+
paths: readonly number[];
|
|
621
1037
|
}
|
|
1038
|
+
/** A set of paths, prepared for repeated snapping. Static targets are
|
|
1039
|
+
* computed on first use and kept. */
|
|
1040
|
+
interface PathSnapIndex {
|
|
1041
|
+
readonly paths: readonly Path[];
|
|
1042
|
+
/** Each path's segments. */
|
|
1043
|
+
readonly segments: readonly (readonly PathSegment[])[];
|
|
1044
|
+
/** The targets that do not depend on the probe, of one kind. */
|
|
1045
|
+
targets(kind: StaticPathSnapKind): readonly PathSnapTarget[];
|
|
1046
|
+
}
|
|
1047
|
+
/** Prepare `paths` for {@link findPathSnap}. Build one per set of paths and
|
|
1048
|
+
* reuse it while they stand: a crossing search is quadratic in segments.
|
|
1049
|
+
* `extra` adds targets of the caller's own — the center of a box, a point
|
|
1050
|
+
* with no segment at it — each naming the path it belongs to. */
|
|
1051
|
+
declare function createPathSnapIndex(paths: readonly Path[], extra?: readonly PathSnapTarget[]): PathSnapIndex;
|
|
622
1052
|
/**
|
|
623
|
-
*
|
|
624
|
-
*
|
|
625
|
-
*
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
* exactly on its first point holds that point twice; the two are one anchor,
|
|
629
|
-
* and the curve's second control is that anchor's inHandle. Quadratic segments are upgraded to
|
|
630
|
-
* cubics (each control reused for both adjacent handles) — this loses no
|
|
631
|
-
* geometry. Linear segments produce anchors with no handles.
|
|
632
|
-
*/
|
|
633
|
-
declare function pathToAnchors(path: PolygonPath): {
|
|
634
|
-
anchors: PenAnchor[][];
|
|
635
|
-
closed: boolean[];
|
|
636
|
-
};
|
|
1053
|
+
* The snap target nearest `probe` within `query.radius`, or null when none
|
|
1054
|
+
* is in range. Every enabled kind competes on distance, except `nearest`,
|
|
1055
|
+
* which answers only when no other target is in range.
|
|
1056
|
+
*/
|
|
1057
|
+
declare function findPathSnap(index: PathSnapIndex, probe: Point, query: PathSnapQuery): PathSnapHit | null;
|
|
637
1058
|
/**
|
|
638
|
-
*
|
|
639
|
-
*
|
|
640
|
-
*
|
|
641
|
-
*
|
|
642
|
-
* the anchor point itself (degenerate but valid; renders as a near-line).
|
|
643
|
-
* Given `like`, the path being reshaped, the result keeps its fill rules.
|
|
1059
|
+
* Every snap target within `query.radius` of `probe`, unsorted. `nearest`
|
|
1060
|
+
* hits appear only when no other target is in range. Tangent and perpendicular targets
|
|
1061
|
+
* closer to the origin than the radius are dropped, so a line cannot snap
|
|
1062
|
+
* back onto its own start.
|
|
644
1063
|
*/
|
|
645
|
-
declare function
|
|
1064
|
+
declare function findPathSnaps(index: PathSnapIndex, probe: Point, query: PathSnapQuery): PathSnapHit[];
|
|
1065
|
+
|
|
1066
|
+
/**
|
|
1067
|
+
* Trim: remove the piece of a stroke between the crossings on either side of
|
|
1068
|
+
* a point, as a drafting trim does.
|
|
1069
|
+
*/
|
|
1070
|
+
|
|
1071
|
+
/** Options for {@link trimPathAt}. */
|
|
1072
|
+
interface TrimPathOptions {
|
|
1073
|
+
/** How far from the stroke `probe` may be. Default: any distance. */
|
|
1074
|
+
radius?: number;
|
|
1075
|
+
}
|
|
1076
|
+
/** What {@link trimPathAt} did. */
|
|
1077
|
+
interface TrimResult {
|
|
1078
|
+
/** The path with the piece gone; it has no commands when nothing is left. */
|
|
1079
|
+
path: PolygonPath;
|
|
1080
|
+
/** The piece removed, as an open path. */
|
|
1081
|
+
removed: PolygonPath;
|
|
1082
|
+
}
|
|
646
1083
|
/**
|
|
647
|
-
*
|
|
648
|
-
*
|
|
649
|
-
*
|
|
1084
|
+
* Remove the piece of `path`'s stroke that `probe` is nearest, bounded by the
|
|
1085
|
+
* nearest crossings on either side — with any of `cutters`, or with the path
|
|
1086
|
+
* itself. On an open subpath an end with no crossing before it bounds the
|
|
1087
|
+
* piece too, so a subpath touched only at its ends goes whole; a closed
|
|
1088
|
+
* subpath is opened, and one crossed at a single point is removed whole.
|
|
650
1089
|
*
|
|
651
|
-
*
|
|
652
|
-
*
|
|
653
|
-
*
|
|
654
|
-
*/
|
|
655
|
-
declare function
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
/** The
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
}
|
|
666
|
-
/**
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
*
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
1090
|
+
* Returns null when the probe is further than `radius` from the stroke, or
|
|
1091
|
+
* when nothing crosses or touches the subpath it is on. Curves are split where they are
|
|
1092
|
+
* cut and keep their type; other subpaths are left as they were.
|
|
1093
|
+
*/
|
|
1094
|
+
declare function trimPathAt(path: Path, cutters: readonly Path[], probe: Point, opts?: TrimPathOptions): TrimResult | null;
|
|
1095
|
+
|
|
1096
|
+
/** What stays put of a path while some of its anchors move. */
|
|
1097
|
+
interface PathAwayFromAnchors {
|
|
1098
|
+
/** The segments touching none of the moving anchors, as open runs; a
|
|
1099
|
+
* subpath none of them is on stays as it was. */
|
|
1100
|
+
path: PolygonPath;
|
|
1101
|
+
/** Every anchor that is not moving, a lone one with no segment left at it
|
|
1102
|
+
* included. */
|
|
1103
|
+
anchors: Point[];
|
|
1104
|
+
}
|
|
1105
|
+
/**
|
|
1106
|
+
* The part of `path` that holds still while the anchors at `moving` (flat
|
|
1107
|
+
* indices, as anchor editing numbers them) are dragged: every segment with a
|
|
1108
|
+
* moving anchor at either end is dropped, and so are the moving anchors.
|
|
1109
|
+
*/
|
|
1110
|
+
declare function pathAwayFromAnchors(path: PolygonPath, moving: Iterable<number>): PathAwayFromAnchors;
|
|
1111
|
+
|
|
1112
|
+
/**
|
|
1113
|
+
* Growing an open end of a path along its tangent: by a distance, or until it
|
|
1114
|
+
* meets another stroke.
|
|
1115
|
+
*/
|
|
1116
|
+
|
|
1117
|
+
/** One end of an open subpath. `sub` counts subpaths as the path's anchor set
|
|
1118
|
+
* (`pathToAnchors`) does, a bare `M` included. */
|
|
1119
|
+
interface OpenPathEnd {
|
|
674
1120
|
sub: number;
|
|
675
|
-
|
|
676
|
-
|
|
1121
|
+
end: 'first' | 'last';
|
|
1122
|
+
}
|
|
1123
|
+
/** Every end of every open subpath of `path` that has a direction to grow in. */
|
|
1124
|
+
declare function openPathEnds(path: Path): OpenPathEnd[];
|
|
1125
|
+
/** Where `end` sits and the unit direction it points out along, or null when
|
|
1126
|
+
* it is no open end or has no direction there. */
|
|
1127
|
+
declare function openEndRay(path: Path, end: OpenPathEnd): {
|
|
1128
|
+
at: Point;
|
|
1129
|
+
dir: Point;
|
|
677
1130
|
} | null;
|
|
1131
|
+
/**
|
|
1132
|
+
* `path` with `end` carried `distance` further along its tangent, by
|
|
1133
|
+
* `lengthenPathEnd` in `'tangent'` mode: a straight end segment grows longer,
|
|
1134
|
+
* and a curved one gains a straight segment, which keeps the tangent
|
|
1135
|
+
* continuous. Null when the end is not open or has no direction, or
|
|
1136
|
+
* `distance` is not positive.
|
|
1137
|
+
*/
|
|
1138
|
+
declare function lengthenOpenEnd(path: Path, end: OpenPathEnd, distance: number): PolygonPath | null;
|
|
1139
|
+
/** Options for {@link extendToMeet}. */
|
|
1140
|
+
interface ExtendToMeetOptions {
|
|
1141
|
+
/** The furthest the end may travel. Default: as far as any stroke reaches. */
|
|
1142
|
+
maxDistance?: number;
|
|
1143
|
+
}
|
|
1144
|
+
/**
|
|
1145
|
+
* Extend `end` of `path` along its tangent to the first stroke it meets —
|
|
1146
|
+
* one of `boundaries`, or `path`'s own other segments. Returns the extended
|
|
1147
|
+
* path, the point it now ends at and how far it went, or null when the
|
|
1148
|
+
* tangent meets nothing.
|
|
1149
|
+
*/
|
|
1150
|
+
declare function extendToMeet(path: Path, boundaries: readonly Path[], end: OpenPathEnd, opts?: ExtendToMeetOptions): {
|
|
1151
|
+
path: PolygonPath;
|
|
1152
|
+
at: Point;
|
|
1153
|
+
distance: number;
|
|
1154
|
+
} | null;
|
|
1155
|
+
|
|
1156
|
+
/**
|
|
1157
|
+
* Grow or trim an open subpath at one of its ends. Lengthen drags this, and
|
|
1158
|
+
* Extend to next path reaches it through `lengthenOpenEnd`.
|
|
1159
|
+
*
|
|
1160
|
+
* A positive distance extends the end outward: straight along the end tangent,
|
|
1161
|
+
* or along a circular arc with the curvature the end has, which meets the path
|
|
1162
|
+
* with matching direction and curvature. A straight end segment is lengthened
|
|
1163
|
+
* in place; a curved one is continued with a new segment. A negative distance
|
|
1164
|
+
* trims the path back along itself by arc length, whichever way it would have
|
|
1165
|
+
* grown.
|
|
1166
|
+
*
|
|
1167
|
+
* The arc rather than extrapolating the end cubic past t = 1: a cubic's
|
|
1168
|
+
* leading term takes over beyond its range, so a continued curve swings off
|
|
1169
|
+
* and curls on itself within a segment's length, while the arc keeps the
|
|
1170
|
+
* curvature the end shows for as long as it is drawn.
|
|
1171
|
+
*/
|
|
1172
|
+
|
|
1173
|
+
/** How `lengthenPathEnd` grows an end: straight on, or bending as the end bends. */
|
|
1174
|
+
type LengthenMode = 'tangent' | 'curvature';
|
|
1175
|
+
/** Where an end is, which way it heads out of the path, and how it bends there. */
|
|
1176
|
+
interface PathEndFrame {
|
|
1177
|
+
point: Point;
|
|
1178
|
+
/** Unit vector pointing out of the path. */
|
|
1179
|
+
tangent: Point;
|
|
1180
|
+
/** Signed curvature along `tangent`: positive turns toward `(-tangent.y, tangent.x)`. */
|
|
1181
|
+
curvature: number;
|
|
1182
|
+
}
|
|
1183
|
+
/** The end of an open subpath that the anchor at `flatIndex` is, or null when it is
|
|
1184
|
+
* an inner anchor, on a closed subpath, or alone in its subpath. */
|
|
1185
|
+
declare function openEndAt(set: AnchorSet, flatIndex: number): OpenPathEnd | null;
|
|
1186
|
+
/** Flat index of the anchor at `end`, or -1 when there is none. */
|
|
1187
|
+
declare function pathEndAnchorIndex(set: AnchorSet, end: OpenPathEnd): number;
|
|
1188
|
+
/** The frame at `end`, or null when it is not the end of an open subpath of two or
|
|
1189
|
+
* more anchors, or the path has no direction there. */
|
|
1190
|
+
declare function pathEndFrame(set: AnchorSet, end: OpenPathEnd): PathEndFrame | null;
|
|
1191
|
+
/**
|
|
1192
|
+
* Lengthen `end` by `distance` (see the module comment), in place. A curvature arc
|
|
1193
|
+
* stops at one full turn. Returns false when `end` is not the end of an open
|
|
1194
|
+
* subpath or nothing changed.
|
|
1195
|
+
*/
|
|
1196
|
+
declare function lengthenPathEnd(set: AnchorSet, end: OpenPathEnd, distance: number, mode: LengthenMode): boolean;
|
|
1197
|
+
/**
|
|
1198
|
+
* The distance `lengthenPathEnd` takes for its new end to land nearest `point`: the
|
|
1199
|
+
* point projected onto the end tangent, or for a curvature lengthening, measured
|
|
1200
|
+
* around the circle of curvature. A measurement around the circle can name the
|
|
1201
|
+
* same spot a turn apart; it answers the one nearest `near`, so a drag passing
|
|
1202
|
+
* half a turn keeps going instead of jumping back.
|
|
1203
|
+
*/
|
|
1204
|
+
declare function lengthToward(set: AnchorSet, end: OpenPathEnd, mode: LengthenMode, point: Point, near?: number): number;
|
|
678
1205
|
|
|
679
1206
|
/**
|
|
680
1207
|
* Controls for the one cubic that replaces `prev → removed → next` when
|
|
@@ -685,8 +1212,8 @@ declare function nearestSegmentT(anchors: PenAnchor[][], wx: number, wy: number,
|
|
|
685
1212
|
* cubic, the original cubic comes back.
|
|
686
1213
|
*/
|
|
687
1214
|
declare function fitCubicThroughDeletion(prev: PenAnchor, removed: PenAnchor, next: PenAnchor): {
|
|
688
|
-
c1: Point
|
|
689
|
-
c2: Point
|
|
1215
|
+
c1: Point;
|
|
1216
|
+
c2: Point;
|
|
690
1217
|
};
|
|
691
1218
|
|
|
692
1219
|
/**
|
|
@@ -698,7 +1225,7 @@ declare function fitCubicThroughDeletion(prev: PenAnchor, removed: PenAnchor, ne
|
|
|
698
1225
|
* `C` cubic segments. For colinear / two-point inputs, returns a single
|
|
699
1226
|
* degenerate cubic. For empty input, returns an empty polygon path.
|
|
700
1227
|
*/
|
|
701
|
-
declare function schneiderFit(samples: ReadonlyArray<Point
|
|
1228
|
+
declare function schneiderFit(samples: ReadonlyArray<Point>, errorTolerance: number): PolygonPath;
|
|
702
1229
|
/**
|
|
703
1230
|
* The single cubic from the first sample to the last that best fits the
|
|
704
1231
|
* samples between, with its control points held to the given unit tangents:
|
|
@@ -709,12 +1236,12 @@ declare function schneiderFit(samples: ReadonlyArray<Point$1>, errorTolerance: n
|
|
|
709
1236
|
* omitted; `passes` is how many times those are refined and the lengths
|
|
710
1237
|
* solved again.
|
|
711
1238
|
*/
|
|
712
|
-
declare function fitCubicWithTangents(samples: ReadonlyArray<Point
|
|
1239
|
+
declare function fitCubicWithTangents(samples: ReadonlyArray<Point>, tStart: Point, tEnd: Point, opts?: {
|
|
713
1240
|
params?: ReadonlyArray<number>;
|
|
714
1241
|
passes?: number;
|
|
715
1242
|
}): {
|
|
716
|
-
cp1: Point
|
|
717
|
-
cp2: Point
|
|
1243
|
+
cp1: Point;
|
|
1244
|
+
cp2: Point;
|
|
718
1245
|
};
|
|
719
1246
|
|
|
720
1247
|
/** Options for {@link simplifyPath}. */
|
|
@@ -734,195 +1261,139 @@ interface SimplifyPathOptions {
|
|
|
734
1261
|
* becomes one straight segment. Fill rules carry over.
|
|
735
1262
|
*/
|
|
736
1263
|
declare function simplifyPath(path: PolygonPath, tolerance: number, opts?: SimplifyPathOptions): PolygonPath;
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
*
|
|
742
|
-
*
|
|
743
|
-
*
|
|
744
|
-
*
|
|
745
|
-
*
|
|
746
|
-
*
|
|
747
|
-
*
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
*/
|
|
752
|
-
interface
|
|
753
|
-
|
|
754
|
-
|
|
1264
|
+
/** One subpath of {@link simplifyPath}: its anchors refitted, corners and
|
|
1265
|
+
* open ends kept. */
|
|
1266
|
+
declare function simplifySubpath(sub: PenAnchor[], closed: boolean, tolerance: number, opts?: SimplifyPathOptions): PenAnchor[];
|
|
1267
|
+
/**
|
|
1268
|
+
* The anchors of `sub` from index `from` to `to`, refitted the way
|
|
1269
|
+
* {@link simplifyPath} refits a subpath: as few as hold the span within
|
|
1270
|
+
* `tolerance`, corners inside it kept. Indices run modulo the subpath's
|
|
1271
|
+
* length, so on a closed subpath `to` may pass its end and wrap; the span is
|
|
1272
|
+
* shorter than one full turn. The two end anchors stay where they are and
|
|
1273
|
+
* keep their handles facing out of the span. Answers the anchors from `from`
|
|
1274
|
+
* to `to`, both included, to splice in place of the originals.
|
|
1275
|
+
*/
|
|
1276
|
+
declare function simplifySpan(sub: PenAnchor[], closed: boolean, from: number, to: number, tolerance: number, opts?: SimplifyPathOptions): PenAnchor[];
|
|
1277
|
+
|
|
1278
|
+
/** Options for {@link growRegion}. */
|
|
1279
|
+
interface GrowRegionOptions {
|
|
1280
|
+
/** How a convex corner turns. `'miter'` keeps it sharp, as a pseudo-distance
|
|
1281
|
+
* field draws it; `'round'` follows the true distance. Default `'miter'`. */
|
|
1282
|
+
join?: 'miter' | 'round';
|
|
1283
|
+
/** Past this ratio of miter length to distance a miter corner is beveled.
|
|
1284
|
+
* Default 4. */
|
|
1285
|
+
miterLimit?: number;
|
|
1286
|
+
/** How far a grown curve may stray from the true offset, in the path's
|
|
1287
|
+
* units. Default 0.1. */
|
|
1288
|
+
tolerance?: number;
|
|
755
1289
|
}
|
|
756
|
-
/** One screen-pixel length as world-space extents, per axis. `scale` is a
|
|
757
|
-
* view's, so neither axis is zero (see `View`).
|
|
758
|
-
*
|
|
759
|
-
* With `rotation`, the axes are a frame turned that far from world, and each
|
|
760
|
-
* extent is how far along it an edge across it must move to move `px` on
|
|
761
|
-
* screen — which, under non-uniform zoom, is not the extent along the screen
|
|
762
|
-
* axis nearest to it. */
|
|
763
|
-
declare function pxExtent(px: number, scale: Scale2, rotation?: number): {
|
|
764
|
-
x: number;
|
|
765
|
-
y: number;
|
|
766
|
-
};
|
|
767
|
-
/** World delta → screen delta. Only the scale participates: translation
|
|
768
|
-
* cancels in a difference, and the kit's views carry no skew. */
|
|
769
|
-
declare function scaleDelta(dx: number, dy: number, scale: Scale2): {
|
|
770
|
-
x: number;
|
|
771
|
-
y: number;
|
|
772
|
-
};
|
|
773
1290
|
/**
|
|
774
|
-
*
|
|
1291
|
+
* The region `path` fills under `'nonzero'`, grown by `distance` (> 0), as a
|
|
1292
|
+
* path that fills it under `'nonzero'`. Every subpath counts as closed. Each
|
|
1293
|
+
* contour is replaced by its offset, so where grown parts meet the contours
|
|
1294
|
+
* overlap rather than merge, and a hole grown shut winds back on itself and
|
|
1295
|
+
* fills. At an inside corner the two offset edges are cut back to where they
|
|
1296
|
+
* cross; where they do not, the gap is passed through the corner's original
|
|
1297
|
+
* point, which closes it with a loop inside the fill.
|
|
775
1298
|
*
|
|
776
|
-
*
|
|
777
|
-
*
|
|
778
|
-
*
|
|
779
|
-
*
|
|
780
|
-
*/
|
|
781
|
-
declare function
|
|
782
|
-
|
|
783
|
-
|
|
1299
|
+
* What it costs: one segment per curve, more where `tolerance` needs the curve
|
|
1300
|
+
* split; a miter corner between two straight edges costs nothing, one beside
|
|
1301
|
+
* a curve gains an anchor or two, a round corner an arc, and an inside corner
|
|
1302
|
+
* whose edges do not cross two.
|
|
1303
|
+
*/
|
|
1304
|
+
declare function growRegion(path: Path, distance: number, opts?: GrowRegionOptions): PolygonPath;
|
|
1305
|
+
|
|
1306
|
+
/**
|
|
1307
|
+
* Simplify only where `flatIndexes` say: each unbroken run of those anchors
|
|
1308
|
+
* along a subpath is refitted as one span by the fitter {@link simplifyPath}
|
|
1309
|
+
* uses (`simplifySpan`), so only anchors the shape does not need, within
|
|
1310
|
+
* `tolerance`, go. A run's first and last anchors stay, and every anchor
|
|
1311
|
+
* outside a run is left as it was. A closed subpath named whole is simplified
|
|
1312
|
+
* whole. Answers whether any anchor went; a run the fit cannot thin is left
|
|
1313
|
+
* untouched.
|
|
1314
|
+
*/
|
|
1315
|
+
declare function simplifyAnchorsAt(set: AnchorSet, flatIndexes: Iterable<number>, tolerance: number, opts?: SimplifyPathOptions): boolean;
|
|
1316
|
+
|
|
1317
|
+
/**
|
|
1318
|
+
* Resample: a path's anchors spread evenly along it by arc length, and its
|
|
1319
|
+
* curves refitted through them.
|
|
1320
|
+
*/
|
|
1321
|
+
|
|
1322
|
+
/** Options for {@link resamplePath}. */
|
|
1323
|
+
interface ResamplePathOptions {
|
|
1324
|
+
/** How many anchors the result holds across all its subpaths. Default: as
|
|
1325
|
+
* many as `path` has. Ignored when `spacing` is given. */
|
|
1326
|
+
count?: number;
|
|
1327
|
+
/** The distance along the path between neighboring anchors, in path units.
|
|
1328
|
+
* Each run between fixed anchors is cut into the whole number of equal
|
|
1329
|
+
* pieces nearest this. */
|
|
1330
|
+
spacing?: number;
|
|
1331
|
+
/** Keep every corner anchor (`isAnchorSmooth` false) where it is, with its
|
|
1332
|
+
* corner, and resample the runs between. Default `true`. Open ends are
|
|
1333
|
+
* kept either way. */
|
|
1334
|
+
keepCorners?: boolean;
|
|
1335
|
+
/** How far the result may stray from the original, in path units. A piece
|
|
1336
|
+
* that cannot follow the original this closely is halved, so the result can
|
|
1337
|
+
* hold more anchors than `count` asks for. Default 0.5. */
|
|
1338
|
+
tolerance?: number;
|
|
1339
|
+
}
|
|
784
1340
|
/**
|
|
785
|
-
*
|
|
786
|
-
*
|
|
787
|
-
*
|
|
788
|
-
*
|
|
789
|
-
*
|
|
790
|
-
*
|
|
791
|
-
* than `px`. Returns the point in world coords and the on-screen unit normal.
|
|
1341
|
+
* `path` with its anchors spread evenly along each run between fixed anchors
|
|
1342
|
+
* ({@link ResamplePathOptions}), each new anchor heading the way the original
|
|
1343
|
+
* does there. Anchors that were smooth stay smooth, and the curves between
|
|
1344
|
+
* are fitted to the original. A closed subpath with no fixed anchor keeps
|
|
1345
|
+
* its first one as the place the even spacing starts from. Fill rules carry
|
|
1346
|
+
* over.
|
|
792
1347
|
*/
|
|
793
|
-
declare function
|
|
794
|
-
x: number;
|
|
795
|
-
y: number;
|
|
796
|
-
}, normal: {
|
|
797
|
-
x: number;
|
|
798
|
-
y: number;
|
|
799
|
-
}, px: number, scale: Scale2): {
|
|
800
|
-
x: number;
|
|
801
|
-
y: number;
|
|
802
|
-
nx: number;
|
|
803
|
-
ny: number;
|
|
804
|
-
};
|
|
805
|
-
/** The screen angle a frame turned `rotation` from world lands its x axis at.
|
|
806
|
-
* Equals `rotation` under uniform zoom; non-uniform zoom bends it. */
|
|
807
|
-
declare function screenAngleOf(rotation: number, scale: Scale2): number;
|
|
1348
|
+
declare function resamplePath(path: PolygonPath, opts?: ResamplePathOptions): PolygonPath;
|
|
808
1349
|
|
|
1350
|
+
/** The parameters in (0, 1) where the segment from `a` to `b` turns in x or
|
|
1351
|
+
* y, ascending, or none for a straight segment. */
|
|
1352
|
+
declare function segmentExtremaTs(a: PenAnchor, b: PenAnchor): number[];
|
|
809
1353
|
/**
|
|
810
|
-
*
|
|
811
|
-
*
|
|
812
|
-
*
|
|
813
|
-
*
|
|
814
|
-
*
|
|
815
|
-
* Callers address anchors by flat index — the sequential position in walk
|
|
816
|
-
* order across all subpaths, which is what `enumerateAnchors` reports.
|
|
817
|
-
* {@link locateAnchor} and {@link flatAnchorIndex} convert to and from the
|
|
818
|
-
* `(sub, idx)` pair.
|
|
819
|
-
*
|
|
820
|
-
* The two orders agree because `pathToAnchors` and `enumerateAnchors`
|
|
821
|
-
* walk the same command stream and emit one anchor per M/L/C/Q, less the
|
|
822
|
-
* end of a closing curve that lands on its subpath's first point.
|
|
823
|
-
* `countPathAnchors`, which sizes the renderer's per-anchor arrays, counts
|
|
824
|
-
* that end too and so can be one higher per closed subpath.
|
|
1354
|
+
* Split every curved segment of `set` at its extremes
|
|
1355
|
+
* ({@link segmentExtremaTs}), in place. `include(sub, segIdx)` limits it to
|
|
1356
|
+
* some segments, named as `segmentEnds` names them; absent, every one.
|
|
1357
|
+
* Returns the new anchors' flat indices in the edited set. Each new anchor is
|
|
1358
|
+
* smooth, and every anchor after one moves up an index.
|
|
825
1359
|
*/
|
|
1360
|
+
declare function addExtremaAnchors(set: AnchorSet, include?: (sub: number, segIdx: number) => boolean): number[];
|
|
826
1361
|
|
|
827
|
-
/** Subpath-major anchor model — the decoded form of a `PolygonPath`. */
|
|
828
|
-
interface AnchorSet {
|
|
829
|
-
anchors: PenAnchor[][];
|
|
830
|
-
closed: boolean[];
|
|
831
|
-
}
|
|
832
|
-
/** A world-space rectangle, as produced by a drag-rect gesture. */
|
|
833
|
-
interface AnchorRect {
|
|
834
|
-
x: number;
|
|
835
|
-
y: number;
|
|
836
|
-
width: number;
|
|
837
|
-
height: number;
|
|
838
|
-
}
|
|
839
|
-
/** Total anchors across every subpath. */
|
|
840
|
-
declare function anchorCount(set: AnchorSet): number;
|
|
841
|
-
/** Flat index → `(sub, idx)`. Returns null when out of range. */
|
|
842
|
-
declare function locateAnchor(set: AnchorSet, flatIndex: number): {
|
|
843
|
-
sub: number;
|
|
844
|
-
idx: number;
|
|
845
|
-
} | null;
|
|
846
|
-
/** `(sub, idx)` → flat index. Returns -1 when out of range. */
|
|
847
|
-
declare function flatAnchorIndex(set: AnchorSet, sub: number, idx: number): number;
|
|
848
|
-
/** Resolve a flat index to the anchor itself. Null when out of range. */
|
|
849
|
-
declare function anchorAt(set: AnchorSet, flatIndex: number): PenAnchor | null;
|
|
850
|
-
/**
|
|
851
|
-
* Decode `path`, hand the mutable anchor set to `edit`, and re-encode.
|
|
852
|
-
* Returns null when `edit` returns `false` (it changed nothing), so callers
|
|
853
|
-
* can skip a no-op commit.
|
|
854
|
-
*/
|
|
855
|
-
declare function editAnchorSet(path: PolygonPath, edit: (set: AnchorSet) => boolean | void): PolygonPath | null;
|
|
856
|
-
/** Translate an anchor and both of its handles by `(dx, dy)`. */
|
|
857
|
-
declare function translateAnchorBy(set: AnchorSet, flatIndex: number, dx: number, dy: number): boolean;
|
|
858
1362
|
/**
|
|
859
|
-
*
|
|
860
|
-
*
|
|
861
|
-
*
|
|
862
|
-
|
|
863
|
-
declare function moveHandleTo(set: AnchorSet, flatIndex: number, side: 'in' | 'out', toX: number, toY: number, breakSmoothness: boolean): boolean;
|
|
864
|
-
/**
|
|
865
|
-
* Split the segment `(sub, segIdx) → (sub, segIdx + 1)` at parameter `t`,
|
|
866
|
-
* inserting a new anchor there. On a closed subpath `segIdx` may also name
|
|
867
|
-
* the closing segment (`sub.length - 1`); its new anchor is appended.
|
|
868
|
-
*
|
|
869
|
-
* A straight segment stays straight — the new anchor has no handles. A curved
|
|
870
|
-
* one splits by de Casteljau, so the two halves trace the original path.
|
|
1363
|
+
* Anchor selections walked along the path: grown or shrunk by one anchor,
|
|
1364
|
+
* every Nth anchor, anchors by kind, and the complement. Each takes the
|
|
1365
|
+
* decoded set and a selection as flat indices, and returns a new selection
|
|
1366
|
+
* as sorted flat indices; none of them edits the set.
|
|
871
1367
|
*
|
|
872
|
-
*
|
|
873
|
-
*
|
|
1368
|
+
* "Along the path" means within a subpath: an anchor's neighbors are the
|
|
1369
|
+
* anchors before and after it there, and a closed subpath's first and last
|
|
1370
|
+
* anchors are neighbors.
|
|
874
1371
|
*/
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
t: number;
|
|
879
|
-
}): number;
|
|
880
|
-
/** A point on a segment, as {@link segmentAt} reports it. */
|
|
881
|
-
interface SegmentHit {
|
|
882
|
-
sub: number;
|
|
883
|
-
segIdx: number;
|
|
884
|
-
/** Parameter on the segment — what {@link insertAnchorOnSegment} takes. */
|
|
885
|
-
t: number;
|
|
886
|
-
/** The point on the path at `t`, in the set's own space. */
|
|
887
|
-
x: number;
|
|
888
|
-
y: number;
|
|
889
|
-
}
|
|
890
|
-
/**
|
|
891
|
-
* The segment point under `(x, y)`, when it lies within `tolerancePx` of
|
|
892
|
-
* the path on screen and no nearer than that to either of the segment's
|
|
893
|
-
* own anchors — a press on an anchor is about the anchor, not the segment
|
|
894
|
-
* beside it.
|
|
895
|
-
*
|
|
896
|
-
* `scale` is the view's, so the tolerance holds per axis under
|
|
897
|
-
* non-uniform zoom. The search runs in screen-scaled space: scaling is
|
|
898
|
-
* affine, so the curve's parameterization, and therefore `t`, carries
|
|
899
|
-
* straight back to world space.
|
|
900
|
-
*/
|
|
901
|
-
declare function segmentAt(set: AnchorSet, x: number, y: number, opts: {
|
|
902
|
-
tolerancePx: number;
|
|
903
|
-
scale?: Scale2;
|
|
904
|
-
}): SegmentHit | null;
|
|
1372
|
+
|
|
1373
|
+
/** `selected` with each selected anchor's neighbors along the path added. */
|
|
1374
|
+
declare function growAnchorSelection(set: AnchorSet, selected: Iterable<number>): number[];
|
|
905
1375
|
/**
|
|
906
|
-
*
|
|
907
|
-
*
|
|
908
|
-
*
|
|
909
|
-
* so the path keeps its shape; a gap between two straight segments closes straight.
|
|
910
|
-
*
|
|
911
|
-
* Subpaths left with fewer than two anchors are dropped entirely. If that
|
|
912
|
-
* would leave the path with no subpaths at all, the whole deletion is refused
|
|
913
|
-
* (returns false, `set` untouched): an empty path leaves the node selected
|
|
914
|
-
* and in the scene with nothing on screen and no anchors to grab it by.
|
|
1376
|
+
* `selected` less every anchor at the edge of a selected run: one with a
|
|
1377
|
+
* neighbor that is unselected, or none on one side, as an open subpath's ends
|
|
1378
|
+
* have. A closed subpath selected all the way round has no edge and stays.
|
|
915
1379
|
*/
|
|
916
|
-
declare function
|
|
1380
|
+
declare function shrinkAnchorSelection(set: AnchorSet, selected: Iterable<number>): number[];
|
|
917
1381
|
/**
|
|
918
|
-
*
|
|
919
|
-
*
|
|
920
|
-
*
|
|
921
|
-
*
|
|
1382
|
+
* Every `n`th anchor along each subpath, counting from its first selected
|
|
1383
|
+
* anchor. With nothing selected, every subpath counts from its first anchor;
|
|
1384
|
+
* otherwise only subpaths holding a selected anchor take part. A closed
|
|
1385
|
+
* subpath is walked once round, so the count does not wrap onto itself.
|
|
922
1386
|
*/
|
|
923
|
-
declare function
|
|
924
|
-
/**
|
|
925
|
-
declare function
|
|
1387
|
+
declare function everyNthAnchor(set: AnchorSet, n: number, selected?: Iterable<number>): number[];
|
|
1388
|
+
/** Every anchor `keep` says yes to. */
|
|
1389
|
+
declare function anchorsWhere(set: AnchorSet, keep: (anchor: PenAnchor) => boolean): number[];
|
|
1390
|
+
/** Every corner anchor: one whose handles are not collinear through it, or
|
|
1391
|
+
* that lacks one (`isAnchorSmooth` false). */
|
|
1392
|
+
declare function cornerAnchors(set: AnchorSet): number[];
|
|
1393
|
+
/** Every smooth anchor (`isAnchorSmooth`). */
|
|
1394
|
+
declare function smoothAnchors(set: AnchorSet): number[];
|
|
1395
|
+
/** Every anchor `selected` leaves out. */
|
|
1396
|
+
declare function invertAnchorSelection(set: AnchorSet, selected: Iterable<number>): number[];
|
|
926
1397
|
|
|
927
1398
|
/**
|
|
928
1399
|
* Average and Join: anchor-set edits that bring anchors together. Both mutate
|
|
@@ -939,6 +1410,13 @@ interface SubpathEnd {
|
|
|
939
1410
|
sub: number;
|
|
940
1411
|
end: 'first' | 'last';
|
|
941
1412
|
}
|
|
1413
|
+
/** How {@link joinSubpathEnds} spans the gap between two ends apart. */
|
|
1414
|
+
interface JoinOptions {
|
|
1415
|
+
/** Absent, a straight segment. Given, a curve leaving each end along the
|
|
1416
|
+
* direction its path was heading there, each handle `tension` times the
|
|
1417
|
+
* gap long; `0` is a straight segment. */
|
|
1418
|
+
tension?: number;
|
|
1419
|
+
}
|
|
942
1420
|
/**
|
|
943
1421
|
* Move each anchor in `flatIndexes` to their mean position, along `axis`.
|
|
944
1422
|
* Each anchor carries its handles with it. Returns false, changing nothing,
|
|
@@ -953,19 +1431,71 @@ declare function subpathEndAt(set: AnchorSet, flatIndex: number): SubpathEnd | n
|
|
|
953
1431
|
* close it; ends of two subpaths make one subpath, `a`'s run followed by
|
|
954
1432
|
* `b`'s, in the slot of whichever came first. Ends that coincide merge into
|
|
955
1433
|
* one anchor, keeping the handle on either side; ends apart are bridged by a
|
|
956
|
-
* straight segment
|
|
957
|
-
*
|
|
1434
|
+
* straight segment, or with `options.tension` by a curve meeting each end
|
|
1435
|
+
* tangentially. Returns false, changing nothing, when the ends are not two
|
|
1436
|
+
* distinct ends of open subpaths.
|
|
958
1437
|
*/
|
|
959
|
-
declare function joinSubpathEnds(set: AnchorSet, a: SubpathEnd, b: SubpathEnd): boolean;
|
|
1438
|
+
declare function joinSubpathEnds(set: AnchorSet, a: SubpathEnd, b: SubpathEnd, options?: JoinOptions): boolean;
|
|
960
1439
|
/** {@link joinSubpathEnds} for two anchors named by flat index, each the end
|
|
961
1440
|
* of an open subpath. */
|
|
962
|
-
declare function joinAnchorsAt(set: AnchorSet, flatA: number, flatB: number): boolean;
|
|
1441
|
+
declare function joinAnchorsAt(set: AnchorSet, flatA: number, flatB: number, options?: JoinOptions): boolean;
|
|
963
1442
|
/**
|
|
964
1443
|
* The two open-subpath ends nearest each other that `accept` allows, on two
|
|
965
1444
|
* different subpaths. Null when there are no two such subpaths.
|
|
966
1445
|
*/
|
|
967
1446
|
declare function closestOpenEnds(set: AnchorSet, accept?: (a: SubpathEnd, b: SubpathEnd) => boolean): [SubpathEnd, SubpathEnd] | null;
|
|
968
1447
|
|
|
1448
|
+
/**
|
|
1449
|
+
* Spiro curves as cubic paths, and back. A solved curve is written as cubics,
|
|
1450
|
+
* each spiral segment split into as many as it takes to stay within tolerance,
|
|
1451
|
+
* so most anchors of the path are not spiro points. `at` records which are:
|
|
1452
|
+
* `at[i]` is the flat anchor index of point `i`, counted across subpaths. The
|
|
1453
|
+
* points are then read back out of the path itself, so whatever moves the path
|
|
1454
|
+
* — a move, a resize, a rotation — moves them with it.
|
|
1455
|
+
*/
|
|
1456
|
+
|
|
1457
|
+
/** One subpath of a spiro curve: its points, and whether it closes. */
|
|
1458
|
+
interface SpiroContour {
|
|
1459
|
+
points: SpiroPoint[];
|
|
1460
|
+
closed: boolean;
|
|
1461
|
+
}
|
|
1462
|
+
/** A spiro curve written as a cubic path, with the anchor each point became. */
|
|
1463
|
+
interface SpiroPath {
|
|
1464
|
+
path: PolygonPath;
|
|
1465
|
+
/** The flat anchor index of each point, in contour order. */
|
|
1466
|
+
at: number[];
|
|
1467
|
+
}
|
|
1468
|
+
/** Options for {@link spiroToPath}. */
|
|
1469
|
+
interface SpiroToPathOptions {
|
|
1470
|
+
/** The furthest a cubic may stray from its spiral, as a fraction of that
|
|
1471
|
+
* segment's arc length. Default `1e-4`. */
|
|
1472
|
+
tolerance?: number;
|
|
1473
|
+
/** The path being reshaped, whose fill rules the result keeps. */
|
|
1474
|
+
like?: PolygonPath;
|
|
1475
|
+
}
|
|
1476
|
+
/**
|
|
1477
|
+
* Solve each contour and write it as a cubic path. Straight segments carry no
|
|
1478
|
+
* handles.
|
|
1479
|
+
*/
|
|
1480
|
+
declare function spiroToPath(contours: readonly SpiroContour[], options?: SpiroToPathOptions): SpiroPath;
|
|
1481
|
+
/**
|
|
1482
|
+
* The spiro points `path` holds, given the kind of each and the anchor each
|
|
1483
|
+
* became. Null when `kinds` and `at` do not describe `path`: the counts
|
|
1484
|
+
* differ, an index is out of order or out of range, or a subpath does not
|
|
1485
|
+
* start on a point.
|
|
1486
|
+
*/
|
|
1487
|
+
declare function spiroContoursOf(path: PolygonPath, kinds: readonly SpiroKind[], at: readonly number[]): SpiroContour[] | null;
|
|
1488
|
+
/** The straight-sided path through each contour's points: what an editor
|
|
1489
|
+
* shows and moves in place of the curve. */
|
|
1490
|
+
declare function spiroControlPath(contours: readonly SpiroContour[]): PolygonPath;
|
|
1491
|
+
/**
|
|
1492
|
+
* Read an edited control path back as contours: every anchor is a point.
|
|
1493
|
+
* Kinds follow from `before`, the contours the edit started from: point for
|
|
1494
|
+
* point when the count is unchanged, else by position, with an anchor that
|
|
1495
|
+
* lands nowhere a point was taking `fallback`. Handles are ignored.
|
|
1496
|
+
*/
|
|
1497
|
+
declare function spiroContoursFromControl(control: PolygonPath, before: readonly SpiroContour[], fallback?: SpiroKind): SpiroContour[];
|
|
1498
|
+
|
|
969
1499
|
/**
|
|
970
1500
|
* Path hit-testing: path-vs-point (filled region and stroke distance),
|
|
971
1501
|
* path-vs-rect, and path-vs-polygon in both directions.
|
|
@@ -1020,15 +1550,15 @@ declare function pathContainsRect(path: Path, rect: Rect, opts?: PointInPathOpti
|
|
|
1020
1550
|
/** Returns true if `rect` overlaps (intersects or contains) `path`. */
|
|
1021
1551
|
declare function pathIntersectsRect(path: Path, rect: Rect, opts?: PointInPathOptions): boolean;
|
|
1022
1552
|
/** Returns true if every vertex of `polygon` lies inside `path`. */
|
|
1023
|
-
declare function pathContainsPolygon(path: Path, polygon: readonly Point
|
|
1553
|
+
declare function pathContainsPolygon(path: Path, polygon: readonly Point[], opts?: PointInPathOptions): boolean;
|
|
1024
1554
|
/** Returns true if `polygon` overlaps (intersects or is contained by) `path`. */
|
|
1025
|
-
declare function pathIntersectsPolygon(path: Path, polygon: readonly Point
|
|
1555
|
+
declare function pathIntersectsPolygon(path: Path, polygon: readonly Point[], opts?: PointInPathOptions): boolean;
|
|
1026
1556
|
/**
|
|
1027
1557
|
* Returns true if all of `path` — every subpath, open ones included, beziers
|
|
1028
1558
|
* flattened — lies inside the closed `polygon`: the inverse of
|
|
1029
1559
|
* {@link pathContainsPolygon}. A lasso enclosing a shape asks this.
|
|
1030
1560
|
*/
|
|
1031
|
-
declare function polygonContainsPath(polygon: readonly Point
|
|
1561
|
+
declare function polygonContainsPath(polygon: readonly Point[], path: Path, opts?: PointInPathOptions): boolean;
|
|
1032
1562
|
/**
|
|
1033
1563
|
* Returns true if any of `path` meets the closed `polygon`: its filled region,
|
|
1034
1564
|
* or the line of an open subpath, which encloses nothing. With `filled: false`
|
|
@@ -1036,7 +1566,16 @@ declare function polygonContainsPath(polygon: readonly Point$1[], path: Path, op
|
|
|
1036
1566
|
* flattened, so a control point off the curve never counts. The companion of
|
|
1037
1567
|
* {@link polygonContainsPath}; a lasso touching a shape asks this.
|
|
1038
1568
|
*/
|
|
1039
|
-
declare function polygonIntersectsPath(polygon: readonly Point
|
|
1569
|
+
declare function polygonIntersectsPath(polygon: readonly Point[], path: Path, opts?: PolygonIntersectsPathOptions): boolean;
|
|
1570
|
+
|
|
1571
|
+
/**
|
|
1572
|
+
* The affine map carrying the points of `from` closest to those of `to`, by
|
|
1573
|
+
* least squares; both are interleaved `x, y` streams of the same length. When
|
|
1574
|
+
* the points lie on one line an affine map is not determined, and the
|
|
1575
|
+
* similarity (turn, even scale and move) is returned instead. Null for fewer
|
|
1576
|
+
* than two distinct points.
|
|
1577
|
+
*/
|
|
1578
|
+
declare function fitAffine(from: ArrayLike<number>, to: ArrayLike<number>): Affine | null;
|
|
1040
1579
|
|
|
1041
1580
|
/**
|
|
1042
1581
|
* Ergonomic builders for tiny shape paths used by chrome / overlays / markers.
|
|
@@ -1394,6 +1933,20 @@ declare function rotatePathAround(path: Path, cx: number, cy: number, rotation:
|
|
|
1394
1933
|
* rotation. Absent is the identity.
|
|
1395
1934
|
*/
|
|
1396
1935
|
type PoseLinear = readonly [a: number, b: number, c: number, d: number];
|
|
1936
|
+
/**
|
|
1937
|
+
* Axis-aligned rectangle in world space. The optional `rotation` (radians,
|
|
1938
|
+
* around the AABB center) and `transform` (inside it, about the same center)
|
|
1939
|
+
* let chrome carry the frame a box is drawn in without a parallel type;
|
|
1940
|
+
* `poseFrameOf` composes the two. routing and core call it `Bounds`.
|
|
1941
|
+
*/
|
|
1942
|
+
interface FramedBox {
|
|
1943
|
+
x: number;
|
|
1944
|
+
y: number;
|
|
1945
|
+
width: number;
|
|
1946
|
+
height: number;
|
|
1947
|
+
rotation?: number;
|
|
1948
|
+
transform?: PoseLinear;
|
|
1949
|
+
}
|
|
1397
1950
|
/** `transform` when it changes anything, `null` for absent or the identity. */
|
|
1398
1951
|
declare function poseLinearOf(pose: unknown): PoseLinear | null;
|
|
1399
1952
|
/**
|
|
@@ -1412,7 +1965,17 @@ declare function poseFrameInverseOf(pose: unknown): Affine | null;
|
|
|
1412
1965
|
/** `path`, given in the pose's unrotated box frame, as the node draws it. */
|
|
1413
1966
|
declare function pathThroughPoseFrame(path: Path, pose: unknown): Path;
|
|
1414
1967
|
|
|
1415
|
-
|
|
1968
|
+
/**
|
|
1969
|
+
* Flat indices of every anchor a round brush covers as it moves from `from` to
|
|
1970
|
+
* `to`: those within `radiusPx` of that segment, measured on screen. A dab is a
|
|
1971
|
+
* segment of zero length. `scale` is the view's, so the brush stays round on
|
|
1972
|
+
* screen under non-uniform zoom; omitted, one unit is one pixel.
|
|
1973
|
+
*/
|
|
1974
|
+
declare function anchorsUnderBrush(set: AnchorSet, from: Point, to: Point, opts: {
|
|
1975
|
+
radiusPx: number;
|
|
1976
|
+
scale?: Scale2;
|
|
1977
|
+
}): number[];
|
|
1978
|
+
|
|
1416
1979
|
/**
|
|
1417
1980
|
* How a path maps onto itself under one transform `m`: `partners[i]` is the
|
|
1418
1981
|
* flat index of the anchor that anchor `i` lands on, and `flips[i]` whether
|
|
@@ -1454,7 +2017,7 @@ declare function translateAnchorsSymmetric(set: AnchorSet, flats: readonly numbe
|
|
|
1454
2017
|
* follow it. Every handle is written once, from its target, so no anchor
|
|
1455
2018
|
* re-aims a handle another image already placed.
|
|
1456
2019
|
*/
|
|
1457
|
-
declare function moveHandleSymmetric(set: AnchorSet, flat: number, side:
|
|
2020
|
+
declare function moveHandleSymmetric(set: AnchorSet, flat: number, side: 'in' | 'out', toX: number, toY: number, breakSmoothness: boolean, syms: readonly AnchorSymmetry[]): boolean;
|
|
1458
2021
|
|
|
1459
2022
|
/** Where on a segment a bend is held, as `segmentAt` reports it. */
|
|
1460
2023
|
interface BendGrip {
|
|
@@ -1475,10 +2038,38 @@ interface BendGrip {
|
|
|
1475
2038
|
*/
|
|
1476
2039
|
declare function bendSegment(set: AnchorSet, grip: BendGrip, dx: number, dy: number): boolean;
|
|
1477
2040
|
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
2041
|
+
/**
|
|
2042
|
+
* `smudgePath` — one dab of a smudge brush: the outline under a round brush
|
|
2043
|
+
* moved along the brush's motion, most at its center and not at all at its rim.
|
|
2044
|
+
*/
|
|
2045
|
+
|
|
2046
|
+
/** Options for {@link smudgePath}. */
|
|
2047
|
+
interface SmudgePathOptions {
|
|
2048
|
+
/** The brush's center before this dab's motion. */
|
|
2049
|
+
center: Point;
|
|
2050
|
+
/** How far the brush moved. */
|
|
2051
|
+
delta: Point;
|
|
2052
|
+
/** The brush's radius, in the path's units. */
|
|
2053
|
+
radius: number;
|
|
2054
|
+
/** How much of `delta` a point under the brush's center moves: `1` all of it. Default 1. */
|
|
2055
|
+
strength?: number;
|
|
2056
|
+
/**
|
|
2057
|
+
* The longest a segment under the brush may be before an anchor is added at its
|
|
2058
|
+
* middle, in the path's units, so the brush has points to move where it needs
|
|
2059
|
+
* them. Default a third of `radius`; `Infinity` adds none.
|
|
2060
|
+
*/
|
|
2061
|
+
detail?: number;
|
|
2062
|
+
}
|
|
2063
|
+
/**
|
|
2064
|
+
* `path` with the outline under the brush pushed along `delta`. A point at distance
|
|
2065
|
+
* `d` from `center` moves by `delta × strength × (1 − (d/radius)²)²`, and an anchor's
|
|
2066
|
+
* handles move with it, so a smooth anchor stays smooth. First, every segment that
|
|
2067
|
+
* passes under the brush and is longer than `detail` is split at its middle until it
|
|
2068
|
+
* is not, so a long straight edge bends where the brush meets it. Returns `path`
|
|
2069
|
+
* itself when nothing is under the brush.
|
|
2070
|
+
*/
|
|
2071
|
+
declare function smudgePath(path: PolygonPath, opts: SmudgePathOptions): PolygonPath;
|
|
2072
|
+
|
|
1482
2073
|
/**
|
|
1483
2074
|
* Collapse the handles of the anchors at `flatIndexes` onto their anchors,
|
|
1484
2075
|
* leaving sharp corners. A segment whose ends both lose their handles turns
|
|
@@ -1507,17 +2098,165 @@ declare function makeHandlesSymmetric(set: AnchorSet, flatIndexes: Iterable<numb
|
|
|
1507
2098
|
* keep and follows `to` freely.
|
|
1508
2099
|
*/
|
|
1509
2100
|
declare function handleAlongItsAngle(anchor: Point, handle: Point, to: Point): Point;
|
|
2101
|
+
/**
|
|
2102
|
+
* Where a handle lands when dragged toward `to` but held to its current
|
|
2103
|
+
* length from `anchor`: on the circle of that length, aimed at `to`. A `to`
|
|
2104
|
+
* on the anchor itself gives no direction, and leaves the handle where it is.
|
|
2105
|
+
*/
|
|
2106
|
+
declare function handleAtItsLength(anchor: Point, handle: Point, to: Point): Point;
|
|
2107
|
+
|
|
2108
|
+
/**
|
|
2109
|
+
* Soft selection over an anchor set: how strongly an edit to some anchors
|
|
2110
|
+
* carries to the anchors near them, by distance measured along the path.
|
|
2111
|
+
*
|
|
2112
|
+
* Distance is arc length along the drawn curve, not a straight line, so two
|
|
2113
|
+
* anchors that sit close across a gap in a shape are as far apart as the
|
|
2114
|
+
* path between them. A `scale` measures it in screen pixels under a view's
|
|
2115
|
+
* zoom, per axis.
|
|
2116
|
+
*/
|
|
2117
|
+
|
|
2118
|
+
/** How influence fades from 1 at a selected anchor to 0 at the radius:
|
|
2119
|
+
* `smooth` eases out and in, `linear` falls evenly, `sharp` drops fast and
|
|
2120
|
+
* tails off. */
|
|
2121
|
+
type SoftFalloff = 'smooth' | 'linear' | 'sharp';
|
|
2122
|
+
/**
|
|
2123
|
+
* The weight `falloff` gives a point `distance` from the selection, for a
|
|
2124
|
+
* radius of `radius`: 1 at distance 0, 0 at the radius and beyond.
|
|
2125
|
+
*/
|
|
2126
|
+
declare function softFalloff(falloff: SoftFalloff, distance: number, radius: number): number;
|
|
2127
|
+
/** Arc length along one segment, sampled at evenly spaced curve parameters. */
|
|
2128
|
+
interface SegmentMeasure {
|
|
2129
|
+
/** Arc length from the subpath's start to each sample; sample `i` is at
|
|
2130
|
+
* parameter `i / (lengths.length - 1)`. */
|
|
2131
|
+
lengths: Float64Array;
|
|
2132
|
+
}
|
|
2133
|
+
/** Arc lengths along one subpath, as {@link measureAnchorPath} takes them. */
|
|
2134
|
+
interface AnchorSubpathMeasure {
|
|
2135
|
+
closed: boolean;
|
|
2136
|
+
/** Flat index of the subpath's first anchor. */
|
|
2137
|
+
first: number;
|
|
2138
|
+
/** Arc length from the subpath's start to each anchor. */
|
|
2139
|
+
at: Float64Array;
|
|
2140
|
+
/** Total length, the closing segment included on a closed subpath. */
|
|
2141
|
+
length: number;
|
|
2142
|
+
/** Segment `i` runs from anchor `i` to anchor `i + 1`, wrapping on a closed subpath. */
|
|
2143
|
+
segments: SegmentMeasure[];
|
|
2144
|
+
}
|
|
2145
|
+
/** Arc lengths along every subpath of an anchor set, as
|
|
2146
|
+
* {@link measureAnchorPath} takes them. Read it with
|
|
2147
|
+
* {@link softSelectionWeights} and {@link softSelectionBand}. */
|
|
2148
|
+
interface AnchorPathMeasure {
|
|
2149
|
+
readonly subpaths: readonly AnchorSubpathMeasure[];
|
|
2150
|
+
}
|
|
2151
|
+
/** Options for {@link measureAnchorPath}. */
|
|
2152
|
+
interface MeasureAnchorPathOptions {
|
|
2153
|
+
/** Per-axis factor applied before measuring — a view's scale, to measure in
|
|
2154
|
+
* screen pixels. Default 1 on both axes. */
|
|
2155
|
+
scale?: {
|
|
2156
|
+
x: number;
|
|
2157
|
+
y: number;
|
|
2158
|
+
};
|
|
2159
|
+
/** Samples taken along each curved segment. Default 24. */
|
|
2160
|
+
samples?: number;
|
|
2161
|
+
}
|
|
2162
|
+
/** Measure the arc length along every subpath of `set`. */
|
|
2163
|
+
declare function measureAnchorPath(set: AnchorSet, opts?: MeasureAnchorPathOptions): AnchorPathMeasure;
|
|
2164
|
+
/**
|
|
2165
|
+
* How much of an edit to the `selected` anchors each anchor receives: 1 for
|
|
2166
|
+
* a selected anchor, the falloff of its distance along the path for one
|
|
2167
|
+
* within `radius` of the nearest selected anchor on its subpath. Anchors
|
|
2168
|
+
* that receive nothing are absent, as are anchors on a subpath with no
|
|
2169
|
+
* selected anchor.
|
|
2170
|
+
*/
|
|
2171
|
+
declare function softSelectionWeights(measure: AnchorPathMeasure, selected: Iterable<number>, radius: number, falloff: SoftFalloff): Map<number, number>;
|
|
2172
|
+
/**
|
|
2173
|
+
* The stretches of path within `radius` of the `selected` anchors, as world
|
|
2174
|
+
* polylines drawn on `set`. `measure` is of the set the distances are taken
|
|
2175
|
+
* on — the path as it was when the edit began — and `set` the geometry to
|
|
2176
|
+
* draw on, which must have the same anchors. A stretch crossing the seam of a
|
|
2177
|
+
* closed subpath comes back as one run.
|
|
2178
|
+
*/
|
|
2179
|
+
declare function softSelectionBand(measure: AnchorPathMeasure, set: AnchorSet, selected: Iterable<number>, radius: number): Point[][];
|
|
2180
|
+
|
|
2181
|
+
/** A curved segment's balance line: from its first handle's tip to its
|
|
2182
|
+
* second's, with a grip at the middle. */
|
|
2183
|
+
interface HandleBalance {
|
|
2184
|
+
sub: number;
|
|
2185
|
+
segIdx: number;
|
|
2186
|
+
/** Flat index of the anchor the segment starts at, which names the segment
|
|
2187
|
+
* the way an anchor's flat index names the anchor. */
|
|
2188
|
+
flat: number;
|
|
2189
|
+
/** Tip of the segment's first handle, the start anchor's out-handle. */
|
|
2190
|
+
from: Point;
|
|
2191
|
+
/** Tip of the segment's second handle, the end anchor's in-handle. */
|
|
2192
|
+
to: Point;
|
|
2193
|
+
/** Midway between the two tips. */
|
|
2194
|
+
grip: Point;
|
|
2195
|
+
}
|
|
2196
|
+
/**
|
|
2197
|
+
* The balance line of every curved segment in `set` that has both handles
|
|
2198
|
+
* pulled off their anchors. Dragging a line's grip scales both handles
|
|
2199
|
+
* together ({@link scaleSegmentHandles}), which fills the curve out toward
|
|
2200
|
+
* its corner or flattens it toward its chord without turning either end.
|
|
2201
|
+
*/
|
|
2202
|
+
declare function handleBalances(set: AnchorSet): HandleBalance[];
|
|
2203
|
+
/**
|
|
2204
|
+
* Scale both handles of segment `(sub, segIdx)` by `factor`, each along its
|
|
2205
|
+
* own direction, so the segment keeps its end tangents. A smooth anchor at
|
|
2206
|
+
* either end stays smooth: its other handle points the same way as before.
|
|
2207
|
+
* `factor` below zero counts as zero, which retracts both handles.
|
|
2208
|
+
*
|
|
2209
|
+
* Under `syms`, as `anchorSymmetries` gives them, every image of either handle
|
|
2210
|
+
* moves to the image of where that handle goes, the way `moveHandleSymmetric`
|
|
2211
|
+
* moves a dragged handle's.
|
|
2212
|
+
*
|
|
2213
|
+
* Returns false when the segment has no balance line or nothing moved.
|
|
2214
|
+
*/
|
|
2215
|
+
declare function scaleSegmentHandles(set: AnchorSet, sub: number, segIdx: number, factor: number, syms?: readonly AnchorSymmetry[]): boolean;
|
|
2216
|
+
/**
|
|
2217
|
+
* The factor {@link scaleSegmentHandles} takes to bring segment
|
|
2218
|
+
* `(sub, segIdx)`'s grip as near `to` as scaling can: `to` projected onto the
|
|
2219
|
+
* line the grip slides along as both handles grow. 1 when the segment has no
|
|
2220
|
+
* balance line.
|
|
2221
|
+
*/
|
|
2222
|
+
declare function balanceFactorToward(set: AnchorSet, sub: number, segIdx: number, to: Point): number;
|
|
2223
|
+
/**
|
|
2224
|
+
* Give both handles of segment `(sub, segIdx)` the same proportion: each
|
|
2225
|
+
* reaches the same fraction of the way from its anchor to the corner where
|
|
2226
|
+
* the two handle lines cross, that fraction being the mean of the two they
|
|
2227
|
+
* had. Where the lines don't cross ahead of both handles, both take the mean
|
|
2228
|
+
* length instead. Directions are kept either way.
|
|
2229
|
+
*
|
|
2230
|
+
* Returns false when the segment has no balance line or the handles already
|
|
2231
|
+
* match.
|
|
2232
|
+
*/
|
|
2233
|
+
declare function equalizeSegmentHandles(set: AnchorSet, sub: number, segIdx: number): boolean;
|
|
2234
|
+
|
|
2235
|
+
/**
|
|
2236
|
+
* Make each smooth anchor at `flatIndexes` curvature-continuous: the curve
|
|
2237
|
+
* bends as tightly just after the anchor as just before it, so it shows no
|
|
2238
|
+
* kink in its curvature there. Only handle lengths change — each handle keeps
|
|
2239
|
+
* its direction, so the anchor stays smooth and the tangent stays put — and
|
|
2240
|
+
* the product of the two lengths is kept, so the anchor's pull on the curve
|
|
2241
|
+
* stays about as strong.
|
|
2242
|
+
*
|
|
2243
|
+
* Absent `flatIndexes`, every anchor in the set. Moving one anchor's handles
|
|
2244
|
+
* changes the curvature at its neighbors, so the fixes are repeated until
|
|
2245
|
+
* they settle.
|
|
2246
|
+
*
|
|
2247
|
+
* Skipped, because lengths alone cannot do it: a corner, an anchor missing a
|
|
2248
|
+
* handle, an end of an open subpath, and an anchor the curve bends opposite
|
|
2249
|
+
* ways either side of, or straight through on one side.
|
|
2250
|
+
*
|
|
2251
|
+
* Returns false when nothing changed.
|
|
2252
|
+
*/
|
|
2253
|
+
declare function harmonizeAnchors(set: AnchorSet, flatIndexes?: Iterable<number>): boolean;
|
|
1510
2254
|
|
|
1511
2255
|
/**
|
|
1512
2256
|
* Where each point of an edited path came from, so an array kept per point (a skin's
|
|
1513
2257
|
* weights) can follow an edit that inserts, deletes, or reorders points.
|
|
1514
2258
|
*/
|
|
1515
2259
|
|
|
1516
|
-
/** The anchor model `pathToAnchors` produces; `AnchorSet` in `anchorEdits`. */
|
|
1517
|
-
interface Anchors {
|
|
1518
|
-
anchors: PenAnchor[][];
|
|
1519
|
-
closed: boolean[];
|
|
1520
|
-
}
|
|
1521
2260
|
/**
|
|
1522
2261
|
* Where a point of an edited path came from: point `a` of the path before the edit, or for a
|
|
1523
2262
|
* point the edit made, a blend `t` of the way from point `a` to point `b`.
|
|
@@ -1526,6 +2265,8 @@ interface PointOrigin {
|
|
|
1526
2265
|
a: number;
|
|
1527
2266
|
b: number;
|
|
1528
2267
|
t: number;
|
|
2268
|
+
/** On an anchor's own point: its subpath now runs the other way through it. */
|
|
2269
|
+
reversed?: true;
|
|
1529
2270
|
}
|
|
1530
2271
|
/**
|
|
1531
2272
|
* `editAnchorSet`, answering also where each point of the new path came from.
|
|
@@ -1536,7 +2277,7 @@ interface PointOrigin {
|
|
|
1536
2277
|
* of it in its subpath, by its distance to each, or a copy of the one it has; its origin is
|
|
1537
2278
|
* `null` when its subpath has none.
|
|
1538
2279
|
*/
|
|
1539
|
-
declare function editAnchorSetTracked(path: PolygonPath, edit: (set:
|
|
2280
|
+
declare function editAnchorSetTracked(path: PolygonPath, edit: (set: AnchorSet) => boolean | void): {
|
|
1540
2281
|
path: PolygonPath;
|
|
1541
2282
|
origins: (PointOrigin | null)[];
|
|
1542
2283
|
} | null;
|
|
@@ -1547,6 +2288,449 @@ declare function editAnchorSetTracked(path: PolygonPath, edit: (set: Anchors) =>
|
|
|
1547
2288
|
*/
|
|
1548
2289
|
declare function remapPointValues(values: ArrayLike<number>, origins: readonly (PointOrigin | null)[]): number[];
|
|
1549
2290
|
|
|
2291
|
+
/**
|
|
2292
|
+
* Arrays kept per anchor of a path — vertex colors, stroke widths — carried through an edit
|
|
2293
|
+
* that `editAnchorSetTracked` reported.
|
|
2294
|
+
*/
|
|
2295
|
+
|
|
2296
|
+
/**
|
|
2297
|
+
* Where each anchor of `after` came from, in anchors of `before` as `countPathAnchors` counts
|
|
2298
|
+
* them, given the point `origins` `editAnchorSetTracked` answered for the edit: anchor `a`, or
|
|
2299
|
+
* for an anchor the edit made, a blend `t` of the way from `a` to `b`. `reversed` marks an
|
|
2300
|
+
* anchor whose subpath now runs the other way through it. Null for an anchor with no origin.
|
|
2301
|
+
*/
|
|
2302
|
+
declare function anchorOriginsOf(before: PolygonPath, after: PolygonPath, origins: readonly (PointOrigin | null)[]): (PointOrigin | null)[];
|
|
2303
|
+
/**
|
|
2304
|
+
* An array kept per anchor of a path, `stride` numbers each — four color channels, say —
|
|
2305
|
+
* carried through an edit from `before` to `after`, with `origins` as
|
|
2306
|
+
* `editAnchorSetTracked` answered. An anchor the edit kept keeps its numbers; one it
|
|
2307
|
+
* made blends those of the anchors it came between. An anchor with no origin reads 0. Anchors
|
|
2308
|
+
* are counted as `countPathAnchors` counts them.
|
|
2309
|
+
*/
|
|
2310
|
+
declare function remapAnchorValues(values: ArrayLike<number>, stride: number, before: PolygonPath, after: PolygonPath, origins: readonly (PointOrigin | null)[]): number[];
|
|
2311
|
+
|
|
2312
|
+
/**
|
|
2313
|
+
* Geometric constraints on a path's anchors. Each names anchors by flat index,
|
|
2314
|
+
* the walk-order numbering `enumerateAnchors` and `anchorAt` use, and is plain
|
|
2315
|
+
* JSON, so a list of them can be kept in scene data and saved with it.
|
|
2316
|
+
*/
|
|
2317
|
+
/** Two anchors by flat index: the straight line from the first to the second. */
|
|
2318
|
+
type AnchorPair = readonly [number, number];
|
|
2319
|
+
/**
|
|
2320
|
+
* One constraint. `fixed` holds an anchor where it was before an edit, so it
|
|
2321
|
+
* moves with its node but not with any edit of the path. `horizontal` and
|
|
2322
|
+
* `vertical` read the axes of the frame the solve is given; `length` is in
|
|
2323
|
+
* the path's own units. `tangent` keeps an anchor's two handles on one line
|
|
2324
|
+
* through it, pointing apart (G1 continuity), their lengths free; it needs
|
|
2325
|
+
* both handles. `onPath` holds an anchor on the path's segment from
|
|
2326
|
+
* `segment[0]` to `segment[1]`, anywhere along it.
|
|
2327
|
+
*/
|
|
2328
|
+
type PathConstraint = {
|
|
2329
|
+
readonly kind: 'fixed' | 'tangent';
|
|
2330
|
+
readonly anchor: number;
|
|
2331
|
+
} | {
|
|
2332
|
+
readonly kind: 'horizontal' | 'vertical';
|
|
2333
|
+
readonly segment: AnchorPair;
|
|
2334
|
+
} | {
|
|
2335
|
+
readonly kind: 'parallel' | 'perpendicular' | 'equalLength';
|
|
2336
|
+
readonly segments: readonly [AnchorPair, AnchorPair];
|
|
2337
|
+
} | {
|
|
2338
|
+
readonly kind: 'length';
|
|
2339
|
+
readonly segment: AnchorPair;
|
|
2340
|
+
readonly length: number;
|
|
2341
|
+
} | {
|
|
2342
|
+
readonly kind: 'coincident';
|
|
2343
|
+
readonly anchors: AnchorPair;
|
|
2344
|
+
} | {
|
|
2345
|
+
readonly kind: 'onPath';
|
|
2346
|
+
readonly anchor: number;
|
|
2347
|
+
readonly segment: AnchorPair;
|
|
2348
|
+
};
|
|
2349
|
+
/** Every kind of {@link PathConstraint}. */
|
|
2350
|
+
type PathConstraintKind = PathConstraint['kind'];
|
|
2351
|
+
/** The anchors `c` reads, in the order it names them; an anchor named twice is listed twice. */
|
|
2352
|
+
declare function constraintAnchors(c: PathConstraint): number[];
|
|
2353
|
+
/**
|
|
2354
|
+
* `c` with every anchor index passed through `to`, or null when `to` answers
|
|
2355
|
+
* `undefined` for any of them — the anchor is gone, and so is the constraint.
|
|
2356
|
+
*/
|
|
2357
|
+
declare function mapConstraintAnchors(c: PathConstraint, to: (anchor: number) => number | undefined): PathConstraint | null;
|
|
2358
|
+
/** Whether every anchor `c` names is an index below `count`. */
|
|
2359
|
+
declare function constraintFits(c: PathConstraint, count: number): boolean;
|
|
2360
|
+
|
|
2361
|
+
/**
|
|
2362
|
+
* The points a constraint solve reads, and the coordinate vector it works in:
|
|
2363
|
+
* anchors, then each anchor's handles as offsets from it (see `ResidualSpace`).
|
|
2364
|
+
*/
|
|
2365
|
+
|
|
2366
|
+
/** An anchor the solver reads and writes, with its handles where it has them. */
|
|
2367
|
+
interface ConstraintPoint {
|
|
2368
|
+
x: number;
|
|
2369
|
+
y: number;
|
|
2370
|
+
inHandle?: {
|
|
2371
|
+
x: number;
|
|
2372
|
+
y: number;
|
|
2373
|
+
};
|
|
2374
|
+
outHandle?: {
|
|
2375
|
+
x: number;
|
|
2376
|
+
y: number;
|
|
2377
|
+
};
|
|
2378
|
+
}
|
|
2379
|
+
/** One handle of an anchor. */
|
|
2380
|
+
interface HandleRef {
|
|
2381
|
+
anchor: number;
|
|
2382
|
+
side: 'in' | 'out';
|
|
2383
|
+
}
|
|
2384
|
+
/**
|
|
2385
|
+
* Whether `c` can be solved over `points`: every anchor it names exists, and
|
|
2386
|
+
* a `tangent` anchor has both handles.
|
|
2387
|
+
*/
|
|
2388
|
+
declare function constraintApplies(c: PathConstraint, points: readonly ConstraintPoint[]): boolean;
|
|
2389
|
+
|
|
2390
|
+
/**
|
|
2391
|
+
* A damped Gauss-Newton solve for anchor constraints: from the state an edit
|
|
2392
|
+
* left, the smallest weighted move of the anchors and handles that makes
|
|
2393
|
+
* every residual zero. Each step is the minimum-norm solution of the
|
|
2394
|
+
* linearized system, `Δ = -M Jᵀ (J M Jᵀ + λI)⁻¹ r`, where `M` weighs how
|
|
2395
|
+
* freely each coordinate may move; λ grows when a step makes things worse and
|
|
2396
|
+
* shrinks when it helps, which is the Levenberg-Marquardt schedule run on the
|
|
2397
|
+
* constraint side.
|
|
2398
|
+
*
|
|
2399
|
+
* A handle is a coordinate of its own only where a `tangent` reads it; any
|
|
2400
|
+
* other rides with its anchor, as an offset nothing changes.
|
|
2401
|
+
*/
|
|
2402
|
+
|
|
2403
|
+
/** Options for {@link solveConstraints}. */
|
|
2404
|
+
interface SolveConstraintsOptions {
|
|
2405
|
+
/** Anchors the edit put where they are — the dragged ones. They move only when no other anchor can satisfy the constraints. */
|
|
2406
|
+
held?: Iterable<number>;
|
|
2407
|
+
/** Handles the edit put where they are, held the way `held` holds anchors. */
|
|
2408
|
+
heldHandles?: Iterable<HandleRef>;
|
|
2409
|
+
/** Where each anchor was before the edit, which is where a `fixed` constraint keeps it. Default: where it is now. */
|
|
2410
|
+
reference?: readonly (ConstraintPoint | undefined)[];
|
|
2411
|
+
/** Radians the frame `horizontal` and `vertical` read is turned from the world's axes. Default 0. */
|
|
2412
|
+
axisAngle?: number;
|
|
2413
|
+
/** A frame per constraint, by index, over `axisAngle` — for constraints gathered from paths drawn in different frames. */
|
|
2414
|
+
axisAngles?: readonly (number | undefined)[];
|
|
2415
|
+
/** Indices of constraints to leave out of the solve — ones already known not to hold. */
|
|
2416
|
+
skip?: Iterable<number>;
|
|
2417
|
+
/** Default 100. */
|
|
2418
|
+
maxIterations?: number;
|
|
2419
|
+
/** The largest residual the solve stops at. Default 1e-7. */
|
|
2420
|
+
tolerance?: number;
|
|
2421
|
+
}
|
|
2422
|
+
/** What {@link solveConstraints} answers. */
|
|
2423
|
+
interface SolveConstraintsResult {
|
|
2424
|
+
/** Every anchor, moved, with its handles. */
|
|
2425
|
+
points: ConstraintPoint[];
|
|
2426
|
+
/** Whether every constraint the solve took holds within its tolerance. */
|
|
2427
|
+
converged: boolean;
|
|
2428
|
+
iterations: number;
|
|
2429
|
+
/** Indices of the constraints that do not hold in `points`, skipped ones included. */
|
|
2430
|
+
unsatisfied: number[];
|
|
2431
|
+
}
|
|
2432
|
+
/**
|
|
2433
|
+
* Move `points` the least that makes `constraints` hold. Anchors named by a
|
|
2434
|
+
* `fixed` constraint go back to `reference` and stay there; `held` anchors
|
|
2435
|
+
* and `heldHandles` stay where they are when the rest can satisfy the
|
|
2436
|
+
* constraints, and give way as little as they must when not. When the
|
|
2437
|
+
* constraints cannot all hold, `converged` is false and `unsatisfied` names
|
|
2438
|
+
* the ones that do not.
|
|
2439
|
+
*/
|
|
2440
|
+
declare function solveConstraints(points: readonly ConstraintPoint[], constraints: readonly PathConstraint[], opts?: SolveConstraintsOptions): SolveConstraintsResult;
|
|
2441
|
+
|
|
2442
|
+
/**
|
|
2443
|
+
* Whether constraints hold for a set of points, and whether a solve made them
|
|
2444
|
+
* hold only by collapsing what they measure.
|
|
2445
|
+
*/
|
|
2446
|
+
|
|
2447
|
+
/** The residual, in the path's units, under which a constraint counts as holding. */
|
|
2448
|
+
declare const CONSTRAINT_TOLERANCE = 0.001;
|
|
2449
|
+
/** Options for {@link unsatisfiedConstraints}. */
|
|
2450
|
+
interface UnsatisfiedConstraintsOptions {
|
|
2451
|
+
axisAngle?: number;
|
|
2452
|
+
/** A frame per constraint, by index, over `axisAngle`. */
|
|
2453
|
+
axisAngles?: readonly (number | undefined)[];
|
|
2454
|
+
/** Where a `fixed` anchor belongs. Absent, a `fixed` constraint always holds. */
|
|
2455
|
+
reference?: readonly (ConstraintPoint | undefined)[];
|
|
2456
|
+
/** Default {@link CONSTRAINT_TOLERANCE}. */
|
|
2457
|
+
tolerance?: number;
|
|
2458
|
+
}
|
|
2459
|
+
/**
|
|
2460
|
+
* Indices of the constraints that do not hold for `points`: a residual past
|
|
2461
|
+
* the tolerance, an anchor index the points do not have, or a tangent on an
|
|
2462
|
+
* anchor missing a handle.
|
|
2463
|
+
*/
|
|
2464
|
+
declare function unsatisfiedConstraints(points: readonly ConstraintPoint[], constraints: readonly PathConstraint[], opts?: UnsatisfiedConstraintsOptions): number[];
|
|
2465
|
+
|
|
2466
|
+
/**
|
|
2467
|
+
* Constraints on a `PolygonPath`: solving them over its anchors, and carrying
|
|
2468
|
+
* them through an edit that renumbers the anchors.
|
|
2469
|
+
*/
|
|
2470
|
+
|
|
2471
|
+
/** Every anchor of `path`, by flat index, with the handles it has. */
|
|
2472
|
+
declare function pathAnchorPoints(path: PolygonPath): ConstraintPoint[];
|
|
2473
|
+
/** {@link solveConstraints} over `path`'s anchors, and `path` with them moved. */
|
|
2474
|
+
interface SolvePathConstraintsResult extends SolveConstraintsResult {
|
|
2475
|
+
/** `path` with each anchor moved where the solve put it, its handles moved with it; `path` itself when none moved. */
|
|
2476
|
+
path: PolygonPath;
|
|
2477
|
+
}
|
|
2478
|
+
/**
|
|
2479
|
+
* Solve `constraints` over the anchors of `path` and write the result back,
|
|
2480
|
+
* carrying each moved anchor's handles with it so its curves keep their
|
|
2481
|
+
* shape, except where a `tangent` turned them.
|
|
2482
|
+
*/
|
|
2483
|
+
declare function solvePathConstraints(path: PolygonPath, constraints: readonly PathConstraint[], opts?: SolveConstraintsOptions): SolvePathConstraintsResult;
|
|
2484
|
+
/**
|
|
2485
|
+
* `path` with its anchors and handles where `to` puts them, given `from`,
|
|
2486
|
+
* where they are now; `path` itself when nothing moved.
|
|
2487
|
+
*/
|
|
2488
|
+
declare function withAnchorPoints(path: PolygonPath, from: readonly ConstraintPoint[], to: readonly ConstraintPoint[]): PolygonPath;
|
|
2489
|
+
/**
|
|
2490
|
+
* For each anchor of `after`, the anchor of `before` it is: the one whose
|
|
2491
|
+
* point `origins` says it was copied from. An anchor the edit made has none.
|
|
2492
|
+
* `origins` is what `editAnchorSetTracked` answered for the edit.
|
|
2493
|
+
*/
|
|
2494
|
+
declare function anchorsBefore(before: PolygonPath, after: PolygonPath, origins: readonly (PointOrigin | null)[]): (number | undefined)[];
|
|
2495
|
+
/**
|
|
2496
|
+
* `constraints` renumbered for the anchors of a path after an edit, given
|
|
2497
|
+
* `wasAnchor` — for each new anchor, the old one it is, as
|
|
2498
|
+
* {@link anchorsBefore} answers. A constraint naming an anchor the edit
|
|
2499
|
+
* removed is dropped; `from` holds each kept one's index in `constraints`.
|
|
2500
|
+
*/
|
|
2501
|
+
declare function remapConstraints(constraints: readonly PathConstraint[], wasAnchor: readonly (number | undefined)[]): {
|
|
2502
|
+
constraints: PathConstraint[];
|
|
2503
|
+
from: number[];
|
|
2504
|
+
};
|
|
2505
|
+
/**
|
|
2506
|
+
* The segment of `path` joining anchors `a` and `b`, as the pair in the order
|
|
2507
|
+
* the path runs it, or null when no segment joins them.
|
|
2508
|
+
*/
|
|
2509
|
+
declare function segmentBetween(path: PolygonPath, a: number, b: number): AnchorPair | null;
|
|
2510
|
+
|
|
2511
|
+
/**
|
|
2512
|
+
* Finishing an edit of constrained paths so their constraints hold: one path
|
|
2513
|
+
* on its own, or several solved together when links — constraints naming
|
|
2514
|
+
* anchors of more than one — tie them.
|
|
2515
|
+
*/
|
|
2516
|
+
|
|
2517
|
+
/** Options for {@link constrainPathEdit}. */
|
|
2518
|
+
interface ConstrainPathEditOptions {
|
|
2519
|
+
/**
|
|
2520
|
+
* Where each point of the edited path came from, as `editAnchorSetTracked`
|
|
2521
|
+
* answers. Absent, the edit is taken to keep every anchor's number, and one
|
|
2522
|
+
* that changes the anchor count drops every constraint.
|
|
2523
|
+
*/
|
|
2524
|
+
origins?: readonly (PointOrigin | null)[];
|
|
2525
|
+
/** See {@link SolveConstraintsOptions.axisAngle}. */
|
|
2526
|
+
axisAngle?: number;
|
|
2527
|
+
}
|
|
2528
|
+
/** What {@link constrainPathEdit} answers. */
|
|
2529
|
+
interface ConstrainedPathEdit {
|
|
2530
|
+
/** The edited path with the constraints holding again. */
|
|
2531
|
+
path: PolygonPath;
|
|
2532
|
+
/** The constraints renumbered for `path`'s anchors. */
|
|
2533
|
+
constraints: PathConstraint[];
|
|
2534
|
+
/** Whether every constraint that held before the edit holds after it. */
|
|
2535
|
+
converged: boolean;
|
|
2536
|
+
/** Indices into `constraints` of the ones that do not hold, including any that already did not before the edit. */
|
|
2537
|
+
unsatisfied: number[];
|
|
2538
|
+
}
|
|
2539
|
+
/** One path of a {@link constrainPathsEdit}: its edit, and its own constraints. */
|
|
2540
|
+
interface PathsEditItem extends ConstrainPathEditOptions {
|
|
2541
|
+
before: PolygonPath;
|
|
2542
|
+
/** `before` as the edit left it; `before` itself for a path the edit did not touch. */
|
|
2543
|
+
after: PolygonPath;
|
|
2544
|
+
constraints: readonly PathConstraint[];
|
|
2545
|
+
}
|
|
2546
|
+
/**
|
|
2547
|
+
* A constraint across paths. Its anchors are numbered over the anchors of
|
|
2548
|
+
* `paths` — indices into the items — one after another in that order: with
|
|
2549
|
+
* `paths: [2, 0]` and a 5-anchor item 2, anchor 6 is item 0's anchor 1. Its
|
|
2550
|
+
* `horizontal` and `vertical` read the world's axes.
|
|
2551
|
+
*/
|
|
2552
|
+
interface PathLink {
|
|
2553
|
+
constraint: PathConstraint;
|
|
2554
|
+
paths: readonly number[];
|
|
2555
|
+
}
|
|
2556
|
+
/** What {@link constrainPathsEdit} answers. */
|
|
2557
|
+
interface ConstrainedPathsEdit {
|
|
2558
|
+
/** Each item, in order: its path with the constraints holding, and its own constraints renumbered for it. */
|
|
2559
|
+
items: {
|
|
2560
|
+
path: PolygonPath;
|
|
2561
|
+
constraints: PathConstraint[];
|
|
2562
|
+
unsatisfied: number[];
|
|
2563
|
+
}[];
|
|
2564
|
+
/** Each link renumbered over its paths' anchors after the edit; null when the edit removed an anchor it names. */
|
|
2565
|
+
links: {
|
|
2566
|
+
constraint: PathConstraint | null;
|
|
2567
|
+
satisfied: boolean;
|
|
2568
|
+
}[];
|
|
2569
|
+
/** Whether every constraint that held before the edit holds after it. */
|
|
2570
|
+
converged: boolean;
|
|
2571
|
+
}
|
|
2572
|
+
/**
|
|
2573
|
+
* An edit of constrained paths, finished so their constraints and the links
|
|
2574
|
+
* between them hold, as one solve over every anchor: the anchors and handles
|
|
2575
|
+
* the edit moved are held, and so are the anchors of a path it left alone
|
|
2576
|
+
* (`after === before`), except one held on a segment; `fixed` anchors go
|
|
2577
|
+
* back to where they were, and the rest move the least they must. A constraint
|
|
2578
|
+
* that did not hold before the edit is left out of the solve, and reported.
|
|
2579
|
+
* Each item's own `horizontal` and `vertical` read its own `axisAngle`.
|
|
2580
|
+
*/
|
|
2581
|
+
declare function constrainPathsEdit(items: readonly PathsEditItem[], links?: readonly PathLink[]): ConstrainedPathsEdit;
|
|
2582
|
+
/**
|
|
2583
|
+
* An edit of a constrained path, `before` → `after`, finished so its
|
|
2584
|
+
* constraints hold: the anchors and handles the edit moved are held, `fixed`
|
|
2585
|
+
* anchors go back to where they were, and the rest move the least they must.
|
|
2586
|
+
* A constraint that did not hold before the edit conflicts with the others
|
|
2587
|
+
* and is left out of the solve rather than allowed to pull them out of true;
|
|
2588
|
+
* `unsatisfied` reports it.
|
|
2589
|
+
*/
|
|
2590
|
+
declare function constrainPathEdit(before: PolygonPath, after: PolygonPath, constraints: readonly PathConstraint[], opts?: ConstrainPathEditOptions): ConstrainedPathEdit;
|
|
2591
|
+
|
|
2592
|
+
/**
|
|
2593
|
+
* Which constraints conflict: not merely the ones a failed solve leaves
|
|
2594
|
+
* unsatisfied, but a smallest set that cannot all hold together, found by a
|
|
2595
|
+
* deletion filter — drop each member in turn, and keep it out when what is
|
|
2596
|
+
* left still fails. Every member of the answer is needed for the conflict.
|
|
2597
|
+
*/
|
|
2598
|
+
|
|
2599
|
+
/** Options for {@link conflictingConstraints}. */
|
|
2600
|
+
interface ConflictingConstraintsOptions {
|
|
2601
|
+
/** Radians the frame `horizontal` and `vertical` read is turned from the world's axes. Default 0. */
|
|
2602
|
+
axisAngle?: number;
|
|
2603
|
+
/** A frame per constraint, by index, over `axisAngle`. */
|
|
2604
|
+
axisAngles?: readonly (number | undefined)[];
|
|
2605
|
+
/** Where each anchor belongs for a `fixed` constraint. Default: where it is now. */
|
|
2606
|
+
reference?: readonly (ConstraintPoint | undefined)[];
|
|
2607
|
+
}
|
|
2608
|
+
/**
|
|
2609
|
+
* The constraints of `constraints` that conflict over `points`: for every
|
|
2610
|
+
* group of them sharing anchors that cannot all hold, a smallest subset that
|
|
2611
|
+
* still cannot — each member needed, the later ones in the list kept in
|
|
2612
|
+
* preference to the earlier — and every constraint that cannot apply at all.
|
|
2613
|
+
* Sorted; empty when every constraint can hold at once.
|
|
2614
|
+
*/
|
|
2615
|
+
declare function conflictingConstraints(points: readonly ConstraintPoint[], constraints: readonly PathConstraint[], opts?: ConflictingConstraintsOptions): number[];
|
|
2616
|
+
|
|
2617
|
+
/**
|
|
2618
|
+
* Edits to a path's order rather than its shape: where a subpath starts, and
|
|
2619
|
+
* which way it runs. Each mutates an `AnchorSet` in place, like the edits in
|
|
2620
|
+
* `anchorEdits`, and moves anchors whole, so anything an anchor carries beside
|
|
2621
|
+
* its point and handles travels with it.
|
|
2622
|
+
*/
|
|
2623
|
+
|
|
2624
|
+
/**
|
|
2625
|
+
* Make the anchor at `flatIndex` its subpath's first. A closed subpath turns
|
|
2626
|
+
* so it starts there, keeping its direction. An open subpath can only start
|
|
2627
|
+
* at one of its ends: its last anchor makes it run the other way, and an
|
|
2628
|
+
* interior anchor changes nothing. Returns whether the set changed.
|
|
2629
|
+
*/
|
|
2630
|
+
declare function setSubpathStart(set: AnchorSet, flatIndex: number): boolean;
|
|
2631
|
+
/**
|
|
2632
|
+
* Run each subpath in `subs` the other way, every one when `subs` is absent.
|
|
2633
|
+
* The shape is unchanged: each anchor's handles trade places. A closed
|
|
2634
|
+
* subpath keeps its start anchor, as `reversePath` does; an open one starts
|
|
2635
|
+
* where it used to end. Returns whether any subpath had a segment to turn.
|
|
2636
|
+
*/
|
|
2637
|
+
declare function reverseSubpaths(set: AnchorSet, subs?: Iterable<number>): boolean;
|
|
2638
|
+
/**
|
|
2639
|
+
* Where each anchor at `flatIndexes` sits once `reverseSubpaths(set, subs)`
|
|
2640
|
+
* has run: an anchor keeps its point, so a selection can follow it. Indexes
|
|
2641
|
+
* outside the set are dropped.
|
|
2642
|
+
*/
|
|
2643
|
+
declare function flatIndexesAfterReverse(set: AnchorSet, flatIndexes: Iterable<number>, subs?: Iterable<number>): number[];
|
|
2644
|
+
/** The subpaths holding the anchors at `flatIndexes`, each once, in order. */
|
|
2645
|
+
declare function subpathsOfAnchors(set: AnchorSet, flatIndexes: Iterable<number>): number[];
|
|
2646
|
+
/** A mark showing which way a path runs: a point on it and the unit vector of its heading there. */
|
|
2647
|
+
interface DirectionMark {
|
|
2648
|
+
x: number;
|
|
2649
|
+
y: number;
|
|
2650
|
+
dx: number;
|
|
2651
|
+
dy: number;
|
|
2652
|
+
/** The subpath the mark is on. */
|
|
2653
|
+
sub: number;
|
|
2654
|
+
}
|
|
2655
|
+
/**
|
|
2656
|
+
* One {@link DirectionMark} at the middle of every segment of `set`, closing
|
|
2657
|
+
* segments included, in walk order. A segment with no length gets none.
|
|
2658
|
+
*/
|
|
2659
|
+
declare function directionMarks(set: AnchorSet): DirectionMark[];
|
|
2660
|
+
|
|
2661
|
+
/**
|
|
2662
|
+
* Straight and curved segments, converted in place. A segment runs from one
|
|
2663
|
+
* anchor to the next, the closing segment of a closed subpath included, and is
|
|
2664
|
+
* named `(sub, segIdx)` as `segmentAt` reports it.
|
|
2665
|
+
*/
|
|
2666
|
+
|
|
2667
|
+
/** A segment of an `AnchorSet`: `segIdx === sub.length - 1` is a closed
|
|
2668
|
+
* subpath's closing segment. */
|
|
2669
|
+
interface SegmentRef {
|
|
2670
|
+
sub: number;
|
|
2671
|
+
segIdx: number;
|
|
2672
|
+
}
|
|
2673
|
+
/** What a segment is made: a line, a curve, or the other of what it is. */
|
|
2674
|
+
type SegmentType = 'line' | 'curve';
|
|
2675
|
+
/**
|
|
2676
|
+
* The segments both of whose ends are among `flatIndexes`, in walk order.
|
|
2677
|
+
* Two adjacent selected anchors select the segment between them; a closed
|
|
2678
|
+
* subpath with every anchor selected has all its segments.
|
|
2679
|
+
*/
|
|
2680
|
+
declare function segmentsBetweenAnchors(set: AnchorSet, flatIndexes: Iterable<number>): SegmentRef[];
|
|
2681
|
+
/** Whether segment `seg` is straight, or null when it does not exist. */
|
|
2682
|
+
declare function isSegmentStraight(set: AnchorSet, seg: SegmentRef): boolean | null;
|
|
2683
|
+
/**
|
|
2684
|
+
* Make each segment in `segs` straight or curved without moving its anchors.
|
|
2685
|
+
* A line becomes a curve with its handles a third of the way in from each
|
|
2686
|
+
* end, which draws the same line; a curve becomes a line by dropping the two
|
|
2687
|
+
* handles that shape it, leaving the handles of the segments beside it alone.
|
|
2688
|
+
* With no `to`, every segment turns curved when any of them is straight, and
|
|
2689
|
+
* straight when all are curved: one press flips the lot.
|
|
2690
|
+
*
|
|
2691
|
+
* Returns whether any segment changed.
|
|
2692
|
+
*/
|
|
2693
|
+
declare function convertSegments(set: AnchorSet, segs: readonly SegmentRef[], to?: SegmentType): boolean;
|
|
2694
|
+
|
|
2695
|
+
/**
|
|
2696
|
+
* Anchors as numbers a person types: the position of the selected anchors,
|
|
2697
|
+
* and for a lone anchor its handles' positions, angles and lengths. Reading
|
|
2698
|
+
* answers what a field shows; writing sets a value on every selected anchor,
|
|
2699
|
+
* or offsets each by an amount.
|
|
2700
|
+
*/
|
|
2701
|
+
|
|
2702
|
+
/** One number of an anchor. Handle angles are degrees counterclockwise from
|
|
2703
|
+
* +x as drawn, where y grows downward; lengths and positions are in the
|
|
2704
|
+
* set's own units. */
|
|
2705
|
+
type AnchorField = 'x' | 'y' | 'inX' | 'inY' | 'inAngle' | 'inLength' | 'outX' | 'outY' | 'outAngle' | 'outLength';
|
|
2706
|
+
/** Every {@link AnchorField}, in the order a panel lists them. */
|
|
2707
|
+
declare const ANCHOR_FIELDS: readonly AnchorField[];
|
|
2708
|
+
/** What a typed field asks for: a value for every anchor, or an amount added to each one's own. */
|
|
2709
|
+
type NumberEntry = {
|
|
2710
|
+
to: number;
|
|
2711
|
+
} | {
|
|
2712
|
+
by: number;
|
|
2713
|
+
};
|
|
2714
|
+
/**
|
|
2715
|
+
* What each field shows for the anchors at `flatIndexes`: a number where
|
|
2716
|
+
* they agree, `null` where they differ, and no key for a field that does not
|
|
2717
|
+
* apply. Position applies to any selection; handle fields only to a single
|
|
2718
|
+
* anchor, and only for a handle it has.
|
|
2719
|
+
*/
|
|
2720
|
+
type AnchorFieldValues = Partial<Record<AnchorField, number | null>>;
|
|
2721
|
+
/** The fields for the anchors at `flatIndexes`; `{}` when none of them exists. */
|
|
2722
|
+
declare function readAnchorFields(set: AnchorSet, flatIndexes: Iterable<number>): AnchorFieldValues;
|
|
2723
|
+
/**
|
|
2724
|
+
* Write `entry` into `field` of every anchor at `flatIndexes`. Moving an
|
|
2725
|
+
* anchor carries its handles. A handle field moves the handle as a drag to
|
|
2726
|
+
* the typed spot would (`moveHandleTo`): on a smooth anchor the opposite
|
|
2727
|
+
* handle mirrors it, taking its turn and its length, and on a corner it stays
|
|
2728
|
+
* where it is. An anchor without that handle is skipped. An angle keeps the
|
|
2729
|
+
* handle's length, and a length keeps its angle. Returns whether anything
|
|
2730
|
+
* moved.
|
|
2731
|
+
*/
|
|
2732
|
+
declare function writeAnchorField(set: AnchorSet, flatIndexes: Iterable<number>, field: AnchorField, entry: NumberEntry): boolean;
|
|
2733
|
+
|
|
1550
2734
|
/**
|
|
1551
2735
|
* Anchor lookup across several paths, measured on screen: which existing
|
|
1552
2736
|
* anchor is nearest a point, and whether it ends an open subpath. Feeds the
|
|
@@ -1671,4 +2855,4 @@ declare function reviveTypedArrays(value: unknown): unknown;
|
|
|
1671
2855
|
/** `tagTypedArrays` as a `JSON.stringify` replacer. */
|
|
1672
2856
|
declare function typedArrayReplacer(_key: string, value: unknown): unknown;
|
|
1673
2857
|
|
|
1674
|
-
export { type Affine, type
|
|
2858
|
+
export { ANCHOR_FIELDS, type Affine, type AnchorField, type AnchorFieldValues, type AnchorPair, type AnchorPathMeasure, AnchorSet, type AnchorSubpathMeasure, type AnchorSymmetry, type AverageAxis, type BendAlongPathOptions, type BendGrip, type BezierEasing, type BlendPathsOptions, type Box, CONSTRAINT_TOLERANCE, CORNER_RESTORE_TOLERANCE, type ConflictingConstraintsOptions, type ConstrainPathEditOptions, type ConstrainedPathEdit, type ConstrainedPathsEdit, type ConstraintPoint, type CornerCut, type CornerFrame, CornerPiece, CornerSpec, type CornerTrace, type CubicContour, type CubicCoords, type CubicSegment, type CurveNearest, DEFAULT_FLATTEN_TOLERANCE, type DirectionMark, EASINGS, EPS, type EasingFn, type EasingName, type EasingSpec, type ExtendToMeetOptions, type FramedBox, type GlMat3, type GrowRegionOptions, type HandleBalance, type HandleRef, type JoinOptions, type LengthenMode, type LineCoords, type MeasureAnchorPathOptions, type MeasurePathOptions, type NumberEntry, type NumberTypedArray, type OpenPathEnd, PATH_C, PATH_CMD_LENGTHS, PATH_COMMANDS, PATH_L, PATH_M, PATH_Q, PATH_SNAP_KINDS, PATH_Z, Path, type PathAnchorHit, type PathAwayFromAnchors, type PathBlend, PathBuilder, type PathCommandCode, type PathCommandName, type PathConstraint, type PathConstraintKind, type PathCrossing, type PathEndFrame, PathFillRule, type PathInWorldPose, type PathLink, type PathMeasure, type PathNearest, PathOpenFill, type PathSegment, type PathSnapHit, type PathSnapIndex, type PathSnapKind, type PathSnapQuery, type PathSnapTarget, type PathStation, type PathStop, type PathsEditItem, PenAnchor, type PlaceRectOptions, type PlacedRect, type Placement, type PlacementAlign, type PlacementSide, Point, type PointAlongPathOptions, type PointInPathOptions, type PointOrigin, type PolygonIntersectsPathOptions, PolygonPath, type PoseLinear, type PoseRotation, type QuadraticCoords, type Rect, RectPath, type RepeatAlongPathOptions, type RepeatStation, type ResamplePathOptions, type ResolvedCorners, SPRING_PRESETS, Scale2, type SegmentCrossing, type SegmentMeasure, type SegmentRef, type SegmentType, type SimplifyPathOptions, type SmudgePathOptions, type SoftFalloff, type SolveConstraintsOptions, type SolveConstraintsResult, type SolvePathConstraintsResult, type SpiroContour, SpiroKind, type SpiroPath, SpiroPoint, type SpiroToPathOptions, type SpringPreset, type SpringPresetName, type StaticPathSnapKind, type StrokeHitTestOptions, type SubpathEnd, TYPED_ARRAY_CONSTRUCTORS, type TaggedTypedArray, type TrimPathOptions, type TrimResult, type TypedArrayTag, type UnsatisfiedConstraintsOptions, type View, ZOOM_FLOOR, addExtremaAnchors, anchorOriginsOf, anchorSymmetries, anchorSymmetry, anchorsBefore, anchorsUnderBrush, anchorsWhere, applyToPoint, approxEq, asPolygonPath, averageAnchorsAt, balanceFactorToward, bendAlongPath, bendSegment, blendPaths, boundsOfCoords, boundsOfPath, boxContainsBox, boxContainsPoint, boxToBox, circlePath, clamp, clampRectWithin, closestOpenEnds, composePath, conflictingConstraints, constrainPathEdit, constrainPathsEdit, constraintAnchors, constraintApplies, constraintFits, convertSegments, cornerAnchors, cornerCuts, cornerFrameAt, cornerFrames, cornerTraces, createPathSnapIndex, cross, cubicAxisExtremaTs, cubicBezierEasing, cubicBounds, cubicContoursToPath, cubicEvalAt, decomposePath, defaultOpenFill, directionMarks, dot, easeIn, easeInBack, easeInBounce, easeInCirc, easeInCubic, easeInElastic, easeInExpo, easeInOut, easeInOutBack, easeInOutBounce, easeInOutCirc, easeInOutCubic, easeInOutElastic, easeInOutExpo, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInOutSine, easeInQuad, easeInQuart, easeInQuint, easeInSine, easeOut, easeOutBack, easeOutBounce, easeOutCirc, easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, editAnchorSetTracked, elevateQuadraticToCubic, ellipsePath, equalizeSegmentHandles, everyNthAnchor, extendToMeet, fillsOpenSubpaths, findPathSnap, findPathSnaps, fitAffine, fitCubicThroughDeletion, fitCubicWithTangents, flatIndexesAfterReverse, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, forEachSegment, growAnchorSelection, growRegion, handleAlongItsAngle, handleAtItsLength, handleBalances, harmonizeAnchors, hasOpenSubpath, identity$1 as identity, intersectSegments, invert$1 as invert, invertAnchorSelection, isSegmentStraight, joinAnchorsAt, joinSubpathEnds, keepCorners, len2, lengthToward, lengthenOpenEnd, lengthenPathEnd, linePath, linear, makeHandlesSymmetric, mapConstraintAnchors, mat3, meanScale, measureAnchorPath, measurePath, moveHandleSymmetric, multiply$1 as multiply, nearestOnCubic, nearestOnLine, nearestOnPath, nearestOnQuadratic, nearestPathAnchor, normalizeZoom, offsetCornerTraces, openEndAt, openEndRay, openPathEnds, pathAnchorPoints, pathAwayFromAnchors, pathCommandCoordCount, pathContainsPoint, pathContainsPolygon, pathContainsRect, pathCrossings, pathDistanceToPoint, pathEndAnchorIndex, pathEndFrame, pathFromD, pathInPoseFrame, pathInWorld, pathIntersectsPolygon, pathIntersectsRect, pathSegments, pathSignedArea, pathThroughPoseFrame, pathToCubicContours, placeRect, pointAlongPath, pointInPath, pointInPolygon, pointSegmentDist2, polygonContainsPath, polygonFromPoints, polygonIntersectsPath, polylineFromPoints, portControls, portCurvePoints, poseFrameInverseOf, poseFrameOf, poseLinearOf, poseRotationOf, prepareBlend, quadraticEvalAt, readAnchorFields, rectMarkerPath, rectPath, rectToContour, regularPolygonPath, remapAnchorValues, remapConstraints, remapPerAnchor, remapPointValues, repeatAlongPath, resamplePath, resolveCorners, resolveCornersWithSources, resolveEasing, restoreCorners, retractHandles, reverseAnchors, reversePath, reverseSubpaths, reviveTypedArrays, rotate, rotateAboutPoint, rotatePathAround, roundRectPath, scale, scalePathToBounds, scaleSegmentHandles, schneiderFit, segmentBetween, segmentExtremaTs, segmentsBetweenAnchors, segmentsCross, setDefaultOpenFill, setSubpathStart, shrinkAnchorSelection, sign, simplifyAnchorsAt, simplifyPath, simplifySpan, simplifySubpath, smoothAnchors, smudgePath, softFalloff, softSelectionBand, softSelectionWeights, solveConstraints, solvePathConstraints, spiroContoursFromControl, spiroContoursOf, spiroControlPath, spiroToPath, splitByClosure, splitCubicAt, splitLineAt, splitQuadraticAt, splitSubpaths, squarePath, starPath, stationsAlongPath, strokeHitTest, sub, subpathEndAt, subpathsOfAnchors, tagTypedArray, tagTypedArrays, transformCoords, transformPath, translate, translateAnchorsSymmetric, translatePath, trimPathAt, typedArrayReplacer, unionBoundsPath, unionBox, unsatisfiedConstraints, untagTypedArray, viewToMat3, withAnchorPoints, worldEditToStorage, writeAnchorField };
|