flo-mat 4.1.5 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/__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 +13944 -10307
- 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 +8 -8
- 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
|
@@ -1,7 +1,64 @@
|
|
|
1
1
|
import { expect, test } from '@jest/globals';
|
|
2
2
|
import { getBranch } from '../../../src/cp-node/fs/get-branch.js';
|
|
3
|
+
import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
|
|
4
|
+
import { getRealProngCount } from '../../../src/cp-node/fs/get-real-prong-count.js';
|
|
5
|
+
import { isTerminating } from '../../../src/cp-node/fs/is-terminating.js';
|
|
6
|
+
import { getMats1 } from '../../get-mats1.js';
|
|
7
|
+
import { cpNodesByIdOn } from '../../helpers/cp-node-by-id.js';
|
|
3
8
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
9
|
+
|
|
10
|
+
test('getBranch', function() {
|
|
11
|
+
const { cpNode } = getMats1()[0];
|
|
12
|
+
const byId = cpNodesByIdOn(cpNode);
|
|
13
|
+
const ids = (cps: { id: number }[]) => cps.map(cp => cp.id);
|
|
14
|
+
|
|
15
|
+
// The branch from the sharp corner [24,8] via the 2-prong {10,11} to the
|
|
16
|
+
// 3-prong {142,143,144}. `getBranch` walks forward to the first vertex
|
|
17
|
+
// that is not a 2-prong and then returns the branch *back* from there
|
|
18
|
+
// (without the final node), so the result depends on the direction of
|
|
19
|
+
// the given node.
|
|
20
|
+
expect(ids(getBranch(byId(1)))).toEqual([143, 11]);
|
|
21
|
+
expect(ids(getBranch(byId(10)))).toEqual([143, 11]);
|
|
22
|
+
expect(ids(getBranch(byId(11)))).toEqual([1, 10]);
|
|
23
|
+
expect(ids(getBranch(byId(143)))).toEqual([1, 10]);
|
|
24
|
+
// a terminating node first steps to its non-terminating twin
|
|
25
|
+
expect(ids(getBranch(byId(0)))).toEqual([143, 11]);
|
|
26
|
+
|
|
27
|
+
// single-edge branches between non-2-prong vertices
|
|
28
|
+
expect(ids(getBranch(byId(144)))).toEqual([146]); // 3-prong -> 3-prong
|
|
29
|
+
expect(ids(getBranch(byId(147)))).toEqual([3]); // 3-prong -> leaf
|
|
30
|
+
|
|
31
|
+
// Structural invariants for every node in the fixture (none are trivial)
|
|
32
|
+
for (const cp of getAllOnLoop(cpNode)) {
|
|
33
|
+
const branch = getBranch(cp);
|
|
34
|
+
expect(branch.length).toBeGreaterThan(0);
|
|
35
|
+
|
|
36
|
+
// consecutive along the boundary
|
|
37
|
+
for (let i=1; i<branch.length; i++) {
|
|
38
|
+
expect(branch[i]).toBe(branch[i-1].next);
|
|
39
|
+
}
|
|
40
|
+
// it starts at a vertex that is not a 2-prong, passes only 2-prongs
|
|
41
|
+
// and the (excluded) final node is again not a 2-prong
|
|
42
|
+
expect(getRealProngCount(branch[0])).not.toBe(2);
|
|
43
|
+
for (const cp of branch.slice(1)) {
|
|
44
|
+
expect(getRealProngCount(cp)).toBe(2);
|
|
45
|
+
}
|
|
46
|
+
const final = branch[branch.length-1].next;
|
|
47
|
+
expect(getRealProngCount(final)).not.toBe(2);
|
|
48
|
+
// every node of the branch represents a real (non-terminating) edge
|
|
49
|
+
for (const cp of branch) { expect(isTerminating(cp)).toBe(false); }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// The fixture MAT has 5 leaves, 3 3-prongs and 2 2-prongs, so there are
|
|
53
|
+
// 7 distinct branches (up to direction).
|
|
54
|
+
const branchKeys = new Set<string>();
|
|
55
|
+
for (const cp of getAllOnLoop(cpNode)) {
|
|
56
|
+
const branch = getBranch(cp);
|
|
57
|
+
// key by the unordered pair of end vertices (via their circles)
|
|
58
|
+
const a = branch[0].pointOnShape.circle;
|
|
59
|
+
const b = branch[branch.length-1].next.pointOnShape.circle;
|
|
60
|
+
const key = [a, b].map(c => `${c.center[0]},${c.center[1]},${c.radius}`).sort().join('|');
|
|
61
|
+
branchKeys.add(key);
|
|
62
|
+
}
|
|
63
|
+
expect(branchKeys.size).toBe(7);
|
|
7
64
|
});
|
|
@@ -1,7 +1,23 @@
|
|
|
1
1
|
import { expect, test } from '@jest/globals';
|
|
2
2
|
import { getCpNodeOrdering } from '../../../src/cp-node/fs/get-cp-node-ordering.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';
|
|
3
6
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
|
|
8
|
+
test('getCpNodeOrdering', function() {
|
|
9
|
+
const { cpNode } = getMats1()[0];
|
|
10
|
+
const byId = cpNodesByIdOn(cpNode);
|
|
11
|
+
|
|
12
|
+
expect(getCpNodeOrdering(byId(147))).toEqual({
|
|
13
|
+
idx: 2, t: 0.2282608695652173, order: 0, order2: 0
|
|
14
|
+
});
|
|
15
|
+
// the two nodes at the same corner point differ in `order` only
|
|
16
|
+
expect(getCpNodeOrdering(byId(0))).toEqual({ idx: 0, t: 1, order: -1, order2: 0 });
|
|
17
|
+
expect(getCpNodeOrdering(byId(1))).toEqual({ idx: 0, t: 1, order: 1, order2: 0 });
|
|
18
|
+
|
|
19
|
+
for (const cp of getAllOnLoop(cpNode)) {
|
|
20
|
+
const { curve, t, order, order2 } = cp.pointOnShape;
|
|
21
|
+
expect(getCpNodeOrdering(cp)).toEqual({ idx: curve.idx, t, order, order2 });
|
|
22
|
+
}
|
|
7
23
|
});
|
|
@@ -1,7 +1,40 @@
|
|
|
1
1
|
import { expect, test } from '@jest/globals';
|
|
2
|
-
import {
|
|
2
|
+
import { distanceBetween } from 'flo-vector2d';
|
|
3
|
+
import { getMatDistanceToNext, getMatDistanceToNext$ } from '../../../src/cp-node/fs/get-distance-to-next.js';
|
|
4
|
+
import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
|
|
5
|
+
import { isTerminating } from '../../../src/cp-node/fs/is-terminating.js';
|
|
6
|
+
import { getMats1 } from '../../get-mats1.js';
|
|
7
|
+
import { cpNodesByIdOn } from '../../helpers/cp-node-by-id.js';
|
|
3
8
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
9
|
+
|
|
10
|
+
test('getMatDistanceToNext', function() {
|
|
11
|
+
const { cpNode } = getMats1()[0];
|
|
12
|
+
const byId = cpNodesByIdOn(cpNode);
|
|
13
|
+
const chord = (cp: typeof cpNode) => distanceBetween(
|
|
14
|
+
cp.pointOnShape.circle.center,
|
|
15
|
+
cp.next.pointOnShape.circle.center
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
// straight MAT edges: the arc length is the distance between the centers
|
|
19
|
+
// 3-prong center [81.5,18.5] -> sharp corner [46,54]
|
|
20
|
+
expect(getMatDistanceToNext(byId(147))).toBeCloseTo(35.5*Math.SQRT2, 9);
|
|
21
|
+
// sharp corner [24,8] -> 2-prong center [46,-5.21425847941623] (along the
|
|
22
|
+
// bisector of the corner)
|
|
23
|
+
expect(getMatDistanceToNext(byId(1))).toBeCloseTo(Math.hypot(22, 8 + 5.21425847941623), 9);
|
|
24
|
+
|
|
25
|
+
// a curved MAT edge (equidistant from a corner point and a line, i.e. a
|
|
26
|
+
// parabola) is strictly longer than its chord
|
|
27
|
+
expect(getMatDistanceToNext(byId(10))).toBeGreaterThan(chord(byId(10)) + 0.01);
|
|
28
|
+
|
|
29
|
+
// the two nodes at a 1-prong share a center
|
|
30
|
+
expect(getMatDistanceToNext(byId(0))).toBe(0);
|
|
31
|
+
|
|
32
|
+
for (const cp of getAllOnLoop(cpNode)) {
|
|
33
|
+
const d = getMatDistanceToNext(cp);
|
|
34
|
+
// never shorter than the chord
|
|
35
|
+
expect(d).toBeGreaterThanOrEqual(chord(cp) - 1e-9);
|
|
36
|
+
if (isTerminating(cp)) { expect(d).toBe(0); }
|
|
37
|
+
// the memoized version agrees
|
|
38
|
+
expect(getMatDistanceToNext$(cp)).toBe(d);
|
|
39
|
+
}
|
|
7
40
|
});
|
|
@@ -1,7 +1,54 @@
|
|
|
1
1
|
import { expect, test } from '@jest/globals';
|
|
2
|
+
import { distanceBetween, dot, fromTo, toUnitVector } from 'flo-vector2d';
|
|
2
3
|
import { getEdgeDirection } from '../../../src/cp-node/fs/get-edge-direction.js';
|
|
4
|
+
import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
|
|
5
|
+
import { isTerminating } from '../../../src/cp-node/fs/is-terminating.js';
|
|
6
|
+
import { getMats1 } from '../../get-mats1.js';
|
|
7
|
+
import { cpNodesByIdOn } from '../../helpers/cp-node-by-id.js';
|
|
8
|
+
import { expectPointClose } from '../../helpers/expect-point-close.js';
|
|
3
9
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
10
|
+
|
|
11
|
+
test('getEdgeDirection', function() {
|
|
12
|
+
const { cpNode } = getMats1()[0];
|
|
13
|
+
const byId = cpNodesByIdOn(cpNode);
|
|
14
|
+
const dir = (id: number) => {
|
|
15
|
+
const [c, v] = getEdgeDirection(byId(id));
|
|
16
|
+
return fromTo(c, v);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// 3-prong with center [81.5,18.5] and contact points [46,18.5] (id 147),
|
|
20
|
+
// [81.5,54] (id 145) and [117,18.5] (id 146): each edge leaves along the
|
|
21
|
+
// bisector of the contact point of the node and the next one on the circle.
|
|
22
|
+
const s = Math.SQRT1_2;
|
|
23
|
+
expectPointClose(dir(147), [-s, s]);
|
|
24
|
+
expectPointClose(dir(145), [ s, s]);
|
|
25
|
+
expectPointClose(dir(146), [ 0,-1]);
|
|
26
|
+
|
|
27
|
+
// 1-prong at the sharp corner [24,8] (ids 0 and 1): the edge leaves along
|
|
28
|
+
// the bisector of the corner (both nodes sit at the same point).
|
|
29
|
+
const bisector = toUnitVector([
|
|
30
|
+
1 + 58/Math.hypot(58, 109), // unit([46,8]-[24,8]) + unit([82,-101]-[24,8])
|
|
31
|
+
0 - 109/Math.hypot(58, 109)
|
|
32
|
+
]);
|
|
33
|
+
expectPointClose(dir(0), bisector);
|
|
34
|
+
expectPointClose(dir(1), bisector);
|
|
35
|
+
|
|
36
|
+
// 2-prong {10,11} on the line [24,8]->[46,8] and the other edge of the
|
|
37
|
+
// corner: its direction continues the corner bisector (the MAT is smooth
|
|
38
|
+
// there) - and the opposite way for the node pointing back to the corner.
|
|
39
|
+
expectPointClose(dir(10), bisector);
|
|
40
|
+
expectPointClose(dir(11), [-bisector[0], -bisector[1]]);
|
|
41
|
+
|
|
42
|
+
for (const cp of getAllOnLoop(cpNode)) {
|
|
43
|
+
const [c, v] = getEdgeDirection(cp);
|
|
44
|
+
// starts at the circle center, unit length
|
|
45
|
+
expect(c).toBe(cp.pointOnShape.circle.center);
|
|
46
|
+
expect(distanceBetween(c, v)).toBeCloseTo(1, 12);
|
|
47
|
+
|
|
48
|
+
// points towards the next vertex (never backwards)
|
|
49
|
+
if (!isTerminating(cp)) {
|
|
50
|
+
const toNext = fromTo(c, cp.next.pointOnShape.circle.center);
|
|
51
|
+
expect(dot(fromTo(c, v), toNext)).toBeGreaterThan(0);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
7
54
|
});
|
|
@@ -1,7 +1,82 @@
|
|
|
1
1
|
import { expect, test } from '@jest/globals';
|
|
2
|
+
import type { CpNode } from '../../../src/cp-node/cp-node.js';
|
|
2
3
|
import { getFirstExit } from '../../../src/cp-node/fs/get-first-exit.js';
|
|
4
|
+
import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
|
|
5
|
+
import { getAllOnCircle } from '../../../src/cp-node/fs/get-all-on-circle.js';
|
|
6
|
+
import { getProngCount } from '../../../src/cp-node/fs/get-prong-count.js';
|
|
7
|
+
import { isTerminating } from '../../../src/cp-node/fs/is-terminating.js';
|
|
8
|
+
import { getMats1 } from '../../get-mats1.js';
|
|
9
|
+
import { getMatsWithHole } from '../../get-mats-with-hole.js';
|
|
10
|
+
import { cpNodesByIdOn } from '../../helpers/cp-node-by-id.js';
|
|
3
11
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
12
|
+
|
|
13
|
+
/** The invariants `getFirstExit` must satisfy for every node of a MAT. */
|
|
14
|
+
function checkFirstExits(cpNode: CpNode) {
|
|
15
|
+
for (const cp of getAllOnLoop(cpNode)) {
|
|
16
|
+
const exit = getFirstExit(cp);
|
|
17
|
+
|
|
18
|
+
// the expected result: the first non-terminating node strictly after
|
|
19
|
+
// `cp` going round the circle, if any
|
|
20
|
+
const others = getAllOnCircle(cp, true);
|
|
21
|
+
const expected = others.find(c => !isTerminating(c));
|
|
22
|
+
|
|
23
|
+
expect(exit).toBe(expected);
|
|
24
|
+
// never the node itself
|
|
25
|
+
expect(exit).not.toBe(cp);
|
|
26
|
+
if (exit !== undefined) {
|
|
27
|
+
expect(getAllOnCircle(cp).includes(exit)).toBe(true);
|
|
28
|
+
expect(isTerminating(exit)).toBe(false);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
test('getFirstExit', function() {
|
|
35
|
+
const { cpNode } = getMats1()[0];
|
|
36
|
+
const byId = cpNodesByIdOn(cpNode);
|
|
37
|
+
|
|
38
|
+
// 1-prong at the corner [24,8]: from the terminating node 0 the exit is
|
|
39
|
+
// node 1; from node 1 there is no *other* exit.
|
|
40
|
+
expect(getFirstExit(byId(0))).toBe(byId(1));
|
|
41
|
+
expect(getFirstExit(byId(1))).toBeUndefined();
|
|
42
|
+
|
|
43
|
+
// 2-prong {10,11}: each is the exit after the other
|
|
44
|
+
expect(getFirstExit(byId(10))).toBe(byId(11));
|
|
45
|
+
expect(getFirstExit(byId(11))).toBe(byId(10));
|
|
46
|
+
|
|
47
|
+
// 3-prong {144,142,143} (all non-terminating): the next one on the circle
|
|
48
|
+
expect(getFirstExit(byId(144))).toBe(byId(142));
|
|
49
|
+
expect(getFirstExit(byId(142))).toBe(byId(143));
|
|
50
|
+
expect(getFirstExit(byId(143))).toBe(byId(144));
|
|
51
|
+
|
|
52
|
+
checkFirstExits(cpNode);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
test('getFirstExit - terminating nodes on 3-prong rings', function() {
|
|
57
|
+
const { cpNode } = getMatsWithHole()[0];
|
|
58
|
+
const all = getAllOnLoop(cpNode);
|
|
59
|
+
|
|
60
|
+
// The test is only meaningful if there are terminating nodes on rings of
|
|
61
|
+
// 3 or more (where `next === prevOnCircle` no longer coincides with
|
|
62
|
+
// `isTerminating`, which is what used to trip this function up).
|
|
63
|
+
const terminatingOnBigRings = all.filter(cp =>
|
|
64
|
+
isTerminating(cp) && getProngCount(cp) >= 3
|
|
65
|
+
);
|
|
66
|
+
expect(terminatingOnBigRings.length).toBeGreaterThan(0);
|
|
67
|
+
|
|
68
|
+
checkFirstExits(cpNode);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
test('getFirstExit - MAT consisting of a single point', function() {
|
|
73
|
+
// Two nodes at the same point forming their own circle and loop (a
|
|
74
|
+
// degenerate MAT); neither exits the circle.
|
|
75
|
+
const a = { id: 0 } as unknown as CpNode;
|
|
76
|
+
const b = { id: 1 } as unknown as CpNode;
|
|
77
|
+
Object.assign(a, { next: b, prev: b, nextOnCircle: b, prevOnCircle: b });
|
|
78
|
+
Object.assign(b, { next: a, prev: a, nextOnCircle: a, prevOnCircle: a });
|
|
79
|
+
|
|
80
|
+
expect(getFirstExit(a)).toBeUndefined();
|
|
81
|
+
expect(getFirstExit(b)).toBeUndefined();
|
|
7
82
|
});
|
|
@@ -1,7 +1,36 @@
|
|
|
1
1
|
import { expect, test } from '@jest/globals';
|
|
2
2
|
import { getHoleClosers } from '../../../src/cp-node/fs/get-hole-closers.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';
|
|
3
6
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
|
|
8
|
+
test('getHoleClosers', function() {
|
|
9
|
+
{
|
|
10
|
+
// a single loop has no holes to close
|
|
11
|
+
const { cpNode } = getMats1()[0];
|
|
12
|
+
expect(getHoleClosers(cpNode)).toEqual([]);
|
|
13
|
+
}
|
|
14
|
+
{
|
|
15
|
+
const { cpNode } = getMatsWithHole()[0];
|
|
16
|
+
const holeClosers = getHoleClosers(cpNode);
|
|
17
|
+
|
|
18
|
+
// the full set of hole closers on the loop, in loop order (compared
|
|
19
|
+
// by identity - `CpNode`s are circular structures)
|
|
20
|
+
const expected = getAllOnLoop(cpNode).filter(cp => cp.isHoleClosing);
|
|
21
|
+
expect(holeClosers.length).toBe(expected.length);
|
|
22
|
+
expect(holeClosers.every((cp, i) => cp === expected[i])).toBe(true);
|
|
23
|
+
expect(holeClosers.length).toBeGreaterThan(0);
|
|
24
|
+
|
|
25
|
+
// hole closers come in twins at the same point - one on each loop
|
|
26
|
+
expect(holeClosers.length % 2).toBe(0);
|
|
27
|
+
for (const cp of holeClosers) {
|
|
28
|
+
const twin = cp.holeCloserTwin!;
|
|
29
|
+
expect(twin).toBeDefined();
|
|
30
|
+
expect(twin.isHoleClosing).toBe(true);
|
|
31
|
+
expect(twin.holeCloserTwin).toBe(cp);
|
|
32
|
+
expect(twin.pointOnShape.p).toEqual(cp.pointOnShape.p);
|
|
33
|
+
expect(holeClosers.includes(twin)).toBe(true);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
7
36
|
});
|
|
@@ -1,7 +1,52 @@
|
|
|
1
1
|
import { expect, test } from '@jest/globals';
|
|
2
2
|
import { getImpliedBoundaryBezierBetween } from '../../../src/cp-node/fs/get-implied-boundary-bezier-between.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('getImpliedBoundaryBezierBetween', function() {
|
|
10
|
+
const { cpNode } = getMats1()[0];
|
|
11
|
+
const byId = cpNodesByIdOn(cpNode);
|
|
12
|
+
|
|
13
|
+
// Both points on the same straight boundary line: a single line.
|
|
14
|
+
{
|
|
15
|
+
const pss = getImpliedBoundaryBezierBetween(byId(147), byId(2));
|
|
16
|
+
expect(pss.length).toBe(1);
|
|
17
|
+
expectBezierClose(pss[0], [[46,18.5],[46,54]]);
|
|
18
|
+
}
|
|
19
|
+
{
|
|
20
|
+
// the tangent at the corner [24,8] is taken from the *outgoing* curve
|
|
21
|
+
const pss = getImpliedBoundaryBezierBetween(byId(1), byId(10));
|
|
22
|
+
expect(pss.length).toBe(1);
|
|
23
|
+
expectBezierClose(pss[0], [[24,8],[46,8]]);
|
|
24
|
+
}
|
|
25
|
+
{
|
|
26
|
+
// ...and at [46,8] (id 10, end of curve 1) likewise, so [46,8] ->
|
|
27
|
+
// [46,18.5] follows curve 2 (vertical)
|
|
28
|
+
const pss = getImpliedBoundaryBezierBetween(byId(10), byId(147));
|
|
29
|
+
expect(pss.length).toBe(1);
|
|
30
|
+
expectBezierClose(pss[0], [[46,8],[46,18.5]]);
|
|
31
|
+
}
|
|
32
|
+
{
|
|
33
|
+
// Tangents (1,0) at [24,8] and (0,1) at [46,18.5] meet at the (cut)
|
|
34
|
+
// corner [46,8]: a single quadratic with that control point.
|
|
35
|
+
const pss = getImpliedBoundaryBezierBetween(byId(1), byId(147));
|
|
36
|
+
expect(pss.length).toBe(1);
|
|
37
|
+
expectBezierClose(pss[0], [[24,8],[46,8],[46,18.5]]);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// For every pair of consecutive nodes the implied boundary runs from the
|
|
41
|
+
// one point to the other.
|
|
42
|
+
for (const cp of getAllOnLoop(cpNode)) {
|
|
43
|
+
const pss = getImpliedBoundaryBezierBetween(cp, cp.next);
|
|
44
|
+
expect(pss.length).toBeGreaterThan(0);
|
|
45
|
+
expect(pss.length).toBeLessThanOrEqual(2);
|
|
46
|
+
expectPointClose(pss[0][0], cp.pointOnShape.p);
|
|
47
|
+
const last = pss[pss.length-1];
|
|
48
|
+
expectPointClose(last[last.length-1], cp.next.pointOnShape.p);
|
|
49
|
+
expectBeziersConnected(pss);
|
|
50
|
+
for (const ps of pss) { expect([2,3]).toContain(ps.length); }
|
|
51
|
+
}
|
|
7
52
|
});
|
|
@@ -1,7 +1,81 @@
|
|
|
1
1
|
import { expect, test } from '@jest/globals';
|
|
2
|
+
import { cross, fromTo, toUnitVector } from 'flo-vector2d';
|
|
2
3
|
import { getMatCurveBetween } from '../../../src/cp-node/fs/get-mat-curve-between.js';
|
|
4
|
+
import { getEdgeDirection } from '../../../src/cp-node/fs/get-edge-direction.js';
|
|
5
|
+
import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
|
|
6
|
+
import { isTerminating } from '../../../src/cp-node/fs/is-terminating.js';
|
|
7
|
+
import { getMats1 } from '../../get-mats1.js';
|
|
8
|
+
import { cpNodesByIdOn } from '../../helpers/cp-node-by-id.js';
|
|
9
|
+
import { expectBezierClose, expectBeziersConnected, expectPointClose } from '../../helpers/expect-point-close.js';
|
|
3
10
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
11
|
+
|
|
12
|
+
/** unit direction of the given line `[p, q]` */
|
|
13
|
+
const lineDir = (l: number[][]) => toUnitVector(fromTo(l[0], l[1]));
|
|
14
|
+
/** unit tangent at the start / end of a bezier */
|
|
15
|
+
const startTan = (ps: number[][]) => toUnitVector(fromTo(ps[0], ps[1]));
|
|
16
|
+
const endTan = (ps: number[][]) => toUnitVector(fromTo(ps[ps.length-2], ps[ps.length-1]));
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
test('getMatCurveBetween', function() {
|
|
20
|
+
const { cpNode } = getMats1()[0];
|
|
21
|
+
const byId = cpNodesByIdOn(cpNode);
|
|
22
|
+
|
|
23
|
+
{
|
|
24
|
+
// 3-prong center [81.5,18.5] to the sharp corner [46,54]: the edge
|
|
25
|
+
// direction and the corner bisector are collinear - a straight line
|
|
26
|
+
const pss = getMatCurveBetween(byId(147), byId(2));
|
|
27
|
+
expect(pss.length).toBe(1);
|
|
28
|
+
expectBezierClose(pss[0], [[81.5,18.5],[46,54]]);
|
|
29
|
+
}
|
|
30
|
+
{
|
|
31
|
+
// sharp corner [24,8] to the 2-prong on its bisector - a straight line
|
|
32
|
+
const pss = getMatCurveBetween(byId(1), byId(10));
|
|
33
|
+
expect(pss.length).toBe(1);
|
|
34
|
+
expectBezierClose(pss[0], [[24,8],[46,-5.21425847941623]]);
|
|
35
|
+
}
|
|
36
|
+
{
|
|
37
|
+
// 2-prong {10,11} to the 3-prong {142,143,144}: the medial axis is a
|
|
38
|
+
// parabola here (equidistant from the corner point [46,8] and a line)
|
|
39
|
+
// - a single quadratic whose control point is the intersection of the
|
|
40
|
+
// two edge directions.
|
|
41
|
+
const pss = getMatCurveBetween(byId(10), byId(144));
|
|
42
|
+
expect(pss.length).toBe(1);
|
|
43
|
+
const ps = pss[0];
|
|
44
|
+
expect(ps.length).toBe(3);
|
|
45
|
+
const l0 = getEdgeDirection(byId(10));
|
|
46
|
+
const l1 = getEdgeDirection(byId(143)); // = 144.prevOnCircle
|
|
47
|
+
expect(cross(fromTo(l0[0], ps[1]), lineDir(l0))).toBeCloseTo(0, 9);
|
|
48
|
+
expect(cross(fromTo(l1[0], ps[1]), lineDir(l1))).toBeCloseTo(0, 9);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// For every MAT edge: 1 or 2 pieces (lines or quadratics), from the
|
|
52
|
+
// circle center of this node to that of the next, joined smoothly,
|
|
53
|
+
// leaving along the edge direction at the start and arriving along the
|
|
54
|
+
// edge direction at the end.
|
|
55
|
+
for (const cp of getAllOnLoop(cpNode)) {
|
|
56
|
+
const pss = getMatCurveBetween(cp, cp.next);
|
|
57
|
+
expect([1,2]).toContain(pss.length);
|
|
58
|
+
for (const ps of pss) { expect([2,3]).toContain(ps.length); }
|
|
59
|
+
|
|
60
|
+
const c0 = cp.pointOnShape.circle.center;
|
|
61
|
+
const c1 = cp.next.pointOnShape.circle.center;
|
|
62
|
+
expectPointClose(pss[0][0], c0);
|
|
63
|
+
const last = pss[pss.length-1];
|
|
64
|
+
expectPointClose(last[last.length-1], c1);
|
|
65
|
+
expectBeziersConnected(pss);
|
|
66
|
+
|
|
67
|
+
if (isTerminating(cp)) {
|
|
68
|
+
// both nodes share a center: a degenerate curve
|
|
69
|
+
for (const ps of pss) { for (const p of ps) { expectPointClose(p, c0); } }
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const d0 = lineDir(getEdgeDirection(cp));
|
|
74
|
+
const d1 = lineDir(getEdgeDirection(cp.next.prevOnCircle));
|
|
75
|
+
expect(cross(startTan(pss[0]), d0)).toBeCloseTo(0, 4);
|
|
76
|
+
expect(cross(endTan(last), d1)).toBeCloseTo(0, 4);
|
|
77
|
+
if (pss.length === 2) {
|
|
78
|
+
expect(cross(endTan(pss[0]), startTan(pss[1]))).toBeCloseTo(0, 9);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
7
81
|
});
|
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
import { expect, test } from '@jest/globals';
|
|
2
|
-
import { getMatCurveToNext } from '../../../src/cp-node/fs/get-mat-curve-to-next.js';
|
|
2
|
+
import { getMatCurveToNext, getMatCurveToNext$ } from '../../../src/cp-node/fs/get-mat-curve-to-next.js';
|
|
3
|
+
import { getMatCurveBetween } from '../../../src/cp-node/fs/get-mat-curve-between.js';
|
|
4
|
+
import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
|
|
5
|
+
import { getMats1 } from '../../get-mats1.js';
|
|
3
6
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
|
|
8
|
+
test('getMatCurveToNext', function() {
|
|
9
|
+
const { cpNode } = getMats1()[0];
|
|
10
|
+
|
|
11
|
+
for (const cp of getAllOnLoop(cpNode)) {
|
|
12
|
+
const pss = getMatCurveToNext(cp);
|
|
13
|
+
expect(pss).toEqual(getMatCurveBetween(cp, cp.next));
|
|
14
|
+
|
|
15
|
+
// the memoized version returns the identical result, once computed
|
|
16
|
+
const pss$ = getMatCurveToNext$(cp);
|
|
17
|
+
expect(pss$).toEqual(pss);
|
|
18
|
+
expect(getMatCurveToNext$(cp)).toBe(pss$);
|
|
19
|
+
}
|
|
7
20
|
});
|
|
@@ -1,7 +1,42 @@
|
|
|
1
1
|
import { expect, test } from '@jest/globals';
|
|
2
2
|
import { getMatCurvesBetween } from '../../../src/cp-node/fs/get-mat-curves-between.js';
|
|
3
|
+
import { getMatCurveToNext } from '../../../src/cp-node/fs/get-mat-curve-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';
|
|
7
|
+
import { expectBeziersConnected, expectPointClose } from '../../helpers/expect-point-close.js';
|
|
3
8
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
9
|
+
|
|
10
|
+
test('getMatCurvesBetween', function() {
|
|
11
|
+
const { cpNode } = getMats1()[0];
|
|
12
|
+
const byId = cpNodesByIdOn(cpNode);
|
|
13
|
+
|
|
14
|
+
// nothing between a node and itself
|
|
15
|
+
expect(getMatCurvesBetween(cpNode, cpNode)).toEqual([]);
|
|
16
|
+
|
|
17
|
+
// the flattened edges 1 -> 10 -> 144 -> 147 (the edge leaving the end
|
|
18
|
+
// node excluded)
|
|
19
|
+
const pss = getMatCurvesBetween(byId(1), byId(147));
|
|
20
|
+
expect(pss).toEqual([
|
|
21
|
+
...getMatCurveToNext(byId(1)),
|
|
22
|
+
...getMatCurveToNext(byId(10)),
|
|
23
|
+
...getMatCurveToNext(byId(144)),
|
|
24
|
+
]);
|
|
25
|
+
expectBeziersConnected(pss);
|
|
26
|
+
expectPointClose(pss[0][0], [24, 8]);
|
|
27
|
+
const last = pss[pss.length-1];
|
|
28
|
+
expectPointClose(last[last.length-1], [81.5, 18.5]);
|
|
29
|
+
|
|
30
|
+
for (const cp of getAllOnLoop(cpNode)) {
|
|
31
|
+
expect(getMatCurvesBetween(cp, cp.next)).toEqual(getMatCurveToNext(cp));
|
|
32
|
+
expect(getMatCurvesBetween(cp, cp.next.next)).toEqual([
|
|
33
|
+
...getMatCurveToNext(cp), ...getMatCurveToNext(cp.next)
|
|
34
|
+
]);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// all the way round (to the predecessor) covers every edge but one
|
|
38
|
+
const all = getAllOnLoop(cpNode);
|
|
39
|
+
expect(getMatCurvesBetween(cpNode, cpNode.prev)).toEqual(
|
|
40
|
+
all.slice(0, -1).flatMap(getMatCurveToNext)
|
|
41
|
+
);
|
|
7
42
|
});
|
|
@@ -1,7 +1,72 @@
|
|
|
1
1
|
import { expect, test } from '@jest/globals';
|
|
2
|
+
import { distanceBetween } from 'flo-vector2d';
|
|
2
3
|
import { getSalience } from '../../../src/cp-node/fs/get-salience.js';
|
|
4
|
+
import { getBoundaryBeziersBetween } from '../../../src/cp-node/fs/get-boundary-beziers-between.js';
|
|
5
|
+
import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
|
|
6
|
+
import { getAllOnLoop_ByLoop } from '../../../src/cp-node/fs/get-all-on-loop-by-loop.js';
|
|
7
|
+
import { getRealProngCount } from '../../../src/cp-node/fs/get-real-prong-count.js';
|
|
8
|
+
import { getMats1 } from '../../get-mats1.js';
|
|
9
|
+
import { getMatsWithHole } from '../../get-mats-with-hole.js';
|
|
10
|
+
import { cpNodesByIdOn } from '../../helpers/cp-node-by-id.js';
|
|
3
11
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
12
|
+
|
|
13
|
+
test('getSalience', function() {
|
|
14
|
+
const { cpNode } = getMats1()[0];
|
|
15
|
+
const byId = cpNodesByIdOn(cpNode);
|
|
16
|
+
|
|
17
|
+
// Salience = (boundary length from this contact point forward to the next
|
|
18
|
+
// contact point on the circle) / (straight distance between them).
|
|
19
|
+
|
|
20
|
+
{
|
|
21
|
+
// 2-prong {10,11} touching [46,8] and a point on the other edge of the
|
|
22
|
+
// corner [24,8]: from id 11 the boundary runs to the corner and on to
|
|
23
|
+
// [46,8] - two equal tangent lengths of 22.
|
|
24
|
+
const cp = byId(11);
|
|
25
|
+
const d = distanceBetween(cp.pointOnShape.p, cp.nextOnCircle.pointOnShape.p);
|
|
26
|
+
expect(getSalience(cp)).toBeCloseTo(44/d, 9);
|
|
27
|
+
}
|
|
28
|
+
{
|
|
29
|
+
// 3-prong {142,143,144}: from [46,8] (id 144) forward to [117,8]
|
|
30
|
+
// (id 142) the boundary goes round the top of the rectangle:
|
|
31
|
+
// 46 + 71 + 46 = 163, against a chord of 71.
|
|
32
|
+
expect(getSalience(byId(144))).toBeCloseTo(163/71, 9);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// the boundary is never shorter than the chord
|
|
36
|
+
for (const cp of getAllOnLoop(cpNode)) {
|
|
37
|
+
if (getRealProngCount(cp) < 2) { continue; } // 1-prongs: see below
|
|
38
|
+
const s = getSalience(cp);
|
|
39
|
+
expect(Number.isFinite(s)).toBe(true);
|
|
40
|
+
expect(s).toBeGreaterThanOrEqual(1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 1-prongs (two nodes at the same point): the terminating node has no
|
|
44
|
+
// boundary between itself and its twin - salience 0 - while the twin has
|
|
45
|
+
// the entire boundary - salience Infinity. Ids 0 and 1 at the corner
|
|
46
|
+
// [24,8] are such a pair.
|
|
47
|
+
expect(getSalience(byId(0))).toBe(0);
|
|
48
|
+
expect(getSalience(byId(1))).toBe(Infinity);
|
|
49
|
+
for (const cp of getAllOnLoop(cpNode)) {
|
|
50
|
+
if (getRealProngCount(cp) >= 2) { continue; }
|
|
51
|
+
const s = getSalience(cp);
|
|
52
|
+
expect(Number.isNaN(s)).toBe(false);
|
|
53
|
+
expect(s === 0 || s === Infinity).toBe(true);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
test('getSalience - hole closers', function() {
|
|
59
|
+
const { cpNode } = getMatsWithHole()[0];
|
|
60
|
+
|
|
61
|
+
// a stretch of boundary passing a hole closer has infinite salience
|
|
62
|
+
const cpNodes = getAllOnLoop_ByLoop(cpNode).flat();
|
|
63
|
+
let infinite = 0;
|
|
64
|
+
for (const cp of cpNodes) {
|
|
65
|
+
const { hasHoleCloser } = getBoundaryBeziersBetween(cp, cp.nextOnCircle);
|
|
66
|
+
if (hasHoleCloser) {
|
|
67
|
+
infinite++;
|
|
68
|
+
expect(getSalience(cp)).toBe(Infinity);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
expect(infinite).toBeGreaterThan(0);
|
|
7
72
|
});
|
|
@@ -1,7 +1,44 @@
|
|
|
1
1
|
import { expect, test } from '@jest/globals';
|
|
2
2
|
import { getVertexForwardChildren } from '../../../src/cp-node/fs/get-vertex-forward-children.js';
|
|
3
|
+
import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
|
|
4
|
+
import { getAllOnCircle } from '../../../src/cp-node/fs/get-all-on-circle.js';
|
|
5
|
+
import { isTerminating } from '../../../src/cp-node/fs/is-terminating.js';
|
|
6
|
+
import { getMats1 } from '../../get-mats1.js';
|
|
7
|
+
import { cpNodesByIdOn } from '../../helpers/cp-node-by-id.js';
|
|
3
8
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
9
|
+
|
|
10
|
+
test('getVertexForwardChildren', function() {
|
|
11
|
+
const { cpNode } = getMats1()[0];
|
|
12
|
+
const byId = cpNodesByIdOn(cpNode);
|
|
13
|
+
const childIds = (id: number) => getVertexForwardChildren(byId(id)).map(cp => cp.id);
|
|
14
|
+
|
|
15
|
+
// Seen as a vertex entered via the given node (its `prevOnCircle` being
|
|
16
|
+
// the edge back to the parent), the forward children are the far ends of
|
|
17
|
+
// the other edges, in on-circle order.
|
|
18
|
+
expect(childIds(144)).toEqual([147, 148]); // 3-prong: two children
|
|
19
|
+
expect(childIds(142)).toEqual([148, 11]); // same 3-prong, entered differently
|
|
20
|
+
expect(childIds(147)).toEqual([2, 4]); // 3-prong towards two leaves
|
|
21
|
+
expect(childIds(10)).toEqual([144]); // 2-prong: one child
|
|
22
|
+
expect(childIds(1)).toEqual([10]); // leaf, leaving
|
|
23
|
+
expect(childIds(0)).toEqual([]); // leaf, entered - no children
|
|
24
|
+
|
|
25
|
+
for (const cp of getAllOnLoop(cpNode)) {
|
|
26
|
+
const children = getVertexForwardChildren(cp);
|
|
27
|
+
|
|
28
|
+
// one child per non-terminating node on the circle other than the one
|
|
29
|
+
// leading back
|
|
30
|
+
const ring = getAllOnCircle(cp);
|
|
31
|
+
const expected = ring
|
|
32
|
+
.filter(c => c !== cp.prevOnCircle && !isTerminating(c))
|
|
33
|
+
.map(c => c.next);
|
|
34
|
+
expect(children.length).toBe(expected.length);
|
|
35
|
+
expect(children.every((c, i) => c === expected[i])).toBe(true);
|
|
36
|
+
|
|
37
|
+
for (const child of children) {
|
|
38
|
+
// a child is reached by an edge from this vertex...
|
|
39
|
+
expect(child.prev.pointOnShape.circle).toBe(cp.pointOnShape.circle);
|
|
40
|
+
// ...to a different vertex
|
|
41
|
+
expect(child.pointOnShape.circle).not.toBe(cp.pointOnShape.circle);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
7
44
|
});
|