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.
Files changed (43) hide show
  1. package/README.md +10 -0
  2. package/dist/svg-path-simplify.esm.js +3905 -1533
  3. package/dist/svg-path-simplify.esm.min.js +13 -1
  4. package/dist/svg-path-simplify.js +3923 -1551
  5. package/dist/svg-path-simplify.min.js +13 -1
  6. package/dist/svg-path-simplify.min.js.gz +0 -0
  7. package/index.html +61 -31
  8. package/package.json +3 -5
  9. package/src/constants.js +3 -0
  10. package/src/index-node.js +0 -1
  11. package/src/index.js +26 -0
  12. package/src/pathData_simplify_cubic.js +74 -31
  13. package/src/pathData_simplify_cubicsToArcs.js +566 -0
  14. package/src/pathData_simplify_harmonize_cpts.js +170 -0
  15. package/src/pathData_simplify_revertToquadratics.js +21 -0
  16. package/src/pathSimplify-main.js +253 -86
  17. package/src/poly-fit-curve-schneider.js +570 -0
  18. package/src/simplify_poly_RDP.js +146 -0
  19. package/src/simplify_poly_radial_distance.js +100 -0
  20. package/src/svg_getViewbox.js +1 -1
  21. package/src/svgii/geometry.js +389 -63
  22. package/src/svgii/geometry_area.js +2 -1
  23. package/src/svgii/pathData_analyze.js +259 -212
  24. package/src/svgii/pathData_convert.js +91 -663
  25. package/src/svgii/pathData_fromPoly.js +12 -0
  26. package/src/svgii/pathData_parse.js +90 -89
  27. package/src/svgii/pathData_parse_els.js +3 -0
  28. package/src/svgii/pathData_parse_fontello.js +449 -0
  29. package/src/svgii/pathData_remove_collinear.js +44 -37
  30. package/src/svgii/pathData_reorder.js +2 -1
  31. package/src/svgii/pathData_simplify_redraw.js +343 -0
  32. package/src/svgii/pathData_simplify_refineCorners.js +18 -9
  33. package/src/svgii/pathData_simplify_refineExtremes.js +19 -78
  34. package/src/svgii/pathData_split.js +42 -45
  35. package/src/svgii/pathData_toPolygon.js +130 -4
  36. package/src/svgii/poly_analyze.js +470 -14
  37. package/src/svgii/poly_to_pathdata.js +224 -19
  38. package/src/svgii/rounding.js +55 -112
  39. package/src/svgii/svg_cleanup.js +13 -1
  40. package/src/svgii/visualize.js +8 -3
  41. package/{debug.cjs → tests/debug.cjs} +3 -0
  42. /package/{test.js → tests/test.js} +0 -0
  43. /package/{testSVG.js → tests/testSVG.js} +0 -0
@@ -1,4 +1,4 @@
1
- import { pointAtT, svgArcToCenterParam, getBezierExtremeT } from "./geometry";
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, tMin=0, tMax=1) {
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
- if (
293
- cp1.x < xMin ||
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
- // no extremes
322
- else {
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, tMin=0, tMax=1) {
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 { getDistAv, pointAtT } from "./geometry";
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(' ')