flo-mat 4.1.5 → 5.0.1

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