diff --git a/interface/bezier.js b/interface/bezier.js
new file mode 100644
index 0000000..c1f5282
--- /dev/null
+++ b/interface/bezier.js
@@ -0,0 +1,75 @@
+// bezier to line conversion script
+// taken from https://github.com/evomotors/BezierCurvesJS
+// written by evomotors (see https://github.com/M4GNV5/EggEsp/issues/1#issuecomment-488673199)
+
+var FactorialLookup = [1.0, 1.0, 2.0, 6.0, 24.0, 120.0, 720.0, 5040.0, 40320.0, 362880.0,
+ 3628800.0, 39916800.0, 479001600.0, 6227020800.0, 87178291200.0,
+ 1307674368000.0, 20922789888000.0, 355687428096000.0, 6402373705728000.0,
+ 121645100408832000.0, 2432902008176640000.0, 51090942171709440000.0,
+ 1124000727777607680000.0, 25852016738884976640000.0, 620448401733239439360000.0,
+ 15511210043330985984000000.0, 403291461126605635584000000.0, 10888869450418352160768000000.0,
+ 304888344611713860501504000000.0, 8841761993739701954543616000000.0, 265252859812191058636308480000000.0,
+ 8222838654177922817725562880000000.0, 263130836933693530167218012160000000.0]
+
+// Calculate points on curve
+function GetBezierPoints(b, cpts)
+{
+ var npts = (b.length) / 2;
+ var p = [];
+
+ var icount = 0;
+ var t = 0;
+ var step = 1.0 / (cpts - 1);
+
+ for (var i1 = 0; i1 != cpts; i1++)
+ {
+ if ((1.0 - t) < 5e-6)
+ t = 1.0;
+
+ var jcount = 0;
+ p[icount] = 0.0;
+ p[icount + 1] = 0.0;
+ for (var i = 0; i != npts; i++)
+ {
+ var basis = Bernstein(npts - 1, i, t);
+ p[icount] += basis * b[jcount];
+ p[icount + 1] += basis * b[jcount + 1];
+ jcount = jcount + 2;
+ }
+
+ if(isNaN(p[icount]) || isNaN(p[icount + 1]))
+ debugger;
+
+ icount += 2;
+ t += step;
+ }
+
+ return p;
+}
+
+// Calculates Bernstein basis
+function Bernstein(n, i, t)
+{
+ var ti;
+ var tni;
+
+ if (t == 0.0 && i == 0)
+ ti = 1.0;
+ else
+ ti = Math.pow(t, i);
+
+ if (n == i && t == 1.0)
+ tni = 1.0;
+ else
+ tni = Math.pow((1 - t), (n - i));
+
+ return (Factorial(n) / (Factorial(i) * Factorial(n - i))) * ti * tni;
+}
+
+function Factorial(n)
+{
+ if(n >= FactorialLookup.length)
+ return Number.MAX_SAFE_INTEGER;
+ else
+ return FactorialLookup[n];
+}
\ No newline at end of file
diff --git a/interface/index.html b/interface/index.html
index 7c7c76f..ca59d04 100644
--- a/interface/index.html
+++ b/interface/index.html
@@ -12,8 +12,9 @@
-
+
+
diff --git a/interface/svg2gcode.js b/interface/svg2gcode.js
index a0a8912..3682222 100644
--- a/interface/svg2gcode.js
+++ b/interface/svg2gcode.js
@@ -70,51 +70,8 @@ function path2gcode(transform, path)
let y = 0;
let wasRelative = false;
- while(split.length > 0)
+ function addOp(op)
{
- let curr = split.shift();
- let op;
- if(xyOps.hasOwnProperty(curr))
- {
- op = {
- op: xyOps[curr],
- x: parseFloat(split.shift()),
- y: parseFloat(split.shift())
- };
- }
- else if(xy0Ops.hasOwnProperty(curr))
- {
- let xy0Op = xy0Ops[curr];
- op = {op: xy0Op.op};
- op[xy0Op.value] = parseFloat(split.shift());
-
- if(isRelative(op.op))
- op[xy0Op.unchanged] = 0;
- else
- op[xy0Op.unchanged] = xy0Op.unchanged == "x" ? x : y;
- }
- else if(curr == "z" || curr == "Z")
- {
- op = {
- op: OP_LINE,
- x: startX,
- y: startY
- };
- }
- //TODO other ops (see https://svgwg.org/specs/paths/#PathElement)
- else if(!isNaN(curr)) //assume L/l by default
- {
- op = {
- op: wasRelative ? OP_LINE_REL : OP_LINE,
- x: parseFloat(curr),
- y: parseFloat(split.shift())
- };
- }
- else
- {
- throw "Invalid/Unsupported svg path character " + curr;
- }
-
wasRelative = isRelative(op.op);
if(ret.length == 0 && wasRelative)
@@ -146,10 +103,88 @@ function path2gcode(transform, path)
applyTransformation(transform, op);
if(isNaN(op.x) || isNaN(op.y))
- throw "Oops, something went wrong!";
+ throw new Error("Oops, something went wrong!");
ret.push(op);
}
+ while(split.length > 0)
+ {
+ let curr = split.shift();
+ if(xyOps.hasOwnProperty(curr))
+ {
+ addOp({
+ op: xyOps[curr],
+ x: parseFloat(split.shift()),
+ y: parseFloat(split.shift())
+ });
+ }
+ else if(xy0Ops.hasOwnProperty(curr))
+ {
+ let xy0Op = xy0Ops[curr];
+ while(!isNaN(split[0]))
+ {
+ let op = {op: xy0Op.op};
+ op[xy0Op.value] = parseFloat(split.shift());
+
+ if(isRelative(op.op))
+ op[xy0Op.unchanged] = 0;
+ else
+ op[xy0Op.unchanged] = xy0Op.unchanged == "x" ? x : y;
+
+ addOp(op);
+ }
+ }
+ else if(curr == "z" || curr == "Z")
+ {
+ addOp({
+ op: OP_LINE,
+ x: startX,
+ y: startY
+ });
+ }
+ else if(curr == "c" || curr == "C")
+ {
+ let points;
+ var endIndex = split.findIndex(x => isNaN(x));
+ if(endIndex == -1)
+ {
+ points = split;
+ split = [];
+ }
+ else
+ {
+ points = split.splice(0, endIndex);
+ }
+
+ points = points.map(x => parseFloat(x));
+
+ //TODO what is a good value for the second argument? Should we let the user define this?
+ points = GetBezierPoints(points, 20);
+
+ for(var i = 0; i < points.length; i += 2)
+ {
+ addOp({
+ op: OP_LINE,
+ x: points[i],
+ y: points[i + 1]
+ });
+ }
+ }
+ //TODO other ops (see https://svgwg.org/specs/paths/#PathElement)
+ else if(!isNaN(curr)) //assume L/l by default
+ {
+ addOp({
+ op: wasRelative ? OP_LINE_REL : OP_LINE,
+ x: parseFloat(curr),
+ y: parseFloat(split.shift())
+ });
+ }
+ else
+ {
+ throw "Invalid/Unsupported svg path character " + curr;
+ }
+ }
+
return ret;
}