Ignore coordinates outside bed for zoom/centering in gcode viewer

They might be nozzle priming routines which are not actually part of
the model proper and hence it doesn't make sense trying to keep them
visible when zooming in on the model, or allowing them to offset the
model center.
This commit is contained in:
Gina Häußge 2017-06-13 15:59:30 +02:00
parent 77db00a2ea
commit cbd94a9020
5 changed files with 196 additions and 57 deletions

View file

@ -14,7 +14,10 @@ var z_heights = {};
var model = [];
var max = {x: undefined, y: undefined, z: undefined};
var min = {x: undefined, y: undefined, z: undefined};
var boundingBox = {minX: undefined, maxX: undefined, minY: undefined, maxY: undefined, minZ: undefined, maxZ: undefined};
var modelSize = {x: undefined, y: undefined, z: undefined};
var bed = {x: undefined, y: undefined, r: undefined, circular: false, centeredOrigin: false};
var ignoreOutsideBed = false;
var filamentByLayer = {};
var totalFilament = [0];
var printTime = 0;
@ -76,6 +79,7 @@ var sendAnalyzeDone = function () {
max: max,
min: min,
modelSize: modelSize,
boundingBox: boundingBox,
totalFilament: totalFilament,
filamentByLayer: filamentByLayer,
printTime: printTime,
@ -106,6 +110,36 @@ var purgeLayers = function () {
}
};
var bedBounds = function() {
if (!bed) {
return {xMin: 0, xMax: 0, yMin: 0, yMax: 0};
}
var result;
if (bed.circular) {
result = {xMin: -bed.r, xMax: bed.r, yMin: -bed.r, yMax: bed.r};
} else if (bed.centeredOrigin) {
result = {xMin: -bed.x/2.0, xMax: bed.x/2.0, yMin: -bed.y/2.0, yMax: bed.y/2.0};
} else {
result = {xMin: 0, xMax: bed.x, yMin: 0, yMax: bed.y};
}
return result;
};
var withinBedBounds = function(x, y, bedBounds) {
if (!ignoreOutsideBed) return true;
var result = true;
if (x !== undefined && !isNaN(x)) {
result = result && (x >= bedBounds.xMin && x <= bedBounds.xMax);
}
if (y !== undefined && !isNaN(y)) {
result = result && (y >= bedBounds.yMin && y <= bedBounds.yMax);
}
return result;
};
var analyzeModel = function () {
var tmp1 = 0, tmp2 = 0;
@ -113,6 +147,8 @@ var analyzeModel = function () {
var type;
var printTimeAdd = 0;
var bounds = bedBounds();
for (var i = 0; i < model.length; i++) {
var cmds = model[i];
if (!cmds) continue;
@ -120,41 +156,56 @@ var analyzeModel = function () {
for (var j = 0; j < cmds.length; j++) {
var tool = cmds[j].tool;
var x_ok = false;
var y_ok = false;
var retract = cmds[j].retract && cmds[j].retract > 0;
var extrude = cmds[j].extrude && cmds[j].extrude > 0 && !retract;
var move = cmds[j].x !== undefined || cmds[j].y !== undefined || cmds[j].z !== undefined;
var prevInBounds = withinBedBounds(cmds[j].prevX, cmds[j].prevY, bounds);
var inBounds = withinBedBounds(cmds[j].x === undefined ? cmds[j].prevX : cmds[j].x,
cmds[j].y === undefined ? cmds[j].prevY : cmds[j].y,
bounds);
var recordX = function(x, inBounds) {
if (x === undefined || isNaN(x)) return;
if (typeof(cmds[j].x) !== 'undefined'
&& typeof(cmds[j].prevX) !== 'undefined'
&& typeof(cmds[j].extrude) !== 'undefined'
&& cmds[j].extrude
&& !isNaN(cmds[j].x)) {
var x = cmds[j].x;
max.x = max.x !== undefined ? Math.max(max.x, x) : x;
min.x = min.x !== undefined ? Math.min(min.x, x) : x;
x_ok = true;
}
if (inBounds) {
boundingBox.minX = boundingBox.minX !== undefined ? Math.min(boundingBox.minX, x): x;
boundingBox.maxX = boundingBox.maxX !== undefined ? Math.max(boundingBox.maxX, x): x;
}
};
if (typeof(cmds[j].y) !== 'undefined'
&& typeof(cmds[j].prevY) !== 'undefined'
&& typeof(cmds[j].extrude) !== 'undefined'
&& cmds[j].extrude
&& !isNaN(cmds[j].y)) {
var y = cmds[j].y;
var recordY = function(y, inBounds) {
if (y === undefined || isNaN(y)) return;
max.y = max.y !== undefined ? Math.max(max.y, y) : y;
min.y = min.y !== undefined ? Math.min(min.y, y) : y;
y_ok = true;
}
if (inBounds) {
boundingBox.minY = boundingBox.minY !== undefined ? Math.min(boundingBox.minY, y): y;
boundingBox.maxY = boundingBox.maxY !== undefined ? Math.max(boundingBox.maxY, y): y;
}
};
var recordZ = function(z) {
if (z === undefined || isNaN(z)) return;
if (typeof(cmds[j].prevZ) !== 'undefined'
&& typeof(cmds[j].extrude) !== 'undefined'
&& cmds[j].extrude
&& !isNaN(cmds[j].prevZ)) {
var z = cmds[j].prevZ;
max.z = max.z !== undefined ? Math.max(max.z, z) : z;
min.z = min.z !== undefined ? Math.min(min.z, z) : z;
boundingBox.minZ = min.z;
boundingBox.maxZ = max.z;
};
if (move && extrude) {
recordX(cmds[j].prevX, prevInBounds);
recordX(cmds[j].x, inBounds);
recordY(cmds[j].prevY, prevInBounds);
recordY(cmds[j].y, inBounds);
recordZ(cmds[j].prevZ);
recordZ(cmds[j].z);
}
if (!totalFilament[tool]) totalFilament[tool] = 0;
@ -165,20 +216,25 @@ var analyzeModel = function () {
filamentByLayer[cmds[j].prevZ][tool] += cmds[j].extrusion;
}
var diffX = cmds[j].x - cmds[j].prevX;
var diffY = cmds[j].y - cmds[j].prevY;
if (x_ok && y_ok) {
printTimeAdd = Math.sqrt(diffX * diffX + diffY * diffY) / (cmds[j].speed / 60);
} else if (cmds[j].retract === 0 && cmds[j].extrusion !== 0) {
tmp1 = Math.sqrt(diffX * diffX + diffY * diffY) / (cmds[j].speed / 60);
tmp2 = Math.abs(cmds[j].extrusion / (cmds[j].speed / 60));
printTimeAdd = Math.max(tmp1, tmp2);
} else if (cmds[j].retract !== 0) {
printTimeAdd = Math.abs(cmds[j].extrusion / (cmds[j].speed / 60));
if (cmds[j].x !== undefined && !isNaN(cmds[j].x)
&& cmds[j].y !== undefined && !isNaN(cmds[j].y)) {
var diffX = cmds[j].x - cmds[j].prevX;
var diffY = cmds[j].y - cmds[j].prevY;
if (move) {
printTimeAdd = Math.sqrt(diffX * diffX + diffY * diffY) / (cmds[j].speed / 60);
} else if (extrude) {
tmp1 = Math.sqrt(diffX * diffX + diffY * diffY) / (cmds[j].speed / 60);
tmp2 = Math.abs(cmds[j].extrusion / (cmds[j].speed / 60));
printTimeAdd = Math.max(tmp1, tmp2);
} else if (retract) {
printTimeAdd = Math.abs(cmds[j].extrusion / (cmds[j].speed / 60));
}
} else {
printTimeAdd = 0;
}
printTime += printTimeAdd;
if (typeof(printTimeByLayer[cmds[j].prevZ]) === 'undefined') {
if (printTimeByLayer[cmds[j].prevZ] === undefined) {
printTimeByLayer[cmds[j].prevZ] = 0;
}
printTimeByLayer[cmds[j].prevZ] += printTimeAdd;
@ -574,6 +630,8 @@ var parseGCode = function (message) {
firstReport = message.options.firstReport;
toolOffsets = message.options.toolOffsets;
if (!toolOffsets || toolOffsets.length == 0) toolOffsets = [{x: 0, y: 0}];
bed = message.options.bed;
ignoreOutsideBed = message.options.ignoreOutsideBed;
g90InfluencesExtruder = message.options.g90InfluencesExtruder;
doParse();
@ -595,6 +653,7 @@ var runAnalyze = function (message) {
max = {x: undefined, y: undefined, z: undefined};
min = {x: undefined, y: undefined, z: undefined};
modelSize = {x: undefined, y: undefined, z: undefined};
boundingBox = {minX: undefined, maxX: undefined, minY: undefined, maxY: undefined, minZ: undefined, maxZ: undefined};
filamentByLayer = {};
totalFilament = 0;
printTime = 0;

View file

@ -12,6 +12,9 @@ GCODE.gCodeReader = (function(){
var max = {x: undefined, y: undefined, z: undefined};
var min = {x: undefined, y: undefined, z: undefined};
var modelSize = {x: undefined, y: undefined, z: undefined};
var boundingBox = {minX: undefined, maxX: undefined,
minY: undefined, maxY: undefined,
minZ: undefined, maxZ: undefined};
var filamentByLayer = {};
var printTimeByLayer;
var totalFilament=0;
@ -25,6 +28,14 @@ GCODE.gCodeReader = (function(){
toolOffsets: [
{x: 0, y: 0}
],
bed: {
x: undefined,
y: undefined,
r: undefined,
circular: undefined,
centeredOrigin: undefined
},
ignoreOutsideBed: false,
g90InfluencesExtruder: false
};
@ -123,6 +134,12 @@ GCODE.gCodeReader = (function(){
clear: function() {
model = [];
z_heights = [];
max = {x: undefined, y: undefined, z: undefined};
min = {x: undefined, y: undefined, z: undefined};
modelSize = {x: undefined, y: undefined, z: undefined};
boundingBox = {minX: undefined, maxX: undefined,
minY: undefined, maxY: undefined,
minZ: undefined, maxZ: undefined};
},
loadFile: function(reader){
@ -140,6 +157,8 @@ GCODE.gCodeReader = (function(){
options: {
firstReport: 5,
toolOffsets: gCodeOptions["toolOffsets"],
bed: gCodeOptions["bed"],
ignoreOutsideBed: gCodeOptions["ignoreOutsideBed"],
g90InfluencesExtruder: gCodeOptions["g90InfluencesExtruder"]
}
}
@ -182,6 +201,7 @@ GCODE.gCodeReader = (function(){
min = msg.min;
max = msg.max;
modelSize = msg.modelSize;
boundingBox = msg.boundingBox;
totalFilament = msg.totalFilament;
filamentByLayer = msg.filamentByLayer;
speeds = msg.speeds;
@ -203,6 +223,7 @@ GCODE.gCodeReader = (function(){
min: min,
max: max,
modelSize: modelSize,
boundingBox: boundingBox,
totalFilament: totalFilament,
speeds: speeds,
speedsByLayer: speedsByLayer,

View file

@ -20,7 +20,8 @@ GCODE.renderer = (function(){
var lastX, lastY;
var dragStart, dragged;
var scaleFactor = 1.1;
var model;
var model = undefined;
var modelInfo = undefined;
var initialized = false;
var renderOptions = {
colorGrid: "#bbbbbb",
@ -40,6 +41,8 @@ GCODE.renderer = (function(){
differentiateColors: true,
showNextLayer: false,
showPreviousLayer: false,
showBoundingBox: false,
showFullSize: false,
moveModel: true,
zoomInOnModel: false,
@ -65,6 +68,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();
drawBoundingBox();
if(renderOptions['showNextLayer'] && layerNumStore < model.length - 1) {
drawLayer(layerNumStore + 1, 0, GCODE.renderer.getLayerNumSegments(layerNumStore + 1), true);
}
@ -378,6 +382,44 @@ GCODE.renderer = (function(){
ctx.stroke();
};
var drawBoundingBox = function() {
if (!modelInfo) return;
var minX, minY, width, height;
if (renderOptions["showFullSize"]) {
minX = modelInfo.min.x * zoomFactor;
minY = modelInfo.min.y * zoomFactor;
width = modelInfo.modelSize.x * zoomFactor;
height = modelInfo.modelSize.y * zoomFactor;
ctx.beginPath();
ctx.strokeStyle = "#0000ff";
ctx.setLineDash([2, 5]);
ctx.rect(minX, minY * -1, width, height * -1);
ctx.stroke();
}
if (renderOptions["showBoundingBox"]) {
minX = modelInfo.boundingBox.minX * zoomFactor;
minY = modelInfo.boundingBox.minY * zoomFactor;
width = modelInfo.boundingBox.maxX * zoomFactor - minX;
height = modelInfo.boundingBox.maxY * zoomFactor - minY;
ctx.beginPath();
ctx.strokeStyle = "#ff0000";
ctx.setLineDash([2, 5]);
ctx.rect(minX, minY * -1, width, height * -1);
ctx.stroke();
}
ctx.setLineDash([1, 0]);
};
var drawLayer = function(layerNum, fromProgress, toProgress, isNotCurrentLayer){
log.trace("Drawing layer " + layerNum + " from " + fromProgress + " to " + toProgress + " (current: " + !isNotCurrentLayer + ")");
@ -524,27 +566,27 @@ GCODE.renderer = (function(){
ctx.stroke();
};
var applyOffsets = function(mdlInfo) {
var applyOffsets = function() {
var canvasCenter;
// determine bed and model offsets
if (ctx) ctx.translate(-offsetModelX, -offsetModelY);
if (renderOptions["centerViewport"] || renderOptions["zoomInOnModel"]) {
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;
if (modelInfo) {
offsetModelX = canvasCenter.x - (modelInfo.boundingBox.minX + modelInfo.boundingBox.maxX) * zoomFactor / 2;
offsetModelY = canvasCenter.y + (modelInfo.boundingBox.minY + modelInfo.boundingBox.maxY) * zoomFactor / 2;
} 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 if (modelInfo && renderOptions["moveModel"]) {
offsetModelX = (renderOptions["bed"]["x"] / 2 - (modelInfo.boundingBox.minX + modelInfo.boundingBox.maxX) / 2) * zoomFactor;
offsetModelY = -1 * (renderOptions["bed"]["y"] / 2 - (modelInfo.boundingBox.minY + modelInfo.boundingBox.maxY) / 2) * zoomFactor;
offsetBedX = -1 * (renderOptions["bed"]["x"] / 2 - (modelInfo.boundingBox.minX + modelInfo.boundingBox.maxX) / 2) * zoomFactor;
offsetBedY = (renderOptions["bed"]["y"] / 2 - (modelInfo.boundingBox.minY + modelInfo.boundingBox.maxY) / 2) * zoomFactor;
} else if (renderOptions["bed"]["circular"] || renderOptions["bed"]["centeredOrigin"]) {
canvasCenter = ctx.transformedPoint(canvas.width / 2, canvas.height / 2);
offsetModelX = canvasCenter.x;
@ -560,7 +602,7 @@ GCODE.renderer = (function(){
if (ctx) ctx.translate(offsetModelX, offsetModelY);
};
var applyZoom = function(mdlInfo) {
var applyZoom = function() {
// get middle of canvas
var pt = ctx.transformedPoint(canvas.width/2,canvas.height/2);
@ -575,9 +617,12 @@ GCODE.renderer = (function(){
transform = ctx.getTransform();
}
if (mdlInfo && renderOptions["zoomInOnModel"]) {
if (modelInfo && renderOptions["zoomInOnModel"]) {
// if we need to zoom in on model, scale factor is calculated by longer side of object in relation to that axis of canvas
var scaleF = mdlInfo.modelSize.x > mdlInfo.modelSize.y ? (canvas.width - 10) / mdlInfo.modelSize.x : (canvas.height - 10) / mdlInfo.modelSize.y;
var width = modelInfo.boundingBox.maxX - modelInfo.boundingBox.minX;
var length = modelInfo.boundingBox.maxY - modelInfo.boundingBox.minY;
var scaleF = width > length ? (canvas.width - 10) / width : (canvas.height - 10) / length;
scaleF /= zoomFactor;
if (transform.a && transform.d) {
scaleX = scaleF / transform.a * (renderOptions["invertAxes"]["x"] ? -1 : 1);
@ -682,6 +727,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();
drawBoundingBox();
if (model && model.length) {
if (layerNum < model.length) {
if (renderOptions['showNextLayer'] && layerNum < model.length - 1) {
@ -715,30 +761,31 @@ GCODE.renderer = (function(){
scaleY = 1;
speeds = [];
speedsByLayer = {};
modelInfo = undefined;
this.doRender([], 0);
},
doRender: function(mdl, layerNum){
model = mdl;
modelInfo = undefined;
var mdlInfo = undefined;
prevX = 0;
prevY = 0;
if (!initialized) this.init();
var toProgress = 1;
if (model) {
mdlInfo = GCODE.gCodeReader.getModelInfo();
speeds = mdlInfo.speeds;
speedsByLayer = mdlInfo.speedsByLayer;
if (model && model.length) {
modelInfo = GCODE.gCodeReader.getModelInfo();
speeds = modelInfo.speeds;
speedsByLayer = modelInfo.speedsByLayer;
if (model[layerNum]) {
toProgress = model[layerNum].length;
}
}
applyInversion();
applyOffsets(mdlInfo);
applyZoom(mdlInfo);
applyOffsets();
applyZoom();
this.render(layerNum, 0, toProgress);
},

View file

@ -161,7 +161,8 @@ GCODE.ui = (function(){
bed: options.bed
});
GCODE.gCodeReader.setOption({
toolOffsets: options.toolOffsets
toolOffsets: options.toolOffsets,
bed: options.bed
});
GCODE.renderer.render(0, 0);

View file

@ -46,6 +46,8 @@ $(function() {
self.renderer_zoomOnModel = ko.observable(false);
self.renderer_showMoves = ko.observable(true);
self.renderer_showRetracts = ko.observable(true);
self.renderer_showBoundingBox = ko.observable(false);
self.renderer_showFullSize = ko.observable(false);
self.renderer_extrusionWidthEnabled = ko.observable(false);
self.renderer_extrusionWidth = ko.observable(2);
self.renderer_showNext = ko.observable(false);
@ -65,6 +67,8 @@ $(function() {
centerViewport: self.renderer_centerViewport(),
showMoves: self.renderer_showMoves(),
showRetracts: self.renderer_showRetracts(),
showBoundingBox: self.renderer_showBoundingBox(),
showFullSize: self.renderer_showFullSize(),
extrusionWidth: self.renderer_extrusionWidthEnabled() ? self.renderer_extrusionWidth() : 1,
showNextLayer: self.renderer_showNext(),
showPreviousLayer: self.renderer_showPrevious(),
@ -77,7 +81,8 @@ $(function() {
var reader = {
sortLayers: self.reader_sortLayers(),
purgeEmptyLayers: self.reader_hideEmptyLayers()
purgeEmptyLayers: self.reader_hideEmptyLayers(),
ignoreOutsideBed: true
};
if (additionalReaderOptions) {
_.extend(reader, additionalReaderOptions);
@ -95,6 +100,8 @@ $(function() {
self.renderer_zoomOnModel.subscribe(self.synchronizeOptions);
self.renderer_showMoves.subscribe(self.synchronizeOptions);
self.renderer_showRetracts.subscribe(self.synchronizeOptions);
self.renderer_showBoundingBox.subscribe(self.synchronizeOptions);
self.renderer_showFullSize.subscribe(self.synchronizeOptions);
self.renderer_extrusionWidthEnabled.subscribe(self.synchronizeOptions);
self.renderer_extrusionWidth.subscribe(self.synchronizeOptions);
self.renderer_showNext.subscribe(self.synchronizeOptions);
@ -120,10 +127,13 @@ $(function() {
}
var bedDimensions = self._retrieveBedDimensions(currentProfileData);
if (toolOffsets) {
if (bedDimensions) {
GCODE.ui.updateOptions({
renderer: {
bed: bedDimensions
},
reader: {
bed: bedDimensions
}
});
}
@ -336,6 +346,7 @@ $(function() {
result: response
}
};
GCODE.renderer.clear();
GCODE.gCodeReader.loadFile(par);
if (self.layerSlider != undefined) {