svg-path-simplify 0.1.3 → 0.2.2
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 +10 -0
- package/dist/svg-path-simplify.esm.js +3905 -1533
- package/dist/svg-path-simplify.esm.min.js +13 -1
- package/dist/svg-path-simplify.js +3923 -1551
- package/dist/svg-path-simplify.min.js +13 -1
- package/dist/svg-path-simplify.min.js.gz +0 -0
- package/index.html +61 -31
- package/package.json +3 -5
- package/src/constants.js +3 -0
- package/src/index-node.js +0 -1
- package/src/index.js +26 -0
- package/src/pathData_simplify_cubic.js +74 -31
- package/src/pathData_simplify_cubicsToArcs.js +566 -0
- package/src/pathData_simplify_harmonize_cpts.js +170 -0
- package/src/pathData_simplify_revertToquadratics.js +21 -0
- package/src/pathSimplify-main.js +253 -86
- package/src/poly-fit-curve-schneider.js +570 -0
- package/src/simplify_poly_RDP.js +146 -0
- package/src/simplify_poly_radial_distance.js +100 -0
- package/src/svg_getViewbox.js +1 -1
- package/src/svgii/geometry.js +389 -63
- package/src/svgii/geometry_area.js +2 -1
- package/src/svgii/pathData_analyze.js +259 -212
- package/src/svgii/pathData_convert.js +91 -663
- package/src/svgii/pathData_fromPoly.js +12 -0
- package/src/svgii/pathData_parse.js +90 -89
- package/src/svgii/pathData_parse_els.js +3 -0
- package/src/svgii/pathData_parse_fontello.js +449 -0
- package/src/svgii/pathData_remove_collinear.js +44 -37
- package/src/svgii/pathData_reorder.js +2 -1
- package/src/svgii/pathData_simplify_redraw.js +343 -0
- package/src/svgii/pathData_simplify_refineCorners.js +18 -9
- package/src/svgii/pathData_simplify_refineExtremes.js +19 -78
- package/src/svgii/pathData_split.js +42 -45
- package/src/svgii/pathData_toPolygon.js +130 -4
- package/src/svgii/poly_analyze.js +470 -14
- package/src/svgii/poly_to_pathdata.js +224 -19
- package/src/svgii/rounding.js +55 -112
- package/src/svgii/svg_cleanup.js +13 -1
- package/src/svgii/visualize.js +8 -3
- package/{debug.cjs → tests/debug.cjs} +3 -0
- /package/{test.js → tests/test.js} +0 -0
- /package/{testSVG.js → tests/testSVG.js} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { pointAtT, svgArcToCenterParam, getBezierExtremeT
|
|
1
|
+
import { pointAtT, svgArcToCenterParam, getBezierExtremeT } from "./geometry";
|
|
2
2
|
import { renderPoint, renderPath } from "./visualize";
|
|
3
3
|
|
|
4
4
|
|
|
@@ -86,7 +86,7 @@ export function getPathDataPlusChunks(pathDataPlus = [], debug = false) {
|
|
|
86
86
|
//console.log('show chunks', pathDataChunks);
|
|
87
87
|
pathDataChunks.forEach((ch, i) => {
|
|
88
88
|
let stroke = i % 2 === 0 ? 'green' : 'orange';
|
|
89
|
-
if(i===pathDataChunks.length-2){
|
|
89
|
+
if (i === pathDataChunks.length - 2) {
|
|
90
90
|
stroke = 'magenta'
|
|
91
91
|
}
|
|
92
92
|
|
|
@@ -156,22 +156,22 @@ export function splitSubpaths0(pathData) {
|
|
|
156
156
|
//let com
|
|
157
157
|
//console.log(pathData);
|
|
158
158
|
|
|
159
|
-
if(!l) return [];
|
|
159
|
+
if (!l) return [];
|
|
160
160
|
|
|
161
161
|
//find split segments indices introduced by M commands
|
|
162
|
-
for(let i=1; i<l; i++){
|
|
163
|
-
let type= pathData[i].type.toLowerCase();
|
|
164
|
-
if(type==='m') indices.push(i)
|
|
162
|
+
for (let i = 1; i < l; i++) {
|
|
163
|
+
let type = pathData[i].type.toLowerCase();
|
|
164
|
+
if (type === 'm') indices.push(i)
|
|
165
165
|
}
|
|
166
166
|
//console.log(indices);
|
|
167
167
|
|
|
168
168
|
// only one sub path
|
|
169
169
|
let len = indices.length;
|
|
170
|
-
if(len===1) return [pathData];
|
|
170
|
+
if (len === 1) return [pathData];
|
|
171
171
|
|
|
172
172
|
let subPathArr = new Array(len);
|
|
173
173
|
|
|
174
|
-
for(let i=0; i<len; i++){
|
|
174
|
+
for (let i = 0; i < len; i++) {
|
|
175
175
|
let idx = indices[i]
|
|
176
176
|
subPathArr[i] = pathData.slice(idx, indices[i + 1]);
|
|
177
177
|
}
|
|
@@ -195,7 +195,7 @@ export function splitCommand(points, t) {
|
|
|
195
195
|
let cp1 = points[1];
|
|
196
196
|
let cp2 = points[points.length - 2];
|
|
197
197
|
let p = points[points.length - 1];
|
|
198
|
-
let m0,m1,m2,m3,m4, p2
|
|
198
|
+
let m0, m1, m2, m3, m4, p2
|
|
199
199
|
|
|
200
200
|
|
|
201
201
|
// cubic
|
|
@@ -270,7 +270,8 @@ export function splitCommand(points, t) {
|
|
|
270
270
|
* calculate command extremes
|
|
271
271
|
*/
|
|
272
272
|
|
|
273
|
-
export function addExtemesToCommand(p0, values,
|
|
273
|
+
export function addExtemesToCommand(p0, values,
|
|
274
|
+
{ tMin = 0, tMax = 1, addExtremes = true, addSemiExtremes = false } = {}) {
|
|
274
275
|
|
|
275
276
|
let pathDataNew = [];
|
|
276
277
|
|
|
@@ -280,56 +281,52 @@ export function addExtemesToCommand(p0, values, tMin=0, tMax=1) {
|
|
|
280
281
|
let p = { x: values[4], y: values[5] }
|
|
281
282
|
|
|
282
283
|
|
|
284
|
+
/*
|
|
283
285
|
// get inner bbox
|
|
284
286
|
let xMax = Math.max(p.x, p0.x)
|
|
285
287
|
let xMin = Math.min(p.x, p0.x)
|
|
286
288
|
let yMax = Math.max(p.y, p0.y)
|
|
287
289
|
let yMin = Math.min(p.y, p0.y)
|
|
290
|
+
*/
|
|
288
291
|
|
|
289
292
|
let extremeCount = 0;
|
|
290
293
|
|
|
291
294
|
//has extreme - split
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
cp1.x > xMax ||
|
|
295
|
-
cp1.y < yMin ||
|
|
296
|
-
cp1.y > yMax ||
|
|
297
|
-
cp2.x < xMin ||
|
|
298
|
-
cp2.x > xMax ||
|
|
299
|
-
cp2.y < yMin ||
|
|
300
|
-
cp2.y > yMax
|
|
301
|
-
|
|
302
|
-
) {
|
|
303
|
-
let pts = type === 'C' ? [p0, cp1, cp2, p] : [p0, cp1, p];
|
|
304
|
-
let tArr = getBezierExtremeT(pts).sort();
|
|
305
|
-
|
|
306
|
-
// avoid t split too close to start or end
|
|
307
|
-
tArr = tArr.filter(t=>t>tMin && t<tMax)
|
|
308
|
-
|
|
309
|
-
if(tArr.length){
|
|
310
|
-
let commandsSplit = splitCommandAtTValues(p0, values, tArr)
|
|
311
|
-
//console.log('commandsSplit', commandsSplit);
|
|
312
|
-
|
|
313
|
-
pathDataNew.push(...commandsSplit)
|
|
314
|
-
extremeCount += commandsSplit.length;
|
|
315
|
-
}else{
|
|
316
|
-
//console.log('no extreme: ', tArr);
|
|
317
|
-
pathDataNew.push({ type: type, values: values })
|
|
318
|
-
}
|
|
295
|
+
tMin = 0;
|
|
296
|
+
tMax = 1;
|
|
319
297
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
298
|
+
let pts = type === 'C' ? [p0, cp1, cp2, p] : [p0, cp1, p];
|
|
299
|
+
let tArrEx = addExtremes ? getBezierExtremeT(pts, { addExtremes, addSemiExtremes: false }) : [];
|
|
300
|
+
let tArrSemi = addSemiExtremes ? getBezierExtremeT(pts, { addExtremes, addSemiExtremes }) : [];
|
|
301
|
+
let tArr = Array.from(new Set([...tArrEx, ...tArrSemi])).sort();
|
|
302
|
+
|
|
303
|
+
// avoid t split too close to start or end
|
|
304
|
+
tArr = tArr.filter(t => t > tMin && t < tMax)
|
|
305
|
+
|
|
306
|
+
if (tArr.length) {
|
|
307
|
+
let commandsSplit = splitCommandAtTValues(p0, values, tArr)
|
|
308
|
+
//console.log('commandsSplit', commandsSplit);
|
|
309
|
+
|
|
310
|
+
pathDataNew.push(...commandsSplit)
|
|
311
|
+
extremeCount += commandsSplit.length;
|
|
312
|
+
} else {
|
|
313
|
+
//console.log('no extreme: ', tArr);
|
|
323
314
|
pathDataNew.push({ type: type, values: values })
|
|
324
315
|
}
|
|
325
316
|
|
|
317
|
+
|
|
326
318
|
return { pathData: pathDataNew, count: extremeCount };
|
|
327
319
|
|
|
328
320
|
}
|
|
329
321
|
|
|
330
322
|
|
|
331
323
|
|
|
332
|
-
export function addExtremePoints(pathData,
|
|
324
|
+
export function addExtremePoints(pathData, {
|
|
325
|
+
tMin = 0,
|
|
326
|
+
tMax = 1,
|
|
327
|
+
addExtremes = true,
|
|
328
|
+
addSemiExtremes = false,
|
|
329
|
+
} = {}) {
|
|
333
330
|
let pathDataNew = [pathData[0]];
|
|
334
331
|
// previous on path point
|
|
335
332
|
let p0 = { x: pathData[0].values[0], y: pathData[0].values[1] };
|
|
@@ -350,12 +347,12 @@ export function addExtremePoints(pathData, tMin=0, tMax=1) {
|
|
|
350
347
|
|
|
351
348
|
else {
|
|
352
349
|
// add extremes
|
|
353
|
-
if (type === 'C' || type === 'Q') {
|
|
354
|
-
let comExt = addExtemesToCommand(p0, values, tMin, tMax).pathData;
|
|
355
|
-
let comExt2 = com;
|
|
350
|
+
if ((addExtremes || addSemiExtremes) && (type === 'C' || type === 'Q')) {
|
|
351
|
+
let comExt = addExtemesToCommand(p0, values, { tMin, tMax, addExtremes, addSemiExtremes }).pathData;
|
|
352
|
+
//let comExt2 = com;
|
|
356
353
|
//comExt2.valu
|
|
357
354
|
//console.log('comExt', comExt);
|
|
358
|
-
pathDataNew.push(...comExt
|
|
355
|
+
pathDataNew.push(...comExt)
|
|
359
356
|
}
|
|
360
357
|
}
|
|
361
358
|
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { deg2rad, rad2Deg } from "../constants";
|
|
2
|
+
import { simplifyRDP } from "../simplify_poly_RDP";
|
|
3
|
+
import { simplifyRD } from "../simplify_poly_radial_distance";
|
|
4
|
+
import { getDistAv, getTatAngles, pointAtT } from "./geometry";
|
|
2
5
|
import { getPolyBBox } from "./geometry_bbox";
|
|
3
6
|
import { addDimensionData, analyzePathData } from "./pathData_analyze";
|
|
7
|
+
import { pathDataFromPoly } from "./pathData_fromPoly";
|
|
4
8
|
import { addExtremePoints } from "./pathData_split";
|
|
5
9
|
import { pathDataToD } from "./pathData_stringify";
|
|
6
10
|
import { analyzePoly } from "./poly_analyze";
|
|
@@ -8,6 +12,128 @@ import { getCurvePathData } from "./poly_to_pathdata";
|
|
|
8
12
|
import { renderPoint } from "./visualize";
|
|
9
13
|
|
|
10
14
|
|
|
15
|
+
|
|
16
|
+
export function pathDataToPolygon(pathData, {
|
|
17
|
+
angles = [],
|
|
18
|
+
split = 0,
|
|
19
|
+
getPathData = true,
|
|
20
|
+
width=0,
|
|
21
|
+
height=0
|
|
22
|
+
} = {}) {
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
let l = pathData.length;
|
|
26
|
+
let M = { x: pathData[0].values[0], y: pathData[0].values[1] }
|
|
27
|
+
let p0 = M
|
|
28
|
+
|
|
29
|
+
let minT = 1 / split * 0.5;
|
|
30
|
+
let maxT = 1 - minT
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
// collect polygon vertices
|
|
34
|
+
let pathDataPoly = []
|
|
35
|
+
let pts = [p0]
|
|
36
|
+
|
|
37
|
+
let ptsEnd = [0]
|
|
38
|
+
let ptCount = 1
|
|
39
|
+
|
|
40
|
+
// get max length
|
|
41
|
+
let minLength = 0;
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
split = !split ? 1 : split;
|
|
45
|
+
|
|
46
|
+
if(width && height){
|
|
47
|
+
minLength = (width+height) * 0.025 / split
|
|
48
|
+
}else{
|
|
49
|
+
//let areas = pathData.map(com => com.cptArea || 0).filter(Boolean).sort()
|
|
50
|
+
let lengths = pathData.map(com => com.dimA || 0).filter(Boolean).sort()
|
|
51
|
+
minLength = lengths[0]
|
|
52
|
+
//console.log('areas', areas, 'lengths', lengths);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
//minLength*=0.5
|
|
56
|
+
|
|
57
|
+
for (let i = 1; i < l; i++) {
|
|
58
|
+
let com = pathData[i];
|
|
59
|
+
//let comPrev = pathData[i - 1];
|
|
60
|
+
let comNext = pathData[i + 1] || null;
|
|
61
|
+
let { type, values } = com;
|
|
62
|
+
let valuesL = values.length;
|
|
63
|
+
let p = valuesL ? { x: values[valuesL - 2], y: values[valuesL - 1] } : M;
|
|
64
|
+
|
|
65
|
+
if (type === 'C' || type === 'Q') {
|
|
66
|
+
|
|
67
|
+
let cp1 = { x: values[0], y: values[1] }
|
|
68
|
+
let cp2 = type === 'C' ? { x: values[2], y: values[3] } : cp1
|
|
69
|
+
let cpts = type === 'C' ? [p0, cp1, cp2, p] : [p0, cp1, p];
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
// calculate split according to length
|
|
73
|
+
let length = com.dimA
|
|
74
|
+
let rat = Math.floor(length / (minLength))
|
|
75
|
+
split = Math.ceil(length / minLength)
|
|
76
|
+
|
|
77
|
+
let tArr = []
|
|
78
|
+
for(let i=1; i<split; i++){
|
|
79
|
+
tArr.push(1/split*i)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
tArr.forEach(t => {
|
|
83
|
+
let pt = pointAtT(cpts, t)
|
|
84
|
+
pts.push(pt)
|
|
85
|
+
ptCount++
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (type === 'M') {
|
|
91
|
+
M = p
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
p.area = com.cptArea|| 0
|
|
96
|
+
p.isExtreme = com.extreme|| false
|
|
97
|
+
p.isCorner = com.corner|| false
|
|
98
|
+
p.isDirChange = com.directionChange || false ;
|
|
99
|
+
|
|
100
|
+
// segment end point
|
|
101
|
+
pts.push(p)
|
|
102
|
+
|
|
103
|
+
// exclude for polygon simplification
|
|
104
|
+
if (com.extreme || com.corner || (comNext && comNext.type !== type) || type === 'L') {
|
|
105
|
+
//console.log('is ext' , com);
|
|
106
|
+
ptsEnd.push(ptCount)
|
|
107
|
+
//renderPoint(markers, p, 'magenta', '2%', '0.5')
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
ptCount++
|
|
111
|
+
|
|
112
|
+
p0 = p
|
|
113
|
+
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// reduce poly vertices
|
|
117
|
+
//pts = simplifyRD(pts, { quality: 0.5, exclude: ptsEnd, width, height })
|
|
118
|
+
pts = simplifyRD(pts, {quality:0.5, width, height})
|
|
119
|
+
//pts = simplifyRDP(pts, { quality: 0.8, width, height })
|
|
120
|
+
//console.log(ptsEnd);
|
|
121
|
+
|
|
122
|
+
/*
|
|
123
|
+
pts.forEach(pt => {
|
|
124
|
+
//renderPoint(markers, pt, 'cyan', '1%', '0.5')
|
|
125
|
+
})
|
|
126
|
+
//console.log(pts);
|
|
127
|
+
*/
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
pathDataPoly = pathDataFromPoly(pts)
|
|
131
|
+
return getPathData ? pathDataPoly : pts;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
// old function
|
|
11
137
|
export function pathDataToPolySingle(pathData, addExtremes = true) {
|
|
12
138
|
|
|
13
139
|
|
|
@@ -63,7 +189,7 @@ export function pathDataToPolySingle(pathData, addExtremes = true) {
|
|
|
63
189
|
dimA = getDistAv(p0, p);
|
|
64
190
|
|
|
65
191
|
|
|
66
|
-
if(extreme){
|
|
192
|
+
if (extreme) {
|
|
67
193
|
//renderPoint(markers, p, 'cyan')
|
|
68
194
|
}
|
|
69
195
|
|
|
@@ -102,7 +228,7 @@ export function pathDataToPolySingle(pathData, addExtremes = true) {
|
|
|
102
228
|
let idx = p.extreme ? i : i - 1
|
|
103
229
|
//console.log('remove', idx);
|
|
104
230
|
remove.add(idx)
|
|
105
|
-
}
|
|
231
|
+
}
|
|
106
232
|
}
|
|
107
233
|
|
|
108
234
|
|
|
@@ -115,7 +241,7 @@ export function pathDataToPolySingle(pathData, addExtremes = true) {
|
|
|
115
241
|
poly.splice(idx, 1)
|
|
116
242
|
}
|
|
117
243
|
|
|
118
|
-
poly.splice(poly.length-1, poly.length)
|
|
244
|
+
poly.splice(poly.length - 1, poly.length)
|
|
119
245
|
|
|
120
246
|
|
|
121
247
|
let polyAtt = poly.map(pt => `${pt.x} ${pt.y} `).join(' ')
|