flo-mat 2.0.2 → 2.0.4

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 (216) hide show
  1. package/browser/index.js +8409 -8358
  2. package/browser/index.min.js +1 -1
  3. package/node/circle.d.ts +20 -20
  4. package/node/circle.js +31 -31
  5. package/node/compare-curvatures-at-interface.d.ts +19 -19
  6. package/node/compare-curvatures-at-interface.js +124 -124
  7. package/node/contact-point.d.ts +26 -26
  8. package/node/contact-point.js +25 -25
  9. package/node/cp-node/clone.d.ts +8 -8
  10. package/node/cp-node/clone.js +31 -31
  11. package/node/cp-node/remove.d.ts +9 -9
  12. package/node/cp-node/remove.js +19 -19
  13. package/node/cp-node.d.ts +202 -202
  14. package/node/cp-node.js +320 -320
  15. package/node/curve.d.ts +46 -46
  16. package/node/curve.js +88 -88
  17. package/node/debug/cp-node-for-debugging.d.ts +11 -11
  18. package/node/debug/cp-node-for-debugging.js +1 -1
  19. package/node/debug/debug-elem-types.d.ts +32 -32
  20. package/node/debug/debug-elem-types.js +1 -1
  21. package/node/debug/debug.d.ts +50 -50
  22. package/node/debug/debug.js +75 -75
  23. package/node/debug/functions/draw-elem/bounding-hull.d.ts +3 -3
  24. package/node/debug/functions/draw-elem/bounding-hull.js +7 -7
  25. package/node/debug/functions/draw-elem/branch.d.ts +4 -4
  26. package/node/debug/functions/draw-elem/branch.js +22 -22
  27. package/node/debug/functions/draw-elem/culls.d.ts +4 -4
  28. package/node/debug/functions/draw-elem/culls.js +21 -21
  29. package/node/debug/functions/draw-elem/draw-circle-percent.d.ts +3 -3
  30. package/node/debug/functions/draw-elem/draw-circle-percent.js +12 -12
  31. package/node/debug/functions/draw-elem/draw-elem.d.ts +8 -8
  32. package/node/debug/functions/draw-elem/draw-elem.js +45 -45
  33. package/node/debug/functions/draw-elem/dull-corner.d.ts +4 -4
  34. package/node/debug/functions/draw-elem/dull-corner.js +10 -10
  35. package/node/debug/functions/draw-elem/leaves.d.ts +4 -4
  36. package/node/debug/functions/draw-elem/leaves.js +12 -12
  37. package/node/debug/functions/draw-elem/loop.d.ts +4 -4
  38. package/node/debug/functions/draw-elem/loop.js +11 -11
  39. package/node/debug/functions/draw-elem/loops.d.ts +4 -4
  40. package/node/debug/functions/draw-elem/loops.js +6 -6
  41. package/node/debug/functions/draw-elem/loose-bounding-box.d.ts +3 -3
  42. package/node/debug/functions/draw-elem/loose-bounding-box.js +9 -9
  43. package/node/debug/functions/draw-elem/mat.d.ts +4 -4
  44. package/node/debug/functions/draw-elem/mat.js +30 -30
  45. package/node/debug/functions/draw-elem/max-vertex.d.ts +4 -4
  46. package/node/debug/functions/draw-elem/max-vertex.js +8 -8
  47. package/node/debug/functions/draw-elem/min-y.d.ts +4 -4
  48. package/node/debug/functions/draw-elem/min-y.js +13 -13
  49. package/node/debug/functions/draw-elem/one-prong-at-dull-corner.d.ts +4 -4
  50. package/node/debug/functions/draw-elem/one-prong-at-dull-corner.js +12 -12
  51. package/node/debug/functions/draw-elem/one-prong.d.ts +4 -4
  52. package/node/debug/functions/draw-elem/one-prong.js +16 -16
  53. package/node/debug/functions/draw-elem/sharp-corner.d.ts +4 -4
  54. package/node/debug/functions/draw-elem/sharp-corner.js +9 -9
  55. package/node/debug/functions/draw-elem/three-prong.d.ts +4 -4
  56. package/node/debug/functions/draw-elem/three-prong.js +16 -16
  57. package/node/debug/functions/draw-elem/tight-bounding-box.d.ts +3 -3
  58. package/node/debug/functions/draw-elem/tight-bounding-box.js +7 -7
  59. package/node/debug/functions/draw-elem/two-prong.d.ts +4 -4
  60. package/node/debug/functions/draw-elem/two-prong.js +36 -36
  61. package/node/debug/functions/draw-elem/vertex.d.ts +4 -4
  62. package/node/debug/functions/draw-elem/vertex.js +27 -27
  63. package/node/debug/functions/general.d.ts +48 -48
  64. package/node/debug/functions/general.js +52 -52
  65. package/node/debug/functions/three-prong.d.ts +11 -11
  66. package/node/debug/functions/three-prong.js +184 -184
  67. package/node/debug/functions/two-prong.d.ts +13 -13
  68. package/node/debug/functions/two-prong.js +117 -117
  69. package/node/debug/three-prong-for-debugging.d.ts +31 -31
  70. package/node/debug/three-prong-for-debugging.js +20 -20
  71. package/node/debug/two-prong-for-debugging.d.ts +26 -26
  72. package/node/debug/two-prong-for-debugging.js +1 -1
  73. package/node/find-mats.d.ts +26 -26
  74. package/node/find-mats.js +122 -122
  75. package/node/get-boundary-bezier-parts-to-next.d.ts +9 -9
  76. package/node/get-boundary-bezier-parts-to-next.js +42 -42
  77. package/node/get-boundary-beziers-to-next.d.ts +8 -8
  78. package/node/get-boundary-beziers-to-next.js +44 -44
  79. package/node/get-bounding-box-.d.ts +2 -2
  80. package/node/get-bounding-box-.js +4 -4
  81. package/node/get-branches.d.ts +12 -12
  82. package/node/get-branches.js +68 -68
  83. package/node/get-curve/get-curve-between.d.ts +9 -9
  84. package/node/get-curve/get-curve-between.js +56 -56
  85. package/node/get-curve/get-edge-direction.d.ts +9 -9
  86. package/node/get-curve/get-edge-direction.js +53 -53
  87. package/node/get-curve-to-next.d.ts +9 -9
  88. package/node/get-curve-to-next.js +11 -11
  89. package/node/get-interface-ccw.d.ts +24 -24
  90. package/node/get-interface-ccw.js +97 -97
  91. package/node/index.d.ts +36 -36
  92. package/node/index.js +32 -32
  93. package/node/loop/get-max-coordinate.d.ts +10 -10
  94. package/node/loop/get-max-coordinate.js +43 -43
  95. package/node/loop.d.ts +16 -16
  96. package/node/loop.js +34 -34
  97. package/node/mat/add-to-cp-graph.d.ts +16 -16
  98. package/node/mat/add-to-cp-graph.js +30 -30
  99. package/node/mat/bezier-piece.d.ts +12 -12
  100. package/node/mat/bezier-piece.js +1 -1
  101. package/node/mat/closest-boundary-point/closest-points-on-curve.d.ts +14 -14
  102. package/node/mat/closest-boundary-point/closest-points-on-curve.js +72 -72
  103. package/node/mat/closest-boundary-point/cull-bezier-pieces.d.ts +9 -9
  104. package/node/mat/closest-boundary-point/cull-bezier-pieces.js +19 -19
  105. package/node/mat/closest-boundary-point/cull-by-loose-bounding-box.d.ts +11 -11
  106. package/node/mat/closest-boundary-point/cull-by-loose-bounding-box.js +24 -24
  107. package/node/mat/closest-boundary-point/cull-by-tight-boundary-box.d.ts +11 -11
  108. package/node/mat/closest-boundary-point/cull-by-tight-boundary-box.js +26 -26
  109. package/node/mat/closest-boundary-point/get-best-distance-squared.d.ts +8 -8
  110. package/node/mat/closest-boundary-point/get-best-distance-squared.js +24 -24
  111. package/node/mat/closest-boundary-point/get-close-boundary-points.d.ts +17 -17
  112. package/node/mat/closest-boundary-point/get-close-boundary-points.js +80 -80
  113. package/node/mat/closest-boundary-point/get-closest-boundary-point.d.ts +18 -18
  114. package/node/mat/closest-boundary-point/get-closest-boundary-point.js +40 -40
  115. package/node/mat/corner.d.ts +37 -37
  116. package/node/mat/corner.js +1 -1
  117. package/node/mat/create-new-cp-tree.d.ts +9 -9
  118. package/node/mat/create-new-cp-tree.js +23 -23
  119. package/node/mat/elem-type-two-prong.d.ts +3 -3
  120. package/node/mat/elem-type-two-prong.js +1 -1
  121. package/node/mat/find-mat/add-1-prong.d.ts +12 -12
  122. package/node/mat/find-mat/add-1-prong.js +42 -42
  123. package/node/mat/find-mat/add-2-prong.d.ts +21 -21
  124. package/node/mat/find-mat/add-2-prong.js +192 -192
  125. package/node/mat/find-mat/add-3-prong.d.ts +19 -19
  126. package/node/mat/find-mat/add-3-prong.js +54 -54
  127. package/node/mat/find-mat/add-debug-info.d.ts +9 -9
  128. package/node/mat/find-mat/add-debug-info.js +67 -67
  129. package/node/mat/find-mat/create-get-interesting-points-on-loop.d.ts +11 -11
  130. package/node/mat/find-mat/create-get-interesting-points-on-loop.js +51 -51
  131. package/node/mat/find-mat/create-initial-cp-graph.d.ts +12 -12
  132. package/node/mat/find-mat/create-initial-cp-graph.js +40 -40
  133. package/node/mat/find-mat/find-2-prong/add-debug-info.d.ts +8 -8
  134. package/node/mat/find-mat/find-2-prong/add-debug-info.js +21 -21
  135. package/node/mat/find-mat/find-2-prong/cull-bezier-pieces.d.ts +11 -11
  136. package/node/mat/find-mat/find-2-prong/cull-bezier-pieces.js +29 -29
  137. package/node/mat/find-mat/find-2-prong/find-2-prong.d.ts +37 -37
  138. package/node/mat/find-mat/find-2-prong/find-2-prong.js +232 -232
  139. package/node/mat/find-mat/find-2-prong/find-equidistant-point-on-line.d.ts +9 -9
  140. package/node/mat/find-mat/find-2-prong/find-equidistant-point-on-line.js +39 -39
  141. package/node/mat/find-mat/find-2-prong/get-initial-bezier-pieces.d.ts +11 -11
  142. package/node/mat/find-mat/find-2-prong/get-initial-bezier-pieces.js +37 -37
  143. package/node/mat/find-mat/find-2-prong/x-for-debugging.d.ts +9 -9
  144. package/node/mat/find-mat/find-2-prong/x-for-debugging.js +1 -1
  145. package/node/mat/find-mat/find-3-prong/calc-better-x.d.ts +19 -19
  146. package/node/mat/find-mat/find-3-prong/calc-better-x.js +36 -36
  147. package/node/mat/find-mat/find-3-prong/calc-initial-3-prong-center.d.ts +13 -13
  148. package/node/mat/find-mat/find-3-prong/calc-initial-3-prong-center.js +25 -25
  149. package/node/mat/find-mat/find-3-prong/find-3-prong-for-delta3s.d.ts +22 -22
  150. package/node/mat/find-mat/find-3-prong/find-3-prong-for-delta3s.js +159 -159
  151. package/node/mat/find-mat/find-3-prong/find-3-prong.d.ts +16 -16
  152. package/node/mat/find-mat/find-3-prong/find-3-prong.js +76 -76
  153. package/node/mat/find-mat/find-3-prong/get-closest-points.d.ts +9 -9
  154. package/node/mat/find-mat/find-3-prong/get-closest-points.js +16 -16
  155. package/node/mat/find-mat/find-and-add-2-prongs-on-all-paths.d.ts +15 -15
  156. package/node/mat/find-mat/find-and-add-2-prongs-on-all-paths.js +20 -20
  157. package/node/mat/find-mat/find-and-add-2-prongs.d.ts +16 -16
  158. package/node/mat/find-mat/find-and-add-2-prongs.js +73 -73
  159. package/node/mat/find-mat/find-and-add-3-prongs.d.ts +13 -13
  160. package/node/mat/find-mat/find-and-add-3-prongs.js +146 -146
  161. package/node/mat/find-mat/find-and-add-hole-closing-2-prongs.d.ts +14 -14
  162. package/node/mat/find-mat/find-and-add-hole-closing-2-prongs.js +33 -33
  163. package/node/mat/find-mat/get-potential-2-prongs.d.ts +4 -4
  164. package/node/mat/find-mat/get-potential-2-prongs.js +16 -16
  165. package/node/mat/find-mat/get-sharp-corners.d.ts +4 -4
  166. package/node/mat/find-mat/get-sharp-corners.js +17 -17
  167. package/node/mat/geometry/get-closest-square-distance-to-rect.d.ts +5 -5
  168. package/node/mat/geometry/get-closest-square-distance-to-rect.js +49 -49
  169. package/node/mat/geometry/get-closest-squared-distance-to-rotated-rect.d.ts +5 -5
  170. package/node/mat/geometry/get-closest-squared-distance-to-rotated-rect.js +15 -15
  171. package/node/mat/get-boundary-piece-beziers.d.ts +11 -11
  172. package/node/mat/get-boundary-piece-beziers.js +58 -58
  173. package/node/mat/get-contact-circles-at-interface.d.ts +8 -8
  174. package/node/mat/get-contact-circles-at-interface.js +20 -20
  175. package/node/mat/get-largest-vertex.d.ts +4 -4
  176. package/node/mat/get-largest-vertex.js +9 -9
  177. package/node/mat/get-leaves.d.ts +4 -4
  178. package/node/mat/get-leaves.js +12 -12
  179. package/node/mat/get-neighboring-cps.d.ts +14 -14
  180. package/node/mat/get-neighboring-cps.js +30 -30
  181. package/node/mat/get-two-prong-type.d.ts +5 -5
  182. package/node/mat/get-two-prong-type.js +8 -8
  183. package/node/mat/is-another-cp-closeby.d.ts +20 -20
  184. package/node/mat/is-another-cp-closeby.js +55 -55
  185. package/node/mat/simplify-mat-map-only.d.ts +23 -23
  186. package/node/mat/simplify-mat-map-only.js +80 -80
  187. package/node/mat/to-scale-axis/add-debug-info.d.ts +7 -7
  188. package/node/mat/to-scale-axis/add-debug-info.js +13 -13
  189. package/node/mat/to-scale-axis/cull-non-cycles.d.ts +9 -9
  190. package/node/mat/to-scale-axis/cull-non-cycles.js +51 -51
  191. package/node/mat/to-scale-axis/cull.d.ts +12 -12
  192. package/node/mat/to-scale-axis/cull.js +132 -132
  193. package/node/mat/trim-mat.d.ts +8 -8
  194. package/node/mat/trim-mat.js +16 -16
  195. package/node/mat.d.ts +22 -22
  196. package/node/mat.js +1 -1
  197. package/node/point-on-shape.d.ts +73 -73
  198. package/node/point-on-shape.js +167 -167
  199. package/node/simplify-mat.d.ts +16 -16
  200. package/node/simplify-mat.js +71 -71
  201. package/node/svg/get-loop-bounds.d.ts +12 -12
  202. package/node/svg/get-loop-bounds.js +80 -80
  203. package/node/svg/get-min-y-pos.d.ts +8 -8
  204. package/node/svg/get-min-y-pos.js +9 -9
  205. package/node/svg/get-shape-bounds.d.ts +9 -9
  206. package/node/svg/get-shape-bounds.js +35 -35
  207. package/node/sweep-line/sweep-line.d.ts +18 -18
  208. package/node/sweep-line/sweep-line.js +72 -72
  209. package/node/to-scale-axis.d.ts +16 -16
  210. package/node/to-scale-axis.js +74 -74
  211. package/node/traverse-edges.d.ts +10 -10
  212. package/node/traverse-edges.js +21 -21
  213. package/node/traverse-vertices.d.ts +12 -12
  214. package/node/traverse-vertices.js +27 -27
  215. package/package.json +15 -15
  216. package/tsconfig.json +0 -1
@@ -1,233 +1,233 @@
1
- import { lineLineIntersection, distanceBetween, squaredDistanceBetween, interpolate, dot } from 'flo-vector2d';
2
- import { evalDeCasteljau as evalDeCasteljau_ } from 'flo-bezier3';
3
- import { getClosestBoundaryPoint } from '../../closest-boundary-point/get-closest-boundary-point.js';
4
- import { getOsculatingCircle } from '../../../point-on-shape.js';
5
- import { add1Prong } from '../add-1-prong.js';
6
- import { addDebugInfo } from './add-debug-info.js';
7
- import { cullBezierPieces } from './cull-bezier-pieces.js';
8
- import { findEquidistantPointOnLine } from './find-equidistant-point-on-line.js';
9
- import { getInitialBezierPieces } from './get-initial-bezier-pieces.js';
10
- import { getCloseBoundaryPoints } from '../../closest-boundary-point/get-close-boundary-points.js';
11
- const evalDeCasteljau = evalDeCasteljau_;
12
- /**
13
- * @hidden
14
- * Adds a 2-prong to the MAT. The first point on the shape boundary is given and
15
- * the second one is found by the algorithm.
16
- *
17
- * A 2-prong is defined as a MAT circle that touches the shape at exactly 2
18
- * points.
19
- *
20
- * Before any 2-prongs are added the entire shape is our δΩ (1-prongs do not
21
- * reduce the boundary).
22
- *
23
- * As per the paper by Choi, Choi, Moon and Wee:
24
- * "The starting point of this algorithm is a choice of a circle Br(x)
25
- * centered at an interior point x which contains two boundary portions c and
26
- * d of dΩ as in Fig. 19."
27
- * In fact, we (and they) start by fixing one point on the boundary beforehand.
28
- * @param loops A shape represented by path loops
29
- * @param extreme The extreme coordinate value of the shape
30
- * @param squaredDiagonalLength The squared diagonal length of the shape
31
- * bounding box.
32
- * @param y The source point of the 2-prong to be found
33
- * @param isHoleClosing True if this is a hole-closing two-prong, false otherwise
34
- * @param k The loop array index
35
- */
36
- function find2Prong(loops, extreme, squaredDiagonalLength, cpTrees, y, isHoleClosing, k) {
37
- const MAX_ITERATIONS = 25;
38
- const squaredSeperationTolerance = (1e-6 * extreme) ** 2;
39
- // TODO - base deltas on theory or remove
40
- const oneProngTolerance = (1e-4) ** 2;
41
- const squaredErrorTolerance = 1e-2 * squaredSeperationTolerance;
42
- const maxOsculatingCircleRadiusSquared = squaredDiagonalLength;
43
- // The boundary piece that should contain the other point of
44
- // the 2-prong circle. (Defined by start and end points).
45
- const { bezierPieces, δ } = getInitialBezierPieces(isHoleClosing, k, loops, cpTrees, y);
46
- //console.log(bezierPieces.length)
47
- /** The center of the two-prong (successively refined) */
48
- let x;
49
- let p;
50
- let r;
51
- if (isHoleClosing) {
52
- p = [y.p[0], y.p[1]];
53
- x = [p[0], p[1] - Math.sqrt(maxOsculatingCircleRadiusSquared)];
54
- r = maxOsculatingCircleRadiusSquared;
55
- }
56
- else {
57
- p = y.p;
58
- //x = PointOnShape.getOsculatingCircle(maxOsculatingCircleRadiusSquared, y).center;
59
- x = getOsculatingCircle(maxOsculatingCircleRadiusSquared, y).center;
60
- r = squaredDistanceBetween(p, x);
61
- }
62
- // The lines below is an optimization.
63
- const r_ = reduceRadius(extreme, bezierPieces, p, x);
64
- if (r > r_) {
65
- x = interpolate(p, x, Math.sqrt(r_ / r));
66
- }
67
- /** Trace the convergence (for debugging). */
68
- const xs = [];
69
- /** The antipode of the two-prong (successively refined) */
70
- let z;
71
- let i = 0;
72
- let done = 0;
73
- let failed = false; // The failed flag is set if a 2-prong cannot be found.
74
- let bezierPieces_ = bezierPieces;
75
- // ---> for (let b of bezierPieces) { d.fs.draw.bezierPiece(document.getElementsByTagName('g')[0], b.curve.ps, b.ts, 'nofill thin10 red', 100); }
76
- do {
77
- i++;
78
- /** squared distance between source boundary point and circle center */
79
- const r = squaredDistanceBetween(x, y.p);
80
- bezierPieces_ = cullBezierPieces(bezierPieces_, x, r);
81
- z = getClosestBoundaryPoint(bezierPieces_, x, y.curve, y.t);
82
- if (z === undefined) {
83
- if (typeof _debug_ !== 'undefined') {
84
- const elems = _debug_.generated.elems;
85
- const elem = isHoleClosing
86
- ? elems.twoProng_holeClosing
87
- : elems.twoProng_regular;
88
- const elemStr = isHoleClosing
89
- ? 'hole-closing: ' + elem.length
90
- : 'regular: ' + elem.length;
91
- console.log('failed: no closest point - ' + elemStr);
92
- }
93
- failed = true;
94
- break;
95
- }
96
- if (typeof _debug_ !== 'undefined') {
97
- xs.push({ x, y, z: z.pos, t: y.t });
98
- }
99
- /** squared distance between anti-pode boundary point and circle center */
100
- const d = squaredDistanceBetween(x, z.pos.p);
101
- //if (i === 1 && d*oneProngTolerance >= r) {
102
- if (i === 1 && r < d + oneProngTolerance) {
103
- // It is a 1-prong.
104
- add1Prong(Math.sqrt(maxOsculatingCircleRadiusSquared), cpTrees, y);
105
- return undefined;
106
- }
107
- // TODO - squaredSeperationTolerance should in future be replaced with
108
- // a relative error, i.e. distance between y (or z) / length(y (or z)).
109
- if (!isHoleClosing && squaredDistanceBetween(y.p, z.pos.p) <= squaredSeperationTolerance) {
110
- if (typeof _debug_ !== 'undefined') {
111
- /*
112
- let elems = _debug_.generated.elems;
113
- let elem = isHoleClosing
114
- ? elems.twoProng_holeClosing
115
- : elems.twoProng_regular
116
- let elemStr = isHoleClosing
117
- ? 'hole-closing: ' + elem.length
118
- : 'regular: ' + elem.length;
119
- console.log(
120
- 'failed: two-prong radius too small - ' + elemStr
121
- );
122
- */
123
- }
124
- failed = true;
125
- break;
126
- }
127
- // TODO - Accuracy optimization: tolerance should not be between x and
128
- // nextX, but rather (distance from x to y) - (distance from x to z)
129
- // Find the point on the line connecting y with x that is
130
- // equidistant from y and z. This will be our next x.
131
- const nextX = findEquidistantPointOnLine(x, y.p, z.pos.p);
132
- const squaredError = squaredDistanceBetween(x, nextX);
133
- x = nextX;
134
- if (squaredError < squaredErrorTolerance) {
135
- done++; // Do one more iteration
136
- }
137
- else if (i === MAX_ITERATIONS) {
138
- // Convergence was too slow.
139
- failed = true;
140
- break; // We're done
141
- }
142
- } while (done < 1);
143
- // TODO - Optimization: only do this if second closest point is within the
144
- // tolerance which can be checked in getClosestBoundaryPoint algorithm
145
- let zs = [];
146
- if (!failed) {
147
- zs = getCloseBoundaryPoints(bezierPieces_, x, y, distanceBetween(x, z.pos.p));
148
- if (!zs.length) {
149
- // TODO - Numerical issue - fix
150
- zs.push(z);
151
- }
152
- }
153
- let circle;
154
- if (z !== undefined) {
155
- circle = { center: x, radius: distanceBetween(x, z.pos.p) };
156
- }
157
- if (typeof _debug_ !== 'undefined' && !failed) {
158
- xs.push({ x, y, z: z.pos, t: y.t });
159
- addDebugInfo(bezierPieces, failed, y, circle, z.pos, δ, xs, isHoleClosing);
160
- }
161
- return failed ? undefined : { circle, zs };
162
- }
163
- /**
164
- * @hidden
165
- * Reduces the circle radius initially as an optimization step.
166
- */
167
- function reduceRadius(extreme, bezierPieces, p, x) {
168
- const TOLERANCE = extreme * 1e-3;
169
- let prevP = undefined;
170
- let minRadius = Number.POSITIVE_INFINITY;
171
- for (let i = 0; i < bezierPieces.length; i++) {
172
- const bezierPiece = bezierPieces[i];
173
- const ps = bezierPiece.curve.ps;
174
- const p1 = evalDeCasteljau(ps, bezierPiece.ts[0]);
175
- let r1 = Number.POSITIVE_INFINITY;
176
- // Prevent evaluating the same points twice
177
- if (!prevP || prevP[0] !== p1[0] || prevP[1] !== p1[1]) {
178
- const cc1 = getCircleCenterFrom2PointsAndNormal(extreme, p, x, p1);
179
- if (cc1) {
180
- r1 = squaredDistanceBetween(p, cc1);
181
- }
182
- }
183
- let r2 = Number.POSITIVE_INFINITY;
184
- const p2 = evalDeCasteljau(ps, bezierPiece.ts[1]);
185
- const cc2 = getCircleCenterFrom2PointsAndNormal(extreme, p, x, p2);
186
- if (cc2) {
187
- r2 = squaredDistanceBetween(p, cc2);
188
- }
189
- prevP = p2;
190
- const d = Math.min(r1, r2);
191
- if (d < minRadius) {
192
- minRadius = d;
193
- }
194
- }
195
- // The extra bit is to account for floating point precision.
196
- // TODO - base delta on theory
197
- return minRadius + TOLERANCE;
198
- }
199
- /**
200
- * @hidden
201
- * @param p A point on the circle with normal pointing to x towards the center
202
- * of the circle.
203
- * @param x
204
- * @param p1 Another point on the circle.
205
- */
206
- function getCircleCenterFrom2PointsAndNormal(extreme, p, x, p1) {
207
- // TODO - remove delta
208
- const TOLERANCE = (1e-4 * extreme) ** 2;
209
- // Ignore if p and p1 are too close together
210
- if (squaredDistanceBetween(p, p1) < TOLERANCE) {
211
- return undefined;
212
- }
213
- /** The perpindicular bisector between the two given points on the circle */
214
- const pb = [
215
- (p[0] + p1[0]) / 2,
216
- (p[1] + p1[1]) / 2,
217
- ];
218
- const tan = [p1[0] - p[0], p1[1] - p[1]];
219
- const norm = [-tan[1], tan[0]]; // Rotate by 90 degrees
220
- const pb2 = [pb[0] + norm[0], pb[1] + norm[1]];
221
- const res = lineLineIntersection([p, x], [pb, pb2]);
222
- if (!res) {
223
- return undefined;
224
- }
225
- const resO = [res[0] - p[0], res[1] - p[1]];
226
- const xO = [x[0] - p[0], x[1] - p[1]];
227
- if (dot(resO, xO) < 0) {
228
- return undefined;
229
- }
230
- return res;
231
- }
232
- export { find2Prong };
1
+ import { lineLineIntersection, distanceBetween, squaredDistanceBetween, interpolate, dot } from 'flo-vector2d';
2
+ import { evalDeCasteljau as evalDeCasteljau_ } from 'flo-bezier3';
3
+ import { getClosestBoundaryPoint } from '../../closest-boundary-point/get-closest-boundary-point.js';
4
+ import { getOsculatingCircle } from '../../../point-on-shape.js';
5
+ import { add1Prong } from '../add-1-prong.js';
6
+ import { addDebugInfo } from './add-debug-info.js';
7
+ import { cullBezierPieces } from './cull-bezier-pieces.js';
8
+ import { findEquidistantPointOnLine } from './find-equidistant-point-on-line.js';
9
+ import { getInitialBezierPieces } from './get-initial-bezier-pieces.js';
10
+ import { getCloseBoundaryPoints } from '../../closest-boundary-point/get-close-boundary-points.js';
11
+ const evalDeCasteljau = evalDeCasteljau_;
12
+ /**
13
+ * @hidden
14
+ * Adds a 2-prong to the MAT. The first point on the shape boundary is given and
15
+ * the second one is found by the algorithm.
16
+ *
17
+ * A 2-prong is defined as a MAT circle that touches the shape at exactly 2
18
+ * points.
19
+ *
20
+ * Before any 2-prongs are added the entire shape is our δΩ (1-prongs do not
21
+ * reduce the boundary).
22
+ *
23
+ * As per the paper by Choi, Choi, Moon and Wee:
24
+ * "The starting point of this algorithm is a choice of a circle Br(x)
25
+ * centered at an interior point x which contains two boundary portions c and
26
+ * d of dΩ as in Fig. 19."
27
+ * In fact, we (and they) start by fixing one point on the boundary beforehand.
28
+ * @param loops A shape represented by path loops
29
+ * @param extreme The extreme coordinate value of the shape
30
+ * @param squaredDiagonalLength The squared diagonal length of the shape
31
+ * bounding box.
32
+ * @param y The source point of the 2-prong to be found
33
+ * @param isHoleClosing True if this is a hole-closing two-prong, false otherwise
34
+ * @param k The loop array index
35
+ */
36
+ function find2Prong(loops, extreme, squaredDiagonalLength, cpTrees, y, isHoleClosing, k) {
37
+ const MAX_ITERATIONS = 25;
38
+ const squaredSeperationTolerance = (1e-6 * extreme) ** 2;
39
+ // TODO - base deltas on theory or remove
40
+ const oneProngTolerance = (1e-4) ** 2;
41
+ const squaredErrorTolerance = 1e-2 * squaredSeperationTolerance;
42
+ const maxOsculatingCircleRadiusSquared = squaredDiagonalLength;
43
+ // The boundary piece that should contain the other point of
44
+ // the 2-prong circle. (Defined by start and end points).
45
+ const { bezierPieces, δ } = getInitialBezierPieces(isHoleClosing, k, loops, cpTrees, y);
46
+ //console.log(bezierPieces.length)
47
+ /** The center of the two-prong (successively refined) */
48
+ let x;
49
+ let p;
50
+ let r;
51
+ if (isHoleClosing) {
52
+ p = [y.p[0], y.p[1]];
53
+ x = [p[0], p[1] - Math.sqrt(maxOsculatingCircleRadiusSquared)];
54
+ r = maxOsculatingCircleRadiusSquared;
55
+ }
56
+ else {
57
+ p = y.p;
58
+ //x = PointOnShape.getOsculatingCircle(maxOsculatingCircleRadiusSquared, y).center;
59
+ x = getOsculatingCircle(maxOsculatingCircleRadiusSquared, y).center;
60
+ r = squaredDistanceBetween(p, x);
61
+ }
62
+ // The lines below is an optimization.
63
+ const r_ = reduceRadius(extreme, bezierPieces, p, x);
64
+ if (r > r_) {
65
+ x = interpolate(p, x, Math.sqrt(r_ / r));
66
+ }
67
+ /** Trace the convergence (for debugging). */
68
+ const xs = [];
69
+ /** The antipode of the two-prong (successively refined) */
70
+ let z;
71
+ let i = 0;
72
+ let done = 0;
73
+ let failed = false; // The failed flag is set if a 2-prong cannot be found.
74
+ let bezierPieces_ = bezierPieces;
75
+ // ---> for (let b of bezierPieces) { d.fs.draw.bezierPiece(document.getElementsByTagName('g')[0], b.curve.ps, b.ts, 'nofill thin10 red', 100); }
76
+ do {
77
+ i++;
78
+ /** squared distance between source boundary point and circle center */
79
+ const r = squaredDistanceBetween(x, y.p);
80
+ bezierPieces_ = cullBezierPieces(bezierPieces_, x, r);
81
+ z = getClosestBoundaryPoint(bezierPieces_, x, y.curve, y.t);
82
+ if (z === undefined) {
83
+ if (typeof _debug_ !== 'undefined') {
84
+ const elems = _debug_.generated.elems;
85
+ const elem = isHoleClosing
86
+ ? elems.twoProng_holeClosing
87
+ : elems.twoProng_regular;
88
+ const elemStr = isHoleClosing
89
+ ? 'hole-closing: ' + elem.length
90
+ : 'regular: ' + elem.length;
91
+ console.log('failed: no closest point - ' + elemStr);
92
+ }
93
+ failed = true;
94
+ break;
95
+ }
96
+ if (typeof _debug_ !== 'undefined') {
97
+ xs.push({ x, y, z: z.pos, t: y.t });
98
+ }
99
+ /** squared distance between anti-pode boundary point and circle center */
100
+ const d = squaredDistanceBetween(x, z.pos.p);
101
+ //if (i === 1 && d*oneProngTolerance >= r) {
102
+ if (i === 1 && r < d + oneProngTolerance) {
103
+ // It is a 1-prong.
104
+ add1Prong(Math.sqrt(maxOsculatingCircleRadiusSquared), cpTrees, y);
105
+ return undefined;
106
+ }
107
+ // TODO - squaredSeperationTolerance should in future be replaced with
108
+ // a relative error, i.e. distance between y (or z) / length(y (or z)).
109
+ if (!isHoleClosing && squaredDistanceBetween(y.p, z.pos.p) <= squaredSeperationTolerance) {
110
+ if (typeof _debug_ !== 'undefined') {
111
+ /*
112
+ let elems = _debug_.generated.elems;
113
+ let elem = isHoleClosing
114
+ ? elems.twoProng_holeClosing
115
+ : elems.twoProng_regular
116
+ let elemStr = isHoleClosing
117
+ ? 'hole-closing: ' + elem.length
118
+ : 'regular: ' + elem.length;
119
+ console.log(
120
+ 'failed: two-prong radius too small - ' + elemStr
121
+ );
122
+ */
123
+ }
124
+ failed = true;
125
+ break;
126
+ }
127
+ // TODO - Accuracy optimization: tolerance should not be between x and
128
+ // nextX, but rather (distance from x to y) - (distance from x to z)
129
+ // Find the point on the line connecting y with x that is
130
+ // equidistant from y and z. This will be our next x.
131
+ const nextX = findEquidistantPointOnLine(x, y.p, z.pos.p);
132
+ const squaredError = squaredDistanceBetween(x, nextX);
133
+ x = nextX;
134
+ if (squaredError < squaredErrorTolerance) {
135
+ done++; // Do one more iteration
136
+ }
137
+ else if (i === MAX_ITERATIONS) {
138
+ // Convergence was too slow.
139
+ failed = true;
140
+ break; // We're done
141
+ }
142
+ } while (done < 1);
143
+ // TODO - Optimization: only do this if second closest point is within the
144
+ // tolerance which can be checked in getClosestBoundaryPoint algorithm
145
+ let zs = [];
146
+ if (!failed) {
147
+ zs = getCloseBoundaryPoints(bezierPieces_, x, y, distanceBetween(x, z.pos.p));
148
+ if (!zs.length) {
149
+ // TODO - Numerical issue - fix
150
+ zs.push(z);
151
+ }
152
+ }
153
+ let circle;
154
+ if (z !== undefined) {
155
+ circle = { center: x, radius: distanceBetween(x, z.pos.p) };
156
+ }
157
+ if (typeof _debug_ !== 'undefined' && !failed) {
158
+ xs.push({ x, y, z: z.pos, t: y.t });
159
+ addDebugInfo(bezierPieces, failed, y, circle, z.pos, δ, xs, isHoleClosing);
160
+ }
161
+ return failed ? undefined : { circle, zs };
162
+ }
163
+ /**
164
+ * @hidden
165
+ * Reduces the circle radius initially as an optimization step.
166
+ */
167
+ function reduceRadius(extreme, bezierPieces, p, x) {
168
+ const TOLERANCE = extreme * 1e-3;
169
+ let prevP = undefined;
170
+ let minRadius = Number.POSITIVE_INFINITY;
171
+ for (let i = 0; i < bezierPieces.length; i++) {
172
+ const bezierPiece = bezierPieces[i];
173
+ const ps = bezierPiece.curve.ps;
174
+ const p1 = evalDeCasteljau(ps, bezierPiece.ts[0]);
175
+ let r1 = Number.POSITIVE_INFINITY;
176
+ // Prevent evaluating the same points twice
177
+ if (!prevP || prevP[0] !== p1[0] || prevP[1] !== p1[1]) {
178
+ const cc1 = getCircleCenterFrom2PointsAndNormal(extreme, p, x, p1);
179
+ if (cc1) {
180
+ r1 = squaredDistanceBetween(p, cc1);
181
+ }
182
+ }
183
+ let r2 = Number.POSITIVE_INFINITY;
184
+ const p2 = evalDeCasteljau(ps, bezierPiece.ts[1]);
185
+ const cc2 = getCircleCenterFrom2PointsAndNormal(extreme, p, x, p2);
186
+ if (cc2) {
187
+ r2 = squaredDistanceBetween(p, cc2);
188
+ }
189
+ prevP = p2;
190
+ const d = Math.min(r1, r2);
191
+ if (d < minRadius) {
192
+ minRadius = d;
193
+ }
194
+ }
195
+ // The extra bit is to account for floating point precision.
196
+ // TODO - base delta on theory
197
+ return minRadius + TOLERANCE;
198
+ }
199
+ /**
200
+ * @hidden
201
+ * @param p A point on the circle with normal pointing to x towards the center
202
+ * of the circle.
203
+ * @param x
204
+ * @param p1 Another point on the circle.
205
+ */
206
+ function getCircleCenterFrom2PointsAndNormal(extreme, p, x, p1) {
207
+ // TODO - remove delta
208
+ const TOLERANCE = (1e-4 * extreme) ** 2;
209
+ // Ignore if p and p1 are too close together
210
+ if (squaredDistanceBetween(p, p1) < TOLERANCE) {
211
+ return undefined;
212
+ }
213
+ /** The perpindicular bisector between the two given points on the circle */
214
+ const pb = [
215
+ (p[0] + p1[0]) / 2,
216
+ (p[1] + p1[1]) / 2,
217
+ ];
218
+ const tan = [p1[0] - p[0], p1[1] - p[1]];
219
+ const norm = [-tan[1], tan[0]]; // Rotate by 90 degrees
220
+ const pb2 = [pb[0] + norm[0], pb[1] + norm[1]];
221
+ const res = lineLineIntersection([p, x], [pb, pb2]);
222
+ if (!res) {
223
+ return undefined;
224
+ }
225
+ const resO = [res[0] - p[0], res[1] - p[1]];
226
+ const xO = [x[0] - p[0], x[1] - p[1]];
227
+ if (dot(resO, xO) < 0) {
228
+ return undefined;
229
+ }
230
+ return res;
231
+ }
232
+ export { find2Prong };
233
233
  //# sourceMappingURL=find-2-prong.js.map
@@ -1,9 +1,9 @@
1
- /**
2
- * @hidden
3
- * @param x
4
- * @param y
5
- * @param z
6
- * @returns The point on the line from y to x that is equidistant from y and z.
7
- */
8
- declare function findEquidistantPointOnLine(x: number[], y: number[], z: number[]): number[];
9
- export { findEquidistantPointOnLine };
1
+ /**
2
+ * @hidden
3
+ * @param x
4
+ * @param y
5
+ * @param z
6
+ * @returns The point on the line from y to x that is equidistant from y and z.
7
+ */
8
+ declare function findEquidistantPointOnLine(x: number[], y: number[], z: number[]): number[];
9
+ export { findEquidistantPointOnLine };
@@ -1,40 +1,40 @@
1
- /**
2
- * @hidden
3
- * @param x
4
- * @param y
5
- * @param z
6
- * @returns The point on the line from y to x that is equidistant from y and z.
7
- */
8
- function findEquidistantPointOnLine(x, y, z) {
9
- // Some basic algebra (not shown) finds the required point.
10
- // Swap axes if x and y are more aligned to y-axis than to x-axis.
11
- const swapAxes = Math.abs((x[1] - y[1]) / (x[0] - y[0])) > 1;
12
- // Cache
13
- let x1, x2, y1, y2, z1, z2;
14
- if (swapAxes) {
15
- x1 = x[1];
16
- x2 = x[0];
17
- y1 = y[1];
18
- y2 = y[0];
19
- z1 = z[1];
20
- z2 = z[0];
21
- }
22
- else {
23
- x1 = x[0];
24
- x2 = x[1];
25
- y1 = y[0];
26
- y2 = y[1];
27
- z1 = z[0];
28
- z2 = z[1];
29
- }
30
- // a <= 1 (due to swapped axes)
31
- const a = (x2 - y2) / (x1 - y1);
32
- const b = y2 - a * y1;
33
- const c = (y1 * y1 + y2 * y2 - z1 * z1 - z2 * z2) + 2 * b * (z2 - y2);
34
- const d = y1 - z1 + a * (y2 - z2);
35
- const t1 = c / (2 * d);
36
- const t2 = a * t1 + b;
37
- return swapAxes ? [t2, t1] : [t1, t2];
38
- }
39
- export { findEquidistantPointOnLine };
1
+ /**
2
+ * @hidden
3
+ * @param x
4
+ * @param y
5
+ * @param z
6
+ * @returns The point on the line from y to x that is equidistant from y and z.
7
+ */
8
+ function findEquidistantPointOnLine(x, y, z) {
9
+ // Some basic algebra (not shown) finds the required point.
10
+ // Swap axes if x and y are more aligned to y-axis than to x-axis.
11
+ const swapAxes = Math.abs((x[1] - y[1]) / (x[0] - y[0])) > 1;
12
+ // Cache
13
+ let x1, x2, y1, y2, z1, z2;
14
+ if (swapAxes) {
15
+ x1 = x[1];
16
+ x2 = x[0];
17
+ y1 = y[1];
18
+ y2 = y[0];
19
+ z1 = z[1];
20
+ z2 = z[0];
21
+ }
22
+ else {
23
+ x1 = x[0];
24
+ x2 = x[1];
25
+ y1 = y[0];
26
+ y2 = y[1];
27
+ z1 = z[0];
28
+ z2 = z[1];
29
+ }
30
+ // a <= 1 (due to swapped axes)
31
+ const a = (x2 - y2) / (x1 - y1);
32
+ const b = y2 - a * y1;
33
+ const c = (y1 * y1 + y2 * y2 - z1 * z1 - z2 * z2) + 2 * b * (z2 - y2);
34
+ const d = y1 - z1 + a * (y2 - z2);
35
+ const t1 = c / (2 * d);
36
+ const t2 = a * t1 + b;
37
+ return swapAxes ? [t2, t1] : [t1, t2];
38
+ }
39
+ export { findEquidistantPointOnLine };
40
40
  //# sourceMappingURL=find-equidistant-point-on-line.js.map
@@ -1,11 +1,11 @@
1
- import { LlRbTree } from 'flo-ll-rb-tree';
2
- import { BezierPiece } from '../../bezier-piece.js';
3
- import { Loop } from '../../../loop.js';
4
- import { CpNode } from '../../../cp-node.js';
5
- import { IPointOnShape } from '../../../point-on-shape.js';
6
- /** @hidden */
7
- declare function getInitialBezierPieces(isHoleClosing: boolean, k: number, loops: Loop[], cpTrees: Map<Loop, LlRbTree<CpNode>>, y: IPointOnShape): {
8
- bezierPieces: BezierPiece[];
9
- δ: CpNode[];
10
- };
11
- export { getInitialBezierPieces };
1
+ import { LlRbTree } from 'flo-ll-rb-tree';
2
+ import { BezierPiece } from '../../bezier-piece.js';
3
+ import { Loop } from '../../../loop.js';
4
+ import { CpNode } from '../../../cp-node.js';
5
+ import { IPointOnShape } from '../../../point-on-shape.js';
6
+ /** @hidden */
7
+ declare function getInitialBezierPieces(isHoleClosing: boolean, k: number, loops: Loop[], cpTrees: Map<Loop, LlRbTree<CpNode>>, y: IPointOnShape): {
8
+ bezierPieces: BezierPiece[];
9
+ δ: CpNode[];
10
+ };
11
+ export { getInitialBezierPieces };