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
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "flo-mat",
|
|
3
3
|
"sideEffects": false,
|
|
4
4
|
"description": "Medial / Scale Axis Transform (MAT/SAT) Library.",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "5.0.2",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Floris Steenkamp"
|
|
8
8
|
},
|
|
@@ -31,22 +31,22 @@
|
|
|
31
31
|
"skeleton"
|
|
32
32
|
],
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"big-float-ts": "^4.0.
|
|
35
|
-
"double-double": "^
|
|
36
|
-
"flo-bezier3": "^
|
|
37
|
-
"flo-boolean": "^6.0.
|
|
34
|
+
"big-float-ts": "^4.0.5",
|
|
35
|
+
"double-double": "^4.0.0",
|
|
36
|
+
"flo-bezier3": "^9.0.1",
|
|
37
|
+
"flo-boolean": "^6.0.3",
|
|
38
38
|
"flo-gauss-quadrature": "^2.1.4",
|
|
39
39
|
"flo-ll-rb-tree": "^1.0.4",
|
|
40
40
|
"flo-memoize": "^2.0.1",
|
|
41
|
-
"flo-poly": "^
|
|
41
|
+
"flo-poly": "^9.0.2",
|
|
42
42
|
"flo-vector2d": "^4.0.6"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@jest/globals": "^30.5.2",
|
|
46
|
-
"@swc/core": "^1.16.
|
|
46
|
+
"@swc/core": "^1.16.18",
|
|
47
47
|
"@swc/jest": "^0.2.39",
|
|
48
48
|
"@types/jest": "^30.0.0",
|
|
49
|
-
"@types/node": "^26.6.
|
|
49
|
+
"@types/node": "^26.6.5",
|
|
50
50
|
"c8": "^12.0.0",
|
|
51
51
|
"cheerio": "^1.2.0",
|
|
52
52
|
"circular-dependency-plugin": "^5.2.2",
|
|
@@ -70,6 +70,6 @@
|
|
|
70
70
|
"allowScripts": {
|
|
71
71
|
"unrs-resolver@1.12.2": true,
|
|
72
72
|
"@parcel/watcher@2.6.0": true,
|
|
73
|
-
"@swc/core@1.16.
|
|
73
|
+
"@swc/core@1.16.18": true
|
|
74
74
|
}
|
|
75
75
|
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Q_V infinite loop - investigation handoff
|
|
2
|
+
|
|
3
|
+
Status: root cause found, **nothing fixed yet**. All diagnostic instrumentation
|
|
4
|
+
has been removed from `src/`.
|
|
5
|
+
|
|
6
|
+
## Symptom
|
|
7
|
+
|
|
8
|
+
`findMats` never returns for the `Q_V` glyph of `__tests__/specific-cases/test-svgs/achispado.svg`
|
|
9
|
+
**once the 1-prong pass is enabled**, i.e. once line 39 of
|
|
10
|
+
`src/find-mat/get-for-1-prongs-on-loop.ts` reads
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
.filter(pos => pos.t > 2**-20 && pos.t < 1 - 2**-20);
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
(The historical form `pos.t < 2**-20` is impossible, so the 1-prong pass added
|
|
17
|
+
nothing and the problem was invisible. Line 39 is correct as written above; the
|
|
18
|
+
bug is elsewhere.)
|
|
19
|
+
|
|
20
|
+
Reproduce (the loop is synchronous, so only a process-level time limit stops it;
|
|
21
|
+
use Git Bash for `timeout`):
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
timeout 120 npx jest __tests__/specific-cases # with "Q_V" in the glyph list
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Where it loops
|
|
28
|
+
|
|
29
|
+
`findAndAdd3Prongs` (`src/find-3-prong/find-and-add-3-prongs.ts`, the
|
|
30
|
+
`do ... while (true)`), started from CpNode #90. Each iteration:
|
|
31
|
+
|
|
32
|
+
1. `traverseCp(#90)` visits the same 7-vertex face.
|
|
33
|
+
2. `find3Prong` finds the same 3-prong: radius 23.18, contacts at the dull
|
|
34
|
+
corner at the end of curve 10, the dull corner at the end of curve 14, and
|
|
35
|
+
curve 14 at t = 0.726.
|
|
36
|
+
3. `findAndAdd3Prong`'s close-by check (`getCloseByCpIfExist`) *does* find the
|
|
37
|
+
copy inserted in the previous iteration, but `if (prongCount <= 2 && ...)`
|
|
38
|
+
ignores anything that is already a 3-prong, so a duplicate is inserted.
|
|
39
|
+
4. The face does not shrink (the new nodes interleave with existing ones at the
|
|
40
|
+
two corners) - repeat forever.
|
|
41
|
+
|
|
42
|
+
## Why the face is wrong
|
|
43
|
+
|
|
44
|
+
`traverseCp` from #90 returns to its own vertex through the *other* node #91 and
|
|
45
|
+
continues, so vertex {#90, #91} appears twice on one face. That 2-prong is
|
|
46
|
+
geometrically invalid: center [567.20, 736.36], radius 14.99; its contacts
|
|
47
|
+
(curve 13 at t = 0.9999926 and the far dull corner of curve 14, t = 1)
|
|
48
|
+
interleave along the boundary with those of the existing 3-prong A
|
|
49
|
+
(curve 13 at 0.58, curve 14 at 0.7265), and A's contact point on curve 14
|
|
50
|
+
([559.44, 748.45]) is 14.37 from the disk's center - inside the disk. The disk
|
|
51
|
+
cuts through curve 14.
|
|
52
|
+
|
|
53
|
+
## Root cause: a degenerate bezier end in the font data
|
|
54
|
+
|
|
55
|
+
Curve 13 (raw path bezier 21) is a tiny cubic whose last two control points are
|
|
56
|
+
identical in the SVG itself:
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
[[551.49,738.38],[552.36,738.88],[552.7243186433545,740.2428659207691],[552.7243186433545,740.2428659207691]]
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Its speed is therefore 0 at t = 1 (|tangent| ~ 2e-10). Three things break:
|
|
63
|
+
|
|
64
|
+
1. **Spurious curvature maximum.** `getCurvatureExtremaDd` reports a maximum at
|
|
65
|
+
t = 0.9999925600310483 - the curvature blowing up toward the zero-speed end
|
|
66
|
+
(2.6e3 there, -4e19 at t = 1), not a feature of the shape. It passes the
|
|
67
|
+
line-39 filter: 7e-6 in parameter from the end, ~1e-10 in distance. The
|
|
68
|
+
candidate *is* the c13/c14 junction.
|
|
69
|
+
2. **Garbage normal.** `ddNormal` at that t is a vector of length 6e-5 whose
|
|
70
|
+
direction is ~11 degrees off the true inward direction at the junction. The
|
|
71
|
+
2-prong ray search runs along it (curve 14 *was* fully in the searched
|
|
72
|
+
pieces), finds no interior tangency on that ray, and accepts the far corner
|
|
73
|
+
of curve 14 at distance 14.99. `getOsculatingCircle` clamps rO to the maximum
|
|
74
|
+
(1346.7) because the curvature sign is wrong there.
|
|
75
|
+
3. **Corner not detected.** The c13/c14 junction is a real corner of ~8 degrees,
|
|
76
|
+
but `getInterfaceCcw(c13.ps, c14.ps)` takes curve 13's end tangent from the
|
|
77
|
+
3e-11-long derivative; the unit tangent comes out as (0.447, 0.894) - a 1:2
|
|
78
|
+
rounding residue - giving a 3.5 degree turn, under the 4 degree `DEGREE_LIMIT`.
|
|
79
|
+
Result: `isDull = true`, `isQuiteDull = false`, so the corner gets no corner
|
|
80
|
+
handling and no corner contact points at all.
|
|
81
|
+
|
|
82
|
+
So the spurious contact sits exactly at a corner position but is ordered as an
|
|
83
|
+
interior point of curve 13 (order 0), outside all corner-ordering logic, while
|
|
84
|
+
the corner itself is never registered - hence the "ordering" smell.
|
|
85
|
+
|
|
86
|
+
## Suggested fixes (not implemented)
|
|
87
|
+
|
|
88
|
+
Most fundamental first:
|
|
89
|
+
|
|
90
|
+
- Handle near-zero end derivatives: in `getInterfaceCcw` take the end tangent
|
|
91
|
+
from the last *distinct* control point when control points coincide; reject
|
|
92
|
+
curvature-extrema 1-prong candidates where the speed is below a scaled
|
|
93
|
+
threshold (or where the osculating radius comes back clamped to the maximum).
|
|
94
|
+
- Make `findAndAdd3Prong` treat an existing 3-prong at the same contact points
|
|
95
|
+
as a duplicate (drop or rethink the `prongCount <= 2` filter) so a repeat is
|
|
96
|
+
detected instead of re-inserted.
|
|
97
|
+
- Put an iteration cap on the `do ... while (true)` in `findAndAdd3Prongs` that
|
|
98
|
+
throws with context, so this class of bug fails loudly.
|
|
99
|
+
- Consider making `traverseCp` terminate on reaching the start *vertex* (any
|
|
100
|
+
node on the start circle), not the start *node*, which would have exposed the
|
|
101
|
+
inconsistency immediately.
|
|
102
|
+
|
|
103
|
+
## Useful diagnostics (how it was found, for re-use)
|
|
104
|
+
|
|
105
|
+
- `node --prof node_modules/jest/bin/jest.js --runInBand <spec>` under
|
|
106
|
+
`timeout`, then `node --prof-process isolate-*.log`: the V8 log is appended
|
|
107
|
+
while running, so it survives the kill and shows the hot functions.
|
|
108
|
+
- A per-call iteration counter in `findAndAdd3Prongs` that logs `traverseCp`'s
|
|
109
|
+
visited nodes (id, curve idx, t, order, radius, ring members, prev/next) once
|
|
110
|
+
a call exceeds ~3 iterations, plus logging of `getCloseByCpIfExist` results
|
|
111
|
+
and `insertCpNode` pred/succ in `addToCpTree`, found the duplicate cycle.
|
|
112
|
+
- Logging `nnorm`, `rO`, the searched curve pieces and the antipodes in
|
|
113
|
+
`find2Prong` for the source at curve 13, t > 0.9999 exposed the bad ray.
|
|
114
|
+
|
|
115
|
+
## Working-tree state to be aware of
|
|
116
|
+
|
|
117
|
+
- Line 39 of `get-for-1-prongs-on-loop.ts` is currently back in the impossible
|
|
118
|
+
`pos.t < 2**-20` form (1-prong pass disabled again).
|
|
119
|
+
- `__tests__/specific-cases/specific-cases.spec.ts` currently lists only `"Q_V"`;
|
|
120
|
+
the full glyph list from HEAD must be restored before committing.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { CurvePiece } from '../mat/curve-piece.js';
|
|
2
|
+
import { getBoundingBox$, getBoundingBoxTight$ } from '../geometry/get-bounding-box-.js';
|
|
3
|
+
import { getClosestSquareDistanceToRect } from '../geometry/get-closest-square-distance-to-rect.js';
|
|
4
|
+
import { getClosestSquaredDistanceToRotatedRect } from '../geometry/get-closest-squared-distance-to-rotated-rect.js';
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Returns the given curve pieces with those culled whose closest possible
|
|
9
|
+
* point to `p` is further than `sqrt(maxSquaredDistance)` away.
|
|
10
|
+
*
|
|
11
|
+
* * a piece is kept only if both its (cheap, axis-aligned) loose bounding box
|
|
12
|
+
* and then its (rotated) tight bounding box come within the distance
|
|
13
|
+
* * the bounding boxes are those of the entire curves (not just the pieces)
|
|
14
|
+
* and are memoized per curve
|
|
15
|
+
* * the given array is not modified (callers may reuse it for other points)
|
|
16
|
+
* * any tolerance for floating point error is the responsibility of the
|
|
17
|
+
* caller (i.e. `maxSquaredDistance` should already include it)
|
|
18
|
+
*
|
|
19
|
+
* @param curvePieces the curve pieces to cull
|
|
20
|
+
* @param p the point
|
|
21
|
+
* @param maxSquaredDistance the squared distance beyond which to cull
|
|
22
|
+
*
|
|
23
|
+
* @internal
|
|
24
|
+
*/
|
|
25
|
+
function cullCurvePieces(
|
|
26
|
+
curvePieces: CurvePiece[],
|
|
27
|
+
p: number[],
|
|
28
|
+
maxSquaredDistance: number): CurvePiece[] {
|
|
29
|
+
|
|
30
|
+
const culled: CurvePiece[] = [];
|
|
31
|
+
|
|
32
|
+
for (let i=0; i<curvePieces.length; i++) {
|
|
33
|
+
const curvePiece = curvePieces[i];
|
|
34
|
+
const { ps } = curvePiece.curve;
|
|
35
|
+
|
|
36
|
+
const d = getClosestSquareDistanceToRect(getBoundingBox$(ps), p);
|
|
37
|
+
if (d > maxSquaredDistance) { continue; }
|
|
38
|
+
|
|
39
|
+
const d2 = getClosestSquaredDistanceToRotatedRect(getBoundingBoxTight$(ps), p);
|
|
40
|
+
if (d2 > maxSquaredDistance) { continue; }
|
|
41
|
+
|
|
42
|
+
culled.push(curvePiece);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return culled;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
export { cullCurvePieces }
|
|
@@ -2,7 +2,8 @@ import type { CurvePiece } from '../mat/curve-piece.js';
|
|
|
2
2
|
import type { FootAndEndpointInfo } from './foot-and-endpoint-info.js';
|
|
3
3
|
import type { PrePointOnShape } from '../point-on-shape/point-on-shape.js';
|
|
4
4
|
import { getPotentialClosestPointsOnCurveCertified } from './get-potential-closest-points-on-curve-certified.js';
|
|
5
|
-
import {
|
|
5
|
+
import { cullCurvePieces } from './cull-curve-pieces.js';
|
|
6
|
+
import { getBestDistanceSquared } from './get-best-distance-squared.js';
|
|
6
7
|
import { toP } from '../point-on-shape/to-p.js';
|
|
7
8
|
|
|
8
9
|
|
|
@@ -20,7 +21,9 @@ function getCloseBoundaryPointsCertified(
|
|
|
20
21
|
curvePieces: CurvePiece[],
|
|
21
22
|
x: number[]): PrePointOnShape[] {
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
// cull the pieces that cannot contain the closest point (the best
|
|
25
|
+
// squared distance already includes a floating point tolerance)
|
|
26
|
+
curvePieces = cullCurvePieces(curvePieces, x, getBestDistanceSquared(curvePieces, x));
|
|
24
27
|
|
|
25
28
|
const pInfos: FootAndEndpointInfo[] = [];
|
|
26
29
|
for (let i=0; i<curvePieces.length; i++) {
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { Curve } from "flo-boolean";
|
|
2
|
+
import type { FootAndEndpointInfo } from './foot-and-endpoint-info.js';
|
|
3
|
+
import { evalDeCasteljauWithErrDd } from 'flo-bezier3';
|
|
4
|
+
import { ddDiffDouble } from 'double-double';
|
|
5
|
+
import { eps } from '../error-analysis/gamma.js';
|
|
6
|
+
|
|
7
|
+
const { abs, max } = Math;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Relative widening of the interval bounds - see the error analysis in
|
|
11
|
+
* `getEndpointInfoCertified`: the exact first order requirement is `6u = 3eps`
|
|
12
|
+
* (`u = eps/2` the unit roundoff); `4eps = 2**-50` (exactly representable)
|
|
13
|
+
* leaves room for the `O(u²)` terms.
|
|
14
|
+
*/
|
|
15
|
+
const WIDEN = 4*eps;
|
|
16
|
+
/**
|
|
17
|
+
* Absolute slack (relative to `ax² + ay²`) for the lower bound - see the error
|
|
18
|
+
* analysis: the exact first order requirement is `2u² = eps²/2`.
|
|
19
|
+
*/
|
|
20
|
+
const SLACK = eps*eps;
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Returns the `FootAndEndpointInfo` of the endpoint at parameter `t` of the
|
|
25
|
+
* given curve, i.e. the certified interval `dSquaredI` guaranteed to contain
|
|
26
|
+
* the squared distance from `x` to the point on the curve at `t` (`t` taken as
|
|
27
|
+
* exact).
|
|
28
|
+
*
|
|
29
|
+
* * the point is kept in double-double precision (including its evaluation
|
|
30
|
+
* error bound) until the differences with `x` have been taken, so the only
|
|
31
|
+
* rounding left is that of forming the interval in double precision, which
|
|
32
|
+
* is accounted for exactly below
|
|
33
|
+
*
|
|
34
|
+
* Error analysis (`u = eps/2` the unit roundoff, `fl(a∘b) = (a∘b)(1+δ)`,
|
|
35
|
+
* `|δ| <= u`): let `a` be the exact magnitude of the double-double difference
|
|
36
|
+
* `dx` and `Δx` the true (exact) difference. Then
|
|
37
|
+
* * `|Δx| ∈ [a(1-ρ) - ex, a(1+ρ) + ex]` with `ρ = 2u²` (the relative error
|
|
38
|
+
* bound of the double-double minus double subtraction) and `ex` the
|
|
39
|
+
* evaluation error bound on the coordinate
|
|
40
|
+
* * `ax = |hi(dx)|` satisfies `|ax - a| <= u·ax` (the low part of a
|
|
41
|
+
* normalized double-double is at most half an ulp of the high part)
|
|
42
|
+
* * the upper bound `(ax+ex)² + (ay+ey)²` is then computed with 3 roundings
|
|
43
|
+
* (addition, square, sum) and widened with 1 more; it must dominate
|
|
44
|
+
* `(a(1+ρ)+ex)² + ...` which requires `(1-u)⁴(1+WIDEN) >= (1+u+ρ)²`, i.e.
|
|
45
|
+
* `WIDEN >= 6u + O(u²)`
|
|
46
|
+
* * the lower bound `(ax-ex)₊² + (ay-ey)₊²` likewise requires
|
|
47
|
+
* `(1+u)⁴(1-WIDEN) <= (1-u-ρ)²`, i.e. `WIDEN >= 6u + O(u²)`, *except* that
|
|
48
|
+
* when the true term is `0` (`a <= ex`) rounding may still leave
|
|
49
|
+
* `ax - ex <= ax·u` positive, giving a spurious `(ax-ex)² <= 2u²·ax²`; this
|
|
50
|
+
* is covered by subtracting `SLACK·(ax² + ay²)` with `SLACK >= 2u²`
|
|
51
|
+
*
|
|
52
|
+
* @param curve the curve
|
|
53
|
+
* @param x the point from which to check
|
|
54
|
+
* @param t the parameter value of the endpoint
|
|
55
|
+
*
|
|
56
|
+
* @internal
|
|
57
|
+
*/
|
|
58
|
+
function getEndpointInfoCertified(
|
|
59
|
+
curve: Curve,
|
|
60
|
+
x: number[],
|
|
61
|
+
t: number): FootAndEndpointInfo {
|
|
62
|
+
|
|
63
|
+
const { ps } = curve;
|
|
64
|
+
|
|
65
|
+
// the point in double-double precision with coordinate-wise absolute
|
|
66
|
+
// error bounds `pE`
|
|
67
|
+
const { p: pDd, pE } = evalDeCasteljauWithErrDd(ps, [0,t]);
|
|
68
|
+
|
|
69
|
+
// the coordinate differences in double-double precision
|
|
70
|
+
const dx = ddDiffDouble(pDd[0], x[0]);
|
|
71
|
+
const dy = ddDiffDouble(pDd[1], x[1]);
|
|
72
|
+
|
|
73
|
+
const ax = abs(dx[1]);
|
|
74
|
+
const ay = abs(dy[1]);
|
|
75
|
+
const [ex, ey] = pE;
|
|
76
|
+
|
|
77
|
+
const lo = max(ax - ex, 0)**2 + max(ay - ey, 0)**2;
|
|
78
|
+
const hi = (ax + ex)**2 + (ay + ey)**2;
|
|
79
|
+
|
|
80
|
+
const dSquaredI = [
|
|
81
|
+
max(lo*(1 - WIDEN) - SLACK*(ax*ax + ay*ay), 0),
|
|
82
|
+
hi*(1 + WIDEN)
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
const t_ = t === 0 ? 1 : t;
|
|
86
|
+
const curve_ = t === 0 ? curve.prev : curve;
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
curve: curve_,
|
|
90
|
+
t: t_,
|
|
91
|
+
dSquaredI
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
export { getEndpointInfoCertified }
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import type { Curve } from "flo-boolean";
|
|
2
2
|
import type { FootAndEndpointInfo } from './foot-and-endpoint-info.js';
|
|
3
3
|
import { roots } from 'flo-poly';
|
|
4
|
-
import {
|
|
4
|
+
import { getFootPointsOnBezierPolysCertified, getIntervalBox } from 'flo-bezier3';
|
|
5
5
|
import { rootIntervalToDistanceSquaredInterval } from './root-interval-to-distance-squared-interval.js';
|
|
6
|
-
import {
|
|
7
|
-
import { eps } from '../error-analysis/gamma.js';
|
|
6
|
+
import { getEndpointInfoCertified } from './get-endpoint-info.js';
|
|
8
7
|
|
|
9
8
|
|
|
10
9
|
/**
|
|
@@ -50,27 +49,10 @@ function getPotentialClosestPointsOnCurveCertified(
|
|
|
50
49
|
}));
|
|
51
50
|
}
|
|
52
51
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
ts.push(tS);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
infos.push(...ts.map(t => {
|
|
59
|
-
const p = evalDeCasteljauDd(ps, [0,t]).map(v => v[0] + v[1]);
|
|
60
|
-
|
|
61
|
-
const d = squaredDistanceBetweenDd(p, x);
|
|
62
|
-
|
|
63
|
-
const dSquaredI = [d*(1 - eps), d*(1 + eps)];
|
|
64
|
-
|
|
65
|
-
const t_ = t === 0 ? 1 : t;
|
|
66
|
-
const curve_ = t === 0 ? curve.prev : curve;
|
|
52
|
+
// the endpoints of the range (just the one if the range is a single point)
|
|
53
|
+
const ts = tS === tE ? [tS] : [tS, tE];
|
|
67
54
|
|
|
68
|
-
|
|
69
|
-
curve: curve_,
|
|
70
|
-
t: t_,
|
|
71
|
-
dSquaredI
|
|
72
|
-
}
|
|
73
|
-
}));
|
|
55
|
+
infos.push(...ts.map(t => getEndpointInfoCertified(curve, x, t)));
|
|
74
56
|
|
|
75
57
|
return infos;
|
|
76
58
|
}
|
|
@@ -1,75 +1,57 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { eps } from '../error-analysis/gamma.js';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const qmq = ddMultDd;
|
|
5
|
-
const qaq = ddAddDd;
|
|
3
|
+
const { max } = Math;
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Relative widening of the interval bounds - see the error analysis in
|
|
7
|
+
* `rootIntervalToDistanceSquaredInterval`: the exact first order requirement
|
|
8
|
+
* is `4u = 2eps` (`u = eps/2` the unit roundoff); `4eps = 2**-50` (exactly
|
|
9
|
+
* representable) leaves room for the `O(u²)` terms.
|
|
10
|
+
*/
|
|
11
|
+
const WIDEN = 4*eps;
|
|
8
12
|
|
|
9
13
|
|
|
10
14
|
/**
|
|
11
|
-
* Returns
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
15
|
+
* Returns an interval `[min, max]` guaranteed to contain the squared distance
|
|
16
|
+
* from the point `p` to *any* point of a curve piece, given an axis-aligned
|
|
17
|
+
* box that is guaranteed to engulf that piece (see `getIntervalBox`).
|
|
18
|
+
*
|
|
19
|
+
* * the minimum squared distance to the box is attained on its boundary (or
|
|
20
|
+
* is `0` if `p` is inside): per axis the distance is the gap between `p` and
|
|
21
|
+
* the box's range on that axis (`0` if `p` is within the range)
|
|
22
|
+
* * the maximum squared distance to the box is attained at a corner: per axis
|
|
23
|
+
* it is the larger of the distances to the two range ends
|
|
24
|
+
*
|
|
25
|
+
* Error analysis (`u = eps/2` the unit roundoff, `fl(a∘b) = (a∘b)(1+δ)`,
|
|
26
|
+
* `|δ| <= u`): all inputs are doubles and each bound is computed with 3
|
|
27
|
+
* roundings per term path (subtraction, square, sum - `max` is exact) and
|
|
28
|
+
* widened with 1 more, so the computed bound is within a factor `(1±u)⁴` of
|
|
29
|
+
* the exact one before widening and `WIDEN >= 4u + O(u²)` makes the interval
|
|
30
|
+
* rigorous. (A gap of `0` is exact: `fl(a-b)` has the sign of `a-b`.)
|
|
31
|
+
*
|
|
32
|
+
* @param box the engulfing box given as `[[minX, minY], [maxX, maxY]]`
|
|
33
|
+
* @param p the point
|
|
34
|
+
*
|
|
19
35
|
* @internal
|
|
20
36
|
*/
|
|
21
37
|
function rootIntervalToDistanceSquaredInterval(
|
|
22
|
-
box: number[][],
|
|
23
|
-
p: number[]) {
|
|
24
|
-
|
|
25
|
-
const bl = box[0];
|
|
26
|
-
const tr = box[1];
|
|
27
|
-
const minX = bl[0];
|
|
28
|
-
const minY = bl[1];
|
|
29
|
-
const maxX = tr[0];
|
|
30
|
-
const maxY = tr[1];
|
|
31
|
-
|
|
32
|
-
const x = p[0]; // <0>
|
|
33
|
-
const y = p[1]; // <0>
|
|
34
|
-
|
|
35
|
-
let minDSquared = +Infinity;
|
|
36
|
-
let maxDSquared = -Infinity;
|
|
37
|
-
|
|
38
|
-
// for each corner of the interval box
|
|
39
|
-
for (const [a,b] of [[minX,minY],[minX,maxY],[maxX,minY],[maxX,maxY]]) {
|
|
40
|
-
/*
|
|
41
|
-
// distance to 1st corner of interval box - `distance² = x² + y²`
|
|
42
|
-
const dc1 = (a - x)**2 + (b - y)**2;
|
|
43
|
-
// max absolute roundoff error of `dc1`
|
|
44
|
-
// <4>dc1 <-- <4>(<3>(<1>(a - x)**2) + <3>(<1>((b - y)**2))
|
|
45
|
-
const dc1E = 4*γ1*((a + x)**2 + (b + y)**2);
|
|
46
|
-
const dc1Min = dc1 - dc1E; // distance minus max error
|
|
47
|
-
const dc1Max = dc1 + dc1E; // distance plus max error
|
|
48
|
-
*/
|
|
38
|
+
box: number[][],
|
|
39
|
+
p: number[]): number[] {
|
|
49
40
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const by = td(b,y); // b - y
|
|
53
|
-
// const dc1Exact = eadd(emult(ax,ax),emult(by,by)); // ax**2 + bx**2
|
|
54
|
-
// const dc1 = estimate(dc1Exact);
|
|
55
|
-
const dc1Dd = qaq(qmq(ax,ax),qmq(by,by)); // ax**2 + bx**2
|
|
56
|
-
const dc1 = dc1Dd[1];
|
|
41
|
+
const [[minX, minY], [maxX, maxY]] = box;
|
|
42
|
+
const [x, y] = p;
|
|
57
43
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
minDSquared = dc1Min;
|
|
65
|
-
}
|
|
44
|
+
// per axis gap between `p` and the box (`0` if `p` is within range)
|
|
45
|
+
const dxMin = max(minX - x, 0, x - maxX);
|
|
46
|
+
const dyMin = max(minY - y, 0, y - maxY);
|
|
47
|
+
// per axis distance from `p` to the furthest end of the box's range
|
|
48
|
+
const dxMax = max(x - minX, maxX - x);
|
|
49
|
+
const dyMax = max(y - minY, maxY - y);
|
|
66
50
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
}
|
|
51
|
+
const minDSquared = dxMin*dxMin + dyMin*dyMin;
|
|
52
|
+
const maxDSquared = dxMax*dxMax + dyMax*dyMax;
|
|
71
53
|
|
|
72
|
-
return [minDSquared,maxDSquared];
|
|
54
|
+
return [minDSquared*(1 - WIDEN), maxDSquared*(1 + WIDEN)];
|
|
73
55
|
}
|
|
74
56
|
|
|
75
57
|
|
package/src/corner/get-corner.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Corner } from "./corner.js";
|
|
2
|
+
import { memoize } from 'flo-memoize';
|
|
2
3
|
import { cross, toUnitVector } from "flo-vector2d";
|
|
3
4
|
import { getInterfaceCcw } from './get-interface-ccw.js';
|
|
4
5
|
|
|
@@ -70,4 +71,12 @@ function getCorner(
|
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
|
|
73
|
-
|
|
74
|
+
/**
|
|
75
|
+
* Memoized version of `getCorner` (keyed on the two control point arrays).
|
|
76
|
+
*
|
|
77
|
+
* @internal
|
|
78
|
+
*/
|
|
79
|
+
const getCorner$ = memoize(getCorner);
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
export { getCorner, getCorner$ }
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { eAdd,
|
|
1
|
+
import { eAdd, eEstimate, eMult, eNegativeOf, twoDiff } from 'big-float-ts';
|
|
2
2
|
import { compareCurvaturesAtInterface } from "./compare-curvatures-at-interface.js";
|
|
3
3
|
|
|
4
4
|
|
|
@@ -137,4 +137,4 @@ function crossPrecise(
|
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
|
|
140
|
-
export { getInterfaceCcw }
|
|
140
|
+
export { getInterfaceCcw }
|
package/src/cp-node/cp-node.ts
CHANGED
|
@@ -26,9 +26,10 @@ import { PointOnShape } from '../point-on-shape/point-on-shape.js';
|
|
|
26
26
|
* following other branches on the MAT.
|
|
27
27
|
*
|
|
28
28
|
* Call `getMatCurveBetween(cpNodeFrom, cpNodeTo)` or `getMatCurveToNext(cpNode)`
|
|
29
|
-
* (replacing the older CpNode.`matCurveToNextVertex`) to get
|
|
30
|
-
* from the maximal disk of this
|
|
31
|
-
* maximal disk and thus directly representing
|
|
29
|
+
* (replacing the older CpNode.`matCurveToNextVertex`) to get the bezier curves
|
|
30
|
+
* (1 or 2 lines or quadratics joined smoothly) from the maximal disk of this
|
|
31
|
+
* `CpNode` to the next `CpNode`'s maximal disk and thus directly representing
|
|
32
|
+
* a piece of the medial axis.
|
|
32
33
|
*
|
|
33
34
|
* The function, `getChildren`, returns the children of this `CpNode` when
|
|
34
35
|
* seen as a MAT edge. Only children in a 'forward' direction are returned. These
|
|
@@ -16,10 +16,6 @@ function getAllOnLoop_ByLoop(
|
|
|
16
16
|
|
|
17
17
|
const cpStarts: CpNode[] = [cpNode];
|
|
18
18
|
const cpStartSet = new Set(cpStarts);
|
|
19
|
-
if (cpNode.isHoleClosing) {
|
|
20
|
-
cpStartSet.add(cpNode.prevOnCircle.holeCloserTwin!);
|
|
21
|
-
}
|
|
22
|
-
cpStartSet.add(cpNode);
|
|
23
19
|
|
|
24
20
|
while (cpStarts.length > 0) {
|
|
25
21
|
const cpNodes: CpNode[] = [];
|
|
@@ -3,7 +3,7 @@ import { tangent } from "flo-bezier3";
|
|
|
3
3
|
import { cross, toUnitVector } from "flo-vector2d";
|
|
4
4
|
import { getMatCurveToNext } from "./get-mat-curve-to-next.js";
|
|
5
5
|
|
|
6
|
-
const { abs, asin, PI: π } = Math;
|
|
6
|
+
const { abs, asin, min, max, PI: π } = Math;
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -17,15 +17,17 @@ function getInitialDegAngleBetweenMatCurves(
|
|
|
17
17
|
cpNode2: CpNode) {
|
|
18
18
|
|
|
19
19
|
const tan1 = toUnitVector(tangent(
|
|
20
|
-
getMatCurveToNext(cpNode1),
|
|
20
|
+
getMatCurveToNext(cpNode1)[0],
|
|
21
21
|
0
|
|
22
22
|
));
|
|
23
23
|
const tan2 = toUnitVector(tangent(
|
|
24
|
-
getMatCurveToNext(cpNode2),
|
|
24
|
+
getMatCurveToNext(cpNode2)[0],
|
|
25
25
|
0
|
|
26
26
|
));
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
// clamp: rounding can push the cross product of two unit vectors just
|
|
29
|
+
// outside [-1,1], which would make `asin` return `NaN`
|
|
30
|
+
const cross_ = max(-1, min(1, cross(tan1, tan2)));
|
|
29
31
|
const angle = abs(asin( cross_ ) * (180/π));
|
|
30
32
|
|
|
31
33
|
return angle;
|
|
@@ -4,15 +4,17 @@ import { getBoundaryBeziersToNext } from "./get-boundary-beziers-to-next.js";
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Returns
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* Returns the bezier curves of the shape boundary from the contact point of
|
|
8
|
+
* the first given `CpNode` to that of the second (following `next`), together
|
|
9
|
+
* with whether a hole closer was passed on the way.
|
|
10
|
+
*
|
|
11
|
+
* * If the second `CpNode` is never encountered the entire boundary is
|
|
10
12
|
* returned.
|
|
11
|
-
*
|
|
12
|
-
* @param cpNode1
|
|
13
|
-
* @param cpNode2
|
|
14
|
-
* @param inclAllIfEqual if `true` and
|
|
15
|
-
*
|
|
13
|
+
*
|
|
14
|
+
* @param cpNode1
|
|
15
|
+
* @param cpNode2
|
|
16
|
+
* @param inclAllIfEqual if `true` and the two `CpNode`s are equal then return
|
|
17
|
+
* the entire boundary, otherwise return nothing.
|
|
16
18
|
*/
|
|
17
19
|
function getBoundaryBeziersBetween(
|
|
18
20
|
cpNode1: CpNode,
|
|
@@ -4,14 +4,15 @@ import { getMatCurveToNext } from './get-mat-curve-to-next.js';
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Returns the
|
|
7
|
+
* Returns the (flattened) array of bezier curves (lines or quadratics)
|
|
8
|
+
* representing the branch associated with the given cpNode
|
|
8
9
|
*
|
|
9
10
|
* @param cpNode `CpNode` representing the start vertex.
|
|
10
11
|
*/
|
|
11
12
|
function getBranchBeziers(
|
|
12
13
|
cpNode: CpNode): number[][][] {
|
|
13
14
|
|
|
14
|
-
return getBranch(cpNode).
|
|
15
|
+
return getBranch(cpNode).flatMap(getMatCurveToNext);
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { CpNode } from '../cp-node.js';
|
|
2
2
|
import { getRealProngCount } from './get-real-prong-count.js';
|
|
3
|
-
import { isFullyTerminating } from './is-fully-terminating.js';
|
|
4
3
|
import { isTerminating } from './is-terminating.js';
|
|
5
4
|
import { isTrivial } from './is-trivial.js';
|
|
6
5
|
|
|
@@ -34,7 +33,7 @@ function getBranch(
|
|
|
34
33
|
do {
|
|
35
34
|
branch.push(cpNode);
|
|
36
35
|
cpNode = cpNode.next;
|
|
37
|
-
} while (
|
|
36
|
+
} while (getRealProngCount(cpNode) === 2)
|
|
38
37
|
|
|
39
38
|
return branch;
|
|
40
39
|
}
|
|
@@ -7,8 +7,10 @@ import { getMatCurveToNext } from "./get-mat-curve-to-next.js";
|
|
|
7
7
|
function getMatDistanceToNext(
|
|
8
8
|
cpNode: CpNode) {
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
const
|
|
10
|
+
let l = 0;
|
|
11
|
+
for (const ps of getMatCurveToNext(cpNode)) {
|
|
12
|
+
l += totalLength(ps);
|
|
13
|
+
}
|
|
12
14
|
|
|
13
15
|
return l;
|
|
14
16
|
}
|