svg-path-simplify 0.4.3 → 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 +11 -0
- package/README.md +1 -0
- package/dist/svg-path-simplify.esm.js +1610 -495
- package/dist/svg-path-simplify.esm.min.js +2 -2
- package/dist/svg-path-simplify.js +1611 -494
- package/dist/svg-path-simplify.min.js +2 -2
- package/dist/svg-path-simplify.pathdata.esm.js +893 -456
- package/dist/svg-path-simplify.pathdata.esm.min.js +2 -2
- package/dist/svg-path-simplify.poly.cjs +9 -8
- package/index.html +58 -17
- package/package.json +1 -1
- package/src/constants.js +4 -0
- package/src/detect_input.js +47 -29
- package/src/index.js +8 -0
- package/src/pathData_simplify_cubic.js +26 -16
- package/src/pathData_simplify_revertToquadratics.js +0 -1
- package/src/pathSimplify-main.js +75 -20
- package/src/pathSimplify-only-pathdata.js +7 -2
- package/src/pathSimplify-presets.js +15 -4
- package/src/svg-getAttributes.js +4 -2
- package/src/svgii/convert_units.js +1 -1
- package/src/svgii/geometry.js +140 -2
- package/src/svgii/geometry_bbox_element.js +1 -1
- package/src/svgii/geometry_deduceRadius.js +116 -27
- package/src/svgii/geometry_length.js +17 -1
- package/src/svgii/pathData_analyze.js +18 -0
- package/src/svgii/pathData_convert.js +188 -88
- package/src/svgii/pathData_fix_directions.js +10 -18
- 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/rounding.js +79 -78
- package/src/svgii/svg_cleanup.js +68 -20
- package/src/svgii/svg_cleanup_convertPathLength.js +22 -15
- package/src/svgii/svg_cleanup_remove_els_and_atts.js +6 -1
- package/src/svgii/svg_el_parse_style_props.js +13 -10
- package/src/svgii/svg_validate.js +220 -0
- package/tests/testSVG.js +14 -1
- package/src/svgii/pathData_refine_round.js +0 -222
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
import { checkLineIntersection, getAngle, getDistAv, getDistManhattan, getDistance, getPointOnEllipse, getSquareDistance, pointAtT, rotatePoint } from "./geometry";
|
|
2
|
+
import { getPolygonArea } from "./geometry_area";
|
|
3
|
+
import { getArcFromPoly } from "./geometry_deduceRadius";
|
|
4
|
+
import { arcToBezierResolved, convertSmallArcsToLinetos, revertCubicQuadratic } from "./pathData_convert";
|
|
5
|
+
import { pathDataToD } from "./pathData_stringify";
|
|
6
|
+
import { renderPath, renderPoint, renderPoly } from "./visualize";
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
export function simplifyAdjacentRound(pathData, {
|
|
10
|
+
threshold = 0,
|
|
11
|
+
tolerance = 1,
|
|
12
|
+
// take arcs or cubic beziers
|
|
13
|
+
toCubic = false,
|
|
14
|
+
debug = false
|
|
15
|
+
} = {}) {
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
// fix small Arcs
|
|
19
|
+
pathData = convertSmallArcsToLinetos(pathData);
|
|
20
|
+
//return pathData
|
|
21
|
+
|
|
22
|
+
// min size threshold for corners
|
|
23
|
+
threshold *= tolerance;
|
|
24
|
+
|
|
25
|
+
let l = pathData.length;
|
|
26
|
+
|
|
27
|
+
// add fist command
|
|
28
|
+
let pathDataN = [pathData[0]]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
// find adjacent cubics between extremes
|
|
32
|
+
//console.log(pathData);
|
|
33
|
+
|
|
34
|
+
for (let i = 1; i < l; i++) {
|
|
35
|
+
let comPrev = pathData[i - 1];
|
|
36
|
+
let com = pathData[i];
|
|
37
|
+
let comN = pathData[i + 1] || null;
|
|
38
|
+
|
|
39
|
+
if (!comN) {
|
|
40
|
+
pathDataN.push(com);
|
|
41
|
+
break
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let { type, extreme = false, p0, p, dimA = 0 } = com;
|
|
45
|
+
// for short segment detection
|
|
46
|
+
let dimAN = comN.dimA;
|
|
47
|
+
let dimA0 = dimA + dimAN;
|
|
48
|
+
let thresh = 0.1
|
|
49
|
+
let extreme0 = extreme
|
|
50
|
+
|
|
51
|
+
// ignore short linetos
|
|
52
|
+
let isShortN = dimAN < dimA0 * thresh;
|
|
53
|
+
//let isFlat =
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
// adjacent cubic commands - accept short in between linetos
|
|
57
|
+
if ((type === 'C') && (comN.type === 'C' || isShortN)) {
|
|
58
|
+
|
|
59
|
+
//console.log((comN.type !== 'C' && isShortN), comN);
|
|
60
|
+
let candidates = []
|
|
61
|
+
|
|
62
|
+
for (let j = i + 1; j < l; j++) {
|
|
63
|
+
let comN = pathData[j];
|
|
64
|
+
let { type, extreme = false, corner = false, dimA = 0 } = comN;
|
|
65
|
+
let isShort = dimA < dimA0 * thresh;
|
|
66
|
+
|
|
67
|
+
// skip for type change(unless very short), extremes or corners
|
|
68
|
+
/*
|
|
69
|
+
if ( (comN.extreme || comN.corner) ) {
|
|
70
|
+
if(!extreme && !corner) candidates.push(comN)
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
*/
|
|
74
|
+
|
|
75
|
+
//|| (type !== 'C' && !isShort && !corner && !extreme)
|
|
76
|
+
if (extreme || corner) {
|
|
77
|
+
|
|
78
|
+
/*
|
|
79
|
+
if (comN.extreme) {
|
|
80
|
+
renderPoint(markers, comN.p, 'cyan')
|
|
81
|
+
}
|
|
82
|
+
else if (comN.corner) {
|
|
83
|
+
renderPoint(markers, comN.p, 'magenta')
|
|
84
|
+
}
|
|
85
|
+
else if (type !== 'C') {
|
|
86
|
+
console.log(type);
|
|
87
|
+
renderPoint(markers, comN.p, 'orange')
|
|
88
|
+
}
|
|
89
|
+
*/
|
|
90
|
+
|
|
91
|
+
if ((extreme || corner) && type === 'C') {
|
|
92
|
+
//renderPoint(markers, com.p, 'purple')
|
|
93
|
+
//break
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
//&& comN.type !== 'C'
|
|
97
|
+
if (isShort && comN.type !== 'C') {
|
|
98
|
+
//renderPoint(markers, comN.p, 'purple')
|
|
99
|
+
//candidates.push(comN)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
if ((extreme && !corner)) {
|
|
104
|
+
//console.log(comN);
|
|
105
|
+
//if(extreme) renderPoint(markers, comN.p0, 'purple')
|
|
106
|
+
//candidates.push(comN)
|
|
107
|
+
candidates.push(comN)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
candidates.push(comN)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// try to create arc command
|
|
118
|
+
if (candidates.length > 1) {
|
|
119
|
+
|
|
120
|
+
let clen = candidates.length;
|
|
121
|
+
let pts = [com.p0, com.p,];
|
|
122
|
+
|
|
123
|
+
// add interpolated points to prevent wrong arc replacements
|
|
124
|
+
candidates.forEach(c => {
|
|
125
|
+
if (c.type === 'C') {
|
|
126
|
+
let pt = pointAtT([c.p0, c.cp1, c.cp2, c.p], 0.5)
|
|
127
|
+
pts.push(pt)
|
|
128
|
+
}
|
|
129
|
+
pts.push(c.p)
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
//let pts = [com.p0, com.p, ...candidates.map(com => com.p)];
|
|
133
|
+
//console.log('pts', pts);
|
|
134
|
+
|
|
135
|
+
let precise = true
|
|
136
|
+
let arcProps = getArcFromPoly(pts, precise)
|
|
137
|
+
|
|
138
|
+
// could be combined
|
|
139
|
+
if (arcProps) {
|
|
140
|
+
//console.log(arcProps, pts);
|
|
141
|
+
|
|
142
|
+
let { centroid, r, deltaAngle, startAngle, endAngle } = arcProps;
|
|
143
|
+
let sweep = deltaAngle > 0 ? 1 : 0;
|
|
144
|
+
//let area = getPolygonArea(pts)
|
|
145
|
+
//let sweep = area > 0 ? 1 : 0;
|
|
146
|
+
let largeArc = Math.abs(deltaAngle) > Math.PI ? 1 : 0;
|
|
147
|
+
largeArc = 0;
|
|
148
|
+
let comLast = candidates[clen - 1]
|
|
149
|
+
let p = comLast.p
|
|
150
|
+
|
|
151
|
+
let comArc = { type: 'A', values: [r, r, 0, largeArc, sweep, p.x, p.y] }
|
|
152
|
+
|
|
153
|
+
//console.log(comArc);
|
|
154
|
+
|
|
155
|
+
comArc.dimA = getDistManhattan(p0, p)
|
|
156
|
+
comArc.p0 = p0
|
|
157
|
+
comArc.p = p
|
|
158
|
+
comArc.error = 0
|
|
159
|
+
comArc.directionChange = comLast.directionChange
|
|
160
|
+
comArc.extreme = comLast.extreme
|
|
161
|
+
comArc.corner = comLast.corner
|
|
162
|
+
pathDataN.push(comArc)
|
|
163
|
+
|
|
164
|
+
i += candidates.length
|
|
165
|
+
continue
|
|
166
|
+
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// arc radius calculation failed - return original
|
|
170
|
+
else {
|
|
171
|
+
pathDataN.push(com)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// could not be simplified – return original command
|
|
176
|
+
else {
|
|
177
|
+
pathDataN.push(com)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
}
|
|
181
|
+
// all other commands
|
|
182
|
+
else {
|
|
183
|
+
pathDataN.push(com)
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
//console.log(pathDataN);
|
|
188
|
+
return pathDataN
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
export function refineRoundSegments(pathData, {
|
|
193
|
+
threshold = 0,
|
|
194
|
+
tolerance = 1,
|
|
195
|
+
// take arcs or cubic beziers
|
|
196
|
+
toCubic = false,
|
|
197
|
+
debug = false
|
|
198
|
+
} = {}) {
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
// min size threshold for corners
|
|
202
|
+
threshold *= tolerance;
|
|
203
|
+
|
|
204
|
+
let l = pathData.length;
|
|
205
|
+
|
|
206
|
+
// add fist command
|
|
207
|
+
let pathDataN = [pathData[0]]
|
|
208
|
+
|
|
209
|
+
// just for debugging
|
|
210
|
+
let pathDataTest = []
|
|
211
|
+
|
|
212
|
+
for (let i = 1; i < l; i++) {
|
|
213
|
+
let com = pathData[i];
|
|
214
|
+
let { type } = com;
|
|
215
|
+
let comP = pathData[i - 1];
|
|
216
|
+
let comN = pathData[i + 1] ? pathData[i + 1] : null;
|
|
217
|
+
let comN2 = pathData[i + 2] ? pathData[i + 2] : null;
|
|
218
|
+
let comN3 = pathData[i + 3] ? pathData[i + 3] : null;
|
|
219
|
+
let comBez = null;
|
|
220
|
+
|
|
221
|
+
if ((com.type === 'C' || com.type === 'Q')) comBez = com;
|
|
222
|
+
else if (comN && (comN.type === 'C' || comN.type === 'Q')) comBez = comN;
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
let cpts = comBez ? (comBez.type === 'C' ? [comBez.p0, comBez.cp1, comBez.cp2, comBez.p] : [comBez.p0, comBez.cp1, comBez.p]) : []
|
|
226
|
+
|
|
227
|
+
let areaBez = 0;
|
|
228
|
+
let areaLines = 0;
|
|
229
|
+
let signChange = false;
|
|
230
|
+
let L1, L2;
|
|
231
|
+
let combine = false
|
|
232
|
+
|
|
233
|
+
let p0_S, p_S;
|
|
234
|
+
let poly = []
|
|
235
|
+
let pMid;
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
// 2. line-line-bezier-line-line
|
|
239
|
+
if (
|
|
240
|
+
comN2 && comN3 &&
|
|
241
|
+
comP.type === 'L' &&
|
|
242
|
+
type === 'L' &&
|
|
243
|
+
comBez &&
|
|
244
|
+
comN2.type === 'L' &&
|
|
245
|
+
(comN3.type === 'L' || comN3.type === 'Z')
|
|
246
|
+
) {
|
|
247
|
+
|
|
248
|
+
L1 = [com.p0, com.p];
|
|
249
|
+
L2 = [comN2.p0, comN2.p];
|
|
250
|
+
p0_S = com.p0
|
|
251
|
+
p_S = comN2.p
|
|
252
|
+
|
|
253
|
+
// don't allow sign changes
|
|
254
|
+
areaBez = getPolygonArea(cpts, false)
|
|
255
|
+
areaLines = getPolygonArea([...L1, ...L2], false)
|
|
256
|
+
signChange = (areaBez < 0 && areaLines > 0) || (areaBez > 0 && areaLines < 0)
|
|
257
|
+
|
|
258
|
+
if (!signChange) {
|
|
259
|
+
|
|
260
|
+
// mid point of mid bezier
|
|
261
|
+
pMid = pointAtT(cpts, 0.5)
|
|
262
|
+
|
|
263
|
+
// add to poly
|
|
264
|
+
poly = [p0_S, pMid, p_S]
|
|
265
|
+
|
|
266
|
+
combine = true
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// 1. line-bezier-bezier-line
|
|
272
|
+
else if (comN && (type === 'C' || type === 'Q') && comP.type === 'L') {
|
|
273
|
+
|
|
274
|
+
//renderPoint(markers, com.p)
|
|
275
|
+
|
|
276
|
+
// 1.2 next is cubic next is lineto
|
|
277
|
+
if (comN2 && comN2.type === 'L' && (comN.type === 'C' || comN.type === 'Q')) {
|
|
278
|
+
|
|
279
|
+
combine = true
|
|
280
|
+
|
|
281
|
+
L1 = [comP.p0, comP.p];
|
|
282
|
+
L2 = [comN2.p0, comN2.p];
|
|
283
|
+
p0_S = comP.p
|
|
284
|
+
p_S = comN2.p0
|
|
285
|
+
|
|
286
|
+
// mid point of mid bezier
|
|
287
|
+
pMid = comBez.p
|
|
288
|
+
|
|
289
|
+
// add to poly
|
|
290
|
+
poly = [p0_S, comBez.p, p_S]
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* calculate either combined
|
|
299
|
+
* cubic or arc commands
|
|
300
|
+
*/
|
|
301
|
+
if (combine) {
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
// try to find center of arc
|
|
305
|
+
let arcProps = getArcFromPoly(poly)
|
|
306
|
+
if (arcProps) {
|
|
307
|
+
|
|
308
|
+
let { centroid, r, deltaAngle, startAngle, endAngle } = arcProps;
|
|
309
|
+
|
|
310
|
+
let xAxisRotation = 0;
|
|
311
|
+
let sweep = deltaAngle > 0 ? 1 : 0;
|
|
312
|
+
let largeArc = Math.abs(deltaAngle) > Math.PI ? 1 : 0;
|
|
313
|
+
|
|
314
|
+
let pCM = rotatePoint(p0_S, centroid.x, centroid.y, deltaAngle * 0.5)
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
let dist2 = getDistAv(pCM, pMid)
|
|
318
|
+
let thresh = getDistAv(p0_S, p_S) * 0.05
|
|
319
|
+
let bezierCommands;
|
|
320
|
+
|
|
321
|
+
// point is close enough
|
|
322
|
+
if (dist2 < thresh) {
|
|
323
|
+
|
|
324
|
+
//toCubic = false;
|
|
325
|
+
|
|
326
|
+
bezierCommands = arcToBezierResolved(
|
|
327
|
+
{
|
|
328
|
+
p0: p0_S,
|
|
329
|
+
p: p_S,
|
|
330
|
+
centroid,
|
|
331
|
+
rx: r,
|
|
332
|
+
ry: r,
|
|
333
|
+
xAxisRotation,
|
|
334
|
+
sweep,
|
|
335
|
+
largeArc,
|
|
336
|
+
deltaAngle,
|
|
337
|
+
startAngle,
|
|
338
|
+
endAngle
|
|
339
|
+
}
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
if (bezierCommands.length === 1) {
|
|
343
|
+
|
|
344
|
+
// prefer more compact quadratic - otherwise arcs
|
|
345
|
+
let comBezier = revertCubicQuadratic(p0_S, bezierCommands[0].cp1, bezierCommands[0].cp2, p_S)
|
|
346
|
+
|
|
347
|
+
if (comBezier.type === 'Q') {
|
|
348
|
+
toCubic = true
|
|
349
|
+
}else{
|
|
350
|
+
comBezier = bezierCommands[0]
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
com = comBezier
|
|
354
|
+
//console.log('bezierCommands', comBezier);
|
|
355
|
+
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
// prefer arcs if 2 cubics are required
|
|
360
|
+
if (bezierCommands.length > 1) toCubic = false;
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
//toCubic = false
|
|
364
|
+
|
|
365
|
+
// return elliptic arc commands
|
|
366
|
+
if (!toCubic) {
|
|
367
|
+
// rewrite simplified command
|
|
368
|
+
com.type = 'A'
|
|
369
|
+
com.values = [r, r, xAxisRotation, largeArc, sweep, p_S.x, p_S.y];
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
//console.log(com);
|
|
373
|
+
|
|
374
|
+
com.p0 = p0_S;
|
|
375
|
+
com.p = p_S;
|
|
376
|
+
com.extreme = false;
|
|
377
|
+
com.corner = false;
|
|
378
|
+
|
|
379
|
+
// test rendering
|
|
380
|
+
//debug=true
|
|
381
|
+
|
|
382
|
+
/*
|
|
383
|
+
if (debug) {
|
|
384
|
+
// arcs
|
|
385
|
+
if (!toCubic) {
|
|
386
|
+
pathDataTest = [
|
|
387
|
+
{ type: 'M', values: [p0_S.x, p0_S.y] },
|
|
388
|
+
{ type: 'A', values: [r, r, xAxisRotation, largeArc, sweep, p_S.x, p_S.y] },
|
|
389
|
+
]
|
|
390
|
+
}
|
|
391
|
+
// cubics
|
|
392
|
+
else {
|
|
393
|
+
pathDataTest = [
|
|
394
|
+
{ type: 'M', values: [p0_S.x, p0_S.y] },
|
|
395
|
+
...bezierCommands
|
|
396
|
+
]
|
|
397
|
+
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
let d = pathDataToD(pathDataTest);
|
|
401
|
+
renderPath(markers, d, 'orange', '0.5%', '0.5')
|
|
402
|
+
}
|
|
403
|
+
*/
|
|
404
|
+
|
|
405
|
+
pathDataN.push(com);
|
|
406
|
+
i++
|
|
407
|
+
continue
|
|
408
|
+
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// pass through
|
|
414
|
+
pathDataN.push(com)
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
//let d= pathDataToD(pathDataN)
|
|
418
|
+
//console.log('!pathDataN', d);
|
|
419
|
+
return pathDataN;
|
|
420
|
+
}
|
package/src/svgii/rounding.js
CHANGED
|
@@ -8,6 +8,42 @@ import { getDistAv, getDistManhattan } from "./geometry";
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* round path data
|
|
13
|
+
* either by explicit decimal value or
|
|
14
|
+
* based on suggested accuracy in path data
|
|
15
|
+
*/
|
|
16
|
+
export function roundPathData(pathData, decimalsGlobal = -1) {
|
|
17
|
+
|
|
18
|
+
if (decimalsGlobal < 0) return pathData;
|
|
19
|
+
|
|
20
|
+
let len = pathData.length;
|
|
21
|
+
let decimals = decimalsGlobal
|
|
22
|
+
let decimalsArc = decimals < 3 ? decimals+2 : decimals
|
|
23
|
+
//decimalsArc = decimals
|
|
24
|
+
//console.log(decimalsArc);
|
|
25
|
+
|
|
26
|
+
for (let c = 0; c < len; c++) {
|
|
27
|
+
let com = pathData[c];
|
|
28
|
+
let { type, values } = com
|
|
29
|
+
let valLen = values.length;
|
|
30
|
+
if (!valLen) continue
|
|
31
|
+
|
|
32
|
+
let isArc = type.toLowerCase() === 'a'
|
|
33
|
+
|
|
34
|
+
for (let v = 0; v < valLen; v++) {
|
|
35
|
+
// allow higher accuracy for arc radii (... it's always arcs)
|
|
36
|
+
pathData[c].values[v] = isArc && v < 2 ? roundTo(values[v], decimalsArc) : roundTo(values[v], decimals);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
//console.log(pathData);
|
|
41
|
+
return pathData;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
11
47
|
export function detectAccuracyPoly(pts) {
|
|
12
48
|
|
|
13
49
|
let minDim = Infinity
|
|
@@ -20,7 +56,7 @@ export function detectAccuracyPoly(pts) {
|
|
|
20
56
|
let { p0 = null, p = null, dimA = 0 } = pt;
|
|
21
57
|
|
|
22
58
|
// use existing averave dimension value or calculate
|
|
23
|
-
if (
|
|
59
|
+
if (p && p0) {
|
|
24
60
|
dimA = dimA ? dimA : getDistManhattan(p0, p);
|
|
25
61
|
|
|
26
62
|
if (dimA) dims.push(dimA);
|
|
@@ -84,11 +120,37 @@ export function detectAccuracy(pathData) {
|
|
|
84
120
|
|
|
85
121
|
}
|
|
86
122
|
|
|
123
|
+
/**
|
|
124
|
+
* rounding helper
|
|
125
|
+
* allows for quantized rounding
|
|
126
|
+
* e.g 0.5 decimals s
|
|
127
|
+
*/
|
|
128
|
+
export function roundTo(num = 0, decimals = 3) {
|
|
129
|
+
if (decimals < 0) return num;
|
|
130
|
+
// Normal integer rounding
|
|
131
|
+
if (!decimals) return Math.round(num);
|
|
132
|
+
|
|
133
|
+
// stepped rounding
|
|
134
|
+
let intPart = Math.floor(decimals);
|
|
135
|
+
//let fracPart = decimals.toString().split('.');
|
|
136
|
+
//fracPart = fracPart[1] ? +fracPart[1] : 0
|
|
137
|
+
|
|
138
|
+
if (intPart !== decimals) {
|
|
139
|
+
let f = +(decimals - intPart).toFixed(2)
|
|
140
|
+
f = f > 0.5 ? (Math.floor((f) / 0.5) * 0.5) : f;
|
|
141
|
+
//console.log('fracPart', f);
|
|
142
|
+
let step = 10 ** -intPart * f;
|
|
143
|
+
return +(Math.round(num / step) * step).toFixed(8);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
let factor = 10 ** decimals;
|
|
147
|
+
return Math.round(num * factor) / factor;
|
|
148
|
+
}
|
|
87
149
|
|
|
88
150
|
|
|
89
151
|
|
|
90
|
-
export function
|
|
91
|
-
if(decimals
|
|
152
|
+
export function roundTo__(num = 0, decimals = 3) {
|
|
153
|
+
if (decimals <= -1) return num;
|
|
92
154
|
if (!decimals) return Math.round(num);
|
|
93
155
|
let factor = 10 ** decimals;
|
|
94
156
|
return Math.round(num * factor) / factor;
|
|
@@ -99,85 +161,24 @@ export function roundTo(num = 0, decimals = 3) {
|
|
|
99
161
|
* floating point accuracy
|
|
100
162
|
* based on numeric value
|
|
101
163
|
*/
|
|
102
|
-
export function autoRound(val, integerThresh = 50){
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if(val>integerThresh*2){
|
|
106
|
-
decimals=0
|
|
107
|
-
}
|
|
108
|
-
else if(val>integerThresh){
|
|
109
|
-
decimals=1
|
|
110
|
-
}else{
|
|
111
|
-
decimals=Math.ceil(500/val).toString().length
|
|
112
|
-
//console.log('decimals small', val, decimals);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
//console.log(val, decimals);
|
|
116
|
-
let factor = 10 ** decimals;
|
|
117
|
-
return Math.round(val * factor) / factor;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* round path data
|
|
125
|
-
* either by explicit decimal value or
|
|
126
|
-
* based on suggested accuracy in path data
|
|
127
|
-
*/
|
|
128
|
-
export function roundPathData(pathData, decimalsGlobal = -1) {
|
|
164
|
+
export function autoRound(val, integerThresh = 50) {
|
|
165
|
+
let decimals = 8;
|
|
129
166
|
|
|
130
|
-
if (
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
let com = pathData[c];
|
|
140
|
-
let {values} = com
|
|
141
|
-
//let values = pathData[c].values
|
|
142
|
-
let valLen = values.length;
|
|
143
|
-
if (!valLen) continue
|
|
144
|
-
|
|
145
|
-
for (let v = 0; v < valLen; v++) {
|
|
146
|
-
pathData[c].values[v] = roundTo(values[v], decimals);
|
|
147
|
-
}
|
|
148
|
-
};
|
|
167
|
+
if (val > integerThresh * 2) {
|
|
168
|
+
decimals = 0
|
|
169
|
+
}
|
|
170
|
+
else if (val > integerThresh) {
|
|
171
|
+
decimals = 1
|
|
172
|
+
} else {
|
|
173
|
+
decimals = Math.ceil(500 / val).toString().length
|
|
174
|
+
//console.log('decimals small', val, decimals);
|
|
175
|
+
}
|
|
149
176
|
|
|
150
|
-
//console.log(
|
|
151
|
-
|
|
177
|
+
//console.log(val, decimals);
|
|
178
|
+
let factor = 10 ** decimals;
|
|
179
|
+
return Math.round(val * factor) / factor;
|
|
152
180
|
}
|
|
153
181
|
|
|
154
182
|
|
|
155
|
-
export function roundPathData_(pathData, decimals = -1) {
|
|
156
|
-
|
|
157
|
-
if (decimals < 0) return pathData;
|
|
158
|
-
|
|
159
|
-
let len = pathData.length;
|
|
160
|
-
let c = 0;
|
|
161
|
-
while (c < len) {
|
|
162
|
-
|
|
163
|
-
//let com = pathData[c];
|
|
164
|
-
let values = pathData[c].values
|
|
165
|
-
let valLen = values.length;
|
|
166
|
-
|
|
167
|
-
// Z commands have no values
|
|
168
|
-
if (!valLen) {
|
|
169
|
-
c++; continue
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
let v = 0;
|
|
173
|
-
while (v < valLen) {
|
|
174
|
-
pathData[c].values[v] = roundTo(values[v], decimals);
|
|
175
|
-
v++
|
|
176
|
-
}
|
|
177
|
-
c++
|
|
178
183
|
|
|
179
|
-
};
|
|
180
184
|
|
|
181
|
-
//console.log(pathData);
|
|
182
|
-
return pathData;
|
|
183
|
-
}
|