flo-mat 4.0.2 → 4.1.0

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 (294) hide show
  1. package/__tests__/find-2-prong/get-medial/dd-get-medial-point-coeffs-same-curve.spec.ts +106 -0
  2. package/__tests__/find-2-prong/get-medial/dd-get-medial-point-coeffs.spec.ts +73 -0
  3. package/__tests__/find-2-prong/get-medial/get-closest-points.spec.ts +5 -2
  4. package/__tests__/helpers/close-to.ts +5 -5
  5. package/__tests__/specific-cases/load-svg/load-svg.ts +30 -0
  6. package/__tests__/specific-cases/specific-cases.spec.ts +170 -0
  7. package/__tests__/specific-cases/test-svgs/achispado.svg +5052 -0
  8. package/browser/index.js +5129 -8785
  9. package/browser/index.min.js +1 -1
  10. package/{jest.config.cjs → jest.config.ts} +8 -3
  11. package/node/closest-boundary-point/get-close-boundary-points-certified.js +3 -2
  12. package/node/closest-boundary-point/get-close-boundary-points-certified.js.map +1 -1
  13. package/node/corner/get-corner.js +1 -1
  14. package/node/corner/get-corner.js.map +1 -1
  15. package/node/cp-node/fs/get-all-on-loop-by-loop.d.ts +11 -0
  16. package/node/cp-node/fs/get-all-on-loop-by-loop.js +42 -0
  17. package/node/cp-node/fs/get-all-on-loop-by-loop.js.map +1 -0
  18. package/node/cp-node/fs/get-boundary-beziers-to-next.d.ts +1 -0
  19. package/node/cp-node/fs/get-boundary-beziers-to-next.js +1 -59
  20. package/node/cp-node/fs/get-boundary-beziers-to-next.js.map +1 -1
  21. package/node/cp-node/fs/get-edge-direction.d.ts +3 -1
  22. package/node/cp-node/fs/get-edge-direction.js +5 -3
  23. package/node/cp-node/fs/get-edge-direction.js.map +1 -1
  24. package/node/cp-node/fs/get-mat-curve-between.js +6 -6
  25. package/node/cp-node/fs/get-mat-curve-between.js.map +1 -1
  26. package/node/cp-node/fs/is-fully-terminating.js +12 -0
  27. package/node/cp-node/fs/is-fully-terminating.js.map +1 -1
  28. package/node/cp-node/fs/is-on-same-loop.d.ts +3 -0
  29. package/node/cp-node/fs/is-on-same-loop.js +6 -0
  30. package/node/cp-node/fs/is-on-same-loop.js.map +1 -0
  31. package/node/debug/debug.d.ts +8 -22
  32. package/node/debug/debug.js +12 -50
  33. package/node/debug/debug.js.map +1 -1
  34. package/node/find-2-prong/add-1-prong.js +1 -4
  35. package/node/find-2-prong/add-1-prong.js.map +1 -1
  36. package/node/find-2-prong/find-2-prong.js +24 -10
  37. package/node/find-2-prong/find-2-prong.js.map +1 -1
  38. package/node/find-2-prong/get-medial/get-antipodal-points.d.ts +1 -1
  39. package/node/find-2-prong/get-medial/get-antipodal-points.js +2 -2
  40. package/node/find-2-prong/get-medial/get-antipodal-points.js.map +1 -1
  41. package/node/find-2-prong/get-medial/get-closest-points.d.ts +7 -1
  42. package/node/find-2-prong/get-medial/get-closest-points.js +60 -14
  43. package/node/find-2-prong/get-medial/get-closest-points.js.map +1 -1
  44. package/node/find-2-prong/reduce-radius.d.ts +3 -1
  45. package/node/find-2-prong/reduce-radius.js +8 -6
  46. package/node/find-2-prong/reduce-radius.js.map +1 -1
  47. package/node/find-3-prong/calc-better-x.js +1 -3
  48. package/node/find-3-prong/calc-better-x.js.map +1 -1
  49. package/node/find-3-prong/calc-initial-3-prong-center.js +1 -2
  50. package/node/find-3-prong/calc-initial-3-prong-center.js.map +1 -1
  51. package/node/find-3-prong/find-3-prong-for-delta3s.js +1 -4
  52. package/node/find-3-prong/find-3-prong-for-delta3s.js.map +1 -1
  53. package/node/find-3-prong/find-3-prong.js.map +1 -1
  54. package/node/find-3-prong/find-and-add-3-prong.js +0 -14
  55. package/node/find-3-prong/find-and-add-3-prong.js.map +1 -1
  56. package/node/find-mat/find-mat.js +2 -2
  57. package/node/find-mat/find-mat.js.map +1 -1
  58. package/node/find-mat/find-mats.js.map +1 -1
  59. package/node/find-mat/get-dull-corners-on-loop.js +3 -2
  60. package/node/find-mat/get-dull-corners-on-loop.js.map +1 -1
  61. package/node/find-mat/get-for-1-prongs-on-loop.js +6 -3
  62. package/node/find-mat/get-for-1-prongs-on-loop.js.map +1 -1
  63. package/node/find-mat/get-for-2-prongs-on-loop.js +5 -1
  64. package/node/find-mat/get-for-2-prongs-on-loop.js.map +1 -1
  65. package/node/find-mat/get-meta.d.ts +4 -6
  66. package/node/find-mat/get-meta.js +12 -26
  67. package/node/find-mat/get-meta.js.map +1 -1
  68. package/node/find-mat/get-sharp-corners.js +4 -2
  69. package/node/find-mat/get-sharp-corners.js.map +1 -1
  70. package/node/get-medial-points/double-double/dd-get-medial-point-coeffs-bez0.d.ts +21 -0
  71. package/node/get-medial-points/double-double/dd-get-medial-point-coeffs-bez0.js +46 -0
  72. package/node/get-medial-points/double-double/dd-get-medial-point-coeffs-bez0.js.map +1 -0
  73. package/node/get-medial-points/double-double/dd-get-medial-point-coeffs-bez1.d.ts +28 -0
  74. package/node/get-medial-points/double-double/dd-get-medial-point-coeffs-bez1.js +97 -0
  75. package/node/get-medial-points/double-double/dd-get-medial-point-coeffs-bez1.js.map +1 -0
  76. package/node/get-medial-points/double-double/dd-get-medial-point-coeffs-bez2-same-curve.d.ts +28 -0
  77. package/node/get-medial-points/double-double/dd-get-medial-point-coeffs-bez2-same-curve.js +109 -0
  78. package/node/get-medial-points/double-double/dd-get-medial-point-coeffs-bez2-same-curve.js.map +1 -0
  79. package/node/get-medial-points/double-double/dd-get-medial-point-coeffs-bez2.d.ts +29 -0
  80. package/node/get-medial-points/double-double/dd-get-medial-point-coeffs-bez2.js +123 -0
  81. package/node/get-medial-points/double-double/dd-get-medial-point-coeffs-bez2.js.map +1 -0
  82. package/node/get-medial-points/double-double/dd-get-medial-point-coeffs-bez3-same-curve.d.ts +30 -0
  83. package/node/get-medial-points/double-double/dd-get-medial-point-coeffs-bez3-same-curve.js +177 -0
  84. package/node/get-medial-points/double-double/dd-get-medial-point-coeffs-bez3-same-curve.js.map +1 -0
  85. package/node/get-medial-points/double-double/dd-get-medial-point-coeffs-bez3.d.ts +29 -0
  86. package/node/get-medial-points/double-double/dd-get-medial-point-coeffs-bez3.js +156 -0
  87. package/node/get-medial-points/double-double/dd-get-medial-point-coeffs-bez3.js.map +1 -0
  88. package/node/get-medial-points/double-double/dd-get-medial-point-coeffs.d.ts +28 -0
  89. package/node/get-medial-points/double-double/dd-get-medial-point-coeffs.js +40 -0
  90. package/node/get-medial-points/double-double/dd-get-medial-point-coeffs.js.map +1 -0
  91. package/node/index.d.ts +6 -10
  92. package/node/index.js +5 -6
  93. package/node/index.js.map +1 -1
  94. package/node/point-on-shape/point-on-shape.d.ts +2 -0
  95. package/node/point-on-shape/to-p.d.ts +1 -1
  96. package/node/point-on-shape/to-p.js +1 -1
  97. package/node/point-on-shape/to-p.js.map +1 -1
  98. package/node/reconstruct-from-mat/get-cp-nodess-for-sat.d.ts +4 -0
  99. package/node/reconstruct-from-mat/get-cp-nodess-for-sat.js +15 -0
  100. package/node/reconstruct-from-mat/get-cp-nodess-for-sat.js.map +1 -0
  101. package/node/reconstruct-from-mat/reconstruct-from-mat.d.ts +10 -0
  102. package/node/reconstruct-from-mat/reconstruct-from-mat.js +160 -0
  103. package/node/reconstruct-from-mat/reconstruct-from-mat.js.map +1 -0
  104. package/node/reconstruct-from-mat/remove-sat-induced-trivial-3prongs.d.ts +12 -0
  105. package/node/reconstruct-from-mat/remove-sat-induced-trivial-3prongs.js +46 -0
  106. package/node/reconstruct-from-mat/remove-sat-induced-trivial-3prongs.js.map +1 -0
  107. package/node/sat/add-debug-info.js +1 -2
  108. package/node/sat/add-debug-info.js.map +1 -1
  109. package/node/svg/get-loop-bounds.js +6 -2
  110. package/node/svg/get-loop-bounds.js.map +1 -1
  111. package/node/utils/map-deep.d.ts +15 -0
  112. package/node/utils/map-deep.js +34 -0
  113. package/node/utils/map-deep.js.map +1 -0
  114. package/package.json +14 -8
  115. package/src/closest-boundary-point/get-close-boundary-points-certified.ts +3 -2
  116. package/src/corner/get-corner.ts +1 -1
  117. package/src/cp-node/fs/get-all-on-loop-by-loop.ts +56 -0
  118. package/src/cp-node/fs/get-all-on-loop.ts +1 -1
  119. package/src/cp-node/fs/get-boundary-beziers-to-next.ts +1 -72
  120. package/src/cp-node/fs/get-edge-direction.ts +8 -4
  121. package/src/cp-node/fs/get-mat-curve-between.ts +6 -6
  122. package/src/cp-node/fs/is-fully-terminating.ts +16 -0
  123. package/src/cp-node/fs/is-on-same-loop.ts +15 -0
  124. package/src/debug/debug.ts +27 -87
  125. package/src/find-2-prong/add-1-prong.ts +1 -5
  126. package/src/find-2-prong/find-2-prong.ts +37 -14
  127. package/src/find-2-prong/get-medial/get-antipodal-points.ts +3 -2
  128. package/src/find-2-prong/get-medial/get-closest-points-d.ts +213 -0
  129. package/src/find-2-prong/get-medial/get-closest-points.ts +74 -13
  130. package/src/find-2-prong/reduce-radius.ts +8 -5
  131. package/src/find-3-prong/calc-better-x.ts +1 -3
  132. package/src/find-3-prong/calc-initial-3-prong-center.ts +1 -2
  133. package/src/find-3-prong/find-3-prong-for-delta3s.ts +1 -4
  134. package/src/find-3-prong/find-3-prong.ts +0 -1
  135. package/src/find-3-prong/find-and-add-3-prong.ts +1 -15
  136. package/src/find-mat/find-mat.ts +3 -2
  137. package/src/find-mat/find-mats.ts +0 -1
  138. package/src/find-mat/get-dull-corners-on-loop.ts +4 -3
  139. package/src/find-mat/get-for-1-prongs-on-loop.ts +8 -3
  140. package/src/find-mat/get-for-2-prongs-on-loop.ts +6 -1
  141. package/src/find-mat/get-meta.ts +14 -38
  142. package/src/find-mat/get-sharp-corners.ts +5 -1
  143. package/src/get-medial-curve/__pycache__/get-cubic-self-medial-curve.cpython-313.pyc +0 -0
  144. package/src/get-medial-curve/get-cubic-self-medial-curve.py +419 -0
  145. package/src/get-medial-points/double-double/dd-get-medial-point-coeffs-bez0-with-running-err.ts +76 -0
  146. package/src/get-medial-points/double-double/dd-get-medial-point-coeffs-bez0.ts +61 -0
  147. package/src/get-medial-points/double-double/dd-get-medial-point-coeffs-bez1.ts +116 -0
  148. package/src/get-medial-points/double-double/dd-get-medial-point-coeffs-bez2-same-curve.ts +129 -0
  149. package/src/get-medial-points/double-double/dd-get-medial-point-coeffs-bez2.ts +142 -0
  150. package/src/get-medial-points/double-double/dd-get-medial-point-coeffs-bez3-same-curve.ts +199 -0
  151. package/src/get-medial-points/double-double/dd-get-medial-point-coeffs-bez3.ts +177 -0
  152. package/src/get-medial-points/double-double/dd-get-medial-point-coeffs.ts +48 -0
  153. package/src/get-medial-points/double-double/error-bound-calc.txt +72 -0
  154. package/src/index.ts +7 -11
  155. package/src/point-on-shape/point-on-shape.ts +3 -0
  156. package/src/point-on-shape/to-p.ts +2 -2
  157. package/src/reconstruct-from-mat/get-cp-nodess-for-sat.ts +24 -0
  158. package/src/reconstruct-from-mat/reconstruct-from-mat.ts +226 -0
  159. package/src/reconstruct-from-mat/remove-sat-induced-trivial-3prongs.ts +62 -0
  160. package/src/sat/add-debug-info.ts +1 -2
  161. package/src/svg/get-loop-bounds.ts +11 -3
  162. package/src/utils/clip.ts +13 -0
  163. package/src/utils/map-deep.ts +75 -0
  164. package/src/utils/map-map.ts +33 -0
  165. package/wallaby.mjs +4 -4
  166. package/node/debug/debug-elem-types.d.ts +0 -26
  167. package/node/debug/debug-elem-types.js +0 -22
  168. package/node/debug/debug-elem-types.js.map +0 -1
  169. package/node/debug/functions/draw/draw-beziers-as-single-path.d.ts +0 -2
  170. package/node/debug/functions/draw/draw-beziers-as-single-path.js +0 -30
  171. package/node/debug/functions/draw/draw-beziers-as-single-path.js.map +0 -1
  172. package/node/debug/functions/draw/xmlns.d.ts +0 -2
  173. package/node/debug/functions/draw/xmlns.js +0 -3
  174. package/node/debug/functions/draw/xmlns.js.map +0 -1
  175. package/node/debug/functions/draw-elem/bounding-hull.d.ts +0 -3
  176. package/node/debug/functions/draw-elem/bounding-hull.js +0 -8
  177. package/node/debug/functions/draw-elem/bounding-hull.js.map +0 -1
  178. package/node/debug/functions/draw-elem/draw-branch.d.ts +0 -4
  179. package/node/debug/functions/draw-elem/draw-branch.js +0 -26
  180. package/node/debug/functions/draw-elem/draw-branch.js.map +0 -1
  181. package/node/debug/functions/draw-elem/draw-circle-percent.d.ts +0 -3
  182. package/node/debug/functions/draw-elem/draw-circle-percent.js +0 -13
  183. package/node/debug/functions/draw-elem/draw-circle-percent.js.map +0 -1
  184. package/node/debug/functions/draw-elem/draw-cp-node.d.ts +0 -4
  185. package/node/debug/functions/draw-elem/draw-cp-node.js +0 -26
  186. package/node/debug/functions/draw-elem/draw-cp-node.js.map +0 -1
  187. package/node/debug/functions/draw-elem/draw-cull.d.ts +0 -3
  188. package/node/debug/functions/draw-elem/draw-cull.js +0 -9
  189. package/node/debug/functions/draw-elem/draw-cull.js.map +0 -1
  190. package/node/debug/functions/draw-elem/draw-dull-corner.d.ts +0 -4
  191. package/node/debug/functions/draw-elem/draw-dull-corner.js +0 -10
  192. package/node/debug/functions/draw-elem/draw-dull-corner.js.map +0 -1
  193. package/node/debug/functions/draw-elem/draw-elem.d.ts +0 -10
  194. package/node/debug/functions/draw-elem/draw-elem.js +0 -39
  195. package/node/debug/functions/draw-elem/draw-elem.js.map +0 -1
  196. package/node/debug/functions/draw-elem/draw-leaves.d.ts +0 -4
  197. package/node/debug/functions/draw-elem/draw-leaves.js +0 -34
  198. package/node/debug/functions/draw-elem/draw-leaves.js.map +0 -1
  199. package/node/debug/functions/draw-elem/draw-loop.d.ts +0 -4
  200. package/node/debug/functions/draw-elem/draw-loop.js +0 -11
  201. package/node/debug/functions/draw-elem/draw-loop.js.map +0 -1
  202. package/node/debug/functions/draw-elem/draw-loops.d.ts +0 -4
  203. package/node/debug/functions/draw-elem/draw-loops.js +0 -6
  204. package/node/debug/functions/draw-elem/draw-loops.js.map +0 -1
  205. package/node/debug/functions/draw-elem/draw-loose-bounding-box.d.ts +0 -3
  206. package/node/debug/functions/draw-elem/draw-loose-bounding-box.js +0 -10
  207. package/node/debug/functions/draw-elem/draw-loose-bounding-box.js.map +0 -1
  208. package/node/debug/functions/draw-elem/draw-mat.d.ts +0 -4
  209. package/node/debug/functions/draw-elem/draw-mat.js +0 -34
  210. package/node/debug/functions/draw-elem/draw-mat.js.map +0 -1
  211. package/node/debug/functions/draw-elem/draw-max-vertex.d.ts +0 -4
  212. package/node/debug/functions/draw-elem/draw-max-vertex.js +0 -9
  213. package/node/debug/functions/draw-elem/draw-max-vertex.js.map +0 -1
  214. package/node/debug/functions/draw-elem/draw-min-y.d.ts +0 -4
  215. package/node/debug/functions/draw-elem/draw-min-y.js +0 -10
  216. package/node/debug/functions/draw-elem/draw-min-y.js.map +0 -1
  217. package/node/debug/functions/draw-elem/draw-one-prong-at-dull-corner.d.ts +0 -4
  218. package/node/debug/functions/draw-elem/draw-one-prong-at-dull-corner.js +0 -22
  219. package/node/debug/functions/draw-elem/draw-one-prong-at-dull-corner.js.map +0 -1
  220. package/node/debug/functions/draw-elem/draw-one-prong.d.ts +0 -4
  221. package/node/debug/functions/draw-elem/draw-one-prong.js +0 -13
  222. package/node/debug/functions/draw-elem/draw-one-prong.js.map +0 -1
  223. package/node/debug/functions/draw-elem/draw-sharp-corner.d.ts +0 -4
  224. package/node/debug/functions/draw-elem/draw-sharp-corner.js +0 -10
  225. package/node/debug/functions/draw-elem/draw-sharp-corner.js.map +0 -1
  226. package/node/debug/functions/draw-elem/draw-three-prong.d.ts +0 -4
  227. package/node/debug/functions/draw-elem/draw-three-prong.js +0 -26
  228. package/node/debug/functions/draw-elem/draw-three-prong.js.map +0 -1
  229. package/node/debug/functions/draw-elem/draw-tight-bounding-box.d.ts +0 -3
  230. package/node/debug/functions/draw-elem/draw-tight-bounding-box.js +0 -8
  231. package/node/debug/functions/draw-elem/draw-tight-bounding-box.js.map +0 -1
  232. package/node/debug/functions/draw-elem/draw-two-prong.d.ts +0 -4
  233. package/node/debug/functions/draw-elem/draw-two-prong.js +0 -49
  234. package/node/debug/functions/draw-elem/draw-two-prong.js.map +0 -1
  235. package/node/debug/functions/draw-elem/draw-vertex.d.ts +0 -4
  236. package/node/debug/functions/draw-elem/draw-vertex.js +0 -13
  237. package/node/debug/functions/draw-elem/draw-vertex.js.map +0 -1
  238. package/node/debug/functions/general.d.ts +0 -48
  239. package/node/debug/functions/general.js +0 -53
  240. package/node/debug/functions/general.js.map +0 -1
  241. package/node/find-3-prong/timed-cc.d.ts +0 -3
  242. package/node/find-3-prong/timed-cc.js +0 -5
  243. package/node/find-3-prong/timed-cc.js.map +0 -1
  244. package/node/point-on-shape/pos-to-human-string.d.ts +0 -8
  245. package/node/point-on-shape/pos-to-human-string.js +0 -12
  246. package/node/point-on-shape/pos-to-human-string.js.map +0 -1
  247. package/node/utils/time-function-call.d.ts +0 -14
  248. package/node/utils/time-function-call.js +0 -32
  249. package/node/utils/time-function-call.js.map +0 -1
  250. package/src/debug/debug-elem-types.ts +0 -43
  251. package/src/debug/elem-type-two-prong.ts +0 -8
  252. package/src/debug/functions/cmp-cp-on-delta.ts +0 -54
  253. package/src/debug/functions/draw-elem/bounding-hull.ts +0 -18
  254. package/src/debug/functions/draw-elem/culls.ts +0 -39
  255. package/src/debug/functions/draw-elem/draw-branch.ts +0 -37
  256. package/src/debug/functions/draw-elem/draw-circle-percent.ts +0 -23
  257. package/src/debug/functions/draw-elem/draw-cp-node.ts +0 -46
  258. package/src/debug/functions/draw-elem/draw-cull.ts +0 -21
  259. package/src/debug/functions/draw-elem/draw-dull-corner.ts +0 -21
  260. package/src/debug/functions/draw-elem/draw-elem.ts +0 -64
  261. package/src/debug/functions/draw-elem/draw-leaves.ts +0 -51
  262. package/src/debug/functions/draw-elem/draw-loop.ts +0 -16
  263. package/src/debug/functions/draw-elem/draw-loops.ts +0 -10
  264. package/src/debug/functions/draw-elem/draw-loose-bounding-box.ts +0 -21
  265. package/src/debug/functions/draw-elem/draw-mat.ts +0 -43
  266. package/src/debug/functions/draw-elem/draw-max-vertex.ts +0 -15
  267. package/src/debug/functions/draw-elem/draw-min-y.ts +0 -18
  268. package/src/debug/functions/draw-elem/draw-one-prong-at-dull-corner.ts +0 -40
  269. package/src/debug/functions/draw-elem/draw-one-prong.ts +0 -25
  270. package/src/debug/functions/draw-elem/draw-sharp-corner.ts +0 -21
  271. package/src/debug/functions/draw-elem/draw-three-prong.ts +0 -44
  272. package/src/debug/functions/draw-elem/draw-tight-bounding-box.ts +0 -18
  273. package/src/debug/functions/draw-elem/draw-two-prong.ts +0 -68
  274. package/src/debug/functions/draw-elem/draw-vertex.ts +0 -27
  275. package/src/debug/functions/draw-elem/dull-corner.ts +0 -21
  276. package/src/debug/functions/draw-elem/leaves.ts +0 -20
  277. package/src/debug/functions/draw-elem/loop.ts +0 -16
  278. package/src/debug/functions/draw-elem/loops.ts +0 -10
  279. package/src/debug/functions/draw-elem/loose-bounding-box.ts +0 -21
  280. package/src/debug/functions/draw-elem/mat.ts +0 -47
  281. package/src/debug/functions/draw-elem/max-vertex.ts +0 -15
  282. package/src/debug/functions/draw-elem/min-y.ts +0 -18
  283. package/src/debug/functions/draw-elem/one-prong-at-dull-corner.ts +0 -26
  284. package/src/debug/functions/draw-elem/one-prong.ts +0 -23
  285. package/src/debug/functions/draw-elem/sharp-corner.ts +0 -20
  286. package/src/debug/functions/draw-elem/three-prong.ts +0 -30
  287. package/src/debug/functions/draw-elem/tight-bounding-box.ts +0 -18
  288. package/src/debug/functions/draw-elem/two-prong.ts +0 -50
  289. package/src/debug/functions/draw-elem/vertex.ts +0 -51
  290. package/src/debug/functions/general.ts +0 -79
  291. package/src/debug/functions/three-prong.ts +0 -249
  292. package/src/debug/functions/two-prong.ts +0 -203
  293. package/src/find-2-prong/add-debug-info.ts +0 -45
  294. package/src/find-3-prong/timed-cc.ts +0 -9
@@ -0,0 +1,419 @@
1
+ """
2
+ Pure symbolic setup for the cubic planar parametric self-medial problem.
3
+
4
+ This file intentionally performs no numeric calculations.
5
+ It derives polynomial equations in symbolic parameters only.
6
+
7
+ Core idea (self-contact pair on one cubic r(u) = (X(u), Y(u))):
8
+ 1. Use two parameters t and s on the same cubic, and an unknown medial point m.
9
+ 2. Use two separate spoke vectors:
10
+ v_t = r(t) - m
11
+ v_s = r(s) - m
12
+ 3. Enforce orthogonality at both contacts:
13
+ v_t . r'(t) = 0
14
+ v_s . r'(s) = 0
15
+ 4. Enforce equal spoke lengths (equal-radius condition):
16
+ |v_t|^2 - |v_s|^2 = 0
17
+ 5. Remove the trivial branch t = s.
18
+
19
+ These polynomial constraints define the nontrivial self-medial relation.
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ from sympy import Matrix, Poly, expand, fraction, simplify, symbols
25
+
26
+
27
+ SymPoint = Matrix
28
+
29
+
30
+ def cubic_power_point_sym(cx, cy, u):
31
+ """
32
+ Return the symbolic point r(u) = (X(u), Y(u)) in power basis.
33
+
34
+ Parameters:
35
+ - cx: coefficients [x0, x1, x2, x3] for X(u)=x0+x1*u+x2*u^2+x3*u^3.
36
+ - cy: coefficients [y0, y1, y2, y3] for Y(u)=y0+y1*u+y2*u^2+y3*u^3.
37
+ - u: symbolic parameter.
38
+
39
+ Returns:
40
+ - A 2D SymPy column vector representing r(u).
41
+ """
42
+ x0, x1, x2, x3 = cx
43
+ y0, y1, y2, y3 = cy
44
+ xu = x0 + x1*u + x2*(u**2) + x3*(u**3)
45
+ yu = y0 + y1*u + y2*(u**2) + y3*(u**3)
46
+ return Matrix([xu, yu])
47
+
48
+
49
+ def cubic_power_d1_sym(cx, cy, u):
50
+ """
51
+ Return the symbolic first derivative r'(u) in power basis.
52
+
53
+ Parameters:
54
+ - cx: coefficients [x0, x1, x2, x3] of X(u).
55
+ - cy: coefficients [y0, y1, y2, y3] of Y(u).
56
+ - u: symbolic parameter.
57
+
58
+ Returns:
59
+ - A 2D SymPy column vector representing r'(u).
60
+ """
61
+ _, x1, x2, x3 = cx
62
+ _, y1, y2, y3 = cy
63
+ dx = x1 + 2*x2*u + 3*x3*(u**2)
64
+ dy = y1 + 2*y2*u + 3*y3*(u**2)
65
+ return Matrix([dx, dy])
66
+
67
+
68
+ def dot2(a: SymPoint, b: SymPoint):
69
+ return a[0]*b[0] + a[1]*b[1]
70
+
71
+
72
+ def orthogonality_equations(cx, cy, t, s, m: SymPoint):
73
+ """
74
+ Build the two orthogonality equations for a self-contact pair.
75
+
76
+ Equations:
77
+ - (r(t) - m) . r'(t) = 0
78
+ - (r(s) - m) . r'(s) = 0
79
+ """
80
+ rt = cubic_power_point_sym(cx, cy, t)
81
+ rs = cubic_power_point_sym(cx, cy, s)
82
+ d1t = cubic_power_d1_sym(cx, cy, t)
83
+ d1s = cubic_power_d1_sym(cx, cy, s)
84
+
85
+ vt = rt - m
86
+ vs = rs - m
87
+
88
+ e_ortho_t = simplify(dot2(vt, d1t))
89
+ e_ortho_s = simplify(dot2(vs, d1s))
90
+
91
+ return e_ortho_t, e_ortho_s
92
+
93
+
94
+ def equal_length_equation(cx, cy, t, s, m: SymPoint):
95
+ """
96
+ Build the equal-length spoke equation for a self-contact pair.
97
+
98
+ Equation:
99
+ - |r(t) - m|^2 - |r(s) - m|^2 = 0
100
+ """
101
+ rt = cubic_power_point_sym(cx, cy, t)
102
+ rs = cubic_power_point_sym(cx, cy, s)
103
+
104
+ vt = rt - m
105
+ vs = rs - m
106
+
107
+ return simplify(dot2(vt, vt) - dot2(vs, vs))
108
+
109
+
110
+ def self_medial_equation_system(cx, cy, t, s, m: SymPoint):
111
+ """
112
+ Return the core symbolic self-medial system {E_t, E_s, E_l}.
113
+
114
+ Where:
115
+ - E_t := (r(t) - m) . r'(t)
116
+ - E_s := (r(s) - m) . r'(s)
117
+ - E_l := |r(t) - m|^2 - |r(s) - m|^2
118
+ """
119
+ e_t, e_s = orthogonality_equations(cx, cy, t, s, m)
120
+ e_l = equal_length_equation(cx, cy, t, s, m)
121
+ return {
122
+ "E_t": simplify(e_t),
123
+ "E_s": simplify(e_s),
124
+ "E_l": simplify(e_l),
125
+ }
126
+
127
+
128
+ def _linear_coeffs_in_m(expr, mx, my):
129
+ """Return coefficients (a, b, c) for a*mx + b*my + c from expr."""
130
+ p = Poly(expr, mx, my)
131
+ a = p.coeff_monomial(mx)
132
+ b = p.coeff_monomial(my)
133
+ c = p.coeff_monomial(1)
134
+ return a, b, c
135
+
136
+
137
+ def eliminate_medial_point(system, mx, my):
138
+ """
139
+ First elimination step: remove mx,my from {E_t,E_s,E_l}.
140
+
141
+ Strategy:
142
+ - E_t and E_s are linear in mx,my.
143
+ - Solve E_t=0 and E_s=0 symbolically for mx,my via Cramer's rule.
144
+ - Substitute into E_l to get a reduced relation in t,s and curve coefficients.
145
+
146
+ Returns:
147
+ - det_m: determinant of the 2x2 linear system in (mx,my)
148
+ - mx_expr, my_expr: symbolic solutions for mx,my
149
+ - E_l_reduced: E_l after substitution
150
+ """
151
+ e_t = system["E_t"]
152
+ e_s = system["E_s"]
153
+ e_l = system["E_l"]
154
+
155
+ a_t, b_t, c_t = _linear_coeffs_in_m(e_t, mx, my)
156
+ a_s, b_s, c_s = _linear_coeffs_in_m(e_s, mx, my)
157
+
158
+ det_m = a_t*b_s - a_s*b_t
159
+
160
+ mx_expr = (b_t*c_s - b_s*c_t) / det_m
161
+ my_expr = (a_s*c_t - a_t*c_s) / det_m
162
+
163
+ e_l_reduced = e_l.subs({mx: mx_expr, my: my_expr})
164
+
165
+ return {
166
+ "det_m": simplify(det_m),
167
+ "mx_expr": simplify(mx_expr),
168
+ "my_expr": simplify(my_expr),
169
+ "E_l_reduced": simplify(e_l_reduced),
170
+ }
171
+
172
+
173
+ def reduced_ts_polynomial_data(elim1, t, s):
174
+ """
175
+ Summarize the reduced t,s relation after eliminating mx,my.
176
+
177
+ Returns:
178
+ - N_ts: denominator-cleared numerator of E_l_reduced
179
+ - deg_t_N, deg_s_N: polynomial degrees of N_ts in t and s
180
+ - generic_branch_condition: det_m != 0
181
+ """
182
+ n_ts, d_ts = fraction(simplify(elim1["E_l_reduced"]))
183
+ n_ts = simplify(n_ts)
184
+
185
+ return {
186
+ "N_ts": n_ts,
187
+ "D_ts": simplify(d_ts),
188
+ "deg_t_N": poly_degree(n_ts, t),
189
+ "deg_s_N": poly_degree(n_ts, s),
190
+ "generic_branch_condition": simplify(elim1["det_m"]),
191
+ }
192
+
193
+
194
+ def extract_t_minus_s_factor(n_ts, t, s):
195
+ """
196
+ Step 5.5: expand N(t,s) and deflate any (t-s)^k factor.
197
+
198
+ Returns:
199
+ - N_expanded: expanded polynomial expression
200
+ - ts_multiplicity: largest k with (t-s)^k dividing N
201
+ - N_deflated: N / (t-s)^k
202
+ - deg_t_deflated, deg_s_deflated
203
+ """
204
+ n_expanded = expand(simplify(n_ts))
205
+
206
+ p = Poly(n_expanded, t, s)
207
+ ts = Poly(t - s, t, s)
208
+
209
+ q = p
210
+ multiplicity = 0
211
+ while True:
212
+ qq, rr = q.div(ts)
213
+ if rr.is_zero:
214
+ q = qq
215
+ multiplicity += 1
216
+ else:
217
+ break
218
+
219
+ n_deflated = simplify(q.as_expr())
220
+
221
+ return {
222
+ "N_expanded": n_expanded,
223
+ "ts_multiplicity": multiplicity,
224
+ "N_deflated": n_deflated,
225
+ "deg_t_deflated": q.degree(t),
226
+ "deg_s_deflated": q.degree(s),
227
+ }
228
+
229
+
230
+ def get_degree5_ts_polynomial():
231
+ """
232
+ Build and return the deflated self-medial relation polynomial in (t,s).
233
+
234
+ For the generic cubic power basis setup in this file, the returned
235
+ polynomial is the Step-5 numerator with the trivial (t-s)^k factor removed.
236
+ In the current symbolic setup this yields a degree-5 in t and degree-5 in s
237
+ polynomial (generic branch).
238
+ """
239
+ x0, x1, x2, x3 = symbols("x0 x1 x2 x3", real=True)
240
+ y0, y1, y2, y3 = symbols("y0 y1 y2 y3", real=True)
241
+ t, s = symbols("t s", real=True)
242
+ mx, my = symbols("mx my", real=True)
243
+
244
+ cx = [x0, x1, x2, x3]
245
+ cy = [y0, y1, y2, y3]
246
+ m = Matrix([mx, my])
247
+
248
+ system = self_medial_equation_system(cx, cy, t, s, m)
249
+ elim1 = eliminate_medial_point(system, mx, my)
250
+ reduced = reduced_ts_polynomial_data(elim1, t, s)
251
+ ts_deflate = extract_t_minus_s_factor(reduced["N_ts"], t, s)
252
+
253
+ return {
254
+ "t": t,
255
+ "s": s,
256
+ "coeffs_x": (x0, x1, x2, x3),
257
+ "coeffs_y": (y0, y1, y2, y3),
258
+ "det_m": reduced["generic_branch_condition"],
259
+ "ts_multiplicity": ts_deflate["ts_multiplicity"],
260
+ "P5": ts_deflate["N_deflated"],
261
+ "deg_t": ts_deflate["deg_t_deflated"],
262
+ "deg_s": ts_deflate["deg_s_deflated"],
263
+ }
264
+
265
+
266
+ def step7_symbolic_mapping_data():
267
+ """
268
+ Step 7 symbolic post-processing stub (no numerics).
269
+
270
+ This function packages the symbolic objects needed after obtaining P5:
271
+ 1. Parameter-space relation: P5(t,s) = 0
272
+ 2. Branch constraints:
273
+ - det_m(t,s) != 0
274
+ - t - s != 0 (nontrivial branch)
275
+ 3. Reconstruction map from parameter pairs to medial points:
276
+ (t,s) -> (mx(t,s), my(t,s))
277
+
278
+ It does not solve P5 or evaluate any numeric roots.
279
+ """
280
+ x0, x1, x2, x3 = symbols("x0 x1 x2 x3", real=True)
281
+ y0, y1, y2, y3 = symbols("y0 y1 y2 y3", real=True)
282
+ t, s = symbols("t s", real=True)
283
+ mx, my = symbols("mx my", real=True)
284
+
285
+ cx = [x0, x1, x2, x3]
286
+ cy = [y0, y1, y2, y3]
287
+ m = Matrix([mx, my])
288
+
289
+ system = self_medial_equation_system(cx, cy, t, s, m)
290
+ elim1 = eliminate_medial_point(system, mx, my)
291
+ reduced = reduced_ts_polynomial_data(elim1, t, s)
292
+ ts_deflate = extract_t_minus_s_factor(reduced["N_ts"], t, s)
293
+
294
+ return {
295
+ "t": t,
296
+ "s": s,
297
+ "coeffs_x": (x0, x1, x2, x3),
298
+ "coeffs_y": (y0, y1, y2, y3),
299
+ "P5": ts_deflate["N_deflated"],
300
+ "deg_t_P5": ts_deflate["deg_t_deflated"],
301
+ "deg_s_P5": ts_deflate["deg_s_deflated"],
302
+ "trivial_factor_multiplicity": ts_deflate["ts_multiplicity"],
303
+ "constraint_det_nonzero": reduced["generic_branch_condition"],
304
+ "constraint_t_minus_s_nonzero": t - s,
305
+ "mx_of_ts": elim1["mx_expr"],
306
+ "my_of_ts": elim1["my_expr"],
307
+ }
308
+
309
+
310
+ def normalize_reduced_numerator(n_ts, t, s):
311
+ """
312
+ Remove obvious repeated factors from N(t,s).
313
+
314
+ This keeps only the primitive square-free part in Q[coeffs][t,s].
315
+ """
316
+ p = Poly(simplify(n_ts), t, s)
317
+ content, primitive = p.primitive()
318
+ sqf = primitive.sqf_part()
319
+
320
+ return {
321
+ "content": simplify(content),
322
+ "N_primitive": simplify(primitive.as_expr()),
323
+ "N_sqf": simplify(sqf.as_expr()),
324
+ "deg_t_sqf": sqf.degree(t),
325
+ "deg_s_sqf": sqf.degree(s),
326
+ "repeated_factor_removed": sqf.total_degree() < primitive.total_degree(),
327
+ }
328
+
329
+
330
+ def poly_degree(expr, var):
331
+ return Poly(simplify(expr), var).degree()
332
+
333
+
334
+
335
+ def _demo_symbolic(*, run_step6: bool = False) -> None:
336
+ # Generic cubic power basis:
337
+ # X(u)=x0+x1*u+x2*u^2+x3*u^3, Y(u)=y0+y1*u+y2*u^2+y3*u^3
338
+ x0, x1, x2, x3 = symbols("x0 x1 x2 x3", real=True)
339
+ y0, y1, y2, y3 = symbols("y0 y1 y2 y3", real=True)
340
+ t, s = symbols("t s", real=True)
341
+ mx, my = symbols("mx my", real=True)
342
+
343
+ cx = [x0, x1, x2, x3]
344
+ cy = [y0, y1, y2, y3]
345
+
346
+ m = Matrix([mx, my])
347
+ e_ortho_t, e_ortho_s = orthogonality_equations(cx, cy, t, s, m)
348
+ e_equal = equal_length_equation(cx, cy, t, s, m)
349
+ system = self_medial_equation_system(cx, cy, t, s, m)
350
+ elim1 = eliminate_medial_point(system, mx, my)
351
+ reduced = reduced_ts_polynomial_data(elim1, t, s)
352
+ ts_deflate = extract_t_minus_s_factor(reduced["N_ts"], t, s)
353
+ degree5 = get_degree5_ts_polynomial()
354
+ normalized = None
355
+ if run_step6:
356
+ normalized = normalize_reduced_numerator(ts_deflate["N_deflated"], t, s)
357
+
358
+ print("Step 1: Orthogonality equations")
359
+ print("(r(t)-m) . r'(t) =", e_ortho_t)
360
+ print("(r(s)-m) . r'(s) =", e_ortho_s)
361
+ print()
362
+
363
+ print("Step 2: Equal-length equation")
364
+ print("|r(t)-m|^2 - |r(s)-m|^2 =", e_equal)
365
+ print()
366
+
367
+ print("Step 3: Packaged symbolic system {E_t, E_s, E_l}")
368
+ print("E_t =", system["E_t"])
369
+ print("E_s =", system["E_s"])
370
+ print("E_l =", system["E_l"])
371
+ print()
372
+
373
+ print("Step 4: First elimination (remove mx,my)")
374
+ print("det_m =", elim1["det_m"])
375
+ print("mx(t,s) =", elim1["mx_expr"])
376
+ print("my(t,s) =", elim1["my_expr"])
377
+ print("E_l after substitution =", elim1["E_l_reduced"])
378
+ print()
379
+
380
+ print("Step 5: Reduced single relation data")
381
+ print("N(t,s) (numerator after clearing denominator) =", reduced["N_ts"])
382
+ print("deg_t N =", reduced["deg_t_N"])
383
+ print("deg_s N =", reduced["deg_s_N"])
384
+ print("generic branch condition: det_m != 0, where det_m =", reduced["generic_branch_condition"])
385
+ print()
386
+
387
+ print("Step 5.5: (t-s) deflation")
388
+ print("(t-s) multiplicity in N =", ts_deflate["ts_multiplicity"])
389
+ print("deg_t N_deflated =", ts_deflate["deg_t_deflated"])
390
+ print("deg_s N_deflated =", ts_deflate["deg_s_deflated"])
391
+ print()
392
+
393
+ print("Final deflated polynomial for future work")
394
+ print("P5(t,s) =", degree5["P5"])
395
+ print()
396
+
397
+ print("Step 7: Symbolic mapping stub")
398
+ print("Use step7_symbolic_mapping_data() to get:")
399
+ print("- P5(t,s)=0 in parameter space")
400
+ print("- constraints det_m!=0 and t-s!=0")
401
+ print("- reconstruction map (t,s)->(mx(t,s), my(t,s))")
402
+
403
+ if run_step6:
404
+ print("Step 6: Normalized reduced numerator")
405
+ print("(applied to N_deflated)")
406
+ print("content(N) =", normalized["content"])
407
+ print("repeated factors removed =", normalized["repeated_factor_removed"])
408
+ print("deg_t N_sqf =", normalized["deg_t_sqf"])
409
+ print("deg_s N_sqf =", normalized["deg_s_sqf"])
410
+ else:
411
+ print("Step 6: Normalized reduced numerator")
412
+ print("Skipped by default (can be expensive on fully generic coefficients).")
413
+ print("To run it, call _demo_symbolic(run_step6=True).")
414
+
415
+ print()
416
+
417
+
418
+ if __name__ == "__main__":
419
+ _demo_symbolic()
@@ -0,0 +1,76 @@
1
+ // import { ddAddDd, ddMultDd, ddMultBy2, ddDiffDouble } from 'double-double';
2
+
3
+ // const { abs } = Math;
4
+
5
+ // const qaq = ddAddDd;
6
+ // const qmq = ddMultDd;
7
+ // const qm2 = ddMultBy2;
8
+ // const qdd = ddDiffDouble;
9
+
10
+
11
+ // // TODO - move all these back to flo-bezier3
12
+ // // TODO - finish
13
+
14
+ // /**
15
+ // * Returns the coefficients `a0` and `b0` for the linear equation
16
+ // * `a0⋅t + b0 = 0`, so the ray parameter can be recovered as `t = -b0/a0`.
17
+ // * That parameter value makes `q(t) = p + t⋅v` equidistant from `p` and `P`.
18
+ // *
19
+ // * Let `p` be a fixed point in the plane.\
20
+ // * Let `v` be a direction vector defining the ray `q(t) = p + t⋅v`.\
21
+ // * Let `P` be another point.\
22
+ // *
23
+ // * In other words, this function returns the coefficients needed to solve for
24
+ // * the ray parameter of the medial point on the ray.
25
+ // *
26
+ // * @param p base point
27
+ // * @param v ray direction from `p`
28
+ // * @param P another "target" point, e.g. `[1,2]`
29
+ // */
30
+ // function ddGetMedialPointCoeffsBez0_WithRunningError(
31
+ // p: number[][],
32
+ // v: number[][],
33
+ // P: number[]) {
34
+
35
+ // // -----------------------------------------------------
36
+ // // See get-medial-points.md for implementation details.
37
+ // // -----------------------------------------------------
38
+ // // See error-bound-calc.txt
39
+ // // -----------------------------------------------------
40
+
41
+ // const [px, py] = p;
42
+ // const [vx, vy] = v;
43
+ // const [x0, y0] = P;
44
+
45
+ // // Constant bezier in power basis: b(s) = c
46
+ // // u(s) = p - b(s) = u0
47
+
48
+ // const $px = px[0] + px[1];
49
+ // const $py = py[0] + py[1];
50
+ // const $vx = vx[0] + vx[1];
51
+ // const $vy = vy[0] + vy[1];
52
+
53
+ // const $u0x = $px - x0;
54
+ // const _u0x = abs($u0x);
55
+ // // const u0x_ = px_
56
+
57
+ // const $u0y = $py - y0;
58
+ // const _u0y = abs($u0y);
59
+
60
+ // const u0x = qdd(px,x0);
61
+ // const u0y = qdd(py,y0);
62
+
63
+ // // E2(s,t): |t⋅v|² - |u(s) + t⋅v|² = 0
64
+ // // => 2⋅(v⋅u(s))⋅t + |u(s)|² = 0
65
+ // // => A(s)⋅t + B(s) = 0
66
+
67
+ // // const a0 = 2*(vx*u0x + vy*u0y);
68
+ // // const b0 = u0x*u0x + u0y*u0y;
69
+ // const a0 = qaq(qmq(qm2(vx),u0x),qmq(qm2(vy),u0y));
70
+ // const b0 = qaq(qmq(u0x,u0x), qmq(u0y,u0y));
71
+
72
+ // return { a0, b0 };
73
+ // }
74
+
75
+
76
+ // export { ddGetMedialPointCoeffsBez0_WithRunningError }
@@ -0,0 +1,61 @@
1
+ import { ddAddDd, ddMultDd, ddMultBy2, ddDiffDouble } from 'double-double';
2
+
3
+ const qaq = ddAddDd;
4
+ const qmq = ddMultDd;
5
+ const qm2 = ddMultBy2;
6
+ const qdd = ddDiffDouble;
7
+
8
+
9
+ // TODO - move all these upstream to flo-bezier3
10
+
11
+ /**
12
+ * Returns the coefficients `a0` and `b0` for the linear equation
13
+ * `a0⋅t + b0 = 0`, so the ray parameter can be recovered as `t = -b0/a0`.
14
+ * That parameter value makes `q(t) = p + t⋅v` equidistant from `p` and `P`.
15
+ *
16
+ * Let `p` be a fixed point in the plane.\
17
+ * Let `v` be a direction vector defining the ray `q(t) = p + t⋅v`.\
18
+ * Let `P` be another point.\
19
+ *
20
+ * In other words, this function returns the coefficients needed to solve for
21
+ * the ray parameter of the medial point on the ray.
22
+ *
23
+ * @param p base point
24
+ * @param v ray direction from `p`
25
+ * @param P another "target" point, e.g. `[1,2]`
26
+ */
27
+ function ddGetMedialPointCoeffsBez0(
28
+ p: number[][],
29
+ v: number[][],
30
+ P: number[]) {
31
+
32
+ // -----------------------------------------------------
33
+ // See get-medial-points.md for implementation details.
34
+ // -----------------------------------------------------
35
+
36
+ const [px, py] = p;
37
+ const [vx, vy] = v;
38
+ const [x0, y0] = P;
39
+
40
+ // Constant bezier in power basis: b(s) = c
41
+ // u(s) = p - b(s) = u0
42
+
43
+ // const u0x = px - x0;
44
+ // const u0y = py - y0;
45
+ const u0x = qdd(px,x0);
46
+ const u0y = qdd(py,y0);
47
+
48
+ // E2(s,t): |t⋅v|² - |u(s) + t⋅v|² = 0
49
+ // => 2⋅(v⋅u(s))⋅t + |u(s)|² = 0
50
+ // => A(s)⋅t + B(s) = 0
51
+
52
+ // const a0 = 2*(vx*u0x + vy*u0y);
53
+ // const b0 = u0x*u0x + u0y*u0y;
54
+ const a0 = qaq(qmq(qm2(vx),u0x),qmq(qm2(vy),u0y));
55
+ const b0 = qaq(qmq(u0x,u0x), qmq(u0y,u0y));
56
+
57
+ return { a0, b0 };
58
+ }
59
+
60
+
61
+ export { ddGetMedialPointCoeffsBez0 }
@@ -0,0 +1,116 @@
1
+ import { twoDiff, ddAddDd, ddMultDd, ddNegativeOf, ddMultByNeg2, ddDiffDouble, ddMultBy2 } from 'double-double';
2
+
3
+ const td = twoDiff;
4
+ const qaq = ddAddDd;
5
+ const qmq = ddMultDd;
6
+ const qno = ddNegativeOf;
7
+ const qmn2 = ddMultByNeg2;
8
+ const qm2 = ddMultBy2;
9
+ const qdd = ddDiffDouble;
10
+
11
+
12
+ /**
13
+ * Returns the polynomial coefficients used to recover ray parameter values `t`
14
+ * for a ray `q(t) = p + t⋅v` and an order-1 bezier curve `ps`.
15
+ *
16
+ * The returned polynomials encode the medial-condition equations in `s` and
17
+ * `t`. For any valid solution, `t` is recovered by eliminating `s` and solving
18
+ * the resulting ray equation, or equivalently by using the linear form
19
+ * `A(s)⋅t + B(s) = 0`, which gives `t = -B(s)/A(s)`.
20
+ *
21
+ * More specifically, the returned values represent:
22
+ * * `A` and `B`: the coefficients of `E2(s,t) = A(s)⋅t + B(s)`
23
+ * * `C` and `D`: the coefficients of `E1(s,t) = C(s)⋅t + D(s)`
24
+ * * `H`: the eliminated polynomial `A(s)⋅D(s) - B(s)⋅C(s)` whose roots are
25
+ * candidate `s` values for medial points
26
+ *
27
+ * @param p base point
28
+ * @param v ray direction vector starting from `p`
29
+ * @param ps order 1 bezier control points, i.e. a line segment
30
+ * given as an array of control points, e.g. `[[0,0],[2,1]]`
31
+ */
32
+ function ddGetMedialPointCoeffsBez1(
33
+ p: number[][],
34
+ v: number[][],
35
+ ps: number[][]) {
36
+
37
+ // -----------------------------------------------------
38
+ // See get-medial-points.md for implementation details.
39
+ // -----------------------------------------------------
40
+ const [px, py] = p;
41
+ const [vx, vy] = v;
42
+ const [[x0, y0], [x1, y1]] = ps;
43
+
44
+ // Linear bezier in power basis: b(s) = b*s + c
45
+ // We can also use: `const [[bx,by], [cx,cy]] = toPowerBasis1(ps)`
46
+ // const bx = x1 - x0;
47
+ // const by = y1 - y0;
48
+ const bx = td(x1,x0);
49
+ const by = td(y1,y0);
50
+
51
+ // u(s) = p - b(s) = u1*s + u0
52
+ // const u0x = px - x0;
53
+ // const u0y = py - y0;
54
+ const u0x = qdd(px,x0);
55
+ const u0y = qdd(py,y0);
56
+
57
+ // b'(s) = w(s) = w0
58
+
59
+ // -----------------------------------------------------
60
+ // E1(s,t): (u(s) + t⋅v) ⋅ b'(s) = 0
61
+ // => C(s)⋅t + D(s) = 0
62
+ // const c0 = vx*bx + vy*by;
63
+ const c0 = qaq(qmq(vx,bx),qmq(vy,by));
64
+ // -----------------------------------------------------
65
+
66
+ // -----------------------------------------------------
67
+ // const d1 = -(bx*bx + by*by);
68
+ // const d0 = bx*u0x + by*u0y;
69
+ // const d1 = qmd(-1,qaq(qmq(bx,bx),qmq(by,by)));
70
+ const d1 = qno(qaq(qmq(bx,bx), qmq(by,by)));
71
+ const d0 = qaq(qmq(bx,u0x), qmq(by,u0y));
72
+ // -----------------------------------------------------
73
+
74
+ // -----------------------------------------------------
75
+ // E2(s,t): |t⋅v|² - |u(s) + t⋅v|² = 0
76
+ // => 2⋅(v⋅u(s))⋅t + |u(s)|² = 0
77
+ // => A(s)⋅t + B(s) = 0
78
+ // const a1 = -2*c0;
79
+ // const a0 = 2*(vx*u0x + vy*u0y);
80
+ const a1 = qmn2(c0);
81
+ const a0 = qaq(qmq(qm2(vx),u0x), qmq(qm2(vy),u0y));
82
+ // -----------------------------------------------------
83
+
84
+ // -----------------------------------------------------
85
+ // const b2 = -d1;
86
+ // const b1 = -2*d0;
87
+ // const b0 = u0x*u0x + u0y*u0y;
88
+ const b2 = qno(d1);
89
+ const b1 = qmn2(d0);
90
+ const b0 = qaq(qmq(u0x,u0x), qmq(u0y,u0y));
91
+ // -----------------------------------------------------
92
+
93
+
94
+ // Eliminate t from:
95
+ // A(s)⋅t + B(s) = 0
96
+ // C(s)⋅t + D(s) = 0
97
+ // by taking A(s)⋅D(s) - B(s)⋅C(s) = 0 (degree ≤ 2 in s)
98
+
99
+ // const H2 = b2*c0;
100
+ // const H1 = a0*d1;
101
+ // const H0 = a0*d0 - b0*c0;
102
+ const H2 = qmq(b2,c0);
103
+ const H1 = qmq(a0,d1);
104
+ const H0 = qaq(qmq(a0,d0), qno(qmq(b0,c0)));
105
+
106
+ return {
107
+ A: [a1, a0],
108
+ B: [b2, b1, b0],
109
+ C: [c0],
110
+ D: [d1, d0],
111
+ H: [H2, H1, H0]
112
+ };
113
+ }
114
+
115
+
116
+ export { ddGetMedialPointCoeffsBez1 }