Skip to content
Permalink
Browse files

More work on the GCode viewer

- confirmation dialog when trying to visualize large files (different threshold for mobile and "regular" devices, configurable of course, although only via config file right now) - should also help a bit with issues leading to #215
 - proper clearing of the viewer area when reconnecting to the backend (e.g. after server restart)

 Also all of this plus previous commits closes #35
  • Loading branch information...
foosel committed Jan 5, 2014
1 parent b9f49a8 commit ad556e7413c8f46f1b731c24ec4544d1b9d4298c
@@ -486,7 +486,7 @@ def mcSdStateChange(self, sdReady):
self._stateMonitor.setState({"state": self._state, "stateString": self.getStateString(), "flags": self._getStateFlags()})

def mcSdFiles(self, files):
eventManager().fire(Events.UPDATED_FILES, {"type": "gcode", "files": files})
eventManager().fire(Events.UPDATED_FILES, {"type": "gcode"})
self._sdFilelistAvailable.set()

def mcFileSelected(self, filename, filesize, sd):
@@ -51,7 +51,7 @@ def index():
"index.jinja2",
webcamStream=settings().get(["webcam", "stream"]),
enableTimelapse=(settings().get(["webcam", "snapshot"]) is not None and settings().get(["webcam", "ffmpeg"]) is not None),
enableGCodeVisualizer=settings().get(["feature", "gCodeVisualizer"]),
enableGCodeVisualizer=settings().get(["gcodeViewer", "enabled"]),
enableTemperatureGraph=settings().get(["feature", "temperatureGraph"]),
enableSystemMenu=settings().get(["system"]) is not None and settings().get(["system", "actions"]) is not None and len(settings().get(["system", "actions"])) > 0,
enableAccessControl=userManager is not None,
@@ -60,7 +60,9 @@ def index():
debug=debug,
gitBranch=branch,
gitCommit=commit,
stylesheet=settings().get(["devel", "stylesheet"])
stylesheet=settings().get(["devel", "stylesheet"]),
gcodeMobileThreshold=settings().get(["gcodeViewer", "mobileSizeThreshold"]),
gcodeThreshold=settings().get(["gcodeViewer", "sizeThreshold"])
)


@@ -54,7 +54,7 @@ def getSettings():
"flipV": s.getBoolean(["webcam", "flipV"])
},
"feature": {
"gcodeViewer": s.getBoolean(["feature", "gCodeVisualizer"]),
"gcodeViewer": s.getBoolean(["gcodeViewer", "enabled"]),
"temperatureGraph": s.getBoolean(["feature", "temperatureGraph"]),
"waitForStart": s.getBoolean(["feature", "waitForStartOnConnect"]),
"alwaysSendChecksum": s.getBoolean(["feature", "alwaysSendChecksum"]),
@@ -130,7 +130,7 @@ def setSettings():
if "flipV" in data["webcam"].keys(): s.setBoolean(["webcam", "flipV"], data["webcam"]["flipV"])

if "feature" in data.keys():
if "gcodeViewer" in data["feature"].keys(): s.setBoolean(["feature", "gCodeVisualizer"], data["feature"]["gcodeViewer"])
if "gcodeViewer" in data["feature"].keys(): s.setBoolean(["gcodeViewer", "enabled"], data["feature"]["gcodeViewer"])
if "temperatureGraph" in data["feature"].keys(): s.setBoolean(["feature", "temperatureGraph"], data["feature"]["temperatureGraph"])
if "waitForStart" in data["feature"].keys(): s.setBoolean(["feature", "waitForStartOnConnect"], data["feature"]["waitForStart"])
if "alwaysSendChecksum" in data["feature"].keys(): s.setBoolean(["feature", "alwaysSendChecksum"], data["feature"]["alwaysSendChecksum"])
@@ -55,8 +55,12 @@ def settings(init=False, configfile=None, basedir=None):
"options": {}
}
},
"gcodeViewer": {
"enabled": True,
"mobileSizeThreshold": 2 * 1024 * 1024, # 2MB
"sizeThreshold": 20 * 1024 * 1024, # 20MB
},
"feature": {
"gCodeVisualizer": True,
"temperatureGraph": True,
"waitForStartOnConnect": False,
"alwaysSendChecksum": False,
@@ -120,13 +120,12 @@ GCODE.gCodeReader = (function(){
// ***** PUBLIC *******
return {
clear: function() {
delete lines;
delete gcode;
model = [];
z_heights = [];
},

loadFile: function(reader){
model = [];
z_heights = [];
this.clear();

var totalSize = reader.target.result.length;
lines = reader.target.result.split(/\n/);
@@ -144,7 +143,6 @@ GCODE.gCodeReader = (function(){
}
}
);
this.clear();
},

setOption: function(options){
@@ -17,10 +17,10 @@ GCODE.renderer = (function(){

var layerNumStore, progressStore={from: 0, to: -1};
var lastX, lastY;
var dragStart,dragged;
var dragStart, dragged;
var scaleFactor = 1.1;
var model;
var initialized=false;
var initialized = false;
var renderOptions = {
colorGrid: "#bbbbbb",
bgColorGrid: "#ffffff",
@@ -55,7 +55,6 @@ GCODE.renderer = (function(){
var speeds = [];
var speedsByLayer = {};


var reRender = function(){
var p1 = ctx.transformedPoint(0,0);
var p2 = ctx.transformedPoint(canvas.width,canvas.height);
@@ -183,8 +182,11 @@ GCODE.renderer = (function(){
};

var drawGrid = function() {
console.log("Drawing grid");

ctx.translate(offsetBedX, offsetBedY);

ctx.beginPath();
var width = renderOptions["bed"]["x"] * zoomFactor;
var height = renderOptions["bed"]["y"] * zoomFactor;
var origin = {
@@ -220,6 +222,8 @@ GCODE.renderer = (function(){
};

var drawLayer = function(layerNum, fromProgress, toProgress, isNotCurrentLayer){
console.log("Drawing layer " + layerNum + " from " + fromProgress + " to " + toProgress + " (current: " + !isNotCurrentLayer + ")");

var i;

isNotCurrentLayer = typeof isNotCurrentLayer !== 'undefined' ? isNotCurrentLayer : false;
@@ -279,7 +283,7 @@ GCODE.renderer = (function(){
x = cmds[i].x;
}
if (typeof(cmds[i].y) === 'undefined' || isNaN(cmds[i].y)) {
y=prevY/zoomFactor;
y = prevY / zoomFactor;
} else {
y = -cmds[i].y;
}
@@ -329,30 +333,58 @@ GCODE.renderer = (function(){
ctx.stroke();
};

/*
var calculateBedOffset = function(bedDimensions) {
if (!bedDimensions) bedDimensions = renderOptions["bed"];
var max = Math.max(bedDimensions.x, bedDimensions.y);
return {
x: (max - bedDimensions.x) / 2 * zoomFactor,
y: (max - bedDimensions.y) / 2 * zoomFactor
};
var applyOffsets = function(mdlInfo) {
// determine bed and model offsets
if (ctx) ctx.translate(-offsetModelX, -offsetModelY);
if (renderOptions["centerViewport"] || renderOptions["zoomInOnModel"]) {
var canvasCenter = ctx.transformedPoint(canvas.width / 2, canvas.height / 2);
if (mdlInfo) {
offsetModelX = canvasCenter.x - (mdlInfo.min.x + mdlInfo.modelSize.x / 2) * zoomFactor;
offsetModelY = canvasCenter.y + (mdlInfo.min.y + mdlInfo.modelSize.y / 2) * zoomFactor;
} else {
offsetModelX = 0;
offsetModelY = 0;
}
offsetBedX = 0;
offsetBedY = 0;
} else if (mdlInfo && renderOptions["moveModel"]) {
offsetModelX = (renderOptions["bed"]["x"] / 2 - (mdlInfo.min.x + mdlInfo.modelSize.x / 2)) * zoomFactor;
offsetModelY = -1 * (renderOptions["bed"]["y"] / 2 - (mdlInfo.min.y + mdlInfo.modelSize.y / 2)) * zoomFactor;
offsetBedX = -1 * (renderOptions["bed"]["x"] / 2 - (mdlInfo.min.x + mdlInfo.modelSize.x / 2)) * zoomFactor;
offsetBedY = (renderOptions["bed"]["y"] / 2 - (mdlInfo.min.y + mdlInfo.modelSize.y / 2)) * zoomFactor;
} else {
offsetModelX = 0;
offsetModelY = 0;
offsetBedX = 0;
offsetBedY = 0;
}
if (ctx) ctx.translate(offsetModelX, offsetModelY);
};

var applyBedOffset = function(bedDimensions, onlyNew) {
if (true) return;
var bedOffset = calculateBedOffset(bedDimensions);
if (offsetBedX == bedOffset.x && offsetBedY == bedOffset.y) return;
ctx.translate(-offsetBedX, offsetBedY);
offsetBedX = bedOffset.x;
offsetBedY = bedOffset.y;
ctx.translate(bedOffset.x, -bedOffset.y);
}
*/

var applyZoom = function(mdlInfo) {
var pt = ctx.transformedPoint(canvas.width/2,canvas.height/2);
var transform = ctx.getTransform();
var scaleF;
if (scaleX && scaleY && transform.a && transform.d) {
ctx.translate(pt.x, pt.y);
ctx.scale(1 / scaleX, 1 / scaleY);
ctx.translate(-pt.x, -pt.y);
}
if (mdlInfo && renderOptions["zoomInOnModel"]) {
scaleF = mdlInfo.modelSize.x > mdlInfo.modelSize.y ? (canvas.width - 10) / mdlInfo.modelSize.x : (canvas.height - 10) / mdlInfo.modelSize.y;
scaleF /= zoomFactor;
if (transform.a && transform.d) {
scaleX = scaleF / transform.a;
scaleY = scaleF / transform.d;
ctx.translate(pt.x,pt.y);
ctx.scale(scaleX, scaleY);
ctx.translate(-pt.x, -pt.y);
}
} else {
scaleX = 1;
scaleY = 1;
}
};

// ***** PUBLIC *******
return {
@@ -366,22 +398,24 @@ GCODE.renderer = (function(){
offsetModelY = 0;
offsetBedX = 0;
offsetBedY = 0;

//applyBedOffset();
},
setOption: function(options){
var mustRefresh = false;
var dirty = false;
for (var opt in options) {
if (!options.hasOwnProperty(opt)) continue;
if (options[opt] === undefined) continue;
if (options.hasOwnProperty(opt)) renderOptions[opt] = options[opt];

dirty = dirty || (renderOptions[opt] != options[opt]);
renderOptions[opt] = options[opt];
if ($.inArray(opt, ["moveModel", "centerViewport", "zoomInOnModel", "bed"])) {
mustRefresh = true;
}
}

if (!dirty) return;
if(initialized) {
if (mustRefresh) {
//applyBedOffset();
this.refresh();
} else {
reRender();
@@ -401,7 +435,7 @@ GCODE.renderer = (function(){
var p2 = ctx.transformedPoint(canvas.width, canvas.height);
ctx.clearRect(p1.x, p1.y, p2.x - p1.x, p2.y - p1.y);
drawGrid();
if (model) {
if (model && model.length) {
if (layerNum < model.length) {
if (renderOptions['showNextLayer'] && layerNum < model.length - 1) {
drawLayer(layerNum + 1, 0, this.getLayerNumSegments(layerNum + 1), true);
@@ -426,68 +460,39 @@ GCODE.renderer = (function(){
}
},
clear: function() {
model = undefined;
initialized = false;
this.render();
offsetModelX = 0;
offsetModelY = 0;
offsetBedX = 0;
offsetBedY = 0;
scaleX = 1;
scaleY = 1;
speeds = [];
speedsByLayer = {};

this.doRender([], 0);
},
doRender: function(mdl, layerNum){
model = mdl;
if (!model || !model[layerNum]) return;

var mdlInfo;
var mdlInfo = undefined;
prevX = 0;
prevY = 0;
if (!initialized) this.init();

mdlInfo = GCODE.gCodeReader.getModelInfo();
speeds = mdlInfo.speeds;
speedsByLayer = mdlInfo.speedsByLayer;

// determine bed and model offsets
if (ctx) ctx.translate(-offsetModelX, -offsetModelY);
if (renderOptions["centerViewport"] || renderOptions["zoomInOnModel"]) {
var canvasCenter = ctx.transformedPoint(canvas.width / 2, canvas.height / 2);
offsetModelX = canvasCenter.x - (mdlInfo.min.x + mdlInfo.modelSize.x / 2) * zoomFactor;
offsetModelY = canvasCenter.y + (mdlInfo.min.y + mdlInfo.modelSize.y / 2) * zoomFactor;
offsetBedX = 0;
offsetBedY = 0;
} else if (renderOptions["moveModel"]) {
offsetModelX = (renderOptions["bed"]["x"] / 2 - (mdlInfo.min.x + mdlInfo.modelSize.x / 2)) * zoomFactor;
offsetModelY = -1 * (renderOptions["bed"]["y"] / 2 - (mdlInfo.min.y + mdlInfo.modelSize.y / 2)) * zoomFactor;
offsetBedX = -1 * (renderOptions["bed"]["x"] / 2 - (mdlInfo.min.x + mdlInfo.modelSize.x / 2)) * zoomFactor;
offsetBedY = (renderOptions["bed"]["y"] / 2 - (mdlInfo.min.y + mdlInfo.modelSize.y / 2)) * zoomFactor;
} else {
offsetModelX = 0;
offsetModelY = 0;
offsetBedX = 0;
offsetBedY = 0;
}
if (ctx) ctx.translate(offsetModelX, offsetModelY);

var pt = ctx.transformedPoint(canvas.width/2,canvas.height/2);
var transform = ctx.getTransform();
var scaleF;
if (scaleX && scaleY && transform.a && transform.d) {
ctx.translate(pt.x, pt.y);
ctx.scale(1 / scaleX, 1 / scaleY);
ctx.translate(-pt.x, -pt.y);
}
if (renderOptions["zoomInOnModel"]) {
scaleF = mdlInfo.modelSize.x > mdlInfo.modelSize.y ? (canvas.width - 10) / mdlInfo.modelSize.x : (canvas.height - 10) / mdlInfo.modelSize.y;
scaleF /= zoomFactor;
if (transform.a && transform.d) {
scaleX = scaleF / transform.a;
scaleY = scaleF / transform.d;
ctx.translate(pt.x,pt.y);
ctx.scale(scaleX, scaleY);
ctx.translate(-pt.x, -pt.y);
var toProgress = 1;
if (model) {
mdlInfo = GCODE.gCodeReader.getModelInfo();
speeds = mdlInfo.speeds;
speedsByLayer = mdlInfo.speedsByLayer;
if (model[layerNum]) {
toProgress = model[layerNum].length;
}
} else {
scaleX = 1;
scaleY = 1;
}

this.render(layerNum, 0, model[layerNum].length);
applyOffsets(mdlInfo);
applyZoom(mdlInfo);

this.render(layerNum, 0, toProgress);
},
refresh: function(layerNum) {
if (!layerNum) layerNum = layerNumStore;

0 comments on commit ad556e7

Please sign in to comment.
You can’t perform that action at this time.