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.
Files changed (356) hide show
  1. package/__tests__/closest-boundary-point/get-endpoint-info.spec.ts +140 -0
  2. package/__tests__/closest-boundary-point/root-interval-to-distance-squared-interval.spec.ts +87 -0
  3. package/__tests__/cp-node/fs/get-all-on-loop-by-loop.spec.ts +55 -0
  4. package/__tests__/cp-node/fs/get-angle-between-mat-curves.spec.ts +39 -3
  5. package/__tests__/cp-node/fs/get-boundary-bezier-parts-to-next.spec.ts +87 -3
  6. package/__tests__/cp-node/fs/get-boundary-beziers-between.spec.ts +68 -3
  7. package/__tests__/cp-node/fs/get-boundary-beziers-to-next.spec.ts +41 -3
  8. package/__tests__/cp-node/fs/get-boundary-distance-to-next.spec.ts +20 -3
  9. package/__tests__/cp-node/fs/get-branch-beziers.spec.ts +42 -3
  10. package/__tests__/cp-node/fs/get-branch.spec.ts +60 -3
  11. package/__tests__/cp-node/fs/get-cp-node-ordering.spec.ts +19 -3
  12. package/__tests__/cp-node/fs/get-distance-to-next.spec.ts +37 -4
  13. package/__tests__/cp-node/fs/get-edge-direction.spec.ts +50 -3
  14. package/__tests__/cp-node/fs/get-first-exit.spec.ts +78 -3
  15. package/__tests__/cp-node/fs/get-hole-closers.spec.ts +32 -3
  16. package/__tests__/cp-node/fs/get-implied-boundary-bezier-between.spec.ts +48 -3
  17. package/__tests__/cp-node/fs/get-mat-curve-between.spec.ts +77 -3
  18. package/__tests__/cp-node/fs/get-mat-curve-to-next.spec.ts +17 -4
  19. package/__tests__/cp-node/fs/get-mat-curves-between.spec.ts +38 -3
  20. package/__tests__/cp-node/fs/get-salience.spec.ts +68 -3
  21. package/__tests__/cp-node/fs/get-vertex-forward-children.spec.ts +40 -3
  22. package/__tests__/cp-node/fs/insert-cp-node.spec.ts +87 -3
  23. package/__tests__/cp-node/fs/is-special.spec.ts +1 -1
  24. package/__tests__/cp-node/fs/remove-cp-node.spec.ts +42 -3
  25. package/__tests__/find-2-prong/calc-seperation-tolerance.spec.ts +46 -0
  26. package/__tests__/find-2-prong/get-medial/get-closest-points.spec.ts +1 -1
  27. package/__tests__/floyd-warshall/get-graph.spec.ts +100 -0
  28. package/__tests__/get-mats-with-hole.ts +28 -0
  29. package/__tests__/get-mats1.spec.ts +61 -0
  30. package/__tests__/get-mats1.ts +75 -67
  31. package/__tests__/helpers/cp-node-by-id.ts +27 -0
  32. package/__tests__/helpers/expect-point-close.ts +42 -0
  33. package/__tests__/mat/hausdorff-distance-one-sided-exceeds.spec.ts +129 -0
  34. package/__tests__/mat/simplify-mat.spec.ts +85 -0
  35. package/__tests__/reconstruct-from-mat/reconstruct-from-mat.spec.ts +39 -0
  36. package/__tests__/specific-cases/test-svgs/achispado.svg +14 -0
  37. package/__tests__/utils/get-beziers-from-tangents.spec.ts +142 -0
  38. package/browser/index.js +12985 -9965
  39. package/browser/index.min.js +1 -1
  40. package/node/closest-boundary-point/cull-curve-pieces.d.ts +21 -0
  41. package/node/closest-boundary-point/cull-curve-pieces.js +40 -0
  42. package/node/closest-boundary-point/cull-curve-pieces.js.map +1 -0
  43. package/node/closest-boundary-point/get-close-boundary-points-certified.js +5 -2
  44. package/node/closest-boundary-point/get-close-boundary-points-certified.js.map +1 -1
  45. package/node/closest-boundary-point/get-endpoint-info.d.ts +39 -0
  46. package/node/closest-boundary-point/get-endpoint-info.js +78 -0
  47. package/node/closest-boundary-point/get-endpoint-info.js.map +1 -0
  48. package/node/closest-boundary-point/get-potential-closest-points-on-curve-certified.js +5 -19
  49. package/node/closest-boundary-point/get-potential-closest-points-on-curve-certified.js.map +1 -1
  50. package/node/closest-boundary-point/root-interval-to-distance-squared-interval.d.ts +17 -5
  51. package/node/closest-boundary-point/root-interval-to-distance-squared-interval.js +37 -50
  52. package/node/closest-boundary-point/root-interval-to-distance-squared-interval.js.map +1 -1
  53. package/node/corner/get-corner.d.ts +18 -1
  54. package/node/corner/get-corner.js +8 -1
  55. package/node/corner/get-corner.js.map +1 -1
  56. package/node/corner/get-interface-ccw.js.map +1 -1
  57. package/node/cp-node/cp-node.d.ts +4 -3
  58. package/node/cp-node/fs/get-all-on-loop-by-loop.js +0 -4
  59. package/node/cp-node/fs/get-all-on-loop-by-loop.js.map +1 -1
  60. package/node/cp-node/fs/get-angle-between-mat-curves.js +6 -4
  61. package/node/cp-node/fs/get-angle-between-mat-curves.js.map +1 -1
  62. package/node/cp-node/fs/get-boundary-beziers-between.d.ts +6 -4
  63. package/node/cp-node/fs/get-boundary-beziers-between.js +6 -4
  64. package/node/cp-node/fs/get-boundary-beziers-between.js.map +1 -1
  65. package/node/cp-node/fs/get-branch-beziers.d.ts +2 -1
  66. package/node/cp-node/fs/get-branch-beziers.js +3 -2
  67. package/node/cp-node/fs/get-branch-beziers.js.map +1 -1
  68. package/node/cp-node/fs/get-branch.js +1 -2
  69. package/node/cp-node/fs/get-branch.js.map +1 -1
  70. package/node/cp-node/fs/get-distance-to-next.js +4 -2
  71. package/node/cp-node/fs/get-distance-to-next.js.map +1 -1
  72. package/node/cp-node/fs/get-first-exit.d.ts +7 -3
  73. package/node/cp-node/fs/get-first-exit.js +13 -11
  74. package/node/cp-node/fs/get-first-exit.js.map +1 -1
  75. package/node/cp-node/fs/get-implied-boundary-bezier-between.d.ts +9 -1
  76. package/node/cp-node/fs/get-implied-boundary-bezier-between.js +11 -55
  77. package/node/cp-node/fs/get-implied-boundary-bezier-between.js.map +1 -1
  78. package/node/cp-node/fs/get-mat-curve-between.d.ts +4 -3
  79. package/node/cp-node/fs/get-mat-curve-between.js +5 -49
  80. package/node/cp-node/fs/get-mat-curve-between.js.map +1 -1
  81. package/node/cp-node/fs/get-mat-curve-to-next.d.ts +1 -1
  82. package/node/cp-node/fs/get-mat-curves-between.d.ts +8 -0
  83. package/node/cp-node/fs/get-mat-curves-between.js +9 -2
  84. package/node/cp-node/fs/get-mat-curves-between.js.map +1 -1
  85. package/node/cp-node/fs/get-real-prong-count.d.ts +2 -1
  86. package/node/cp-node/fs/get-real-prong-count.js +11 -5
  87. package/node/cp-node/fs/get-real-prong-count.js.map +1 -1
  88. package/node/cp-node/fs/get-salience.d.ts +10 -0
  89. package/node/cp-node/fs/get-salience.js +17 -1
  90. package/node/cp-node/fs/get-salience.js.map +1 -1
  91. package/node/cp-node/fs/is-fully-terminating.d.ts +4 -2
  92. package/node/cp-node/fs/is-fully-terminating.js +6 -15
  93. package/node/cp-node/fs/is-fully-terminating.js.map +1 -1
  94. package/node/cp-node/fs/is-on-same-loop.d.ts +1 -1
  95. package/node/cp-node/fs/is-special.d.ts +7 -0
  96. package/node/cp-node/fs/is-special.js +9 -2
  97. package/node/cp-node/fs/is-special.js.map +1 -1
  98. package/node/cp-node/fs/is-vertex.d.ts +1 -1
  99. package/node/cp-node/fs/traverse-edges.d.ts +7 -3
  100. package/node/cp-node/fs/traverse-edges.js +7 -3
  101. package/node/cp-node/fs/traverse-edges.js.map +1 -1
  102. package/node/cp-node/stringification/from-stringifyable.d.ts +2 -2
  103. package/node/cp-node/stringification/from-stringifyable.js +1 -1
  104. package/node/cp-node/stringification/from-stringifyable.js.map +1 -1
  105. package/node/cp-node/stringification/to-stringifyable.d.ts +3 -3
  106. package/node/cp-node/stringification/to-stringifyable.js +3 -3
  107. package/node/debug/debug.d.ts +26 -3
  108. package/node/debug/debug.js +16 -5
  109. package/node/debug/debug.js.map +1 -1
  110. package/node/find-2-prong/add-2-prong.js +1 -7
  111. package/node/find-2-prong/add-2-prong.js.map +1 -1
  112. package/node/find-2-prong/calc-seperation-tolerance.d.ts +28 -5
  113. package/node/find-2-prong/calc-seperation-tolerance.js +32 -89
  114. package/node/find-2-prong/calc-seperation-tolerance.js.map +1 -1
  115. package/node/find-2-prong/find-2-prong.js +8 -10
  116. package/node/find-2-prong/find-2-prong.js.map +1 -1
  117. package/node/find-2-prong/find-and-add-2-prongs.js +2 -2
  118. package/node/find-2-prong/find-and-add-2-prongs.js.map +1 -1
  119. package/node/find-2-prong/get-medial/get-antipodal-points.d.ts +1 -2
  120. package/node/find-2-prong/get-medial/get-antipodal-points.js +2 -3
  121. package/node/find-2-prong/get-medial/get-antipodal-points.js.map +1 -1
  122. package/node/find-2-prong/get-medial/get-closest-points.d.ts +1 -8
  123. package/node/find-2-prong/get-medial/get-closest-points.js +4 -40
  124. package/node/find-2-prong/get-medial/get-closest-points.js.map +1 -1
  125. package/node/find-2-prong/reduce-radius.d.ts +1 -1
  126. package/node/find-2-prong/reduce-radius.js +6 -3
  127. package/node/find-2-prong/reduce-radius.js.map +1 -1
  128. package/node/find-3-prong/calc-better-x.js +1 -1
  129. package/node/find-3-prong/calc-better-x.js.map +1 -1
  130. package/node/find-3-prong/find-3-prong-for-delta3s.d.ts +3 -2
  131. package/node/find-3-prong/find-3-prong-for-delta3s.js +35 -41
  132. package/node/find-3-prong/find-3-prong-for-delta3s.js.map +1 -1
  133. package/node/find-3-prong/find-3-prong.js +3 -1
  134. package/node/find-3-prong/find-3-prong.js.map +1 -1
  135. package/node/find-3-prong/find-and-add-3-prongs.js +16 -0
  136. package/node/find-3-prong/find-and-add-3-prongs.js.map +1 -1
  137. package/node/find-mat/create-initial-cp-tree.js +2 -2
  138. package/node/find-mat/create-initial-cp-tree.js.map +1 -1
  139. package/node/find-mat/find-mat.js +3 -4
  140. package/node/find-mat/find-mat.js.map +1 -1
  141. package/node/find-mat/find-mats.d.ts +6 -12
  142. package/node/find-mat/find-mats.js +10 -27
  143. package/node/find-mat/find-mats.js.map +1 -1
  144. package/node/find-mat/get-dull-corners-on-loop.js +2 -2
  145. package/node/find-mat/get-dull-corners-on-loop.js.map +1 -1
  146. package/node/find-mat/get-for-1-prongs-on-loop.js +36 -8
  147. package/node/find-mat/get-for-1-prongs-on-loop.js.map +1 -1
  148. package/node/find-mat/get-meta.d.ts +14 -4
  149. package/node/find-mat/get-meta.js +30 -24
  150. package/node/find-mat/get-meta.js.map +1 -1
  151. package/node/find-mat/get-sharp-corners.js +2 -2
  152. package/node/find-mat/get-sharp-corners.js.map +1 -1
  153. package/node/find-mat/mat-options.d.ts +2 -2
  154. package/node/floyd-warshall/get-graph.d.ts +12 -1
  155. package/node/floyd-warshall/get-graph.js +41 -38
  156. package/node/floyd-warshall/get-graph.js.map +1 -1
  157. package/node/geometry/get-bounding-box-.d.ts +16 -2
  158. package/node/geometry/get-bounding-box-.js +5 -2
  159. package/node/geometry/get-bounding-box-.js.map +1 -1
  160. package/node/geometry/get-closest-square-distance-to-rect.d.ts +3 -0
  161. package/node/geometry/get-closest-square-distance-to-rect.js +7 -5
  162. package/node/geometry/get-closest-square-distance-to-rect.js.map +1 -1
  163. package/node/geometry/get-closest-squared-distance-to-rotated-rect.d.ts +4 -0
  164. package/node/geometry/get-closest-squared-distance-to-rotated-rect.js +11 -5
  165. package/node/geometry/get-closest-squared-distance-to-rotated-rect.js.map +1 -1
  166. package/node/get-medial-points/double-double/dd-get-medial-point-coeffs-bez3.js +1 -2
  167. package/node/get-medial-points/double-double/dd-get-medial-point-coeffs-bez3.js.map +1 -1
  168. package/node/index.d.ts +3 -2
  169. package/node/index.js +2 -1
  170. package/node/index.js.map +1 -1
  171. package/node/mat/clone-mat.d.ts +9 -0
  172. package/node/mat/clone-mat.js +17 -0
  173. package/node/mat/clone-mat.js.map +1 -0
  174. package/node/mat/clone-meta.d.ts +12 -0
  175. package/node/mat/clone-meta.js +24 -0
  176. package/node/mat/clone-meta.js.map +1 -0
  177. package/node/mat/get-boundary-piece-beziers.d.ts +5 -0
  178. package/node/mat/get-boundary-piece-beziers.js +7 -93
  179. package/node/mat/get-boundary-piece-beziers.js.map +1 -1
  180. package/node/mat/get-largest-3-prong.d.ts +6 -0
  181. package/node/mat/get-largest-3-prong.js +8 -5
  182. package/node/mat/get-largest-3-prong.js.map +1 -1
  183. package/node/mat/get-largest-vertex.d.ts +15 -1
  184. package/node/mat/get-largest-vertex.js +20 -7
  185. package/node/mat/get-largest-vertex.js.map +1 -1
  186. package/node/mat/hausdorff-distance-one-sided-exceeds.d.ts +79 -0
  187. package/node/mat/hausdorff-distance-one-sided-exceeds.js +251 -0
  188. package/node/mat/hausdorff-distance-one-sided-exceeds.js.map +1 -0
  189. package/node/mat/mat-meta.d.ts +0 -6
  190. package/node/mat/simplify-mat.d.ts +25 -8
  191. package/node/mat/simplify-mat.js +182 -53
  192. package/node/mat/simplify-mat.js.map +1 -1
  193. package/node/mat/trim-mat.d.ts +4 -2
  194. package/node/mat/trim-mat.js +3 -1
  195. package/node/mat/trim-mat.js.map +1 -1
  196. package/node/point-on-shape/get-boundary-tangent-line.d.ts +19 -0
  197. package/node/point-on-shape/get-boundary-tangent-line.js +33 -0
  198. package/node/point-on-shape/get-boundary-tangent-line.js.map +1 -0
  199. package/node/point-on-shape/get-osculating-circle.d.ts +6 -4
  200. package/node/point-on-shape/get-osculating-circle.js +6 -4
  201. package/node/point-on-shape/get-osculating-circle.js.map +1 -1
  202. package/node/point-on-shape/get-pos-corner.js +2 -2
  203. package/node/point-on-shape/get-pos-corner.js.map +1 -1
  204. package/node/reconstruct-from-mat/reconstruct-from-mat.js +20 -80
  205. package/node/reconstruct-from-mat/reconstruct-from-mat.js.map +1 -1
  206. package/node/reconstruct-from-mat/remove-sat-induced-trivial-3prongs.d.ts +4 -0
  207. package/node/reconstruct-from-mat/remove-sat-induced-trivial-3prongs.js +4 -0
  208. package/node/reconstruct-from-mat/remove-sat-induced-trivial-3prongs.js.map +1 -1
  209. package/node/sat/cull.d.ts +7 -6
  210. package/node/sat/cull.js +13 -16
  211. package/node/sat/cull.js.map +1 -1
  212. package/node/sat/get-sat-culls.d.ts +12 -2
  213. package/node/sat/get-sat-culls.js +21 -16
  214. package/node/sat/get-sat-culls.js.map +1 -1
  215. package/node/svg/get-shape-bounds.d.ts +1 -12
  216. package/node/svg/get-shape-bounds.js +2 -3
  217. package/node/svg/get-shape-bounds.js.map +1 -1
  218. package/node/sweep-line/sweep-line.js.map +1 -1
  219. package/node/utils/get-beziers-from-tangents.d.ts +28 -0
  220. package/node/utils/get-beziers-from-tangents.js +92 -0
  221. package/node/utils/get-beziers-from-tangents.js.map +1 -0
  222. package/node/vertex/remove-vertex.d.ts +5 -3
  223. package/node/vertex/remove-vertex.js +5 -3
  224. package/node/vertex/remove-vertex.js.map +1 -1
  225. package/package.json +9 -9
  226. package/qv-infinite-loop.md +120 -0
  227. package/src/closest-boundary-point/cull-curve-pieces.ts +49 -0
  228. package/src/closest-boundary-point/get-close-boundary-points-certified.ts +5 -2
  229. package/src/closest-boundary-point/get-endpoint-info.ts +96 -0
  230. package/src/closest-boundary-point/get-potential-closest-points-on-curve-certified.ts +5 -23
  231. package/src/closest-boundary-point/root-interval-to-distance-squared-interval.ts +42 -60
  232. package/src/corner/get-corner.ts +10 -1
  233. package/src/corner/get-interface-ccw.ts +2 -2
  234. package/src/cp-node/cp-node.ts +4 -3
  235. package/src/cp-node/fs/get-all-on-loop-by-loop.ts +0 -4
  236. package/src/cp-node/fs/get-angle-between-mat-curves.ts +6 -4
  237. package/src/cp-node/fs/get-boundary-beziers-between.ts +10 -8
  238. package/src/cp-node/fs/get-branch-beziers.ts +3 -2
  239. package/src/cp-node/fs/get-branch.ts +1 -2
  240. package/src/cp-node/fs/get-distance-to-next.ts +4 -2
  241. package/src/cp-node/fs/get-first-exit.ts +15 -14
  242. package/src/cp-node/fs/get-implied-boundary-bezier-between.ts +17 -69
  243. package/src/cp-node/fs/get-mat-curve-between.ts +9 -67
  244. package/src/cp-node/fs/get-mat-curves-between.ts +9 -2
  245. package/src/cp-node/fs/get-real-prong-count.ts +11 -7
  246. package/src/cp-node/fs/get-salience.ts +15 -2
  247. package/src/cp-node/fs/is-fully-terminating.ts +6 -18
  248. package/src/cp-node/fs/is-on-same-loop.ts +2 -2
  249. package/src/cp-node/fs/is-special.ts +11 -6
  250. package/src/cp-node/fs/is-vertex.ts +1 -1
  251. package/src/cp-node/fs/traverse-edges.ts +8 -4
  252. package/src/cp-node/stringification/from-stringifyable.ts +75 -75
  253. package/src/cp-node/stringification/to-stringifyable.ts +3 -3
  254. package/src/debug/debug.ts +44 -8
  255. package/src/find-2-prong/add-2-prong.ts +2 -9
  256. package/src/find-2-prong/calc-seperation-tolerance.ts +34 -115
  257. package/src/find-2-prong/find-2-prong.ts +9 -11
  258. package/src/find-2-prong/find-and-add-2-prongs.ts +2 -2
  259. package/src/find-2-prong/get-medial/get-antipodal-points.ts +1 -3
  260. package/src/find-2-prong/get-medial/get-closest-points.ts +6 -51
  261. package/src/find-2-prong/reduce-radius.ts +6 -4
  262. package/src/find-3-prong/calc-better-x.ts +2 -2
  263. package/src/find-3-prong/find-3-prong-for-delta3s.ts +197 -214
  264. package/src/find-3-prong/find-3-prong.ts +54 -51
  265. package/src/find-3-prong/find-and-add-3-prongs.ts +20 -1
  266. package/src/find-mat/create-initial-cp-tree.ts +2 -2
  267. package/src/find-mat/find-mat.ts +4 -6
  268. package/src/find-mat/find-mats.ts +83 -105
  269. package/src/find-mat/get-dull-corners-on-loop.ts +2 -2
  270. package/src/find-mat/get-for-1-prongs-on-loop.ts +40 -8
  271. package/src/find-mat/get-meta.ts +34 -39
  272. package/src/find-mat/get-sharp-corners.ts +2 -2
  273. package/src/find-mat/mat-options.ts +2 -2
  274. package/src/floyd-warshall/get-graph.ts +46 -47
  275. package/src/geometry/get-bounding-box-.ts +5 -2
  276. package/src/geometry/get-closest-square-distance-to-rect.ts +7 -7
  277. package/src/geometry/get-closest-squared-distance-to-rotated-rect.ts +12 -10
  278. package/src/get-medial-points/double-double/dd-get-medial-point-coeffs-bez3.ts +1 -2
  279. package/src/index.ts +3 -2
  280. package/src/mat/clone-mat.ts +9 -3
  281. package/src/mat/clone-meta.ts +8 -0
  282. package/src/mat/get-boundary-piece-beziers.ts +16 -117
  283. package/src/mat/get-largest-3-prong.ts +9 -6
  284. package/src/mat/get-largest-vertex.ts +25 -9
  285. package/src/mat/hausdorff-distance-one-sided-exceeds.ts +314 -0
  286. package/src/mat/mat-meta.ts +0 -9
  287. package/src/mat/simplify-mat.ts +254 -116
  288. package/src/mat/trim-mat.ts +6 -4
  289. package/src/point-on-shape/get-boundary-tangent-line.ts +36 -0
  290. package/src/point-on-shape/get-osculating-circle.ts +7 -5
  291. package/src/point-on-shape/get-pos-corner.ts +2 -2
  292. package/src/reconstruct-from-mat/reconstruct-from-mat.ts +22 -111
  293. package/src/reconstruct-from-mat/remove-sat-induced-trivial-3prongs.ts +4 -0
  294. package/src/sat/cull.ts +16 -20
  295. package/src/sat/get-sat-culls.ts +28 -23
  296. package/src/svg/get-shape-bounds.ts +2 -3
  297. package/src/sweep-line/sweep-line.ts +1 -1
  298. package/src/utils/get-beziers-from-tangents.ts +110 -0
  299. package/src/utils/map-map.ts +1 -1
  300. package/src/vertex/remove-vertex.ts +5 -3
  301. package/__tests__/cp-node/fs/get-distance-between.spec.ts +0 -7
  302. package/__tests__/cp-node/fs/get-terminating-on-circle.spec.ts +0 -24
  303. package/__tests__/cp-node/fs/is-single-3-prong.spec.ts +0 -17
  304. package/__tests__/cp-node/fs/iterate-all-on-loop.spec.ts +0 -17
  305. package/__tests__/cp-node/fs/traverse-all-forward.spec.ts +0 -14
  306. package/node/closest-boundary-point/cull-bezier-pieces-1.d.ts +0 -9
  307. package/node/closest-boundary-point/cull-bezier-pieces-1.js +0 -17
  308. package/node/closest-boundary-point/cull-bezier-pieces-1.js.map +0 -1
  309. package/node/closest-boundary-point/cull-by-loose-bounding-box.d.ts +0 -13
  310. package/node/closest-boundary-point/cull-by-loose-bounding-box.js +0 -27
  311. package/node/closest-boundary-point/cull-by-loose-bounding-box.js.map +0 -1
  312. package/node/closest-boundary-point/cull-by-tight-boundary-box.d.ts +0 -11
  313. package/node/closest-boundary-point/cull-by-tight-boundary-box.js +0 -27
  314. package/node/closest-boundary-point/cull-by-tight-boundary-box.js.map +0 -1
  315. package/node/cp-node/fs/find-first.d.ts +0 -10
  316. package/node/cp-node/fs/find-first.js +0 -19
  317. package/node/cp-node/fs/find-first.js.map +0 -1
  318. package/node/debug/functions/check-ordering.d.ts +0 -4
  319. package/node/debug/functions/check-ordering.js +0 -43
  320. package/node/debug/functions/check-ordering.js.map +0 -1
  321. package/node/find-2-prong/cull-bezier-pieces.d.ts +0 -13
  322. package/node/find-2-prong/cull-bezier-pieces.js +0 -43
  323. package/node/find-2-prong/cull-bezier-pieces.js.map +0 -1
  324. package/node/floyd-warshall/get-hole-closer-pairs.d.ts +0 -8
  325. package/node/floyd-warshall/get-hole-closer-pairs.js +0 -27
  326. package/node/floyd-warshall/get-hole-closer-pairs.js.map +0 -1
  327. package/node/utils/dual-set.d.ts +0 -27
  328. package/node/utils/dual-set.js +0 -55
  329. package/node/utils/dual-set.js.map +0 -1
  330. package/node/utils/tri-map.d.ts +0 -27
  331. package/node/utils/tri-map.js +0 -49
  332. package/node/utils/tri-map.js.map +0 -1
  333. package/src/closest-boundary-point/cull-bezier-pieces-1.ts +0 -36
  334. package/src/closest-boundary-point/cull-by-loose-bounding-box.ts +0 -42
  335. package/src/closest-boundary-point/cull-by-tight-boundary-box.ts +0 -43
  336. package/src/closest-boundary-point/get-p-from-box.ts +0 -14
  337. package/src/cp-node/fs/add-distance-from.ts +0 -49
  338. package/src/cp-node/fs/get-distance-between.ts +0 -16
  339. package/src/cp-node/fs/get-terminating-on-circle.ts +0 -24
  340. package/src/cp-node/fs/is-single-3-prong.ts +0 -15
  341. package/src/cp-node/fs/iterate-all-on-loop.ts +0 -15
  342. package/src/cp-node/fs/traverse-all-forward.ts +0 -24
  343. package/src/debug/functions/draw/draw-beziers-as-single-path.ts +0 -40
  344. package/src/debug/functions/draw/draw-disk.ts +0 -34
  345. package/src/debug/functions/draw/xmlns.ts +0 -5
  346. package/src/find-2-prong/cull-bezier-pieces.ts +0 -61
  347. package/src/find-2-prong/find-and-add-2-prong.ts +0 -30
  348. package/src/find-2-prong/get-medial/get-closest-points-d.ts +0 -213
  349. package/src/find-2-prong/x-for-debugging.ts +0 -13
  350. package/src/floyd-warshall/get-hole-closer-pairs.ts +0 -35
  351. package/src/mat/get-two-prong-type.ts +0 -13
  352. package/src/point-on-shape/is-pos-dull-corner.ts +0 -18
  353. package/src/point-on-shape/is-pos-quite-dull-corner.ts +0 -18
  354. package/src/point-on-shape/is-pos-quite-sharp-corner.ts +0 -18
  355. package/src/point-on-shape/pos-to-human-string.ts +0 -18
  356. 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": "4.1.5",
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.4",
35
- "double-double": "^3.0.4",
36
- "flo-bezier3": "^8.1.1",
37
- "flo-boolean": "^6.0.2",
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": "^8.1.4",
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.13",
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.4",
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.13": true
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 { cullCurvePieces1 } from './cull-bezier-pieces-1.js';
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
- curvePieces = cullCurvePieces1(curvePieces, x);
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 { evalDeCasteljauDd, getFootPointsOnBezierPolysCertified, getIntervalBox } from 'flo-bezier3';
4
+ import { getFootPointsOnBezierPolysCertified, getIntervalBox } from 'flo-bezier3';
5
5
  import { rootIntervalToDistanceSquaredInterval } from './root-interval-to-distance-squared-interval.js';
6
- import { squaredDistanceBetweenDd } from "../find-2-prong/squared-distance-between-dd.js";
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
- const ts = tRange.slice();
54
- if (tS === tE) {
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
- return {
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 { twoDiff, ddMultDd, ddAddDd } from 'double-double';
1
+ import { eps } from '../error-analysis/gamma.js';
2
2
 
3
- const td = twoDiff;
4
- const qmq = ddMultDd;
5
- const qaq = ddAddDd;
3
+ const { max } = Math;
6
4
 
7
- const eps = Number.EPSILON;
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 the distance interval squared given the root interval (currently
12
- * ignoring multiplicity).
13
- *
14
- * * the result is returned as `[minPossibleSquared, maxPossibleSquared]` distance.
15
- *
16
- * @param box
17
- * @param p
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
- /** distance to 1st corner of interval box - `distance² = x² + y²` */
51
- const ax = td(a,x); // a - x
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
- // const dc1Min = dc1*(1 - 2**maxCoordPowerOf2*eps); // distance minus max error
59
- // const dc1Max = dc1*(1 + 2**maxCoordPowerOf2*eps); // distance plus max error
60
- const dc1Min = dc1*(1 - eps); // distance minus max error
61
- const dc1Max = dc1*(1 + eps); // distance plus max error
62
-
63
- if (dc1Min <= minDSquared) {
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
- if (dc1Max >= maxDSquared) {
68
- maxDSquared = dc1Max;
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
 
@@ -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
- export { getCorner }
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, eCompress, eEstimate, eMult, eNegativeOf, eProduct, orient2d, twoDiff } from 'big-float-ts';
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 }
@@ -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 a bezier curve
30
- * from the maximal disk of this `CpNode` to the next `CpNode`'s
31
- * maximal disk and thus directly representing a piece of the medial axis.
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
- const cross_ = cross(tan1, tan2);
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 all `CpNode`s between the two given ones (inclusive).
8
- *
9
- * * If the second `CpNode` is never encountered all on the loop will be
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 first and last `CpNode`s are equal then
15
- * include all `CpNode`s around the loop, otherwise include none.
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 branch associated with the give cpNode
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).map(b => getMatCurveToNext(b));
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 (!isFullyTerminating(cpNode) && getRealProngCount(cpNode) === 2)
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
- const ps = getMatCurveToNext(cpNode);
11
- const l = totalLength(ps);
10
+ let l = 0;
11
+ for (const ps of getMatCurveToNext(cpNode)) {
12
+ l += totalLength(ps);
13
+ }
12
14
 
13
15
  return l;
14
16
  }