flo-mat 2.0.4 → 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.
- package/browser/index.js +75 -53
- package/browser/index.min.js +1 -1
- package/node/debug/functions/draw-elem/three-prong.js +1 -1
- package/node/debug/functions/draw-elem/two-prong.js +2 -2
- package/node/debug/functions/draw-elem/two-prong.js.map +1 -1
- package/node/mat/closest-boundary-point/closest-points-on-curve.js +9 -6
- package/node/mat/closest-boundary-point/closest-points-on-curve.js.map +1 -1
- package/node/mat/closest-boundary-point/get-close-boundary-points.js +0 -4
- package/node/mat/closest-boundary-point/get-close-boundary-points.js.map +1 -1
- package/node/mat/closest-boundary-point/get-closest-boundary-point.js.map +1 -1
- package/node/mat/find-mat/add-3-prong.js +16 -12
- package/node/mat/find-mat/add-3-prong.js.map +1 -1
- package/node/mat/find-mat/create-get-interesting-points-on-loop.js +5 -4
- package/node/mat/find-mat/create-get-interesting-points-on-loop.js.map +1 -1
- package/node/mat/find-mat/find-2-prong/find-2-prong.js +37 -7
- package/node/mat/find-mat/find-2-prong/find-2-prong.js.map +1 -1
- package/node/mat/find-mat/find-2-prong/find-equidistant-point-on-line-dd.d.ts +9 -0
- package/node/mat/find-mat/find-2-prong/find-equidistant-point-on-line-dd.js +58 -0
- package/node/mat/find-mat/find-2-prong/find-equidistant-point-on-line-dd.js.map +1 -0
- package/node/mat/find-mat/find-3-prong/find-3-prong-for-delta3s.js.map +1 -1
- package/node/mat/find-mat/get-sharp-corners.js +0 -1
- package/node/mat/find-mat/get-sharp-corners.js.map +1 -1
- package/node/mat/is-another-cp-closeby.js +5 -16
- package/node/mat/is-another-cp-closeby.js.map +1 -1
- package/node/point-on-shape.js.map +1 -1
- package/package.json +2 -2
- package/src/debug/functions/draw-elem/three-prong.ts +1 -1
- package/src/debug/functions/draw-elem/two-prong.ts +2 -2
- package/src/mat/closest-boundary-point/closest-points-on-curve.ts +12 -8
- package/src/mat/closest-boundary-point/get-close-boundary-points.ts +1 -5
- package/src/mat/closest-boundary-point/get-closest-boundary-point-dd.ts +62 -0
- package/src/mat/closest-boundary-point/get-closest-boundary-point.ts +7 -7
- package/src/mat/cmp-cp-on-delta.ts +3 -0
- package/src/mat/find-mat/add-3-prong.ts +23 -13
- package/src/mat/find-mat/create-get-interesting-points-on-loop.ts +5 -4
- package/src/mat/find-mat/find-2-prong/find-2-prong.ts +44 -9
- package/src/mat/find-mat/find-2-prong/find-equidistant-point-on-line-dd.ts +79 -0
- package/src/mat/find-mat/find-3-prong/find-3-prong-for-delta3s.ts +1 -1
- package/src/mat/find-mat/get-sharp-corners.ts +0 -1
- package/src/mat/is-another-cp-closeby.ts +8 -24
- package/src/point-on-shape.ts +2 -1
- package/src/mat/closest-boundary-point/closest-point-on-curve-old.ts_ +0 -88
- package/src/mat/closest-boundary-point/closest-point-on-curve.ts_ +0 -95
|
@@ -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
|
-
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
|
|
34
|
-
|
|
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.
|
|
39
|
-
let cmpAft = PointOnShape.
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
57
|
-
if (ts.length
|
|
58
|
-
|
|
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-
|
|
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
|
|
112
|
+
const xy = squaredDistanceBetween(x, y.p);
|
|
111
113
|
|
|
112
|
-
bezierPieces_ = cullBezierPieces(bezierPieces_, x,
|
|
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
|
|
145
|
+
const xz = squaredDistanceBetween(x, z.pos.p);
|
|
144
146
|
//if (i === 1 && d*oneProngTolerance >= r) {
|
|
145
|
-
if (i === 1 &&
|
|
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
|
-
|
|
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 {
|
|
17
|
+
import { getCornerAtEnd } from '../../../curve.js';
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
/** @hidden */
|
|
@@ -8,12 +8,7 @@ import { getNeighbouringPoints } from './get-neighboring-cps.js';
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
/** @hidden */
|
|
11
|
-
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
}
|
package/src/point-on-shape.ts
CHANGED
|
@@ -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
|
);
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { deflate, allRootsPrecise } from 'flo-poly';
|
|
3
|
-
|
|
4
|
-
import { getObjClosestTo } from 'flo-vector2d';
|
|
5
|
-
import { evaluate, getTangentPolyFromPoint } from 'flo-bezier3';
|
|
6
|
-
|
|
7
|
-
import { Curve } from "../../curve";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
/** @hidden */
|
|
11
|
-
// TODO - remove delta
|
|
12
|
-
let DELTA = 1e-11;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @hidden
|
|
17
|
-
* @param curve The curve
|
|
18
|
-
* @param p The point from which to check
|
|
19
|
-
* @param tRange The allowed t range
|
|
20
|
-
* @param touchedCurve The bezier on which p is located
|
|
21
|
-
* @param t The t value of the bezier that locates p
|
|
22
|
-
*/
|
|
23
|
-
function closestPointOnCurve(
|
|
24
|
-
curve: Curve,
|
|
25
|
-
p: number[],
|
|
26
|
-
tRange: number[] = [0,1],
|
|
27
|
-
touchedCurve?: Curve,
|
|
28
|
-
t?: number) {
|
|
29
|
-
|
|
30
|
-
let poly = getTangentPolyFromPoint(curve.ps, p);
|
|
31
|
-
|
|
32
|
-
if (curve === touchedCurve) {
|
|
33
|
-
poly = deflate(poly, t);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
let roots = allRootsPrecise(poly, tRange[0], tRange[1]);
|
|
37
|
-
|
|
38
|
-
// Also test the endpoints
|
|
39
|
-
let push0 = true;
|
|
40
|
-
let push1 = true;
|
|
41
|
-
if ((t === 1 && curve === touchedCurve.next) ||
|
|
42
|
-
(t === 0 && curve === touchedCurve)) {
|
|
43
|
-
push0 = false;
|
|
44
|
-
}
|
|
45
|
-
if ((t === 0 && curve === touchedCurve.prev) ||
|
|
46
|
-
(t === 1 && curve === touchedCurve)) {
|
|
47
|
-
push1 = false;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (tRange[0] === 0) {
|
|
51
|
-
if (push0) { roots.push(0); }
|
|
52
|
-
} else if (tRange[0] === 1) {
|
|
53
|
-
if (push1) { roots.push(1); }
|
|
54
|
-
} else {
|
|
55
|
-
roots.push(tRange[0]);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (tRange[1] === 0) {
|
|
59
|
-
if (push0) { roots.push(0); }
|
|
60
|
-
} else if (tRange[1] === 1) {
|
|
61
|
-
if (push1) { roots.push(1); }
|
|
62
|
-
} else {
|
|
63
|
-
roots.push(tRange[1]);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// This is to take care of a numerical issue - see shape p1.svg.
|
|
67
|
-
let roots_: number[] = [];
|
|
68
|
-
for (let i=0; i<roots.length; i++) {
|
|
69
|
-
let root = roots[i];
|
|
70
|
-
if (root !== 0 && root < DELTA) {
|
|
71
|
-
root = 0;
|
|
72
|
-
} else if (root !== 1 && 1-root < DELTA) {
|
|
73
|
-
root = 1;
|
|
74
|
-
}
|
|
75
|
-
roots_.push(root);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
let ev = evaluate(curve.ps);
|
|
79
|
-
let ps = roots_.map(
|
|
80
|
-
//let ps = roots.map(
|
|
81
|
-
root => ({ p: ev(root), t: root })
|
|
82
|
-
);
|
|
83
|
-
|
|
84
|
-
return getObjClosestTo(p, ps, p => p.p);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
export { closestPointOnCurve }
|