2013-07-26 22:39:28 +02:00
|
|
|
var gcodeStart = [];
|
2013-08-12 21:54:30 +02:00
|
|
|
gcodeStart.push(";Generated with Doodle3D");
|
|
|
|
gcodeStart.push("G21"); // metric values
|
|
|
|
gcodeStart.push("G91"); // relative positioning
|
|
|
|
gcodeStart.push("M107"); // start with the fan off
|
|
|
|
gcodeStart.push("G28 X0 Y0"); // move X/Y to min endstops
|
|
|
|
gcodeStart.push("G28 Z0"); // move Z to min endstops
|
|
|
|
gcodeStart.push("G1 Z15 F9000"); // move the platform down 15mm
|
|
|
|
gcodeStart.push("G92 E0"); // zero the extruded length
|
|
|
|
gcodeStart.push("G1 F200 E10"); // extrude 10mm of feed stock
|
|
|
|
gcodeStart.push("G92 E0"); // zero the extruded length again
|
|
|
|
gcodeStart.push("G92 X-100 Y-100 E0"); // zero the extruded length again and make center the start position
|
|
|
|
gcodeStart.push("G1 F9000");
|
|
|
|
gcodeStart.push("G90"); // absolute positioning
|
|
|
|
gcodeStart.push("M117 Printing Doodle... "); // display message (20 characters to clear whole screen)
|
|
|
|
|
2013-07-26 22:39:28 +02:00
|
|
|
var gcodeEnd= [];
|
2013-08-12 21:54:30 +02:00
|
|
|
gcodeEnd.push("M107"); // fan off
|
|
|
|
gcodeEnd.push("G91"); // relative positioning
|
|
|
|
gcodeEnd.push("G1 E-1 F300"); // retract the filament a bit before lifting the nozzle, to release some of the pressure
|
|
|
|
gcodeEnd.push("G1 Z+0.5 E-5 X-20 Y-20 F9000"); // move Z up a bit and retract filament even more
|
|
|
|
gcodeEnd.push("G28 X0 Y0"); // move X/Y to min endstops, so the head is out of the way
|
|
|
|
gcodeEnd.push("M84"); // disable axes / steppers
|
|
|
|
gcodeEnd.push("G90"); // absolute positioning
|
|
|
|
gcodeEnd.push("M117 Done "); // display message (20 characters to clear whole screen)
|
2013-07-26 22:39:28 +02:00
|
|
|
|
2013-09-07 16:06:59 +02:00
|
|
|
|
2013-07-26 22:39:28 +02:00
|
|
|
var gcode = [];
|
|
|
|
function generate_gcode(callback) {
|
|
|
|
console.log("f:generategcode()");
|
|
|
|
|
2013-09-07 16:06:59 +02:00
|
|
|
var startGcode = [];
|
|
|
|
var endGcode = [];
|
|
|
|
|
|
|
|
// get gcode start statements
|
|
|
|
if ($("#startgcode").val().trim().length != 0) {
|
|
|
|
console.log(" found contents for start-gcode in settings.html")
|
|
|
|
startGcode = $("#startgcode").val().trim().split("\n");
|
|
|
|
} else {
|
|
|
|
console.log(" no start-gcode in settings.html, using defaults")
|
|
|
|
startGcode.concat(gcodeStart);
|
|
|
|
}
|
|
|
|
|
|
|
|
// get gcode end statements
|
|
|
|
if ($("#endgcode").val().trim().length != 0) {
|
|
|
|
console.log(" found contents for end-gcode in settings.html")
|
|
|
|
endGcode = $("#endgcode").val().trim().split("\n");
|
|
|
|
} else {
|
|
|
|
console.log(" no end-gcode in settings.html, using defaults")
|
|
|
|
endGcode.concat(gcodeEnd);
|
|
|
|
}
|
|
|
|
|
2013-07-26 22:39:28 +02:00
|
|
|
gcode = [];
|
|
|
|
|
2013-09-07 16:06:59 +02:00
|
|
|
console.log("settings: ",settings);
|
|
|
|
var speed = settings["printer.speed"]
|
|
|
|
var normalSpeed = speed;
|
|
|
|
var bottomSpeed = speed*0.5;
|
|
|
|
var travelSpeed = settings["printer.travelSpeed"]
|
|
|
|
var filamentThickness = settings["printer.filamentThickness"];
|
|
|
|
var wallThickness = settings["printer.wallThickness"];
|
2013-09-17 15:14:59 +02:00
|
|
|
var screenToMillimeterScale = settings["printer.screenToMillimeterScale"];
|
2013-09-07 16:06:59 +02:00
|
|
|
var layerHeight = settings["printer.layerHeight"];
|
2013-09-17 15:14:59 +02:00
|
|
|
var maxObjectHeight = settings["printer.maxObjectHeight"];
|
2013-09-07 16:06:59 +02:00
|
|
|
var temperature = settings["printer.temperature"];
|
|
|
|
var useSubLayers = settings["printer.useSubLayers"];
|
2013-09-17 15:14:59 +02:00
|
|
|
var enableTraveling = settings["printer.enableTraveling"];
|
|
|
|
var retractionEnabled = settings["printer.retraction.enabled"];
|
2013-09-07 16:06:59 +02:00
|
|
|
var retractionspeed = settings["printer.retraction.speed"];
|
|
|
|
var retractionminDistance = settings["printer.retraction.minDistance"];
|
|
|
|
var retractionamount = settings["printer.retraction.amount"];
|
|
|
|
|
|
|
|
/*
|
|
|
|
console.log("f:generate_gcode >> EFFE CHECKEN:");
|
|
|
|
console.log(" speed: " + speed);
|
|
|
|
console.log(" travelSpeed: " + travelSpeed);
|
|
|
|
console.log(" filamentThickness: " + filamentThickness);
|
|
|
|
console.log(" wallThickness: " + wallThickness);
|
|
|
|
console.log(" screenToMillimeterScale: " + screenToMillimeterScale);
|
|
|
|
console.log(" layerHeight: " + layerHeight);
|
|
|
|
console.log(" objectHeight: " + objectHeight);
|
|
|
|
console.log(" maxObjectHeight: " + maxObjectHeight);
|
|
|
|
console.log(" temperature: " + temperature);
|
|
|
|
console.log(" maxObjectHeight: " + maxObjectHeight);
|
|
|
|
console.log(" useSubLayers: " + useSubLayers);
|
|
|
|
console.log(" enableTraveling: " + enableTraveling);
|
|
|
|
console.log(" retractionspeed: " + retractionspeed);
|
|
|
|
console.log(" retractionminDistance: " + retractionminDistance);
|
|
|
|
console.log(" retractionamount: " + retractionamount);
|
|
|
|
console.log("");
|
|
|
|
//*/
|
|
|
|
|
2013-09-18 16:59:48 +02:00
|
|
|
// max amount of real world layers
|
|
|
|
var layers = maxObjectHeight / layerHeight; //maxObjectHeight instead of objectHeight
|
|
|
|
|
|
|
|
// translate numLayers in preview to objectHeight in real world
|
|
|
|
//objectHeight = Math.ceil(numLayers / 5); // in settings objectHeight = 20, in previewRendering_v01.js numLayers is 100, hence the / 5
|
|
|
|
//objectHeight = numLayers; // in settings objectHeight = 20, in previewRendering_v01.js numLayers is 100, hence the / 5
|
|
|
|
objectHeight = Math.round(numLayers/maxNumLayers*maxObjectHeight);
|
|
|
|
|
|
|
|
// translate preview rotation (per layer) to real world rotation
|
|
|
|
var rStepGCode = rStep * maxNumLayers/layers; ///maxNumLayers*maxObjectHeight;
|
|
|
|
// correct direction
|
|
|
|
rStepGCode = -rStepGCode;
|
|
|
|
|
2013-07-26 22:39:28 +02:00
|
|
|
// todo hier een array van PATHS maken wat de losse paths zijn
|
|
|
|
|
|
|
|
// copy array without reference -> http://stackoverflow.com/questions/9885821/copying-of-an-array-of-objects-to-another-array-without-object-reference-in-java
|
|
|
|
var points = JSON.parse(JSON.stringify(_points));
|
|
|
|
console.log("f:generategcode() >> points.length: " + points.length);
|
|
|
|
|
|
|
|
// console.log("f:generategcode() >> paths: " + paths.toString());
|
|
|
|
// console.log("paths.toString(): " + paths.toString());
|
|
|
|
// return;
|
|
|
|
|
2013-08-12 21:54:30 +02:00
|
|
|
console.log("printer temperature: ",temperature);
|
|
|
|
gcode.push("M109 S" + temperature); // set target temperature and wait for the extruder to reach it
|
2013-07-26 22:39:28 +02:00
|
|
|
// add gcode begin commands
|
2013-09-07 16:06:59 +02:00
|
|
|
gcode = gcode.concat(startGcode);
|
2013-08-12 21:54:30 +02:00
|
|
|
|
|
|
|
//gcode.push("M109 S" + temperature); // set target temperature and wait for the extruder to reach it
|
2013-07-26 22:39:28 +02:00
|
|
|
|
2013-08-12 21:54:30 +02:00
|
|
|
var layers = maxObjectHeight / layerHeight; //maxObjectHeight instead of objectHeight
|
2013-07-26 22:39:28 +02:00
|
|
|
var extruder = 0.0;
|
|
|
|
var prev = new Point(); prev.set(0, 0);
|
|
|
|
|
2013-07-30 14:21:04 +02:00
|
|
|
// replacement (and improvement) for ofxGetCenterofMass
|
2013-07-26 22:39:28 +02:00
|
|
|
var centerOfDoodle = {
|
|
|
|
x: doodleBounds[0] + (doodleBounds[2]- doodleBounds[0])/2,
|
|
|
|
y: doodleBounds[1] + (doodleBounds[3] - doodleBounds[1])/2
|
|
|
|
// x: doodleBounds[0],
|
|
|
|
// y: doodleBounds[1]
|
|
|
|
}
|
2013-09-07 16:06:59 +02:00
|
|
|
|
2013-07-26 22:39:28 +02:00
|
|
|
console.log("f:generategcode() >> layers: " + layers);
|
2013-09-07 16:06:59 +02:00
|
|
|
if (layers == Infinity) return;
|
|
|
|
|
2013-07-26 22:39:28 +02:00
|
|
|
for (var layer = 0; layer < layers; layer++) {
|
|
|
|
|
|
|
|
var p = JSON.parse(JSON.stringify(points)); // [].concat(points);
|
|
|
|
|
|
|
|
if (p.length < 2) return;
|
|
|
|
var even = (layer % 2 == 0);
|
|
|
|
var progress = layer / layers;
|
|
|
|
|
|
|
|
// float layerScale = scaleFunction(float(layer)/layers); // scaleFactor van de layer -> lookup naar vfunc[] voor die scaleVals
|
|
|
|
var layerScale = 1.0;
|
|
|
|
|
|
|
|
// if begin point this row and end point last row are close enough, isLoop is true
|
|
|
|
var isLoop = lineLength(points[0][0], points[0][1], points[points.length-1][0], points[points.length-1][1]) < 3;
|
|
|
|
|
|
|
|
// set center of doodle as middle (ie subtract to that)
|
|
|
|
pointsTranslate(p, -centerOfDoodle.x, -centerOfDoodle.y);
|
|
|
|
pointsScale(p, screenToMillimeterScale,-screenToMillimeterScale);
|
|
|
|
pointsScale(p, layerScale, layerScale);
|
|
|
|
|
|
|
|
// sort-of in de buurt van (360/2.5)
|
|
|
|
// // -> aight.. er zijn 750 lines vs 1000 in de d3d app. 135 = .75 * 180... dit kan je nog rechttrekken als je NET wat slimmer nadenkt :)
|
2013-09-18 17:01:45 +02:00
|
|
|
// update: NEE, het is niet .75 * 180 want 135 was niet de beste value.
|
2013-09-18 16:59:48 +02:00
|
|
|
//pointsRotate(p, rStep * progress * 139);
|
|
|
|
pointsRotate(p, rStepGCode * layer);
|
2013-07-26 22:39:28 +02:00
|
|
|
|
|
|
|
if (layer == 0) {
|
2013-08-12 21:54:30 +02:00
|
|
|
//gcode.push("M107"); //fan off
|
|
|
|
if (firstLayerSlow) {
|
|
|
|
//gcode.push("M220 S20"); //slow speed
|
|
|
|
speed = bottomSpeed;
|
2013-08-14 20:54:48 +02:00
|
|
|
//console.log("> speed: ",speed);
|
2013-08-12 21:54:30 +02:00
|
|
|
}
|
2013-07-30 14:21:04 +02:00
|
|
|
} else if (layer == 2) { ////////LET OP, pas bij layer 2 weer op normale snelheid ipv layer 1
|
2013-07-26 22:39:28 +02:00
|
|
|
gcode.push("M106"); //fan on
|
2013-08-12 21:54:30 +02:00
|
|
|
//gcode.push("M220 S100"); //normal speed
|
|
|
|
speed = normalSpeed;
|
2013-08-14 20:54:48 +02:00
|
|
|
//console.log("> speed: ",speed);
|
2013-07-26 22:39:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
var curLayerCommand = 0;
|
|
|
|
var totalLayerCommands = p.length;
|
2013-07-30 14:21:04 +02:00
|
|
|
var layerProgress = 0;
|
2013-07-26 22:39:28 +02:00
|
|
|
|
|
|
|
var paths = [];
|
|
|
|
var pathCounter = -1;
|
|
|
|
// var points = [];
|
|
|
|
|
|
|
|
for (var i = 0; i < p.length; i++) {
|
|
|
|
if (p[i][2] == true) {
|
|
|
|
pathCounter++;
|
|
|
|
paths.push([]);
|
|
|
|
paths[pathCounter].push([p[i][0], p[i][1]]);
|
|
|
|
} else {
|
|
|
|
paths[pathCounter].push([p[i][0], p[i][1]]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// console.log("f:generategcode() >> paths.length: " + paths.length);
|
2013-08-12 21:54:30 +02:00
|
|
|
|
2013-07-26 22:39:28 +02:00
|
|
|
// loop over the subpaths (the separately drawn lines)
|
2013-07-30 14:21:04 +02:00
|
|
|
for (var j = 0; j < paths.length; j++) { // TODO paths > subpaths
|
2013-07-26 22:39:28 +02:00
|
|
|
// this line is probably for drawing efficiency, alternating going from 0->end and end->0 (i.e. to and fro)
|
|
|
|
// vector<ofSubPath::Command> &commands = subpaths[even ? j : subpaths.size()-1-j].getCommands();
|
2013-07-30 14:21:04 +02:00
|
|
|
var commands = paths[j]; //commands zijn alle points uit subpath j // TODO commands > subpathPoints
|
2013-07-26 22:39:28 +02:00
|
|
|
|
|
|
|
// loop over the coordinates of the subpath
|
|
|
|
for (var i = 0; i < commands.length; i++) {
|
|
|
|
var last = commands.length - 1;
|
|
|
|
|
|
|
|
// this line is probably for drawing efficiency, alternating going from 0->end and end->0 (i.e. to and fro)
|
|
|
|
// ofPoint to = commands[(even || isLoop || loopAlways) ? i : last-i].to;
|
|
|
|
var to = new Point(); to.set(commands[i][0], commands[i][1]);
|
|
|
|
var sublayer = (layer == 0) ? 0.0 : layer + (useSubLayers ? (curLayerCommand/totalLayerCommands) : 0);
|
2013-09-07 16:06:59 +02:00
|
|
|
var z = (sublayer + 1) * layerHeight; // 2013-09-06 removed zOffset (seemed to be useless)
|
2013-07-26 22:39:28 +02:00
|
|
|
|
|
|
|
var isTraveling = !isLoop && i==0;
|
2013-09-17 15:14:59 +02:00
|
|
|
var doRetract = retractionEnabled && prev.distance(to) > retractionminDistance;
|
2013-07-26 22:39:28 +02:00
|
|
|
|
|
|
|
if (enableTraveling && isTraveling) {
|
|
|
|
// console.log("enableTraveling && isTraveling >> doRetract: " + doRetract + ", retractionspeed: " + retractionspeed);
|
2013-08-12 21:54:30 +02:00
|
|
|
if (doRetract) gcode.push("G0 E" + (extruder - retractionamount).toFixed(3) + " F" + (retractionspeed * 60).toFixed(3)); //retract
|
2013-09-07 16:06:59 +02:00
|
|
|
gcode.push("G0 X" + to.x.toFixed(3) + " Y" + to.y.toFixed(3) + " Z" + z.toFixed(3) + " F" + (travelSpeed * 60).toFixed(3));
|
2013-08-12 21:54:30 +02:00
|
|
|
if (doRetract) gcode.push("G0 E" + extruder.toFixed(3) + " F" + (retractionspeed * 60).toFixed(3)); // return to normal
|
2013-07-26 22:39:28 +02:00
|
|
|
} else {
|
|
|
|
// console.log(" else");
|
2013-08-12 21:54:30 +02:00
|
|
|
extruder += prev.distance(to) * wallThickness * layerHeight / filamentThickness;
|
2013-07-26 22:39:28 +02:00
|
|
|
gcode.push("G1 X" + to.x.toFixed(3) + " Y" + to.y.toFixed(3) + " Z" + z.toFixed(3) + " F" + (speed * 60).toFixed(3) + " E" + extruder.toFixed(3));
|
|
|
|
}
|
|
|
|
|
|
|
|
curLayerCommand++;
|
2013-07-30 14:21:04 +02:00
|
|
|
layerProgress = curLayerCommand/totalLayerCommands;
|
2013-07-26 22:39:28 +02:00
|
|
|
prev = to;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((layer/layers) > (objectHeight/maxObjectHeight)) {
|
2013-09-07 16:06:59 +02:00
|
|
|
console.log("f:generategcode() >> (layer/layers) > (objectHeight/maxObjectHeight) is true -> breaking at layer " + (layer + 1));
|
2013-07-26 22:39:28 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// add gcode end commands
|
2013-09-07 16:06:59 +02:00
|
|
|
gcode = gcode.concat(endGcode);
|
2013-07-26 22:39:28 +02:00
|
|
|
|
|
|
|
// debug
|
|
|
|
// var _gc = gc.join("\n");
|
|
|
|
// console.log("f:generategcode() >> _gc = " + _gc);
|
|
|
|
|
|
|
|
// Return the gcode array, joined to one string with '\n' (line break) as the join parameter
|
|
|
|
// This should result in a nice long string with line breaks
|
|
|
|
if (callback == undefined) {
|
2013-07-29 16:48:13 +02:00
|
|
|
return gcode;
|
2013-07-26 22:39:28 +02:00
|
|
|
} else {
|
|
|
|
// post
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pointsTranslate = function(p, x, y) {
|
|
|
|
for (var i = 0; i < p.length; i++) {
|
|
|
|
p[i][0] += x;
|
|
|
|
p[i][1] += y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pointsScale = function(p, sx, sy) {
|
|
|
|
for (var i = 0; i < p.length; i++) {
|
|
|
|
p[i][0] *= sx;
|
|
|
|
p[i][1] *= sy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// rotates around point 0,0 (origin).
|
|
|
|
// Not the prettiest kind of rotation solution but in our case we're assuming that the points have just been translated to origin
|
|
|
|
pointsRotate = function(p, ang) {
|
|
|
|
var _ang, dist;
|
|
|
|
for (var i = 0; i < p.length; i++) {
|
|
|
|
dist = Math.sqrt(p[i][0] * p[i][0] + p[i][1] * p[i][1]);
|
|
|
|
_ang = Math.atan2(p[i][1], p[i][0]);
|
|
|
|
p[i][0] = Math.cos(_ang + ang) * dist;
|
|
|
|
p[i][1] = Math.sin(_ang + ang) * dist;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//+ Jonas Raoni Soares Silva
|
|
|
|
//@ http://jsfromhell.com/math/line-length [rev. #1]
|
|
|
|
lineLength = function(x, y, x0, y0){
|
|
|
|
return Math.sqrt((x -= x0) * x + (y -= y0) * y);
|
|
|
|
};
|
|
|
|
|
|
|
|
var Point = function() {};
|
|
|
|
Point.prototype = {
|
|
|
|
x: 0,
|
|
|
|
y: 0,
|
|
|
|
set: function(_x, _y) {
|
|
|
|
this.x = _x;
|
|
|
|
this.y = _y;
|
|
|
|
},
|
|
|
|
distance: function(p) {
|
|
|
|
var d = -1;
|
|
|
|
if (p instanceof Point) {
|
|
|
|
d = Math.sqrt((p.x - this.x) * (p.x - this.x) + (p.y - this.y) * (p.y - this.y));
|
|
|
|
}
|
|
|
|
return d;
|
|
|
|
},
|
|
|
|
toString: function() {
|
|
|
|
console.log("x:" + this.x + ", y:" + this.y);
|
|
|
|
}
|
|
|
|
}
|