Small fixes prior to merge of #852
* Proper origin visualization in gcode viewer for centered rectangular * Validation of origin profile entry * Auto-migration of existing profiles upon load * Added changelog entry
This commit is contained in:
parent
12310c5e3a
commit
cd244f341d
4 changed files with 97 additions and 24 deletions
|
|
@ -118,6 +118,9 @@
|
|||
* Renamed "Temperature Timeout" and "SD Status Timeout" in Settings to "Temperature Interval" and "SD Status Interval"
|
||||
to better reflect what those values are actually used for.
|
||||
* Better behaviour of the settings dialog on mobile devices.
|
||||
* Added support for rectangular printer beds with the origin in the center ([#682](https://github.com/foosel/OctoPrint/issues/682)
|
||||
and [#852](https://github.com/foosel/OctoPrint/pull/852)). Printer profiles now contain a new settings ``volume.origin``
|
||||
which can either be ``lowerleft`` or ``center``. For circular beds only ``center`` is supported.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
|
|
|
|||
|
|
@ -80,10 +80,9 @@ 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``
|
||||
* - ``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``)
|
||||
|
|
@ -304,7 +303,15 @@ class PrinterProfileManager(object):
|
|||
import yaml
|
||||
with open(path) as f:
|
||||
profile = yaml.safe_load(f)
|
||||
|
||||
if self._migrate_profile(profile):
|
||||
try:
|
||||
self._save_to_path(path, profile, allow_overwrite=True)
|
||||
except:
|
||||
self._logger.exception("Tried to save profile to {path} after migrating it while loading, ran into exception".format(path=path))
|
||||
|
||||
profile = self._ensure_valid_profile(profile)
|
||||
|
||||
if not profile:
|
||||
self._logger.warn("Invalid profile: %s" % path)
|
||||
raise InvalidProfileError()
|
||||
|
|
@ -356,6 +363,14 @@ class PrinterProfileManager(object):
|
|||
sanitized_name = sanitized_name.replace(" ", "_")
|
||||
return sanitized_name
|
||||
|
||||
def _migrate_profile(self, profile):
|
||||
# make sure profile format is up to date
|
||||
if "volume" in profile and "formFactor" in profile["volume"] and not "origin" in profile["volume"]:
|
||||
profile["volume"]["origin"] = BedOrigin.CENTER if profile["volume"]["formFactor"] == BedTypes.CIRCULAR else BedOrigin.LOWERLEFT
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _ensure_valid_profile(self, profile):
|
||||
# ensure all keys are present
|
||||
if not dict_contains_keys(self.default, profile):
|
||||
|
|
@ -399,6 +414,15 @@ class PrinterProfileManager(object):
|
|||
if not profile["volume"]["formFactor"] in BedTypes.values():
|
||||
return False
|
||||
|
||||
# validate origin type
|
||||
if not profile["volume"]["origin"] in BedOrigin.values():
|
||||
return False
|
||||
|
||||
# ensure origin and form factor combination is legal
|
||||
if profile["volume"]["formFactor"] == BedTypes.CIRCULAR and not profile["volume"]["origin"] == BedOrigin.CENTER:
|
||||
# we do not support circular beds with anything other than a centered origin
|
||||
return False
|
||||
|
||||
# validate offsets
|
||||
offsets = []
|
||||
for offset in profile["extruder"]["offsets"]:
|
||||
|
|
|
|||
|
|
@ -258,43 +258,66 @@ GCODE.renderer = (function(){
|
|||
};
|
||||
|
||||
var drawRectangularGrid = function() {
|
||||
var i;
|
||||
var width = renderOptions["bed"]["x"] * zoomFactor;
|
||||
var height = renderOptions["bed"]["y"] * zoomFactor;
|
||||
var origin = {
|
||||
x: 0,
|
||||
y: -1 * renderOptions["bed"]["y"] * zoomFactor
|
||||
};
|
||||
var x, y;
|
||||
var width = renderOptions["bed"]["x"];
|
||||
var height = renderOptions["bed"]["y"];
|
||||
|
||||
var minX, maxX, minY, maxY;
|
||||
if (renderOptions["bed"]["centeredOrigin"]) {
|
||||
origin.x -= width / 2;
|
||||
origin.y += height / 2;
|
||||
var halfWidth = width / 2;
|
||||
var halfHeight = height / 2;
|
||||
|
||||
minX = -halfWidth;
|
||||
maxX = halfWidth;
|
||||
minY = -halfHeight;
|
||||
maxY = halfHeight;
|
||||
} else {
|
||||
minX = 0;
|
||||
maxX = width;
|
||||
minY = 0;
|
||||
maxY = height;
|
||||
}
|
||||
|
||||
//~ bed outline and origin
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle = renderOptions["colorGrid"];
|
||||
ctx.fillStyle = "#ffffff";
|
||||
ctx.lineWidth = 2;
|
||||
|
||||
ctx.rect(origin.x, origin.y, width, height);
|
||||
// outline
|
||||
ctx.rect(minX * zoomFactor, -1 * minY * zoomFactor, width * zoomFactor, -1 * height * zoomFactor);
|
||||
|
||||
// origin
|
||||
ctx.moveTo(minX * zoomFactor, 0);
|
||||
ctx.lineTo(maxX * zoomFactor, 0);
|
||||
ctx.moveTo(0, -1 * minY * zoomFactor);
|
||||
ctx.lineTo(0, -1 * maxY * zoomFactor);
|
||||
|
||||
// draw
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.strokeStyle = renderOptions["colorGrid"];
|
||||
ctx.lineWidth = 1;
|
||||
|
||||
//~~ grid starting from origin
|
||||
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);
|
||||
for (x = 0; x <= maxX; x += gridStep) {
|
||||
ctx.moveTo(x * zoomFactor, -1 * minY * zoomFactor);
|
||||
ctx.lineTo(x * zoomFactor, -1 * maxY * zoomFactor);
|
||||
|
||||
ctx.moveTo(-1 * x * zoomFactor, -1 * minY * zoomFactor);
|
||||
ctx.lineTo(-1 * x * zoomFactor, -1 * maxY * 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);
|
||||
for (y = 0; y <= maxY; y += gridStep) {
|
||||
ctx.moveTo(minX * zoomFactor, -1 * y * zoomFactor);
|
||||
ctx.lineTo(maxX * zoomFactor, -1 * y * zoomFactor);
|
||||
|
||||
ctx.moveTo(minX * zoomFactor, y * zoomFactor);
|
||||
ctx.lineTo(maxX * zoomFactor, y * zoomFactor);
|
||||
}
|
||||
ctx.stroke();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -69,6 +69,12 @@ $(function() {
|
|||
self.editorVolumeFormFactor = ko.observable();
|
||||
self.editorVolumeOrigin = ko.observable();
|
||||
|
||||
self.editorVolumeFormFactor.subscribe(function(oldVal, newVal) {
|
||||
if (oldVal != newVal && newVal == "circular") {
|
||||
self.editorVolumeOrigin("center");
|
||||
}
|
||||
});
|
||||
|
||||
self.editorHeatedBed = ko.observable();
|
||||
|
||||
self.editorNozzleDiameter = ko.observable();
|
||||
|
|
@ -95,10 +101,27 @@ $(function() {
|
|||
{key: "black", name: gettext("black")}
|
||||
]);
|
||||
|
||||
self.availableOrigins = ko.observable([
|
||||
{key: "lowerleft", name: gettext("Lower Left")},
|
||||
{key: "center", name: gettext("Centered")}
|
||||
]);
|
||||
self.availableOrigins = ko.computed(function() {
|
||||
var formFactor = self.editorVolumeFormFactor();
|
||||
|
||||
var possibleOrigins = {
|
||||
"lowerleft": gettext("Lower Left"),
|
||||
"center": gettext("Center")
|
||||
};
|
||||
|
||||
var keys = [];
|
||||
if (formFactor == "rectangular") {
|
||||
keys = ["lowerleft", "center"];
|
||||
} else if (formFactor == "circular") {
|
||||
keys = ["center"];
|
||||
}
|
||||
|
||||
var result = [];
|
||||
_.each(keys, function(key) {
|
||||
result.push({key: key, name: possibleOrigins[key]});
|
||||
});
|
||||
return result;
|
||||
});
|
||||
|
||||
self.koEditorExtruderOffsets = ko.computed(function() {
|
||||
var extruderOffsets = self.editorExtruderOffsets();
|
||||
|
|
|
|||
Loading…
Reference in a new issue