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,42 @@
|
|
|
1
|
+
import { expect } from '@jest/globals';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
/** Asserts two points (or any equal-length number arrays) are nearly equal. */
|
|
5
|
+
function expectPointClose(
|
|
6
|
+
actual: number[],
|
|
7
|
+
expected: number[],
|
|
8
|
+
digits = 9): void {
|
|
9
|
+
|
|
10
|
+
expect(actual.length).toBe(expected.length);
|
|
11
|
+
for (let i=0; i<actual.length; i++) {
|
|
12
|
+
expect(actual[i]).toBeCloseTo(expected[i], digits);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
/** Asserts two bezier curves are nearly equal (same order and control points). */
|
|
18
|
+
function expectBezierClose(
|
|
19
|
+
actual: number[][],
|
|
20
|
+
expected: number[][],
|
|
21
|
+
digits = 9): void {
|
|
22
|
+
|
|
23
|
+
expect(actual.length).toBe(expected.length);
|
|
24
|
+
for (let i=0; i<actual.length; i++) {
|
|
25
|
+
expectPointClose(actual[i], expected[i], digits);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
/** Asserts consecutive beziers in the array join up end-to-start. */
|
|
31
|
+
function expectBeziersConnected(
|
|
32
|
+
pss: number[][][],
|
|
33
|
+
digits = 9): void {
|
|
34
|
+
|
|
35
|
+
for (let i=1; i<pss.length; i++) {
|
|
36
|
+
const prev = pss[i-1];
|
|
37
|
+
expectPointClose(pss[i][0], prev[prev.length-1], digits);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
export { expectPointClose, expectBezierClose, expectBeziersConnected }
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { describe, expect, test } from '@jest/globals';
|
|
2
|
+
import { hausdorffDistanceOneSided, closestPointOnBezier, evalDeCasteljau } from 'flo-bezier3';
|
|
3
|
+
import { hausdorffDistanceOneSidedExceeds, distanceToCurves } from '../../src/mat/hausdorff-distance-one-sided-exceeds.js';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The one-sided Hausdorff distance from `A` to the piecewise curve `B`
|
|
8
|
+
* approximated by dense sampling of `A` (a lower bound, accurate to within
|
|
9
|
+
* the sample spacing times the speed of `A`).
|
|
10
|
+
*/
|
|
11
|
+
function sampledHausdorffDistanceOneSided(
|
|
12
|
+
A: number[][],
|
|
13
|
+
B: number[][][],
|
|
14
|
+
samples = 4096): number {
|
|
15
|
+
|
|
16
|
+
let worst = 0;
|
|
17
|
+
for (let i=0; i<=samples; i++) {
|
|
18
|
+
const p = evalDeCasteljau(A, i/samples);
|
|
19
|
+
let best = Infinity;
|
|
20
|
+
for (const qs of B) {
|
|
21
|
+
best = Math.min(best, closestPointOnBezier(qs, p).d);
|
|
22
|
+
}
|
|
23
|
+
worst = Math.max(worst, best);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return worst;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
// a handful of 'from' curves of all orders
|
|
31
|
+
const As: number[][][] = [
|
|
32
|
+
[[0,0], [100,0]], // a line
|
|
33
|
+
[[0,0], [50,30], [100,0]], // a quadratic
|
|
34
|
+
[[0,0], [30,40], [70,-40], [100,0]], // a cubic with an inflection
|
|
35
|
+
[[0,0], [10,80], [90,80], [100,0]], // a 'tall' cubic
|
|
36
|
+
[[0,0], [100,0], [0,0]], // a degenerate (folded) quadratic
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
// a handful of 'to' curves
|
|
40
|
+
const Bs: number[][][] = [
|
|
41
|
+
[[0,1], [100,1]], // a line (offset by 1)
|
|
42
|
+
[[0,0], [50,10], [100,0]], // a quadratic
|
|
43
|
+
[[0,0], [50,-10], [100,0]], // a quadratic bending the other way
|
|
44
|
+
[[-10,5], [40,60], [110,-20]], // a quadratic not sharing endpoints
|
|
45
|
+
[[0,0], [30,10], [70,10], [100,0]], // a cubic
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
// relative margin beyond which the answers must certainly agree
|
|
49
|
+
const MARGIN = 2**-10;
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
describe('hausdorffDistanceOneSidedExceeds', function() {
|
|
53
|
+
test('agrees with the computed one-sided Hausdorff distance (single curve B)', function() {
|
|
54
|
+
let checks = 0;
|
|
55
|
+
for (const A of As) {
|
|
56
|
+
for (const B of Bs) {
|
|
57
|
+
// a very accurate reference value
|
|
58
|
+
const hd = hausdorffDistanceOneSided(A, B, 2**-30, 10_000);
|
|
59
|
+
expect(hd).toBeGreaterThan(0);
|
|
60
|
+
|
|
61
|
+
// tolerances on both sides of the reference value (a large
|
|
62
|
+
// iteration budget is given since certifying a distance that
|
|
63
|
+
// is *just* within tolerance requires resolving the curve to
|
|
64
|
+
// within the margin - e.g. the folded quadratic is at a
|
|
65
|
+
// uniform distance of 1 from the first line)
|
|
66
|
+
for (const f of [1/4, 1/2, 1 - 2*MARGIN, 1 + 2*MARGIN, 2, 4]) {
|
|
67
|
+
const tolerance = f*hd;
|
|
68
|
+
const exceeds = hausdorffDistanceOneSidedExceeds(A, [B], tolerance, 1_000_000);
|
|
69
|
+
expect(exceeds).toBe(hd > tolerance);
|
|
70
|
+
checks++;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
expect(checks).toBe(As.length*Bs.length*6);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('agrees with a densely sampled one-sided Hausdorff distance (piecewise B)', function() {
|
|
78
|
+
// piecewise 'to' curves - two quads joined at a point, and two
|
|
79
|
+
// disconnected pieces
|
|
80
|
+
const Bss: number[][][][] = [
|
|
81
|
+
[[[0,0], [25,20], [50,10]], [[50,10], [75,0], [100,0]]],
|
|
82
|
+
[[[0,2], [40,2]], [[60,-2], [100,-2]]],
|
|
83
|
+
[[[0,0], [30,10], [50,0]], [[50,0], [70,-10], [100,0]]],
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
for (const A of As) {
|
|
87
|
+
for (const Bs of Bss) {
|
|
88
|
+
const hd = sampledHausdorffDistanceOneSided(A, Bs);
|
|
89
|
+
expect(hd).toBeGreaterThan(0);
|
|
90
|
+
|
|
91
|
+
// the sampled value is a lower bound accurate to about
|
|
92
|
+
// `speed/4096` which is ~0.05 here, so stay well clear of it
|
|
93
|
+
expect(hausdorffDistanceOneSidedExceeds(A, Bs, hd*(1 - 2**-3), 1000)).toBe(true);
|
|
94
|
+
expect(hausdorffDistanceOneSidedExceeds(A, Bs, hd*(1 + 2**-3), 1000)).toBe(false);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('decides trivially for a point or line to a line', function() {
|
|
100
|
+
const B = [[[0,1], [100,1]]];
|
|
101
|
+
expect(hausdorffDistanceOneSidedExceeds([[50,0]], B, 0.5)).toBe(true);
|
|
102
|
+
expect(hausdorffDistanceOneSidedExceeds([[50,0]], B, 1.5)).toBe(false);
|
|
103
|
+
expect(hausdorffDistanceOneSidedExceeds([[0,0], [100,0]], B, 0.5)).toBe(true);
|
|
104
|
+
expect(hausdorffDistanceOneSidedExceeds([[0,0], [100,0]], B, 1.5)).toBe(false);
|
|
105
|
+
// a line to a line not parallel to it - the max is at an endpoint
|
|
106
|
+
expect(hausdorffDistanceOneSidedExceeds([[0,0], [100,0]], [[[0,0], [100,10]]], 9.9)).toBe(true);
|
|
107
|
+
expect(hausdorffDistanceOneSidedExceeds([[0,0], [100,0]], [[[0,0], [100,10]]], 10.1)).toBe(false);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test('is conservative when the iteration budget is exhausted', function() {
|
|
111
|
+
// the endpoints of `A` lie on `B` but the middle is 10 away; the
|
|
112
|
+
// initial upper bound is half the control polygon length (~54) so
|
|
113
|
+
// with no bisections allowed a tolerance of 30 cannot be certified
|
|
114
|
+
// either way and the check must fail
|
|
115
|
+
const A = [[0,0], [50,20], [100,0]];
|
|
116
|
+
const B = [[[0,0], [100,0]]];
|
|
117
|
+
expect(hausdorffDistanceOneSidedExceeds(A, B, 30, 0)).toBe(true);
|
|
118
|
+
// with a budget it decides correctly
|
|
119
|
+
expect(hausdorffDistanceOneSidedExceeds(A, B, 30, 50)).toBe(false);
|
|
120
|
+
expect(hausdorffDistanceOneSidedExceeds(A, B, 9.9, 50)).toBe(true);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test('distanceToCurves is the minimum over the pieces', function() {
|
|
124
|
+
const Bs = [[[0,0], [100,0]], [[0,10], [100,10]]];
|
|
125
|
+
expect(distanceToCurves([50,2], Bs)).toBeCloseTo(2, 12);
|
|
126
|
+
expect(distanceToCurves([50,8], Bs)).toBeCloseTo(2, 12);
|
|
127
|
+
expect(distanceToCurves([150,0], Bs)).toBeCloseTo(50, 12);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { expect, test } from '@jest/globals';
|
|
2
|
+
import { getPathsFromStr } from 'flo-boolean';
|
|
3
|
+
import { closestPointOnBezier, evalDeCasteljau } from 'flo-bezier3';
|
|
4
|
+
import { distanceBetween } from 'flo-vector2d';
|
|
5
|
+
import { findMats } from '../../src/find-mat/find-mats.js';
|
|
6
|
+
import { simplifyMat } from '../../src/mat/simplify-mat.js';
|
|
7
|
+
import { getAllOnLoop } from '../../src/cp-node/fs/get-all-on-loop.js';
|
|
8
|
+
import { getMatCurveToNext } from '../../src/cp-node/fs/get-mat-curve-to-next.js';
|
|
9
|
+
import { isTerminating } from '../../src/cp-node/fs/is-terminating.js';
|
|
10
|
+
import type { CpNode } from '../../src/cp-node/cp-node.js';
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
/** All the bezier pieces making up the MAT. */
|
|
14
|
+
function getMatBeziers(cpNode: CpNode): number[][][] {
|
|
15
|
+
return getAllOnLoop(cpNode)
|
|
16
|
+
.filter(cp => !isTerminating(cp))
|
|
17
|
+
.flatMap(getMatCurveToNext);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The one-sided Hausdorff distance from the curves `A` to the curves `B`,
|
|
23
|
+
* approximated by sampling points on `A`.
|
|
24
|
+
*/
|
|
25
|
+
function sampledHausdorffDistanceOneSided(
|
|
26
|
+
A: number[][][],
|
|
27
|
+
B: number[][][],
|
|
28
|
+
samplesPerCurve = 16): number {
|
|
29
|
+
|
|
30
|
+
let worst = 0;
|
|
31
|
+
for (const ps of A) {
|
|
32
|
+
for (let i=0; i<=samplesPerCurve; i++) {
|
|
33
|
+
const p = evalDeCasteljau(ps, i/samplesPerCurve);
|
|
34
|
+
let best = Infinity;
|
|
35
|
+
for (const qs of B) {
|
|
36
|
+
const { p: q } = closestPointOnBezier(qs, p);
|
|
37
|
+
best = Math.min(best, distanceBetween(p, q));
|
|
38
|
+
}
|
|
39
|
+
worst = Math.max(worst, best);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return worst;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
test('simplifyMat', function() {
|
|
48
|
+
// A smooth blob: its MAT is a single long branch made up of very many
|
|
49
|
+
// 2-prongs, so there is a lot to simplify.
|
|
50
|
+
const loops = getPathsFromStr(
|
|
51
|
+
'M0 0 C 50 -40 150 -40 200 0 C 250 40 250 80 200 120 ' +
|
|
52
|
+
'C 150 160 50 160 0 120 C -50 80 -50 40 0 0 Z'
|
|
53
|
+
);
|
|
54
|
+
const [mat] = findMats(loops, { simplify: false, applySat: false });
|
|
55
|
+
const original = getMatBeziers(mat.cpNode);
|
|
56
|
+
const originalCount = getAllOnLoop(mat.cpNode).length;
|
|
57
|
+
const originalTreeSizes = [...mat.meta.cpTrees.values()].map(t => t.size);
|
|
58
|
+
|
|
59
|
+
const hausdorffTolerance = 2**-3;
|
|
60
|
+
const simplified = simplifyMat(mat, hausdorffTolerance);
|
|
61
|
+
const simplifiedBeziers = getMatBeziers(simplified.cpNode);
|
|
62
|
+
|
|
63
|
+
// it did simplify...
|
|
64
|
+
expect(getAllOnLoop(simplified.cpNode).length).toBeLessThan(originalCount);
|
|
65
|
+
expect(simplifiedBeziers.length).toBeLessThan(original.length);
|
|
66
|
+
|
|
67
|
+
// ...but stayed within the tolerance: no point of the original MAT is
|
|
68
|
+
// further than `hausdorffTolerance` from the simplified MAT (the tolerance
|
|
69
|
+
// is a certified bound, up to floating point roundoff)
|
|
70
|
+
const hd = sampledHausdorffDistanceOneSided(original, simplifiedBeziers);
|
|
71
|
+
expect(hd).toBeLessThanOrEqual(hausdorffTolerance * (1 + 2**-20));
|
|
72
|
+
|
|
73
|
+
// the input MAT is left intact - its linked list *and* its `cpTrees`
|
|
74
|
+
expect(getAllOnLoop(mat.cpNode).length).toBe(originalCount);
|
|
75
|
+
expect([...mat.meta.cpTrees.values()].map(t => t.size)).toEqual(originalTreeSizes);
|
|
76
|
+
|
|
77
|
+
// the simplified MAT has its own `cpTrees`, consistent with its nodes
|
|
78
|
+
expect(simplified.meta.cpTrees).not.toBe(mat.meta.cpTrees);
|
|
79
|
+
const simplifiedNodes = getAllOnLoop(simplified.cpNode);
|
|
80
|
+
for (const [loop, tree] of simplified.meta.cpTrees) {
|
|
81
|
+
const onLoop = simplifiedNodes.filter(cp => cp.pointOnShape.curve.loop === loop);
|
|
82
|
+
expect(tree.size).toBe(onLoop.length);
|
|
83
|
+
for (const cp of onLoop) { expect(tree.find(cp)?.datum).toBe(cp); }
|
|
84
|
+
}
|
|
85
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { expect, test } from '@jest/globals';
|
|
2
|
+
import { reconstructFromMats } from '../../src/reconstruct-from-mat/reconstruct-from-mat.js';
|
|
3
|
+
import { getAllOnLoop } from '../../src/cp-node/fs/get-all-on-loop.js';
|
|
4
|
+
import { getMatsWithHole } from '../get-mats-with-hole.js';
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
test('reconstructFromMats - does not modify the given MATs', function() {
|
|
8
|
+
// (the fixture is SAT-processed, so SAT-induced trivial 3-prongs - which
|
|
9
|
+
// `reconstructFromMats` removes before reconstructing - may be present)
|
|
10
|
+
const mats = getMatsWithHole();
|
|
11
|
+
const before = mats.map(mat => ({
|
|
12
|
+
cpNode: mat.cpNode,
|
|
13
|
+
nodes: getAllOnLoop(mat.cpNode),
|
|
14
|
+
links: getAllOnLoop(mat.cpNode).map(cp =>
|
|
15
|
+
[cp.prev, cp.next, cp.prevOnCircle, cp.nextOnCircle]
|
|
16
|
+
)
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
const piecesss = reconstructFromMats(mats);
|
|
20
|
+
expect(piecesss.length).toBe(mats.length);
|
|
21
|
+
for (const piecess of piecesss) {
|
|
22
|
+
for (const pieces of piecess) { expect(pieces.length).toBeGreaterThan(0); }
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// same start node, same nodes, same links
|
|
26
|
+
mats.forEach((mat, i) => {
|
|
27
|
+
expect(mat.cpNode).toBe(before[i].cpNode);
|
|
28
|
+
const nodes = getAllOnLoop(mat.cpNode);
|
|
29
|
+
expect(nodes.length).toBe(before[i].nodes.length);
|
|
30
|
+
expect(nodes.every((cp, k) => cp === before[i].nodes[k])).toBe(true);
|
|
31
|
+
nodes.forEach((cp, k) => {
|
|
32
|
+
const [prev, next, prevOnCircle, nextOnCircle] = before[i].links[k];
|
|
33
|
+
expect(cp.prev).toBe(prev);
|
|
34
|
+
expect(cp.next).toBe(next);
|
|
35
|
+
expect(cp.prevOnCircle).toBe(prevOnCircle);
|
|
36
|
+
expect(cp.nextOnCircle).toBe(nextOnCircle);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -7,6 +7,20 @@
|
|
|
7
7
|
<glyph glyph-name=".notdef" horiz-adv-x="500"
|
|
8
8
|
d="M15 609v-593h469v593h-469zM500 0h-500v625h500v-625z" />
|
|
9
9
|
|
|
10
|
+
<glyph glyph-name="Q_V2"
|
|
11
|
+
d="
|
|
12
|
+
M 600 700
|
|
13
|
+
L 570 670
|
|
14
|
+
L 551.4300900092946 724.4845356715714
|
|
15
|
+
C 550.4300900092946 726.2165864791402 550.2961154130791 728.4486372867091 550.6621408168635 729.8146626904936
|
|
16
|
+
C 550.0281662206479 732.9127389018469 550.7602170282167 735.6447897094158 551.4922678357857 738.3768405169847
|
|
17
|
+
C 552.3582932395701 738.8768405169847 552.7243186433545 740.2428659207691 552.7243186433545 740.2428659207691
|
|
18
|
+
C 554.6884202584923 744.8409421321223 558.5185472774145 748.2069675359069 562.8486742963368 750.7069675359069
|
|
19
|
+
C 568.0448267190433 753.7069675359069 573.3749537379655 754.474916728338 578.3390553531033 753.8768405169847
|
|
20
|
+
z
|
|
21
|
+
"
|
|
22
|
+
/>
|
|
23
|
+
|
|
10
24
|
<glyph glyph-name="Q_V" unicode="" horiz-adv-x="750"
|
|
11
25
|
d="
|
|
12
26
|
M 1154.0678381635485 290.68533730950645
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { expect, test } from '@jest/globals';
|
|
2
|
+
import { cross, distanceBetween, fromTo, toUnitVector, translate } from 'flo-vector2d';
|
|
3
|
+
import { getBeziersFromTangents } from '../../src/utils/get-beziers-from-tangents.js';
|
|
4
|
+
import { expectBezierClose, expectBeziersConnected, expectPointClose } from '../helpers/expect-point-close.js';
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
const startTan = (ps: number[][]) => toUnitVector(fromTo(ps[0], ps[1]));
|
|
8
|
+
const endTan = (ps: number[][]) => toUnitVector(fromTo(ps[ps.length-2], ps[ps.length-1]));
|
|
9
|
+
/** tangent line at `p` with direction `angle` radians from the x-axis (and the given length) */
|
|
10
|
+
const line = (p: number[], angle: number, length = 1) =>
|
|
11
|
+
[p, translate(p, [length*Math.cos(angle), length*Math.sin(angle)])];
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
/** The invariants of a twisted result: two quadratics, exact ends, smooth join. */
|
|
15
|
+
function checkTwoQuadratics(pss: number[][][], p0: number[], p1: number[], d0: number[], d1: number[]) {
|
|
16
|
+
expect(pss.length).toBe(2);
|
|
17
|
+
expect(pss[0].length).toBe(3);
|
|
18
|
+
expect(pss[1].length).toBe(3);
|
|
19
|
+
|
|
20
|
+
// endpoints and end tangents are exact
|
|
21
|
+
expect(pss[0][0]).toBe(p0);
|
|
22
|
+
expect(pss[1][2]).toBe(p1);
|
|
23
|
+
expect(cross(startTan(pss[0]), toUnitVector(d0))).toBeCloseTo(0, 12);
|
|
24
|
+
expect(cross(endTan(pss[1]), toUnitVector(d1))).toBeCloseTo(0, 12);
|
|
25
|
+
|
|
26
|
+
// joined, and smoothly so
|
|
27
|
+
expectBeziersConnected(pss, 12);
|
|
28
|
+
expect(cross(endTan(pss[0]), startTan(pss[1]))).toBeCloseTo(0, 12);
|
|
29
|
+
|
|
30
|
+
// control points lie on the tangent lines a quarter chord away from the
|
|
31
|
+
// endpoints, towards the other endpoint
|
|
32
|
+
const chord = distanceBetween(p0, p1);
|
|
33
|
+
expect(distanceBetween(p0, pss[0][1])).toBeCloseTo(chord/4, 9);
|
|
34
|
+
expect(distanceBetween(p1, pss[1][1])).toBeCloseTo(chord/4, 9);
|
|
35
|
+
expect(distanceBetween(pss[0][1], p1)).toBeLessThan(distanceBetween(p0, p1) + chord/4);
|
|
36
|
+
expect(distanceBetween(pss[1][1], p0)).toBeLessThan(distanceBetween(p0, p1) + chord/4);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
test('getBeziersFromTangents - not twisted: a single quadratic', function() {
|
|
41
|
+
// tangents (1,1) at [0,0] and (1,-1) at [10,0] meet at [5,5]
|
|
42
|
+
const pss = getBeziersFromTangents(line([0,0], Math.PI/4), line([10,0], -Math.PI/4));
|
|
43
|
+
expect(pss.length).toBe(1);
|
|
44
|
+
expectBezierClose(pss[0], [[0,0],[5,5],[10,0]]);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
test('getBeziersFromTangents - collinear: a line', function() {
|
|
49
|
+
const pss = getBeziersFromTangents(line([0,0], 0), line([10,0], 0));
|
|
50
|
+
expect(pss).toEqual([[[0,0],[10,0]]]);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
test('getBeziersFromTangents - collinear with the intersection landing on an endpoint: a line', function() {
|
|
55
|
+
// From the `getMats1` fixture (edge 3 -> 145): both tangents point along
|
|
56
|
+
// the chord [46,54] -> [81.5,18.5] but numerically the lines intersect
|
|
57
|
+
// exactly at the end point. This must not produce a degenerate quadratic
|
|
58
|
+
// `[p0, p1, p1]` (with a zero end tangent) but a line.
|
|
59
|
+
const s = Math.SQRT1_2;
|
|
60
|
+
const l0 = [[46,54], [46+s, 54-s]];
|
|
61
|
+
const l1 = [[81.5,18.5], [81.5-s, 18.5+s]];
|
|
62
|
+
const pss = getBeziersFromTangents(l0, l1);
|
|
63
|
+
expect(pss.length).toBe(1);
|
|
64
|
+
expect(pss[0].length).toBe(2);
|
|
65
|
+
expectPointClose(pss[0][0], [46,54]);
|
|
66
|
+
expectPointClose(pss[0][1], [81.5,18.5]);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
test('getBeziersFromTangents - twisted (inflection): two quadratics', function() {
|
|
71
|
+
// tangents tilted to the *same* side at both ends force an S-shape
|
|
72
|
+
const cases = [
|
|
73
|
+
{ p0: [0,0], p1: [10,0], a0: 0.006, a1: 0.006 }, // symmetric
|
|
74
|
+
{ p0: [0,0], p1: [10,0], a0: 0.008, a1: 0.001 }, // asymmetric
|
|
75
|
+
{ p0: [3,7], p1: [9,2], a0: -0.007, a1: -0.004 }, // rotated chord
|
|
76
|
+
{ p0: [0,0], p1: [10,0], a0: 0.5, a1: 0.3 }, // strongly twisted
|
|
77
|
+
{ p0: [0,0], p1: [10,0], a0: Math.PI/2, a1: Math.PI/2 }, // tangents perpendicular to the chord
|
|
78
|
+
];
|
|
79
|
+
for (const { p0, p1, a0, a1 } of cases) {
|
|
80
|
+
const chordAngle = Math.atan2(p1[1]-p0[1], p1[0]-p0[0]);
|
|
81
|
+
const l0 = line(p0, chordAngle + a0);
|
|
82
|
+
const l1 = line(p1, chordAngle + a1);
|
|
83
|
+
const d0 = fromTo(l0[0], l0[1]);
|
|
84
|
+
const d1 = fromTo(l1[0], l1[1]);
|
|
85
|
+
|
|
86
|
+
checkTwoQuadratics(getBeziersFromTangents(l0, l1), p0, p1, d0, d1);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
test('getBeziersFromTangents - scale, tangent magnitude and orientation do not matter', function() {
|
|
92
|
+
const p0 = [0,0], p1 = [10,0];
|
|
93
|
+
const ref = getBeziersFromTangents(line(p0, 0.006), line(p1, 0.006));
|
|
94
|
+
|
|
95
|
+
const expectSame = (pss: number[][][]) => {
|
|
96
|
+
expect(pss.length).toBe(ref.length);
|
|
97
|
+
pss.forEach((ps, i) => ps.forEach((p, k) => expectPointClose(p, ref[i][k], 9)));
|
|
98
|
+
};
|
|
99
|
+
// tangent magnitude (e.g. an unnormalized bezier derivative)
|
|
100
|
+
expectSame(getBeziersFromTangents(line(p0, 0.006, 123.4), line(p1, 0.006, 0.001)));
|
|
101
|
+
// tangent orientation (either direction along the tangent line)
|
|
102
|
+
expectSame(getBeziersFromTangents(line(p0, 0.006 + Math.PI), line(p1, 0.006)));
|
|
103
|
+
expectSame(getBeziersFromTangents(line(p0, 0.006), line(p1, 0.006 + Math.PI)));
|
|
104
|
+
// scale: the same configuration scaled by 1000 (and by 1/1000) gives the
|
|
105
|
+
// same *kind* of result, scaled
|
|
106
|
+
for (const s of [1000, 1/1000]) {
|
|
107
|
+
const pss = getBeziersFromTangents(line([0,0], 0.006), line([10*s,0], 0.006));
|
|
108
|
+
expect(pss.length).toBe(ref.length);
|
|
109
|
+
pss.forEach((ps, i) => ps.forEach((p, k) => {
|
|
110
|
+
expectPointClose(p, [ref[i][k][0]*s, ref[i][k][1]*s], 9);
|
|
111
|
+
}));
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
test('getBeziersFromTangents - twisted but within tolerance: a line', function() {
|
|
117
|
+
// barely twisted (sine of the angle below 2**-16): a straight line will do
|
|
118
|
+
const pss = getBeziersFromTangents(line([0,0], 1e-6), line([10,0], 1e-6));
|
|
119
|
+
expect(pss.length).toBe(1);
|
|
120
|
+
expectBezierClose(pss[0], [[0,0],[10,0]]);
|
|
121
|
+
// ...at any scale
|
|
122
|
+
const pss2 = getBeziersFromTangents(line([0,0], 1e-6), line([1e6,0], 1e-6));
|
|
123
|
+
expect(pss2.length).toBe(1);
|
|
124
|
+
expect(pss2[0].length).toBe(2);
|
|
125
|
+
// ...but just above the tolerance it is two quadratics
|
|
126
|
+
expect(getBeziersFromTangents(line([0,0], 2e-5), line([10,0], 2e-5)).length).toBe(2);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
test('getBeziersFromTangents - coinciding endpoints: a degenerate line', function() {
|
|
131
|
+
const p = [46,8];
|
|
132
|
+
const pss = getBeziersFromTangents([p, [47,8]], [p, [46,9]]);
|
|
133
|
+
expect(pss).toEqual([[p, p]]);
|
|
134
|
+
// the same from the two nodes of a 1-prong (identical tangent lines)
|
|
135
|
+
expect(getBeziersFromTangents([p, [47,9]], [p, [47,9]])).toEqual([[p, p]]);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
test('getBeziersFromTangents - degenerate tangent: a line', function() {
|
|
140
|
+
const pss = getBeziersFromTangents([[0,0], [0,0]], line([10,0], 0.3));
|
|
141
|
+
expect(pss).toEqual([[[0,0],[10,0]]]);
|
|
142
|
+
});
|