svg-path-simplify 0.2.7 → 0.3.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.
- package/README.md +52 -5
- package/dist/svg-path-simplify.esm.js +2787 -2767
- package/dist/svg-path-simplify.esm.min.js +5 -7
- package/dist/svg-path-simplify.js +2787 -2767
- package/dist/svg-path-simplify.min.js +5 -7
- package/dist/svg-path-simplify.pathdata.esm.js +5123 -0
- package/dist/svg-path-simplify.pathdata.esm.min.js +9 -0
- package/dist/svg-path-simplify.worker.js +1 -36
- package/index.html +209 -158
- package/package.json +1 -1
- package/src/detect_input.js +30 -3
- package/src/index-pathdata.js +6 -0
- package/src/pathData_simplify_cubic_extrapolate.js +3 -2
- package/src/pathSimplify-main.js +131 -66
- package/src/pathSimplify-only-pathdata.js +274 -0
- package/src/poly-fit-curve-schneider.js +266 -175
- package/src/simplify_poly_RDP.js +101 -1
- package/src/simplify_poly_radial_distance.js +85 -2
- package/src/svgii/geometry.js +1 -0
- package/src/svgii/pathData_fromPoly.js +22 -7
- package/src/svgii/pathData_toPolygon.js +122 -230
- package/src/svgii/poly_analyze.js +114 -435
- package/src/svgii/poly_analyze_get_chunks.js +67 -0
- package/src/svgii/poly_normalize.js +51 -0
- package/src/svgii/poly_to_pathdata.js +51 -24
- package/src/svgii/rounding.js +36 -0
- package/src/svgii/svg_cleanup.js +10 -0
- package/dist/svg-path-simplify.min.js.gz +0 -0
package/src/simplify_poly_RDP.js
CHANGED
|
@@ -3,7 +3,105 @@ import { getPolyBBox } from "./svgii/geometry_bbox";
|
|
|
3
3
|
import { renderPoint } from "./svgii/visualize";
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
export function
|
|
6
|
+
export function simplifyPolyRDP(pts, {quality = 0.9, width = 0, height = 0}={}) {
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* switch between absolute or
|
|
10
|
+
* quality based relative thresholds
|
|
11
|
+
*/
|
|
12
|
+
let isAbsolute = false;
|
|
13
|
+
|
|
14
|
+
if (typeof quality === 'string') {
|
|
15
|
+
isAbsolute = true;
|
|
16
|
+
quality = parseFloat(quality);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (pts.length < 4 || (!isAbsolute && quality) >= 1) return pts;
|
|
20
|
+
|
|
21
|
+
// convert quality to squaredistance tolerance
|
|
22
|
+
let tolerance = quality;
|
|
23
|
+
//console.log('simplifyRDP', tolerance);
|
|
24
|
+
|
|
25
|
+
if (!isAbsolute) {
|
|
26
|
+
|
|
27
|
+
tolerance = 1 - quality;
|
|
28
|
+
|
|
29
|
+
// adjust for higher qualities
|
|
30
|
+
if (quality > 0.5) tolerance /= 2;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* approximate dimensions
|
|
34
|
+
* adjust tolerance for
|
|
35
|
+
* very small polygons e.g geodata
|
|
36
|
+
*/
|
|
37
|
+
if (!width && !height) {
|
|
38
|
+
let polyS = reducePoints(pts, 12);
|
|
39
|
+
({ width, height } = getPolyBBox(polyS));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// average side lengths
|
|
43
|
+
let dimAvg = (width + height) / 2;
|
|
44
|
+
let scale = dimAvg / 100;
|
|
45
|
+
tolerance = (tolerance * (scale)) ** 2
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
// Square distance from point to segment
|
|
50
|
+
const segmentSquareDistance = (p, p1, p2) => {
|
|
51
|
+
let x = p1.x, y = p1.y;
|
|
52
|
+
let dx = p2.x - x, dy = p2.y - y;
|
|
53
|
+
|
|
54
|
+
if (dx !== 0 || dy !== 0) {
|
|
55
|
+
let t = ((p.x - x) * dx + (p.y - y) * dy) / (dx * dx + dy * dy);
|
|
56
|
+
if (t > 1) {
|
|
57
|
+
x = p2.x;
|
|
58
|
+
y = p2.y;
|
|
59
|
+
} else if (t > 0) {
|
|
60
|
+
x += dx * t;
|
|
61
|
+
y += dy * t;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return (p.x - x) ** 2 + (p.y - y) ** 2;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
// start collecting ptsSmp polyline
|
|
70
|
+
let ptsSmp = [pts[0]];
|
|
71
|
+
|
|
72
|
+
// create processing stack
|
|
73
|
+
let stack = [];
|
|
74
|
+
stack.push([0, pts.length - 1]);
|
|
75
|
+
|
|
76
|
+
while (stack.length > 0) {
|
|
77
|
+
let [first, last] = stack.pop();
|
|
78
|
+
let maxDist = tolerance;
|
|
79
|
+
let index = -1;
|
|
80
|
+
|
|
81
|
+
// Find point with maximum distance
|
|
82
|
+
for (let i = first + 1; i < last; i++) {
|
|
83
|
+
let currentDist = segmentSquareDistance(pts[i], pts[first], pts[last]);
|
|
84
|
+
if (currentDist > maxDist) {
|
|
85
|
+
index = i;
|
|
86
|
+
maxDist = currentDist;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// If max distance > tolerance, split and process
|
|
91
|
+
if (maxDist > tolerance) {
|
|
92
|
+
stack.push([index, last]);
|
|
93
|
+
stack.push([first, index]);
|
|
94
|
+
} else {
|
|
95
|
+
ptsSmp.push(pts[last]);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return ptsSmp;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
export function simplifyPolyRDP__(pts, {
|
|
7
105
|
quality = 0.9,
|
|
8
106
|
width = 0,
|
|
9
107
|
height = 0,
|
|
@@ -28,6 +126,8 @@ export function simplifyRDP(pts, {
|
|
|
28
126
|
quality = parseFloat(quality);
|
|
29
127
|
}
|
|
30
128
|
|
|
129
|
+
if(absolute && quality===0) return pts;
|
|
130
|
+
|
|
31
131
|
if (pts.length < 4 || (!absolute && quality) >= 1) return pts;
|
|
32
132
|
|
|
33
133
|
// convert quality to squaredistance or manhattan tolerance
|
|
@@ -8,7 +8,87 @@ import { getDistManhattan, getSquareDistance, reducePoints } from "./svgii/geome
|
|
|
8
8
|
import { getPolyBBox } from "./svgii/geometry_bbox";
|
|
9
9
|
import { renderPoint } from "./svgii/visualize";
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* radialDistance simplification
|
|
15
|
+
* sloppy but fast
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
export function simplifyPolyRD(pts, {quality = 0.9, width = 0, height = 0}={}) {
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* switch between absolute or
|
|
23
|
+
* quality based relative thresholds
|
|
24
|
+
*/
|
|
25
|
+
let isAbsolute = false;
|
|
26
|
+
|
|
27
|
+
if (typeof quality === 'string') {
|
|
28
|
+
let value = parseFloat(quality);
|
|
29
|
+
isAbsolute = true;
|
|
30
|
+
quality = value;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// nothing to do - exit
|
|
34
|
+
if (pts.length < 4 || (!isAbsolute && quality) >= 1) return pts;
|
|
35
|
+
|
|
36
|
+
let p0 = pts[0];
|
|
37
|
+
let pt;
|
|
38
|
+
let ptsSmp = [p0];
|
|
39
|
+
|
|
40
|
+
// convert quality to squaredistance tolerance
|
|
41
|
+
let tolerance = quality;
|
|
42
|
+
|
|
43
|
+
if (!isAbsolute) {
|
|
44
|
+
|
|
45
|
+
// quality to tolerance
|
|
46
|
+
tolerance = 1 - quality;
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* approximate dimensions
|
|
51
|
+
* adjust tolerance for
|
|
52
|
+
* very small polygons e.g geodata
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
if (!width && !height) {
|
|
56
|
+
let polyS = reducePoints(pts, 12);
|
|
57
|
+
({ width, height } = getPolyBBox(polyS));
|
|
58
|
+
}
|
|
59
|
+
// average side lengths
|
|
60
|
+
let dimAvg = (width + height) / 2;
|
|
61
|
+
let scale = dimAvg / 25;
|
|
62
|
+
tolerance = (tolerance * (scale)) ** 2
|
|
63
|
+
|
|
64
|
+
if (quality > 0.5) tolerance /= 10
|
|
65
|
+
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
//console.log('simplifyRD', tolerance);
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
for (let i = 1, l = pts.length; i < l; i++) {
|
|
72
|
+
pt = pts[i];
|
|
73
|
+
let dist = getSquareDistance(p0, pt)
|
|
74
|
+
|
|
75
|
+
if (dist > tolerance) {
|
|
76
|
+
ptsSmp.push(pt);
|
|
77
|
+
p0 = pt;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// add last point - if not coinciding with first point
|
|
82
|
+
if (p0.x !== pt.x && p0.y !== pt.y) {
|
|
83
|
+
ptsSmp.push(pt);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return ptsSmp;
|
|
87
|
+
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
export function simplifyPolyRD__(pts, {
|
|
12
92
|
quality = 0.9,
|
|
13
93
|
width = 0,
|
|
14
94
|
height = 0,
|
|
@@ -24,11 +104,14 @@ export function simplifyRD(pts, {
|
|
|
24
104
|
*/
|
|
25
105
|
|
|
26
106
|
if (typeof quality === 'string') {
|
|
27
|
-
let value = parseFloat(quality);
|
|
107
|
+
let value = parseFloat(quality)**2;
|
|
28
108
|
absolute = true;
|
|
29
109
|
quality = value;
|
|
110
|
+
console.log(quality);
|
|
30
111
|
}
|
|
31
112
|
|
|
113
|
+
if(absolute && quality===0) return pts;
|
|
114
|
+
|
|
32
115
|
// nothing to do - exit
|
|
33
116
|
if (pts.length < 4 || (!absolute && quality) >= 1) return pts;
|
|
34
117
|
|
package/src/svgii/geometry.js
CHANGED
|
@@ -1273,6 +1273,7 @@ export function intersectLines(p1, p2, p3, p4) {
|
|
|
1273
1273
|
*/
|
|
1274
1274
|
export function getDistance(p1, p2, isArray = false) {
|
|
1275
1275
|
//if(Array.isArray(p1)) isArray = true;
|
|
1276
|
+
|
|
1276
1277
|
//console.log(p1, p2);
|
|
1277
1278
|
let dx = isArray ? p2[0] - p1[0] : (p2.x - p1.x);
|
|
1278
1279
|
let dy = isArray ? p2[1] - p1[1] : (p2.y - p1.y);
|
|
@@ -1,12 +1,27 @@
|
|
|
1
|
-
export function pathDataFromPoly(pts, closed=true){
|
|
1
|
+
export function pathDataFromPoly(pts, closed = true) {
|
|
2
2
|
|
|
3
|
-
let pathData = [
|
|
4
|
-
|
|
5
|
-
...pts.slice(1).map(pt => { return { type: 'L', values: [pt.x, pt.y] } })
|
|
6
|
-
];
|
|
3
|
+
let pathData = []
|
|
4
|
+
let subPath = []
|
|
7
5
|
|
|
8
|
-
if(closed) pathData.push({type:'Z', values:[]})
|
|
9
6
|
|
|
7
|
+
// complex polygon
|
|
8
|
+
if (Array.isArray(pts[0])) {
|
|
9
|
+
pts.forEach(sub => {
|
|
10
|
+
subPath = [
|
|
11
|
+
{ type: 'M', values: [sub[0].x, sub[0].y] },
|
|
12
|
+
...sub.slice(1).map(pt => { return { type: 'L', values: [pt.x, pt.y] } })
|
|
13
|
+
];
|
|
14
|
+
pathData.push(...subPath)
|
|
15
|
+
})
|
|
16
|
+
}else{
|
|
17
|
+
pathData = [
|
|
18
|
+
{ type: 'M', values: [pts[0].x, pts[0].y] },
|
|
19
|
+
...pts.slice(1).map(pt => { return { type: 'L', values: [pt.x, pt.y] } })
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (closed) pathData.push({ type: 'Z', values: [] })
|
|
10
24
|
return pathData
|
|
11
25
|
|
|
12
|
-
}
|
|
26
|
+
}
|
|
27
|
+
|