flo-mat 4.1.5 → 5.0.2
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/__tests__/closest-boundary-point/get-endpoint-info.spec.ts +140 -0
- package/__tests__/closest-boundary-point/root-interval-to-distance-squared-interval.spec.ts +87 -0
- package/__tests__/cp-node/fs/get-all-on-loop-by-loop.spec.ts +55 -0
- package/__tests__/cp-node/fs/get-angle-between-mat-curves.spec.ts +39 -3
- package/__tests__/cp-node/fs/get-boundary-bezier-parts-to-next.spec.ts +87 -3
- package/__tests__/cp-node/fs/get-boundary-beziers-between.spec.ts +68 -3
- package/__tests__/cp-node/fs/get-boundary-beziers-to-next.spec.ts +41 -3
- package/__tests__/cp-node/fs/get-boundary-distance-to-next.spec.ts +20 -3
- package/__tests__/cp-node/fs/get-branch-beziers.spec.ts +42 -3
- package/__tests__/cp-node/fs/get-branch.spec.ts +60 -3
- package/__tests__/cp-node/fs/get-cp-node-ordering.spec.ts +19 -3
- package/__tests__/cp-node/fs/get-distance-to-next.spec.ts +37 -4
- package/__tests__/cp-node/fs/get-edge-direction.spec.ts +50 -3
- package/__tests__/cp-node/fs/get-first-exit.spec.ts +78 -3
- package/__tests__/cp-node/fs/get-hole-closers.spec.ts +32 -3
- package/__tests__/cp-node/fs/get-implied-boundary-bezier-between.spec.ts +48 -3
- package/__tests__/cp-node/fs/get-mat-curve-between.spec.ts +77 -3
- package/__tests__/cp-node/fs/get-mat-curve-to-next.spec.ts +17 -4
- package/__tests__/cp-node/fs/get-mat-curves-between.spec.ts +38 -3
- package/__tests__/cp-node/fs/get-salience.spec.ts +68 -3
- package/__tests__/cp-node/fs/get-vertex-forward-children.spec.ts +40 -3
- package/__tests__/cp-node/fs/insert-cp-node.spec.ts +87 -3
- package/__tests__/cp-node/fs/is-special.spec.ts +1 -1
- package/__tests__/cp-node/fs/remove-cp-node.spec.ts +42 -3
- package/__tests__/find-2-prong/calc-seperation-tolerance.spec.ts +46 -0
- package/__tests__/find-2-prong/get-medial/get-closest-points.spec.ts +1 -1
- package/__tests__/floyd-warshall/get-graph.spec.ts +100 -0
- package/__tests__/get-mats-with-hole.ts +28 -0
- package/__tests__/get-mats1.spec.ts +61 -0
- package/__tests__/get-mats1.ts +75 -67
- package/__tests__/helpers/cp-node-by-id.ts +27 -0
- package/__tests__/helpers/expect-point-close.ts +42 -0
- package/__tests__/mat/hausdorff-distance-one-sided-exceeds.spec.ts +129 -0
- package/__tests__/mat/simplify-mat.spec.ts +85 -0
- package/__tests__/reconstruct-from-mat/reconstruct-from-mat.spec.ts +39 -0
- package/__tests__/specific-cases/test-svgs/achispado.svg +14 -0
- package/__tests__/utils/get-beziers-from-tangents.spec.ts +142 -0
- package/browser/index.js +12985 -9965
- package/browser/index.min.js +1 -1
- package/node/closest-boundary-point/cull-curve-pieces.d.ts +21 -0
- package/node/closest-boundary-point/cull-curve-pieces.js +40 -0
- package/node/closest-boundary-point/cull-curve-pieces.js.map +1 -0
- package/node/closest-boundary-point/get-close-boundary-points-certified.js +5 -2
- package/node/closest-boundary-point/get-close-boundary-points-certified.js.map +1 -1
- package/node/closest-boundary-point/get-endpoint-info.d.ts +39 -0
- package/node/closest-boundary-point/get-endpoint-info.js +78 -0
- package/node/closest-boundary-point/get-endpoint-info.js.map +1 -0
- package/node/closest-boundary-point/get-potential-closest-points-on-curve-certified.js +5 -19
- package/node/closest-boundary-point/get-potential-closest-points-on-curve-certified.js.map +1 -1
- package/node/closest-boundary-point/root-interval-to-distance-squared-interval.d.ts +17 -5
- package/node/closest-boundary-point/root-interval-to-distance-squared-interval.js +37 -50
- package/node/closest-boundary-point/root-interval-to-distance-squared-interval.js.map +1 -1
- package/node/corner/get-corner.d.ts +18 -1
- package/node/corner/get-corner.js +8 -1
- package/node/corner/get-corner.js.map +1 -1
- package/node/corner/get-interface-ccw.js.map +1 -1
- package/node/cp-node/cp-node.d.ts +4 -3
- package/node/cp-node/fs/get-all-on-loop-by-loop.js +0 -4
- package/node/cp-node/fs/get-all-on-loop-by-loop.js.map +1 -1
- package/node/cp-node/fs/get-angle-between-mat-curves.js +6 -4
- package/node/cp-node/fs/get-angle-between-mat-curves.js.map +1 -1
- package/node/cp-node/fs/get-boundary-beziers-between.d.ts +6 -4
- package/node/cp-node/fs/get-boundary-beziers-between.js +6 -4
- package/node/cp-node/fs/get-boundary-beziers-between.js.map +1 -1
- package/node/cp-node/fs/get-branch-beziers.d.ts +2 -1
- package/node/cp-node/fs/get-branch-beziers.js +3 -2
- package/node/cp-node/fs/get-branch-beziers.js.map +1 -1
- package/node/cp-node/fs/get-branch.js +1 -2
- package/node/cp-node/fs/get-branch.js.map +1 -1
- package/node/cp-node/fs/get-distance-to-next.js +4 -2
- package/node/cp-node/fs/get-distance-to-next.js.map +1 -1
- package/node/cp-node/fs/get-first-exit.d.ts +7 -3
- package/node/cp-node/fs/get-first-exit.js +13 -11
- package/node/cp-node/fs/get-first-exit.js.map +1 -1
- package/node/cp-node/fs/get-implied-boundary-bezier-between.d.ts +9 -1
- package/node/cp-node/fs/get-implied-boundary-bezier-between.js +11 -55
- package/node/cp-node/fs/get-implied-boundary-bezier-between.js.map +1 -1
- package/node/cp-node/fs/get-mat-curve-between.d.ts +4 -3
- package/node/cp-node/fs/get-mat-curve-between.js +5 -49
- package/node/cp-node/fs/get-mat-curve-between.js.map +1 -1
- package/node/cp-node/fs/get-mat-curve-to-next.d.ts +1 -1
- package/node/cp-node/fs/get-mat-curves-between.d.ts +8 -0
- package/node/cp-node/fs/get-mat-curves-between.js +9 -2
- package/node/cp-node/fs/get-mat-curves-between.js.map +1 -1
- package/node/cp-node/fs/get-real-prong-count.d.ts +2 -1
- package/node/cp-node/fs/get-real-prong-count.js +11 -5
- package/node/cp-node/fs/get-real-prong-count.js.map +1 -1
- package/node/cp-node/fs/get-salience.d.ts +10 -0
- package/node/cp-node/fs/get-salience.js +17 -1
- package/node/cp-node/fs/get-salience.js.map +1 -1
- package/node/cp-node/fs/is-fully-terminating.d.ts +4 -2
- package/node/cp-node/fs/is-fully-terminating.js +6 -15
- package/node/cp-node/fs/is-fully-terminating.js.map +1 -1
- package/node/cp-node/fs/is-on-same-loop.d.ts +1 -1
- package/node/cp-node/fs/is-special.d.ts +7 -0
- package/node/cp-node/fs/is-special.js +9 -2
- package/node/cp-node/fs/is-special.js.map +1 -1
- package/node/cp-node/fs/is-vertex.d.ts +1 -1
- package/node/cp-node/fs/traverse-edges.d.ts +7 -3
- package/node/cp-node/fs/traverse-edges.js +7 -3
- package/node/cp-node/fs/traverse-edges.js.map +1 -1
- package/node/cp-node/stringification/from-stringifyable.d.ts +2 -2
- package/node/cp-node/stringification/from-stringifyable.js +1 -1
- package/node/cp-node/stringification/from-stringifyable.js.map +1 -1
- package/node/cp-node/stringification/to-stringifyable.d.ts +3 -3
- package/node/cp-node/stringification/to-stringifyable.js +3 -3
- package/node/debug/debug.d.ts +26 -3
- package/node/debug/debug.js +16 -5
- package/node/debug/debug.js.map +1 -1
- package/node/find-2-prong/add-2-prong.js +1 -7
- package/node/find-2-prong/add-2-prong.js.map +1 -1
- package/node/find-2-prong/calc-seperation-tolerance.d.ts +28 -5
- package/node/find-2-prong/calc-seperation-tolerance.js +32 -89
- package/node/find-2-prong/calc-seperation-tolerance.js.map +1 -1
- package/node/find-2-prong/find-2-prong.js +8 -10
- package/node/find-2-prong/find-2-prong.js.map +1 -1
- package/node/find-2-prong/find-and-add-2-prongs.js +2 -2
- package/node/find-2-prong/find-and-add-2-prongs.js.map +1 -1
- package/node/find-2-prong/get-medial/get-antipodal-points.d.ts +1 -2
- package/node/find-2-prong/get-medial/get-antipodal-points.js +2 -3
- package/node/find-2-prong/get-medial/get-antipodal-points.js.map +1 -1
- package/node/find-2-prong/get-medial/get-closest-points.d.ts +1 -8
- package/node/find-2-prong/get-medial/get-closest-points.js +4 -40
- package/node/find-2-prong/get-medial/get-closest-points.js.map +1 -1
- package/node/find-2-prong/reduce-radius.d.ts +1 -1
- package/node/find-2-prong/reduce-radius.js +6 -3
- package/node/find-2-prong/reduce-radius.js.map +1 -1
- package/node/find-3-prong/calc-better-x.js +1 -1
- package/node/find-3-prong/calc-better-x.js.map +1 -1
- package/node/find-3-prong/find-3-prong-for-delta3s.d.ts +3 -2
- package/node/find-3-prong/find-3-prong-for-delta3s.js +35 -41
- package/node/find-3-prong/find-3-prong-for-delta3s.js.map +1 -1
- package/node/find-3-prong/find-3-prong.js +3 -1
- package/node/find-3-prong/find-3-prong.js.map +1 -1
- package/node/find-3-prong/find-and-add-3-prongs.js +16 -0
- package/node/find-3-prong/find-and-add-3-prongs.js.map +1 -1
- package/node/find-mat/create-initial-cp-tree.js +2 -2
- package/node/find-mat/create-initial-cp-tree.js.map +1 -1
- package/node/find-mat/find-mat.js +3 -4
- package/node/find-mat/find-mat.js.map +1 -1
- package/node/find-mat/find-mats.d.ts +6 -12
- package/node/find-mat/find-mats.js +10 -27
- package/node/find-mat/find-mats.js.map +1 -1
- package/node/find-mat/get-dull-corners-on-loop.js +2 -2
- package/node/find-mat/get-dull-corners-on-loop.js.map +1 -1
- package/node/find-mat/get-for-1-prongs-on-loop.js +36 -8
- package/node/find-mat/get-for-1-prongs-on-loop.js.map +1 -1
- package/node/find-mat/get-meta.d.ts +14 -4
- package/node/find-mat/get-meta.js +30 -24
- package/node/find-mat/get-meta.js.map +1 -1
- package/node/find-mat/get-sharp-corners.js +2 -2
- package/node/find-mat/get-sharp-corners.js.map +1 -1
- package/node/find-mat/mat-options.d.ts +2 -2
- package/node/floyd-warshall/get-graph.d.ts +12 -1
- package/node/floyd-warshall/get-graph.js +41 -38
- package/node/floyd-warshall/get-graph.js.map +1 -1
- package/node/geometry/get-bounding-box-.d.ts +16 -2
- package/node/geometry/get-bounding-box-.js +5 -2
- package/node/geometry/get-bounding-box-.js.map +1 -1
- package/node/geometry/get-closest-square-distance-to-rect.d.ts +3 -0
- package/node/geometry/get-closest-square-distance-to-rect.js +7 -5
- package/node/geometry/get-closest-square-distance-to-rect.js.map +1 -1
- package/node/geometry/get-closest-squared-distance-to-rotated-rect.d.ts +4 -0
- package/node/geometry/get-closest-squared-distance-to-rotated-rect.js +11 -5
- package/node/geometry/get-closest-squared-distance-to-rotated-rect.js.map +1 -1
- package/node/get-medial-points/double-double/dd-get-medial-point-coeffs-bez3.js +1 -2
- package/node/get-medial-points/double-double/dd-get-medial-point-coeffs-bez3.js.map +1 -1
- package/node/index.d.ts +3 -2
- package/node/index.js +2 -1
- package/node/index.js.map +1 -1
- package/node/mat/clone-mat.d.ts +9 -0
- package/node/mat/clone-mat.js +17 -0
- package/node/mat/clone-mat.js.map +1 -0
- package/node/mat/clone-meta.d.ts +12 -0
- package/node/mat/clone-meta.js +24 -0
- package/node/mat/clone-meta.js.map +1 -0
- package/node/mat/get-boundary-piece-beziers.d.ts +5 -0
- package/node/mat/get-boundary-piece-beziers.js +7 -93
- package/node/mat/get-boundary-piece-beziers.js.map +1 -1
- package/node/mat/get-largest-3-prong.d.ts +6 -0
- package/node/mat/get-largest-3-prong.js +8 -5
- package/node/mat/get-largest-3-prong.js.map +1 -1
- package/node/mat/get-largest-vertex.d.ts +15 -1
- package/node/mat/get-largest-vertex.js +20 -7
- package/node/mat/get-largest-vertex.js.map +1 -1
- package/node/mat/hausdorff-distance-one-sided-exceeds.d.ts +79 -0
- package/node/mat/hausdorff-distance-one-sided-exceeds.js +251 -0
- package/node/mat/hausdorff-distance-one-sided-exceeds.js.map +1 -0
- package/node/mat/mat-meta.d.ts +0 -6
- package/node/mat/simplify-mat.d.ts +25 -8
- package/node/mat/simplify-mat.js +182 -53
- package/node/mat/simplify-mat.js.map +1 -1
- package/node/mat/trim-mat.d.ts +4 -2
- package/node/mat/trim-mat.js +3 -1
- package/node/mat/trim-mat.js.map +1 -1
- package/node/point-on-shape/get-boundary-tangent-line.d.ts +19 -0
- package/node/point-on-shape/get-boundary-tangent-line.js +33 -0
- package/node/point-on-shape/get-boundary-tangent-line.js.map +1 -0
- package/node/point-on-shape/get-osculating-circle.d.ts +6 -4
- package/node/point-on-shape/get-osculating-circle.js +6 -4
- package/node/point-on-shape/get-osculating-circle.js.map +1 -1
- package/node/point-on-shape/get-pos-corner.js +2 -2
- package/node/point-on-shape/get-pos-corner.js.map +1 -1
- package/node/reconstruct-from-mat/reconstruct-from-mat.js +20 -80
- package/node/reconstruct-from-mat/reconstruct-from-mat.js.map +1 -1
- package/node/reconstruct-from-mat/remove-sat-induced-trivial-3prongs.d.ts +4 -0
- package/node/reconstruct-from-mat/remove-sat-induced-trivial-3prongs.js +4 -0
- package/node/reconstruct-from-mat/remove-sat-induced-trivial-3prongs.js.map +1 -1
- package/node/sat/cull.d.ts +7 -6
- package/node/sat/cull.js +13 -16
- package/node/sat/cull.js.map +1 -1
- package/node/sat/get-sat-culls.d.ts +12 -2
- package/node/sat/get-sat-culls.js +21 -16
- package/node/sat/get-sat-culls.js.map +1 -1
- package/node/svg/get-shape-bounds.d.ts +1 -12
- package/node/svg/get-shape-bounds.js +2 -3
- package/node/svg/get-shape-bounds.js.map +1 -1
- package/node/sweep-line/sweep-line.js.map +1 -1
- package/node/utils/get-beziers-from-tangents.d.ts +28 -0
- package/node/utils/get-beziers-from-tangents.js +92 -0
- package/node/utils/get-beziers-from-tangents.js.map +1 -0
- package/node/vertex/remove-vertex.d.ts +5 -3
- package/node/vertex/remove-vertex.js +5 -3
- package/node/vertex/remove-vertex.js.map +1 -1
- package/package.json +9 -9
- package/qv-infinite-loop.md +120 -0
- package/src/closest-boundary-point/cull-curve-pieces.ts +49 -0
- package/src/closest-boundary-point/get-close-boundary-points-certified.ts +5 -2
- package/src/closest-boundary-point/get-endpoint-info.ts +96 -0
- package/src/closest-boundary-point/get-potential-closest-points-on-curve-certified.ts +5 -23
- package/src/closest-boundary-point/root-interval-to-distance-squared-interval.ts +42 -60
- package/src/corner/get-corner.ts +10 -1
- package/src/corner/get-interface-ccw.ts +2 -2
- package/src/cp-node/cp-node.ts +4 -3
- package/src/cp-node/fs/get-all-on-loop-by-loop.ts +0 -4
- package/src/cp-node/fs/get-angle-between-mat-curves.ts +6 -4
- package/src/cp-node/fs/get-boundary-beziers-between.ts +10 -8
- package/src/cp-node/fs/get-branch-beziers.ts +3 -2
- package/src/cp-node/fs/get-branch.ts +1 -2
- package/src/cp-node/fs/get-distance-to-next.ts +4 -2
- package/src/cp-node/fs/get-first-exit.ts +15 -14
- package/src/cp-node/fs/get-implied-boundary-bezier-between.ts +17 -69
- package/src/cp-node/fs/get-mat-curve-between.ts +9 -67
- package/src/cp-node/fs/get-mat-curves-between.ts +9 -2
- package/src/cp-node/fs/get-real-prong-count.ts +11 -7
- package/src/cp-node/fs/get-salience.ts +15 -2
- package/src/cp-node/fs/is-fully-terminating.ts +6 -18
- package/src/cp-node/fs/is-on-same-loop.ts +2 -2
- package/src/cp-node/fs/is-special.ts +11 -6
- package/src/cp-node/fs/is-vertex.ts +1 -1
- package/src/cp-node/fs/traverse-edges.ts +8 -4
- package/src/cp-node/stringification/from-stringifyable.ts +75 -75
- package/src/cp-node/stringification/to-stringifyable.ts +3 -3
- package/src/debug/debug.ts +44 -8
- package/src/find-2-prong/add-2-prong.ts +2 -9
- package/src/find-2-prong/calc-seperation-tolerance.ts +34 -115
- package/src/find-2-prong/find-2-prong.ts +9 -11
- package/src/find-2-prong/find-and-add-2-prongs.ts +2 -2
- package/src/find-2-prong/get-medial/get-antipodal-points.ts +1 -3
- package/src/find-2-prong/get-medial/get-closest-points.ts +6 -51
- package/src/find-2-prong/reduce-radius.ts +6 -4
- package/src/find-3-prong/calc-better-x.ts +2 -2
- package/src/find-3-prong/find-3-prong-for-delta3s.ts +197 -214
- package/src/find-3-prong/find-3-prong.ts +54 -51
- package/src/find-3-prong/find-and-add-3-prongs.ts +20 -1
- package/src/find-mat/create-initial-cp-tree.ts +2 -2
- package/src/find-mat/find-mat.ts +4 -6
- package/src/find-mat/find-mats.ts +83 -105
- package/src/find-mat/get-dull-corners-on-loop.ts +2 -2
- package/src/find-mat/get-for-1-prongs-on-loop.ts +40 -8
- package/src/find-mat/get-meta.ts +34 -39
- package/src/find-mat/get-sharp-corners.ts +2 -2
- package/src/find-mat/mat-options.ts +2 -2
- package/src/floyd-warshall/get-graph.ts +46 -47
- package/src/geometry/get-bounding-box-.ts +5 -2
- package/src/geometry/get-closest-square-distance-to-rect.ts +7 -7
- package/src/geometry/get-closest-squared-distance-to-rotated-rect.ts +12 -10
- package/src/get-medial-points/double-double/dd-get-medial-point-coeffs-bez3.ts +1 -2
- package/src/index.ts +3 -2
- package/src/mat/clone-mat.ts +9 -3
- package/src/mat/clone-meta.ts +8 -0
- package/src/mat/get-boundary-piece-beziers.ts +16 -117
- package/src/mat/get-largest-3-prong.ts +9 -6
- package/src/mat/get-largest-vertex.ts +25 -9
- package/src/mat/hausdorff-distance-one-sided-exceeds.ts +314 -0
- package/src/mat/mat-meta.ts +0 -9
- package/src/mat/simplify-mat.ts +254 -116
- package/src/mat/trim-mat.ts +6 -4
- package/src/point-on-shape/get-boundary-tangent-line.ts +36 -0
- package/src/point-on-shape/get-osculating-circle.ts +7 -5
- package/src/point-on-shape/get-pos-corner.ts +2 -2
- package/src/reconstruct-from-mat/reconstruct-from-mat.ts +22 -111
- package/src/reconstruct-from-mat/remove-sat-induced-trivial-3prongs.ts +4 -0
- package/src/sat/cull.ts +16 -20
- package/src/sat/get-sat-culls.ts +28 -23
- package/src/svg/get-shape-bounds.ts +2 -3
- package/src/sweep-line/sweep-line.ts +1 -1
- package/src/utils/get-beziers-from-tangents.ts +110 -0
- package/src/utils/map-map.ts +1 -1
- package/src/vertex/remove-vertex.ts +5 -3
- package/__tests__/cp-node/fs/get-distance-between.spec.ts +0 -7
- package/__tests__/cp-node/fs/get-terminating-on-circle.spec.ts +0 -24
- package/__tests__/cp-node/fs/is-single-3-prong.spec.ts +0 -17
- package/__tests__/cp-node/fs/iterate-all-on-loop.spec.ts +0 -17
- package/__tests__/cp-node/fs/traverse-all-forward.spec.ts +0 -14
- package/node/closest-boundary-point/cull-bezier-pieces-1.d.ts +0 -9
- package/node/closest-boundary-point/cull-bezier-pieces-1.js +0 -17
- package/node/closest-boundary-point/cull-bezier-pieces-1.js.map +0 -1
- package/node/closest-boundary-point/cull-by-loose-bounding-box.d.ts +0 -13
- package/node/closest-boundary-point/cull-by-loose-bounding-box.js +0 -27
- package/node/closest-boundary-point/cull-by-loose-bounding-box.js.map +0 -1
- package/node/closest-boundary-point/cull-by-tight-boundary-box.d.ts +0 -11
- package/node/closest-boundary-point/cull-by-tight-boundary-box.js +0 -27
- package/node/closest-boundary-point/cull-by-tight-boundary-box.js.map +0 -1
- package/node/cp-node/fs/find-first.d.ts +0 -10
- package/node/cp-node/fs/find-first.js +0 -19
- package/node/cp-node/fs/find-first.js.map +0 -1
- package/node/debug/functions/check-ordering.d.ts +0 -4
- package/node/debug/functions/check-ordering.js +0 -43
- package/node/debug/functions/check-ordering.js.map +0 -1
- package/node/find-2-prong/cull-bezier-pieces.d.ts +0 -13
- package/node/find-2-prong/cull-bezier-pieces.js +0 -43
- package/node/find-2-prong/cull-bezier-pieces.js.map +0 -1
- package/node/floyd-warshall/get-hole-closer-pairs.d.ts +0 -8
- package/node/floyd-warshall/get-hole-closer-pairs.js +0 -27
- package/node/floyd-warshall/get-hole-closer-pairs.js.map +0 -1
- package/node/utils/dual-set.d.ts +0 -27
- package/node/utils/dual-set.js +0 -55
- package/node/utils/dual-set.js.map +0 -1
- package/node/utils/tri-map.d.ts +0 -27
- package/node/utils/tri-map.js +0 -49
- package/node/utils/tri-map.js.map +0 -1
- package/src/closest-boundary-point/cull-bezier-pieces-1.ts +0 -36
- package/src/closest-boundary-point/cull-by-loose-bounding-box.ts +0 -42
- package/src/closest-boundary-point/cull-by-tight-boundary-box.ts +0 -43
- package/src/closest-boundary-point/get-p-from-box.ts +0 -14
- package/src/cp-node/fs/add-distance-from.ts +0 -49
- package/src/cp-node/fs/get-distance-between.ts +0 -16
- package/src/cp-node/fs/get-terminating-on-circle.ts +0 -24
- package/src/cp-node/fs/is-single-3-prong.ts +0 -15
- package/src/cp-node/fs/iterate-all-on-loop.ts +0 -15
- package/src/cp-node/fs/traverse-all-forward.ts +0 -24
- package/src/debug/functions/draw/draw-beziers-as-single-path.ts +0 -40
- package/src/debug/functions/draw/draw-disk.ts +0 -34
- package/src/debug/functions/draw/xmlns.ts +0 -5
- package/src/find-2-prong/cull-bezier-pieces.ts +0 -61
- package/src/find-2-prong/find-and-add-2-prong.ts +0 -30
- package/src/find-2-prong/get-medial/get-closest-points-d.ts +0 -213
- package/src/find-2-prong/x-for-debugging.ts +0 -13
- package/src/floyd-warshall/get-hole-closer-pairs.ts +0 -35
- package/src/mat/get-two-prong-type.ts +0 -13
- package/src/point-on-shape/is-pos-dull-corner.ts +0 -18
- package/src/point-on-shape/is-pos-quite-dull-corner.ts +0 -18
- package/src/point-on-shape/is-pos-quite-sharp-corner.ts +0 -18
- package/src/point-on-shape/pos-to-human-string.ts +0 -18
- package/src/sweep-line/are-boxes-intersecting.ts +0 -37
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { expect, test } from '@jest/globals';
|
|
2
|
+
import type { Curve } from 'flo-boolean';
|
|
3
|
+
import type { FootAndEndpointInfo } from '../../src/closest-boundary-point/foot-and-endpoint-info.js';
|
|
4
|
+
import { evalDeCasteljauDd } from 'flo-bezier3';
|
|
5
|
+
import { ddDiffDouble, ddMultDd, ddAddDd, ddLt, ddGt, ddToStr } from 'double-double';
|
|
6
|
+
import { getEndpointInfoCertified } from '../../src/closest-boundary-point/get-endpoint-info.js';
|
|
7
|
+
import { squaredDistanceBetweenDd } from '../../src/find-2-prong/squared-distance-between-dd.js';
|
|
8
|
+
import { eps } from '../../src/error-analysis/gamma.js';
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The *previous* (library) implementation, kept here for comparison only: the
|
|
13
|
+
* point is rounded to double precision *before* the distance is taken, which
|
|
14
|
+
* introduces an absolute error of about `|p|·eps/2` per coordinate; the
|
|
15
|
+
* returned interval only accounts for a *relative* error of `eps` in the
|
|
16
|
+
* squared distance and is thus too narrow whenever the point is closer to `x`
|
|
17
|
+
* than to the origin.
|
|
18
|
+
*/
|
|
19
|
+
function getEndpointInfoUncertified(
|
|
20
|
+
curve: Curve,
|
|
21
|
+
x: number[],
|
|
22
|
+
t: number): FootAndEndpointInfo {
|
|
23
|
+
|
|
24
|
+
const { ps } = curve;
|
|
25
|
+
|
|
26
|
+
const p = evalDeCasteljauDd(ps, [0,t]).map(v => v[0] + v[1]);
|
|
27
|
+
const d = squaredDistanceBetweenDd(p, x);
|
|
28
|
+
const dSquaredI = [d*(1 - eps), d*(1 + eps)];
|
|
29
|
+
|
|
30
|
+
const t_ = t === 0 ? 1 : t;
|
|
31
|
+
const curve_ = t === 0 ? curve.prev : curve;
|
|
32
|
+
|
|
33
|
+
return { curve: curve_, t: t_, dSquaredI };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The squared distance from `x` to the point at `t` on `ps` in double-double
|
|
39
|
+
* precision (accurate to roughly 30 significant digits): the reference value.
|
|
40
|
+
*/
|
|
41
|
+
function squaredDistanceDd(ps: number[][], t: number, x: number[]): number[] {
|
|
42
|
+
const pDd = evalDeCasteljauDd(ps, [0,t]);
|
|
43
|
+
const dx = ddDiffDouble(pDd[0], x[0]);
|
|
44
|
+
const dy = ddDiffDouble(pDd[1], x[1]);
|
|
45
|
+
return ddAddDd(ddMultDd(dx,dx), ddMultDd(dy,dy));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const contains = (I: number[], dRef: number[]) => !ddLt(dRef, [0,I[0]]) && !ddGt(dRef, [0,I[1]]);
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
test('getEndpointInfoCertified vs the old implementation - point far from the origin, close to x', function() {
|
|
52
|
+
// A cubic with a chord of about 1000 units, living around coordinate
|
|
53
|
+
// 1000..2000 (as e.g. glyph outlines do); the point at `t` is about
|
|
54
|
+
// 1300 from the origin but less than 1 unit from `x`.
|
|
55
|
+
const ps = [[1000,0],[1300,0],[1700,0],[2000,0]];
|
|
56
|
+
const t = 0.3;
|
|
57
|
+
const curve = { ps } as Curve;
|
|
58
|
+
const p = evalDeCasteljauDd(ps, [0,t]).map(v => v[0] + v[1]);
|
|
59
|
+
const x = [Math.floor(p[0]), 0]; // on the line, just before the point
|
|
60
|
+
expect(p[0] - x[0]).toBeGreaterThan(0.1);
|
|
61
|
+
expect(p[0] - x[0]).toBeLessThan(1);
|
|
62
|
+
|
|
63
|
+
// The reference squared distance to ~30 digits. The error from rounding
|
|
64
|
+
// the point to double is about |p|*eps/2 ~ 1300 * 1.1e-16 ~ 1.4e-13 in
|
|
65
|
+
// the coordinate, i.e. ~3e-13 in the squared distance - roughly a
|
|
66
|
+
// thousand times the `eps` relative error the old interval claims.
|
|
67
|
+
const dRef = squaredDistanceDd(ps, t, x);
|
|
68
|
+
|
|
69
|
+
const oldI = getEndpointInfoUncertified(curve, x, t).dSquaredI;
|
|
70
|
+
const newI = getEndpointInfoCertified(curve, x, t).dSquaredI;
|
|
71
|
+
|
|
72
|
+
console.log(
|
|
73
|
+
`reference d² = ${ddToStr(dRef)}\n` +
|
|
74
|
+
`old interval = [${oldI[0]}, ${oldI[1]}] width/d = ${(oldI[1]-oldI[0])/oldI[0]}\n` +
|
|
75
|
+
`new interval = [${newI[0]}, ${newI[1]}] width/d = ${(newI[1]-newI[0])/newI[0]}\n` +
|
|
76
|
+
`old interval contains reference: ${contains(oldI, dRef)}\n` +
|
|
77
|
+
`new interval contains reference: ${contains(newI, dRef)}`
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
// the old interval is far too narrow: it misses the reference value
|
|
81
|
+
expect(contains(oldI, dRef)).toBe(false);
|
|
82
|
+
// its claimed relative width is just ~2*eps (a couple of ulps)...
|
|
83
|
+
expect((oldI[1] - oldI[0]) / oldI[0]).toBeLessThan(4*eps);
|
|
84
|
+
// ...while the reference lies ~1000*eps away from it
|
|
85
|
+
const dRefApprox = dRef[1] + dRef[0];
|
|
86
|
+
expect(Math.abs(dRefApprox - oldI[1]) / oldI[1]).toBeGreaterThan(100*eps);
|
|
87
|
+
|
|
88
|
+
// the certified interval contains it and is only ~8*eps wide
|
|
89
|
+
expect(contains(newI, dRef)).toBe(true);
|
|
90
|
+
expect((newI[1] - newI[0]) / newI[0]).toBeLessThan(16*eps);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
test('getEndpointInfoCertified - always contains the reference, old version does not', function() {
|
|
95
|
+
// sweep a few parameters and offsets on a curve far from the origin
|
|
96
|
+
const ps = [[5000,3000],[5400,3900],[6100,2200],[6000,3000]];
|
|
97
|
+
const curve = { ps } as Curve;
|
|
98
|
+
|
|
99
|
+
let oldMisses = 0;
|
|
100
|
+
let checks = 0;
|
|
101
|
+
for (const t of [0.1, 0.3, 0.45, 0.7, 0.9]) {
|
|
102
|
+
const p = evalDeCasteljauDd(ps, [0,t]).map(v => v[0] + v[1]);
|
|
103
|
+
for (const off of [[0.5,0.25],[-1,0.75],[2,-3],[0.1,-0.1]]) {
|
|
104
|
+
const x = [p[0] + off[0], p[1] + off[1]];
|
|
105
|
+
const dRef = squaredDistanceDd(ps, t, x);
|
|
106
|
+
|
|
107
|
+
expect(contains(getEndpointInfoCertified(curve, x, t).dSquaredI, dRef)).toBe(true);
|
|
108
|
+
if (!contains(getEndpointInfoUncertified(curve, x, t).dSquaredI, dRef)) { oldMisses++; }
|
|
109
|
+
checks++;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// the old interval misses most of the time (it is only right by luck)
|
|
114
|
+
expect(oldMisses).toBeGreaterThan(checks/2);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
test('getEndpointInfoCertified - x (numerically) on the point: the lower bound is 0', function() {
|
|
119
|
+
const ps = [[1000,0],[1300,0],[1700,0],[2000,0]];
|
|
120
|
+
const curve = { ps } as Curve;
|
|
121
|
+
const t = 0.3;
|
|
122
|
+
const x = evalDeCasteljauDd(ps, [0,t]).map(v => v[0] + v[1]); // the rounded point
|
|
123
|
+
|
|
124
|
+
const [lo, hi] = getEndpointInfoCertified(curve, x, t).dSquaredI;
|
|
125
|
+
// the true distance is about the rounding error of the point (~1e-13)
|
|
126
|
+
expect(lo).toBeGreaterThanOrEqual(0);
|
|
127
|
+
expect(hi).toBeLessThan(1e-24);
|
|
128
|
+
expect(contains([lo, hi], squaredDistanceDd(ps, t, x))).toBe(true);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
test('getEndpointInfoCertified - endpoint at t=0 is attributed to the previous curve', function() {
|
|
133
|
+
const prev = { ps: [[0,0],[10,0]] } as Curve;
|
|
134
|
+
const curve = { ps: [[10,0],[10,10]], prev } as Curve;
|
|
135
|
+
const info = getEndpointInfoCertified(curve, [10,-1], 0);
|
|
136
|
+
expect(info.curve).toBe(prev);
|
|
137
|
+
expect(info.t).toBe(1);
|
|
138
|
+
expect(info.dSquaredI[0]).toBeLessThanOrEqual(1);
|
|
139
|
+
expect(info.dSquaredI[1]).toBeGreaterThanOrEqual(1);
|
|
140
|
+
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { expect, test } from '@jest/globals';
|
|
2
|
+
import { evalDeCasteljau, getIntervalBox } from 'flo-bezier3';
|
|
3
|
+
import { squaredDistanceBetween } from 'flo-vector2d';
|
|
4
|
+
import { rootIntervalToDistanceSquaredInterval } from '../../src/closest-boundary-point/root-interval-to-distance-squared-interval.js';
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
test('rootIntervalToDistanceSquaredInterval - exact cases on a plain box', function() {
|
|
8
|
+
const box = [[10, 20], [14, 23]]; // 4 wide, 3 high
|
|
9
|
+
|
|
10
|
+
// p inside the box: the min is 0, the max is the furthest corner
|
|
11
|
+
{
|
|
12
|
+
const [lo, hi] = rootIntervalToDistanceSquaredInterval(box, [11, 21]);
|
|
13
|
+
expect(lo).toBe(0);
|
|
14
|
+
expect(hi).toBeCloseTo(3**2 + 2**2, 12); // corner [14,23]
|
|
15
|
+
}
|
|
16
|
+
// p directly below the box (within its x range): the min is the vertical
|
|
17
|
+
// gap, *not* the distance to a corner (which the old version returned)
|
|
18
|
+
{
|
|
19
|
+
const [lo, hi] = rootIntervalToDistanceSquaredInterval(box, [12, 15]);
|
|
20
|
+
expect(lo).toBeCloseTo(5**2, 12);
|
|
21
|
+
expect(lo).toBeLessThan(2**2 + 5**2); // nearest corner [10,20] or [14,20]
|
|
22
|
+
expect(hi).toBeCloseTo(2**2 + 8**2, 12);
|
|
23
|
+
}
|
|
24
|
+
// p diagonally away from the box: the min and max are both at corners
|
|
25
|
+
{
|
|
26
|
+
const [lo, hi] = rootIntervalToDistanceSquaredInterval(box, [7, 16]);
|
|
27
|
+
expect(lo).toBeCloseTo(3**2 + 4**2, 12); // corner [10,20]
|
|
28
|
+
expect(hi).toBeCloseTo(7**2 + 7**2, 12); // corner [14,23]
|
|
29
|
+
}
|
|
30
|
+
// p on the box's boundary
|
|
31
|
+
{
|
|
32
|
+
const [lo] = rootIntervalToDistanceSquaredInterval(box, [10, 21.5]);
|
|
33
|
+
expect(lo).toBe(0);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
test('rootIntervalToDistanceSquaredInterval - encloses the distances to a curve piece', function() {
|
|
39
|
+
// the box engulfs the piece, so the squared distance from `p` to every
|
|
40
|
+
// point of the piece must lie within the returned interval
|
|
41
|
+
const curves = [
|
|
42
|
+
[[0,0],[30,80],[70,-40],[100,0]],
|
|
43
|
+
[[1000,2000],[1200,2500],[1800,1900],[2000,2000]],
|
|
44
|
+
[[-5,3],[4,9],[12,-2]],
|
|
45
|
+
];
|
|
46
|
+
const tRanges: [number, number][] = [[0.1, 0.11], [0.5, 0.5002], [0.9, 0.95], [0, 1]];
|
|
47
|
+
const offsets = [[0,0],[0.3,-0.2],[5,0],[0,-7],[40,40],[-1000,1]];
|
|
48
|
+
|
|
49
|
+
for (const ps of curves) {
|
|
50
|
+
for (const ts of tRanges) {
|
|
51
|
+
const box = getIntervalBox(ps, ts);
|
|
52
|
+
const mid = evalDeCasteljau(ps, (ts[0]+ts[1])/2);
|
|
53
|
+
for (const off of offsets) {
|
|
54
|
+
const p = [mid[0] + off[0], mid[1] + off[1]];
|
|
55
|
+
const [lo, hi] = rootIntervalToDistanceSquaredInterval(box, p);
|
|
56
|
+
expect(lo).toBeLessThanOrEqual(hi);
|
|
57
|
+
|
|
58
|
+
for (let i=0; i<=50; i++) {
|
|
59
|
+
const t = ts[0] + (ts[1]-ts[0])*i/50;
|
|
60
|
+
const d = squaredDistanceBetween(p, evalDeCasteljau(ps, t));
|
|
61
|
+
expect(d).toBeGreaterThanOrEqual(lo);
|
|
62
|
+
expect(d).toBeLessThanOrEqual(hi);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
test('rootIntervalToDistanceSquaredInterval - the min is tight (not a corner distance)', function() {
|
|
71
|
+
// A nearly flat piece of a curve with `p` sitting right above its middle:
|
|
72
|
+
// the true minimum distance is about the vertical gap, while the
|
|
73
|
+
// distance to the nearest box corner is much larger.
|
|
74
|
+
const ps = [[0,0],[33,0.2],[66,0.2],[100,0]];
|
|
75
|
+
const ts: [number, number] = [0.2, 0.8];
|
|
76
|
+
const box = getIntervalBox(ps, ts);
|
|
77
|
+
const p = [50, 10];
|
|
78
|
+
|
|
79
|
+
const [lo] = rootIntervalToDistanceSquaredInterval(box, p);
|
|
80
|
+
const nearestCornerSq = Math.min(
|
|
81
|
+
...[[box[0][0],box[0][1]],[box[0][0],box[1][1]],[box[1][0],box[0][1]],[box[1][0],box[1][1]]]
|
|
82
|
+
.map(c => squaredDistanceBetween(p, c))
|
|
83
|
+
);
|
|
84
|
+
// the gap is ~10 so lo ~ 100, while the corners are ~30 away horizontally
|
|
85
|
+
expect(lo).toBeLessThan(11**2);
|
|
86
|
+
expect(nearestCornerSq).toBeGreaterThan(30**2);
|
|
87
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { expect, test } from '@jest/globals';
|
|
2
|
+
import { getAllOnLoop_ByLoop } from '../../../src/cp-node/fs/get-all-on-loop-by-loop.js';
|
|
3
|
+
import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
|
|
4
|
+
import { getMats1 } from '../../get-mats1.js';
|
|
5
|
+
import { getMatsWithHole } from '../../get-mats-with-hole.js';
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
test('getAllOnLoop_ByLoop - single loop', function() {
|
|
9
|
+
const { cpNode } = getMats1()[0];
|
|
10
|
+
const all = getAllOnLoop(cpNode);
|
|
11
|
+
|
|
12
|
+
for (const cp of all) {
|
|
13
|
+
const cpNodess = getAllOnLoop_ByLoop(cp);
|
|
14
|
+
expect(cpNodess.length).toBe(1);
|
|
15
|
+
expect(cpNodess[0].length).toBe(all.length);
|
|
16
|
+
expect(cpNodess[0][0]).toBe(cp);
|
|
17
|
+
// same nodes, in the same (boundary) order
|
|
18
|
+
const expected = getAllOnLoop(cp);
|
|
19
|
+
expect(cpNodess[0].every((c, i) => c === expected[i])).toBe(true);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
test('getAllOnLoop_ByLoop - two loops joined by hole closers', function() {
|
|
25
|
+
const { cpNode } = getMatsWithHole()[0];
|
|
26
|
+
// `getAllOnLoop` follows `next` across the hole closers and so visits
|
|
27
|
+
// the nodes of *both* loops
|
|
28
|
+
const all = getAllOnLoop(cpNode);
|
|
29
|
+
const loops = new Set(all.map(cp => cp.pointOnShape.curve.loop));
|
|
30
|
+
expect(loops.size).toBe(2);
|
|
31
|
+
|
|
32
|
+
// From *every* start node (in particular from hole closers, which used
|
|
33
|
+
// to drop the other loop) every node must be returned exactly once,
|
|
34
|
+
// grouped by loop.
|
|
35
|
+
for (const cp of all) {
|
|
36
|
+
const cpNodess = getAllOnLoop_ByLoop(cp);
|
|
37
|
+
|
|
38
|
+
expect(cpNodess.length).toBe(2);
|
|
39
|
+
const flat = cpNodess.flat();
|
|
40
|
+
expect(flat.length).toBe(all.length);
|
|
41
|
+
expect(new Set(flat).size).toBe(all.length);
|
|
42
|
+
for (const c of all) { expect(flat.includes(c)).toBe(true); }
|
|
43
|
+
|
|
44
|
+
// the first group starts at the given node
|
|
45
|
+
expect(cpNodess[0][0]).toBe(cp);
|
|
46
|
+
|
|
47
|
+
// each group is on a single loop and the groups are on different ones
|
|
48
|
+
const groupLoops = cpNodess.map(cpNodes => {
|
|
49
|
+
const loop = cpNodes[0].pointOnShape.curve.loop;
|
|
50
|
+
for (const c of cpNodes) { expect(c.pointOnShape.curve.loop).toBe(loop); }
|
|
51
|
+
return loop;
|
|
52
|
+
});
|
|
53
|
+
expect(new Set(groupLoops).size).toBe(2);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
@@ -1,7 +1,43 @@
|
|
|
1
1
|
import { expect, test } from '@jest/globals';
|
|
2
2
|
import { getInitialDegAngleBetweenMatCurves } from '../../../src/cp-node/fs/get-angle-between-mat-curves.js';
|
|
3
|
+
import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
|
|
4
|
+
import { isTerminating } from '../../../src/cp-node/fs/is-terminating.js';
|
|
5
|
+
import { getMats1 } from '../../get-mats1.js';
|
|
6
|
+
import { cpNodesByIdOn } from '../../helpers/cp-node-by-id.js';
|
|
3
7
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
8
|
+
|
|
9
|
+
test('getInitialDegAngleBetweenMatCurves', function() {
|
|
10
|
+
const { cpNode } = getMats1()[0];
|
|
11
|
+
const byId = cpNodesByIdOn(cpNode);
|
|
12
|
+
const angle = (id1: number, id2: number) =>
|
|
13
|
+
getInitialDegAngleBetweenMatCurves(byId(id1), byId(id2));
|
|
14
|
+
|
|
15
|
+
// The angle is between the *initial* tangents of the MAT edges leaving
|
|
16
|
+
// the two `CpNode`s, folded into [0,90] (it is `|asin(cross)|`).
|
|
17
|
+
const nonTerminating = getAllOnLoop(cpNode).filter(cp => !isTerminating(cp));
|
|
18
|
+
for (const a of nonTerminating) {
|
|
19
|
+
expect(getInitialDegAngleBetweenMatCurves(a, a)).toBeCloseTo(0, 10);
|
|
20
|
+
for (const b of nonTerminating) {
|
|
21
|
+
const ab = getInitialDegAngleBetweenMatCurves(a, b);
|
|
22
|
+
const ba = getInitialDegAngleBetweenMatCurves(b, a);
|
|
23
|
+
expect(ab).toBeCloseTo(ba, 10);
|
|
24
|
+
expect(ab).toBeGreaterThanOrEqual(0);
|
|
25
|
+
expect(ab).toBeLessThanOrEqual(90);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// The 3-prong with center [81.5,18.5] (ids 147, 145, 146) has contact
|
|
30
|
+
// points [46,18.5], [81.5,54] and [117,18.5]; its edges leave along the
|
|
31
|
+
// bisectors (-1,1), (1,1) and (0,-1).
|
|
32
|
+
expect(angle(147, 145)).toBeCloseTo(90, 8);
|
|
33
|
+
expect(angle(147, 146)).toBeCloseTo(45, 8); // 135 degrees folded into [0,90]
|
|
34
|
+
expect(angle(145, 146)).toBeCloseTo(45, 8);
|
|
35
|
+
|
|
36
|
+
// The medial axis is smooth through a 2-prong: the edge leaving the sharp
|
|
37
|
+
// corner [24,8] (id 1) and the edge continuing from the 2-prong it reaches
|
|
38
|
+
// (id 10) share a tangent.
|
|
39
|
+
expect(angle(1, 10)).toBeCloseTo(0, 6);
|
|
40
|
+
// ...and the two edges leaving a 2-prong (ids 10 and 11) are exactly
|
|
41
|
+
// opposite, which also folds to 0.
|
|
42
|
+
expect(angle(10, 11)).toBeCloseTo(0, 6);
|
|
7
43
|
});
|
|
@@ -1,7 +1,91 @@
|
|
|
1
1
|
import { expect, test } from '@jest/globals';
|
|
2
|
+
import { fromTo, totalLength } from 'flo-bezier3';
|
|
2
3
|
import { getBoundaryBezierPartsToNext } from '../../../src/cp-node/fs/get-boundary-bezier-parts-to-next.js';
|
|
4
|
+
import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
|
|
5
|
+
import { getAllOnLoop_ByLoop } from '../../../src/cp-node/fs/get-all-on-loop-by-loop.js';
|
|
6
|
+
import { getMats1 } from '../../get-mats1.js';
|
|
7
|
+
import { getMatsWithHole } from '../../get-mats-with-hole.js';
|
|
8
|
+
import { cpNodesByIdOn } from '../../helpers/cp-node-by-id.js';
|
|
3
9
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
10
|
+
|
|
11
|
+
test('getBoundaryBezierPartsToNext', function() {
|
|
12
|
+
const { cpNode } = getMats1()[0];
|
|
13
|
+
const byId = cpNodesByIdOn(cpNode);
|
|
14
|
+
|
|
15
|
+
{
|
|
16
|
+
// id 1 is at the end (t=1) of curve 0 and its next (id 10) at the end
|
|
17
|
+
// of curve 1 - so a degenerate piece of curve 0 and all of curve 1.
|
|
18
|
+
const cp = byId(1);
|
|
19
|
+
const parts = getBoundaryBezierPartsToNext(cp);
|
|
20
|
+
expect(parts.length).toBe(2);
|
|
21
|
+
expect(parts[0].ps).toBe(cp.pointOnShape.curve.ps);
|
|
22
|
+
expect(parts[0].ts).toEqual([1, 1]);
|
|
23
|
+
expect(parts[1].ps).toBe(cp.next.pointOnShape.curve.ps);
|
|
24
|
+
expect(parts[1].ts).toEqual([0, 1]);
|
|
25
|
+
}
|
|
26
|
+
{
|
|
27
|
+
// id 147 and its next (id 2) are both on curve 2 - a single piece.
|
|
28
|
+
const cp = byId(147);
|
|
29
|
+
const parts = getBoundaryBezierPartsToNext(cp);
|
|
30
|
+
expect(parts.length).toBe(1);
|
|
31
|
+
expect(parts[0].ps).toBe(cp.pointOnShape.curve.ps);
|
|
32
|
+
expect(parts[0].ts).toEqual([cp.pointOnShape.t, 1]);
|
|
33
|
+
expect(parts[0].ts[0]).toBeCloseTo(0.2282608695652173, 15);
|
|
34
|
+
}
|
|
35
|
+
{
|
|
36
|
+
// ids 150 -> 143 are both strictly inside curve 0
|
|
37
|
+
const cp = byId(150);
|
|
38
|
+
const parts = getBoundaryBezierPartsToNext(cp);
|
|
39
|
+
expect(parts.length).toBe(1);
|
|
40
|
+
expect(parts[0].ts).toEqual([cp.pointOnShape.t, cp.next.pointOnShape.t]);
|
|
41
|
+
expect(parts[0].ts[0]).toBeLessThan(parts[0].ts[1]);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Structural invariants for every node: starts at the (curve,t) of this
|
|
45
|
+
// node, ends at the (curve,t) of the next node, skipped curves are taken
|
|
46
|
+
// whole, and the parameter intervals are ordered.
|
|
47
|
+
let total = 0;
|
|
48
|
+
for (const cp of getAllOnLoop(cpNode)) {
|
|
49
|
+
const parts = getBoundaryBezierPartsToNext(cp);
|
|
50
|
+
expect(parts.length).toBeGreaterThan(0);
|
|
51
|
+
|
|
52
|
+
const first = parts[0];
|
|
53
|
+
const last = parts[parts.length-1];
|
|
54
|
+
expect(first.ps).toBe(cp.pointOnShape.curve.ps);
|
|
55
|
+
expect(first.ts[0]).toBe(cp.pointOnShape.t);
|
|
56
|
+
expect(last.ps).toBe(cp.next.pointOnShape.curve.ps);
|
|
57
|
+
expect(last.ts[1]).toBe(cp.next.pointOnShape.t);
|
|
58
|
+
for (let i=1; i<parts.length; i++) {
|
|
59
|
+
expect(parts[i].ts[0]).toBe(0);
|
|
60
|
+
if (i < parts.length-1) { expect(parts[i].ts[1]).toBe(1); }
|
|
61
|
+
}
|
|
62
|
+
if (parts.length > 1) { expect(first.ts[1]).toBe(1); }
|
|
63
|
+
for (const { ts } of parts) { expect(ts[0]).toBeLessThanOrEqual(ts[1]); }
|
|
64
|
+
|
|
65
|
+
total += parts.reduce((s, bp) => s + totalLength(fromTo(bp.ps, bp.ts[0], bp.ts[1])), 0);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ...and all the pieces together cover the boundary exactly once.
|
|
69
|
+
const perimeter = cpNode.pointOnShape.curve.loop.curves
|
|
70
|
+
.reduce((s, curve) => s + totalLength(curve.ps), 0);
|
|
71
|
+
expect(total).toBeCloseTo(perimeter, 8);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
test('getBoundaryBezierPartsToNext - hole closers', function() {
|
|
76
|
+
const { cpNode } = getMatsWithHole()[0];
|
|
77
|
+
const cpNodes = getAllOnLoop_ByLoop(cpNode).flat();
|
|
78
|
+
|
|
79
|
+
// `[]` if and only if the next `CpNode` is on another loop
|
|
80
|
+
let crossings = 0;
|
|
81
|
+
for (const cp of cpNodes) {
|
|
82
|
+
const crossesLoops = cp.pointOnShape.curve.loop !== cp.next.pointOnShape.curve.loop;
|
|
83
|
+
const parts = getBoundaryBezierPartsToNext(cp);
|
|
84
|
+
expect(parts.length === 0).toBe(crossesLoops);
|
|
85
|
+
if (crossesLoops) {
|
|
86
|
+
crossings++;
|
|
87
|
+
expect(cp.isHoleClosing).toBe(true);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
expect(crossings).toBeGreaterThan(0);
|
|
7
91
|
});
|
|
@@ -1,7 +1,72 @@
|
|
|
1
1
|
import { expect, test } from '@jest/globals';
|
|
2
|
+
import { totalLength } from 'flo-bezier3';
|
|
2
3
|
import { getBoundaryBeziersBetween } from '../../../src/cp-node/fs/get-boundary-beziers-between.js';
|
|
4
|
+
import { getBoundaryBeziersToNext } from '../../../src/cp-node/fs/get-boundary-beziers-to-next.js';
|
|
5
|
+
import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
|
|
6
|
+
import { getMats1 } from '../../get-mats1.js';
|
|
7
|
+
import { getMatsWithHole } from '../../get-mats-with-hole.js';
|
|
8
|
+
import { cpNodesByIdOn } from '../../helpers/cp-node-by-id.js';
|
|
9
|
+
import { expectBeziersConnected, expectPointClose } from '../../helpers/expect-point-close.js';
|
|
3
10
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
11
|
+
|
|
12
|
+
const length = (pss: number[][][]) => pss.reduce((s, ps) => s + totalLength(ps), 0);
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
test('getBoundaryBeziersBetween', function() {
|
|
16
|
+
const { cpNode } = getMats1()[0];
|
|
17
|
+
const byId = cpNodesByIdOn(cpNode);
|
|
18
|
+
|
|
19
|
+
// to the next node: same as `getBoundaryBeziersToNext`
|
|
20
|
+
for (const cp of getAllOnLoop(cpNode)) {
|
|
21
|
+
const { pss, hasHoleCloser } = getBoundaryBeziersBetween(cp, cp.next);
|
|
22
|
+
expect(pss).toEqual(getBoundaryBeziersToNext(cp));
|
|
23
|
+
expect(hasHoleCloser).toBe(false);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
{
|
|
27
|
+
// from [46,18.5] (id 147) around two corners to [117,54] (id 4):
|
|
28
|
+
// 35.5 up, 71 across - the piece leaving the end node is not included
|
|
29
|
+
const { pss, hasHoleCloser } = getBoundaryBeziersBetween(byId(147), byId(4));
|
|
30
|
+
expect(hasHoleCloser).toBe(false);
|
|
31
|
+
expectPointClose(pss[0][0], [46,18.5]);
|
|
32
|
+
expectPointClose(pss[pss.length-1][1], [117,54]);
|
|
33
|
+
expectBeziersConnected(pss);
|
|
34
|
+
expect(length(pss)).toBeCloseTo(35.5 + 71, 8);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// equal start and end: everything or nothing
|
|
38
|
+
const perimeter = cpNode.pointOnShape.curve.loop.curves
|
|
39
|
+
.reduce((s, curve) => s + totalLength(curve.ps), 0);
|
|
40
|
+
{
|
|
41
|
+
const { pss } = getBoundaryBeziersBetween(cpNode, cpNode);
|
|
42
|
+
expect(length(pss)).toBeCloseTo(perimeter, 8);
|
|
43
|
+
expectBeziersConnected(pss);
|
|
44
|
+
expectPointClose(pss[pss.length-1][1], pss[0][0]);
|
|
45
|
+
}
|
|
46
|
+
{
|
|
47
|
+
const { pss } = getBoundaryBeziersBetween(cpNode, cpNode, true);
|
|
48
|
+
expect(length(pss)).toBeCloseTo(perimeter, 8);
|
|
49
|
+
}
|
|
50
|
+
{
|
|
51
|
+
const { pss, hasHoleCloser } = getBoundaryBeziersBetween(cpNode, cpNode, false);
|
|
52
|
+
expect(pss).toEqual([]);
|
|
53
|
+
expect(hasHoleCloser).toBe(false);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
test('getBoundaryBeziersBetween - hole closers', function() {
|
|
59
|
+
const { cpNode } = getMatsWithHole()[0];
|
|
60
|
+
|
|
61
|
+
// going all the way round passes the hole closers
|
|
62
|
+
const { hasHoleCloser } = getBoundaryBeziersBetween(cpNode, cpNode);
|
|
63
|
+
expect(hasHoleCloser).toBe(true);
|
|
64
|
+
|
|
65
|
+
// ...but a stretch without any hole closer reports none
|
|
66
|
+
const cps = getAllOnLoop(cpNode);
|
|
67
|
+
const i = cps.findIndex((cp, i) =>
|
|
68
|
+
!cp.isHoleClosing && !cps[(i+1) % cps.length].isHoleClosing);
|
|
69
|
+
expect(i).toBeGreaterThanOrEqual(0);
|
|
70
|
+
const cp = cps[i];
|
|
71
|
+
expect(getBoundaryBeziersBetween(cp, cp.next.next).hasHoleCloser).toBe(false);
|
|
7
72
|
});
|
|
@@ -1,7 +1,45 @@
|
|
|
1
1
|
import { expect, test } from '@jest/globals';
|
|
2
2
|
import { getBoundaryBeziersToNext } from '../../../src/cp-node/fs/get-boundary-beziers-to-next.js';
|
|
3
|
+
import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
|
|
4
|
+
import { getMats1 } from '../../get-mats1.js';
|
|
5
|
+
import { cpNodesByIdOn } from '../../helpers/cp-node-by-id.js';
|
|
6
|
+
import { expectBezierClose, expectBeziersConnected, expectPointClose } from '../../helpers/expect-point-close.js';
|
|
3
7
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
8
|
+
|
|
9
|
+
test('getBoundaryBeziersToNext', function() {
|
|
10
|
+
const { cpNode } = getMats1()[0];
|
|
11
|
+
const byId = cpNodesByIdOn(cpNode);
|
|
12
|
+
|
|
13
|
+
{
|
|
14
|
+
// from the corner [24,8] (end of curve 0) to [46,8] (end of curve 1)
|
|
15
|
+
const pss = getBoundaryBeziersToNext(byId(1));
|
|
16
|
+
expect(pss.length).toBe(2);
|
|
17
|
+
expectBezierClose(pss[0], [[24,8],[24,8]]); // degenerate rest of curve 0
|
|
18
|
+
expectBezierClose(pss[1], [[24,8],[46,8]]); // all of curve 1
|
|
19
|
+
}
|
|
20
|
+
{
|
|
21
|
+
// from [46,18.5] up to the corner [46,54] - part of a single line
|
|
22
|
+
const pss = getBoundaryBeziersToNext(byId(147));
|
|
23
|
+
expect(pss.length).toBe(1);
|
|
24
|
+
expectBezierClose(pss[0], [[46,18.5],[46,54]]);
|
|
25
|
+
}
|
|
26
|
+
{
|
|
27
|
+
// two nodes at the same point (a 1-prong corner) - zero length
|
|
28
|
+
const pss = getBoundaryBeziersToNext(byId(0));
|
|
29
|
+
expect(pss.length).toBe(1);
|
|
30
|
+
expectBezierClose(pss[0], [[24,8],[24,8]]);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// For every node the beziers run from the point of this node to that of
|
|
34
|
+
// the next, joined end to start.
|
|
35
|
+
for (const cp of getAllOnLoop(cpNode)) {
|
|
36
|
+
const pss = getBoundaryBeziersToNext(cp);
|
|
37
|
+
expect(pss.length).toBeGreaterThan(0);
|
|
38
|
+
expectPointClose(pss[0][0], cp.pointOnShape.p);
|
|
39
|
+
const last = pss[pss.length-1];
|
|
40
|
+
expectPointClose(last[last.length-1], cp.next.pointOnShape.p);
|
|
41
|
+
expectBeziersConnected(pss);
|
|
42
|
+
// the fixture boundary consists of lines only
|
|
43
|
+
for (const ps of pss) { expect(ps.length).toBe(2); }
|
|
44
|
+
}
|
|
7
45
|
});
|
|
@@ -1,7 +1,24 @@
|
|
|
1
1
|
import { expect, test } from '@jest/globals';
|
|
2
|
+
import { totalLength } from 'flo-bezier3';
|
|
2
3
|
import { getBoundaryDistanceToNext } from '../../../src/cp-node/fs/get-boundary-distance-to-next.js';
|
|
4
|
+
import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
|
|
5
|
+
import { getMats1 } from '../../get-mats1.js';
|
|
6
|
+
import { cpNodesByIdOn } from '../../helpers/cp-node-by-id.js';
|
|
3
7
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
8
|
+
|
|
9
|
+
test('getBoundaryDistanceToNext', function() {
|
|
10
|
+
const { cpNode } = getMats1()[0];
|
|
11
|
+
const byId = cpNodesByIdOn(cpNode);
|
|
12
|
+
|
|
13
|
+
expect(getBoundaryDistanceToNext(byId(1))).toBeCloseTo(22, 10); // [24,8] -> [46,8]
|
|
14
|
+
expect(getBoundaryDistanceToNext(byId(147))).toBeCloseTo(35.5, 10); // [46,18.5] -> [46,54]
|
|
15
|
+
expect(getBoundaryDistanceToNext(byId(144))).toBeCloseTo(10.5, 10); // [46,8] -> [46,18.5] (crosses a corner)
|
|
16
|
+
expect(getBoundaryDistanceToNext(byId(0))).toBe(0); // two nodes at the same corner point
|
|
17
|
+
|
|
18
|
+
// the distances around the loop add up to the perimeter
|
|
19
|
+
const perimeter = cpNode.pointOnShape.curve.loop.curves
|
|
20
|
+
.reduce((s, curve) => s + totalLength(curve.ps), 0);
|
|
21
|
+
const total = getAllOnLoop(cpNode)
|
|
22
|
+
.reduce((s, cp) => s + getBoundaryDistanceToNext(cp), 0);
|
|
23
|
+
expect(total).toBeCloseTo(perimeter, 8);
|
|
7
24
|
});
|
|
@@ -1,7 +1,46 @@
|
|
|
1
1
|
import { expect, test } from '@jest/globals';
|
|
2
2
|
import { getBranchBeziers } from '../../../src/cp-node/fs/get-branch-beziers.js';
|
|
3
|
+
import { getBranch } from '../../../src/cp-node/fs/get-branch.js';
|
|
4
|
+
import { getMatCurveToNext } from '../../../src/cp-node/fs/get-mat-curve-to-next.js';
|
|
5
|
+
import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
|
|
6
|
+
import { getMats1 } from '../../get-mats1.js';
|
|
7
|
+
import { cpNodesByIdOn } from '../../helpers/cp-node-by-id.js';
|
|
8
|
+
import { expectBeziersConnected, expectPointClose } from '../../helpers/expect-point-close.js';
|
|
3
9
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
10
|
+
|
|
11
|
+
test('getBranchBeziers', function() {
|
|
12
|
+
const { cpNode } = getMats1()[0];
|
|
13
|
+
const byId = cpNodesByIdOn(cpNode);
|
|
14
|
+
|
|
15
|
+
{
|
|
16
|
+
// the branch [143, 11]: from the 3-prong center to the 2-prong center
|
|
17
|
+
// to the sharp corner [24,8]
|
|
18
|
+
const pss = getBranchBeziers(byId(1));
|
|
19
|
+
expect(pss).toEqual([
|
|
20
|
+
...getMatCurveToNext(byId(143)),
|
|
21
|
+
...getMatCurveToNext(byId(11))
|
|
22
|
+
]);
|
|
23
|
+
expectPointClose(pss[0][0], [81.5, -12.641417453935567]);
|
|
24
|
+
const last = pss[pss.length-1];
|
|
25
|
+
expectPointClose(last[last.length-1], [24, 8]);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// For every node: the (flattened) beziers are the edges of the branch in
|
|
29
|
+
// order, joined end to start, from the first vertex center to the last.
|
|
30
|
+
for (const cp of getAllOnLoop(cpNode)) {
|
|
31
|
+
const branch = getBranch(cp);
|
|
32
|
+
const pss = getBranchBeziers(cp);
|
|
33
|
+
|
|
34
|
+
expect(pss).toEqual(branch.flatMap(getMatCurveToNext));
|
|
35
|
+
expect(pss.length).toBeGreaterThanOrEqual(branch.length);
|
|
36
|
+
expectBeziersConnected(pss);
|
|
37
|
+
expectPointClose(pss[0][0], branch[0].pointOnShape.circle.center);
|
|
38
|
+
const last = pss[pss.length-1];
|
|
39
|
+
expectPointClose(
|
|
40
|
+
last[last.length-1],
|
|
41
|
+
branch[branch.length-1].next.pointOnShape.circle.center
|
|
42
|
+
);
|
|
43
|
+
// lines and quadratics only
|
|
44
|
+
for (const ps of pss) { expect([2,3]).toContain(ps.length); }
|
|
45
|
+
}
|
|
7
46
|
});
|