From 1491d995cf6d78fd16bc4940fd3cb2d3eaa193c1 Mon Sep 17 00:00:00 2001 From: Teja Date: Sun, 18 Jan 2015 22:33:04 +0100 Subject: [PATCH] slicing works again after dealing with svg namespaces. --- src/octoprint/plugins/svgtogcode/__init__.py | 4 +- .../plugins/svgtogcode/static/js/convert.js | 33 ++++-- .../svgtogcode/static/js/working_area.js | 12 ++- .../templates/override_index.jinja2 | 13 ++- src/octoprint/server/api/files.py | 100 ++++++++++++++++++ src/octoprint/server/api/printer.py | 4 +- src/octoprint/static/js/app/main.js | 4 +- .../static/js/app/viewmodels/printerstate.js | 7 +- .../static/js/app/viewmodels/terminal.js | 6 +- src/octoprint/util/comm.py | 10 +- 10 files changed, 167 insertions(+), 26 deletions(-) diff --git a/src/octoprint/plugins/svgtogcode/__init__.py b/src/octoprint/plugins/svgtogcode/__init__.py index 4875f81c..adbaab48 100644 --- a/src/octoprint/plugins/svgtogcode/__init__.py +++ b/src/octoprint/plugins/svgtogcode/__init__.py @@ -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 diff --git a/src/octoprint/plugins/svgtogcode/static/js/convert.js b/src/octoprint/plugins/svgtogcode/static/js/convert.js index 29092523..aefe1cdd 100644 --- a/src/octoprint/plugins/svgtogcode/static/js/convert.js +++ b/src/octoprint/plugins/svgtogcode/static/js/convert.js @@ -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", diff --git a/src/octoprint/plugins/svgtogcode/static/js/working_area.js b/src/octoprint/plugins/svgtogcode/static/js/working_area.js index 02b7d5d0..ac3baa2f 100644 --- a/src/octoprint/plugins/svgtogcode/static/js/working_area.js +++ b/src/octoprint/plugins/svgtogcode/static/js/working_area.js @@ -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! diff --git a/src/octoprint/plugins/svgtogcode/templates/override_index.jinja2 b/src/octoprint/plugins/svgtogcode/templates/override_index.jinja2 index 65b19ceb..469cd433 100644 --- a/src/octoprint/plugins/svgtogcode/templates/override_index.jinja2 +++ b/src/octoprint/plugins/svgtogcode/templates/override_index.jinja2 @@ -212,12 +212,19 @@ var UI_API_KEY = "{{ uiApiKey }}";
- @@ -360,8 +367,8 @@ var UI_API_KEY = "{{ uiApiKey }}";

 								
 							
 
diff --git a/src/octoprint/server/api/files.py b/src/octoprint/server/api/files.py
index cc01dba7..c1d50161 100644
--- a/src/octoprint/server/api/files.py
+++ b/src/octoprint/server/api/files.py
@@ -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//", methods=["DELETE"])
 @restricted_access
diff --git a/src/octoprint/server/api/printer.py b/src/octoprint/server/api/printer.py
index d52a4f64..0e229526 100644
--- a/src/octoprint/server/api/printer.py
+++ b/src/octoprint/server/api/printer.py
@@ -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"]:
diff --git a/src/octoprint/static/js/app/main.js b/src/octoprint/static/js/app/main.js
index f7250ecb..cd75b5fb 100644
--- a/src/octoprint/static/js/app/main.js
+++ b/src/octoprint/static/js/app/main.js
@@ -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);
diff --git a/src/octoprint/static/js/app/viewmodels/printerstate.js b/src/octoprint/static/js/app/viewmodels/printerstate.js
index b8b6beba..e600086d 100644
--- a/src/octoprint/static/js/app/viewmodels/printerstate.js
+++ b/src/octoprint/static/js/app/viewmodels/printerstate.js
@@ -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({
diff --git a/src/octoprint/static/js/app/viewmodels/terminal.js b/src/octoprint/static/js/app/viewmodels/terminal.js
index edf5841c..6cbf92a4 100644
--- a/src/octoprint/static/js/app/viewmodels/terminal.js
+++ b/src/octoprint/static/js/app/viewmodels/terminal.js
@@ -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] : "");
diff --git a/src/octoprint/util/comm.py b/src/octoprint/util/comm.py
index 6a4161cb..87041b62 100644
--- a/src/octoprint/util/comm.py
+++ b/src/octoprint/util/comm.py
@@ -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(":")