added basic features for using the JS svgtogcode converter
This commit is contained in:
parent
ea591a954e
commit
7b88cddd3e
4 changed files with 134 additions and 61 deletions
|
|
@ -235,7 +235,7 @@ class SvgToGcodePlugin(octoprint.plugin.SlicerPlugin,
|
|||
|
||||
def get_assets(self):
|
||||
return dict(
|
||||
js=[ "js/convert.js", "js/working_area.js", "js/gcode_parser.js", "js/lib/snap.svg-min.js", "js/lib/photobooth_min.js", "js/matrix_oven.js", "js/render_fills.js", "js/drag_scale_rotate.js"],
|
||||
js=[ "js/convert.js", "js/working_area.js", "js/gcode_parser.js", "js/lib/snap.svg-min.js", "js/lib/photobooth_min.js", "js/matrix_oven.js", "js/render_fills.js", "js/drag_scale_rotate.js", "js/svg2gcode.js"],
|
||||
less=["less/svgtogcode.less"],
|
||||
css=["css/svgtogcode.css", "css/mrbeam.css"]
|
||||
)
|
||||
|
|
@ -344,7 +344,7 @@ class SvgToGcodePlugin(octoprint.plugin.SlicerPlugin,
|
|||
if not machinecode_path:
|
||||
path, _ = os.path.splitext(model_path)
|
||||
machinecode_path = path + ".gco"
|
||||
|
||||
|
||||
self._svgtogcode_logger.info("### Slicing %s to %s using profile stored at %s" % (model_path, machinecode_path, profile_path))
|
||||
|
||||
## direct call
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ $(function(){
|
|||
self.profiles = ko.observableArray();
|
||||
self.defaultSlicer = undefined;
|
||||
self.defaultProfile = undefined;
|
||||
|
||||
|
||||
// expert settings
|
||||
self.showHints = ko.observable(false);
|
||||
self.showExpertSettings = ko.observable(false);
|
||||
|
|
@ -37,7 +37,7 @@ $(function(){
|
|||
self.minSpeed = ko.observable(20);
|
||||
self.fill_areas = ko.observable(false);
|
||||
self.show_fill_areas_checkbox = ko.observable(false);
|
||||
|
||||
|
||||
// image engraving stuff
|
||||
// preset values are a good start for wood engraving
|
||||
self.images_placed = ko.observable(false);
|
||||
|
|
@ -46,16 +46,16 @@ $(function(){
|
|||
});
|
||||
self.imgIntensityWhite = ko.observable(0);
|
||||
self.imgIntensityBlack = ko.observable(500);
|
||||
self.imgFeedrateWhite = ko.observable(1500);
|
||||
self.imgFeedrateWhite = ko.observable(1500);
|
||||
self.imgFeedrateBlack = ko.observable(250);
|
||||
self.imgDithering = ko.observable(false);
|
||||
self.imgSharpening = ko.observable(1);
|
||||
self.imgContrast = ko.observable(1);
|
||||
self.beamDiameter = ko.observable(0.2);
|
||||
|
||||
|
||||
self.sharpeningMax = 25;
|
||||
self.contrastMax = 2;
|
||||
|
||||
|
||||
// preprocessing preview ... returns opacity 0.0 - 1.0
|
||||
self.sharpenedPreview = ko.computed(function(){
|
||||
if(self.imgDithering()) return 0;
|
||||
|
|
@ -73,7 +73,6 @@ $(function(){
|
|||
return contrastPercents - sharpeningPercents/2;
|
||||
}
|
||||
}, self);
|
||||
|
||||
|
||||
self.maxSpeed.subscribe(function(val){
|
||||
self._configureFeedrateSlider();
|
||||
|
|
@ -91,7 +90,7 @@ $(function(){
|
|||
if(self.laserIntensity() === undefined){
|
||||
var intensity = self.settings.settings.plugins.svgtogcode.defaultIntensity();
|
||||
self.laserIntensity(intensity);
|
||||
}
|
||||
}
|
||||
if(self.laserSpeed() === undefined){
|
||||
var speed = self.settings.settings.plugins.svgtogcode.defaultFeedrate();
|
||||
self.laserSpeed(speed);
|
||||
|
|
@ -107,7 +106,7 @@ $(function(){
|
|||
self.convert();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
self.cancel_conversion = function(){
|
||||
if(self.slicing_in_progress()){
|
||||
//console.log('cancel slicing', self.slicing_in_progress());
|
||||
|
|
@ -139,14 +138,14 @@ $(function(){
|
|||
if(uniqueDesigns > 1){
|
||||
gcode_name += "_"+(uniqueDesigns-1)+"more";
|
||||
}
|
||||
|
||||
|
||||
return gcode_name;
|
||||
} else {
|
||||
} else {
|
||||
console.error("no designs placed.");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
self.settingsString = ko.computed(function(){
|
||||
var intensity = self.laserIntensity();
|
||||
var feedrate = self.laserSpeed();
|
||||
|
|
@ -248,7 +247,7 @@ $(function(){
|
|||
} else {
|
||||
self.slicing_in_progress(true);
|
||||
self.workingArea.getCompositionSVG(self.fill_areas(), function(composition){
|
||||
self.svg = composition;
|
||||
self.svg = composition;
|
||||
var filename = self.gcodeFilename() + self.settingsString() + '.gco';
|
||||
var gcodeFilename = self._sanitize(filename);
|
||||
|
||||
|
|
@ -279,6 +278,10 @@ $(function(){
|
|||
data.gcodeFilesToAppend = self.gcodeFilesToAppend;
|
||||
}
|
||||
|
||||
var snapelement = snap.select("#userContent");
|
||||
snapelement.bake(false, 5);
|
||||
data.gcodedata = snapelement.toGcode();
|
||||
|
||||
$.ajax({
|
||||
url: API_BASEURL + "files/convert",
|
||||
type: "POST",
|
||||
|
|
@ -286,7 +289,6 @@ $(function(){
|
|||
contentType: "application/json; charset=UTF-8",
|
||||
data: JSON.stringify(data)
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -303,7 +305,7 @@ $(function(){
|
|||
self._configureFeedrateSlider();
|
||||
self._configureImgSliders();
|
||||
};
|
||||
|
||||
|
||||
self.onSlicingProgress = function(slicer, model_path, machinecode_path, progress){
|
||||
self.slicing_progress(progress);
|
||||
};
|
||||
|
|
@ -389,7 +391,7 @@ $(function(){
|
|||
self._calcRealSpeed = function(sliderVal){
|
||||
return Math.round(self.minSpeed() + sliderVal/100 * (self.maxSpeed() - self.minSpeed()));
|
||||
};
|
||||
|
||||
|
||||
self._configureImgSliders = function() {
|
||||
self.contrastSlider = $("#svgtogcode_contrast_slider").slider({
|
||||
step: .1,
|
||||
|
|
@ -400,7 +402,7 @@ $(function(){
|
|||
}).on("slide", function(ev){
|
||||
self.imgContrast(ev.value);
|
||||
});
|
||||
|
||||
|
||||
self.sharpeningSlider = $("#svgtogcode_sharpening_slider").slider({
|
||||
step: 1,
|
||||
min: 1,
|
||||
|
|
@ -419,9 +421,9 @@ $(function(){
|
|||
});
|
||||
|
||||
}
|
||||
|
||||
ADDITIONAL_VIEWMODELS.push([VectorConversionViewModel,
|
||||
["loginStateViewModel", "settingsViewModel", "printerStateViewModel", "workingAreaViewModel", "gcodeFilesViewModel"],
|
||||
|
||||
ADDITIONAL_VIEWMODELS.push([VectorConversionViewModel,
|
||||
["loginStateViewModel", "settingsViewModel", "printerStateViewModel", "workingAreaViewModel", "gcodeFilesViewModel"],
|
||||
document.getElementById("dialog_vector_graphics_conversion")]);
|
||||
|
||||
|
||||
});
|
||||
|
|
|
|||
66
src/octoprint/plugins/svgtogcode/static/js/svg2gcode.js
Normal file
66
src/octoprint/plugins/svgtogcode/static/js/svg2gcode.js
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
Snap.plugin(function (Snap, Element, Paper, global) {
|
||||
/**
|
||||
* generates and returns the svg as gcode
|
||||
*
|
||||
* @param {integer} variablename : description
|
||||
* @returns {list of gcode}
|
||||
*/
|
||||
Element.prototype.toGcode = function () {
|
||||
var gCodeList = [];
|
||||
var elem = this.selectAll("path");
|
||||
for (var i = 0; i < elem.length; i++) {
|
||||
gCodeList.push(elem[i].pathStringToGCode());
|
||||
}
|
||||
return gCodeList;
|
||||
}
|
||||
|
||||
Element.prototype.pathStringToGCode = function () {
|
||||
if (this.type !== "path") {
|
||||
return this;
|
||||
}
|
||||
var gcode = []
|
||||
var startP = [0, 0]
|
||||
var lastP = [0, 0]
|
||||
var arr = Snap.parsePathString(this.realPath);
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
if (arr[i][0] == "M") {
|
||||
gcode.push("G0X" + arr[i][1] + "Y" + arr[i][2]);
|
||||
startP = [arr[i][1], arr[i][2]];
|
||||
lastP = [arr[i][1], arr[i][2]];
|
||||
} else if (arr[i][0] == "L") {
|
||||
gcode.push("G1X" + arr[i][1] + "Y" + arr[i][2]);
|
||||
lastP = [arr[i][1], arr[i][2]];
|
||||
} else if (arr[i][0] == "H") {
|
||||
gcode.push("H");
|
||||
} else if (arr[i][0] == "V") {
|
||||
gcode.push("V");
|
||||
} else if (arr[i][0] == "C") {
|
||||
var x0 = lastP[0];
|
||||
var y0 = lastP[1];
|
||||
var x1 = arr[i][1];
|
||||
var y1 = arr[i][2];
|
||||
var x2 = arr[i][3];
|
||||
var y2 = arr[i][4];
|
||||
var x3 = arr[i][5];
|
||||
var y3 = arr[i][6];
|
||||
var tmp = Snap.path.getTotalLength("M" + lastP[0] + "," + lastP[1] + arr[i][0] + arr[i][1] + "," + arr[i][2] + "," + arr[i][3] + "," + arr[i][4] + "," + arr[i][5] + "," + arr[i][6]);
|
||||
var range = Math.round(tmp) * 10;
|
||||
for (var t = 1; t <= range; t++) {
|
||||
obj = Snap.path.findDotsAtSegment(x0, y0, x1, y1, x2, y2, x3, y3, t / range)
|
||||
gcode.push("G1X" + Math.round(obj.x * 100) / 100 + "Y" + Math.round(obj.y * 100) / 100);
|
||||
}
|
||||
lastP = [arr[i][5], arr[i][6]];
|
||||
} else if (arr[i][0] == "Q") {
|
||||
gcode.push("NOT_IMPLEMENTED");
|
||||
} else if (arr[i][0] == "A") {
|
||||
gcode.push("NOT_IMPLEMENTED");
|
||||
} else if (arr[i][0] == "Z") {
|
||||
if (lastP[0] != startP[0] && lastP[1] != startP[1]) {
|
||||
gcode.push("G1X" + startP[0] + "Y" + startP[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
//console.log(gcode.join("\n").length)
|
||||
return gcode.join("\n");
|
||||
}
|
||||
});
|
||||
|
|
@ -13,7 +13,7 @@ from octoprint.settings import settings, valid_boolean_trues
|
|||
from octoprint.server import printer, fileManager, slicingManager, eventManager, NO_CONTENT
|
||||
from octoprint.server.util.flask import restricted_access, get_json_command_from_request
|
||||
from octoprint.server.api import api
|
||||
from octoprint.events import Events
|
||||
from octoprint.events import eventManager, Events
|
||||
import octoprint.filemanager
|
||||
import shutil
|
||||
import octoprint.filemanager.util
|
||||
|
|
@ -419,7 +419,7 @@ def gcodeFileCommand(filename, target):
|
|||
@restricted_access
|
||||
def gcodeConvertCommand():
|
||||
target = FileDestinations.LOCAL;
|
||||
|
||||
|
||||
# valid file commands, dict mapping command name to mandatory parameters
|
||||
valid_commands = {
|
||||
"convert": []
|
||||
|
|
@ -427,14 +427,14 @@ def gcodeConvertCommand():
|
|||
command, data, response = get_json_command_from_request(request, valid_commands)
|
||||
if response is not None:
|
||||
return response
|
||||
|
||||
|
||||
appendGcodeFiles = data['gcodeFilesToAppend']
|
||||
del data['gcodeFilesToAppend']
|
||||
|
||||
|
||||
# def appendCallback(location, path, sources, **kwargs):
|
||||
# if '_error' in kwargs:
|
||||
# result = kwargs['_error']
|
||||
# return make_response("Could not slice: {result}".format(result=result), 500)
|
||||
# return make_response("Could not slice: {result}".format(result=result), 500)
|
||||
# else:
|
||||
# output_path = fileManager.path_on_disk(location, path)
|
||||
# # append additioal gcodes
|
||||
|
|
@ -461,18 +461,16 @@ def gcodeConvertCommand():
|
|||
# #r = make_response(jsonify(result), 202)
|
||||
# #r.headers["Location"] = location
|
||||
# #return r
|
||||
|
||||
|
||||
|
||||
if command == "convert":
|
||||
# TODO stripping non-ascii is a hack - svg contains lots of non-ascii in <text> tags. Fix this!
|
||||
import re
|
||||
svg = ''.join(i for i in data['svg'] if ord(i)<128) # strip non-ascii chars like €
|
||||
del data['svg']
|
||||
|
||||
svg = ''.join(i for i in data['svg'] if ord(i)<128) # strip non-ascii chars like €
|
||||
del data['svg']
|
||||
|
||||
import os
|
||||
name, _ = os.path.splitext(data['gcode'])
|
||||
|
||||
|
||||
filename = target + "/temp.svg"
|
||||
class Wrapper(object):
|
||||
def __init__(self, filename, content):
|
||||
|
|
@ -486,7 +484,7 @@ def gcodeConvertCommand():
|
|||
|
||||
fileObj = Wrapper(filename, svg)
|
||||
fileManager.add_file(target, filename, fileObj, links=None, allow_overwrite=True)
|
||||
|
||||
|
||||
slicer = "svgtogcode";
|
||||
slicer_instance = slicingManager.get_slicer(slicer)
|
||||
if slicer_instance.get_slicer_properties()["same_device"] and (printer.is_printing() or printer.is_paused()):
|
||||
|
|
@ -500,7 +498,7 @@ def gcodeConvertCommand():
|
|||
import os
|
||||
name, _ = os.path.splitext(filename)
|
||||
gcode_name = name + ".gco"
|
||||
|
||||
|
||||
# append number if file exists
|
||||
name, ext = os.path.splitext(gcode_name)
|
||||
i = 1;
|
||||
|
|
@ -518,7 +516,7 @@ def gcodeConvertCommand():
|
|||
del data["profile"]
|
||||
else:
|
||||
profile = None
|
||||
##
|
||||
|
||||
if "printerProfile" in data.keys() and data["printerProfile"]:
|
||||
printerProfile = data["printerProfile"]
|
||||
del data["printerProfile"]
|
||||
|
|
@ -530,7 +528,7 @@ def gcodeConvertCommand():
|
|||
del data["position"]
|
||||
else:
|
||||
position = None
|
||||
|
||||
|
||||
select_after_slicing = False
|
||||
if "select" in data.keys() and data["select"] in valid_boolean_trues:
|
||||
if not printer.is_operational():
|
||||
|
|
@ -548,34 +546,41 @@ def gcodeConvertCommand():
|
|||
for key in override_keys:
|
||||
overrides[key[len("profile."):]] = data[key]
|
||||
|
||||
def slicing_done(target, gcode_name, select_after_slicing, print_after_slicing, append_these_files):
|
||||
# append additioal gcodes
|
||||
if data.has_key('gcodedata'):
|
||||
output_path = fileManager.path_on_disk(target, gcode_name)
|
||||
with open(output_path,'ab') as wfd:
|
||||
for f in append_these_files:
|
||||
path = fileManager.path_on_disk(f['origin'], f['name'])
|
||||
wfd.write( "\n; "+ f['name'] + "\n")
|
||||
with open(output_path,'wb') as wfd:
|
||||
for line in data['gcodedata']:
|
||||
wfd.write(line)
|
||||
eventManager().fire(Events.SLICING_DONE, {"stl": filename, "gcode": gcode_name, "gcode_location": target, "time": 1.0})
|
||||
else:
|
||||
def slicing_done(target, gcode_name, select_after_slicing, print_after_slicing, append_these_files):
|
||||
# append additioal gcodes
|
||||
output_path = fileManager.path_on_disk(target, gcode_name)
|
||||
with open(output_path,'ab') as wfd:
|
||||
for f in append_these_files:
|
||||
path = fileManager.path_on_disk(f['origin'], f['name'])
|
||||
wfd.write( "\n; "+ f['name'] + "\n")
|
||||
|
||||
with open(path,'rb') as fd:
|
||||
shutil.copyfileobj(fd, wfd, 1024*1024*10)
|
||||
with open(path,'rb') as fd:
|
||||
shutil.copyfileobj(fd, wfd, 1024*1024*10)
|
||||
|
||||
wfd.write( "\nM05\n") # ensure that the laser is off.
|
||||
wfd.write( "\nM05\n") # ensure that the laser is off.
|
||||
|
||||
if select_after_slicing or print_after_slicing:
|
||||
sd = False
|
||||
filenameToSelect = fileManager.path_on_disk(target, gcode_name)
|
||||
printer.select_file(filenameToSelect, sd, True)
|
||||
if select_after_slicing or print_after_slicing:
|
||||
sd = False
|
||||
filenameToSelect = fileManager.path_on_disk(target, gcode_name)
|
||||
printer.select_file(filenameToSelect, sd, True)
|
||||
|
||||
try:
|
||||
fileManager.slice(slicer, target, filename, target, gcode_name,
|
||||
profile=profile,
|
||||
printer_profile_id=printerProfile,
|
||||
position=position,
|
||||
overrides=overrides,
|
||||
callback=slicing_done,
|
||||
callback_args=[target, gcode_name, select_after_slicing, print_after_slicing, appendGcodeFiles])
|
||||
except octoprint.slicing.UnknownProfile:
|
||||
return make_response("Profile {profile} doesn't exist".format(**locals()), 400)
|
||||
try:
|
||||
fileManager.slice(slicer, target, filename, target, gcode_name,
|
||||
profile=profile,
|
||||
printer_profile_id=printerProfile,
|
||||
position=position,
|
||||
overrides=overrides,
|
||||
callback=slicing_done,
|
||||
callback_args=[target, gcode_name, select_after_slicing, print_after_slicing, appendGcodeFiles])
|
||||
except octoprint.slicing.UnknownProfile:
|
||||
return make_response("Profile {profile} doesn't exist".format(**locals()), 400)
|
||||
|
||||
files = {}
|
||||
location = url_for(".readGcodeFile", target=target, filename=gcode_name, _external=True)
|
||||
|
|
@ -593,7 +598,7 @@ def gcodeConvertCommand():
|
|||
return r
|
||||
|
||||
return NO_CONTENT
|
||||
|
||||
|
||||
|
||||
@api.route("/files/<string:target>/<path:filename>", methods=["DELETE"])
|
||||
@restricted_access
|
||||
|
|
|
|||
Loading…
Reference in a new issue