slicing works again after dealing with svg namespaces.

This commit is contained in:
Teja 2015-01-18 22:33:04 +01:00
parent 0c68913e56
commit 1491d995cf
10 changed files with 167 additions and 26 deletions

View file

@ -246,6 +246,7 @@ class SvgToGcodePlugin(octoprint.plugin.SlicerPlugin,
on_progress_kwargs = dict()
self._svgtogcode_logger.info("### Slicing %s to %s using profile stored at %s" % (model_path, machinecode_path, profile_path))
print("### Slicing %s to %s using profile stored at %s" % (model_path, machinecode_path, profile_path))
engine_settings = self._convert_to_engine(profile_path)
@ -253,6 +254,7 @@ class SvgToGcodePlugin(octoprint.plugin.SlicerPlugin,
homedir = expanduser("~")
executable = homedir + "/mrbeam-inkscape-ext/mrbeam.py"
log_path = homedir + "/.octoprint/logs/svgtogcode.log"
log_enabled = "true"
# debugging stuff. TODO remove
hostname = socket.gethostname()
@ -269,7 +271,7 @@ class SvgToGcodePlugin(octoprint.plugin.SlicerPlugin,
args = ['python "%s"' % executable, '-f "%s"' % dest_file, '-d "%s"' % dest_dir]
for k, v in engine_settings.items():
args += ['"%s=%s"' % (k, str(v))]
args += ['--create-log=false', '"--log-filename=%s"' % log_path,'"%s"' % model_path]
args += ['--create-log=%s' % log_enabled, '"--log-filename=%s"' % log_path,'"%s"' % model_path]
#python ~/mrbeam-inkscape-ext/standalone.py -f output.gcode -d output/path --engraving-laser-speed=300
# --laser-intensity=1000 --create-log=false path/to/input.svg

View file

@ -2,6 +2,7 @@ function VectorConversionViewModel(loginStateViewModel, settingsViewModel) {
var self = this;
self.loginState = loginStateViewModel;
self.settings = settingsViewModel;
self.target = undefined;
self.file = undefined;
@ -27,19 +28,34 @@ function VectorConversionViewModel(loginStateViewModel, settingsViewModel) {
self.gcodeFilename(self.file.substr(0, self.file.lastIndexOf(".")));
$("#dialog_vector_graphics_conversion").modal("show");
};
self.show2 = function() {
var tmpsvg = snap.select("#scaleGroup"); // get working area
var dim = self.settings.printer_bedDimensions();
var w = dim.x * 90/25.4; // convert mm to pix with 90dpi (inkscape default - TODO use 72 for illustrator svg)
var h = dim.y * 90/25.4;
var s = Snap(w, h); // create new empty svg with working area dimensions
s.append(tmpsvg); // .. and fill it
self.svg = s.outerSVG();
// TODO: js svg conversion
self.title(gettext("Converting"));
var gcodeFile = "tmp"+Date.now()+".gco"; // TODO: user should not deal with gcode anymore. go and laser it.
self.gcodeFilename(gcodeFile);
$("#dialog_vector_graphics_conversion").modal("show");
};
self.slicer.subscribe(function(newValue) {
self.profilesForSlicer(newValue);
});
self.enableConvertButton = ko.computed(function() {
if (self.laserIntensity() == undefined || self.laserSpeed() == undefined || self.gcodeFilename() == undefined) {
if (self.laserIntensity() === undefined || self.laserSpeed() === undefined || self.gcodeFilename() === undefined) {
return false;
} else {
var tmpIntensity = parseInt(self.laserIntensity().trim());
var tmpSpeed = parseInt(self.laserSpeed().trim());
var tmpGcodeFilename = self.gcodeFilename().trim();
return tmpGcodeFilename != ""
return tmpGcodeFilename !== ""
&& tmpIntensity > 0 && tmpIntensity <= 1000
&& tmpSpeed >= 30 && tmpSpeed <= 2000;
}
@ -51,18 +67,17 @@ function VectorConversionViewModel(loginStateViewModel, settingsViewModel) {
type: "GET",
dataType: "json",
success: self.fromResponse
})
});
};
self.fromResponse = function(data) {
console.log("convert.js", data);
self.data = data;
var selectedSlicer = undefined;
self.slicers.removeAll();
_.each(_.values(data), function(slicer) {
var name = slicer.displayName;
if (name == undefined) {
if (name === undefined) {
name = slicer.key;
}
@ -126,15 +141,19 @@ function VectorConversionViewModel(loginStateViewModel, settingsViewModel) {
}
var data = {
command: "slice",
command: "convert",
"profile.speed": self.laserSpeed(),
"profile.intensity": self.laserIntensity(),
slicer: "svgtogcode",
gcode: gcodeFilename
};
if(self.svg !== undefined){
data.svg = self.svg;
}
$.ajax({
url: API_BASEURL + "files/" + self.target + "/" + self.file,
url: API_BASEURL + "files/convert",
type: "POST",
dataType: "json",
contentType: "application/json; charset=UTF-8",

View file

@ -109,11 +109,19 @@ function WorkingAreaViewModel(loginStateViewModel, settingsViewModel, printerSta
//self.getDivDimensions(); // init
self.placeSVG = function(url){
console.log("workingarea", url);
Snap.load(url, function (f) {
var namespaces = {};
var root = f.select('svg').node.attributes;
for(var i = 0; i < root.length; i++){
var attr = root[i];
if(attr.name.indexOf("xmlns") === 0){
namespaces[attr.name] = attr.value;
}
}
var newSvg = f.select("g");
newSvg.attr(namespaces);
var id = self.generateId(url);
newSvg.attr("id", id);
snap.select("#scaleGroup").append(newSvg);
newSvg.drag();// Making croc draggable. Go ahead drag it around!

View file

@ -212,12 +212,19 @@ var UI_API_KEY = "{{ uiApiKey }}";
<div class="bar" id="job_progressBar" data-bind="style: { width: progressString() + '%' }"></div>
</div>
<div class="row-fluid print-control" style="display: none;" data-bind="visible: loginState.isUser">
<!-- <div class="row-fluid print-control" style="display: none;" data-bind="visible: loginState.isUser">
<button class="btn btn-danger span4" data-bind="click: print_with_safety_glasses_warning, enable: isOperational() && isReady() && !isPrinting() && loginState.isUser(), attr: {title: titlePrintButton}" id="job_print">
<i class="icon-white" data-bind="css: {'icon-fire': !isPaused(), 'icon-undo': isPaused(), 'wobble': isPrinting()}"></i> <span data-bind="text: (isPaused() ? '{{ _('Restart') }}' : '{{ _('Laser') }}')">{{ _('Laser') }}</span>
</button>
<button class="btn span4" id="job_pause" data-bind="click: pause, enable: isOperational() && (isPrinting() || isPaused()) && loginState.isUser(), css: {active: isPaused()}, attr: {title: titlePauseButton}"><i data-bind="css: {'icon-pause': !isPaused(), 'icon-play': isPaused()}"></i> <span data-bind="visible: !isPaused()">{{ _('Pause') }}</span><span data-bind="visible: isPaused()">{{ _('Resume') }}</span></button>
<button class="btn span4" id="job_cancel" data-bind="click: cancel, enable: isOperational() && (isPrinting() || isPaused()) && loginState.isUser()" title="{{ _('Cancels the job') }}"><i class="icon-stop"></i> {{ _('Cancel') }}</button>
</div>-->
<div class="row-fluid print-control" style="display: none;" data-bind="visible: loginState.isUser">
<button class="btn btn-danger span4" data-bind="click: convertWorkingArea, enable: isOperational() && isReady() && !isPrinting() && loginState.isUser(), attr: {title: titlePrintButton}" id="job_print">
<i class="icon-white" data-bind="css: {'icon-fire': !isPaused(), 'icon-undo': isPaused(), 'wobble': isPrinting()}"></i> <span data-bind="text: (isPaused() ? '{{ _('Restart') }}' : '{{ _('Laser') }}')">{{ _('Laser') }}</span>
</button>
<button class="btn span4" id="job_pause" data-bind="click: pause, enable: isOperational() && (isPrinting() || isPaused()) && loginState.isUser(), css: {active: isPaused()}, attr: {title: titlePauseButton}"><i data-bind="css: {'icon-pause': !isPaused(), 'icon-play': isPaused()}"></i> <span data-bind="visible: !isPaused()">{{ _('Pause') }}</span><span data-bind="visible: isPaused()">{{ _('Resume') }}</span></button>
<button class="btn span4" id="job_cancel" data-bind="click: cancel, enable: isOperational() && (isPrinting() || isPaused()) && loginState.isUser()" title="{{ _('Cancels the job') }}"><i class="icon-stop"></i> {{ _('Cancel') }}</button>
</div>
</div>
</div>
@ -360,8 +367,8 @@ var UI_API_KEY = "{{ uiApiKey }}";
<pre id="terminal-output" class="pre-scrollable"></pre>
<div class="input-append" style="display: none;" data-bind="visible: loginState.isUser">
<input type="text" id="terminal-command" style="width:88%;" data-bind="value: command, event: { keyup: function(d,e) { return handleKeyUp(e); }, keydown: function(d,e) { return handleKeyDown(e); } }, enable: isOperational() && loginState.isUser()">
<button class="btn" type="button" id="terminal-send" data-bind="click: sendCommand, enable: isOperational() && loginState.isUser()">{{ _('Send') }}</button>
<input type="text" id="terminal-command" style="width:88%;" data-bind="value: command, event: { keyup: function(d,e) { return handleKeyUp(e); }, keydown: function(d,e) { return handleKeyDown(e); } }, enable: (isOperational() || isLocked()) && loginState.isUser()">
<button class="btn" type="button" id="terminal-send" data-bind="click: sendCommand, enable: (isOperational() || isLocked()) && loginState.isUser()">{{ _('Send') }}</button>
</div>
</div>

View file

@ -359,6 +359,106 @@ def gcodeFileCommand(filename, target):
return NO_CONTENT
@api.route("/files/convert", methods=["POST"])
@restricted_access
def gcodeConvertCommand():
target = FileDestinations.LOCAL;
#if not _verifyFileExists(target, filename):
# return make_response("File not found on '%s': %s" % (target, filename), 404)
# valid file commands, dict mapping command name to mandatory parameters
valid_commands = {
"convert": []
}
command, data, response = util.getJsonCommandFromRequest(request, valid_commands)
if response is not None:
return response
import re
svg = data['svg']
#svg = re.sub(r"inkscape:[a-zA-Z_-]+=\".*?\" ", "", svg)
#svg = re.sub(r"sodipodi:[a-zA-Z_-]+=\".*?\" ", "", svg)
del data['svg']
if command == "convert":
print("files.py convert", data)
import os
name, _ = os.path.splitext(data['gcode'])
filename = target + "/" + name + ".svg"
class Wrapper(object):
def __init__(self, filename, content):
self.filename = filename
self.content = content
def save(self, absolute_dest_path):
with open(absolute_dest_path, "w") as d:
d.write(self.content)
d.close()
fileObj = Wrapper(filename, svg)
fileManager.add_file(target, filename, fileObj, links=None, allow_overwrite=True)
#fh = open(filename, 'w')
#fh.write(svg)
#fh.close()
slicer = "svgtogcode";
if "slicer" in data.keys() and data["slicer"]:
slicer = data["slicer"]
del data["slicer"]
slicer_instance = slicingManager.get_slicer(slicer)
if slicer_instance.get_slicer_properties()["same_device"] and (printer.isPrinting() or printer.isPaused()):
# slicer runs on same device as OctoPrint, slicing while printing is hence disabled
return make_response("Cannot convert while lasering due to performance reasons".format(**locals()), 409)
if "gcode" in data.keys() and data["gcode"]:
gcode_name = data["gcode"]
del data["gcode"]
else:
import os
name, _ = os.path.splitext(filename)
gcode_name = name + ".gco"
# prohibit overwriting the file that is currently being printed
currentOrigin, currentFilename = _getCurrentFile()
if currentFilename == gcode_name and currentOrigin == target and (printer.isPrinting() or printer.isPaused()):
make_response("Trying to slice into file that is currently being printed: %s" % gcode_name, 409)
if "profile" in data.keys() and data["profile"]:
profile = data["profile"]
del data["profile"]
else:
profile = None
override_keys = [k for k in data if k.startswith("profile.") and data[k] is not None]
overrides = dict()
for key in override_keys:
overrides[key[len("profile."):]] = data[key]
ok, result = fileManager.slice(slicer, target, filename, target, gcode_name, profile=profile, overrides=overrides)
if ok:
files = {}
location = url_for(".readGcodeFile", target=target, filename=gcode_name, _external=True)
result = {
"name": gcode_name,
"origin": FileDestinations.LOCAL,
"refs": {
"resource": location,
"download": url_for("index", _external=True) + "downloads/files/" + target + "/" + gcode_name
}
}
r = make_response(jsonify(result), 202)
r.headers["Location"] = location
return r
else:
return make_response("Could not slice: {result}".format(result=result), 500)
return NO_CONTENT
@api.route("/files/<string:target>/<path:filename>", methods=["DELETE"])
@restricted_access

View file

@ -212,7 +212,7 @@ def printerBedState():
@api.route("/printer/printhead", methods=["POST"])
@restricted_access
def printerPrintheadCommand():
if not printer.isOperational() or printer.isPrinting():
if not (printer.isOperational() or printer.isLocked()) or printer.isPrinting():
# do not jog when a print job is running or we don't have a connection
return make_response("Printer is not operational or currently printing", 409)
@ -301,7 +301,7 @@ def printerSdState():
@restricted_access
def printerCommand():
# TODO: document me
if not printer.isOperational():
if not (printer.isOperational() or printer.isLocked()):
return make_response("Printer is not operational", 409)
if not "application/json" in request.headers["Content-Type"]:

View file

@ -62,13 +62,13 @@ $(function() {
var settingsViewModel = new SettingsViewModel(loginStateViewModel, usersViewModel);
var connectionViewModel = new ConnectionViewModel(loginStateViewModel, settingsViewModel);
var timelapseViewModel = new TimelapseViewModel(loginStateViewModel);
var printerStateViewModel = new PrinterStateViewModel(loginStateViewModel, timelapseViewModel);
var vectorConversionViewModel = new VectorConversionViewModel(loginStateViewModel, settingsViewModel);
var printerStateViewModel = new PrinterStateViewModel(loginStateViewModel, vectorConversionViewModel);
var appearanceViewModel = new AppearanceViewModel(settingsViewModel);
var temperatureViewModel = new TemperatureViewModel(loginStateViewModel, settingsViewModel);
var controlViewModel = new ControlViewModel(loginStateViewModel, settingsViewModel, printerStateViewModel);
var terminalViewModel = new TerminalViewModel(loginStateViewModel, settingsViewModel);
var slicingViewModel = new SlicingViewModel(loginStateViewModel);
var vectorConversionViewModel = new VectorConversionViewModel(loginStateViewModel, settingsViewModel);
var workingAreaViewModel = new WorkingAreaViewModel(loginStateViewModel, settingsViewModel, printerStateViewModel);
var gcodeFilesViewModel = new GcodeFilesViewModel(printerStateViewModel, loginStateViewModel, slicingViewModel, vectorConversionViewModel, workingAreaViewModel);
var gcodeViewModel = new GcodeViewModel(loginStateViewModel, settingsViewModel);

View file

@ -1,4 +1,4 @@
function PrinterStateViewModel(loginStateViewModel) {
function PrinterStateViewModel(loginStateViewModel, vectorConversionViewModel) {
var self = this;
self.loginState = loginStateViewModel;
@ -32,6 +32,7 @@ function PrinterStateViewModel(loginStateViewModel) {
self.currentHeight = ko.observable(undefined);
self.currentPos = ko.observable(undefined);
self.conversion = vectorConversionViewModel;
self.TITLE_PRINT_BUTTON_PAUSED = gettext("Restarts the print job from the beginning");
@ -240,6 +241,10 @@ function PrinterStateViewModel(loginStateViewModel) {
self.cancel = function() {
self._jobCommand("cancel");
};
self.convertWorkingArea = function(){
self.conversion.show2();
};
self._jobCommand = function(command, callback) {
$.ajax({

View file

@ -10,6 +10,7 @@ function TerminalViewModel(loginStateViewModel, settingsViewModel) {
self.isErrorOrClosed = ko.observable(undefined);
self.isOperational = ko.observable(undefined);
self.isLocked = ko.observable(undefined);
self.isPrinting = ko.observable(undefined);
self.isPaused = ko.observable(undefined);
self.isError = ko.observable(undefined);
@ -56,6 +57,7 @@ function TerminalViewModel(loginStateViewModel, settingsViewModel) {
self._processStateData = function(data) {
self.isErrorOrClosed(data.flags.closedOrError);
self.isOperational(data.flags.operational);
self.isLocked(data.flags.locked);
self.isPaused(data.flags.paused);
self.isPrinting(data.flags.printing);
self.isError(data.flags.error);
@ -70,7 +72,6 @@ function TerminalViewModel(loginStateViewModel, settingsViewModel) {
} else {
self.filterRegex = new RegExp(filterRegexStr);
}
console.log("Terminal filter regex: " + filterRegexStr);
};
self.updateOutput = function() {
@ -97,7 +98,8 @@ function TerminalViewModel(loginStateViewModel, settingsViewModel) {
return;
}
var re = /^([gmt][0-9]+)(\s.*)?/;
//var re = /^([gmt][0-9]+)(\s.*)?/;
var re = /^(([gmtfs][0-9]+)|(\$[cinhgx#$])|([?~!]))(\s.*)?/; // grbl style
var commandMatch = command.match(re);
if (commandMatch != null) {
command = commandMatch[1].toUpperCase() + ((commandMatch[2] !== undefined) ? commandMatch[2] : "");

View file

@ -387,7 +387,7 @@ class MachineCom(object):
cmd = cmd.encode('ascii', 'replace')
if self.isPrinting() and not self.isSdFileSelected():
self._commandQueue.put(cmd)
elif self.isOperational():
elif self.isOperational() or self.isLocked():
self._sendCommand(cmd)
def startPrint(self):
@ -745,11 +745,9 @@ class MachineCom(object):
if("Alarm" in line):
self._changeState(self.STATE_LOCKED)
else:
if(grblMoving):
self._changeState(self.STATE_PRINTING)
else:
self._changeState(self.STATE_OPERATIONAL)
if("Idle" in line):
self._changeState(self.STATE_OPERATIONAL)
parts = line.strip("\r\n").split(":")