flo-mat 2.0.3 → 2.0.5

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 (43) hide show
  1. package/browser/index.js +298 -226
  2. package/browser/index.min.js +1 -1
  3. package/node/debug/functions/draw-elem/three-prong.js +1 -1
  4. package/node/debug/functions/draw-elem/two-prong.js +2 -2
  5. package/node/debug/functions/draw-elem/two-prong.js.map +1 -1
  6. package/node/mat/closest-boundary-point/closest-points-on-curve.js +9 -6
  7. package/node/mat/closest-boundary-point/closest-points-on-curve.js.map +1 -1
  8. package/node/mat/closest-boundary-point/get-close-boundary-points.js +0 -4
  9. package/node/mat/closest-boundary-point/get-close-boundary-points.js.map +1 -1
  10. package/node/mat/closest-boundary-point/get-closest-boundary-point.js.map +1 -1
  11. package/node/mat/find-mat/add-3-prong.js +16 -12
  12. package/node/mat/find-mat/add-3-prong.js.map +1 -1
  13. package/node/mat/find-mat/create-get-interesting-points-on-loop.js +5 -4
  14. package/node/mat/find-mat/create-get-interesting-points-on-loop.js.map +1 -1
  15. package/node/mat/find-mat/find-2-prong/find-2-prong.js +37 -7
  16. package/node/mat/find-mat/find-2-prong/find-2-prong.js.map +1 -1
  17. package/node/mat/find-mat/find-2-prong/find-equidistant-point-on-line-dd.d.ts +9 -0
  18. package/node/mat/find-mat/find-2-prong/find-equidistant-point-on-line-dd.js +58 -0
  19. package/node/mat/find-mat/find-2-prong/find-equidistant-point-on-line-dd.js.map +1 -0
  20. package/node/mat/find-mat/find-3-prong/find-3-prong-for-delta3s.js.map +1 -1
  21. package/node/mat/find-mat/get-sharp-corners.js +0 -1
  22. package/node/mat/find-mat/get-sharp-corners.js.map +1 -1
  23. package/node/mat/is-another-cp-closeby.js +5 -16
  24. package/node/mat/is-another-cp-closeby.js.map +1 -1
  25. package/node/point-on-shape.js.map +1 -1
  26. package/package.json +14 -14
  27. package/src/debug/functions/draw-elem/three-prong.ts +1 -1
  28. package/src/debug/functions/draw-elem/two-prong.ts +2 -2
  29. package/src/mat/closest-boundary-point/closest-points-on-curve.ts +12 -8
  30. package/src/mat/closest-boundary-point/get-close-boundary-points.ts +1 -5
  31. package/src/mat/closest-boundary-point/get-closest-boundary-point-dd.ts +62 -0
  32. package/src/mat/closest-boundary-point/get-closest-boundary-point.ts +7 -7
  33. package/src/mat/cmp-cp-on-delta.ts +3 -0
  34. package/src/mat/find-mat/add-3-prong.ts +23 -13
  35. package/src/mat/find-mat/create-get-interesting-points-on-loop.ts +5 -4
  36. package/src/mat/find-mat/find-2-prong/find-2-prong.ts +44 -9
  37. package/src/mat/find-mat/find-2-prong/find-equidistant-point-on-line-dd.ts +79 -0
  38. package/src/mat/find-mat/find-3-prong/find-3-prong-for-delta3s.ts +1 -1
  39. package/src/mat/find-mat/get-sharp-corners.ts +0 -1
  40. package/src/mat/is-another-cp-closeby.ts +8 -24
  41. package/src/point-on-shape.ts +2 -1
  42. package/src/mat/closest-boundary-point/closest-point-on-curve-old.ts_ +0 -88
  43. package/src/mat/closest-boundary-point/closest-point-on-curve.ts_ +0 -95
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "flo-mat",
3
3
  "sideEffects": false,
4
4
  "description": "Medial / Scale Axis Transform (MAT/SAT) Library.",
5
- "version": "2.0.3",
5
+ "version": "2.0.5",
6
6
  "author": {
7
7
  "name": "Floris Steenkamp"
8
8
  },
@@ -34,34 +34,34 @@
34
34
  "big-float-ts": "^3.0.3",
35
35
  "double-double": "^2.0.7",
36
36
  "flo-bezier3": "^4.1.4",
37
- "flo-boolean": "^2.1.6",
37
+ "flo-boolean": "^2.1.7",
38
38
  "flo-draw": "^2.0.2",
39
39
  "flo-gauss-quadrature": "^2.1.2",
40
40
  "flo-ll-rb-tree": "^0.3.3",
41
- "flo-memoize": "^1.0.2",
41
+ "flo-memoize": "^1.1.1",
42
42
  "flo-poly": "^6.0.5",
43
43
  "flo-vector2d": "^4.0.2"
44
44
  },
45
45
  "devDependencies": {
46
- "@types/chai": "^4.3.4",
46
+ "@types/chai": "^4.3.5",
47
47
  "@types/mocha": "^10.0.1",
48
- "@types/node": "^18.15.11",
49
- "@typescript-eslint/eslint-plugin": "^5.58.0",
50
- "@typescript-eslint/parser": "^5.58.0",
51
- "c8": "^7.13.0",
48
+ "@types/node": "^20.4.2",
49
+ "@typescript-eslint/eslint-plugin": "^6.0.0",
50
+ "@typescript-eslint/parser": "^6.0.0",
51
+ "c8": "^8.0.0",
52
52
  "chai": "^4.3.7",
53
53
  "circular-dependency-plugin": "^5.2.2",
54
- "eslint": "^8.38.0",
54
+ "eslint": "^8.45.0",
55
55
  "eslint-plugin-tree-shaking": "^1.10.0",
56
56
  "mocha": "^10.2.0",
57
57
  "resolve-typescript-plugin": "^2.0.1",
58
- "rimraf": "^5.0.0",
58
+ "rimraf": "^5.0.1",
59
59
  "source-map-support": "^0.5.21",
60
- "ts-loader": "^9.4.2",
60
+ "ts-loader": "^9.4.4",
61
61
  "ts-node": "^10.9.1",
62
- "typescript": "^5.0.4",
63
- "webpack": "^5.78.0",
64
- "webpack-cli": "^5.0.1"
62
+ "typescript": "^5.1.6",
63
+ "webpack": "^5.88.1",
64
+ "webpack-cli": "^5.1.4"
65
65
  },
66
66
  "scripts": {
67
67
  "build": "npm run build-browser && npm run build-node",
@@ -4,7 +4,7 @@ import { Circle, scaleCircle } from '../../../circle.js';
4
4
 
5
5
 
6
6
  /** @hidden */
7
- const scaleFactor = 0.3;
7
+ const scaleFactor = 0.1;
8
8
 
9
9
 
10
10
  /** @hidden */
@@ -5,7 +5,7 @@ import { getTwoProngType } from '../../../mat/get-two-prong-type.js';
5
5
 
6
6
  /** @hidden */
7
7
  function twoProng(g: SVGGElement, twoProng: TwoProngForDebugging) {
8
- const scaleFactor = 0.3;
8
+ const scaleFactor = 0.01;
9
9
 
10
10
  let $failedDot : SVGElement[] = [];
11
11
  let $center : SVGElement[] = [];
@@ -33,7 +33,7 @@ function twoProng(g: SVGGElement, twoProng: TwoProngForDebugging) {
33
33
  if (twoProng.failed) {
34
34
  $failedDot = drawFs.dot(g, twoProng.pos.p, 1*scaleFactor, 'black');
35
35
  } else if (!twoProng.failed) {
36
- $center = drawFs.dot (g, twoProng.circle.center, 1*scaleFactor, 'yellow');
36
+ $center = drawFs.dot (g, twoProng.circle.center, 0.02*scaleFactor, 'yellow');
37
37
  $circle = drawFs.circle(g, twoProng.circle, color + 'thin' + thin + ' nofill');
38
38
  $cp1 = drawFs.dot (g, twoProng.pos.p, 0.035*scaleFactor, color);
39
39
  $cp2 = drawFs.dot (g, twoProng.z, 0.07*scaleFactor, color);
@@ -1,9 +1,6 @@
1
- // qqq import { deflateQuad, allRootsMultiWithErrBounds, RootInterval } from 'flo-poly';
2
- // qqq import { getTangentPolyFromPointExact, evalDeCasteljau, evaluate, getFootpointPolyExact } from 'flo-bezier3';
3
1
  import { ddDeflate, allRootsCertified, RootInterval } from 'flo-poly';
4
- import { evalDeCasteljau, evaluate, getFootpointPolyDd, getFootpointPolyExact } from 'flo-bezier3';
2
+ import { evalDeCasteljau, evalDeCasteljauDd, evaluate, getFootpointPolyDd, getFootpointPolyExact } from 'flo-bezier3';
5
3
  import { Curve } from "../../curve.js";
6
- import { eToDd } from 'big-float-ts';
7
4
 
8
5
 
9
6
  /**
@@ -24,15 +21,12 @@ function closestPointsOnCurve(
24
21
  t: number;
25
22
  }[] {
26
23
 
27
- // qqq let poly = getTangentPolyFromPointExact(curve.ps, p);
28
24
  const _poly = getFootpointPolyDd(curve.ps, p);
29
25
 
30
- // qqq poly = deflateQuad(poly, t);
31
26
  const poly = curve === touchedCurve
32
27
  ? ddDeflate(_poly, t)
33
28
  : _poly;
34
29
 
35
- // let roots: Omit<RootInterval,'multiplicity'>[] = allRootsMultiWithErrBounds(
36
30
  const roots: Omit<RootInterval,'multiplicity'>[] = allRootsCertified(poly, tS, tE);
37
31
 
38
32
  // Also test the endpoints
@@ -72,8 +66,18 @@ function closestPointsOnCurve(
72
66
  ? 0
73
67
  : tE > 1 ? 1 : (tS + tE)/2;
74
68
  // TODO - why does evalDeCasteljau not work here?
75
- return { p: evaluate(curve.ps,t), t }
76
69
  //return { p: evalDeCasteljau(curve.ps,t), t }
70
+
71
+ // TODO2 - will make it slower
72
+ // const aa = evaluate(curve.ps,t);
73
+ // const bb = evalDeCasteljauDd(curve.ps,[0,t]).map(v => v[1]);
74
+ // if (aa[0] !== bb[0] || aa[1] !== bb[1]) {
75
+ // console.log(aa);
76
+ // console.log(bb);
77
+ // }
78
+ return { p: evaluate(curve.ps,t), t }
79
+ // return { p: evalDeCasteljauDd(curve.ps,[0,t]).map(v => v[1]), t }
80
+
77
81
  }
78
82
  );
79
83
 
@@ -69,11 +69,7 @@ function getCloseBoundaryPoints(
69
69
  // comparing closeness!
70
70
  const indexesToCheck: number[] = [];
71
71
  for (let i=0; i<posInfos.length; i++) {
72
- const pi = posInfos[i];
73
- // Only check if they are close to the edges. Why??
74
- //if (pi.pos.t < 1e-2 || 1-pi.pos.t < 1e-2) {
75
- indexesToCheck.push(i);
76
- //}
72
+ indexesToCheck.push(i);
77
73
  }
78
74
  const indexesToRemove: number[] = [];
79
75
  for (let i=0; i<indexesToCheck.length; i++) {
@@ -0,0 +1,62 @@
1
+ import { distanceBetween, getObjClosestTo } from 'flo-vector2d';
2
+ import { Curve } from '../../curve.js';
3
+ import { PointOnShape, IPointOnShape } from '../../point-on-shape.js';
4
+ import { BezierPiece } from '../bezier-piece.js';
5
+ import { cullBezierPieces } from './cull-bezier-pieces.js';
6
+ import { closestPointsOnCurve } from './closest-points-on-curve.js';
7
+
8
+
9
+ /**
10
+ * @hidden
11
+ * Returns the closest boundary point to the given point, limited to the given
12
+ * bezier pieces, including the beziers actually checked after culling.
13
+ * @param bezierPieces
14
+ * @param point
15
+ * @param touchedCurve
16
+ * @param t
17
+ * @param extreme
18
+ */
19
+ function getClosestBoundaryPointDd(
20
+ bezierPieces: BezierPiece[],
21
+ point: number[],
22
+ touchedCurve: Curve,
23
+ t: number) {
24
+
25
+ let bestDistance = Number.POSITIVE_INFINITY;
26
+ let posInfo: { pos: IPointOnShape; d: number };
27
+ for (let i=0; i<bezierPieces.length; i++) {
28
+ const bezierPiece = bezierPieces[i];
29
+
30
+ const ps = closestPointsOnCurve(
31
+ bezierPiece.curve,
32
+ point,
33
+ bezierPiece.ts,
34
+ touchedCurve,
35
+ t
36
+ );
37
+
38
+ const p = getObjClosestTo(point, ps, p => p.p)
39
+
40
+ if (p === undefined) { continue; }
41
+
42
+ const d = distanceBetween(p.p, point);
43
+
44
+ let curve = bezierPiece.curve;
45
+ let t_= p.t;
46
+
47
+ if (d < bestDistance) {
48
+ if (t_ === 0) {
49
+ t_ = 1;
50
+ curve = bezierPiece.curve.prev;
51
+ }
52
+
53
+ posInfo = { pos: new PointOnShape(curve, t_), d };
54
+ bestDistance = d;
55
+ }
56
+ }
57
+
58
+ return posInfo;
59
+ }
60
+
61
+
62
+ export { getClosestBoundaryPointDd };
@@ -29,13 +29,13 @@ function getClosestBoundaryPoint(
29
29
  for (let i=0; i<bezierPieces.length; i++) {
30
30
  const bezierPiece = bezierPieces[i];
31
31
 
32
- const ps = closestPointsOnCurve(
33
- bezierPiece.curve,
34
- point,
35
- bezierPiece.ts,
36
- touchedCurve,
37
- t
38
- );
32
+ const ps = closestPointsOnCurve(
33
+ bezierPiece.curve,
34
+ point,
35
+ bezierPiece.ts,
36
+ touchedCurve,
37
+ t
38
+ );
39
39
 
40
40
  const p = getObjClosestTo(point, ps, p => p.p)
41
41
 
@@ -4,11 +4,14 @@ import { ContactPoint, compareCps } from '../contact-point.js';
4
4
 
5
5
  /**
6
6
  * @hidden
7
+ *
7
8
  * Note: For debugging only
9
+ *
8
10
  * Checks the position of the ContactPoint (cp) on the boundary piece.
9
11
  * Returns < 0 if the cp is not on δ, > 0 if it is on the boundary piece
10
12
  * excluding the endpoints and 0 if it is on the endpoints. Also returns > 0 if
11
13
  * δ === undefined.
14
+ *
12
15
  * @param δ The boundary piece
13
16
  * @param cp The contact point
14
17
  */
@@ -1,10 +1,14 @@
1
+ declare const _debug_: Debug;
2
+
3
+ import { Debug } from '../../debug/debug.js';
1
4
  import { LlRbTree } from 'flo-ll-rb-tree';
2
5
  import { CpNode } from '../../cp-node.js';
3
6
  import { Loop } from '../../loop.js';
4
7
  import { Circle } from '../../circle.js';
5
- import { IPointOnShape } from '../../point-on-shape.js';
8
+ import { comparePoss, IPointOnShape, PointOnShape } from '../../point-on-shape.js';
6
9
  import { addToCpGraph } from '../add-to-cp-graph.js';
7
10
  import { isAnotherCpCloseby } from '../is-another-cp-closeby.js';
11
+ import { compareCps } from '../../contact-point.js';
8
12
 
9
13
 
10
14
  /**
@@ -27,27 +31,31 @@ function add3Prong(
27
31
  const { circle, ps: poss, δ3s } = threeProng;
28
32
 
29
33
  // Keep for possible future debugging.
34
+
30
35
  /*
31
36
  if (typeof _debug_ !== 'undefined') {
32
37
  for (let i=0; i<3; i++) {
33
- let cpBef = threeProng.δ3s[i][0].cp;
34
- let cpAft = threeProng.δ3s[i][1].cp;
35
- //let cmpBef = PointOnShape.compareInclOrder(cpBef.pointOnShape, ps[i], cpBef.order, orders[i]);
36
- //let cmpAft = PointOnShape.compareInclOrder(cpAft.pointOnShape, ps[i], cpAft.order, orders[i]);
38
+ const cpBef = threeProng.δ3s[i][0].cp;
39
+ const cpAft = threeProng.δ3s[i][1].cp;
37
40
 
38
- let cmpBef = PointOnShape.compare(cpBef.pointOnShape, ps[i]);
39
- let cmpAft = PointOnShape.compare(cpAft.pointOnShape, ps[i]);
41
+ //let cmpBef = PointOnShape.compareInclOrder(cpBef.pointOnShape, poss[i], cpBef.order, orders[i]);
42
+ //let cmpAft = PointOnShape.compareInclOrder(cpAft.pointOnShape, poss[i], cpAft.order, orders[i]);
43
+ const cmpBef = compareCps(cpBef, { pointOnShape: poss[i], order: orders[i], order2: 0, circle: undefined });
44
+ const cmpAft = compareCps(cpAft, { pointOnShape: poss[i], order: orders[i], order2: 0, circle: undefined });
45
+
46
+ // const cmpBef = comparePoss(cpBef.pointOnShape, poss[i]);
47
+ // const cmpAft = comparePoss(cpAft.pointOnShape, poss[i]);
40
48
 
41
49
  // len is used by debug functions to reference a particular
42
50
  // three-prong.
43
- let len = _debug_.generated.elems.threeProng.length-1;
51
+ const len = _debug_.generated.elems.threeProng.length-1;
44
52
  if (cmpBef > 0) {
45
53
  console.log('----------------------------------------');
46
54
  console.log(`3-prong order is wrong (bef) : i: ${i} - cmp: ${cmpBef} - n: ${len}`);
47
55
  console.log(threeProng);
48
56
  console.log(cpBef);
49
57
  console.log(cpAft);
50
- console.log(ps[i]);
58
+ console.log(poss[i]);
51
59
  }
52
60
  if (cmpAft < 0) {
53
61
  console.log('----------------------------------------');
@@ -55,16 +63,18 @@ function add3Prong(
55
63
  console.log(threeProng);
56
64
  console.log(cpBef);
57
65
  console.log(cpAft);
58
- console.log(ps[i]);
66
+ console.log(poss[i]);
59
67
  }
60
68
  }
61
69
  }
62
70
  */
63
71
 
64
72
  // TODO - replace 1000 below with correct value
65
- isAnotherCpCloseby(cpTrees, poss[0], circle, orders[0], 0, 1000, 'blue');
66
- isAnotherCpCloseby(cpTrees, poss[1], circle, orders[1], 0, 1000, 'blue');
67
- isAnotherCpCloseby(cpTrees, poss[2], circle, orders[2], 0, 1000, 'blue');
73
+ const c1 = isAnotherCpCloseby(cpTrees, poss[0], circle, orders[0], 0, 1000, 'blue');
74
+ const c2 = isAnotherCpCloseby(cpTrees, poss[1], circle, orders[1], 0, 1000, 'blue');
75
+ const c3 = isAnotherCpCloseby(cpTrees, poss[2], circle, orders[2], 0, 1000, 'blue');
76
+
77
+ // console.log(c1,c2,c3);
68
78
 
69
79
  addToCpGraph(circle, orders, cpTrees, poss, δ3s);
70
80
 
@@ -53,10 +53,11 @@ function getInterestingPointsOnLoop(
53
53
  ...maxAbsCurvatures,
54
54
  );
55
55
 
56
- let ts = splitByCurvatureAndLength(curve.ps, maxCurviness, maxLength);
57
- if (ts.length === 2) {
58
- ts = [0, 0.5, 1];
59
- }
56
+ const ts = splitByCurvatureAndLength(curve.ps, maxCurviness, maxLength);
57
+ // if (ts.length > 10) { console.log(ts); }
58
+ // if (ts.length === 2) {
59
+ // ts = [0, 0.5, 1];
60
+ // }
60
61
 
61
62
  for (let i=1; i<ts.length-1; i++) {
62
63
  allPoints.push( new PointOnShape(curve, ts[i]) );
@@ -1,10 +1,10 @@
1
1
  /** @internal */
2
2
  declare const _debug_: Debug;
3
3
 
4
+ import { Debug } from '../../../debug/debug.js';
4
5
  import { LlRbTree } from 'flo-ll-rb-tree';
5
6
  import { lineLineIntersection, distanceBetween, squaredDistanceBetween, interpolate, dot } from 'flo-vector2d';
6
7
  import { evalDeCasteljau as evalDeCasteljau_ } from 'flo-bezier3';
7
- import { Debug } from '../../../debug/debug.js';
8
8
  import { getClosestBoundaryPoint } from
9
9
  '../../closest-boundary-point/get-closest-boundary-point.js';
10
10
  import { CpNode } from '../../../cp-node.js';
@@ -17,6 +17,7 @@ import { addDebugInfo } from './add-debug-info.js';
17
17
  import { TXForDebugging } from './x-for-debugging.js';
18
18
  import { cullBezierPieces } from './cull-bezier-pieces.js';
19
19
  import { findEquidistantPointOnLine } from './find-equidistant-point-on-line.js';
20
+ import { findEquidistantPointOnLineDd } from './find-equidistant-point-on-line-dd.js';
20
21
  import { getInitialBezierPieces } from './get-initial-bezier-pieces.js';
21
22
  import { getCloseBoundaryPoints } from '../../closest-boundary-point/get-close-boundary-points.js';
22
23
 
@@ -59,9 +60,11 @@ function find2Prong(
59
60
  k: number) {
60
61
 
61
62
  const MAX_ITERATIONS = 25;
62
- const squaredSeperationTolerance = (1e-6 * extreme)**2;
63
+ const squaredSeperationTolerance = (1e-5 * extreme)**2;
63
64
  // TODO - base deltas on theory or remove
64
65
  const oneProngTolerance = (1e-4)**2;
66
+ // const oneProngTolerance = (1e-5)**2;
67
+ // const oneProngTolerance = 0;
65
68
  const squaredErrorTolerance = 1e-2 * squaredSeperationTolerance;
66
69
  const maxOsculatingCircleRadiusSquared = squaredDiagonalLength;
67
70
 
@@ -82,7 +85,6 @@ function find2Prong(
82
85
  r = maxOsculatingCircleRadiusSquared;
83
86
  } else {
84
87
  p = y.p;
85
- //x = PointOnShape.getOsculatingCircle(maxOsculatingCircleRadiusSquared, y).center;
86
88
  x = getOsculatingCircle(maxOsculatingCircleRadiusSquared, y).center;
87
89
  r = squaredDistanceBetween(p,x);
88
90
  }
@@ -107,9 +109,9 @@ function find2Prong(
107
109
  i++
108
110
 
109
111
  /** squared distance between source boundary point and circle center */
110
- const r = squaredDistanceBetween(x, y.p);
112
+ const xy = squaredDistanceBetween(x, y.p);
111
113
 
112
- bezierPieces_ = cullBezierPieces(bezierPieces_, x, r);
114
+ bezierPieces_ = cullBezierPieces(bezierPieces_, x, xy);
113
115
 
114
116
  z = getClosestBoundaryPoint(
115
117
  bezierPieces_,
@@ -140,17 +142,19 @@ function find2Prong(
140
142
  }
141
143
 
142
144
  /** squared distance between anti-pode boundary point and circle center */
143
- const d = squaredDistanceBetween(x, z.pos.p);
145
+ const xz = squaredDistanceBetween(x, z.pos.p);
144
146
  //if (i === 1 && d*oneProngTolerance >= r) {
145
- if (i === 1 && r < d+oneProngTolerance) {
147
+ if (i === 1 && xy < xz+oneProngTolerance) {
146
148
  // It is a 1-prong.
149
+ // TODO2 - below line was removed (maybe)
147
150
  add1Prong(Math.sqrt(maxOsculatingCircleRadiusSquared), cpTrees, y);
148
151
  return undefined;
149
152
  }
150
153
 
151
154
  // TODO - squaredSeperationTolerance should in future be replaced with
152
155
  // a relative error, i.e. distance between y (or z) / length(y (or z)).
153
- if (!isHoleClosing && squaredDistanceBetween(y.p, z.pos.p) <= squaredSeperationTolerance) {
156
+ const yz = squaredDistanceBetween(y.p, z.pos.p);
157
+ if (!isHoleClosing && yz <= squaredSeperationTolerance) {
154
158
  if (typeof _debug_ !== 'undefined') {
155
159
  /*
156
160
  let elems = _debug_.generated.elems;
@@ -174,9 +178,10 @@ function find2Prong(
174
178
 
175
179
  // Find the point on the line connecting y with x that is
176
180
  // equidistant from y and z. This will be our next x.
181
+ // const nextX = findEquidistantPointOnLineDd(x, y.p, z.pos.p);
177
182
  const nextX = findEquidistantPointOnLine(x, y.p, z.pos.p);
178
-
179
183
  const squaredError = squaredDistanceBetween(x, nextX);
184
+ // const squaredError = Math.abs(xy - xz);
180
185
 
181
186
  x = nextX;
182
187
 
@@ -189,6 +194,32 @@ function find2Prong(
189
194
  }
190
195
  } while (done < 1);
191
196
 
197
+
198
+ /************************************************************************ */
199
+ /* Do one more double-double precision iteration
200
+ /************************************************************************ */
201
+ /*
202
+ z = getClosestBoundaryPoint(
203
+ bezierPieces_, x, y.curve, y.t
204
+ );
205
+
206
+ if (z === undefined) {
207
+ failed = true;
208
+ }
209
+
210
+ if (typeof _debug_ !== 'undefined') {
211
+ xs.push({ x, y, z: z.pos, t: y.t });
212
+ }
213
+
214
+ if (!isHoleClosing && squaredDistanceBetween(y.p, z.pos.p) <= squaredSeperationTolerance) {
215
+ failed = true;
216
+ } else {
217
+ x = findEquidistantPointOnLineDd(x, y.p, z.pos.p);
218
+ }
219
+ /************************************************************************ */
220
+ /************************************************************************ */
221
+
222
+
192
223
  // TODO - Optimization: only do this if second closest point is within the
193
224
  // tolerance which can be checked in getClosestBoundaryPoint algorithm
194
225
  let zs: { pos: IPointOnShape; d: number; }[] = [];
@@ -211,6 +242,10 @@ function find2Prong(
211
242
  circle = { center: x, radius: distanceBetween(x, z.pos.p) };
212
243
  }
213
244
 
245
+
246
+ // TODO2
247
+ // if (Math.random() > 0.8 && !isHoleClosing) { return undefined; }
248
+
214
249
  if (typeof _debug_ !== 'undefined' && !failed) {
215
250
  xs.push({ x, y, z: z.pos, t: y.t });
216
251
  addDebugInfo(bezierPieces, failed, y, circle, z.pos, δ, xs, isHoleClosing);
@@ -0,0 +1,79 @@
1
+ import {
2
+ twoDiff, twoSum, twoProduct, doubleDivDouble, ddDivDd,
3
+ ddAddDd, ddDiffDd, ddMultDd, ddMultBy2, ddMultDouble1
4
+ } from "double-double";
5
+
6
+
7
+ const { abs } = Math;
8
+
9
+ const td = twoDiff;
10
+ const ts = twoSum;
11
+ const tp = twoProduct;
12
+
13
+
14
+
15
+ /**
16
+ * @hidden
17
+ * @param x
18
+ * @param y
19
+ * @param z
20
+ * @returns The point on the line from y to x that is equidistant from y and z.
21
+ */
22
+ function findEquidistantPointOnLineDd(x: number[], y: number[], z: number[]) {
23
+ // Some basic algebra (not shown) finds the required point.
24
+
25
+ // Swap axes if x and y are more aligned to y-axis than to x-axis.
26
+ // TODO2 - changed
27
+ // const swapAxes = abs((x[1] - y[1]) / (x[0] - y[0])) > 1;
28
+ const swapAxes = abs(x[1] - y[1]) > abs(x[0] - y[0]);
29
+
30
+ // Cache
31
+ let x1: number;
32
+ let x2: number;
33
+ let y1: number;
34
+ let y2: number;
35
+ let z1: number;
36
+ let z2: number;
37
+
38
+ if (swapAxes) {
39
+ x1 = x[1]; x2 = x[0];
40
+ y1 = y[1]; y2 = y[0];
41
+ z1 = z[1]; z2 = z[0];
42
+ } else {
43
+ x1 = x[0]; x2 = x[1];
44
+ y1 = y[0]; y2 = y[1];
45
+ z1 = z[0]; z2 = z[1];
46
+ }
47
+
48
+ // a <= 1 (due to swapped axes)
49
+ // const a = (x2 - y2) / (x1 - y1);
50
+ // const b = y2 - a*y1;
51
+ // const c = (y1*y1 + y2*y2 - z1*z1 - z2*z2) + 2*b*(z2 - y2);
52
+ // const d = y1 - z1 + a*(y2 - z2);
53
+ // const t1 = c/(2*d);
54
+ // const t2 = a*t1 + b;
55
+
56
+
57
+ const a = ddDivDd(td(x2,y2),td(x1,y1));
58
+ const b = ddDiffDd([0,y2], ddMultDouble1(y1,a));
59
+
60
+
61
+
62
+ const c = ddAddDd(
63
+ (ddDiffDd(
64
+ ddAddDd(tp(y1,y1), tp(y2,y2)),
65
+ ddAddDd(tp(z1,z1), tp(z2,z2))
66
+ )),
67
+ ddMultBy2(ddMultDd(b,(td(z2,y2))))
68
+ );
69
+
70
+
71
+ const d = ddAddDd(td(y1,z1), ddMultDd(a,td(y2,z2)));
72
+ const t1 = ddDivDd(c,ddMultBy2(d));
73
+ const t2 = ddAddDd(ddMultDd(a,t1), b);
74
+
75
+ return swapAxes ? [t2[1],t1[1]] : [t1[1],t2[1]];
76
+ }
77
+
78
+
79
+ export { findEquidistantPointOnLineDd }
@@ -14,7 +14,7 @@ import { getClosestBoundaryPoint } from '../../closest-boundary-point/get-closes
14
14
  import { calcInitial3ProngCenter } from './calc-initial-3-prong-center.js';
15
15
  import { getClosestPoints } from './get-closest-points.js';
16
16
  import { calcBetterX } from './calc-better-x.js';
17
- import { Curve, getCornerAtEnd } from '../../../curve.js';
17
+ import { getCornerAtEnd } from '../../../curve.js';
18
18
 
19
19
 
20
20
  /** @hidden */
@@ -9,7 +9,6 @@ function getSharpCorners(possPerLoop: IPointOnShape[][]) {
9
9
  const sharpCorners = [];
10
10
 
11
11
  for (const pos of poss) {
12
- //if (PointOnShape.isQuiteSharpCorner(pos)) {
13
12
  if (isPosQuiteSharpCorner(pos)) {
14
13
  sharpCorners.push(pos);
15
14
  }
@@ -8,12 +8,7 @@ import { getNeighbouringPoints } from './get-neighboring-cps.js';
8
8
 
9
9
 
10
10
  /** @hidden */
11
- //const ANGLE_THRESHOLD = Math.cos(3 * (Math.PI / 180)); // 3 degrees
12
- const ANGLE_THRESHOLD = 0.9986295347545738; // === Math.cos(3 degrees)
13
- //const ANGLE_THRESHOLD = 0.9848077530122080; // === Math.cos(10 degrees)
14
- //const ANGLE_THRESHOLD = 0.9998476951563913; // === Math.cos(1 degrees)
15
- //const ANGLE_THRESHOLD = 0.9999984769132877; // === Math.cos(0.1 degrees)
16
- //const ANGLE_THRESHOLD = 0.9999999847691291 // === Math.cos(0.01 degrees)
11
+ const ANGLE_THRESHOLD = Math.cos(15 * (Math.PI / 180)); // 15 degrees
17
12
 
18
13
 
19
14
  /**
@@ -38,15 +33,7 @@ function isAnotherCpCloseby(
38
33
  extreme: number,
39
34
  color: string): boolean {
40
35
 
41
- //console.log(extreme)
42
- //const DISTANCE_THRESHOLD = extreme * 1e-1;
43
- //const DISTANCE_THRESHOLD = extreme * 1e-1;
44
36
  const DISTANCE_THRESHOLD = extreme * 1e-4;
45
- //const DISTANCE_THRESHOLD = extreme * 1e-4; - was this
46
- //const DISTANCE_THRESHOLD = extreme * 1e-6;
47
- //const DISTANCE_THRESHOLD = extreme * 1e-12;
48
- // It seems this can be zero else the ordering should be correct
49
- //const DISTANCE_THRESHOLD = 0;
50
37
 
51
38
  const cpTree = cpTrees.get(pos.curve.loop);
52
39
  const cpNodes = getNeighbouringPoints(cpTree, pos, order, order2);
@@ -61,18 +48,15 @@ function isAnotherCpCloseby(
61
48
  continue;
62
49
  }
63
50
 
64
- const v1 = toUnitVector(fromTo(
65
- cpNode.cp.pointOnShape.p,
66
- cpNode.cp.circle.center
67
- ));
68
- const v2 = toUnitVector(fromTo(
69
- p1,
70
- circle.center
71
- ));
51
+ // TODO2
52
+ return true;
53
+
54
+ const v1 = toUnitVector(fromTo(p2, cpNode.cp.circle.center));
55
+ const v2 = toUnitVector(fromTo(p1, circle.center));
72
56
  const cosTheta = dot(v1,v2);
73
-
57
+
74
58
  if (cosTheta > ANGLE_THRESHOLD) {
75
- //console.log(`%c${cosTheta} - ${distanceBetween(p1,p2)}`, `color: ${color}`);
59
+ // console.log(`%c${cosTheta} - ${distanceBetween(p1,p2)}`, `color: ${color}`);
76
60
  return true;
77
61
  }
78
62
  }
@@ -3,6 +3,7 @@ import { memoize } from 'flo-memoize';
3
3
  import { curvature, evalDeCasteljau, tangent } from 'flo-bezier3';
4
4
  import { Curve, getCornerAtEnd } from './curve.js';
5
5
  import { Circle } from './circle.js';
6
+ import { Corner } from './mat/corner.js';
6
7
 
7
8
 
8
9
  interface IPointOnShape {
@@ -55,7 +56,7 @@ function isPosCorner(pos: IPointOnShape) {
55
56
  /**
56
57
  * @hidden
57
58
  */
58
- function getPosCorner(pos: IPointOnShape) {
59
+ function getPosCorner(pos: IPointOnShape): Corner {
59
60
  return getCornerAtEnd(
60
61
  pos.t === 1 ? pos.curve : pos.curve.prev
61
62
  );