flo-mat 4.1.4 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/__tests__/closest-boundary-point/get-endpoint-info.spec.ts +140 -0
- package/__tests__/closest-boundary-point/root-interval-to-distance-squared-interval.spec.ts +87 -0
- package/__tests__/cp-node/circle-identity.spec.ts +56 -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/dd-get-medial-point-coeffs-same-curve.spec.ts +7 -5
- package/__tests__/find-2-prong/get-medial/dd-get-medial-point-coeffs.spec.ts +4 -2
- 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 +17882 -13800
- package/browser/index.min.js +1 -1
- package/node/add-n-prong.ts/join-spokes.js +3 -2
- package/node/add-n-prong.ts/join-spokes.js.map +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/enhance-cp-node.d.ts +9 -9
- 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.d.ts +1 -1
- package/node/cp-node/fs/get-angle-between-mat-curves.js +7 -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-edge-direction.js +3 -2
- package/node/cp-node/fs/get-edge-direction.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 +10 -2
- package/node/cp-node/fs/get-implied-boundary-bezier-between.js +11 -54
- 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 +5 -3
- package/node/cp-node/fs/get-mat-curve-between.js +6 -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 -17
- package/node/cp-node/fs/is-fully-terminating.js.map +1 -1
- package/node/cp-node/fs/is-on-same-circle.d.ts +3 -0
- package/node/cp-node/fs/is-on-same-circle.js +4 -4
- package/node/cp-node/fs/is-on-same-circle.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 +17 -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 +7 -9
- 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 +36 -42
- 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 +12 -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-closeby-cp-if-exist.js +2 -1
- package/node/mat/get-closeby-cp-if-exist.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/point-on-shape/point-on-shape.d.ts +5 -0
- 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 +16 -16
- package/qv-infinite-loop.md +120 -0
- package/src/add-n-prong.ts/join-spokes.ts +4 -2
- 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 +9 -5
- 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-edge-direction.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 +18 -70
- package/src/cp-node/fs/get-mat-curve-between.ts +10 -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 -22
- package/src/cp-node/fs/is-on-same-circle.ts +6 -7
- 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 -58
- 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 +9 -11
- 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 +15 -13
- 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-closeby-cp-if-exist.ts +3 -1
- 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/point-on-shape/point-on-shape.ts +5 -0
- 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/deg-to-rad.ts +4 -2
- package/src/utils/get-beziers-from-tangents.ts +110 -0
- package/src/utils/map-map.ts +1 -1
- package/src/utils/rad-to-deg.ts +4 -1
- package/src/vertex/remove-vertex.ts +5 -3
- package/webpack.config.cjs +7 -2
- 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,92 @@
|
|
|
1
|
+
import { fromTo, dot, cross, lineLineIntersection } from 'flo-vector2d';
|
|
2
|
+
const { abs, sqrt } = Math;
|
|
3
|
+
/**
|
|
4
|
+
* The maximum sine of the angle between the chord and either tangent for
|
|
5
|
+
* which a 'twisted' (inflected) curve is approximated by a straight line -
|
|
6
|
+
* the line then deviates from the true curve by only about a millionth of the
|
|
7
|
+
* chord length.
|
|
8
|
+
*
|
|
9
|
+
* * a relative (angle) tolerance and thus independent of the scale of the
|
|
10
|
+
* shape and of the magnitude of the given tangents
|
|
11
|
+
*
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
const SIN_TOLERANCE_USE_LINE = 2 ** -16;
|
|
15
|
+
/**
|
|
16
|
+
* Returns an array of 1 or 2 bezier curves (each a line or a quadratic) that
|
|
17
|
+
* together form a smooth curve from the start point of `l0` to the start point
|
|
18
|
+
* of `l1` such that the curve is tangent to `l0` at its start and tangent to
|
|
19
|
+
* `l1` at its end.
|
|
20
|
+
*
|
|
21
|
+
* * `l0` and `l1` are given as `[p, p + dir]` where `p` is the curve endpoint
|
|
22
|
+
* and `dir` is the tangent direction (of any magnitude; its orientation does
|
|
23
|
+
* not matter)
|
|
24
|
+
* * if the tangent lines are not 'twisted' (they meet strictly between the
|
|
25
|
+
* endpoints along the chord) a single quadratic is returned
|
|
26
|
+
* * if the tangent lines are 'twisted' (the curve must have an inflection)
|
|
27
|
+
* 2 quadratics joined smoothly at the inflection are returned as an
|
|
28
|
+
* approximation - or, if both tangents deviate from the chord by less than
|
|
29
|
+
* `SIN_TOLERANCE_USE_LINE`, a single line
|
|
30
|
+
* * if the endpoints coincide (or a tangent is degenerate) a (degenerate) line
|
|
31
|
+
* is returned
|
|
32
|
+
*
|
|
33
|
+
* FUTURE: a strongly twisted MAT edge indicates that an additional 2-prong
|
|
34
|
+
* should be added so that the edge is approximated by two less twisted ones.
|
|
35
|
+
*
|
|
36
|
+
* @param l0 the tangent line at the start of the curve
|
|
37
|
+
* @param l1 the tangent line at the end of the curve
|
|
38
|
+
*
|
|
39
|
+
* @internal
|
|
40
|
+
*/
|
|
41
|
+
function getBeziersFromTangents(l0, l1) {
|
|
42
|
+
const p0 = l0[0];
|
|
43
|
+
const p1 = l1[0];
|
|
44
|
+
const c = fromTo(p0, p1);
|
|
45
|
+
if (c[0] === 0 && c[1] === 0) {
|
|
46
|
+
return [[p0, p1]]; // coinciding endpoints - a degenerate line
|
|
47
|
+
}
|
|
48
|
+
const w0 = fromTo(l0[0], l0[1]);
|
|
49
|
+
const w1 = fromTo(l1[0], l1[1]);
|
|
50
|
+
const lc = sqrt(dot(c, c));
|
|
51
|
+
const lw0 = sqrt(dot(w0, w0));
|
|
52
|
+
const lw1 = sqrt(dot(w1, w1));
|
|
53
|
+
if (lw0 === 0 || lw1 === 0) {
|
|
54
|
+
return [[p0, p1]]; // a degenerate tangent - fall back to a line
|
|
55
|
+
}
|
|
56
|
+
const mid = lineLineIntersection(l0, l1);
|
|
57
|
+
let twisted;
|
|
58
|
+
if (!mid) {
|
|
59
|
+
twisted = true;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
const a = fromTo(p0, mid);
|
|
63
|
+
const b = fromTo(p1, mid);
|
|
64
|
+
// (`<= 0` / `>= 0`: an intersection *at* an endpoint, which happens for
|
|
65
|
+
// collinear tangents, would give a degenerate quadratic with a zero
|
|
66
|
+
// end tangent - treat it as twisted so a line results instead)
|
|
67
|
+
twisted = dot(a, c) <= 0 || dot(b, c) >= 0;
|
|
68
|
+
}
|
|
69
|
+
if (!twisted) {
|
|
70
|
+
return [[p0, mid, p1]];
|
|
71
|
+
}
|
|
72
|
+
// the sines of the angles between the chord and the tangents
|
|
73
|
+
const sin0 = abs(cross(c, w0)) / (lc * lw0);
|
|
74
|
+
const sin1 = abs(cross(c, w1)) / (lc * lw1);
|
|
75
|
+
if (sin0 <= SIN_TOLERANCE_USE_LINE && sin1 <= SIN_TOLERANCE_USE_LINE) {
|
|
76
|
+
return [[p0, p1]]; // within tolerance - a straight line
|
|
77
|
+
}
|
|
78
|
+
// Approximate with 2 quadratic beziers joined smoothly at the inflection.
|
|
79
|
+
// The control points lie on the tangent lines a quarter of the chord
|
|
80
|
+
// length away from the endpoints, on the side facing the other endpoint
|
|
81
|
+
// (for small angles this is the midpoint degree reduction of the cubic
|
|
82
|
+
// having control points at 1/3 and 2/3 along the chord; unlike placing
|
|
83
|
+
// them at 1/4 and 3/4 *along* the chord it stays bounded for any angle).
|
|
84
|
+
const q0 = (dot(w0, c) < 0 ? -1 : 1) * lc / (4 * lw0);
|
|
85
|
+
const q1 = (dot(w1, c) < 0 ? 1 : -1) * lc / (4 * lw1);
|
|
86
|
+
const c0 = [p0[0] + q0 * w0[0], p0[1] + q0 * w0[1]];
|
|
87
|
+
const c1 = [p1[0] + q1 * w1[0], p1[1] + q1 * w1[1]];
|
|
88
|
+
const j = [(c0[0] + c1[0]) / 2, (c0[1] + c1[1]) / 2];
|
|
89
|
+
return [[p0, c0, j], [j, c1, p1]];
|
|
90
|
+
}
|
|
91
|
+
export { getBeziersFromTangents };
|
|
92
|
+
//# sourceMappingURL=get-beziers-from-tangents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-beziers-from-tangents.js","sourceRoot":"","sources":["../../src/utils/get-beziers-from-tangents.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { CpNode } from "../cp-node/cp-node.js";
|
|
2
2
|
import type { MatMeta } from '../mat/mat-meta.js';
|
|
3
3
|
/**
|
|
4
|
-
* Removes
|
|
4
|
+
* Removes the (2-prong) vertex represented by the given `CpNode` from the MAT,
|
|
5
|
+
* i.e. both `CpNode`s on its circle are unlinked from the boundary and removed
|
|
6
|
+
* from `meta.cpTrees`.
|
|
5
7
|
*
|
|
6
|
-
* @param
|
|
7
|
-
* @param
|
|
8
|
+
* @param cpNode a `CpNode` on the vertex to remove
|
|
9
|
+
* @param meta the `MatMeta` whose `cpTrees` hold the `CpNode`s of the MAT
|
|
8
10
|
*/
|
|
9
11
|
declare function removeVertex(cpNode: CpNode, meta: MatMeta): void;
|
|
10
12
|
export { removeVertex };
|
|
@@ -2,10 +2,12 @@ import { getAllOnCircle } from '../cp-node/fs/get-all-on-circle.js';
|
|
|
2
2
|
import { getProngCount } from '../cp-node/fs/get-prong-count.js';
|
|
3
3
|
import { removeCpNode } from '../cp-node/fs/remove-cp-node.js';
|
|
4
4
|
/**
|
|
5
|
-
* Removes
|
|
5
|
+
* Removes the (2-prong) vertex represented by the given `CpNode` from the MAT,
|
|
6
|
+
* i.e. both `CpNode`s on its circle are unlinked from the boundary and removed
|
|
7
|
+
* from `meta.cpTrees`.
|
|
6
8
|
*
|
|
7
|
-
* @param
|
|
8
|
-
* @param
|
|
9
|
+
* @param cpNode a `CpNode` on the vertex to remove
|
|
10
|
+
* @param meta the `MatMeta` whose `cpTrees` hold the `CpNode`s of the MAT
|
|
9
11
|
*/
|
|
10
12
|
function removeVertex(cpNode, meta) {
|
|
11
13
|
const prongCount = getProngCount(cpNode);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remove-vertex.js","sourceRoot":"","sources":["../../src/vertex/remove-vertex.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAG/D
|
|
1
|
+
{"version":3,"file":"remove-vertex.js","sourceRoot":"","sources":["../../src/vertex/remove-vertex.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAG/D;;;;;;;GAOG;AACH,SAAS,YAAY,CACb,MAAc,EACd,IAAa;IAEjB,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACzC,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,+BAA+B,UAAU,QAAQ,CAAC,CAAA;IACtE,CAAC;IAED,cAAc,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;AACzE,CAAC;AAGD,OAAO,EAAE,YAAY,EAAE,CAAA"}
|
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.1",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Floris Steenkamp"
|
|
8
8
|
},
|
|
@@ -32,32 +32,32 @@
|
|
|
32
32
|
],
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"big-float-ts": "^4.0.4",
|
|
35
|
-
"double-double": "^
|
|
36
|
-
"flo-bezier3": "^
|
|
37
|
-
"flo-boolean": "^6.0.
|
|
35
|
+
"double-double": "^4.0.0",
|
|
36
|
+
"flo-bezier3": "^9.0.0",
|
|
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.0",
|
|
42
42
|
"flo-vector2d": "^4.0.6"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"
|
|
46
|
-
"@
|
|
47
|
-
"@swc/core": "^1.16.2",
|
|
45
|
+
"@jest/globals": "^30.5.2",
|
|
46
|
+
"@swc/core": "^1.16.18",
|
|
48
47
|
"@swc/jest": "^0.2.39",
|
|
49
48
|
"@types/jest": "^30.0.0",
|
|
50
|
-
"
|
|
51
|
-
"jest-ts-webcompat-resolver": "^1.0.1",
|
|
52
|
-
"ts-node": "^10.9.2",
|
|
53
|
-
"@types/node": "^26.6.0",
|
|
49
|
+
"@types/node": "^26.6.5",
|
|
54
50
|
"c8": "^12.0.0",
|
|
55
51
|
"cheerio": "^1.2.0",
|
|
56
52
|
"circular-dependency-plugin": "^5.2.2",
|
|
53
|
+
"jest": "^30.5.2",
|
|
54
|
+
"jest-ts-webcompat-resolver": "^1.0.1",
|
|
57
55
|
"rimraf": "^6.1.3",
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
56
|
+
"squares-rng": "^2.0.4",
|
|
57
|
+
"swc-loader": "^0.2.7",
|
|
58
|
+
"ts-node": "^10.9.2",
|
|
59
|
+
"typescript": "^7.0.2",
|
|
60
|
+
"webpack": "^5.111.1",
|
|
61
61
|
"webpack-cli": "^7.2.3"
|
|
62
62
|
},
|
|
63
63
|
"scripts": {
|
|
@@ -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.
|
|
@@ -2,6 +2,8 @@ import type { CpNode } from "../cp-node/cp-node.js";
|
|
|
2
2
|
import type { Circle } from "../geometry/circle.js";
|
|
3
3
|
import type { Mutable } from "../utils/mutable.js";
|
|
4
4
|
|
|
5
|
+
const { atan2 } = Math;
|
|
6
|
+
|
|
5
7
|
|
|
6
8
|
function joinSpokes(
|
|
7
9
|
circle: Circle,
|
|
@@ -30,8 +32,8 @@ function byAngle(circle: Circle) {
|
|
|
30
32
|
a = [a[0] - c[0], a[1] - c[1]];
|
|
31
33
|
b = [b[0] - c[0], b[1] - c[1]];
|
|
32
34
|
|
|
33
|
-
const a_ =
|
|
34
|
-
const b_ =
|
|
35
|
+
const a_ = atan2(a[1], a[0]);
|
|
36
|
+
const b_ = atan2(b[1], b[0]);
|
|
35
37
|
|
|
36
38
|
return b_ - a_;
|
|
37
39
|
}
|
|
@@ -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
|
}
|