flo-mat 4.1.4 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (379) 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/circle-identity.spec.ts +56 -0
  4. package/__tests__/cp-node/fs/get-all-on-loop-by-loop.spec.ts +55 -0
  5. package/__tests__/cp-node/fs/get-angle-between-mat-curves.spec.ts +39 -3
  6. package/__tests__/cp-node/fs/get-boundary-bezier-parts-to-next.spec.ts +87 -3
  7. package/__tests__/cp-node/fs/get-boundary-beziers-between.spec.ts +68 -3
  8. package/__tests__/cp-node/fs/get-boundary-beziers-to-next.spec.ts +41 -3
  9. package/__tests__/cp-node/fs/get-boundary-distance-to-next.spec.ts +20 -3
  10. package/__tests__/cp-node/fs/get-branch-beziers.spec.ts +42 -3
  11. package/__tests__/cp-node/fs/get-branch.spec.ts +60 -3
  12. package/__tests__/cp-node/fs/get-cp-node-ordering.spec.ts +19 -3
  13. package/__tests__/cp-node/fs/get-distance-to-next.spec.ts +37 -4
  14. package/__tests__/cp-node/fs/get-edge-direction.spec.ts +50 -3
  15. package/__tests__/cp-node/fs/get-first-exit.spec.ts +78 -3
  16. package/__tests__/cp-node/fs/get-hole-closers.spec.ts +32 -3
  17. package/__tests__/cp-node/fs/get-implied-boundary-bezier-between.spec.ts +48 -3
  18. package/__tests__/cp-node/fs/get-mat-curve-between.spec.ts +77 -3
  19. package/__tests__/cp-node/fs/get-mat-curve-to-next.spec.ts +17 -4
  20. package/__tests__/cp-node/fs/get-mat-curves-between.spec.ts +38 -3
  21. package/__tests__/cp-node/fs/get-salience.spec.ts +68 -3
  22. package/__tests__/cp-node/fs/get-vertex-forward-children.spec.ts +40 -3
  23. package/__tests__/cp-node/fs/insert-cp-node.spec.ts +87 -3
  24. package/__tests__/cp-node/fs/is-special.spec.ts +1 -1
  25. package/__tests__/cp-node/fs/remove-cp-node.spec.ts +42 -3
  26. package/__tests__/find-2-prong/calc-seperation-tolerance.spec.ts +46 -0
  27. package/__tests__/find-2-prong/get-medial/dd-get-medial-point-coeffs-same-curve.spec.ts +7 -5
  28. package/__tests__/find-2-prong/get-medial/dd-get-medial-point-coeffs.spec.ts +4 -2
  29. package/__tests__/find-2-prong/get-medial/get-closest-points.spec.ts +1 -1
  30. package/__tests__/floyd-warshall/get-graph.spec.ts +100 -0
  31. package/__tests__/get-mats-with-hole.ts +28 -0
  32. package/__tests__/get-mats1.spec.ts +61 -0
  33. package/__tests__/get-mats1.ts +75 -67
  34. package/__tests__/helpers/cp-node-by-id.ts +27 -0
  35. package/__tests__/helpers/expect-point-close.ts +42 -0
  36. package/__tests__/mat/hausdorff-distance-one-sided-exceeds.spec.ts +129 -0
  37. package/__tests__/mat/simplify-mat.spec.ts +85 -0
  38. package/__tests__/reconstruct-from-mat/reconstruct-from-mat.spec.ts +39 -0
  39. package/__tests__/specific-cases/test-svgs/achispado.svg +14 -0
  40. package/__tests__/utils/get-beziers-from-tangents.spec.ts +142 -0
  41. package/browser/index.js +17882 -13800
  42. package/browser/index.min.js +1 -1
  43. package/node/add-n-prong.ts/join-spokes.js +3 -2
  44. package/node/add-n-prong.ts/join-spokes.js.map +1 -1
  45. package/node/closest-boundary-point/cull-curve-pieces.d.ts +21 -0
  46. package/node/closest-boundary-point/cull-curve-pieces.js +40 -0
  47. package/node/closest-boundary-point/cull-curve-pieces.js.map +1 -0
  48. package/node/closest-boundary-point/get-close-boundary-points-certified.js +5 -2
  49. package/node/closest-boundary-point/get-close-boundary-points-certified.js.map +1 -1
  50. package/node/closest-boundary-point/get-endpoint-info.d.ts +39 -0
  51. package/node/closest-boundary-point/get-endpoint-info.js +78 -0
  52. package/node/closest-boundary-point/get-endpoint-info.js.map +1 -0
  53. package/node/closest-boundary-point/get-potential-closest-points-on-curve-certified.js +5 -19
  54. package/node/closest-boundary-point/get-potential-closest-points-on-curve-certified.js.map +1 -1
  55. package/node/closest-boundary-point/root-interval-to-distance-squared-interval.d.ts +17 -5
  56. package/node/closest-boundary-point/root-interval-to-distance-squared-interval.js +37 -50
  57. package/node/closest-boundary-point/root-interval-to-distance-squared-interval.js.map +1 -1
  58. package/node/corner/get-corner.d.ts +18 -1
  59. package/node/corner/get-corner.js +8 -1
  60. package/node/corner/get-corner.js.map +1 -1
  61. package/node/corner/get-interface-ccw.js.map +1 -1
  62. package/node/cp-node/cp-node.d.ts +4 -3
  63. package/node/cp-node/fs/enhance-cp-node.d.ts +9 -9
  64. package/node/cp-node/fs/get-all-on-loop-by-loop.js +0 -4
  65. package/node/cp-node/fs/get-all-on-loop-by-loop.js.map +1 -1
  66. package/node/cp-node/fs/get-angle-between-mat-curves.d.ts +1 -1
  67. package/node/cp-node/fs/get-angle-between-mat-curves.js +7 -4
  68. package/node/cp-node/fs/get-angle-between-mat-curves.js.map +1 -1
  69. package/node/cp-node/fs/get-boundary-beziers-between.d.ts +6 -4
  70. package/node/cp-node/fs/get-boundary-beziers-between.js +6 -4
  71. package/node/cp-node/fs/get-boundary-beziers-between.js.map +1 -1
  72. package/node/cp-node/fs/get-branch-beziers.d.ts +2 -1
  73. package/node/cp-node/fs/get-branch-beziers.js +3 -2
  74. package/node/cp-node/fs/get-branch-beziers.js.map +1 -1
  75. package/node/cp-node/fs/get-branch.js +1 -2
  76. package/node/cp-node/fs/get-branch.js.map +1 -1
  77. package/node/cp-node/fs/get-distance-to-next.js +4 -2
  78. package/node/cp-node/fs/get-distance-to-next.js.map +1 -1
  79. package/node/cp-node/fs/get-edge-direction.js +3 -2
  80. package/node/cp-node/fs/get-edge-direction.js.map +1 -1
  81. package/node/cp-node/fs/get-first-exit.d.ts +7 -3
  82. package/node/cp-node/fs/get-first-exit.js +13 -11
  83. package/node/cp-node/fs/get-first-exit.js.map +1 -1
  84. package/node/cp-node/fs/get-implied-boundary-bezier-between.d.ts +10 -2
  85. package/node/cp-node/fs/get-implied-boundary-bezier-between.js +11 -54
  86. package/node/cp-node/fs/get-implied-boundary-bezier-between.js.map +1 -1
  87. package/node/cp-node/fs/get-mat-curve-between.d.ts +5 -3
  88. package/node/cp-node/fs/get-mat-curve-between.js +6 -49
  89. package/node/cp-node/fs/get-mat-curve-between.js.map +1 -1
  90. package/node/cp-node/fs/get-mat-curve-to-next.d.ts +1 -1
  91. package/node/cp-node/fs/get-mat-curves-between.d.ts +8 -0
  92. package/node/cp-node/fs/get-mat-curves-between.js +9 -2
  93. package/node/cp-node/fs/get-mat-curves-between.js.map +1 -1
  94. package/node/cp-node/fs/get-real-prong-count.d.ts +2 -1
  95. package/node/cp-node/fs/get-real-prong-count.js +11 -5
  96. package/node/cp-node/fs/get-real-prong-count.js.map +1 -1
  97. package/node/cp-node/fs/get-salience.d.ts +10 -0
  98. package/node/cp-node/fs/get-salience.js +17 -1
  99. package/node/cp-node/fs/get-salience.js.map +1 -1
  100. package/node/cp-node/fs/is-fully-terminating.d.ts +4 -2
  101. package/node/cp-node/fs/is-fully-terminating.js +6 -17
  102. package/node/cp-node/fs/is-fully-terminating.js.map +1 -1
  103. package/node/cp-node/fs/is-on-same-circle.d.ts +3 -0
  104. package/node/cp-node/fs/is-on-same-circle.js +4 -4
  105. package/node/cp-node/fs/is-on-same-circle.js.map +1 -1
  106. package/node/cp-node/fs/is-on-same-loop.d.ts +1 -1
  107. package/node/cp-node/fs/is-special.d.ts +7 -0
  108. package/node/cp-node/fs/is-special.js +9 -2
  109. package/node/cp-node/fs/is-special.js.map +1 -1
  110. package/node/cp-node/fs/is-vertex.d.ts +1 -1
  111. package/node/cp-node/fs/traverse-edges.d.ts +7 -3
  112. package/node/cp-node/fs/traverse-edges.js +7 -3
  113. package/node/cp-node/fs/traverse-edges.js.map +1 -1
  114. package/node/cp-node/stringification/from-stringifyable.d.ts +2 -2
  115. package/node/cp-node/stringification/from-stringifyable.js +17 -1
  116. package/node/cp-node/stringification/from-stringifyable.js.map +1 -1
  117. package/node/cp-node/stringification/to-stringifyable.d.ts +3 -3
  118. package/node/cp-node/stringification/to-stringifyable.js +3 -3
  119. package/node/debug/debug.d.ts +26 -3
  120. package/node/debug/debug.js +16 -5
  121. package/node/debug/debug.js.map +1 -1
  122. package/node/find-2-prong/add-2-prong.js +7 -9
  123. package/node/find-2-prong/add-2-prong.js.map +1 -1
  124. package/node/find-2-prong/calc-seperation-tolerance.d.ts +28 -5
  125. package/node/find-2-prong/calc-seperation-tolerance.js +32 -89
  126. package/node/find-2-prong/calc-seperation-tolerance.js.map +1 -1
  127. package/node/find-2-prong/find-2-prong.js +8 -10
  128. package/node/find-2-prong/find-2-prong.js.map +1 -1
  129. package/node/find-2-prong/find-and-add-2-prongs.js +2 -2
  130. package/node/find-2-prong/find-and-add-2-prongs.js.map +1 -1
  131. package/node/find-2-prong/get-medial/get-antipodal-points.d.ts +1 -2
  132. package/node/find-2-prong/get-medial/get-antipodal-points.js +2 -3
  133. package/node/find-2-prong/get-medial/get-antipodal-points.js.map +1 -1
  134. package/node/find-2-prong/get-medial/get-closest-points.d.ts +1 -8
  135. package/node/find-2-prong/get-medial/get-closest-points.js +4 -40
  136. package/node/find-2-prong/get-medial/get-closest-points.js.map +1 -1
  137. package/node/find-2-prong/reduce-radius.d.ts +1 -1
  138. package/node/find-2-prong/reduce-radius.js +6 -3
  139. package/node/find-2-prong/reduce-radius.js.map +1 -1
  140. package/node/find-3-prong/calc-better-x.js +1 -1
  141. package/node/find-3-prong/calc-better-x.js.map +1 -1
  142. package/node/find-3-prong/find-3-prong-for-delta3s.d.ts +3 -2
  143. package/node/find-3-prong/find-3-prong-for-delta3s.js +36 -42
  144. package/node/find-3-prong/find-3-prong-for-delta3s.js.map +1 -1
  145. package/node/find-3-prong/find-3-prong.js +3 -1
  146. package/node/find-3-prong/find-3-prong.js.map +1 -1
  147. package/node/find-3-prong/find-and-add-3-prongs.js +16 -0
  148. package/node/find-3-prong/find-and-add-3-prongs.js.map +1 -1
  149. package/node/find-mat/create-initial-cp-tree.js +2 -2
  150. package/node/find-mat/create-initial-cp-tree.js.map +1 -1
  151. package/node/find-mat/find-mat.js +3 -4
  152. package/node/find-mat/find-mat.js.map +1 -1
  153. package/node/find-mat/find-mats.d.ts +6 -12
  154. package/node/find-mat/find-mats.js +10 -27
  155. package/node/find-mat/find-mats.js.map +1 -1
  156. package/node/find-mat/get-dull-corners-on-loop.js +2 -2
  157. package/node/find-mat/get-dull-corners-on-loop.js.map +1 -1
  158. package/node/find-mat/get-for-1-prongs-on-loop.js +36 -8
  159. package/node/find-mat/get-for-1-prongs-on-loop.js.map +1 -1
  160. package/node/find-mat/get-meta.d.ts +14 -4
  161. package/node/find-mat/get-meta.js +30 -24
  162. package/node/find-mat/get-meta.js.map +1 -1
  163. package/node/find-mat/get-sharp-corners.js +2 -2
  164. package/node/find-mat/get-sharp-corners.js.map +1 -1
  165. package/node/find-mat/mat-options.d.ts +2 -2
  166. package/node/floyd-warshall/get-graph.d.ts +12 -1
  167. package/node/floyd-warshall/get-graph.js +41 -38
  168. package/node/floyd-warshall/get-graph.js.map +1 -1
  169. package/node/geometry/get-bounding-box-.d.ts +16 -2
  170. package/node/geometry/get-bounding-box-.js +5 -2
  171. package/node/geometry/get-bounding-box-.js.map +1 -1
  172. package/node/geometry/get-closest-square-distance-to-rect.d.ts +3 -0
  173. package/node/geometry/get-closest-square-distance-to-rect.js +7 -5
  174. package/node/geometry/get-closest-square-distance-to-rect.js.map +1 -1
  175. package/node/geometry/get-closest-squared-distance-to-rotated-rect.d.ts +4 -0
  176. package/node/geometry/get-closest-squared-distance-to-rotated-rect.js +12 -5
  177. package/node/geometry/get-closest-squared-distance-to-rotated-rect.js.map +1 -1
  178. package/node/get-medial-points/double-double/dd-get-medial-point-coeffs-bez3.js +1 -2
  179. package/node/get-medial-points/double-double/dd-get-medial-point-coeffs-bez3.js.map +1 -1
  180. package/node/index.d.ts +3 -2
  181. package/node/index.js +2 -1
  182. package/node/index.js.map +1 -1
  183. package/node/mat/clone-mat.d.ts +9 -0
  184. package/node/mat/clone-mat.js +17 -0
  185. package/node/mat/clone-mat.js.map +1 -0
  186. package/node/mat/clone-meta.d.ts +12 -0
  187. package/node/mat/clone-meta.js +24 -0
  188. package/node/mat/clone-meta.js.map +1 -0
  189. package/node/mat/get-boundary-piece-beziers.d.ts +5 -0
  190. package/node/mat/get-boundary-piece-beziers.js +7 -93
  191. package/node/mat/get-boundary-piece-beziers.js.map +1 -1
  192. package/node/mat/get-closeby-cp-if-exist.js +2 -1
  193. package/node/mat/get-closeby-cp-if-exist.js.map +1 -1
  194. package/node/mat/get-largest-3-prong.d.ts +6 -0
  195. package/node/mat/get-largest-3-prong.js +8 -5
  196. package/node/mat/get-largest-3-prong.js.map +1 -1
  197. package/node/mat/get-largest-vertex.d.ts +15 -1
  198. package/node/mat/get-largest-vertex.js +20 -7
  199. package/node/mat/get-largest-vertex.js.map +1 -1
  200. package/node/mat/hausdorff-distance-one-sided-exceeds.d.ts +79 -0
  201. package/node/mat/hausdorff-distance-one-sided-exceeds.js +251 -0
  202. package/node/mat/hausdorff-distance-one-sided-exceeds.js.map +1 -0
  203. package/node/mat/mat-meta.d.ts +0 -6
  204. package/node/mat/simplify-mat.d.ts +25 -8
  205. package/node/mat/simplify-mat.js +182 -53
  206. package/node/mat/simplify-mat.js.map +1 -1
  207. package/node/mat/trim-mat.d.ts +4 -2
  208. package/node/mat/trim-mat.js +3 -1
  209. package/node/mat/trim-mat.js.map +1 -1
  210. package/node/point-on-shape/get-boundary-tangent-line.d.ts +19 -0
  211. package/node/point-on-shape/get-boundary-tangent-line.js +33 -0
  212. package/node/point-on-shape/get-boundary-tangent-line.js.map +1 -0
  213. package/node/point-on-shape/get-osculating-circle.d.ts +6 -4
  214. package/node/point-on-shape/get-osculating-circle.js +6 -4
  215. package/node/point-on-shape/get-osculating-circle.js.map +1 -1
  216. package/node/point-on-shape/get-pos-corner.js +2 -2
  217. package/node/point-on-shape/get-pos-corner.js.map +1 -1
  218. package/node/point-on-shape/point-on-shape.d.ts +5 -0
  219. package/node/reconstruct-from-mat/reconstruct-from-mat.js +20 -80
  220. package/node/reconstruct-from-mat/reconstruct-from-mat.js.map +1 -1
  221. package/node/reconstruct-from-mat/remove-sat-induced-trivial-3prongs.d.ts +4 -0
  222. package/node/reconstruct-from-mat/remove-sat-induced-trivial-3prongs.js +4 -0
  223. package/node/reconstruct-from-mat/remove-sat-induced-trivial-3prongs.js.map +1 -1
  224. package/node/sat/cull.d.ts +7 -6
  225. package/node/sat/cull.js +13 -16
  226. package/node/sat/cull.js.map +1 -1
  227. package/node/sat/get-sat-culls.d.ts +12 -2
  228. package/node/sat/get-sat-culls.js +21 -16
  229. package/node/sat/get-sat-culls.js.map +1 -1
  230. package/node/svg/get-shape-bounds.d.ts +1 -12
  231. package/node/svg/get-shape-bounds.js +2 -3
  232. package/node/svg/get-shape-bounds.js.map +1 -1
  233. package/node/sweep-line/sweep-line.js.map +1 -1
  234. package/node/utils/get-beziers-from-tangents.d.ts +28 -0
  235. package/node/utils/get-beziers-from-tangents.js +92 -0
  236. package/node/utils/get-beziers-from-tangents.js.map +1 -0
  237. package/node/vertex/remove-vertex.d.ts +5 -3
  238. package/node/vertex/remove-vertex.js +5 -3
  239. package/node/vertex/remove-vertex.js.map +1 -1
  240. package/package.json +16 -16
  241. package/qv-infinite-loop.md +120 -0
  242. package/src/add-n-prong.ts/join-spokes.ts +4 -2
  243. package/src/closest-boundary-point/cull-curve-pieces.ts +49 -0
  244. package/src/closest-boundary-point/get-close-boundary-points-certified.ts +5 -2
  245. package/src/closest-boundary-point/get-endpoint-info.ts +96 -0
  246. package/src/closest-boundary-point/get-potential-closest-points-on-curve-certified.ts +5 -23
  247. package/src/closest-boundary-point/root-interval-to-distance-squared-interval.ts +42 -60
  248. package/src/corner/get-corner.ts +10 -1
  249. package/src/corner/get-interface-ccw.ts +2 -2
  250. package/src/cp-node/cp-node.ts +4 -3
  251. package/src/cp-node/fs/get-all-on-loop-by-loop.ts +0 -4
  252. package/src/cp-node/fs/get-angle-between-mat-curves.ts +9 -5
  253. package/src/cp-node/fs/get-boundary-beziers-between.ts +10 -8
  254. package/src/cp-node/fs/get-branch-beziers.ts +3 -2
  255. package/src/cp-node/fs/get-branch.ts +1 -2
  256. package/src/cp-node/fs/get-distance-to-next.ts +4 -2
  257. package/src/cp-node/fs/get-edge-direction.ts +4 -2
  258. package/src/cp-node/fs/get-first-exit.ts +15 -14
  259. package/src/cp-node/fs/get-implied-boundary-bezier-between.ts +18 -70
  260. package/src/cp-node/fs/get-mat-curve-between.ts +10 -67
  261. package/src/cp-node/fs/get-mat-curves-between.ts +9 -2
  262. package/src/cp-node/fs/get-real-prong-count.ts +11 -7
  263. package/src/cp-node/fs/get-salience.ts +15 -2
  264. package/src/cp-node/fs/is-fully-terminating.ts +6 -22
  265. package/src/cp-node/fs/is-on-same-circle.ts +6 -7
  266. package/src/cp-node/fs/is-on-same-loop.ts +2 -2
  267. package/src/cp-node/fs/is-special.ts +11 -6
  268. package/src/cp-node/fs/is-vertex.ts +1 -1
  269. package/src/cp-node/fs/traverse-edges.ts +8 -4
  270. package/src/cp-node/stringification/from-stringifyable.ts +75 -58
  271. package/src/cp-node/stringification/to-stringifyable.ts +3 -3
  272. package/src/debug/debug.ts +44 -8
  273. package/src/find-2-prong/add-2-prong.ts +9 -11
  274. package/src/find-2-prong/calc-seperation-tolerance.ts +34 -115
  275. package/src/find-2-prong/find-2-prong.ts +9 -11
  276. package/src/find-2-prong/find-and-add-2-prongs.ts +2 -2
  277. package/src/find-2-prong/get-medial/get-antipodal-points.ts +1 -3
  278. package/src/find-2-prong/get-medial/get-closest-points.ts +6 -51
  279. package/src/find-2-prong/reduce-radius.ts +6 -4
  280. package/src/find-3-prong/calc-better-x.ts +2 -2
  281. package/src/find-3-prong/find-3-prong-for-delta3s.ts +197 -214
  282. package/src/find-3-prong/find-3-prong.ts +54 -51
  283. package/src/find-3-prong/find-and-add-3-prongs.ts +20 -1
  284. package/src/find-mat/create-initial-cp-tree.ts +2 -2
  285. package/src/find-mat/find-mat.ts +4 -6
  286. package/src/find-mat/find-mats.ts +83 -105
  287. package/src/find-mat/get-dull-corners-on-loop.ts +2 -2
  288. package/src/find-mat/get-for-1-prongs-on-loop.ts +40 -8
  289. package/src/find-mat/get-meta.ts +34 -39
  290. package/src/find-mat/get-sharp-corners.ts +2 -2
  291. package/src/find-mat/mat-options.ts +2 -2
  292. package/src/floyd-warshall/get-graph.ts +46 -47
  293. package/src/geometry/get-bounding-box-.ts +5 -2
  294. package/src/geometry/get-closest-square-distance-to-rect.ts +7 -7
  295. package/src/geometry/get-closest-squared-distance-to-rotated-rect.ts +15 -13
  296. package/src/get-medial-points/double-double/dd-get-medial-point-coeffs-bez3.ts +1 -2
  297. package/src/index.ts +3 -2
  298. package/src/mat/clone-mat.ts +9 -3
  299. package/src/mat/clone-meta.ts +8 -0
  300. package/src/mat/get-boundary-piece-beziers.ts +16 -117
  301. package/src/mat/get-closeby-cp-if-exist.ts +3 -1
  302. package/src/mat/get-largest-3-prong.ts +9 -6
  303. package/src/mat/get-largest-vertex.ts +25 -9
  304. package/src/mat/hausdorff-distance-one-sided-exceeds.ts +314 -0
  305. package/src/mat/mat-meta.ts +0 -9
  306. package/src/mat/simplify-mat.ts +254 -116
  307. package/src/mat/trim-mat.ts +6 -4
  308. package/src/point-on-shape/get-boundary-tangent-line.ts +36 -0
  309. package/src/point-on-shape/get-osculating-circle.ts +7 -5
  310. package/src/point-on-shape/get-pos-corner.ts +2 -2
  311. package/src/point-on-shape/point-on-shape.ts +5 -0
  312. package/src/reconstruct-from-mat/reconstruct-from-mat.ts +22 -111
  313. package/src/reconstruct-from-mat/remove-sat-induced-trivial-3prongs.ts +4 -0
  314. package/src/sat/cull.ts +16 -20
  315. package/src/sat/get-sat-culls.ts +28 -23
  316. package/src/svg/get-shape-bounds.ts +2 -3
  317. package/src/sweep-line/sweep-line.ts +1 -1
  318. package/src/utils/deg-to-rad.ts +4 -2
  319. package/src/utils/get-beziers-from-tangents.ts +110 -0
  320. package/src/utils/map-map.ts +1 -1
  321. package/src/utils/rad-to-deg.ts +4 -1
  322. package/src/vertex/remove-vertex.ts +5 -3
  323. package/webpack.config.cjs +7 -2
  324. package/__tests__/cp-node/fs/get-distance-between.spec.ts +0 -7
  325. package/__tests__/cp-node/fs/get-terminating-on-circle.spec.ts +0 -24
  326. package/__tests__/cp-node/fs/is-single-3-prong.spec.ts +0 -17
  327. package/__tests__/cp-node/fs/iterate-all-on-loop.spec.ts +0 -17
  328. package/__tests__/cp-node/fs/traverse-all-forward.spec.ts +0 -14
  329. package/node/closest-boundary-point/cull-bezier-pieces-1.d.ts +0 -9
  330. package/node/closest-boundary-point/cull-bezier-pieces-1.js +0 -17
  331. package/node/closest-boundary-point/cull-bezier-pieces-1.js.map +0 -1
  332. package/node/closest-boundary-point/cull-by-loose-bounding-box.d.ts +0 -13
  333. package/node/closest-boundary-point/cull-by-loose-bounding-box.js +0 -27
  334. package/node/closest-boundary-point/cull-by-loose-bounding-box.js.map +0 -1
  335. package/node/closest-boundary-point/cull-by-tight-boundary-box.d.ts +0 -11
  336. package/node/closest-boundary-point/cull-by-tight-boundary-box.js +0 -27
  337. package/node/closest-boundary-point/cull-by-tight-boundary-box.js.map +0 -1
  338. package/node/cp-node/fs/find-first.d.ts +0 -10
  339. package/node/cp-node/fs/find-first.js +0 -19
  340. package/node/cp-node/fs/find-first.js.map +0 -1
  341. package/node/debug/functions/check-ordering.d.ts +0 -4
  342. package/node/debug/functions/check-ordering.js +0 -43
  343. package/node/debug/functions/check-ordering.js.map +0 -1
  344. package/node/find-2-prong/cull-bezier-pieces.d.ts +0 -13
  345. package/node/find-2-prong/cull-bezier-pieces.js +0 -43
  346. package/node/find-2-prong/cull-bezier-pieces.js.map +0 -1
  347. package/node/floyd-warshall/get-hole-closer-pairs.d.ts +0 -8
  348. package/node/floyd-warshall/get-hole-closer-pairs.js +0 -27
  349. package/node/floyd-warshall/get-hole-closer-pairs.js.map +0 -1
  350. package/node/utils/dual-set.d.ts +0 -27
  351. package/node/utils/dual-set.js +0 -55
  352. package/node/utils/dual-set.js.map +0 -1
  353. package/node/utils/tri-map.d.ts +0 -27
  354. package/node/utils/tri-map.js +0 -49
  355. package/node/utils/tri-map.js.map +0 -1
  356. package/src/closest-boundary-point/cull-bezier-pieces-1.ts +0 -36
  357. package/src/closest-boundary-point/cull-by-loose-bounding-box.ts +0 -42
  358. package/src/closest-boundary-point/cull-by-tight-boundary-box.ts +0 -43
  359. package/src/closest-boundary-point/get-p-from-box.ts +0 -14
  360. package/src/cp-node/fs/add-distance-from.ts +0 -49
  361. package/src/cp-node/fs/get-distance-between.ts +0 -16
  362. package/src/cp-node/fs/get-terminating-on-circle.ts +0 -24
  363. package/src/cp-node/fs/is-single-3-prong.ts +0 -15
  364. package/src/cp-node/fs/iterate-all-on-loop.ts +0 -15
  365. package/src/cp-node/fs/traverse-all-forward.ts +0 -24
  366. package/src/debug/functions/draw/draw-beziers-as-single-path.ts +0 -40
  367. package/src/debug/functions/draw/draw-disk.ts +0 -34
  368. package/src/debug/functions/draw/xmlns.ts +0 -5
  369. package/src/find-2-prong/cull-bezier-pieces.ts +0 -61
  370. package/src/find-2-prong/find-and-add-2-prong.ts +0 -30
  371. package/src/find-2-prong/get-medial/get-closest-points-d.ts +0 -213
  372. package/src/find-2-prong/x-for-debugging.ts +0 -13
  373. package/src/floyd-warshall/get-hole-closer-pairs.ts +0 -35
  374. package/src/mat/get-two-prong-type.ts +0 -13
  375. package/src/point-on-shape/is-pos-dull-corner.ts +0 -18
  376. package/src/point-on-shape/is-pos-quite-dull-corner.ts +0 -18
  377. package/src/point-on-shape/is-pos-quite-sharp-corner.ts +0 -18
  378. package/src/point-on-shape/pos-to-human-string.ts +0 -18
  379. package/src/sweep-line/are-boxes-intersecting.ts +0 -37
@@ -7,7 +7,7 @@ import type { MatMeta } from '../mat/mat-meta.js';
7
7
  import { find2Prong } from './find-2-prong.js';
8
8
  import { add2Prong } from './add-2-prong.js';
9
9
  import { rotateNeg90Degrees } from 'flo-vector2d';
10
- import { getCorner } from '../corner/get-corner.js';
10
+ import { getCorner$ } from '../corner/get-corner.js';
11
11
 
12
12
 
13
13
  const { PI, atan2 } = Math;
@@ -67,7 +67,7 @@ function getValidAngles(
67
67
  const angles = [0];
68
68
  if (ppos.t === 1) {
69
69
  const { curve } = ppos;
70
- const corner = getCorner(curve.ps, curve.next.ps);
70
+ const corner = getCorner$(curve.ps, curve.next.ps);
71
71
  if (corner.isQuiteDull) {
72
72
  const tangentI = rotateNeg90Degrees(corner.tangents[0]);
73
73
  const tangentO = rotateNeg90Degrees(corner.tangents[1]);
@@ -9,7 +9,6 @@ import { getClosestPoint } from './get-closest-points.js';
9
9
  * bezier pieces, including the beziers actually checked after culling.
10
10
  *
11
11
  * @param maxCoordPowerOf2
12
- * @param nnorm
13
12
  * @param yPos
14
13
  * @param for1Prong defaults to `false`;
15
14
  * @param angle angle from normal
@@ -19,7 +18,6 @@ import { getClosestPoint } from './get-closest-points.js';
19
18
  */
20
19
  function getAntipodalPoints(
21
20
  maxCoordPowerOf2: number,
22
- nnorm: number[],
23
21
  nnormDd: number[][],
24
22
  yPos: PrePointOnShape,
25
23
  for1Prong: boolean,
@@ -31,7 +29,7 @@ function getAntipodalPoints(
31
29
  const curvePiece = curvePieces[i];
32
30
 
33
31
  const pInfos = getClosestPoint(
34
- maxCoordPowerOf2, nnorm, nnormDd, yPos, for1Prong, angle,
32
+ maxCoordPowerOf2, nnormDd, yPos, for1Prong, angle,
35
33
  curvePiece
36
34
  );
37
35
 
@@ -4,21 +4,20 @@ import type { PrePointOnShape } from "../../point-on-shape/point-on-shape.js";
4
4
  import type { AntipodalPoint } from './antipodal-point.js';
5
5
  import { ddMultDouble1 } from 'double-double';
6
6
  import { lengthSquared } from "flo-vector2d";
7
- import { roots, Horner, ddHorner } from 'flo-poly';
8
- import { evalDeCasteljau, getMedialPointCoeffs, getMedialPointCoeffsBez0 } from 'flo-bezier3';
7
+ import { roots, ddHorner } from 'flo-poly';
8
+ import { evalDeCasteljau } from 'flo-bezier3';
9
9
  import { ddGetMedialPointCoeffs } from '../../get-medial-points/double-double/dd-get-medial-point-coeffs.js';
10
10
  import { ddGetMedialPointCoeffsBez2_SameCurve } from '../../get-medial-points/double-double/dd-get-medial-point-coeffs-bez2-same-curve.js';
11
11
  import { ddGetMedialPointCoeffsBez3_SameCurve } from '../../get-medial-points/double-double/dd-get-medial-point-coeffs-bez3-same-curve.js';
12
12
  import { ddGetMedialPointCoeffsBez0 } from '../../get-medial-points/double-double/dd-get-medial-point-coeffs-bez0.js';
13
13
 
14
- const { sqrt, abs, max } = Math;
14
+ const { sqrt, abs } = Math;
15
15
 
16
16
  const qmd = ddMultDouble1;
17
17
 
18
18
 
19
19
  /**
20
20
  * @param maxCoordPowerOf2
21
- * @param nnorm
22
21
  * @param yPos The point on the shape
23
22
  * @param for1Prong defaults to `false`;
24
23
  * @param angle defaults to `0`;
@@ -28,7 +27,6 @@ const qmd = ddMultDouble1;
28
27
  */
29
28
  function getClosestPoint(
30
29
  maxCoordPowerOf2: number,
31
- nnorm: number[],
32
30
  nnormDd: number[][],
33
31
  yPos: PrePointOnShape,
34
32
  for1Prong: boolean,
@@ -90,8 +88,7 @@ function getClosestPoint(
90
88
  const _AS = abs(AS);
91
89
  // const _CS = abs(CS);
92
90
 
93
- // if (max(_AS, _CS) < 2**-40) { continue; }
94
- if (max(_AS) < 2**-40) { continue; }
91
+ if (_AS < 2**-40) { continue; }
95
92
 
96
93
  // const w = _AS > _CS
97
94
  // ? -BS / AS
@@ -144,7 +141,7 @@ function getClosestPoint(
144
141
  //------------------------------------------
145
142
  const pLast = ps[ps.length - 1];
146
143
 
147
- let dontPush1 = (
144
+ const dontPush1 = (
148
145
  (t === 0 && curve === touchedCurve!.prev) ||
149
146
  (t === 1 && curve === touchedCurve)
150
147
  );
@@ -177,7 +174,7 @@ function getClosestPoint(
177
174
  // which cannot be culled if this curve`s `t === 0` is included
178
175
  } else if (tE === 1) {
179
176
  if (!dontPush1 && !endPushed) {
180
- PS.push({ P: pLast, t: 1 }); dontPush1 = true;
177
+ PS.push({ P: pLast, t: 1 });
181
178
  }
182
179
  } else {
183
180
  if (!endPushed) {
@@ -228,45 +225,3 @@ function getClosestPoint(
228
225
 
229
226
 
230
227
  export { getClosestPoint }
231
-
232
-
233
-
234
- /**
235
- * Recovers a numerically stable ray parameter `t` from linear equations
236
- * `A*t + B = 0` and (optionally) `C*t + D = 0` evaluated at a fixed `s`.
237
- *
238
- * If `C,D` are unavailable, this falls back to `-B/A`.
239
- */
240
- // function chooseStableT(
241
- // A: number,
242
- // B: number,
243
- // C: number,
244
- // D: number) {
245
-
246
- // const epsScale = max(1, abs(A), abs(B), abs(C), abs(D));
247
- // const eps = Number.EPSILON * epsScale;
248
-
249
- // const denomAB = abs(A);
250
- // const hasAB = denomAB > eps;
251
- // const denomCD = abs(C);
252
- // const hasCD = denomCD > eps;
253
-
254
- // if (!hasAB && !hasCD) {
255
- // return undefined;
256
- // }
257
- // if (hasAB && !hasCD) {
258
- // return -B / A;
259
- // }
260
- // if (!hasAB && hasCD) {
261
- // return -D / C;
262
- // }
263
-
264
- // const tAB = -B / A;
265
- // const tCD = -D / C;
266
-
267
- // // Score each candidate by how well it satisfies the *other* equation.
268
- // const scoreAB = abs(C*tAB + D) / (abs(C) + abs(D) + eps);
269
- // const scoreCD = abs(A*tCD + B) / (abs(A) + abs(B) + eps);
270
-
271
- // return scoreAB <= scoreCD ? tAB : tCD;
272
- // }
@@ -2,7 +2,7 @@ import type { CurvePiece } from '../mat/curve-piece.js';
2
2
  import { getMedialPointCoeffsBez0 } from "flo-bezier3";
3
3
  import { lengthSquared, squaredDistanceBetween } from "flo-vector2d";
4
4
 
5
- const { abs } = Math;
5
+ const { abs, sqrt } = Math;
6
6
 
7
7
 
8
8
  const TOLERANCE = 1 + 2**-20;
@@ -16,14 +16,16 @@ const TOLERANCE = 1 + 2**-20;
16
16
  * @internal
17
17
  */
18
18
  function reduceRadius(
19
- maxCoordPowerOf2: number,
20
19
  rO: number,
21
- curvePieces: CurvePiece[],
20
+ curvePieces: CurvePiece[],
22
21
  y: number[],
23
22
  nnorm: number[]): number {
24
23
 
25
24
  let minRadiusSqrd = rO**2;
26
- let x = [y[0] + nnorm[0], y[1] + nnorm[1]];
25
+ // the center of the initial circle (radius `rO`) - `nnorm` is not
26
+ // necessarily of unit length so scale it
27
+ const s = rO / sqrt(lengthSquared(nnorm));
28
+ let x = [y[0] + s*nnorm[0], y[1] + s*nnorm[1]];
27
29
 
28
30
  for (let i=0; i<curvePieces.length; i++) {
29
31
  const curvePiece = curvePieces[i];
@@ -31,7 +31,7 @@ function calcBetterX(
31
31
 
32
32
  let nu = 1;
33
33
  let better;
34
- let newX;
34
+ let newX: number[];
35
35
  let newPoss: PrePointOnShape[];
36
36
  let newV;
37
37
  let i = 0; // Safeguard
@@ -40,7 +40,7 @@ function calcBetterX(
40
40
  newX = translate(shift, x);
41
41
 
42
42
  newPoss = curvePiece3s.map(curvePieces =>
43
- getCloseBoundaryPointsCertified(curvePieces, x)[0]
43
+ getCloseBoundaryPointsCertified(curvePieces, newX)[0]
44
44
  );
45
45
 
46
46
  // Point of zero V
@@ -1,214 +1,197 @@
1
- import type { CpNode } from '../cp-node/cp-node.js';
2
- import type { CurvePiece } from '../mat/curve-piece.js';
3
- import type { ThreeProngInfo } from './three-prong-info.js';
4
- import type { PrePointOnShape } from '../point-on-shape/point-on-shape.js';
5
- import { circumCenter as getCircumCenter, fromTo, len, distanceBetween, toUnitVector, rotate90Degrees, cross } from 'flo-vector2d';
6
- import { tangent } from 'flo-bezier3';
7
- import { calcInitial3ProngCenter } from './calc-initial-3-prong-center.js';
8
- import { getClosestPoints } from './get-closest-points.js';
9
- import { calcBetterX } from './calc-better-x.js';
10
- import { getCloseBoundaryPointsCertified } from '../closest-boundary-point/get-close-boundary-points-certified.js';
11
- import { getCorner } from '../corner/get-corner.js';
12
- import { isPosCorner } from '../point-on-shape/is-pos-corner.js';
13
- import { getPosCorner$ } from '../point-on-shape/get-pos-corner.js';
14
- import { isSharp } from '../cp-node/fs/is-sharp.js';
15
-
16
- const { min, abs, asin } = Math;
17
-
18
-
19
- /**
20
- * Finds a 3-prong using only the 3 given δs.
21
- *
22
- * @param δs the boundary pieces
23
- * @param idx δ identifier
24
- * @param k δs identifier
25
- * @param curvePiecess
26
- * @param maxCoordPowerOf2
27
- *
28
- * @internal
29
- */
30
- function find3ProngForDelta3s(
31
- δs: [CpNode, CpNode][],
32
- idx: number,
33
- k: number,
34
- curvePiecess: CurvePiece[][],
35
- maxCoordPowerOf2: number): { error: number, threeProngInfo: ThreeProngInfo } | undefined {
36
-
37
- const TOLERANCE = 2**(maxCoordPowerOf2 - 32);
38
- const MAX_ITERATIONS = 10;
39
-
40
- const δs_: [[CpNode,CpNode], [CpNode,CpNode], [CpNode,CpNode]] = [
41
- δs[0],
42
- δs[idx],
43
- δs[δs.length-1]
44
- ];
45
-
46
- const curvePieces_: [CurvePiece[], CurvePiece[], CurvePiece[]] = [
47
- curvePiecess[0],
48
- curvePiecess[idx],
49
- curvePiecess[δs.length - 1]
50
- ];
51
-
52
- const δ3ss: [
53
- [[CpNode, CpNode], [CpNode, CpNode], [CpNode, CpNode]],
54
- [[CpNode, CpNode], [CpNode, CpNode], [CpNode, CpNode]],
55
- [[CpNode, CpNode], [CpNode, CpNode], [CpNode, CpNode]]
56
- ] = [
57
- [δs_[0], δs_[1], δs_[2]],
58
- [δs_[1], δs_[2], δs_[0]],
59
- [δs_[2], δs_[0], δs_[1]],
60
- ];
61
-
62
- const curvePiecess_: [
63
- [CurvePiece[], CurvePiece[], CurvePiece[]],
64
- [CurvePiece[], CurvePiece[], CurvePiece[]],
65
- [CurvePiece[], CurvePiece[], CurvePiece[]]
66
- ] = [
67
- [curvePieces_[0], curvePieces_[1], curvePieces_[2]],
68
- [curvePieces_[1], curvePieces_[2], curvePieces_[0]],
69
- [curvePieces_[2], curvePieces_[0], curvePieces_[1]],
70
- ]
71
-
72
-
73
- const δ3s = δ3ss[k];
74
- const curvePiece3s = curvePiecess_[k];
75
-
76
- if (isSharp(δ3s[0][0])) { return undefined; }
77
-
78
- //----------------------------
79
- // const l1 = curvePiece3s[0].length;
80
- // const l2 = curvePiece3s[1].length;
81
- // const l3 = curvePiece3s[2].length;
82
- // if (l1 === 1 && l2 == 1 && l3 === 1) {
83
- // // console.log('aaa');
84
- // const A = curvePiece3s[0][0].curve.ps;
85
- // const B = curvePiece3s[1][0].curve.ps;
86
- // const C = curvePiece3s[2][0].curve.ps;
87
-
88
- // console.log(A.length, B.length, C.length);
89
- // } else {
90
- // // console.log('bbb');
91
- // }
92
- //----------------------------
93
-
94
-
95
- let poss: PrePointOnShape[] = undefined!;
96
- let j = 0; // Safeguard for slow convergence
97
- let x = calcInitial3ProngCenter(δ3s, curvePiece3s);
98
-
99
- let tolerance = Infinity;
100
- while (tolerance > TOLERANCE && j < MAX_ITERATIONS) {
101
- j++;
102
-
103
- poss = getClosestPoints(x, curvePiece3s);
104
- if (!Number.isFinite(x[0]) || !Number.isFinite(x[1])) {
105
-
106
- // FUTURE - the code can be cleaned up and sped up a lot if we don't
107
- // use this function as is but instead use δs[0] and δs[2] as is
108
- // and make δs[1] include all the rest of the beziers around the
109
- // loop. This check, for instance, would be eliminated completely.
110
- return undefined;
111
- }
112
-
113
- const circumCenter = getCircumCenter(poss.map(x => x.p));
114
- const vectorToZeroV = fromTo(x, circumCenter);
115
-
116
- if (!Number.isFinite(vectorToZeroV[0]) || !Number.isFinite(vectorToZeroV[1])) {
117
-
118
- // FUTURE - the code can be cleaned up and sped up a lot if we don't
119
- // use this function as is but instead use δs[0] and δs[2] as is
120
- // and make δs[1] include all the rest of the beziers around the
121
- // loop. This check, for instance, would be eliminated completely.
122
- return undefined;
123
- }
124
- const upds = calcBetterX(curvePiece3s, x, vectorToZeroV);
125
- x = upds.newX;
126
- poss = upds.newPoss;
127
-
128
- const V = len(vectorToZeroV); // The 'potential'
129
-
130
- tolerance = abs(V - upds.newV);
131
- }
132
-
133
- const radius = (distanceBetween(x, poss[0].p) +
134
- distanceBetween(x, poss[1].p) +
135
- distanceBetween(x, poss[2].p)) / 3;
136
-
137
- const circle = { center: x, radius };
138
-
139
- //-------------------------------------------------------------------------
140
- // Calculate the unit tangent vector at 3-prong circle points - they should
141
- // be very close to tangent to the boundary piece tangents at those points
142
- // (up to sign). Dull corners is a common special case.
143
- //-------------------------------------------------------------------------
144
- let totalAngleError = 0;
145
- for (let i=0; i<3; i++) {
146
- const pos = poss[i];
147
- //----------------------------
148
- // Tangent of circle at point
149
- //----------------------------
150
- const v = toUnitVector(fromTo(pos.p, x));
151
- const v1 = rotate90Degrees(v);
152
-
153
-
154
- //-----------------------------------
155
- // Check if point is on dull crorner
156
- //-----------------------------------
157
- if (isPosCorner(pos) && getPosCorner$(pos).isDull) {
158
- const corner = getCorner(pos.curve.ps, pos.curve.next.ps);
159
- const tans = corner.tangents;
160
- const perps = tans.map( rotate90Degrees );
161
-
162
- const angleError1 = asin( cross( perps[0], v ) );
163
- const angleError2 = asin( cross( v, perps[1] ) );
164
-
165
- let angleError = 0;
166
- if (angleError1 > 0) { angleError += angleError1; }
167
- if (angleError2 > 0) { angleError += angleError2; }
168
-
169
- totalAngleError += angleError;
170
- } else {
171
- //---------------------------
172
- // Tangent of curve at point
173
- //---------------------------
174
- const v2 = toUnitVector( tangent(pos.curve.ps, pos.t) );
175
-
176
- // Cross is more numerically stable than Vector.dot at angles a
177
- // multiple of `Math.PI` **and** is close to the actual angle value
178
- // and can thus just be added to cone method of looking at
179
- // tolerance.
180
-
181
- // Should be close to zero and is close to the actual angle.
182
- const cross_ = abs( asin( cross(v1, v2) ) );
183
-
184
- totalAngleError += cross_;
185
- }
186
- }
187
-
188
- //-------------------------------------------------------------------------
189
- // Calculate radiusDelta, the difference between the radius and the closest
190
- // point to the 3-prong. It should be around 0. If not, this is not a good
191
- // candidate for the 3-prong.
192
- //-------------------------------------------------------------------------
193
- const closestDs = [];
194
- for (let i=0; i<curvePiecess.length; i++) {
195
- const pos = getCloseBoundaryPointsCertified(
196
- curvePiecess[i],
197
- x
198
- )[0];
199
-
200
- closestDs.push( distanceBetween(pos.p, x) );
201
- }
202
- const closestD = min(...closestDs);
203
- const radiusDelta = abs(radius - closestD);
204
-
205
- // Weights below still need to be optimized.
206
- const W1 = 1;
207
- const W2 = 1;
208
- const error = W1*radiusDelta + W2*totalAngleError;
209
-
210
- return { threeProngInfo: { poss, circle, δ3s }, error };
211
- }
212
-
213
-
214
- export { find3ProngForDelta3s }
1
+ import type { CpNode } from '../cp-node/cp-node.js';
2
+ import type { CurvePiece } from '../mat/curve-piece.js';
3
+ import type { ThreeProngInfo } from './three-prong-info.js';
4
+ import type { PrePointOnShape } from '../point-on-shape/point-on-shape.js';
5
+ import { circumCenter as getCircumCenter, fromTo, len, distanceBetween, toUnitVector, rotate90Degrees, cross } from 'flo-vector2d';
6
+ import { tangent } from 'flo-bezier3';
7
+ import { calcInitial3ProngCenter } from './calc-initial-3-prong-center.js';
8
+ import { getClosestPoints } from './get-closest-points.js';
9
+ import { calcBetterX } from './calc-better-x.js';
10
+ import { getCloseBoundaryPointsCertified } from '../closest-boundary-point/get-close-boundary-points-certified.js';
11
+ import { cullCurvePieces } from '../closest-boundary-point/cull-curve-pieces.js';
12
+ import { getCorner$ } from '../corner/get-corner.js';
13
+ import { isPosCorner } from '../point-on-shape/is-pos-corner.js';
14
+ import { getPosCorner$ } from '../point-on-shape/get-pos-corner.js';
15
+ import { isSharp } from '../cp-node/fs/is-sharp.js';
16
+
17
+ const { abs, asin } = Math;
18
+
19
+
20
+ /**
21
+ * Finds a 3-prong using only the 3 given δs.
22
+ *
23
+ * @param δs the boundary pieces
24
+ * @param idx δ identifier
25
+ * @param k δs identifier
26
+ * @param curvePiecess the curve pieces of each boundary piece
27
+ * @param allCurvePieces all of the above flattened into one array
28
+ * @param maxCoordPowerOf2
29
+ *
30
+ * @internal
31
+ */
32
+
33
+ function find3ProngForDelta3s(
34
+ δs: [CpNode, CpNode][],
35
+ idx: number,
36
+ k: number,
37
+ curvePiecess: CurvePiece[][],
38
+ allCurvePieces: CurvePiece[],
39
+ maxCoordPowerOf2: number): { error: number, threeProngInfo: ThreeProngInfo } | undefined {
40
+
41
+ const TOLERANCE = 2**(maxCoordPowerOf2 - 32);
42
+ const MAX_ITERATIONS = 10;
43
+
44
+ // The three boundary pieces (and their curve pieces) with the first,
45
+ // the `idx`th and the last taken, rotated so that the one with index `k`
46
+ // comes first (the first one is treated specially below).
47
+ const δs_ = [δs[0], δs[idx], δs[δs.length-1]];
48
+ const curvePieces_ = [curvePiecess[0], curvePiecess[idx], curvePiecess[δs.length-1]];
49
+ const r = (i: number) => (k + i) % 3;
50
+ const δ3s: [[CpNode,CpNode], [CpNode,CpNode], [CpNode,CpNode]] =
51
+ [δs_[r(0)], δs_[r(1)], δs_[r(2)]];
52
+ const curvePiece3s: [CurvePiece[], CurvePiece[], CurvePiece[]] =
53
+ [curvePieces_[r(0)], curvePieces_[r(1)], curvePieces_[r(2)]];
54
+
55
+ if (isSharp(δ3s[0][0])) { return undefined; }
56
+
57
+ //----------------------------
58
+ // const l1 = curvePiece3s[0].length;
59
+ // const l2 = curvePiece3s[1].length;
60
+ // const l3 = curvePiece3s[2].length;
61
+ // if (l1 === 1 && l2 == 1 && l3 === 1) {
62
+ // // console.log('aaa');
63
+ // const A = curvePiece3s[0][0].curve.ps;
64
+ // const B = curvePiece3s[1][0].curve.ps;
65
+ // const C = curvePiece3s[2][0].curve.ps;
66
+
67
+ // console.log(A.length, B.length, C.length);
68
+ // } else {
69
+ // // console.log('bbb');
70
+ // }
71
+ //----------------------------
72
+
73
+
74
+ let poss: PrePointOnShape[] = undefined!;
75
+ let j = 0; // Safeguard for slow convergence
76
+ let x = calcInitial3ProngCenter(δ3s, curvePiece3s);
77
+
78
+ if (!Number.isFinite(x[0]) || !Number.isFinite(x[1])) {
79
+
80
+ // FUTURE - the code can be cleaned up and sped up a lot if we don't
81
+ // use this function as is but instead use δs[0] and δs[2] as is
82
+ // and make δs[1] include all the rest of the beziers around the
83
+ // loop. This check, for instance, would be eliminated completely.
84
+ return undefined;
85
+ }
86
+
87
+ // the closest points on the three boundary pieces to the current center
88
+ poss = getClosestPoints(x, curvePiece3s);
89
+
90
+ let tolerance = Infinity;
91
+ while (tolerance > TOLERANCE && j < MAX_ITERATIONS) {
92
+ j++;
93
+
94
+
95
+ const circumCenter = getCircumCenter(poss.map(x => x.p));
96
+ const vectorToZeroV = fromTo(x, circumCenter);
97
+
98
+ if (!Number.isFinite(vectorToZeroV[0]) || !Number.isFinite(vectorToZeroV[1])) {
99
+
100
+ // FUTURE - the code can be cleaned up and sped up a lot if we don't
101
+ // use this function as is but instead use δs[0] and δs[2] as is
102
+ // and make δs[1] include all the rest of the beziers around the
103
+ // loop. This check, for instance, would be eliminated completely.
104
+ return undefined;
105
+ }
106
+ const upds = calcBetterX(curvePiece3s, x, vectorToZeroV);
107
+ x = upds.newX;
108
+ // `calcBetterX` already found the closest points at the new center -
109
+ // use them for the next iteration instead of searching again
110
+ poss = upds.newPoss;
111
+
112
+ const V = len(vectorToZeroV); // The 'potential'
113
+
114
+ tolerance = abs(V - upds.newV);
115
+ }
116
+
117
+ const radius = (distanceBetween(x, poss[0].p) +
118
+ distanceBetween(x, poss[1].p) +
119
+ distanceBetween(x, poss[2].p)) / 3;
120
+
121
+ const circle = { center: x, radius };
122
+
123
+ //-------------------------------------------------------------------------
124
+ // Calculate the unit tangent vector at 3-prong circle points - they should
125
+ // be very close to tangent to the boundary piece tangents at those points
126
+ // (up to sign). Dull corners is a common special case.
127
+ //-------------------------------------------------------------------------
128
+ let totalAngleError = 0;
129
+ for (let i=0; i<3; i++) {
130
+ const pos = poss[i];
131
+ //----------------------------
132
+ // Tangent of circle at point
133
+ //----------------------------
134
+ const v = toUnitVector(fromTo(pos.p, x));
135
+ const v1 = rotate90Degrees(v);
136
+
137
+
138
+ //-----------------------------------
139
+ // Check if point is on dull crorner
140
+ //-----------------------------------
141
+ if (isPosCorner(pos) && getPosCorner$(pos).isDull) {
142
+ const corner = getCorner$(pos.curve.ps, pos.curve.next.ps);
143
+ const tans = corner.tangents;
144
+ const perps = tans.map( rotate90Degrees );
145
+
146
+ const angleError1 = asin( cross( perps[0], v ) );
147
+ const angleError2 = asin( cross( v, perps[1] ) );
148
+
149
+ let angleError = 0;
150
+ if (angleError1 > 0) { angleError += angleError1; }
151
+ if (angleError2 > 0) { angleError += angleError2; }
152
+
153
+ totalAngleError += angleError;
154
+ } else {
155
+ //---------------------------
156
+ // Tangent of curve at point
157
+ //---------------------------
158
+ const v2 = toUnitVector( tangent(pos.curve.ps, pos.t) );
159
+
160
+ // Cross is more numerically stable than Vector.dot at angles a
161
+ // multiple of π **and** is close to the actual angle value
162
+ // and can thus just be added to cone method of looking at
163
+ // tolerance.
164
+
165
+ // Should be close to zero and is close to the actual angle.
166
+ const cross_ = abs( asin( cross(v1, v2) ) );
167
+
168
+ totalAngleError += cross_;
169
+ }
170
+ }
171
+
172
+ //-------------------------------------------------------------------------
173
+ // Calculate radiusDelta, the difference between the radius and the closest
174
+ // point to the 3-prong. It should be around 0. If not, this is not a good
175
+ // candidate for the 3-prong.
176
+ //-------------------------------------------------------------------------
177
+ // Only boundary pieces that come within the radius of the center can be
178
+ // closer than the three touching pieces, so cull against the radius first
179
+ // (cheap, memoized bounding box tests) and run the (expensive) certified
180
+ // closest point search once on the survivors only. The touching pieces
181
+ // always survive (their distance is about the radius) so the result is
182
+ // the true closest distance over all the boundary pieces.
183
+ const nearCurvePieces = cullCurvePieces(allCurvePieces, x, (1 + 2**-20)*radius*radius);
184
+ const closestPos = getCloseBoundaryPointsCertified(nearCurvePieces, x)[0];
185
+ const closestD = closestPos === undefined ? radius : distanceBetween(closestPos.p, x);
186
+ const radiusDelta = abs(radius - closestD);
187
+
188
+ // Weights below still need to be optimized.
189
+ const W1 = 1;
190
+ const W2 = 1;
191
+ const error = W1*radiusDelta + W2*totalAngleError;
192
+
193
+ return { threeProngInfo: { poss, circle, δ3s }, error };
194
+ }
195
+
196
+
197
+ export { find3ProngForDelta3s }