(cmds, options, font)
| 1114 | }; |
| 1115 | |
| 1116 | function pathToPoints(cmds, options, font) { |
| 1117 | |
| 1118 | const parseOpts = (options, defaults) => { |
| 1119 | if (typeof options !== 'object') { |
| 1120 | options = defaults; |
| 1121 | } else { |
| 1122 | for (const key in defaults) { |
| 1123 | if (typeof options[key] === 'undefined') { |
| 1124 | options[key] = defaults[key]; |
| 1125 | } |
| 1126 | } |
| 1127 | } |
| 1128 | return options; |
| 1129 | }; |
| 1130 | |
| 1131 | const at = (v, i) => { |
| 1132 | const s = v.length; |
| 1133 | return v[i < 0 ? i % s + s : i % s]; |
| 1134 | }; |
| 1135 | |
| 1136 | const simplify = (pts, angle) => { |
| 1137 | angle = angle || 0; |
| 1138 | let num = 0; |
| 1139 | for (let i = pts.length - 1; pts.length > 3 && i >= 0; --i) { |
| 1140 | if (collinear(at(pts, i - 1), at(pts, i), at(pts, i + 1), angle)) { |
| 1141 | pts.splice(i % pts.length, 1); // Remove middle point |
| 1142 | num++; |
| 1143 | } |
| 1144 | } |
| 1145 | return num; |
| 1146 | }; |
| 1147 | |
| 1148 | const collinear = (a, b, c, thresholdAngle) => { |
| 1149 | if (!thresholdAngle) { |
| 1150 | return areaTriangle(a, b, c) === 0; |
| 1151 | } |
| 1152 | |
| 1153 | if (typeof collinear.tmpPoint1 === 'undefined') { |
| 1154 | collinear.tmpPoint1 = []; |
| 1155 | collinear.tmpPoint2 = []; |
| 1156 | } |
| 1157 | |
| 1158 | const ab = collinear.tmpPoint1, |
| 1159 | bc = collinear.tmpPoint2; |
| 1160 | ab.x = b.x - a.x; |
| 1161 | ab.y = b.y - a.y; |
| 1162 | bc.x = c.x - b.x; |
| 1163 | bc.y = c.y - b.y; |
| 1164 | |
| 1165 | const dot = ab.x * bc.x + ab.y * bc.y, |
| 1166 | magA = Math.sqrt(ab.x * ab.x + ab.y * ab.y), |
| 1167 | magB = Math.sqrt(bc.x * bc.x + bc.y * bc.y), |
| 1168 | angle = Math.acos(dot / (magA * magB)); |
| 1169 | |
| 1170 | return angle < thresholdAngle; |
| 1171 | }; |
| 1172 | |
| 1173 | const areaTriangle = (a, b, c) => { |
no test coverage detected