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