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.
Files changed (61) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +7 -4
  3. package/dist/svg-path-simplify.esm.js +3593 -1279
  4. package/dist/svg-path-simplify.esm.min.js +2 -2
  5. package/dist/svg-path-simplify.js +3594 -1278
  6. package/dist/svg-path-simplify.min.js +2 -2
  7. package/dist/svg-path-simplify.pathdata.esm.js +1017 -538
  8. package/dist/svg-path-simplify.pathdata.esm.min.js +2 -2
  9. package/dist/svg-path-simplify.poly.cjs +9 -8
  10. package/docs/privacy-webapp.md +24 -0
  11. package/index.html +331 -152
  12. package/package.json +1 -1
  13. package/src/constants.js +4 -0
  14. package/src/css_parse.js +317 -0
  15. package/src/detect_input.js +76 -28
  16. package/src/index.js +8 -0
  17. package/src/pathData_simplify_cubic.js +26 -16
  18. package/src/pathData_simplify_harmonize_cpts.js +77 -1
  19. package/src/pathData_simplify_revertToquadratics.js +0 -1
  20. package/src/pathSimplify-main.js +304 -276
  21. package/src/pathSimplify-only-pathdata.js +7 -2
  22. package/src/pathSimplify-presets.js +254 -0
  23. package/src/poly-fit-curve-schneider.js +14 -7
  24. package/src/simplify_poly_RC.js +102 -0
  25. package/src/simplify_poly_RDP.js +109 -1
  26. package/src/simplify_poly_radial_distance.js +3 -3
  27. package/src/string_helpers.js +130 -4
  28. package/src/svg-getAttributes.js +4 -2
  29. package/src/svgii/convert_units.js +1 -1
  30. package/src/svgii/geometry.js +322 -5
  31. package/src/svgii/geometry_bbox_element.js +1 -1
  32. package/src/svgii/geometry_deduceRadius.js +116 -27
  33. package/src/svgii/geometry_length.js +253 -0
  34. package/src/svgii/pathData_analyze.js +18 -0
  35. package/src/svgii/pathData_convert.js +193 -89
  36. package/src/svgii/pathData_fix_directions.js +12 -14
  37. package/src/svgii/pathData_fromPoly.js +3 -3
  38. package/src/svgii/pathData_getLength.js +86 -0
  39. package/src/svgii/pathData_parse.js +2 -0
  40. package/src/svgii/pathData_parse_els.js +66 -68
  41. package/src/svgii/pathData_reorder.js +122 -16
  42. package/src/svgii/pathData_simplify_refineCorners.js +130 -35
  43. package/src/svgii/pathData_simplify_refine_round.js +420 -0
  44. package/src/svgii/pathData_split_to_groups.js +168 -0
  45. package/src/svgii/pathData_stringify.js +26 -64
  46. package/src/svgii/pathData_toPolygon.js +3 -4
  47. package/src/svgii/poly_analyze.js +61 -0
  48. package/src/svgii/poly_normalize.js +11 -2
  49. package/src/svgii/poly_to_pathdata.js +85 -24
  50. package/src/svgii/rounding.js +80 -78
  51. package/src/svgii/svg_cleanup.js +421 -619
  52. package/src/svgii/svg_cleanup_convertPathLength.js +39 -0
  53. package/src/svgii/svg_cleanup_general_svg_atts.js +97 -0
  54. package/src/svgii/svg_cleanup_normalize_transforms.js +83 -0
  55. package/src/svgii/svg_cleanup_remove_els_and_atts.js +77 -0
  56. package/src/svgii/svg_cleanup_ungroup.js +36 -0
  57. package/src/svgii/svg_el_parse_style_props.js +72 -47
  58. package/src/svgii/svg_getElementLength.js +67 -0
  59. package/src/svgii/svg_validate.js +220 -0
  60. package/tests/testSVG.js +14 -1
  61. package/src/svgii/pathData_refine_round.js +0 -222
@@ -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
  };
@@ -5,15 +5,19 @@
5
5
  * https://francoisromain.medium.com/smooth-a-svg-path-with-cubic-bezier-curves-e37b49d46c74
6
6
  */
7
7
 
8
- import { checkLineIntersection, getDistManhattan, interpolate, mirrorCpts } from "./geometry";
8
+ import { checkLineIntersection, getAngle, getDistance, getDistManhattan, getPathDataVertices, getPointOnEllipse, getSquareDistance, interpolate, mirrorCpts, reducePoints, rotatePoint } from "./geometry";
9
9
  import { getPolyBBox } from "./geometry_bbox";
10
10
  import { renderPath, renderPoint, renderPoly } from "./visualize";
11
11
  import { simplifyPolyRDP } from "../simplify_poly_RDP";
12
12
  import { pathDataFromPoly } from "./pathData_fromPoly";
13
13
  import { getPolyChunks } from "./poly_analyze_get_chunks";
14
- import { analyzePoly, isClosedPolygon } from "./poly_analyze";
14
+ import { analyzePoly, detectRegularPolygon, getPolyCentroid, getPolyCentroidWeighted, isClosedPolygon } from "./poly_analyze";
15
15
  import { fitCurveSchneider } from "../poly-fit-curve-schneider";
16
16
  import { simplifyPolyRD } from "../simplify_poly_radial_distance";
17
+ import { simplifyRC } from "../simplify_poly_RC";
18
+ import { getPolygonArea } from "./geometry_area";
19
+ import { pathDataToD } from "./pathData_stringify";
20
+ import { fixIntersectingCpts } from "../pathData_simplify_harmonize_cpts";
17
21
 
18
22
 
19
23
 
@@ -34,34 +38,89 @@ export function simplifyPolygonToPathData(pts, {
34
38
  } = {}) {
35
39
 
36
40
 
41
+ let polyPath = [];
42
+ let l = pts.length;
43
+ let M = pts[0]
44
+ let Z = pts[l - 1]
45
+
46
+
47
+ // triangle
48
+ if (pts.length === 3) {
49
+
50
+ let pM1 = interpolate(M, pts[1], 0.5)
51
+ let pM2 = interpolate(pts[1], Z, 0.5)
52
+ let pM3 = interpolate(Z, pts[0], 0.5)
53
+
54
+ /*
55
+ console.log('triangle');
56
+ renderPoint(markers, M)
57
+ renderPoint(markers, pM1)
58
+ renderPoint(markers, pM2)
59
+ renderPoint(markers, pM3)
60
+ */
61
+
62
+ if (closed) {
63
+ let t = 0.6666
64
+ let cp1_1 = interpolate(pM1, pts[1], t)
65
+ let cp2_1 = interpolate(pM2, pts[1], t)
66
+ let cp1_2 = interpolate(pM2, Z, t)
67
+ let cp2_2 = interpolate(pM3, Z, t)
68
+ let cp1_3 = interpolate(pM3, M, t)
69
+ let cp2_3 = interpolate(pM1, M, t)
70
+
71
+ polyPath = [
72
+ { type: 'M', values: [pM1.x, pM1.y] },
73
+ { type: 'C', values: [cp1_1.x, cp1_1.y, cp2_1.x, cp2_1.y, pM2.x, pM2.y] },
74
+ { type: 'C', values: [cp1_2.x, cp1_2.y, cp2_2.x, cp2_2.y, pM3.x, pM3.y] },
75
+ { type: 'C', values: [cp1_3.x, cp1_3.y, cp2_3.x, cp2_3.y, pM1.x, pM1.y] },
76
+ { type: 'Z', values: [] },
77
+ ]
37
78
 
38
- /*
39
- // denoise via RDP
40
- if (denoise && denoise !== 1) {
41
- pts = simplifyPolyRDP(pts, {
42
- width,
43
- height,
44
- quality: denoise,
45
- manhattan,
46
- absolute
47
- })
79
+ } else {
80
+ polyPath = [
81
+ //{ type: 'M', values: [pM1.x, pM1.y] },
82
+ { type: 'M', values: [M.x, M.y] },
83
+ { type: 'C', values: [pts[1].x, pts[1].y, pts[1].x, pts[1].y, Z.x, Z.y] },
84
+ ]
85
+ }
86
+ return polyPath;
48
87
  }
49
- */
50
88
 
51
89
 
52
- /*
53
- // simplify polygon
54
- if (simplifyRD != 1) {
55
- pts = simplifyPolyRD(pts, { quality: simplifyRD+'px' })
56
- }
90
+
91
+ // remove colinear
92
+ //pts = simplifyRC(pts)
93
+
94
+ /**
95
+ * detect regular polygon
96
+ * curved path is a circle
97
+ */
98
+ let centroid = getPolyCentroid(simplifyRC(pts))
99
+ let isRegularPolygon = detectRegularPolygon(pts, centroid)
57
100
 
58
101
 
59
- if (simplifyRDP != 1) {
60
- pts = simplifyPolyRDP(pts, { quality: simplifyRDP+'px' })
102
+ if (isRegularPolygon) {
103
+ //renderPoint(markers, centroid)
104
+ //let r = getDistance(centroid, pts[0])
105
+ let ptAd = rotatePoint(pts[0], centroid.x, centroid.y, Math.PI)
106
+ let sweep = getPolygonArea(pts) > 0 ? 1 : 0;
107
+
108
+ polyPath = [
109
+ { type: 'M', values: [pts[0].x, pts[0].y] },
110
+ { type: 'A', values: [1, 1, 0, 0, sweep, ptAd.x, ptAd.y] },
111
+ { type: 'A', values: [1, 1, 0, 0, sweep, pts[0].x, pts[0].y] }
112
+ ]
113
+
114
+ if (closed) {
115
+ polyPath.push({ type: 'Z', values: [] })
116
+ }
117
+ return polyPath;
61
118
  }
62
- */
63
119
 
64
120
 
121
+ // remove colinear
122
+ //pts = simplifyRC(pts)
123
+
65
124
  // get topology of poly
66
125
  let polyAnalyzed = !keepExtremes && !keepCorners ? pts : analyzePoly(pts, {
67
126
  debug: false
@@ -70,7 +129,6 @@ export function simplifyPolygonToPathData(pts, {
70
129
  })
71
130
 
72
131
  //console.log(polyAnalyzed, polyAnalyzed2);
73
- //return
74
132
 
75
133
  // split into segment chunks
76
134
  let chunks = !keepExtremes && !keepCorners ? [polyAnalyzed] : getPolyChunks(polyAnalyzed, { keepCorners, keepExtremes, keepInflections });
@@ -81,12 +139,15 @@ export function simplifyPolygonToPathData(pts, {
81
139
 
82
140
  //threshold = 2
83
141
 
84
- let polyPath = simplifyPolyChunks(chunks, {
142
+ polyPath = simplifyPolyChunks(chunks, {
85
143
  closed,
86
144
  tolerance: threshold,
87
- keepCorners
145
+ keepCorners,
146
+ keepExtremes: true,
88
147
  });
89
148
 
149
+ polyPath = fixIntersectingCpts(polyPath);
150
+
90
151
  return polyPath;
91
152
  }
92
153