svg-path-simplify 0.0.7 → 0.0.8
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/dist/svg-path-simplify.esm.js +775 -169
- package/dist/svg-path-simplify.esm.min.js +1 -1
- package/dist/svg-path-simplify.js +4674 -4068
- package/dist/svg-path-simplify.min.js +1 -1
- package/dist/svg-path-simplify.node.js +775 -169
- package/dist/svg-path-simplify.node.min.js +1 -1
- package/index.html +11 -8
- package/package.json +5 -3
- package/src/dom-polyfill.js +29 -0
- package/src/dom-polyfill_back.js +22 -0
- package/src/index.js +7 -1
- package/src/pathData_simplify_cubic.js +1 -37
- package/src/pathData_simplify_cubic_extrapolate.js +43 -28
- package/src/pathSimplify-main.js +50 -9
- package/src/svgii/geometry.js +8 -155
- package/src/svgii/geometry_flatness.js +101 -0
- package/src/svgii/pathData_analyze.js +11 -596
- package/src/svgii/pathData_parse_els.js +239 -0
- package/src/svgii/pathData_remove_collinear.js +3 -1
- package/src/svgii/pathData_remove_orphaned.js +20 -0
- package/src/svgii/pathData_remove_zerolength.js +12 -2
- package/src/svgii/pathData_reorder.js +3 -1
- package/src/svgii/pathData_split.js +1 -0
- package/src/svgii/rounding.js +25 -19
- package/src/svgii/simplify_refineExtremes.js +173 -0
- package/src/svgii/svg_cleanup.js +4 -1
- package/testSVG.js +39 -0
package/src/pathSimplify-main.js
CHANGED
|
@@ -2,11 +2,13 @@ import { detectInputType } from './detect_input';
|
|
|
2
2
|
import { combineCubicPairs } from './pathData_simplify_cubic';
|
|
3
3
|
import { getPathDataVertices, pointAtT } from './svgii/geometry';
|
|
4
4
|
import { getPolyBBox } from './svgii/geometry_bbox';
|
|
5
|
-
import { analyzePathData
|
|
5
|
+
import { analyzePathData } from './svgii/pathData_analyze';
|
|
6
6
|
import { combineArcs, convertPathData, cubicCommandToArc, revertCubicQuadratic } from './svgii/pathData_convert';
|
|
7
7
|
import { parsePathDataNormalized } from './svgii/pathData_parse';
|
|
8
|
+
import { shapeElToPath } from './svgii/pathData_parse_els';
|
|
8
9
|
import { pathDataRemoveColinear } from './svgii/pathData_remove_collinear';
|
|
9
|
-
import {
|
|
10
|
+
import { removeOrphanedM } from './svgii/pathData_remove_orphaned';
|
|
11
|
+
import { removeZeroLengthLinetos } from './svgii/pathData_remove_zerolength';
|
|
10
12
|
import { optimizeClosePath, pathDataToTopLeft } from './svgii/pathData_reorder';
|
|
11
13
|
import { reversePathData } from './svgii/pathData_reverse';
|
|
12
14
|
import { addExtremePoints, splitSubpaths } from './svgii/pathData_split';
|
|
@@ -15,6 +17,7 @@ import { pathDataToD } from './svgii/pathData_stringify';
|
|
|
15
17
|
import { analyzePoly } from './svgii/poly_analyze';
|
|
16
18
|
import { getCurvePathData } from './svgii/poly_to_pathdata';
|
|
17
19
|
import { detectAccuracy } from './svgii/rounding';
|
|
20
|
+
import { refineAdjacentExtremes } from './svgii/simplify_refineExtremes';
|
|
18
21
|
import { cleanUpSVG, removeEmptySVGEls, stringifySVG } from './svgii/svg_cleanup';
|
|
19
22
|
import { renderPoint } from './svgii/visualize';
|
|
20
23
|
|
|
@@ -42,11 +45,13 @@ export function svgPathSimplify(input = '', {
|
|
|
42
45
|
flatBezierToLinetos = true,
|
|
43
46
|
revertToQuadratics = true,
|
|
44
47
|
|
|
48
|
+
refineExtremes = true,
|
|
45
49
|
keepExtremes = true,
|
|
46
50
|
keepCorners = true,
|
|
47
51
|
extrapolateDominant = true,
|
|
48
52
|
keepInflections = false,
|
|
49
53
|
addExtremes = false,
|
|
54
|
+
removeOrphanSubpaths = false,
|
|
50
55
|
|
|
51
56
|
|
|
52
57
|
// svg path optimizations
|
|
@@ -61,6 +66,7 @@ export function svgPathSimplify(input = '', {
|
|
|
61
66
|
mergePaths = false,
|
|
62
67
|
removeHidden = true,
|
|
63
68
|
removeUnused = true,
|
|
69
|
+
shapesToPaths = true,
|
|
64
70
|
|
|
65
71
|
|
|
66
72
|
} = {}) {
|
|
@@ -105,6 +111,14 @@ export function svgPathSimplify(input = '', {
|
|
|
105
111
|
svg = cleanUpSVG(input, { returnDom, removeHidden, removeUnused }
|
|
106
112
|
);
|
|
107
113
|
|
|
114
|
+
if(shapesToPaths){
|
|
115
|
+
let shapes = svg.querySelectorAll('polygon, polyline, line, rect, circle, ellipse');
|
|
116
|
+
shapes.forEach(shape=>{
|
|
117
|
+
let path = shapeElToPath(shape);
|
|
118
|
+
shape.replaceWith(path)
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
|
|
108
122
|
// collect paths
|
|
109
123
|
let pathEls = svg.querySelectorAll('path')
|
|
110
124
|
pathEls.forEach(path => {
|
|
@@ -132,15 +146,23 @@ export function svgPathSimplify(input = '', {
|
|
|
132
146
|
paths.forEach(path => {
|
|
133
147
|
let { d, el } = path;
|
|
134
148
|
|
|
149
|
+
///let t0 = performance.now()
|
|
135
150
|
let pathDataO = parsePathDataNormalized(d, { quadraticToCubic, toAbsolute, arcToCubic });
|
|
136
|
-
//console.log(pathDataO);
|
|
137
|
-
|
|
138
|
-
// create clone for fallback
|
|
139
|
-
let pathData = JSON.parse(JSON.stringify(pathDataO));
|
|
151
|
+
//console.log('pathDataO', pathDataO);
|
|
140
152
|
|
|
141
153
|
// count commands for evaluation
|
|
142
154
|
let comCount = pathDataO.length
|
|
143
155
|
|
|
156
|
+
|
|
157
|
+
// create clone for fallback
|
|
158
|
+
//let pathData = JSON.parse(JSON.stringify(pathDataO));
|
|
159
|
+
let pathData = pathDataO;
|
|
160
|
+
//let t1 = performance.now() - t0;
|
|
161
|
+
//console.log('t1', t1);
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
if(removeOrphanSubpaths) pathData = removeOrphanedM(pathData);
|
|
165
|
+
|
|
144
166
|
/**
|
|
145
167
|
* get sub paths
|
|
146
168
|
*/
|
|
@@ -182,8 +204,17 @@ export function svgPathSimplify(input = '', {
|
|
|
182
204
|
//let pathDataN = pathData;
|
|
183
205
|
|
|
184
206
|
//console.log(pathDataPlus);
|
|
185
|
-
|
|
207
|
+
//let t0=performance.now()
|
|
186
208
|
pathData = simplifyBezier ? simplifyPathDataCubic(pathData, { simplifyBezier, keepInflections, keepExtremes, keepCorners, extrapolateDominant, revertToQuadratics, tolerance, reverse }) : pathData;
|
|
209
|
+
//let t1=performance.now() - t0;
|
|
210
|
+
//console.log('t1', t1);
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
// refine extremes
|
|
214
|
+
if(refineExtremes){
|
|
215
|
+
let thresholdEx = (bb.width + bb.height) / 2 * 0.05
|
|
216
|
+
pathData = refineAdjacentExtremes(pathData, {threshold:thresholdEx, tolerance})
|
|
217
|
+
}
|
|
187
218
|
|
|
188
219
|
|
|
189
220
|
// cubic to arcs
|
|
@@ -207,6 +238,9 @@ export function svgPathSimplify(input = '', {
|
|
|
207
238
|
}
|
|
208
239
|
|
|
209
240
|
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
|
|
210
244
|
// simplify to quadratics
|
|
211
245
|
if (revertToQuadratics) {
|
|
212
246
|
pathData.forEach((com, c) => {
|
|
@@ -232,6 +266,7 @@ export function svgPathSimplify(input = '', {
|
|
|
232
266
|
|
|
233
267
|
//if (removeColinear) pathDataSub = pathDataRemoveColinear(pathDataSub, tolerance, flatBezierToLinetos);
|
|
234
268
|
|
|
269
|
+
|
|
235
270
|
// optimize close path
|
|
236
271
|
if (optimizeOrder) pathData = optimizeClosePath(pathData)
|
|
237
272
|
|
|
@@ -260,13 +295,17 @@ export function svgPathSimplify(input = '', {
|
|
|
260
295
|
*/
|
|
261
296
|
if (autoAccuracy) {
|
|
262
297
|
decimals = detectAccuracy(pathData)
|
|
298
|
+
pathOptions.decimals = decimals
|
|
299
|
+
//console.log('!decimals', decimals);
|
|
263
300
|
}
|
|
264
301
|
|
|
302
|
+
//console.log('autoAccuracy', autoAccuracy, decimals);
|
|
303
|
+
|
|
265
304
|
// optimize path data
|
|
266
305
|
pathData = convertPathData(pathData, pathOptions)
|
|
267
306
|
|
|
268
307
|
// remove zero-length segments introduced by rounding
|
|
269
|
-
pathData =
|
|
308
|
+
pathData = removeZeroLengthLinetos(pathData);
|
|
270
309
|
|
|
271
310
|
// compare command count
|
|
272
311
|
let comCountS = pathData.length
|
|
@@ -301,7 +340,8 @@ export function svgPathSimplify(input = '', {
|
|
|
301
340
|
let pathData = convertPathData(pathData_merged, pathOptions)
|
|
302
341
|
|
|
303
342
|
// remove zero-length segments introduced by rounding
|
|
304
|
-
pathData = removeZeroLengthLinetos_post(pathData);
|
|
343
|
+
//pathData = removeZeroLengthLinetos_post(pathData);
|
|
344
|
+
pathData = removeZeroLengthLinetos(pathData);
|
|
305
345
|
|
|
306
346
|
|
|
307
347
|
let dOpt = pathDataToD(pathData, minifyD)
|
|
@@ -419,6 +459,7 @@ function simplifyPathDataCubic(pathData, {
|
|
|
419
459
|
// add cumulative error to prevent distortions
|
|
420
460
|
//console.log('combined', combined);
|
|
421
461
|
error += combined[0].error * 0.5;
|
|
462
|
+
//error += combined[0].error * 1;
|
|
422
463
|
offset++
|
|
423
464
|
}
|
|
424
465
|
com = combined[0]
|
package/src/svgii/geometry.js
CHANGED
|
@@ -23,19 +23,24 @@ export function getAngle(p1, p2, normalize = false) {
|
|
|
23
23
|
* http://jsfiddle.net/justin_c_rounds/Gd2S2/light/
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
export function checkLineIntersection(p1, p2, p3, p4, exact = true) {
|
|
26
|
+
export function checkLineIntersection(p1=null, p2=null, p3=null, p4=null, exact = true, debug=false) {
|
|
27
27
|
// if the lines intersect, the result contains the x and y of the intersection (treating the lines as infinite) and booleans for whether line segment 1 or line segment 2 contain the point
|
|
28
28
|
let denominator, a, b, numerator1, numerator2;
|
|
29
29
|
let intersectionPoint = {}
|
|
30
30
|
|
|
31
|
+
if(!p1 || !p2 || !p3 || !p4){
|
|
32
|
+
if(debug) console.warn('points missing');
|
|
33
|
+
return false
|
|
34
|
+
}
|
|
35
|
+
|
|
31
36
|
try {
|
|
32
37
|
denominator = ((p4.y - p3.y) * (p2.x - p1.x)) - ((p4.x - p3.x) * (p2.y - p1.y));
|
|
33
38
|
if (denominator == 0) {
|
|
34
39
|
return false;
|
|
35
40
|
}
|
|
36
|
-
|
|
37
41
|
} catch {
|
|
38
|
-
console.
|
|
42
|
+
if(debug) console.warn('!catch', p1, p2, 'p3:', p3, 'p4:', p4);
|
|
43
|
+
return false
|
|
39
44
|
}
|
|
40
45
|
|
|
41
46
|
a = p1.y - p3.y;
|
|
@@ -52,9 +57,6 @@ export function checkLineIntersection(p1, p2, p3, p4, exact = true) {
|
|
|
52
57
|
y: p1.y + (a * (p2.y - p1.y))
|
|
53
58
|
}
|
|
54
59
|
|
|
55
|
-
// console.log('intersectionPoint', intersectionPoint, p1, p2);
|
|
56
|
-
|
|
57
|
-
|
|
58
60
|
|
|
59
61
|
let intersection = false;
|
|
60
62
|
// if line1 is a segment and line2 is infinite, they intersect if:
|
|
@@ -874,156 +876,8 @@ export function intersectLines(p1, p2, p3, p4) {
|
|
|
874
876
|
|
|
875
877
|
|
|
876
878
|
|
|
877
|
-
/**
|
|
878
|
-
* check polygon flatness helper
|
|
879
|
-
* basically a reduced shoelace algorithm
|
|
880
|
-
*/
|
|
881
|
-
export function commandIsFlat0(points, tolerance = 0.025) {
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
let xArr = points.map(pt => { return pt.x })
|
|
885
|
-
let yArr = points.map(pt => { return pt.y })
|
|
886
|
-
|
|
887
|
-
let xMin = Math.min(...xArr)
|
|
888
|
-
let xMax = Math.max(...xArr)
|
|
889
|
-
let yMin = Math.min(...yArr)
|
|
890
|
-
let yMax = Math.max(...yArr)
|
|
891
|
-
let w = xMax - xMin
|
|
892
|
-
let h = yMax - yMin
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
if (points.length < 3 || (w === 0 || h === 0)) {
|
|
896
|
-
return { area: 0, flat: true, thresh: 0.0001, ratio: 0 };
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
tolerance = 0.5;
|
|
900
|
-
let thresh = (w + h) * 0.5 * tolerance;
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
//let thresh = tolerance;
|
|
904
|
-
//console.log('w,h', w, h, thresh);
|
|
905
|
-
|
|
906
|
-
let area = 0;
|
|
907
|
-
for (let i = 0; i < points.length; i++) {
|
|
908
|
-
let addX = points[i].x;
|
|
909
|
-
let addY = points[i === points.length - 1 ? 0 : i + 1].y;
|
|
910
|
-
let subX = points[i === points.length - 1 ? 0 : i + 1].x;
|
|
911
|
-
let subY = points[i].y;
|
|
912
|
-
area += addX * addY * 0.5 - subX * subY * 0.5;
|
|
913
|
-
}
|
|
914
|
-
|
|
915
|
-
//console.log('flatArea', area, points);
|
|
916
|
-
area = +Math.abs(area).toFixed(9);
|
|
917
|
-
|
|
918
|
-
let ratio = area / thresh;
|
|
919
|
-
let isFlat = area === 0 ? true : (ratio < 0.15 ? true : false);
|
|
920
|
-
//isFlat= false
|
|
921
|
-
|
|
922
|
-
return { area: area, flat: isFlat, thresh: thresh, ratio: ratio };
|
|
923
|
-
}
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
export function commandIsFlat(points, tolerance = 0.025) {
|
|
927
|
-
|
|
928
|
-
let p0 = points[0];
|
|
929
|
-
let p = points[points.length - 1];
|
|
930
|
-
|
|
931
|
-
let xArr = points.map(pt => { return pt.x })
|
|
932
|
-
let yArr = points.map(pt => { return pt.y })
|
|
933
|
-
|
|
934
|
-
let xMin = Math.min(...xArr)
|
|
935
|
-
let xMax = Math.max(...xArr)
|
|
936
|
-
let yMin = Math.min(...yArr)
|
|
937
|
-
let yMax = Math.max(...yArr)
|
|
938
|
-
let w = xMax - xMin
|
|
939
|
-
let h = yMax - yMin
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
if (points.length < 3 || (w === 0 || h === 0)) {
|
|
943
|
-
return { area: 0, flat: true, thresh: 0.0001, ratio: 0 };
|
|
944
|
-
}
|
|
945
|
-
|
|
946
|
-
let squareDist = getSquareDistance(p0, p)
|
|
947
|
-
let squareDist1 = getSquareDistance(p0, points[0])
|
|
948
|
-
let squareDist2 = points.length > 3 ? getSquareDistance(p, points[1]) : squareDist1;
|
|
949
|
-
let squareDistAvg = (squareDist1 + squareDist2) / 2
|
|
950
|
-
|
|
951
|
-
tolerance = 0.5;
|
|
952
|
-
let thresh = (w + h) * 0.5 * tolerance;
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
//let thresh = tolerance;
|
|
956
|
-
//console.log('w,h', w, h, thresh);
|
|
957
|
-
|
|
958
|
-
let area = 0;
|
|
959
|
-
for (let i = 0, l = points.length; i < l; i++) {
|
|
960
|
-
let addX = points[i].x;
|
|
961
|
-
let addY = points[i === points.length - 1 ? 0 : i + 1].y;
|
|
962
|
-
let subX = points[i === points.length - 1 ? 0 : i + 1].x;
|
|
963
|
-
let subY = points[i].y;
|
|
964
|
-
area += addX * addY * 0.5 - subX * subY * 0.5;
|
|
965
|
-
}
|
|
966
|
-
|
|
967
|
-
//console.log('flatArea', area, points);
|
|
968
|
-
area = +Math.abs(area).toFixed(9);
|
|
969
|
-
|
|
970
|
-
let diff = Math.abs(area - squareDist);
|
|
971
|
-
let areaDiff = Math.abs(100 - (100 / area * (area + diff)))
|
|
972
|
-
let areaThresh = 1000
|
|
973
|
-
|
|
974
|
-
//let ratio = area / (squareDistAvg/areaThresh);
|
|
975
|
-
let ratio = area / (squareDistAvg);
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
//let isFlat = area === 0 ? true : (ratio < 0.15 ? true : false);
|
|
979
|
-
//let isFlat = area === 0 ? true : (area < squareDist/areaThresh ? true : false);
|
|
980
|
-
|
|
981
|
-
let isFlat = area === 0 ? true : area < squareDistAvg / areaThresh;
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
return { area: area, flat: isFlat, thresh: thresh, ratio: ratio, squareDist: squareDist, areaThresh: squareDist / areaThresh };
|
|
985
|
-
}
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
export function checkBezierFlatness(p0, cpts, p) {
|
|
989
|
-
|
|
990
|
-
let isFlat = false;
|
|
991
|
-
|
|
992
|
-
let isCubic = cpts.length===2;
|
|
993
|
-
|
|
994
|
-
let cp1 = cpts[0]
|
|
995
|
-
let cp2 = isCubic ? cpts[1] : cp1;
|
|
996
|
-
|
|
997
|
-
if(p0.x===cp1.x && p0.y===cp1.y && p.x===cp2.x && p.y===cp2.y) return true;
|
|
998
|
-
|
|
999
|
-
let dx1 = cp1.x - p0.x;
|
|
1000
|
-
let dy1 = cp1.y - p0.y;
|
|
1001
|
-
|
|
1002
|
-
let dx2 = p.x - cp2.x;
|
|
1003
|
-
let dy2 = p.y - cp2.y;
|
|
1004
879
|
|
|
1005
|
-
let cross1 = Math.abs(dx1 * dy2 - dy1 * dx2);
|
|
1006
880
|
|
|
1007
|
-
if(!cross1) return true
|
|
1008
|
-
|
|
1009
|
-
let dx0 = p.x - p0.x;
|
|
1010
|
-
let dy0 = p.y - p0.y;
|
|
1011
|
-
let cross0 = Math.abs(dx0 * dy1 - dy0 * dx1);
|
|
1012
|
-
|
|
1013
|
-
if(!cross0) return true
|
|
1014
|
-
|
|
1015
|
-
//let diff = Math.abs(cross0 - cross1)
|
|
1016
|
-
//let rat0 = 1/cross0 * diff;
|
|
1017
|
-
let rat = (cross0/cross1)
|
|
1018
|
-
|
|
1019
|
-
if (rat<1.1 ) {
|
|
1020
|
-
//console.log('cross', cross0, cross1, 'rat', rat, rat0, diff );
|
|
1021
|
-
isFlat = true;
|
|
1022
|
-
}
|
|
1023
|
-
|
|
1024
|
-
return isFlat;
|
|
1025
|
-
|
|
1026
|
-
}
|
|
1027
881
|
|
|
1028
882
|
/**
|
|
1029
883
|
* sloppy distance calculation
|
|
@@ -1041,7 +895,6 @@ export function getDistAv(pt1, pt2) {
|
|
|
1041
895
|
let diff = Math.abs(diffX + diffY) / 2;
|
|
1042
896
|
*/
|
|
1043
897
|
|
|
1044
|
-
|
|
1045
898
|
return diff;
|
|
1046
899
|
}
|
|
1047
900
|
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { getSquareDistance } from "./geometry";
|
|
2
|
+
import { getPolygonArea } from "./geometry_area";
|
|
3
|
+
|
|
4
|
+
export function commandIsFlat(points, tolerance = 0.025) {
|
|
5
|
+
|
|
6
|
+
let p0 = points[0];
|
|
7
|
+
let p = points[points.length - 1];
|
|
8
|
+
|
|
9
|
+
let xArr = points.map(pt => { return pt.x })
|
|
10
|
+
let yArr = points.map(pt => { return pt.y })
|
|
11
|
+
|
|
12
|
+
let xMin = Math.min(...xArr)
|
|
13
|
+
let xMax = Math.max(...xArr)
|
|
14
|
+
let yMin = Math.min(...yArr)
|
|
15
|
+
let yMax = Math.max(...yArr)
|
|
16
|
+
let w = xMax - xMin
|
|
17
|
+
let h = yMax - yMin
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
if (points.length < 3 || (w === 0 || h === 0)) {
|
|
21
|
+
return { area: 0, flat: true, thresh: 0.0001, ratio: 0 };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let squareDist = getSquareDistance(p0, p)
|
|
25
|
+
let squareDist1 = getSquareDistance(p0, points[0])
|
|
26
|
+
let squareDist2 = points.length > 3 ? getSquareDistance(p, points[1]) : squareDist1;
|
|
27
|
+
let squareDistAvg = (squareDist1 + squareDist2) / 2
|
|
28
|
+
|
|
29
|
+
tolerance = 0.5;
|
|
30
|
+
let thresh = (w + h) * 0.5 * tolerance;
|
|
31
|
+
|
|
32
|
+
//let thresh = tolerance;
|
|
33
|
+
let area = getPolygonArea(points, true)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
let diff = Math.abs(area - squareDist);
|
|
37
|
+
let areaDiff = Math.abs(100 - (100 / area * (area + diff)))
|
|
38
|
+
let areaThresh = 1000
|
|
39
|
+
|
|
40
|
+
//let ratio = area / (squareDistAvg/areaThresh);
|
|
41
|
+
let ratio = area / (squareDistAvg);
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
let isFlat = area === 0 ? true : area < squareDistAvg / areaThresh;
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
return { area: area, flat: isFlat, thresh: thresh, ratio: ratio, squareDist: squareDist, areaThresh: squareDist / areaThresh };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
export function checkBezierFlatness(p0, cpts, p) {
|
|
52
|
+
|
|
53
|
+
let isFlat = false;
|
|
54
|
+
|
|
55
|
+
let isCubic = cpts.length === 2;
|
|
56
|
+
|
|
57
|
+
let cp1 = cpts[0]
|
|
58
|
+
let cp2 = isCubic ? cpts[1] : cp1;
|
|
59
|
+
|
|
60
|
+
if (p0.x === cp1.x && p0.y === cp1.y && p.x === cp2.x && p.y === cp2.y) return true;
|
|
61
|
+
|
|
62
|
+
let dx1 = cp1.x - p0.x;
|
|
63
|
+
let dy1 = cp1.y - p0.y;
|
|
64
|
+
|
|
65
|
+
let dx2 = p.x - cp2.x;
|
|
66
|
+
let dy2 = p.y - cp2.y;
|
|
67
|
+
|
|
68
|
+
let cross1 = Math.abs(dx1 * dy2 - dy1 * dx2);
|
|
69
|
+
|
|
70
|
+
if (!cross1) return true
|
|
71
|
+
|
|
72
|
+
let dx0 = p.x - p0.x;
|
|
73
|
+
let dy0 = p.y - p0.y;
|
|
74
|
+
let cross0 = Math.abs(dx0 * dy1 - dy0 * dx1);
|
|
75
|
+
|
|
76
|
+
if (!cross0) return true
|
|
77
|
+
|
|
78
|
+
let area = getPolygonArea([p0,...cpts, p], true)
|
|
79
|
+
let dist1 = getSquareDistance(p0, p)
|
|
80
|
+
let thresh = dist1/200;
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
// if(area<thresh) return true;
|
|
84
|
+
isFlat = area<thresh;
|
|
85
|
+
//console.log('area', area, thresh, isFlat);
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
/*
|
|
89
|
+
//let diff = Math.abs(cross0 - cross1)
|
|
90
|
+
//let rat0 = 1/cross0 * diff;
|
|
91
|
+
let rat = (cross0 / cross1)
|
|
92
|
+
|
|
93
|
+
if (rat < 1.1) {
|
|
94
|
+
console.log('cross', cross0, cross1, 'rat', rat );
|
|
95
|
+
isFlat = true;
|
|
96
|
+
}
|
|
97
|
+
*/
|
|
98
|
+
|
|
99
|
+
return isFlat;
|
|
100
|
+
|
|
101
|
+
}
|