svg-path-simplify 0.4.2 → 0.4.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/CHANGELOG.md +21 -0
- package/README.md +7 -4
- package/dist/svg-path-simplify.esm.js +3593 -1279
- package/dist/svg-path-simplify.esm.min.js +2 -2
- package/dist/svg-path-simplify.js +3594 -1278
- package/dist/svg-path-simplify.min.js +2 -2
- package/dist/svg-path-simplify.pathdata.esm.js +1017 -538
- package/dist/svg-path-simplify.pathdata.esm.min.js +2 -2
- package/dist/svg-path-simplify.poly.cjs +9 -8
- package/docs/privacy-webapp.md +24 -0
- package/index.html +331 -152
- package/package.json +1 -1
- package/src/constants.js +4 -0
- package/src/css_parse.js +317 -0
- package/src/detect_input.js +76 -28
- package/src/index.js +8 -0
- package/src/pathData_simplify_cubic.js +26 -16
- package/src/pathData_simplify_harmonize_cpts.js +77 -1
- package/src/pathData_simplify_revertToquadratics.js +0 -1
- package/src/pathSimplify-main.js +304 -276
- package/src/pathSimplify-only-pathdata.js +7 -2
- package/src/pathSimplify-presets.js +254 -0
- package/src/poly-fit-curve-schneider.js +14 -7
- package/src/simplify_poly_RC.js +102 -0
- package/src/simplify_poly_RDP.js +109 -1
- package/src/simplify_poly_radial_distance.js +3 -3
- package/src/string_helpers.js +130 -4
- package/src/svg-getAttributes.js +4 -2
- package/src/svgii/convert_units.js +1 -1
- package/src/svgii/geometry.js +322 -5
- package/src/svgii/geometry_bbox_element.js +1 -1
- package/src/svgii/geometry_deduceRadius.js +116 -27
- package/src/svgii/geometry_length.js +253 -0
- package/src/svgii/pathData_analyze.js +18 -0
- package/src/svgii/pathData_convert.js +193 -89
- package/src/svgii/pathData_fix_directions.js +12 -14
- package/src/svgii/pathData_fromPoly.js +3 -3
- package/src/svgii/pathData_getLength.js +86 -0
- package/src/svgii/pathData_parse.js +2 -0
- package/src/svgii/pathData_parse_els.js +66 -68
- package/src/svgii/pathData_reorder.js +122 -16
- package/src/svgii/pathData_simplify_refineCorners.js +130 -35
- package/src/svgii/pathData_simplify_refine_round.js +420 -0
- package/src/svgii/pathData_split_to_groups.js +168 -0
- package/src/svgii/pathData_stringify.js +26 -64
- package/src/svgii/pathData_toPolygon.js +3 -4
- package/src/svgii/poly_analyze.js +61 -0
- package/src/svgii/poly_normalize.js +11 -2
- package/src/svgii/poly_to_pathdata.js +85 -24
- package/src/svgii/rounding.js +80 -78
- package/src/svgii/svg_cleanup.js +421 -619
- package/src/svgii/svg_cleanup_convertPathLength.js +39 -0
- package/src/svgii/svg_cleanup_general_svg_atts.js +97 -0
- package/src/svgii/svg_cleanup_normalize_transforms.js +83 -0
- package/src/svgii/svg_cleanup_remove_els_and_atts.js +77 -0
- package/src/svgii/svg_cleanup_ungroup.js +36 -0
- package/src/svgii/svg_el_parse_style_props.js +72 -47
- package/src/svgii/svg_getElementLength.js +67 -0
- package/src/svgii/svg_validate.js +220 -0
- package/tests/testSVG.js +14 -1
- package/src/svgii/pathData_refine_round.js +0 -222
|
@@ -13,10 +13,11 @@ import { pathDataToD } from './svgii/pathData_stringify';
|
|
|
13
13
|
import { detectAccuracy } from './svgii/rounding';
|
|
14
14
|
import { refineAdjacentExtremes } from './svgii/pathData_simplify_refineExtremes';
|
|
15
15
|
import { refineRoundedCorners } from './svgii/pathData_simplify_refineCorners';
|
|
16
|
-
import { refineRoundSegments } from './svgii/pathData_refine_round';
|
|
16
|
+
//import { refineRoundSegments } from './svgii/pathData_refine_round';
|
|
17
17
|
import { refineClosingCommand } from './svgii/pathData_remove_short';
|
|
18
18
|
import { pathDataRevertCubicToQuadratic } from './pathData_simplify_revertToquadratics';
|
|
19
19
|
import { pathDataLineToCubic } from './svgii/pathData_line_to_cubic';
|
|
20
|
+
import { refineRoundSegments } from './svgii/pathData_simplify_refine_round';
|
|
20
21
|
|
|
21
22
|
//import { installDOMPolyfills } from './dom-polyfill';
|
|
22
23
|
|
|
@@ -97,7 +98,11 @@ export function simplifyPathData(input = '', {
|
|
|
97
98
|
let yArr = []
|
|
98
99
|
|
|
99
100
|
// mode:0 – single path
|
|
100
|
-
let inputType = detectInputType(input)
|
|
101
|
+
//let inputType = detectInputType(input)
|
|
102
|
+
let inputDetection = detectInputType(input);
|
|
103
|
+
let {inputType, log} = inputDetection
|
|
104
|
+
|
|
105
|
+
|
|
101
106
|
if (inputType === 'pathDataString') {
|
|
102
107
|
d = input
|
|
103
108
|
} else if (inputType === 'polyString') {
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
export let settingsDefaults = {
|
|
2
|
+
|
|
3
|
+
// SVG elements
|
|
4
|
+
removeComments: true,
|
|
5
|
+
removeOffCanvas: false,
|
|
6
|
+
|
|
7
|
+
// attributes
|
|
8
|
+
removeDimensions: false,
|
|
9
|
+
removeIds: false,
|
|
10
|
+
removeClassNames: false,
|
|
11
|
+
omitNamespace: false,
|
|
12
|
+
cleanUpStrokes: true,
|
|
13
|
+
addViewBox: true,
|
|
14
|
+
addDimensions: false,
|
|
15
|
+
removePrologue: true,
|
|
16
|
+
removeHidden: true,
|
|
17
|
+
removeUnused: true,
|
|
18
|
+
cleanupDefs: true,
|
|
19
|
+
cleanupClip: true,
|
|
20
|
+
cleanupSVGAtts: true,
|
|
21
|
+
removeNameSpaced: true,
|
|
22
|
+
removeNameSpacedAtts: true,
|
|
23
|
+
attributesToGroup: false,
|
|
24
|
+
minifyRgbColors: true,
|
|
25
|
+
stylesToAttributes: false,
|
|
26
|
+
fixHref: false,
|
|
27
|
+
legacyHref: false,
|
|
28
|
+
allowMeta: false,
|
|
29
|
+
allowDataAtts: true,
|
|
30
|
+
allowAriaAtts: true,
|
|
31
|
+
//pathlength conversion
|
|
32
|
+
convertPathLength: false,
|
|
33
|
+
toAbsoluteUnits: false,
|
|
34
|
+
|
|
35
|
+
// custom removal
|
|
36
|
+
removeElements: [],
|
|
37
|
+
removeSVGAttributes: [],
|
|
38
|
+
removeElAttributes: [],
|
|
39
|
+
|
|
40
|
+
// merging/splitting
|
|
41
|
+
unGroup: false,
|
|
42
|
+
mergePaths: false,
|
|
43
|
+
splitCompound: false,
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
// shape conversions
|
|
48
|
+
shapesToPaths: false,
|
|
49
|
+
shapeConvert: 0,
|
|
50
|
+
convertShapes: ['rect', 'ellipse', 'circle', 'line', 'polygon', 'polyline'],
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
// simplify
|
|
54
|
+
keepSmaller: true,
|
|
55
|
+
simplifyBezier: true,
|
|
56
|
+
optimizeOrder: true,
|
|
57
|
+
autoClose: false,
|
|
58
|
+
removeZeroLength: true,
|
|
59
|
+
refineClosing: true,
|
|
60
|
+
removeColinear: true,
|
|
61
|
+
flatBezierToLinetos: true,
|
|
62
|
+
revertToQuadratics: true,
|
|
63
|
+
refineExtremes: false,
|
|
64
|
+
simplifyCorners: false,
|
|
65
|
+
simplifyQuadraticCorners: false,
|
|
66
|
+
keepExtremes: true,
|
|
67
|
+
keepCorners: true,
|
|
68
|
+
keepInflections: false,
|
|
69
|
+
addExtremes: false,
|
|
70
|
+
|
|
71
|
+
// draw direction
|
|
72
|
+
fixDirections: false,
|
|
73
|
+
reversePath: false,
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
// pathdata
|
|
77
|
+
toAbsolute: false,
|
|
78
|
+
toRelative: true,
|
|
79
|
+
toMixed: false,
|
|
80
|
+
toShorthands: true,
|
|
81
|
+
toLonghands: false,
|
|
82
|
+
quadraticToCubic: true,
|
|
83
|
+
arcToCubic: false,
|
|
84
|
+
cubicToArc: false,
|
|
85
|
+
lineToCubic: false,
|
|
86
|
+
|
|
87
|
+
// minification
|
|
88
|
+
decimals: 3,
|
|
89
|
+
autoAccuracy: true,
|
|
90
|
+
minifyD: 0,
|
|
91
|
+
tolerance: 1,
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
// polygon
|
|
95
|
+
toPolygon: false,
|
|
96
|
+
smoothPoly: false,
|
|
97
|
+
polyFormat: 'object',
|
|
98
|
+
precisionPoly: 1,
|
|
99
|
+
simplifyRD: 0,
|
|
100
|
+
simplifyRDP: 0,
|
|
101
|
+
harmonizeCpts: false,
|
|
102
|
+
removeOrphanSubpaths: false,
|
|
103
|
+
simplifyRound: false,
|
|
104
|
+
|
|
105
|
+
//svg scaling
|
|
106
|
+
scale: 1,
|
|
107
|
+
scaleTo: 0,
|
|
108
|
+
crop: false,
|
|
109
|
+
alignToOrigin: false,
|
|
110
|
+
|
|
111
|
+
// flatten transforms
|
|
112
|
+
convertTransforms: false,
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const settingsNull = {}
|
|
118
|
+
|
|
119
|
+
for (let prop in settingsDefaults) {
|
|
120
|
+
let val = settingsDefaults[prop];
|
|
121
|
+
let isBoolean = val === false || val === true;
|
|
122
|
+
let isNum = !isNaN(val)
|
|
123
|
+
let isArray = Array.isArray(val)
|
|
124
|
+
|
|
125
|
+
if (isBoolean) val = false
|
|
126
|
+
else if (!isArray && isNum) val = val === 1 ? 1 : (prop === 'decimals' ? -1 : 0);
|
|
127
|
+
else if (isArray) val = []
|
|
128
|
+
settingsNull[prop] = val;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
export const presetSettings = {
|
|
133
|
+
default: settingsDefaults,
|
|
134
|
+
|
|
135
|
+
education: {
|
|
136
|
+
...settingsDefaults,
|
|
137
|
+
...{
|
|
138
|
+
keepSmaller: false,
|
|
139
|
+
toRelative: false,
|
|
140
|
+
toMixed: false,
|
|
141
|
+
toShorthands: false,
|
|
142
|
+
fixHref: true,
|
|
143
|
+
legacyHref: false,
|
|
144
|
+
addViewBox: true,
|
|
145
|
+
addDimensions: true,
|
|
146
|
+
removeComments: false,
|
|
147
|
+
decimals: 3,
|
|
148
|
+
minifyD: 2
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
null: settingsNull,
|
|
153
|
+
|
|
154
|
+
editor: {
|
|
155
|
+
...settingsDefaults,
|
|
156
|
+
...{
|
|
157
|
+
keepSmaller: false,
|
|
158
|
+
convertPathLength:true,
|
|
159
|
+
toRelative: true,
|
|
160
|
+
toMixed: true,
|
|
161
|
+
toShorthands: true,
|
|
162
|
+
//fixHref: true,
|
|
163
|
+
allowMeta:true,
|
|
164
|
+
allowDataAtts:true,
|
|
165
|
+
allowAriaAtts:true,
|
|
166
|
+
legacyHref: true,
|
|
167
|
+
addViewBox: true,
|
|
168
|
+
addDimensions: true,
|
|
169
|
+
removeComments: true,
|
|
170
|
+
autoAccuracy: true,
|
|
171
|
+
//decimals:5,
|
|
172
|
+
minifyD: 0.5
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
noSimplification: {
|
|
177
|
+
...settingsDefaults,
|
|
178
|
+
...{
|
|
179
|
+
simplifyBezier: false,
|
|
180
|
+
quadraticToCubic: false,
|
|
181
|
+
toRelative: true,
|
|
182
|
+
toShorthands: true,
|
|
183
|
+
fixHref: true,
|
|
184
|
+
optimizeOrder: false,
|
|
185
|
+
removeZeroLength: false,
|
|
186
|
+
refineExtremes: false,
|
|
187
|
+
refineClosing: false,
|
|
188
|
+
removeColinear: false,
|
|
189
|
+
flatBezierToLinetos: false,
|
|
190
|
+
//addViewBox: false,
|
|
191
|
+
addDimensions: false,
|
|
192
|
+
removeComments: true,
|
|
193
|
+
minifyD: 0
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
},
|
|
197
|
+
path: {
|
|
198
|
+
...settingsDefaults,
|
|
199
|
+
...{
|
|
200
|
+
shapeConvert: 'toPaths',
|
|
201
|
+
convertShapes: ['rect', 'ellipse', 'circle', 'line', 'polygon', 'polyline'],
|
|
202
|
+
addViewBox: true,
|
|
203
|
+
minifyD: 0.5
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
poly: {
|
|
208
|
+
...settingsDefaults,
|
|
209
|
+
...{
|
|
210
|
+
toPolygon: true,
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
|
|
214
|
+
curvefit: {
|
|
215
|
+
...settingsDefaults,
|
|
216
|
+
...{
|
|
217
|
+
smoothPoly: true,
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
|
|
221
|
+
detransform: {
|
|
222
|
+
...settingsDefaults,
|
|
223
|
+
...{
|
|
224
|
+
convertTransforms: true,
|
|
225
|
+
addViewBox: true,
|
|
226
|
+
minifyD: 0.5
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
|
|
230
|
+
high: {
|
|
231
|
+
...settingsDefaults,
|
|
232
|
+
...{
|
|
233
|
+
tolerance: 1.1,
|
|
234
|
+
toMixed: true,
|
|
235
|
+
refineExtremes: true,
|
|
236
|
+
simplifyCorners: true,
|
|
237
|
+
simplifyQuadraticCorners: true,
|
|
238
|
+
removeOrphanSubpaths: true,
|
|
239
|
+
simplifyRound: true,
|
|
240
|
+
removeClassNames: true,
|
|
241
|
+
cubicToArc: true,
|
|
242
|
+
minifyD: 0,
|
|
243
|
+
removeComments: true,
|
|
244
|
+
removeHidden: true,
|
|
245
|
+
addViewBox: true,
|
|
246
|
+
removeDimensions: true,
|
|
247
|
+
removeOffCanvas: true,
|
|
248
|
+
|
|
249
|
+
/*
|
|
250
|
+
*/
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
}
|
|
@@ -9,13 +9,16 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { harmonizeCubicCpts, harmonizeCubicCptsThird } from "./pathData_simplify_harmonize_cpts";
|
|
12
|
-
import { getAngle, getDistance, getSquareDistance, pointAtT, rotatePoint } from "./svgii/geometry";
|
|
12
|
+
import { checkLineIntersection, getAngle, getDistance, getSquareDistance, pointAtT, reducePoints, rotatePoint } from "./svgii/geometry";
|
|
13
13
|
import { getPolygonArea } from "./svgii/geometry_area";
|
|
14
|
+
import { detectRegularPolygon, getPolyCentroid } from "./svgii/poly_analyze";
|
|
14
15
|
import { renderPath, renderPoint } from "./svgii/visualize";
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
|
|
20
|
+
|
|
21
|
+
|
|
19
22
|
/**
|
|
20
23
|
* Fit one or more Bezier curves to a set of pts.
|
|
21
24
|
*
|
|
@@ -50,17 +53,18 @@ export function fitCurveSchneider(pts, {
|
|
|
50
53
|
|
|
51
54
|
// create pathdata
|
|
52
55
|
let pathData = bezierPtsToPathData(beziers)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
56
|
let cp1, cp2;
|
|
57
57
|
|
|
58
58
|
adjustCpts = false
|
|
59
|
-
harmonize = false;
|
|
59
|
+
//harmonize = false;
|
|
60
|
+
|
|
61
|
+
adjustCpts = true;
|
|
62
|
+
//harmonize = true;
|
|
63
|
+
|
|
60
64
|
|
|
61
65
|
if (adjustCpts) {
|
|
62
66
|
|
|
63
|
-
console.log('refine cpts');
|
|
67
|
+
//console.log('refine cpts');
|
|
64
68
|
|
|
65
69
|
let len2 = pathData.length;
|
|
66
70
|
let com1 = pathData[0]
|
|
@@ -91,13 +95,16 @@ export function fitCurveSchneider(pts, {
|
|
|
91
95
|
com2.values[3] = cp2.y
|
|
92
96
|
}
|
|
93
97
|
|
|
98
|
+
/*
|
|
94
99
|
// harmonize too tight tangents
|
|
95
|
-
|
|
100
|
+
let harmonize = true;
|
|
101
|
+
harmonize = false;
|
|
96
102
|
if (harmonize) {
|
|
97
103
|
pathData = harmonizeCubicCptsThird([{ type: 'M', values: [pts[0].x, pts[0].y] },
|
|
98
104
|
...pathData])
|
|
99
105
|
pathData.shift()
|
|
100
106
|
}
|
|
107
|
+
*/
|
|
101
108
|
|
|
102
109
|
}
|
|
103
110
|
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { getSquareDistance, reducePoints } from "./svgii/geometry";
|
|
2
|
+
import { getPolygonArea } from "./svgii/geometry_area";
|
|
3
|
+
import { getPolyBBox } from "./svgii/geometry_bbox";
|
|
4
|
+
|
|
5
|
+
export function simplifyRC(pts, quality = 1, shiftStart = true) {
|
|
6
|
+
|
|
7
|
+
if (pts.length < 4) return pts;
|
|
8
|
+
|
|
9
|
+
let l = pts.length;
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
// starting point
|
|
13
|
+
let M = pts[0];
|
|
14
|
+
|
|
15
|
+
// last point
|
|
16
|
+
let Z = pts[l - 1];
|
|
17
|
+
|
|
18
|
+
// remove unnecessary closing point
|
|
19
|
+
if (M.x === Z.x && M.y === Z.y) {
|
|
20
|
+
pts.pop();
|
|
21
|
+
l--;
|
|
22
|
+
Z = pts[l - 1];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// init new point array
|
|
26
|
+
let ptsSmp = [M];
|
|
27
|
+
let pt0 = M;
|
|
28
|
+
let pt1, pt2;
|
|
29
|
+
|
|
30
|
+
// loop through vertices by triangles
|
|
31
|
+
for (let i = 2; i < l; i++) {
|
|
32
|
+
pt1 = pts[i - 1];
|
|
33
|
+
pt2 = pts[i];
|
|
34
|
+
let isLast = i === l - 1;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* 1. Skip zero-length segments
|
|
38
|
+
*/
|
|
39
|
+
if ((pt1.x === pt0.x && pt1.y === pt0.y) || (pt1.x === pt2.x && pt1.y === pt2.y)) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 2. Check for perfectly flat
|
|
45
|
+
* vertical/horizontal segments
|
|
46
|
+
*/
|
|
47
|
+
let isVertical = (pt0.x === pt1.x);
|
|
48
|
+
let isHorizontal = (pt0.y === pt1.y);
|
|
49
|
+
|
|
50
|
+
if (isVertical || isHorizontal) {
|
|
51
|
+
|
|
52
|
+
let isVertical2 = (pt1.x === pt2.x);
|
|
53
|
+
let isHorizontal2 = (pt1.y === pt2.y);
|
|
54
|
+
|
|
55
|
+
if (((isVertical && isVertical2) || (isHorizontal && isHorizontal2))) {
|
|
56
|
+
|
|
57
|
+
// perfectly flat segment - skip
|
|
58
|
+
if (!isLast) continue;
|
|
59
|
+
|
|
60
|
+
// flat but last – add last and skip colinearity check
|
|
61
|
+
if (isLast && M.x !== pt2.x && M.y !== pt2.y) {
|
|
62
|
+
|
|
63
|
+
ptsSmp.push(pt2);
|
|
64
|
+
continue
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// check area
|
|
71
|
+
let area = getPolygonArea([pt0, pt1, pt2], true)
|
|
72
|
+
let thresh = getSquareDistance(pt0, pt2) * 0.005;
|
|
73
|
+
|
|
74
|
+
// flat
|
|
75
|
+
if ( area <= thresh && i<l-1) {
|
|
76
|
+
//console.log(area, thresh, pt0, pt1, pt2, i);
|
|
77
|
+
pt0 = pt1;
|
|
78
|
+
continue
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// no simplification - add mid pt
|
|
82
|
+
ptsSmp.push(pt1);
|
|
83
|
+
|
|
84
|
+
// add last point if not first
|
|
85
|
+
if (isLast && M.x !== pt2.x && M.y !== pt2.y) {
|
|
86
|
+
// console.log('add last', M, pt2);
|
|
87
|
+
ptsSmp.push(pt2);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// update previous point
|
|
91
|
+
pt0 = pt1;
|
|
92
|
+
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// 1st and last are colinear
|
|
96
|
+
let area0 = getPolygonArea([ptsSmp[1], M, ptsSmp[ptsSmp.length-1]], true)
|
|
97
|
+
let thresh0 = getSquareDistance (ptsSmp[1], ptsSmp[ptsSmp.length-1]) * 0.005
|
|
98
|
+
// remove first point
|
|
99
|
+
if(area0 < thresh0) ptsSmp.shift()
|
|
100
|
+
|
|
101
|
+
return ptsSmp;
|
|
102
|
+
}
|
package/src/simplify_poly_RDP.js
CHANGED
|
@@ -3,6 +3,113 @@ import { getPolyBBox } from "./svgii/geometry_bbox";
|
|
|
3
3
|
import { renderPoint } from "./svgii/visualize";
|
|
4
4
|
|
|
5
5
|
|
|
6
|
+
|
|
7
|
+
export function simplifyRDP_rel(pts, quality = 0.9, width = 0, height = 0) {
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* switch between absolute or
|
|
11
|
+
* quality based relative thresholds
|
|
12
|
+
*/
|
|
13
|
+
let isAbsolute = false;
|
|
14
|
+
|
|
15
|
+
if (typeof quality === 'string') {
|
|
16
|
+
isAbsolute = true;
|
|
17
|
+
quality = parseFloat(quality);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (pts.length < 4 ) return pts;
|
|
21
|
+
|
|
22
|
+
// convert quality to squaredistance tolerance
|
|
23
|
+
let tolerance = quality;
|
|
24
|
+
//console.log('simplifyRDP', tolerance);
|
|
25
|
+
|
|
26
|
+
if (!isAbsolute) {
|
|
27
|
+
|
|
28
|
+
//tolerance = 1 - quality;
|
|
29
|
+
tolerance = quality;
|
|
30
|
+
|
|
31
|
+
// adjust for higher qualities
|
|
32
|
+
if (quality > 0.5) tolerance /= 2;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* approximate dimensions
|
|
36
|
+
* adjust tolerance for
|
|
37
|
+
* very small polygons e.g geodata
|
|
38
|
+
*/
|
|
39
|
+
if (!width && !height) {
|
|
40
|
+
let polyS = reducePoints(pts, 12);
|
|
41
|
+
({ width, height } = getPolyBBox(polyS));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// average side lengths
|
|
45
|
+
let dimAvg = (width + height) / 2;
|
|
46
|
+
let scale = dimAvg / 100;
|
|
47
|
+
tolerance = (tolerance * (scale)) ** 2
|
|
48
|
+
|
|
49
|
+
console.log('!!!tolerance', tolerance);
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
// Square distance from point to segment
|
|
56
|
+
const segmentSquareDistance = (p, p1, p2) => {
|
|
57
|
+
let x = p1.x, y = p1.y;
|
|
58
|
+
let dx = p2.x - x, dy = p2.y - y;
|
|
59
|
+
|
|
60
|
+
if (dx !== 0 || dy !== 0) {
|
|
61
|
+
let t = ((p.x - x) * dx + (p.y - y) * dy) / (dx * dx + dy * dy);
|
|
62
|
+
if (t > 1) {
|
|
63
|
+
x = p2.x;
|
|
64
|
+
y = p2.y;
|
|
65
|
+
} else if (t > 0) {
|
|
66
|
+
x += dx * t;
|
|
67
|
+
y += dy * t;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return (p.x - x) ** 2 + (p.y - y) ** 2;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
// start collecting ptsSmp polyline
|
|
76
|
+
let ptsSmp = [pts[0]];
|
|
77
|
+
|
|
78
|
+
// create processing stack
|
|
79
|
+
let stack = [];
|
|
80
|
+
stack.push([0, pts.length - 1]);
|
|
81
|
+
|
|
82
|
+
while (stack.length > 0) {
|
|
83
|
+
let [first, last] = stack.pop();
|
|
84
|
+
let maxDist = tolerance;
|
|
85
|
+
let index = -1;
|
|
86
|
+
|
|
87
|
+
// Find point with maximum distance
|
|
88
|
+
for (let i = first + 1; i < last; i++) {
|
|
89
|
+
let currentDist = segmentSquareDistance(pts[i], pts[first], pts[last]);
|
|
90
|
+
if (currentDist > maxDist) {
|
|
91
|
+
index = i;
|
|
92
|
+
maxDist = currentDist;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// If max distance > tolerance, split and process
|
|
97
|
+
if (maxDist > tolerance) {
|
|
98
|
+
stack.push([index, last]);
|
|
99
|
+
stack.push([first, index]);
|
|
100
|
+
} else {
|
|
101
|
+
ptsSmp.push(pts[last]);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return ptsSmp;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
|
|
6
113
|
export function simplifyPolyRDP(pts, {quality = 0.9, width = 0, height = 0}={}) {
|
|
7
114
|
|
|
8
115
|
/**
|
|
@@ -16,7 +123,8 @@ export function simplifyPolyRDP(pts, {quality = 0.9, width = 0, height = 0}={})
|
|
|
16
123
|
quality = parseFloat(quality);
|
|
17
124
|
}
|
|
18
125
|
|
|
19
|
-
|
|
126
|
+
//|| (!isAbsolute && quality) >= 1
|
|
127
|
+
if (pts.length < 4 ) return pts;
|
|
20
128
|
|
|
21
129
|
// convert quality to squaredistance tolerance
|
|
22
130
|
let tolerance = quality;
|
|
@@ -31,7 +31,8 @@ export function simplifyPolyRD(pts, {quality = 0.9, width = 0, height = 0}={}) {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
// nothing to do - exit
|
|
34
|
-
|
|
34
|
+
//|| (!isAbsolute && quality) >= 1
|
|
35
|
+
if (pts.length < 4 ) return pts;
|
|
35
36
|
|
|
36
37
|
let p0 = pts[0];
|
|
37
38
|
let pt;
|
|
@@ -43,8 +44,7 @@ export function simplifyPolyRD(pts, {quality = 0.9, width = 0, height = 0}={}) {
|
|
|
43
44
|
if (!isAbsolute) {
|
|
44
45
|
|
|
45
46
|
// quality to tolerance
|
|
46
|
-
tolerance =
|
|
47
|
-
|
|
47
|
+
tolerance = quality;
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
50
|
* approximate dimensions
|