svg-path-simplify 0.4.2 → 0.4.3

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 (44) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +6 -4
  3. package/dist/svg-path-simplify.esm.js +2139 -940
  4. package/dist/svg-path-simplify.esm.min.js +2 -2
  5. package/dist/svg-path-simplify.js +2139 -940
  6. package/dist/svg-path-simplify.min.js +2 -2
  7. package/dist/svg-path-simplify.pathdata.esm.js +127 -85
  8. package/dist/svg-path-simplify.pathdata.esm.min.js +2 -2
  9. package/docs/privacy-webapp.md +24 -0
  10. package/index.html +290 -152
  11. package/package.json +1 -1
  12. package/src/css_parse.js +317 -0
  13. package/src/detect_input.js +34 -4
  14. package/src/pathData_simplify_harmonize_cpts.js +77 -1
  15. package/src/pathSimplify-main.js +242 -269
  16. package/src/pathSimplify-presets.js +243 -0
  17. package/src/poly-fit-curve-schneider.js +14 -7
  18. package/src/simplify_poly_RC.js +102 -0
  19. package/src/simplify_poly_RDP.js +109 -1
  20. package/src/simplify_poly_radial_distance.js +3 -3
  21. package/src/string_helpers.js +130 -4
  22. package/src/svgii/geometry.js +182 -3
  23. package/src/svgii/geometry_length.js +237 -0
  24. package/src/svgii/pathData_convert.js +5 -1
  25. package/src/svgii/pathData_fix_directions.js +6 -0
  26. package/src/svgii/pathData_fromPoly.js +3 -3
  27. package/src/svgii/pathData_getLength.js +86 -0
  28. package/src/svgii/pathData_parse.js +2 -0
  29. package/src/svgii/pathData_parse_els.js +66 -68
  30. package/src/svgii/pathData_split_to_groups.js +168 -0
  31. package/src/svgii/pathData_stringify.js +26 -64
  32. package/src/svgii/pathData_toPolygon.js +3 -4
  33. package/src/svgii/poly_analyze.js +61 -0
  34. package/src/svgii/poly_normalize.js +11 -2
  35. package/src/svgii/poly_to_pathdata.js +85 -24
  36. package/src/svgii/rounding.js +8 -7
  37. package/src/svgii/svg_cleanup.js +374 -620
  38. package/src/svgii/svg_cleanup_convertPathLength.js +32 -0
  39. package/src/svgii/svg_cleanup_general_svg_atts.js +97 -0
  40. package/src/svgii/svg_cleanup_normalize_transforms.js +83 -0
  41. package/src/svgii/svg_cleanup_remove_els_and_atts.js +72 -0
  42. package/src/svgii/svg_cleanup_ungroup.js +36 -0
  43. package/src/svgii/svg_el_parse_style_props.js +65 -43
  44. package/src/svgii/svg_getElementLength.js +67 -0
@@ -16,29 +16,25 @@ import { autoRound, roundTo } from './rounding.js';
16
16
  import { attLookup } from './svg-styles-to-attributes-const.js';
17
17
  import { qrDecomposeMatrix } from './transform_qr_decompose.js';
18
18
 
19
-
19
+ /**
20
+ * Convert shapes to paths
21
+ * converts also transforms
22
+ */
20
23
  export function shapeElToPath(el, { width = 0,
21
24
  height = 0,
22
- convert_rects = false,
23
- convert_ellipses = false,
24
- convert_poly = false,
25
- convert_lines = false,
26
- //matrix={a:1, b:0, c:0, d:1, e:0, f:0},
27
- matrix=null
25
+ convertShapes = [],
26
+ matrix = null
28
27
 
29
28
  } = {}) {
30
29
 
30
+
31
31
  let nodeName = el.nodeName.toLowerCase();
32
32
  //console.log('shapeElToPath', nodeName);
33
33
 
34
34
 
35
- if (
36
- nodeName === 'path' && !matrix ||
37
- nodeName === 'rect' && !convert_rects ||
38
- (nodeName === 'circle' || nodeName === 'ellipse') && !convert_ellipses ||
39
- (nodeName === 'polygon' || nodeName === 'polyline') && !convert_poly ||
40
- (nodeName === 'line') && !convert_lines
41
- ) return el;
35
+
36
+ if (!convertShapes.includes(nodeName)) return el;
37
+ //console.log(convertShapes);
42
38
 
43
39
 
44
40
  let pathData = getPathDataFromEl(el, { width, height });
@@ -47,8 +43,9 @@ export function shapeElToPath(el, { width = 0,
47
43
  let exclude = ['d', 'x', 'y', 'x1', 'y1', 'x2', 'y2', 'cx', 'cy', 'dx', 'dy', 'r', 'rx', 'ry', 'width', 'height', 'points'];
48
44
 
49
45
  // transform pathData
50
- if(matrix && Object.values(matrix).join('')!=='100100'){
46
+ if (matrix && Object.values(matrix).join('') !== '100100') {
51
47
  pathData = transformPathData(pathData, matrix)
48
+ //console.log('transformPathData', pathData);
52
49
  exclude.push('transform', 'transform-origin')
53
50
  }
54
51
 
@@ -72,14 +69,7 @@ export function shapeElToPath(el, { width = 0,
72
69
  return pathN
73
70
 
74
71
  }
75
- /*
76
- export function copyAttributes(newEl, oldEl){
77
72
 
78
- let attributes = [...oldEl.attributes].map(att => att.name);
79
-
80
-
81
- }
82
- */
83
73
 
84
74
 
85
75
  // retrieve pathdata from svg geometry elements
@@ -112,39 +102,7 @@ export function getPathDataFromEl(el, {
112
102
  case 'rect':
113
103
  attNames = ['x', 'y', 'width', 'height', 'rx', 'ry'];
114
104
  ({ x=0, y=0, width=0, height=0, rx=0, ry=0 } = atts);
115
-
116
- if (!rx && !ry) {
117
- pathData = [
118
- { type: "M", values: [x, y] },
119
- { type: "L", values: [x + width, y] },
120
- { type: "L", values: [x + width, y + height] },
121
- { type: "L", values: [x, y + height] },
122
- { type: "Z", values: [] }
123
- ];
124
- } else {
125
-
126
- rx = rx ? rx : ry;
127
- ry = ry ? ry : rx;
128
-
129
- if (rx > width / 2) {
130
- rx = width / 2;
131
- }
132
- if (ry > height / 2) {
133
- ry = height / 2;
134
- }
135
- pathData = [
136
- { type: "M", values: [x + rx, y] },
137
- { type: "L", values: [x + width - rx, y] },
138
- { type: "A", values: [rx, ry, 0, 0, 1, x + width, y + ry] },
139
- { type: "L", values: [x + width, y + height - ry] },
140
- { type: "A", values: [rx, ry, 0, 0, 1, x + width - rx, y + height] },
141
- { type: "L", values: [x + rx, y + height] },
142
- { type: "A", values: [rx, ry, 0, 0, 1, x, y + height - ry] },
143
- { type: "L", values: [x, y + ry] },
144
- { type: "A", values: [rx, ry, 0, 0, 1, x + rx, y] },
145
- { type: "Z", values: [] }
146
- ];
147
- }
105
+ pathData = rectToPathData(x, y, width, height, rx, ry);
148
106
  break;
149
107
 
150
108
  case 'circle':
@@ -164,7 +122,6 @@ export function getPathDataFromEl(el, {
164
122
  ry = ry ? ry : r;
165
123
  }
166
124
 
167
-
168
125
  // simplified radii for circles
169
126
  let rxS = isCircle && r >= 1 ? 1 : rx;
170
127
  let ryS = isCircle && r >= 1 ? 1 : ry;
@@ -210,13 +167,51 @@ export function getPathDataFromEl(el, {
210
167
  };
211
168
 
212
169
 
170
+ export function rectToPathData(x = 0, y = 0, width = 0, height = 0, rx = 0, ry = 0) {
171
+ let pathData = [];
172
+
173
+ if (!rx && !ry) {
174
+ pathData = [
175
+ { type: "M", values: [x, y] },
176
+ { type: "L", values: [x + width, y] },
177
+ { type: "L", values: [x + width, y + height] },
178
+ { type: "L", values: [x, y + height] },
179
+ { type: "Z", values: [] }
180
+ ];
181
+ } else {
182
+
183
+ rx = rx ? rx : ry;
184
+ ry = ry ? ry : rx;
185
+
186
+ if (rx > width / 2) {
187
+ rx = width / 2;
188
+ }
189
+ if (ry > height / 2) {
190
+ ry = height / 2;
191
+ }
192
+ pathData = [
193
+ { type: "M", values: [x + rx, y] },
194
+ { type: "L", values: [x + width - rx, y] },
195
+ { type: "A", values: [rx, ry, 0, 0, 1, x + width, y + ry] },
196
+ { type: "L", values: [x + width, y + height - ry] },
197
+ { type: "A", values: [rx, ry, 0, 0, 1, x + width - rx, y + height] },
198
+ { type: "L", values: [x + rx, y + height] },
199
+ { type: "A", values: [rx, ry, 0, 0, 1, x, y + height - ry] },
200
+ { type: "L", values: [x, y + ry] },
201
+ { type: "A", values: [rx, ry, 0, 0, 1, x + rx, y] },
202
+ { type: "Z", values: [] }
203
+ ];
204
+ }
205
+
206
+ return pathData
207
+ }
208
+
209
+
210
+
213
211
 
214
212
 
215
213
  export function pathElToShape(el, {
216
- convert_rects = false,
217
- convert_ellipses = false,
218
- convert_poly = false,
219
- convert_lines = false
214
+ convertShapes = [],
220
215
  } = {}) {
221
216
 
222
217
  //console.log('pathElToShape', convert_rects, convert_ellipses, convert_lines );
@@ -236,10 +231,13 @@ export function pathElToShape(el, {
236
231
  let attsNew = {}
237
232
  let decimals = 7;
238
233
 
234
+
239
235
  if (isPoly) {
240
236
 
237
+ //console.log('pathsToShapes', isPoly);
238
+
241
239
  // is line
242
- if (pathData.length === 2 && convert_lines) {
240
+ if (pathData.length === 2 && convertShapes.includes('line')) {
243
241
  type = 'line'
244
242
  shape = document.createElementNS(svgNs, type)
245
243
  let [x1, y1, x2, y2] = [...pathData[0].values, ...pathData[1].values].map(val => roundTo(val, decimals))
@@ -255,7 +253,7 @@ export function pathElToShape(el, {
255
253
  let areaDiff = Math.abs(1 - areaRect / areaPoly);
256
254
 
257
255
  // is rect
258
- if (convert_rects && areaDiff < 0.01) {
256
+ if (convertShapes.includes('rect') && areaDiff < 0.01) {
259
257
  type = 'rect'
260
258
  shape = document.createElementNS(svgNs, type)
261
259
  let { x, y, width, height } = bb
@@ -263,7 +261,7 @@ export function pathElToShape(el, {
263
261
 
264
262
  }
265
263
  // polyline or polygon
266
- else if(convert_poly) {
264
+ else if (convertShapes.includes('polygon') || convertShapes.includes('polyline')) {
267
265
  type = closed ? 'polygon' : 'polyline';
268
266
  shape = document.createElementNS(svgNs, type)
269
267
  let points = vertices.map(pt => { return [pt.x, pt.y] }).flat().map(val => roundTo(val, decimals)).join(' ')
@@ -272,7 +270,7 @@ export function pathElToShape(el, {
272
270
  }
273
271
  }
274
272
  // circles or ellipses
275
- else if (!hasLines && convert_ellipses) {
273
+ else if (!hasLines && (convertShapes.includes('circle') || convertShapes.includes('ellipse'))) {
276
274
 
277
275
  // try to convert cubics to arcs
278
276
  if (!hasArcs && hasBeziers) {
@@ -308,11 +306,11 @@ export function pathElToShape(el, {
308
306
  rxVals = Array.from(rxVals)
309
307
  ryVals = Array.from(ryVals)
310
308
 
311
- if(cxVals.length===1 && cyVals.length===1 && rxVals.length===1 && ryVals.length===1){
309
+ if (cxVals.length === 1 && cyVals.length === 1 && rxVals.length === 1 && ryVals.length === 1) {
312
310
  let [rx, ry, cx, cy] = [rxVals[0], ryVals[0], cxVals[0], cyVals[0]]
313
- type = rx===ry ? 'circle' : 'ellipse';
311
+ type = rx === ry ? 'circle' : 'ellipse';
314
312
  shape = document.createElementNS(svgNs, type)
315
- attsNew = type==='circle' ? { r:rx, cx, cy } : {rx, ry, cx, cy}
313
+ attsNew = type === 'circle' ? { r: rx, cx, cy } : { rx, ry, cx, cy }
316
314
  }
317
315
  }
318
316
  }
@@ -334,11 +332,11 @@ export function pathElToShape(el, {
334
332
  shape.setAttribute(att, attributes[att])
335
333
  }
336
334
  }
337
-
338
335
  // replace
339
336
  el = shape;
340
337
  }
341
338
 
339
+ //console.log(el);
342
340
  return el;
343
341
 
344
342
  }
@@ -0,0 +1,168 @@
1
+ import { svgNs } from "../constants";
2
+ import { getPathDataVertices, isPointInPolygon } from "./geometry";
3
+ import { checkBBoxIntersections, getPolyBBox } from "./geometry_bbox";
4
+ import { convertPathData } from "./pathData_convert";
5
+ import { pathDataToD } from "./pathData_stringify";
6
+ import { roundTo } from "./rounding";
7
+ import { renderPoint } from "./visualize";
8
+
9
+ export function splitCompundGroups(pathDataPlusArr = [], {
10
+ toRelative = true,
11
+ toShorthands = true,
12
+ minifyD = 0,
13
+ decimals = 3,
14
+ addDimensions = false
15
+ } = {}) {
16
+
17
+ //console.log('???pathDataPlusArr', pathDataPlusArr);
18
+ let pathDataSplit = [];
19
+ pathDataPlusArr = JSON.parse(JSON.stringify(pathDataPlusArr))
20
+ let len = pathDataPlusArr.length;
21
+
22
+ //let bb0 =
23
+ let xArr = [];
24
+ let yArr = []
25
+
26
+ // refine bbox and add cpt polygon
27
+ for (let i = 0; i < len; i++) {
28
+ let sub = pathDataPlusArr[i]
29
+ let { pathData, bb } = sub
30
+
31
+ // console.log(bb);
32
+ // include control points for better overlapping approximation
33
+ //let poly = getPathDataVertices(pathData, true);
34
+ //let bb2 = getPolyBBox(poly);
35
+
36
+ if (bb.width && bb.height) {
37
+ } else {
38
+ let poly = getPathDataVertices(pathData, true);
39
+ bb = getPolyBBox(poly);
40
+ pathDataPlusArr[i].bb = bb;
41
+ //console.log(bb, sub);
42
+ }
43
+
44
+ xArr.push(bb.left, bb.right)
45
+ yArr.push(bb.top, bb.bottom)
46
+ sub.includes = []
47
+ }
48
+
49
+
50
+ /**
51
+ * check overlapping
52
+ * sub paths
53
+ */
54
+ for (let i = 0, l = pathDataPlusArr.length; i < l; i++) {
55
+ let sub1 = pathDataPlusArr[i];
56
+ let { bb, poly } = sub1;
57
+
58
+ for (let j = 0; j < l; j++) {
59
+
60
+ let sub1 = pathDataPlusArr[j];
61
+ if (i === j) continue;
62
+
63
+ //let [bb1, poly1] = [sub1.bb, sub1.poly];
64
+ let bb1 = sub1.bb;
65
+ //let poly1 = sub1.poly
66
+
67
+ // test sample on-path points
68
+ let ptM = { x: bb1.x + bb1.width * 0.5, y: bb1.y + bb1.height * 0.5 };
69
+
70
+
71
+ let inPoly = false;
72
+ if (ptM.x >= bb.x && ptM.y >= bb.y && ptM.x <= bb.right && ptM.y <= bb.bottom) {
73
+ inPoly = true;
74
+ pathDataPlusArr[i].includes.push(j);
75
+ }
76
+
77
+ }
78
+ }
79
+
80
+
81
+ /**
82
+ * combine overlapping
83
+ * compound paths
84
+ */
85
+ for (let i = 0, l = pathDataPlusArr.length; i < l; i++) {
86
+ let sub = pathDataPlusArr[i];
87
+ let { includes } = sub;
88
+
89
+ includes.forEach(s => {
90
+ let pathData = pathDataPlusArr[s].pathData;
91
+ if (pathData.length) {
92
+ pathDataPlusArr[i].pathData.push(...pathData);
93
+ pathDataPlusArr[s].pathData = [];
94
+ }
95
+ });
96
+ }
97
+
98
+ // remove empty els due to grouping
99
+ pathDataPlusArr = pathDataPlusArr.filter(sub => sub.pathData.length);
100
+
101
+ // try to find row left to right order
102
+ //pathDataPlusArr = pathDataPlusArr.sort((a, b) => ((a.bb.x + a.bb.y * 3) - (b.bb.x + b.bb.y * 3)))
103
+ //pathDataPlusArr = pathDataPlusArr.sort((a, b) => ((a.bb.x + a.bb.y * 2) - (b.bb.x + b.bb.y * 2)))
104
+ pathDataPlusArr = pathDataPlusArr.sort((a, b) => ((a.bb.x ) - (b.bb.x)))
105
+
106
+ // create SVG
107
+ let x = Math.min(...xArr);
108
+ let y = Math.min(...yArr);
109
+ let right = Math.max(...xArr);
110
+ let bottom = Math.max(...yArr);
111
+ let width = right - x;
112
+ let height = bottom - y;
113
+
114
+ [x, y, width, height] = [x, y, width, height].map(val => roundTo(val, decimals));
115
+
116
+ let dimensionAtts = addDimensions ? `width="${width}" height="${height}"` : ''
117
+ let svgSplit = `<svg ${dimensionAtts} viewBox="${x} ${y} ${width} ${height}" xmlns="${svgNs}">`;
118
+
119
+ pathDataPlusArr.forEach(sub => {
120
+ let { pathData } = sub;
121
+
122
+ pathData = convertPathData(pathData, { toRelative, toShorthands, decimals });
123
+ let d = pathDataToD(pathData, minifyD);
124
+ svgSplit += `<path d="${d}"/>`;
125
+
126
+ });
127
+
128
+ svgSplit += '</svg>';
129
+
130
+ let splitObj = { pathData: pathDataPlusArr, svg: svgSplit }
131
+ //console.log('splitObj', splitObj);
132
+ return splitObj
133
+
134
+ }
135
+
136
+
137
+ /*
138
+ function checkBBoxIntersections2(bb, bb1) {
139
+ let [x, y, width, height, right, bottom] = [
140
+ bb.x,
141
+ bb.y,
142
+ bb.width,
143
+ bb.height,
144
+ bb.x + bb.width,
145
+ bb.y + bb.height
146
+ ];
147
+ let [x1, y1, width1, height1, right1, bottom1] = [
148
+ bb1.x,
149
+ bb1.y,
150
+ bb1.width,
151
+ bb1.height,
152
+ bb1.x + bb1.width,
153
+ bb1.y + bb1.height
154
+ ];
155
+ let intersects = false;
156
+ //console.log('bb', bb, bb1);
157
+ //console.log();
158
+
159
+ if (x < x1 && right > right1 && y < y1 && bottom > bottom1) {
160
+ intersects = true;
161
+ }
162
+
163
+ console.log('???', intersects, 'dims', width, height, '2', width1, height1);
164
+
165
+
166
+ return intersects;
167
+ }
168
+ */
@@ -4,22 +4,24 @@
4
4
  * d attribute string
5
5
  */
6
6
 
7
- export function pathDataToD(pathData, optimize = 0) {
8
-
9
- optimize = parseFloat(optimize)
10
-
11
-
7
+ export function pathDataToD(pathData, mode = 0) {
8
+
9
+ mode = parseFloat(mode)
10
+ /*
11
+ 0 = max minification
12
+ 0.5 = safe
13
+ 1 = verbose
14
+ 2 = beautify
15
+ */
12
16
  let len = pathData.length;
13
- let beautify = optimize > 1;
14
- let minify = beautify || optimize ? false : true;
15
17
 
16
-
17
- let d = '';
18
18
  let valsString = pathData[0].values.join(" ");
19
- let separator_command = beautify ? `\n` : (minify ? '' : ' ');
20
- let separator_type = !minify ? ' ' : '';
19
+ let separator_command = mode > 1 ? `\n` :
20
+ ((mode < 1) ? '' : ' ');
21
+ let separator_type = mode > 0.5 ? ' ' : '';
21
22
 
22
- d = `${pathData[0].type}${separator_type}${valsString}${separator_command}`;
23
+ // 1st command
24
+ let d = `${pathData[0].type}${separator_type}${valsString}${separator_command}`;
23
25
 
24
26
 
25
27
  for (let i = 1; i < len; i++) {
@@ -29,7 +31,7 @@ export function pathDataToD(pathData, optimize = 0) {
29
31
  valsString = '';
30
32
 
31
33
  // Minify Arc commands (A/a) – actually sucks!
32
- if (minify && (type === 'A' || type === 'a')) {
34
+ if (!mode && (type === 'A' || type === 'a')) {
33
35
  values = [
34
36
  values[0], values[1], values[2],
35
37
  `${values[3]}${values[4]}${values[5]}`,
@@ -38,16 +40,15 @@ export function pathDataToD(pathData, optimize = 0) {
38
40
  }
39
41
 
40
42
  // Omit type for repeated commands
41
- type = (minify && com0.type === com.type && com.type.toLowerCase() !== 'm')
43
+ type = ((mode < 1) && com0.type === com.type && com.type.toLowerCase() !== 'm')
42
44
  ? " "
43
- : (minify && com0.type === "M" && com.type === "L"
45
+ : ((mode < 1) && com0.type === "M" && com.type === "L"
44
46
  ? " "
45
47
  : com.type);
46
48
 
47
49
 
48
50
  // concatenate subsequent floating point values
49
- if (minify) {
50
-
51
+ if (!mode) {
51
52
 
52
53
  let prevWasFloat = false;
53
54
 
@@ -67,71 +68,32 @@ export function pathDataToD(pathData, optimize = 0) {
67
68
  if (v > 0 && !(prevWasFloat && isSmallFloat)) {
68
69
  valsString += ' ';
69
70
  }
70
- //console.log(isSmallFloat, prevWasFloat, valStr);
71
71
 
72
72
  valsString += valStr
73
73
  prevWasFloat = isSmallFloat;
74
74
  }
75
75
 
76
- //console.log('minify', valsString);
77
- d += `${type}${separator_type}${valsString}${separator_command}`;
78
-
79
76
  }
80
77
  // regular non-minified output
81
78
  else {
82
- d += `${type}${separator_type}${values.join(' ')}${separator_command}`;
79
+ valsString = values.join(' ')
83
80
  }
81
+
82
+ if(i===len-1) separator_command=''
83
+ d += `${type}${separator_type}${valsString}${separator_command}`;
84
84
  }
85
85
 
86
- if (minify) {
86
+
87
+ if (mode < 1) {
87
88
  d = d
88
89
  .replace(/[A-Za-z]0(?=\.)/g, m => m[0])
89
90
  .replace(/ 0\./g, " .") // Space before small decimals
90
91
  .replace(/ -/g, "-") // Remove space before negatives
91
92
  .replace(/-0\./g, "-.") // Remove leading zero from negative decimals
92
- .replace(/Z/g, "z"); // Convert uppercase 'Z' to lowercase
93
- }
94
-
95
- return d;
96
- }
97
-
98
-
99
- export function pathDataToD_0(pathData, decimals = -1, minify = false) {
100
- // implicit l command
101
- if (pathData[1].type === "l" && minify) {
102
- pathData[0].type = "m";
103
- }
104
- let d = `${pathData[0].type}${pathData[0].values.join(" ")}`;
105
-
106
- for (let i = 1; i < pathData.length; i++) {
107
- let com0 = pathData[i - 1];
108
- let com = pathData[i];
109
-
110
- let type = (com0.type === com.type && minify) ?
111
- " " : (
112
- (com0.type === "m" && com.type === "l") ||
113
- (com0.type === "M" && com.type === "l") ||
114
- (com0.type === "M" && com.type === "L")
115
- ) && minify ?
116
- " " : com.type;
117
-
118
- // round
119
- if (com.values.length && decimals > -1) {
120
- com.values = com.values.map(val => { return +val.toFixed(decimals) })
121
- }
122
- d += `${type}${com.values.join(" ")}`;
93
+ .replace(/Z/g, "z") // Convert uppercase 'Z' to lowercase
123
94
  }
124
95
 
125
-
126
- if (minify) {
127
- d = d
128
- .replaceAll(" 0.", " .")
129
- .replaceAll(" -", "-")
130
- .replaceAll("-0.", "-.")
131
- .replace(/\s+([mlcsqtahvz])/gi, "$1")
132
- .replaceAll("Z", "z");
133
- }
96
+ //console.log(`"${d}"`);
134
97
 
135
98
  return d;
136
99
  }
137
-
@@ -21,7 +21,7 @@ import { renderPoint } from "./visualize";
21
21
  * creates precise polygon approximation from pathdata
22
22
  * converts arc to cubis
23
23
  */
24
- export function pathDataToPolygon(pathData, {
24
+ export function pathDataToPolygonOpt(pathData, {
25
25
  precisionPoly = 1,
26
26
  autoAccuracy=false,
27
27
  polyFormat='points',
@@ -105,12 +105,12 @@ simplifyRDP=1,
105
105
 
106
106
  // simplify polygon
107
107
  if(simplifyRD>0){
108
- pts2 = simplifyPolyRD(pts2, {quality:simplifyRD+'px'})
108
+ pts2 = simplifyPolyRD(pts2, {quality:simplifyRD})
109
109
  }
110
110
 
111
111
 
112
112
  if(simplifyRDP>0){
113
- pts2 = simplifyPolyRDP(pts2, {quality:simplifyRDP+'px'})
113
+ pts2 = simplifyPolyRDP(pts2, {quality:simplifyRDP})
114
114
  }
115
115
 
116
116
 
@@ -120,7 +120,6 @@ simplifyRDP=1,
120
120
 
121
121
  if(autoAccuracy){
122
122
  decimals = detectAccuracyPoly(pts)
123
- //console.log('decimals', decimals);
124
123
  }
125
124
 
126
125
  let poly = decimals>-1 ? pts2.map(pt => { return { x: roundTo(pt.x, decimals), y: roundTo(pt.y, decimals) } }) : pts2.map(pt => { return { x: pt.x, y: pt.y } })
@@ -9,6 +9,67 @@ import { pathDataToD } from "./pathData_stringify";
9
9
  import { renderPath, renderPoint, renderPoly } from "./visualize";
10
10
 
11
11
 
12
+ export function getPolyCentroid(pts) {
13
+
14
+ let l = pts.length;
15
+ let x = 0, y = 0;
16
+ for (let i = 0; l && i < l; i++) {
17
+ let pt = pts[i];
18
+ x += pt.x
19
+ y += pt.y
20
+ }
21
+
22
+ let centroid = {x: x/l, y:y/l}
23
+ return centroid
24
+ //console.log(centroid);
25
+
26
+ }
27
+
28
+ export function getPolyCentroidWeighted(points) {
29
+ if (!points || points.length === 0) return null;
30
+
31
+ let totalWeight = 0;
32
+ let sumX = 0;
33
+ let sumY = 0;
34
+
35
+ for (const point of points) {
36
+ let weight = point.weight || 1; // default weight = 1
37
+ sumX += point.x * weight;
38
+ sumY += point.y * weight;
39
+ totalWeight += weight;
40
+ }
41
+
42
+ if (totalWeight === 0) return null;
43
+
44
+ return {
45
+ x: sumX / totalWeight,
46
+ y: sumY / totalWeight
47
+ };
48
+ }
49
+
50
+
51
+
52
+ export function detectRegularPolygon(pts, centroid={x:0, y:0}) {
53
+ let rSq = getSquareDistance(pts[0], centroid);
54
+ let isRegular = true;
55
+
56
+ for (let i = 1, l = pts.length; i < l; i++) {
57
+ let pt1 = pts[i];
58
+ let dist = getSquareDistance(pt1, centroid);
59
+
60
+ let diff = Math.abs(rSq-dist);
61
+ let diffRel = diff/rSq
62
+ //console.log('diffRel', diffRel);
63
+
64
+ if (diffRel > 0.05) {
65
+ return false;
66
+ }
67
+
68
+
69
+ }
70
+ return isRegular;
71
+ }
72
+
12
73
 
13
74
  export function analyzePoly(pts, {
14
75
  x = 0,
@@ -64,8 +64,17 @@ export function polyPtsToArray(pts) {
64
64
  // convert flat point value array to point object array
65
65
  export function toPointArray(pts) {
66
66
  let ptArr = [];
67
- for (let i = 1, l = pts.length; i < l; i += 2) {
68
- ptArr.push({ x: pts[i - 1], y: pts[i] });
67
+
68
+ if(pts[0].length===2){
69
+ for (let i = 0, l = pts.length; i < l; i ++) {
70
+ let pt = pts[i]
71
+ ptArr.push({ x: pt[0], y:pt[1] });
72
+ }
73
+
74
+ }else{
75
+ for (let i = 1, l = pts.length; i < l; i += 2) {
76
+ ptArr.push({ x: pts[i - 1], y: pts[i] });
77
+ }
69
78
  }
70
79
  return ptArr;
71
80
  };