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:
Gina Häußge 2015-04-16 15:20:18 +02:00
parent 12310c5e3a
commit cd244f341d
4 changed files with 97 additions and 24 deletions

View file

@ -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

View file

@ -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"]:

View file

@ -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();
};

View file

@ -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();