From fbe50e33d380bb5faf28e7b77807e346bee7e0f6 Mon Sep 17 00:00:00 2001 From: Mark Walker Date: Wed, 15 Apr 2015 02:33:31 -0700 Subject: [PATCH 1/3] Add a printer profile option to allow centered origin on rectangular beds Some printers have (0, 0) at the center of the bed. Circular beds commonly, but also some rectangular beds. --- src/octoprint/printer/profile.py | 7 +++++++ src/octoprint/static/gcodeviewer/js/renderer.js | 15 ++++++++++----- src/octoprint/static/js/app/viewmodels/gcode.js | 9 ++++++--- .../static/js/app/viewmodels/printerprofiles.js | 3 +++ .../dialogs/settings/printerprofiles.jinja2 | 8 ++++++++ 5 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/octoprint/printer/profile.py b/src/octoprint/printer/profile.py index 547e81df..ac9845b1 100644 --- a/src/octoprint/printer/profile.py +++ b/src/octoprint/printer/profile.py @@ -72,6 +72,11 @@ class PrinterProfileManager(object): * - ``volume.formFactor`` - ``string`` - Form factor of the print bed, either ``rectangular`` or ``circular`` + * - ``centeredOrigin`` + - ``bool`` + - Whether the printer's origin is in the center of the bed, otherwise + - the origin is assumed to be the lower left and all valid coordinates + - positive. * - ``heatedBed`` - ``bool`` - Whether the printer has a heated bed (``True``) or not (``False``) @@ -140,6 +145,7 @@ class PrinterProfileManager(object): formFactor = BedTypes.RECTANGULAR, ), heatedBed = False, + centeredOrigin = False, extruder=dict( count = 1, offsets = [ @@ -291,6 +297,7 @@ class PrinterProfileManager(object): import yaml with open(path) as f: profile = yaml.safe_load(f) + profile = dict_merge(self._load_default(), profile) profile = self._ensure_valid_profile(profile) if not profile: self._logger.warn("Invalid profile: %s" % path) diff --git a/src/octoprint/static/gcodeviewer/js/renderer.js b/src/octoprint/static/gcodeviewer/js/renderer.js index 79abfff8..15b44eca 100644 --- a/src/octoprint/static/gcodeviewer/js/renderer.js +++ b/src/octoprint/static/gcodeviewer/js/renderer.js @@ -266,6 +266,11 @@ GCODE.renderer = (function(){ y: -1 * renderOptions["bed"]["y"] * zoomFactor }; + if (renderOptions["bed"]["centeredOrigin"]) { + origin.x -= width / 2; + origin.y += height / 2; + } + ctx.beginPath(); ctx.strokeStyle = renderOptions["colorGrid"]; ctx.fillStyle = "#ffffff"; @@ -281,15 +286,15 @@ GCODE.renderer = (function(){ ctx.beginPath(); for (i = 0; i <= renderOptions["bed"]["x"]; i += gridStep) { - ctx.moveTo(i * zoomFactor, 0); - ctx.lineTo(i * zoomFactor, -1 * renderOptions["bed"]["y"] * zoomFactor); + ctx.moveTo(origin.x + i * zoomFactor, origin.y); + ctx.lineTo(origin.x + i * zoomFactor, origin.y + height); } ctx.stroke(); ctx.beginPath(); for (i = 0; i <= renderOptions["bed"]["y"]; i += gridStep) { - ctx.moveTo(0, -1 * i * zoomFactor); - ctx.lineTo(renderOptions["bed"]["x"] * zoomFactor, -1 * i * zoomFactor); + ctx.moveTo(origin.x, origin.y + i * zoomFactor); + ctx.lineTo(origin.x + width, origin.y + i * zoomFactor); } ctx.stroke(); }; @@ -496,7 +501,7 @@ GCODE.renderer = (function(){ 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 (renderOptions["bed"]["circular"]) { + } else if (renderOptions["bed"]["circular"] || renderOptions["bed"]["centeredOrigin"]) { canvasCenter = ctx.transformedPoint(canvas.width / 2, canvas.height / 2); offsetModelX = canvasCenter.x; offsetModelY = canvasCenter.y; diff --git a/src/octoprint/static/js/app/viewmodels/gcode.js b/src/octoprint/static/js/app/viewmodels/gcode.js index e44096c7..d3923677 100644 --- a/src/octoprint/static/js/app/viewmodels/gcode.js +++ b/src/octoprint/static/js/app/viewmodels/gcode.js @@ -137,22 +137,25 @@ $(function() { } if (currentProfileData && currentProfileData.volume && currentProfileData.volume.formFactor() && currentProfileData.volume.width() && currentProfileData.volume.depth()) { - var x = undefined, y = undefined, r = undefined, circular = false; + var x = undefined, y = undefined, r = undefined, circular = false, centeredOrigin = false; var formFactor = currentProfileData.volume.formFactor(); if (formFactor == "circular") { r = currentProfileData.volume.width() / 2; circular = true; + centeredOrigin = true; } else { x = currentProfileData.volume.width(); y = currentProfileData.volume.depth(); + centeredOrigin = currentProfileData.hasOwnProperty("centeredOrigin") && currentProfileData.centeredOrigin(); } return { x: x, y: y, r: r, - circular: circular + circular: circular, + centeredOrigin: centeredOrigin }; } else { return undefined; @@ -507,4 +510,4 @@ $(function() { ["loginStateViewModel", "settingsViewModel"], "#gcode" ]); -}); \ No newline at end of file +}); diff --git a/src/octoprint/static/js/app/viewmodels/printerprofiles.js b/src/octoprint/static/js/app/viewmodels/printerprofiles.js index 516c207b..de57ff38 100644 --- a/src/octoprint/static/js/app/viewmodels/printerprofiles.js +++ b/src/octoprint/static/js/app/viewmodels/printerprofiles.js @@ -68,6 +68,7 @@ $(function() { self.editorVolumeFormFactor = ko.observable(); self.editorHeatedBed = ko.observable(); + self.editorCenteredOrigin = ko.observable(); self.editorNozzleDiameter = ko.observable(); self.editorExtruders = ko.observable(); @@ -284,6 +285,7 @@ $(function() { self.editorVolumeFormFactor(data.volume.formFactor); self.editorHeatedBed(data.heatedBed); + self.editorCenteredOrigin(data.centeredOrigin); self.editorNozzleDiameter(data.extruder.nozzleDiameter); self.editorExtruders(data.extruder.count); @@ -349,6 +351,7 @@ $(function() { formFactor: self.editorVolumeFormFactor() }, heatedBed: self.editorHeatedBed(), + centeredOrigin: self.editorCenteredOrigin(), extruder: { count: parseInt(self.editorExtruders()), offsets: [ diff --git a/src/octoprint/templates/dialogs/settings/printerprofiles.jinja2 b/src/octoprint/templates/dialogs/settings/printerprofiles.jinja2 index 821be236..df368488 100644 --- a/src/octoprint/templates/dialogs/settings/printerprofiles.jinja2 +++ b/src/octoprint/templates/dialogs/settings/printerprofiles.jinja2 @@ -100,6 +100,14 @@ +
+ +
+ +
+
From a4df56dcb7f795f1b3a6e1fcef5f18724de3d5b3 Mon Sep 17 00:00:00 2001 From: Mark Walker Date: Wed, 15 Apr 2015 04:04:34 -0700 Subject: [PATCH 2/3] Undo so we can go another way --- src/octoprint/printer/profile.py | 7 ------- src/octoprint/static/gcodeviewer/js/renderer.js | 15 +++++---------- src/octoprint/static/js/app/viewmodels/gcode.js | 9 +++------ .../static/js/app/viewmodels/printerprofiles.js | 3 --- .../dialogs/settings/printerprofiles.jinja2 | 8 -------- 5 files changed, 8 insertions(+), 34 deletions(-) diff --git a/src/octoprint/printer/profile.py b/src/octoprint/printer/profile.py index ac9845b1..547e81df 100644 --- a/src/octoprint/printer/profile.py +++ b/src/octoprint/printer/profile.py @@ -72,11 +72,6 @@ class PrinterProfileManager(object): * - ``volume.formFactor`` - ``string`` - Form factor of the print bed, either ``rectangular`` or ``circular`` - * - ``centeredOrigin`` - - ``bool`` - - Whether the printer's origin is in the center of the bed, otherwise - - the origin is assumed to be the lower left and all valid coordinates - - positive. * - ``heatedBed`` - ``bool`` - Whether the printer has a heated bed (``True``) or not (``False``) @@ -145,7 +140,6 @@ class PrinterProfileManager(object): formFactor = BedTypes.RECTANGULAR, ), heatedBed = False, - centeredOrigin = False, extruder=dict( count = 1, offsets = [ @@ -297,7 +291,6 @@ class PrinterProfileManager(object): import yaml with open(path) as f: profile = yaml.safe_load(f) - profile = dict_merge(self._load_default(), profile) profile = self._ensure_valid_profile(profile) if not profile: self._logger.warn("Invalid profile: %s" % path) diff --git a/src/octoprint/static/gcodeviewer/js/renderer.js b/src/octoprint/static/gcodeviewer/js/renderer.js index 15b44eca..79abfff8 100644 --- a/src/octoprint/static/gcodeviewer/js/renderer.js +++ b/src/octoprint/static/gcodeviewer/js/renderer.js @@ -266,11 +266,6 @@ GCODE.renderer = (function(){ y: -1 * renderOptions["bed"]["y"] * zoomFactor }; - if (renderOptions["bed"]["centeredOrigin"]) { - origin.x -= width / 2; - origin.y += height / 2; - } - ctx.beginPath(); ctx.strokeStyle = renderOptions["colorGrid"]; ctx.fillStyle = "#ffffff"; @@ -286,15 +281,15 @@ GCODE.renderer = (function(){ ctx.beginPath(); for (i = 0; i <= renderOptions["bed"]["x"]; i += gridStep) { - ctx.moveTo(origin.x + i * zoomFactor, origin.y); - ctx.lineTo(origin.x + i * zoomFactor, origin.y + height); + ctx.moveTo(i * zoomFactor, 0); + ctx.lineTo(i * zoomFactor, -1 * renderOptions["bed"]["y"] * zoomFactor); } ctx.stroke(); ctx.beginPath(); for (i = 0; i <= renderOptions["bed"]["y"]; i += gridStep) { - ctx.moveTo(origin.x, origin.y + i * zoomFactor); - ctx.lineTo(origin.x + width, origin.y + i * zoomFactor); + ctx.moveTo(0, -1 * i * zoomFactor); + ctx.lineTo(renderOptions["bed"]["x"] * zoomFactor, -1 * i * zoomFactor); } ctx.stroke(); }; @@ -501,7 +496,7 @@ GCODE.renderer = (function(){ 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 (renderOptions["bed"]["circular"] || renderOptions["bed"]["centeredOrigin"]) { + } else if (renderOptions["bed"]["circular"]) { canvasCenter = ctx.transformedPoint(canvas.width / 2, canvas.height / 2); offsetModelX = canvasCenter.x; offsetModelY = canvasCenter.y; diff --git a/src/octoprint/static/js/app/viewmodels/gcode.js b/src/octoprint/static/js/app/viewmodels/gcode.js index d3923677..e44096c7 100644 --- a/src/octoprint/static/js/app/viewmodels/gcode.js +++ b/src/octoprint/static/js/app/viewmodels/gcode.js @@ -137,25 +137,22 @@ $(function() { } if (currentProfileData && currentProfileData.volume && currentProfileData.volume.formFactor() && currentProfileData.volume.width() && currentProfileData.volume.depth()) { - var x = undefined, y = undefined, r = undefined, circular = false, centeredOrigin = false; + var x = undefined, y = undefined, r = undefined, circular = false; var formFactor = currentProfileData.volume.formFactor(); if (formFactor == "circular") { r = currentProfileData.volume.width() / 2; circular = true; - centeredOrigin = true; } else { x = currentProfileData.volume.width(); y = currentProfileData.volume.depth(); - centeredOrigin = currentProfileData.hasOwnProperty("centeredOrigin") && currentProfileData.centeredOrigin(); } return { x: x, y: y, r: r, - circular: circular, - centeredOrigin: centeredOrigin + circular: circular }; } else { return undefined; @@ -510,4 +507,4 @@ $(function() { ["loginStateViewModel", "settingsViewModel"], "#gcode" ]); -}); +}); \ No newline at end of file diff --git a/src/octoprint/static/js/app/viewmodels/printerprofiles.js b/src/octoprint/static/js/app/viewmodels/printerprofiles.js index de57ff38..516c207b 100644 --- a/src/octoprint/static/js/app/viewmodels/printerprofiles.js +++ b/src/octoprint/static/js/app/viewmodels/printerprofiles.js @@ -68,7 +68,6 @@ $(function() { self.editorVolumeFormFactor = ko.observable(); self.editorHeatedBed = ko.observable(); - self.editorCenteredOrigin = ko.observable(); self.editorNozzleDiameter = ko.observable(); self.editorExtruders = ko.observable(); @@ -285,7 +284,6 @@ $(function() { self.editorVolumeFormFactor(data.volume.formFactor); self.editorHeatedBed(data.heatedBed); - self.editorCenteredOrigin(data.centeredOrigin); self.editorNozzleDiameter(data.extruder.nozzleDiameter); self.editorExtruders(data.extruder.count); @@ -351,7 +349,6 @@ $(function() { formFactor: self.editorVolumeFormFactor() }, heatedBed: self.editorHeatedBed(), - centeredOrigin: self.editorCenteredOrigin(), extruder: { count: parseInt(self.editorExtruders()), offsets: [ diff --git a/src/octoprint/templates/dialogs/settings/printerprofiles.jinja2 b/src/octoprint/templates/dialogs/settings/printerprofiles.jinja2 index df368488..821be236 100644 --- a/src/octoprint/templates/dialogs/settings/printerprofiles.jinja2 +++ b/src/octoprint/templates/dialogs/settings/printerprofiles.jinja2 @@ -100,14 +100,6 @@
-
- -
- -
-
From 5a27ab6e54eea609b60cac6fcca0eefe11a57583 Mon Sep 17 00:00:00 2001 From: Mark Walker Date: Wed, 15 Apr 2015 04:05:48 -0700 Subject: [PATCH 3/3] Move the centered option into printer volume Also, modify the cura slicer to recognize the setting and avoid adjusting the model position, just leave it in the center where it would be on a circular platform --- src/octoprint/plugins/cura/profile.py | 2 +- src/octoprint/printer/profile.py | 13 +++++++++++++ src/octoprint/static/gcodeviewer/js/renderer.js | 15 ++++++++++----- src/octoprint/static/js/app/viewmodels/gcode.js | 11 ++++++++--- .../static/js/app/viewmodels/printerprofiles.js | 13 +++++++++++-- .../dialogs/settings/printerprofiles.jinja2 | 9 +++++++++ 6 files changed, 52 insertions(+), 11 deletions(-) diff --git a/src/octoprint/plugins/cura/profile.py b/src/octoprint/plugins/cura/profile.py index 6587c527..a63ff9cb 100644 --- a/src/octoprint/plugins/cura/profile.py +++ b/src/octoprint/plugins/cura/profile.py @@ -531,7 +531,7 @@ class Profile(object): elif key == "machine_height": return self._printer_profile["volume"]["height"] elif key == "machine_center_is_zero": - return self._printer_profile["volume"]["formFactor"] == "circular" + return self._printer_profile["volume"]["formFactor"] == "circular" or self._printer_profile["volume"]["origin"] == "center" else: return None diff --git a/src/octoprint/printer/profile.py b/src/octoprint/printer/profile.py index 547e81df..0b3f6834 100644 --- a/src/octoprint/printer/profile.py +++ b/src/octoprint/printer/profile.py @@ -31,6 +31,14 @@ class BedTypes(object): def values(cls): return [getattr(cls, name) for name in cls.__dict__ if not name.startswith("__")] +class BedOrigin(object): + LOWERLEFT = "lowerleft" + CENTER = "center" + + @classmethod + def values(cls): + return [getattr(cls, name) for name in cls.__dict__ if not name.startswith("__")] + class PrinterProfileManager(object): """ Manager for printer profiles. Offers methods to select the globally used printer profile and to list, add, remove, @@ -72,6 +80,10 @@ class PrinterProfileManager(object): * - ``volume.formFactor`` - ``string`` - Form factor of the print bed, either ``rectangular`` or ``circular`` + - ``volume.origin`` + - ``string`` + - Location of gcode origin in the print volume, either ``lowerleft`` + - or ``center`` * - ``heatedBed`` - ``bool`` - Whether the printer has a heated bed (``True``) or not (``False``) @@ -138,6 +150,7 @@ class PrinterProfileManager(object): depth = 200, height = 200, formFactor = BedTypes.RECTANGULAR, + origin = BedOrigin.LOWERLEFT ), heatedBed = False, extruder=dict( diff --git a/src/octoprint/static/gcodeviewer/js/renderer.js b/src/octoprint/static/gcodeviewer/js/renderer.js index 79abfff8..15b44eca 100644 --- a/src/octoprint/static/gcodeviewer/js/renderer.js +++ b/src/octoprint/static/gcodeviewer/js/renderer.js @@ -266,6 +266,11 @@ GCODE.renderer = (function(){ y: -1 * renderOptions["bed"]["y"] * zoomFactor }; + if (renderOptions["bed"]["centeredOrigin"]) { + origin.x -= width / 2; + origin.y += height / 2; + } + ctx.beginPath(); ctx.strokeStyle = renderOptions["colorGrid"]; ctx.fillStyle = "#ffffff"; @@ -281,15 +286,15 @@ GCODE.renderer = (function(){ ctx.beginPath(); for (i = 0; i <= renderOptions["bed"]["x"]; i += gridStep) { - ctx.moveTo(i * zoomFactor, 0); - ctx.lineTo(i * zoomFactor, -1 * renderOptions["bed"]["y"] * zoomFactor); + ctx.moveTo(origin.x + i * zoomFactor, origin.y); + ctx.lineTo(origin.x + i * zoomFactor, origin.y + height); } ctx.stroke(); ctx.beginPath(); for (i = 0; i <= renderOptions["bed"]["y"]; i += gridStep) { - ctx.moveTo(0, -1 * i * zoomFactor); - ctx.lineTo(renderOptions["bed"]["x"] * zoomFactor, -1 * i * zoomFactor); + ctx.moveTo(origin.x, origin.y + i * zoomFactor); + ctx.lineTo(origin.x + width, origin.y + i * zoomFactor); } ctx.stroke(); }; @@ -496,7 +501,7 @@ GCODE.renderer = (function(){ 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 (renderOptions["bed"]["circular"]) { + } else if (renderOptions["bed"]["circular"] || renderOptions["bed"]["centeredOrigin"]) { canvasCenter = ctx.transformedPoint(canvas.width / 2, canvas.height / 2); offsetModelX = canvasCenter.x; offsetModelY = canvasCenter.y; diff --git a/src/octoprint/static/js/app/viewmodels/gcode.js b/src/octoprint/static/js/app/viewmodels/gcode.js index e44096c7..aa3af46b 100644 --- a/src/octoprint/static/js/app/viewmodels/gcode.js +++ b/src/octoprint/static/js/app/viewmodels/gcode.js @@ -137,22 +137,27 @@ $(function() { } if (currentProfileData && currentProfileData.volume && currentProfileData.volume.formFactor() && currentProfileData.volume.width() && currentProfileData.volume.depth()) { - var x = undefined, y = undefined, r = undefined, circular = false; + var x = undefined, y = undefined, r = undefined, circular = false, centeredOrigin = false; var formFactor = currentProfileData.volume.formFactor(); if (formFactor == "circular") { r = currentProfileData.volume.width() / 2; circular = true; + centeredOrigin = true; } else { x = currentProfileData.volume.width(); y = currentProfileData.volume.depth(); + if (currentProfileData.volume.origin) { + centeredOrigin = currentProfileData.volume.origin() == "center"; + } } return { x: x, y: y, r: r, - circular: circular + circular: circular, + centeredOrigin: centeredOrigin }; } else { return undefined; @@ -507,4 +512,4 @@ $(function() { ["loginStateViewModel", "settingsViewModel"], "#gcode" ]); -}); \ No newline at end of file +}); diff --git a/src/octoprint/static/js/app/viewmodels/printerprofiles.js b/src/octoprint/static/js/app/viewmodels/printerprofiles.js index 516c207b..109c0791 100644 --- a/src/octoprint/static/js/app/viewmodels/printerprofiles.js +++ b/src/octoprint/static/js/app/viewmodels/printerprofiles.js @@ -12,7 +12,8 @@ $(function() { formFactor: "rectangular", width: 200, depth: 200, - height: 200 + height: 200, + origin: "lowerleft" }, heatedBed: false, axes: { @@ -66,6 +67,7 @@ $(function() { self.editorVolumeDepth = ko.observable(); self.editorVolumeHeight = ko.observable(); self.editorVolumeFormFactor = ko.observable(); + self.editorVolumeOrigin = ko.observable(); self.editorHeatedBed = ko.observable(); @@ -93,6 +95,11 @@ $(function() { {key: "black", name: gettext("black")} ]); + self.availableOrigins = ko.observable([ + {key: "lowerleft", name: gettext("Lower Left")}, + {key: "center", name: gettext("Centered")} + ]); + self.koEditorExtruderOffsets = ko.computed(function() { var extruderOffsets = self.editorExtruderOffsets(); var numExtruders = self.editorExtruders(); @@ -282,6 +289,7 @@ $(function() { self.editorVolumeDepth(data.volume.depth); self.editorVolumeHeight(data.volume.height); self.editorVolumeFormFactor(data.volume.formFactor); + self.editorVolumeOrigin(data.volume.origin); self.editorHeatedBed(data.heatedBed); @@ -346,7 +354,8 @@ $(function() { width: parseFloat(self.editorVolumeWidth()), depth: parseFloat(self.editorVolumeDepth()), height: parseFloat(self.editorVolumeHeight()), - formFactor: self.editorVolumeFormFactor() + formFactor: self.editorVolumeFormFactor(), + origin: self.editorVolumeOrigin() }, heatedBed: self.editorHeatedBed(), extruder: { diff --git a/src/octoprint/templates/dialogs/settings/printerprofiles.jinja2 b/src/octoprint/templates/dialogs/settings/printerprofiles.jinja2 index 821be236..d49ce3e2 100644 --- a/src/octoprint/templates/dialogs/settings/printerprofiles.jinja2 +++ b/src/octoprint/templates/dialogs/settings/printerprofiles.jinja2 @@ -76,6 +76,15 @@
+
+
+ +
+ +
+
+