Compare commits

..

60 commits

Author SHA1 Message Date
ceca65577c
Update mrbeam_index.jinja2 2018-06-29 01:29:29 +02:00
47cd5345e8
mr drawification 2018-06-29 01:12:06 +02:00
3a24067560
Update README.md 2018-06-29 01:04:49 +02:00
make-ing
ff8b77500b changed pull command in git-pull.py script to fix my github delete repo fuck up. 2017-01-20 11:30:05 +01:00
make-ing
39c8f7886a chrome vs. firefox bugfix... Maybe needs further check to see if it can be simplyfied. Maybe use other values etc... 2016-10-04 13:03:35 +02:00
Florian
eb5e7408a9 Merge pull request #80 from mrbeam/mrbeam-dev
July Release
2016-07-06 15:08:57 +02:00
clemniem
0e346add14 #77 fixed
dataURL needed to be encoded correctly for non latin1

- rephrasing of popup for DPI conversion (Illustrator)
2016-07-06 12:11:53 +02:00
clemniem
5a696e01fa - cleanup of code 2016-07-01 12:42:40 +02:00
clemniem
9311463cfa - remove text deleted (again)
- clippath text edited
2016-07-01 12:35:32 +02:00
Florian
b19477dcfb Merge pull request #74 from mrbeam/stable-1.2.2
bux fixing issue #67: Chrome now treats the event target attributes l…
2016-07-01 10:18:32 +02:00
Clem
75f69dd0df Merge pull request #73 from mrbeam/mrbeam-dev-textInSvg
Mrbeam dev text in svg
2016-07-01 10:10:31 +02:00
clemniem
793b009ab6 popup dialoge informing user about the handling of text elements in SVG that have been detected 2016-06-30 17:45:41 +02:00
clemniem
e366b4c805 popup shows always laser infill if text is in userContent. 2016-06-30 17:31:07 +02:00
make-ing
bcfa42a034 changed back to the correct grbl.hex file 2016-06-24 10:39:38 +02:00
clemniem
6c44d8e243 added text to infill conversion, text will be treated like an image and always engraved. 2016-06-23 16:51:50 +02:00
make-ing
24cebced83 removed the xml stuff which magically appeared a previous commit 2016-06-23 15:49:47 +02:00
clemniem
8e02a97a61 added text to infill conversion, test 2 2016-06-23 14:53:04 +02:00
clemniem
4cb819fd7b added text to infill conversion 2016-06-23 14:43:04 +02:00
clemniem
3ffdceb5af fixed conversion dialog, added second checkbox for text_fills, no real functionality added yet 2016-06-23 14:09:39 +02:00
clemniem
fffc0c4ecb excluded text from being jumped over, because it is not on the paper 2016-06-23 11:04:22 +02:00
make-ing
1966a8b68c fixed #28: select all elements with attribute "display=none" and remove them. 2016-06-21 16:20:41 +02:00
clemniem
aad5efff2d WIP show text after upload in svg.
missing:
- add warning/dialogue about text in conversion dialogue
- cleanup
2016-06-21 15:13:36 +02:00
make-ing
f486a24914 fixed the DPI settings not working Problem, and added a PNotify messsage if an Illustrator comment is detected. 2016-06-21 13:44:19 +02:00
make-ing
179d2571ee Merge remote-tracking branch 'origin/mrbeam-dev' into mrbeam-dev 2016-06-21 09:49:29 +02:00
make-ing
074140bcd0 removed "?" from position commands to avoid aditional "ok" response and mazbe problems with advanced character counting. 2016-06-21 09:49:04 +02:00
clemniem
6641390620 resolved #69
rectangles are now removed after pressing clear button
2016-06-20 11:26:08 +02:00
make-ing
12a3f092e2 fixed problem when svg elements contain mm units, by converting them to pixel with a fixed dpi of 90. 2016-06-17 14:18:44 +02:00
make-ing
25be52587e fixed problem when xml tag in svg file is missing. 2016-06-17 12:02:56 +02:00
make-ing
3bbdd702db added functionality to remove comments ahead of time to remove the progress bar bug on gcode files with embeded (base64) images. 2016-06-15 11:30:53 +02:00
make-ing
0c5804e51a added functionality to remove all clipPath elements from svg into the placeSVG function 2016-06-02 18:12:50 +02:00
make-ing
36837246fe Merge branch 'mrbeam' into mrbeam-dev 2016-06-02 15:28:11 +02:00
make-ing
2c416eafc2 added functionality to unlock the GUI when grbl is also unlocked with "$x" command 2016-06-02 14:43:20 +02:00
make-ing
16d2e18daa bux fixing issue #67: Chrome now treats the event target attributes like Firefox, so no need for distinction anymore.
(cherry picked from commit 3128ac7)
2016-05-27 18:27:13 +02:00
make-ing
3128ac7765 bux fixing issue #67: Chrome now treats the event target attributes like Firefox, so no need for distinction anymore. 2016-05-27 18:17:39 +02:00
clemniem
6ffcaabbeb bugfix #64 renamed update notification to mention mrbeam 2016-05-25 16:04:39 +02:00
make-ing
48f5b659e1 changed back last commit 2016-05-04 16:35:55 +02:00
make-ing
9e95f49461 changed to new grbl.hex file 2016-05-04 16:23:43 +02:00
make-ing
64763e8ce1 added version check again... was missing since the change to comm_acc2.py 2016-05-02 09:57:58 +02:00
make-ing
e7fcb5b228 Merge branch 'nativeserial' into mrbeam 2016-04-18 17:16:28 +02:00
make-ing
020073f3ae Merge branch 'mrbeam' into stable-1.2.2 2016-04-18 14:44:52 +02:00
make-ing
c0e4f123ff Firefox bug fixes 2016-04-18 11:35:28 +02:00
make-ing
94c673473b Merge branch 'mrbeam' into stable-1.2.2 2016-04-15 16:00:28 +02:00
make-ing
974094b907 changed "toElement" to "target" for better cross browser compatibility 2016-04-15 15:53:48 +02:00
make-ing
dc23dac20c fix for the chrome 50 changes where they removed the SVGElement.offset* attributes. 2016-04-15 15:42:04 +02:00
make-ing
ba2716f968 added the Raspberry Pi native serial port ttyAMA* to serialList function 2016-04-13 12:09:39 +02:00
make-ing
a0e685ef1c fixed reset of finished passes bug. 2016-03-21 12:45:50 +01:00
make-ing
cfacbe2610 Merge branch 'stable-1.2.2' into mrbeam-multipass
Conflicts:
	src/octoprint/static/js/app/viewmodels/printerstate.js
	src/octoprint/util/comm_acc2.py
2016-03-18 13:38:05 +01:00
make-ing
4da0c3dbe0 added number of passes reset on print start 2016-03-18 13:33:57 +01:00
make-ing
a1d9d2ea7b moved reset override slider functionality to separate method.
(cherry picked from commit e5c600e)
2016-03-18 13:28:40 +01:00
make-ing
3201053e16 added multi passes support in backend 2016-03-18 12:24:41 +01:00
make-ing
e5c600e972 moved reset override slider functionality to separate method. 2016-03-17 09:59:49 +01:00
make-ing
d7b5fae614 fixed wrong feedrate and intensity slider bug. On every new print start the sliders are set back to 100%. 2016-03-16 14:16:15 +01:00
make-ing
bf4c9c2105 fixed bug within placeIMG where the picture was to high to fit into the workspace area. 2016-03-15 17:11:54 +01:00
make-ing
3db371fbb0 added feedrate and intesity reset at beginning of each laser job. 2016-03-14 15:15:13 +01:00
make-ing
064cd33455 merged with mrbeam branch 2016-02-22 12:11:34 +01:00
make-ing
e54364a45c parenthesis bug fixed 2016-02-22 10:54:29 +01:00
make-ing
327ac869ce added support for embedded images in svg via "href" and "xlink:href" 2016-02-22 10:37:20 +01:00
make-ing
60fb13faa2 fixed bug with embedded images in svg's 2016-02-17 16:17:45 +01:00
make-ing
94effaeda7 fixed wrong positioning if only x2 value was to out of bounds maybe also need to be tested for y direction 2016-02-16 13:54:39 +01:00
make-ing
17f29984e5 fixed image bug with missing {} 2016-02-16 12:53:20 +01:00
31 changed files with 2118 additions and 2134 deletions

View file

@ -1,5 +1,6 @@
OctoPrint OctoPrint
========= =========
What I did was take the MrBeam fork of Octoprint (because I have a MrBeam, and I like it) - and modify it for pen plotting with an axidraw v3 clone.
[![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=foosel&url=https://github.com/foosel/OctoPrint&title=OctoPrint&language=&tags=github&category=software) [![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=foosel&url=https://github.com/foosel/OctoPrint&title=OctoPrint&language=&tags=github&category=software)

File diff suppressed because it is too large Load diff

View file

@ -97,7 +97,7 @@ def update_source(git_executable, folder, target, force=False):
raise RuntimeError("Could not update, \"git reset --hard\" failed with returncode %d: %s" % (returncode, stdout)) raise RuntimeError("Could not update, \"git reset --hard\" failed with returncode %d: %s" % (returncode, stdout))
print(">>> Running: git pull") print(">>> Running: git pull")
returncode, stdout = _git(["pull"], folder, git_executable=git_executable) returncode, stdout = _git(["pull", "origin", "stable-1.2.2"], folder, git_executable=git_executable)
if returncode != 0: if returncode != 0:
raise RuntimeError("Could not update, \"git pull\" failed with returncode %d: %s" % (returncode, stdout)) raise RuntimeError("Could not update, \"git pull\" failed with returncode %d: %s" % (returncode, stdout))
print(stdout) print(stdout)

View file

@ -158,7 +158,7 @@ $(function() {
text += "<small>" + gettext("Those components marked with <i class=\"icon-ok\"></i> can be updated directly.") + "</small>"; text += "<small>" + gettext("Those components marked with <i class=\"icon-ok\"></i> can be updated directly.") + "</small>";
var options = { var options = {
title: gettext("Update Available"), title: gettext("Mr Beam Update Available"),
text: text, text: text,
hide: false hide: false
}; };

View file

@ -235,7 +235,7 @@ class SvgToGcodePlugin(octoprint.plugin.SlicerPlugin,
def get_assets(self): def get_assets(self):
return dict( 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/extrude.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"],
less=["less/svgtogcode.less"], less=["less/svgtogcode.less"],
css=["css/svgtogcode.css", "css/mrbeam.css"] css=["css/svgtogcode.css", "css/mrbeam.css"]
) )
@ -270,7 +270,7 @@ class SvgToGcodePlugin(octoprint.plugin.SlicerPlugin,
feedrate = max(1,data["defaultFeedrate"]) feedrate = max(1,data["defaultFeedrate"])
s.set(["defaultFeedrate"], feedrate) s.set(["defaultFeedrate"], feedrate)
if "svgDPI" in data and data["svgDPI"]: if "svgDPI" in data and data["svgDPI"]:
s.set(["svgDPI"], data["svgDPI"]) s.set_int(["svgDPI"], data["svgDPI"])
if "debug_logging" in data: if "debug_logging" in data:
old_debug_logging = s.get_boolean(["debug_logging"]) old_debug_logging = s.get_boolean(["debug_logging"])
new_debug_logging = data["debug_logging"] in octoprint.settings.valid_boolean_trues new_debug_logging = data["debug_logging"] in octoprint.settings.valid_boolean_trues
@ -344,7 +344,7 @@ class SvgToGcodePlugin(octoprint.plugin.SlicerPlugin,
if not machinecode_path: if not machinecode_path:
path, _ = os.path.splitext(model_path) path, _ = os.path.splitext(model_path)
machinecode_path = path + ".gco" machinecode_path = path + ".gco"
self._svgtogcode_logger.info("### Slicing %s to %s using profile stored at %s" % (model_path, machinecode_path, profile_path)) self._svgtogcode_logger.info("### Slicing %s to %s using profile stored at %s" % (model_path, machinecode_path, profile_path))
## direct call ## direct call
@ -357,6 +357,8 @@ class SvgToGcodePlugin(octoprint.plugin.SlicerPlugin,
converter_path = '/home/teja/workspace/mrbeam-inkscape-ext' converter_path = '/home/teja/workspace/mrbeam-inkscape-ext'
elif("denkbrett" in hostname): elif("denkbrett" in hostname):
converter_path = '/home/flo/mrbeam/git/mrbeam-inkscape-ext' converter_path = '/home/flo/mrbeam/git/mrbeam-inkscape-ext'
elif ("clems-Air" in hostname):
converter_path = '/Users/clem/Dropbox/mrBeam/mrbeam-inkscape-ext'
import sys import sys
sys.path.append(converter_path) sys.path.append(converter_path)

View file

@ -16,7 +16,7 @@ defaults = dict(
# general settings # general settings
svgDPI = 90, svgDPI = 90,
pierce_time = 0, pierce_time = 0,
# vector settings # vector settings
speed = 300, speed = 300,
intensity = 500, intensity = 500,
@ -24,7 +24,7 @@ defaults = dict(
cross_fill = False, cross_fill = False,
fill_angle = 0, fill_angle = 0,
fill_spacing = 0.25, fill_spacing = 0.25,
# pixel settings # pixel settings
beam_diameter = 0.25, beam_diameter = 0.25,
intensity_white = 0, intensity_white = 0,
@ -251,8 +251,8 @@ class Profile(object):
} }
return settings return settings
def convert_to_engine2(self): def convert_to_engine2(self):
settings = { settings = {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8 MiB

View file

@ -41,8 +41,10 @@ $(function(){
// image engraving stuff // image engraving stuff
// preset values are a good start for wood engraving // preset values are a good start for wood engraving
self.images_placed = ko.observable(false); self.images_placed = ko.observable(false);
self.text_placed = ko.observable(false);
self.show_image_parameters = ko.computed(function(){ self.show_image_parameters = ko.computed(function(){
return self.images_placed() || (self.fill_areas() && self.show_vector_parameters()); return (self.images_placed() || self.text_placed()
|| (self.fill_areas() && self.show_vector_parameters()));
}); });
self.imgIntensityWhite = ko.observable(0); self.imgIntensityWhite = ko.observable(0);
self.imgIntensityBlack = ko.observable(500); self.imgIntensityBlack = ko.observable(500);
@ -85,6 +87,7 @@ $(function(){
self.show_vector_parameters(self.workingArea.getPlacedSvgs().length > 0); self.show_vector_parameters(self.workingArea.getPlacedSvgs().length > 0);
self.show_fill_areas_checkbox(self.workingArea.hasFilledVectors()) self.show_fill_areas_checkbox(self.workingArea.hasFilledVectors())
self.images_placed(self.workingArea.getPlacedImages().length > 0); self.images_placed(self.workingArea.getPlacedImages().length > 0);
self.text_placed(self.workingArea.hasTextItems());
//self.show_image_parameters(self.workingArea.getPlacedImages().length > 0); //self.show_image_parameters(self.workingArea.getPlacedImages().length > 0);
if(self.show_vector_parameters() || self.show_image_parameters()){ if(self.show_vector_parameters() || self.show_image_parameters()){

View file

@ -1,158 +0,0 @@
// extrude.js - a snapsvg.io plugin to generate extrusion walls of svg paths.
// Copyright (C) 2016 Teja Philipp <osd@tejaphilipp.de>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
Snap.plugin(function (Snap, Element, Paper, global) {
/**
* @param {elem} elem start point
*
* @returns {path}
*/
Element.prototype.extrude = function(height, perforation_curvature_threshold){
var subdiv_length = 1;
var material_thickness = 1;
var perforation_curvature_threshold = perforation_curvature_threshold || 5;
var elem = this;
var walls = [];
var children = elem.children();
if (children.length > 0) {
var goRecursive = (elem.type !== "defs" && // ignore these tags
elem.type !== "clipPath" &&
elem.type !== "metadata" &&
elem.type !== "rdf:rdf" &&
elem.type !== "cc:work" &&
elem.type !== "sodipodi:namedview");
if(goRecursive) {
for (var i = 0; i < children.length; i++) {
var child = children[i];
var more = child.extrude(height);
walls.push.apply(walls, more);
}
}
} else {
var e;
if (elem.type !== "path"){
console.log('converting element to path', elem.type);
e = elem.toPath();
} else {
e = elem;
}
var dOriginal = e.attr('d');
var parts = Snap.path.toRelative(dOriginal).toString();
var segments = parts.split('m');
console.log('d',dOriginal);
for (var i = 0; i < segments.length; i++) {
if(segments[i].trim() !== ''){
var seg = 'M' + segments[i];
var l = Snap.path.getTotalLength(seg);
console.log("segment", seg, l);
walls.push(createWrappingPath2(seg), height);
}
}
//walls.push( createWrappingPath(segments, height));
}
return walls;
};
function createWrappingPath2(segment, height){
var l = Snap.path.getTotalLength(segment);
console.log(segment, l);
// create "rectangle"
var rect_d = "m0,0 l"+l+',0' // top
+ ' l0,'+height // right
+ ' l-'+l+',0' // bottom
+ ' l0,-'+height; // left
var perforations = getPerforations(segment, 5);
var perf_d = [];
for (var i = 0; i < perforations.length; i++) {
var perf = perforations[i];
var density = 0.8 * perf.curvature/90;
perf_d.push(createVerticalPerforation(perf.loc,height,density, height/10));
}
return rect_d+perf_d.join(',');
}
function getPerforations(d, perf_curvature_threshold){
var stepSize = 1;
var perfs = [];
var e = snap.path(d)
var l = e.getTotalLength();
var i = 0;
var last_alpha = -999;
var curvature_sum = 0;
while(i<l){
var p = e.getPointAtLength(i);
p.curvature = last_alpha - p.alpha;
p.loc = i;
curvature_sum += p.curvature;
last_alpha = p.alpha;
if(Math.abs(curvature_sum) > perf_curvature_threshold){
perfs.push({loc:i, curve:p.curvature});
curvature_sum = 0;
}
i+=stepSize;
}
return perfs;
}
function createWrappingPath(divs, height){
var upper_d = "M0,0";
var lower_d = "M0,"+height;
var verticals = ['M0,0l0,'+height];
for (var i = 0; i < divs.length; i++) {
var d = divs[i];
var x = d.loc.toFixed(2);
upper_d += 'L'+x+',0';
lower_d += 'L'+x+','+height;
var density = 0.8* d.curvature/180;
verticals.push(createVerticalPerforation(x,height, density, height/15));
}
return upper_d+lower_d+verticals.join();
}
function createVerticalPerforation(x, height, density, perfLength){
var cut = (perfLength * (density)).toFixed(2);
var gap = (perfLength - cut).toFixed(2);
var d = 'M'+x+',0';
var y = 0;
while(y < height){
d += 'l0,'+cut+'m0,'+gap;
y += perfLength;
}
return d;
}
});

View file

@ -1,7 +1,7 @@
// Matrix Oven - a snapsvg.io plugin to apply & remove transformations from svg files. // Matrix Oven - a snapsvg.io plugin to apply & remove transformations from svg files.
// Copyright (C) 2015 Teja Philipp <osd@tejaphilipp.de> // Copyright (C) 2015 Teja Philipp <osd@tejaphilipp.de>
// //
// based on work by https://gist.github.com/timo22345/9413158 // based on work by https://gist.github.com/timo22345/9413158
// and https://github.com/duopixel/Method-Draw/blob/master/editor/src/svgcanvas.js // and https://github.com/duopixel/Method-Draw/blob/master/editor/src/svgcanvas.js
// //
// This program is free software: you can redistribute it and/or modify // This program is free software: you can redistribute it and/or modify
@ -20,24 +20,25 @@
Snap.plugin(function (Snap, Element, Paper, global) { Snap.plugin(function (Snap, Element, Paper, global) {
/** /**
* bakes transformations of the element and all sub-elements into coordinates * bakes transformations of the element and all sub-elements into coordinates
* *
* @param {boolean} toCubics : use only cubic path segments * @param {boolean} toCubics : use only cubic path segments
* @param {integer} dec : number of digits after decimal separator. defaults to 5 * @param {integer} dec : number of digits after decimal separator. defaults to 5
* @returns {undefined} * @returns {undefined}
*/ */
Element.prototype.bake = function (toCubics, dec) { Element.prototype.bake = function (toCubics, dec) {
var elem = this; var elem = this;
if (!elem || !elem.paper) // don't handle unplaced elements. this causes double handling.
if (!elem || !elem.paper || elem.type !== "text" || elem.type !== "#text" || elem.type !== "tspan"){
return; return;
} // don't handle unplaced elements. this causes double handling.
if (typeof (toCubics) === 'undefined') if (typeof (toCubics) === 'undefined')
toCubics = false; toCubics = false;
if (typeof (dec) === 'undefined') if (typeof (dec) === 'undefined')
dec = 5; dec = 5;
//var children = elem.selectAll('*')
var children = elem.children(); var children = elem.children();
if (children.length > 0) { if (children.length > 0) {
for (var i = 0; i < children.length; i++) { for (var i = 0; i < children.length; i++) {
@ -54,15 +55,16 @@ Snap.plugin(function (Snap, Element, Paper, global) {
elem.type !== "polygon" && elem.type !== "polygon" &&
elem.type !== "polyline" && elem.type !== "polyline" &&
elem.type !== "image" && elem.type !== "image" &&
elem.type !== "path"){ elem.type !== "path" &&
elem.type !== "text" &&
// if(elem.type !== 'g' && elem.type !== 'desc' && elem.type !== 'defs') elem.type !== "tspan" &&
// console.log('skipping unsupported element ', elem.type); elem.type !== "#text"){
return; return;
} }
if (elem.type == 'image'){ if (elem.type == 'image' || elem.type == "text" || elem.type == "#text"){
// TODO ... // TODO ...
var x = parseFloat(elem.attr('x')), var x = parseFloat(elem.attr('x')),
y = parseFloat(elem.attr('y')), y = parseFloat(elem.attr('y')),
w = parseFloat(elem.attr('width')), w = parseFloat(elem.attr('width')),
@ -70,24 +72,25 @@ Snap.plugin(function (Snap, Element, Paper, global) {
// Validity checks from http://www.w3.org/TR/SVG/shapes.html#RectElement: // Validity checks from http://www.w3.org/TR/SVG/shapes.html#RectElement:
// If 'x' and 'y' are not specified, then set both to 0. // CorelDraw is creating that sometimes // If 'x' and 'y' are not specified, then set both to 0. // CorelDraw is creating that sometimes
if (!isFinite(x)) if (!isFinite(x)) {
console.log('No attribute "x" in image tag. Assuming 0.') console.log('No attribute "x" in image tag. Assuming 0.')
x = 0; x = 0;
if (!isFinite(y)) }
if (!isFinite(y)) {
console.log('No attribute "y" in image tag. Assuming 0.') console.log('No attribute "y" in image tag. Assuming 0.')
y = 0; y = 0;
}
var transform = elem.transform(); var transform = elem.transform();
var matrix = transform['totalMatrix']; var matrix = transform['totalMatrix'];
var transformedX = matrix.x(x, y); var transformedX = matrix.x(x, y);
var transformedY = matrix.y(x, y); var transformedY = matrix.y(x, y);
var transformedW = matrix.x(x+w, y+h) - transformedX; var transformedW = matrix.x(x+w, y+h) - transformedX;
var transformedH = matrix.y(x+w, y+h) - transformedY; var transformedH = matrix.y(x+w, y+h) - transformedY;
elem.attr({x: transformedX, y: transformedY, width: transformedW, height: transformedH}); elem.attr({x: transformedX, y: transformedY, width: transformedW, height: transformedH});
return; return;
} }
//if(elem.type !== 'path') console.log("bake: converting " + elem.type + " to path");
var path_elem = elem.convertToPath(); var path_elem = elem.convertToPath();
if (!path_elem || path_elem.attr('d') === '' || path_elem.attr('d') === null) if (!path_elem || path_elem.attr('d') === '' || path_elem.attr('d') === null)
@ -99,7 +102,7 @@ Snap.plugin(function (Snap, Element, Paper, global) {
} else { } else {
dec = false; dec = false;
} }
function r(num) { function r(num) {
if (dec !== false) { if (dec !== false) {
return Math.round(num * Math.pow(10, dec)) / Math.pow(10, dec); return Math.round(num * Math.pow(10, dec)) / Math.pow(10, dec);
@ -112,8 +115,8 @@ Snap.plugin(function (Snap, Element, Paper, global) {
var d = path_elem.attr('d'); var d = path_elem.attr('d');
d = (d || "").trim(); d = (d || "").trim();
var arr_orig; var arr_orig;
arr = Snap.parsePathString(d); arr = Snap.parsePathString(d);
if (!toCubics) { if (!toCubics) {
arr_orig = arr; arr_orig = arr;
arr = Snap.path.toAbsolute(arr); arr = Snap.path.toAbsolute(arr);
} else { } else {
@ -126,7 +129,7 @@ Snap.plugin(function (Snap, Element, Paper, global) {
var matrix = transform['totalMatrix']; var matrix = transform['totalMatrix'];
// apply the matrix transformation on the path segments // apply the matrix transformation on the path segments
var j; var j;
var m = arr.length; var m = arr.length;
var letter = ''; var letter = '';
var letter_orig = ''; var letter_orig = '';
@ -134,8 +137,8 @@ Snap.plugin(function (Snap, Element, Paper, global) {
var y = 0; var y = 0;
var new_segments = []; var new_segments = [];
var pt = {x: 0, y: 0}; var pt = {x: 0, y: 0};
var pt_baked = {}; var pt_baked = {};
var subpath_start = {}; var subpath_start = {};
var prevX = 0; var prevX = 0;
var prevY = 0; var prevY = 0;
subpath_start.x = null; subpath_start.x = null;
@ -153,7 +156,7 @@ Snap.plugin(function (Snap, Element, Paper, global) {
pt.x = arr[i][6]; pt.x = arr[i][6];
pt.y = arr[i][7]; pt.y = arr[i][7];
new_segments[i] = _arc_transform(arr[i][1], arr[i][2], arr[i][3], arr[i][4], arr[i][5], pt, matrix); new_segments[i] = _arc_transform(arr[i][1], arr[i][2], arr[i][3], arr[i][4], arr[i][5], pt, matrix);
} else if (letter !== 'Z') { } else if (letter !== 'Z') {
// parse other segs than Z and A // parse other segs than Z and A
for (j = 1; j < arr[i].length; j = j + 2) { for (j = 1; j < arr[i].length; j = j + 2) {
@ -189,7 +192,7 @@ Snap.plugin(function (Snap, Element, Paper, global) {
y = subpath_start.y; y = subpath_start.y;
} }
} }
// Convert all that was relative back to relative // Convert all that was relative back to relative
// This could be combined to above, but to make code more readable // This could be combined to above, but to make code more readable
// this is made separately. // this is made separately.
@ -259,7 +262,7 @@ Snap.plugin(function (Snap, Element, Paper, global) {
//console.log("baked matrix ", matrix, " of ", path_elem.attr('id')); //console.log("baked matrix ", matrix, " of ", path_elem.attr('id'));
}; };
/** /**
* Helper to apply matrix transformations to arcs. * Helper to apply matrix transformations to arcs.
* From flatten.js (https://gist.github.com/timo22345/9413158), modified a bit. * From flatten.js (https://gist.github.com/timo22345/9413158), modified a bit.
@ -267,7 +270,7 @@ Snap.plugin(function (Snap, Element, Paper, global) {
* @param {type} a_rh : r1 of the ellipsis in degree * @param {type} a_rh : r1 of the ellipsis in degree
* @param {type} a_rv : r2 of the ellipsis in degree * @param {type} a_rv : r2 of the ellipsis in degree
* @param {type} a_offsetrot : x-axis rotation in degree * @param {type} a_offsetrot : x-axis rotation in degree
* @param {type} large_arc_flag : 0 or 1 * @param {type} large_arc_flag : 0 or 1
* @param {int} sweep_flag : 0 or 1 * @param {int} sweep_flag : 0 or 1
* @param {object} endpoint with properties x and y * @param {object} endpoint with properties x and y
* @param {type} matrix : transformation matrix * @param {type} matrix : transformation matrix
@ -309,12 +312,12 @@ Snap.plugin(function (Snap, Element, Paper, global) {
// convert implicit equation to angle and halfaxis: // convert implicit equation to angle and halfaxis:
// disabled intentionally // disabled intentionally
if (false && NEARZERO(B)) { // there is a bug in this optimization: does not work for path below if (false && NEARZERO(B)) { // there is a bug in this optimization: does not work for path below
a_offsetrot = 0; a_offsetrot = 0;
// d="M0,350 l 50,-25 // d="M0,350 l 50,-25
// a25,25 -30 0,1 50,-25 l 50,-25 // a25,25 -30 0,1 50,-25 l 50,-25
// a25,50 -30 0,1 50,-25 l 50,-25 // a25,50 -30 0,1 50,-25 l 50,-25
// a25,75 -30 0,1 50,-25 l 50,-25 // a25,75 -30 0,1 50,-25 l 50,-25
// a25,100 -30 0,1 50,-25 l 50,-25" // a25,100 -30 0,1 50,-25 l 50,-25"
// with matrix transform="scale(0.5,2.0)" // with matrix transform="scale(0.5,2.0)"
A2 = A; A2 = A;
@ -330,7 +333,7 @@ Snap.plugin(function (Snap, Element, Paper, global) {
// Clamp (precision issues might need this.. not likely, but better save than sorry) // Clamp (precision issues might need this.. not likely, but better save than sorry)
K = (K < 0) ? 0 : Math.sqrt(K); K = (K < 0) ? 0 : Math.sqrt(K);
A2 = 0.5 * (A + C + K * ac); A2 = 0.5 * (A + C + K * ac);
C2 = 0.5 * (A + C - K * ac); C2 = 0.5 * (A + C - K * ac);
a_offsetrot = 0.5 * Math.atan2(B, ac); a_offsetrot = 0.5 * Math.atan2(B, ac);
@ -351,7 +354,7 @@ Snap.plugin(function (Snap, Element, Paper, global) {
a_rh = A2; a_rh = A2;
} }
// If the transformation matrix contain a mirror-component // If the transformation matrix contain a mirror-component
// winding order of the ellise needs to be changed. // winding order of the ellise needs to be changed.
if ((matrix.a * matrix.d) - (matrix.b * matrix.c) < 0){ if ((matrix.a * matrix.d) - (matrix.b * matrix.c) < 0){
sweep_flag = !sweep_flag ? 1 : 0; sweep_flag = !sweep_flag ? 1 : 0;
@ -374,30 +377,30 @@ Snap.plugin(function (Snap, Element, Paper, global) {
var _convertToString = function (arr) { var _convertToString = function (arr) {
return arr.join(',').replace(_p2s, '$1'); return arr.join(',').replace(_p2s, '$1');
}; };
/** /**
* Replaces an element with a path of same shape. * Replaces an element with a path of same shape.
* Supports rect, ellipse, circle, line, polyline, polygon and of course path * Supports rect, ellipse, circle, line, polyline, polygon and of course path
* The element will be replaced by the path with same id. * The element will be replaced by the path with same id.
* *
* @returns {path} * @returns {path}
*/ */
Element.prototype.convertToPath = function(){ Element.prototype.convertToPath = function(){
var old_element = this; var old_element = this;
var path = old_element.toPath(); var path = old_element.toPath();
old_element.before(path); old_element.before(path);
old_element.remove(); old_element.remove();
return path; return path;
}; };
/** /**
* Creates a path in the same shape as the origin element * Creates a path in the same shape as the origin element
* Supports rect, ellipse, circle, line, polyline, polygon and of course path * Supports rect, ellipse, circle, line, polyline, polygon and of course path
* *
* based on * based on
* https://github.com/duopixel/Method-Draw/blob/master/editor/src/svgcanvas.js * https://github.com/duopixel/Method-Draw/blob/master/editor/src/svgcanvas.js
* Modifications: Timo (https://github.com/timo22345) * Modifications: Timo (https://github.com/timo22345)
* *
* @returns {path} path element * @returns {path} path element
*/ */
Element.prototype.toPath = function () { Element.prototype.toPath = function () {
@ -428,7 +431,7 @@ Snap.plugin(function (Snap, Element, Paper, global) {
var validRadius = function (val) { var validRadius = function (val) {
return (isFinite(val) && (val >= 0)); return (isFinite(val) && (val >= 0));
}; };
var validCoordinate = function (val) { var validCoordinate = function (val) {
return (isFinite(val)); return (isFinite(val));
}; };
@ -436,6 +439,19 @@ Snap.plugin(function (Snap, Element, Paper, global) {
// Possibly the cubed root of 6, but 1.81 works best // Possibly the cubed root of 6, but 1.81 works best
var num = 1.81; var num = 1.81;
var tag = old_element.type; var tag = old_element.type;
var convertMMtoPixel = function (val) {
attrList = ['rx','ry','r','cx','cy','x1','x2','y1','y2','x','y','width','height'];
for(var attrIdx in attrList) {
if(val.attr(attrList[attrIdx]) != null && val.attr(attrList[attrIdx]).indexOf('mm') > -1) {
var tmp = parseFloat(val.attr(attrList[attrIdx])) * 3.5433;
val.attr(attrList[attrIdx], tmp);
}
}
}
convertMMtoPixel(old_element);
switch (tag) { switch (tag) {
case 'ellipse': case 'ellipse':
case 'circle': case 'circle':
@ -446,13 +462,13 @@ Snap.plugin(function (Snap, Element, Paper, global) {
if (tag === 'circle') { if (tag === 'circle') {
rx = ry = +old_element.attr('r'); rx = ry = +old_element.attr('r');
} }
// If 'x' and 'y' are not specified, then set both to 0. // CorelDraw is creating that sometimes // If 'x' and 'y' are not specified, then set both to 0. // CorelDraw is creating that sometimes
if (!validCoordinate(cx)) if (!validCoordinate(cx))
cx = 0; cx = 0;
if (!validCoordinate(cy)) if (!validCoordinate(cy))
cy = 0; cy = 0;
d += _convertToString([ d += _convertToString([
['M', (cx - rx), (cy)], ['M', (cx - rx), (cy)],
['C', (cx - rx), (cy - ry / num), (cx - rx / num), (cy - ry), (cx), (cy - ry)], ['C', (cx - rx), (cy - ry / num), (cx - rx / num), (cy - ry), (cx), (cy - ry)],
@ -479,7 +495,7 @@ Snap.plugin(function (Snap, Element, Paper, global) {
d = 'M' + old_element.attr('points') + 'Z'; d = 'M' + old_element.attr('points') + 'Z';
break; break;
case 'rect': case 'rect':
// TODO ... // TODO ...
var rx = parseFloat(old_element.attr('rx')), var rx = parseFloat(old_element.attr('rx')),
ry = parseFloat(old_element.attr('ry')), ry = parseFloat(old_element.attr('ry')),
x = parseFloat(old_element.attr('x')), x = parseFloat(old_element.attr('x')),

View file

@ -1,7 +1,7 @@
// render_fills.js - a snapsvg.io plugin to render the infill of svg files into a bitmap. // render_fills.js - a snapsvg.io plugin to render the infill of svg files into a bitmap.
// Copyright (C) 2015 Teja Philipp <osd@tejaphilipp.de> // Copyright (C) 2015 Teja Philipp <osd@tejaphilipp.de>
// //
// based on work by http://davidwalsh.name/convert-canvas-image // based on work by http://davidwalsh.name/convert-canvas-image
// and http://getcontext.net/read/svg-images-on-a-html5-canvas // and http://getcontext.net/read/svg-images-on-a-html5-canvas
// //
// This program is free software: you can redistribute it and/or modify // This program is free software: you can redistribute it and/or modify
@ -20,12 +20,12 @@
Snap.plugin(function (Snap, Element, Paper, global) { Snap.plugin(function (Snap, Element, Paper, global) {
/** /**
* @param {elem} elem start point * @param {elem} elem start point
* *
* @returns {path} * @returns {path}
*/ */
@ -34,7 +34,7 @@ Snap.plugin(function (Snap, Element, Paper, global) {
var selection = []; var selection = [];
var children = elem.children(); var children = elem.children();
if (children.length > 0) { if (children.length > 0) {
var goRecursive = (elem.type !== "defs" && // ignore these tags var goRecursive = (elem.type !== "defs" && // ignore these tags
elem.type !== "clipPath" && elem.type !== "clipPath" &&
@ -42,7 +42,7 @@ Snap.plugin(function (Snap, Element, Paper, global) {
elem.type !== "rdf:rdf" && elem.type !== "rdf:rdf" &&
elem.type !== "cc:work" && elem.type !== "cc:work" &&
elem.type !== "sodipodi:namedview"); elem.type !== "sodipodi:namedview");
if(goRecursive) { if(goRecursive) {
for (var i = 0; i < children.length; i++) { for (var i = 0; i < children.length; i++) {
var child = children[i]; var child = children[i];
@ -50,7 +50,7 @@ Snap.plugin(function (Snap, Element, Paper, global) {
} }
} }
} else { } else {
if(elem.type === 'image'){ if(elem.type === 'image' || elem.type === "text" || elem.type === "#text"){
selection.push(elem); selection.push(elem);
} else { } else {
if(fillPaths && elem.is_filled()){ if(fillPaths && elem.is_filled()){
@ -65,7 +65,7 @@ Snap.plugin(function (Snap, Element, Paper, global) {
Element.prototype.is_filled = function(){ Element.prototype.is_filled = function(){
var elem = this; var elem = this;
// TODO text support // TODO text support
// TODO opacity support // TODO opacity support
if (elem.type !== "circle" && if (elem.type !== "circle" &&
@ -74,14 +74,17 @@ Snap.plugin(function (Snap, Element, Paper, global) {
elem.type !== "line" && elem.type !== "line" &&
elem.type !== "polygon" && elem.type !== "polygon" &&
elem.type !== "polyline" && elem.type !== "polyline" &&
elem.type !== "path" ){ elem.type !== "path" //&&
// elem.type !== "text" &&
// elem.type !== "#text"
){
return false; return false;
} }
var fill = elem.attr('fill'); var fill = elem.attr('fill');
var opacity = elem.attr('fill-opacity'); var opacity = elem.attr('fill-opacity');
if(fill !== 'none'){ if(fill !== 'none'){
if(opacity === null || opacity > 0){ if(opacity === null || opacity > 0){
return true; return true;
@ -89,7 +92,7 @@ Snap.plugin(function (Snap, Element, Paper, global) {
} }
return false; return false;
}; };
Element.prototype.embedImage = function(callback){ Element.prototype.embedImage = function(callback){
var elem = this; var elem = this;
if(elem.type !== 'image') return; if(elem.type !== 'image') return;
@ -113,15 +116,15 @@ Snap.plugin(function (Snap, Element, Paper, global) {
}; };
image.src = url; image.src = url;
}; };
Element.prototype.renderPNG = function (wMM, hMM, pxPerMM, callback) { Element.prototype.renderPNG = function (wMM, hMM, pxPerMM, callback) {
var elem = this; var elem = this;
// get svg as dataUrl // get svg as dataUrl
var svgStr = elem.outerSVG(); var svgStr = elem.outerSVG();
var svgDataUri = 'data:image/svg+xml;base64,' + window.btoa(svgStr); var svgDataUri = 'data:image/svg+xml;base64,' + window.btoa(unescape(encodeURIComponent(svgStr))); //deprecated unescape needed!
var source = new Image(); var source = new Image();
source.src = svgDataUri; source.src = svgDataUri;
@ -129,7 +132,7 @@ Snap.plugin(function (Snap, Element, Paper, global) {
var renderCanvas = document.createElement('canvas'); var renderCanvas = document.createElement('canvas');
renderCanvas.id = "renderCanvas"; renderCanvas.id = "renderCanvas";
renderCanvas.width = wMM * pxPerMM; renderCanvas.width = wMM * pxPerMM;
renderCanvas.height = hMM * pxPerMM; renderCanvas.height = hMM * pxPerMM;
document.getElementsByTagName('body')[0].appendChild(renderCanvas); document.getElementsByTagName('body')[0].appendChild(renderCanvas);
var renderCanvasContext = renderCanvas.getContext('2d'); var renderCanvasContext = renderCanvas.getContext('2d');

View file

@ -1,5 +1,20 @@
$(function(){ $(function(){
// Opera 8.0+
var isOpera = (!!window.opr && !!opr.addons) || !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0;
// Firefox 1.0+
var isFirefox = typeof InstallTrigger !== 'undefined';
// At least Safari 3+: "[object HTMLElementConstructor]"
var isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0;
// Internet Explorer 6-11
var isIE = /*@cc_on!@*/false || !!document.documentMode;
// Edge 20+
var isEdge = !isIE && !!window.StyleMedia;
// Chrome 1+
var isChrome = !!window.chrome && !!window.chrome.webstore;
// Blink engine detection
var isBlink = (isChrome || isOpera) && !!window.CSS;
function WorkingAreaViewModel(params) { function WorkingAreaViewModel(params) {
var self = this; var self = this;
@ -92,6 +107,7 @@ $(function(){
self.clear = function(){ self.clear = function(){
snap.selectAll('#userContent>*').remove(); snap.selectAll('#userContent>*').remove();
snap.selectAll('#placedGcodes>*').remove(); snap.selectAll('#placedGcodes>*').remove();
snap.selectAll('rect:not(#coordGrid)').remove();
self.placedDesigns([]); self.placedDesigns([]);
}; };
@ -102,24 +118,34 @@ $(function(){
self.availableWidth($('#workingarea div.span8').innerWidth()); self.availableWidth($('#workingarea div.span8').innerWidth());
}; };
self.move_laser = function(el){ self.move_laser = function(data, evt){
self.abortFreeTransforms(); self.abortFreeTransforms();
if(self.state.isOperational() && !self.state.isPrinting()){ if(self.state.isOperational() && !self.state.isPrinting()){
var x = self.px2mm(event.offsetX); var coord = self.getXYCoord(evt);
var y = self.px2mm(event.toElement.ownerSVGElement.offsetHeight - event.offsetY); // hopefully this works across browsers
x = Math.min(x, self.workingAreaWidthMM());
y = Math.min(y, self.workingAreaHeightMM());
$.ajax({ $.ajax({
url: API_BASEURL + "printer/printhead", url: API_BASEURL + "printer/printhead",
type: "POST", type: "POST",
dataType: "json", dataType: "json",
contentType: "application/json; charset=UTF8", contentType: "application/json; charset=UTF8",
data: JSON.stringify({"command": "position", x:x, y:y}) data: JSON.stringify({"command": "position", x:coord.x, y:coord.y})
}); });
} }
}; };
self.getXYCoord = function(evt){
if(/firefox/.test(navigator.userAgent.toLowerCase())) {
var scale = evt.target.parentElement.transform.baseVal[0].matrix.a;
var x = self.px2mm(evt.offsetX) * scale;
var y = self.px2mm(parseFloat(evt.target.attributes.height.value) - evt.offsetY) * scale;
} else
{
var x = self.px2mm(evt.offsetX);
var y = self.px2mm(parseFloat(evt.target.farthestViewportElement.clientHeight) - evt.offsetY);
}
x = Math.min(x, self.workingAreaWidthMM());
y = Math.min(y, self.workingAreaHeightMM());
return {x:x, y:y};
}
self.crosshairX = function(){ self.crosshairX = function(){
var pos = self.state.currentPos(); var pos = self.state.currentPos();
@ -127,7 +153,7 @@ $(function(){
}; };
self.crosshairY = function(){ self.crosshairY = function(){
var h = document.getElementById('area_preview').clientHeight; var h = Snap($('#area_preview')[0]).getBBox().height;
var pos = self.state.currentPos(); var pos = self.state.currentPos();
return pos !== undefined ? (h - self.mm2px(pos.y) - 15) : -100; // subtract height/2; return pos !== undefined ? (h - self.mm2px(pos.y) - 15) : -100; // subtract height/2;
}; };
@ -217,11 +243,26 @@ $(function(){
var url = self._getSVGserveUrl(file); var url = self._getSVGserveUrl(file);
callback = function (f) { callback = function (f) {
var newSvgAttrs = {}; var newSvgAttrs = {};
var root_attrs = f.select('svg').node.attributes; if(f.select('svg') == null){
root_attrs = f.node.attributes;
} else {
var root_attrs = f.select('svg').node.attributes;
}
var doc_width = null; var doc_width = null;
var doc_height = null; var doc_height = null;
var doc_viewbox = null; var doc_viewbox = null;
// find clippath elements
var clipPathEl = f.selectAll('clipPath');
if(clipPathEl.length != 0){
console.warn("Warning: removed unsupported clipPath element in SVG");
self.svg_contains_clipPath_warning();
clipPathEl.remove()
}
// find all elements with "display=none" and remove them
f.selectAll("[display=none]").remove()
// iterate svg tag attributes // iterate svg tag attributes
for(var i = 0; i < root_attrs.length; i++){ for(var i = 0; i < root_attrs.length; i++){
var attr = root_attrs[i]; var attr = root_attrs[i];
@ -237,9 +278,19 @@ $(function(){
} }
} }
// find Illustrator comment and notify
f.node.childNodes.forEach(function(entry) {
if(entry.nodeType == 8) { // Nodetype 8 = comment
if(entry.textContent.indexOf('Illustrator') > -1) {
new PNotify({title: gettext("Illustrator SVG Detected"), text: "Illustrator SVG detected! To preserve coorect scale, please go to the \'Settings\' menu and change the \'SVG dpi\' field under \'Plugins/Svg Conversion\' according to your file. And add it again.", type: "info", hide: false});
}
}
});
// scale matrix // scale matrix
var mat = self.getDocumentViewBoxMatrix(doc_width, doc_height, doc_viewbox); var mat = self.getDocumentViewBoxMatrix(doc_width, doc_height, doc_viewbox);
var scaleMatrixStr = new Snap.Matrix(mat[0][0],mat[0][1],mat[1][0],mat[1][1],mat[0][2],mat[1][2]).toTransformString(); var dpiscale = 90 / self.settings.settings.plugins.svgtogcode.svgDPI();
var scaleMatrixStr = new Snap.Matrix(mat[0][0],mat[0][1],mat[1][0],mat[1][1],mat[0][2],mat[1][2]).scale(dpiscale).toTransformString();
newSvgAttrs['transform'] = scaleMatrixStr; newSvgAttrs['transform'] = scaleMatrixStr;
var newSvg = snap.group(f.selectAll("svg>*")); var newSvg = snap.group(f.selectAll("svg>*"));
@ -345,7 +396,7 @@ $(function(){
dx = -svgBB.x + 0.01; dx = -svgBB.x + 0.01;
outside = true; outside = true;
} else if(svgBB.x2 > waBB.x2){ } else if(svgBB.x2 > waBB.x2){
dx = -svgBB.x2 + waBB.x2 - 0.01; dx = -svgBB.x + 0.01;
outside = true; outside = true;
} }
if(svgBB.y < waBB.y){ if(svgBB.y < waBB.y){
@ -365,8 +416,20 @@ $(function(){
}; };
}; };
self.svg_contains_clipPath_warning = function(){
var error = "<p>" + gettext("The SVG file contains clipPath elements.<br/>clipPath is not supported yet and has been removed from file.") + "</p>";
//error += pnotifyAdditionalInfo("<pre>" + data.jqXHR.responseText + "</pre>");
new PNotify({
title: "clipPath elements removed",
text: error,
type: "warn",
hide: false
});
};
self.svg_contains_text_warning = function(svg){ self.svg_contains_text_warning = function(svg){
var error = "<p>" + gettext("The svg file contains text elements.<br/>Please convert them to paths.<br/>Otherwise they will be ignored.") + "</p>"; var error = "<p>" + gettext("The SVG file contains text elements.<br/>If you want to laser just their outlines,<br/>please convert them to paths.<br/>Otherwise they will be engraved with infill.") + "</p>";
//error += pnotifyAdditionalInfo("<pre>" + data.jqXHR.responseText + "</pre>"); //error += pnotifyAdditionalInfo("<pre>" + data.jqXHR.responseText + "</pre>");
new PNotify({ new PNotify({
title: "Text elements found", title: "Text elements found",
@ -374,7 +437,6 @@ $(function(){
type: "warn", type: "warn",
hide: false hide: false
}); });
svg.selectAll('text,tspan').remove();
}; };
self.svg_misfitting_warning = function(svg, misfitting){ self.svg_misfitting_warning = function(svg, misfitting){
@ -390,7 +452,7 @@ $(function(){
}); });
}; };
self.placeIMG = function (file) { self.placeIMG = function (file) {
var url = self._getIMGserveUrl(file); var url = self._getIMGserveUrl(file);
var img = new Image(); var img = new Image();
@ -426,10 +488,16 @@ $(function(){
}; };
self.getUsefulDimensions = function(wpx, hpx){ self.getUsefulDimensions = function(wpx, hpx){
var maxWidthMM = wpx * 0.25; // TODO parametrize var maxWidthMM = wpx * 0.25; // TODO parametrize
var aspectRatio = wpx / hpx; var maxHeightMM = hpx * 0.25; // TODO parametrize
var destWidthMM = Math.min(self.workingAreaWidthMM() - 2, maxWidthMM); var aspectRatio = wpx / hpx;
var destHeightMM = destWidthMM / aspectRatio; var destWidthMM = Math.min(self.workingAreaWidthMM() - 2, maxWidthMM);
var destHeightMM = Math.min(self.workingAreaHeightMM() - 2, maxHeightMM);
if ((destWidthMM / aspectRatio) > destHeightMM) {
destWidthMM = destHeightMM * aspectRatio;
} else {
destHeightMM = destWidthMM / aspectRatio;
}
var destWidthPT = self.mm2svgUnits(destWidthMM); var destWidthPT = self.mm2svgUnits(destWidthMM);
var destHeightPT = self.mm2svgUnits(destHeightMM); var destHeightPT = self.mm2svgUnits(destHeightMM);
return [destWidthPT, destHeightPT]; return [destWidthPT, destHeightPT];
@ -632,13 +700,13 @@ $(function(){
var userContent = snap.select("#userContent").clone(); var userContent = snap.select("#userContent").clone();
compSvg.append(userContent); compSvg.append(userContent);
self.renderInfill(compSvg, fillAreas, wMM, hMM, 10, function(svgWithRenderedInfill){ self.renderInfill(compSvg, fillAreas, wMM, hMM, 10, function(svgWithRenderedInfill){
callback( self._wrapInSvgAndScale(svgWithRenderedInfill)); callback( self._wrapInSvgAndScale(svgWithRenderedInfill));
$('#compSvg').remove(); $('#compSvg').remove();
}); });
}; };
self._wrapInSvgAndScale = function(content){ self._wrapInSvgAndScale = function(content){
var svgStr = content.innerSVG(); var svgStr = content.innerSVG();
if(svgStr !== ''){ if(svgStr !== ''){
@ -674,6 +742,16 @@ $(function(){
return snap.selectAll("#userContent image"); return snap.selectAll("#userContent image");
}; };
self.hasTextItems = function () {
if(snap.selectAll("#userContent tspan").length > 0 ||
snap.selectAll("#userContent text").length > 0 ||
snap.selectAll("userContent #text").length > 0) {
return true
}else{
return false
}
};
self.getPlacedGcodes = ko.computed(function() { self.getPlacedGcodes = ko.computed(function() {
var gcodeFiles = []; var gcodeFiles = [];
ko.utils.arrayForEach(self.placedDesigns(), function(design) { ko.utils.arrayForEach(self.placedDesigns(), function(design) {
@ -721,7 +799,7 @@ $(function(){
self.clear_gcode = function(){ self.clear_gcode = function(){
snap.select('#gCodePreview').clear(); snap.select('#gCodePreview').clear();
}; };
self.onStartup = function(){ self.onStartup = function(){
self.state.workingArea = self; self.state.workingArea = self;
self.files.workingArea = self; self.files.workingArea = self;
@ -754,11 +832,16 @@ $(function(){
} }
}); });
}; };
self._embedAllImages = function(svg, callback){ self._embedAllImages = function(svg, callback){
var allImages = svg.selectAll('image'); var allImages = svg.selectAll('image');
var linkedImages = allImages.items.filter(function(i){ return !i.attr('href').startsWith('data:') }); var linkedImages = allImages.items.filter(function(i){
if(i.attr('xlink:href') != null) {
return !i.attr('xlink:href').startsWith('data:');
} else if(i.attr('href') != null) {
return !i.attr('href').startsWith('data:');
}});
if(linkedImages.length > 0){ if(linkedImages.length > 0){
var callbackCounter = linkedImages.length; var callbackCounter = linkedImages.length;
for (var i = 0; i < linkedImages.length; i++) { for (var i = 0; i < linkedImages.length; i++) {
@ -790,8 +873,8 @@ $(function(){
var fillings = userContent.removeUnfilled(fillAreas); var fillings = userContent.removeUnfilled(fillAreas);
for (var i = 0; i < fillings.length; i++) { for (var i = 0; i < fillings.length; i++) {
var item = fillings[i]; var item = fillings[i];
if (item.type === 'image') { if (item.type === 'image' || item.type === "text" || item.type === "#text") {
// remove filter effects on images for proper rendering // remove filter effects on images for proper rendering
var style = item.attr('style'); var style = item.attr('style');
if (style !== null) { if (style !== null) {

View file

@ -18,7 +18,7 @@
</div> </div>
<div class="controls alert alert-info hint" data-bind="visible: showHints"> <div class="controls alert alert-info hint" data-bind="visible: showHints">
<span class="icon icon-question-sign" aria-hidden="true"></span> <span class="icon icon-question-sign" aria-hidden="true"></span>
Sets the intensity of the laser. The more intensity the deeper the effect on the material. Sets the intensity of the laser. The more intensity the deeper the effect on the material.
Cutting needs higher intensities than engraving. Cutting needs higher intensities than engraving.
The effect in general is dependent from the material and its color and surface. The effect in general is dependent from the material and its color and surface.
</div> </div>
@ -33,8 +33,8 @@
</div> </div>
<div class="controls alert alert-info hint" data-bind="visible: showHints"> <div class="controls alert alert-info hint" data-bind="visible: showHints">
<span class="icon icon-question-sign" aria-hidden="true"></span> <span class="icon icon-question-sign" aria-hidden="true"></span>
Sets the velocity of the laser head. The slower the movement the deeper the effect on the material. Sets the velocity of the laser head. The slower the movement the deeper the effect on the material.
Cutting needs slower movement than engraving. Cutting needs slower movement than engraving.
The effect in general is dependent from the material and its color and surface. The effect in general is dependent from the material and its color and surface.
</div> </div>
</div> </div>
@ -56,11 +56,11 @@
<div class="controls alert alert-info hint" data-bind="visible: showHints"> <div class="controls alert alert-info hint" data-bind="visible: showHints">
<span class="icon icon-question-sign" aria-hidden="true"></span> <span class="icon icon-question-sign" aria-hidden="true"></span>
Some (especially bright) materials require the laser to dwell a little until the surface has absorbed enough energy to be affected. Some (especially bright) materials require the laser to dwell a little until the surface has absorbed enough energy to be affected.
This parameter sets the amount of time in milliseconds the movement is paused after the laser is switched on. This parameter sets the amount of time in milliseconds the movement is paused after the laser is switched on.
If the result shows gaps in lines for example increase this value carefully. The higher the value the higher the risk of material ignition. If the result shows gaps in lines for example increase this value carefully. The higher the value the higher the risk of material ignition.
</div> </div>
</div> </div>
<div data-bind="visible: show_image_parameters "> <div data-bind="visible: show_image_parameters ">
<p>{{ _('Image engraving parameters:') }}</p> <p>{{ _('Image engraving parameters:') }}</p>
<div class="control-group" > <div class="control-group" >
@ -103,10 +103,10 @@
<div class="controls alert alert-info hint" data-bind="visible: showHints"> <div class="controls alert alert-info hint" data-bind="visible: showHints">
<span class="icon icon-question-sign" aria-hidden="true"></span> <span class="icon icon-question-sign" aria-hidden="true"></span>
Pixel / raster engravings are done line by line. This sets the distance between the single lines. Pixel / raster engravings are done line by line. This sets the distance between the single lines.
Smaller values allow finer engravings but require a more precise focus and are slower. Smaller values allow finer engravings but require a more precise focus and are slower.
</div> </div>
<p >{{ _('Image Preprocessing') }}</p> <p >{{ _('Image Preprocessing') }}</p>
<div class="controls"> <div class="controls">
<div class="img_preprocessing_preview before" style="background-image:url(/plugin/svgtogcode/static/img/kitty_grayscale.png);" >before</div> <div class="img_preprocessing_preview before" style="background-image:url(/plugin/svgtogcode/static/img/kitty_grayscale.png);" >before</div>
@ -114,22 +114,22 @@
<div class="img_preprocessing_preview contrast" style="background-image:url(/plugin/svgtogcode/static/img/kitty_contrast.png);" data-bind="style: { opacity: contrastPreview }" ></div> <div class="img_preprocessing_preview contrast" style="background-image:url(/plugin/svgtogcode/static/img/kitty_contrast.png);" data-bind="style: { opacity: contrastPreview }" ></div>
<div class="img_preprocessing_preview sharpened" style="background-image:url(/plugin/svgtogcode/static/img/kitty_sharpened.png);" data-bind="style: { opacity: sharpenedPreview }" ></div> <div class="img_preprocessing_preview sharpened" style="background-image:url(/plugin/svgtogcode/static/img/kitty_sharpened.png);" data-bind="style: { opacity: sharpenedPreview }" ></div>
<div class="img_preprocessing_preview dithered" style="background-image:url(/plugin/svgtogcode/static/img/kitty_dithered_150.png);" data-bind="visible: imgDithering"></div> <div class="img_preprocessing_preview dithered" style="background-image:url(/plugin/svgtogcode/static/img/kitty_dithered_150.png);" data-bind="visible: imgDithering"></div>
</div> </div>
<div class="photo_attribution"><a href="http://www.christianholmer.com" target="_blank">Photo: Christian Holmér</a></div> <div class="photo_attribution"><a href="http://www.christianholmer.com" target="_blank">Photo: Christian Holmér</a></div>
</div> </div>
<div data-bind="disable:imgDithering "> <div data-bind="disable:imgDithering ">
<label class="control-label">{{ _('Contrast') }}</label> <label class="control-label">{{ _('Contrast') }}</label>
<div class="controls img_slider"> <div class="controls img_slider">
<input id="svgtogcode_contrast_slider" type="text" data-bind="value: imgContrast" > <input id="svgtogcode_contrast_slider" type="text" data-bind="value: imgContrast" >
</div> </div>
<div style="clear:both"></div> <div style="clear:both"></div>
<div class="controls alert alert-info hint" data-bind="visible: showHints"> <div class="controls alert alert-info hint" data-bind="visible: showHints">
<span class="icon icon-question-sign" aria-hidden="true"></span> <span class="icon icon-question-sign" aria-hidden="true"></span>
Increases the image contrast before converting to gcode. Increases the image contrast before converting to gcode.
</div> </div>
<label class="control-label">{{ _('Sharpening') }}</label> <label class="control-label">{{ _('Sharpening') }}</label>
<div class="controls img_slider"> <div class="controls img_slider">
<input id="svgtogcode_sharpening_slider" class="uninitialized" type="text" data-bind="value: imgSharpening"> <input id="svgtogcode_sharpening_slider" class="uninitialized" type="text" data-bind="value: imgSharpening">
@ -137,10 +137,10 @@
<div style="clear:both"></div> <div style="clear:both"></div>
<div class="controls alert alert-info hint" data-bind="visible: showHints"> <div class="controls alert alert-info hint" data-bind="visible: showHints">
<span class="icon icon-question-sign" aria-hidden="true"></span> <span class="icon icon-question-sign" aria-hidden="true"></span>
Sharpens the image before converting to gcode. Sharpens the image before converting to gcode.
</div> </div>
</div> </div>
<label class="control-label">{{ _('Dithering') }}</label> <label class="control-label">{{ _('Dithering') }}</label>
<div class="controls"> <div class="controls">
<label class="checkbox"> <label class="checkbox">
@ -149,8 +149,8 @@
</div> </div>
<div class="controls alert alert-info hint" data-bind="visible: showHints"> <div class="controls alert alert-info hint" data-bind="visible: showHints">
<span class="icon icon-question-sign" aria-hidden="true"></span> <span class="icon icon-question-sign" aria-hidden="true"></span>
Converts the image to solely black and white pixels. Converts the image to solely black and white pixels.
Use this if the laser effect on your material is not able to transfer grayscales. Use this if the laser effect on your material is not able to transfer grayscales.
</div> </div>
</div> </div>
@ -185,4 +185,4 @@
<a href="#" class="btn" data-dismiss="modal" aria-hidden="true" data-bind="click: $root.cancel_conversion()">{{ _('Cancel') }}</a> <a href="#" class="btn" data-dismiss="modal" aria-hidden="true" data-bind="click: $root.cancel_conversion()">{{ _('Cancel') }}</a>
<a href="#" class="btn btn-primary" data-bind="click: function() { if ($root.enableConvertButton()) { $root.convert() } }, enabled: enableConvertButton, css: {disabled: !$root.enableConvertButton()}">{{ _('Convert') }}</a> <a href="#" class="btn btn-primary" data-bind="click: function() { if ($root.enableConvertButton()) { $root.convert() } }, enabled: enableConvertButton, css: {disabled: !$root.enableConvertButton()}">{{ _('Convert') }}</a>
</div> </div>
</div> </div>

View file

@ -331,7 +331,7 @@ class Printer(PrinterInterface, comm.MachineComPrintCallback):
def position(self, x, y): def position(self, x, y):
printer_profile = self._printerProfileManager.get_current_or_default() printer_profile = self._printerProfileManager.get_current_or_default()
movement_speed = min(printer_profile["axes"]["x"]["speed"], printer_profile["axes"]["y"]["speed"]) movement_speed = min(printer_profile["axes"]["x"]["speed"], printer_profile["axes"]["y"]["speed"])
self.commands(["G90", "G0 X%.3f Y%.3f F%d" % (x, y, movement_speed), "?"]) self.commands(["G90", "G0 X%.3f Y%.3f F%d" % (x, y, movement_speed)])
def _convert_rate_value(self, factor, min=0, max=200): def _convert_rate_value(self, factor, min=0, max=200):
if not isinstance(factor, (int, float, long)): if not isinstance(factor, (int, float, long)):

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View file

@ -217,6 +217,8 @@ $(function() {
$("#confirmation_dialog .confirmation_dialog_acknowledge").click( $("#confirmation_dialog .confirmation_dialog_acknowledge").click(
function (e) { function (e) {
if (typeof callback === 'function') { if (typeof callback === 'function') {
self.resetOverrideSlider();
self.numberOfPasses(1);
callback(e); callback(e);
$("#confirmation_dialog").modal("hide"); $("#confirmation_dialog").modal("hide");
$("#confirmation_dialog .confirmation_dialog_message").html(''); $("#confirmation_dialog .confirmation_dialog_message").html('');
@ -286,8 +288,14 @@ $(function() {
self.onEventRealTimeState = function(payload){ self.onEventRealTimeState = function(payload){
self.currentPos({x: payload.wx, y: payload.wy}); self.currentPos({x: payload.wx, y: payload.wy});
}; };
self.intensityOverride.subscribe(function(factor){
self._overrideCommand("/intensity "+factor);
});
self.feedrateOverride.subscribe(function(factor){
self._overrideCommand("/feedrate "+factor);
});
self._overrideCommand = function(command, callback) { self._overrideCommand = function(command, callback) {
$.ajax({ $.ajax({
url: API_BASEURL + "printer/command", url: API_BASEURL + "printer/command",
@ -302,34 +310,30 @@ $(function() {
} }
}); });
}; };
self._configureOverrideSliders = function() { self._configureOverrideSliders = function() {
self.intensityOverrideSlider = $("#intensity_override_slider").slider({ self.intensityOverrideSlider = $("#intensity_override_slider").slider({
step: 1, step: 1,
min: 10, min: 10,
max: 200, max: 200,
value: 100, value: 100,
tooltip: 'hide' // tooltip: 'hide'
}).on("slide", function(ev){
self.intensityOverride(ev.value);
}).on("slideStop", function(ev){ }).on("slideStop", function(ev){
self._overrideCommand("/intensity "+self.intensityOverride()); self.intensityOverride(ev.value);
}); });
self.feedrateOverrideSlider = $("#feedrate_override_slider").slider({ self.feedrateOverrideSlider = $("#feedrate_override_slider").slider({
step: 1, step: 1,
min: 10, min: 10,
max: 200, max: 200,
value: 100, value: 100,
tooltip: 'hide' // tooltip: 'hide'
}).on("slide", function(ev){
self.feedrateOverride(ev.value);
}).on("slideStop", function(ev){ }).on("slideStop", function(ev){
self._overrideCommand("/feedrate "+self.feedrateOverride()); self.feedrateOverride(ev.value);
}); });
}; };
self.increasePasses = function(){ self.increasePasses = function(){
self.numberOfPasses(self.numberOfPasses()+1); self.numberOfPasses(self.numberOfPasses()+1);
self._jobCommand("incpasses"); self._jobCommand("incpasses");
@ -339,17 +343,21 @@ $(function() {
self.numberOfPasses(passes); self.numberOfPasses(passes);
self._jobCommand("degpasses"); self._jobCommand("degpasses");
} }
self.onEventPrintDone = function(){ self.onEventPrintDone = function(){
self.feedrateOverrideSlider.slider('setValue', 100); self.resetOverrideSlider();
};
self.onStartup = function() {
self._configureOverrideSliders();
};
self.resetOverrideSlider = function() {
self.feedrateOverrideSlider.slider('setValue', 100);
self.intensityOverrideSlider.slider('setValue', 100); self.intensityOverrideSlider.slider('setValue', 100);
self.intensityOverride(100); self.intensityOverride(100);
self.feedrateOverride(100); self.feedrateOverride(100);
}; };
self.onStartup = function() {
self._configureOverrideSliders();
};
} }
OCTOPRINT_VIEWMODELS.push([ OCTOPRINT_VIEWMODELS.push([

View file

@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title data-bind="text: title">Mr Beam</title> <title data-bind="text: title">Mr Draw</title>
<link rel="shortcut icon" href="{{ url_for('static', filename='img/favicon.png') }}"> <link rel="shortcut icon" href="{{ url_for('static', filename='img/favicon.png') }}">
<link rel="apple-touch-icon" sizes="114x114" href="{{ url_for('static', filename='img/apple-touch-icon-114x114.png') }}"> <link rel="apple-touch-icon" sizes="114x114" href="{{ url_for('static', filename='img/apple-touch-icon-114x114.png') }}">
@ -9,27 +9,14 @@
{% include 'stylesheets.jinja2' %} {% include 'stylesheets.jinja2' %}
{% include 'initscript.jinja2' %} {% include 'initscript.jinja2' %}
<script type="text/javascript" >
function cycle_bg(){
var path = $('#cam').attr('xlink:href');
var m = path.match(/[0-9]+/);
var number = 0;
if(m.length > 0){
number = (parseInt(m[0]) + 1) % 12;
}
var nPath = "/plugin/svgtogcode/static/img/wa_preview/" + number + ".jpg";
$('#cam').attr('xlink:href', nPath);
}
</script>
</head> </head>
<body> <body>
<div class="container octoprint-container"> <div class="container octoprint-container">
<nav class="navbar navbar-default navbar-fixed-top" role="navigation" id="navbar"> <nav class="navbar navbar-default navbar-fixed-top" role="navigation" id="navbar">
<div class="container"> <div class="container">
<div class="navbar-header brand" style="min-width: 272px;" onclick="cycle_bg()"> <div class="navbar-header brand" style="min-width: 272px;">
<a class="navbar-brand" href="#" > <a class="navbar-brand" href="#">
<img alt="Mr Beam Logo" src="{{ url_for('static', filename='img/mr-typo-red_x120.png') }}"> <img alt="Mr Draw Logo" src="{{ url_for('static', filename='img/mr-draw-red_x120.png') }}">
</a> </a>
</div> </div>
<!-- Navbar --> <!-- Navbar -->
@ -71,7 +58,7 @@
<div id="control" class="accordion-inner" data-bind="visible: isReady() || isLocked() || isFlashing()"> <div id="control" class="accordion-inner" data-bind="visible: isReady() || isLocked() || isFlashing()">
<div data-bind="visible: isLocked "> <div data-bind="visible: isLocked ">
Mr Beam is in a locked state as it does not know its position. Mr Draw is in a locked state as it does not know its position.
First remove any objects blocking the gantry's travel range. First remove any objects blocking the gantry's travel range.
Then do a homing cycle. Then do a homing cycle.
<div style='text-align: center; padding:.5em;'> <div style='text-align: center; padding:.5em;'>
@ -329,9 +316,6 @@
<feFuncB type="table" tableValues="0.2 1"></feFuncB> <feFuncB type="table" tableValues="0.2 1"></feFuncB>
</feComponentTransfer> </feComponentTransfer>
</filter> </filter>
<image id="cam" xlink:href="/plugin/svgtogcode/static/img/wa_preview/0.jpg" x="0" y="0"
height="0px" width="0px" data-bind="attr: { width: workingAreaWidthPx()+'px', height: workingAreaHeightPx()+'px'}" />
<g id="scaleGroup" data-bind="attr: { transform: scaleMatrix() }"> <g id="scaleGroup" data-bind="attr: { transform: scaleMatrix() }">
<text <text
@ -673,12 +657,10 @@
<div class="span4"> <div class="span4">
<ul class="focus_steps"> <ul class="focus_steps">
<li>1. Place your material on the working area</li> <li>1. Place your material on the working area</li>
<li>2. Move the laser over the material</li> <li>2. Move the pen over the material</li>
<li>3. Put on your safety glasses</li> <li>&RightArrow; Now enable the pen calibration mode</li>
<li>4. Turn the laser safety switch to on</li> <li>5. Adjust the pen until it touches the paper</li>
<li>&RightArrow; Now enable the focus mode</li> <li>&RightArrow; Disable the pen calibration mode. </li>
<li>5. Adjust the focus until the laser beam is as small as possible</li>
<li>&RightArrow; Disable the focus mode. </li>
</ul> </ul>
<div style="text-align:center"> <div style="text-align:center">
<div class="btn-group" role="group" aria-label="focus mode control" style=""> <div class="btn-group" role="group" aria-label="focus mode control" style="">

View file

@ -568,8 +568,8 @@ msgstr ""
"aktualisiert werden." "aktualisiert werden."
#: src/octoprint/plugins/softwareupdate/static/js/softwareupdate.js:131 #: src/octoprint/plugins/softwareupdate/static/js/softwareupdate.js:131
msgid "Update Available" msgid "Mr Beam Update Available"
msgstr "Aktualisierung verfügbar" msgstr "Mr Beam Aktualisierung verfügbar"
#: src/octoprint/plugins/softwareupdate/static/js/softwareupdate.js:143 #: src/octoprint/plugins/softwareupdate/static/js/softwareupdate.js:143
msgid "Ignore" msgid "Ignore"

View file

@ -84,9 +84,11 @@ class MachineCom(object):
self._actual_intensity = None self._actual_intensity = None
self._feedrate_dict = {} self._feedrate_dict = {}
self._intensity_dict = {} self._intensity_dict = {}
self._passes = 1
self._finished_passes = 0
# regular expressions # regular expressions
self._regex_command = re.compile("^\s*\$?([GM]\d+|[TH])") self._regex_command = re.compile("^\s*\$?([GM]\d+|[THX])")
self._regex_feedrate = re.compile("F\d+", re.IGNORECASE) self._regex_feedrate = re.compile("F\d+", re.IGNORECASE)
self._regex_intensity = re.compile("S\d+", re.IGNORECASE) self._regex_intensity = re.compile("S\d+", re.IGNORECASE)
@ -145,7 +147,7 @@ class MachineCom(object):
elif line.startswith('['): # feedback message elif line.startswith('['): # feedback message
self._handle_feedback_message(line) self._handle_feedback_message(line)
elif line.startswith('Grb'): # Grbl startup message elif line.startswith('Grb'): # Grbl startup message
self._handle_startup_message() self._handle_startup_message(line)
except: except:
self._logger.exception("Something crashed inside the monitoring loop, please report this to Mr. Beam") self._logger.exception("Something crashed inside the monitoring loop, please report this to Mr. Beam")
errorMsg = "See octoprint.log for details" errorMsg = "See octoprint.log for details"
@ -164,8 +166,15 @@ class MachineCom(object):
if cmd is not None: if cmd is not None:
self.sendCommand(cmd) self.sendCommand(cmd)
self._callback.on_comm_progress() self._callback.on_comm_progress()
elif len(self._acc_line_buffer) == 0: else:
self._set_print_finished() if self._finished_passes >= self._passes:
if len(self._acc_line_buffer) == 0:
self._set_print_finished()
self._currentFile.resetToBeginning()
cmd = self._getNext()
if cmd is not None:
self.sendCommand(cmd)
self._callback.on_comm_progress()
self._sendCommand() self._sendCommand()
self._send_event.wait(1) self._send_event.wait(1)
@ -311,7 +320,9 @@ class MachineCom(object):
if self._finished_currentFile is False: if self._finished_currentFile is False:
line = self._currentFile.getNext() line = self._currentFile.getNext()
if line is None: if line is None:
self._finished_currentFile = True self._finished_passes += 1
if self._finished_passes >= self._passes:
self._finished_currentFile = True
return line return line
else: else:
return None return None
@ -347,7 +358,6 @@ class MachineCom(object):
def _handle_ok_message(self): def _handle_ok_message(self):
if self._state == self.STATE_HOMING: if self._state == self.STATE_HOMING:
self._changeState(self.STATE_OPERATIONAL) self._changeState(self.STATE_OPERATIONAL)
self._onHomingDone()
def _handle_error_message(self, line): def _handle_error_message(self, line):
self._errorValue = line self._errorValue = line
@ -395,7 +405,7 @@ class MachineCom(object):
elif line[1:].startswith('Dis'): # [Disabled] elif line[1:].startswith('Dis'): # [Disabled]
pass pass
def _handle_startup_message(self): def _handle_startup_message(self, line):
if self.isOperational(): if self.isOperational():
errorMsg = "Machine reset." errorMsg = "Machine reset."
self._cmd = None self._cmd = None
@ -410,7 +420,14 @@ class MachineCom(object):
self._changeState(self.STATE_LOCKED) self._changeState(self.STATE_LOCKED)
eventManager().fire(Events.ERROR, {"error": self.getErrorString()}) eventManager().fire(Events.ERROR, {"error": self.getErrorString()})
else: else:
self._onConnected(self.STATE_LOCKED) versionMatch = re.search("Grbl (?P<grbl>.+?)(_(?P<git>[0-9a-f]{7})(?P<dirty>-dirty)?)? \[.+\]", line)
if versionMatch:
versionDict = versionMatch.groupdict()
self._writeGrblVersionToFile(versionDict)
if self._compareGrblVersion(versionDict) is False:
self._flashGrbl()
else:
self._onConnected(self.STATE_LOCKED)
def _update_grbl_pos(self, line): def _update_grbl_pos(self, line):
# line example: # line example:
@ -540,11 +557,6 @@ class MachineCom(object):
payload = dict(port=self._port, baudrate=self._baudrate) payload = dict(port=self._port, baudrate=self._baudrate)
eventManager().fire(Events.CONNECTED, payload) eventManager().fire(Events.CONNECTED, payload)
def _onHomingDone(self):
self.sendCommand("G92X500Y0Z0")
self.sendCommand("G90")
self.sendCommand("G21")
def _detectPort(self, close): def _detectPort(self, close):
self._log("Serial port list: %s" % (str(serialList()))) self._log("Serial port list: %s" % (str(serialList())))
for p in serialList(): for p in serialList():
@ -606,7 +618,7 @@ class MachineCom(object):
params = ["avrdude", "-patmega328p", "-carduino", "-b" + str(self._baudrate), "-P" + str(self._port), "-D", "-Uflash:w:" + pathToGrblHex] params = ["avrdude", "-patmega328p", "-carduino", "-b" + str(self._baudrate), "-P" + str(self._port), "-D", "-Uflash:w:" + pathToGrblHex]
rc = subprocesscall(params) rc = subprocesscall(params)
if rc is False: if rc == 0:
self._log("successfully flashed new grbl version") self._log("successfully flashed new grbl version")
self._openSerial() self._openSerial()
self._changeState(self.STATE_CONNECTING) self._changeState(self.STATE_CONNECTING)
@ -743,6 +755,10 @@ class MachineCom(object):
self._changeState(self.STATE_HOMING) self._changeState(self.STATE_HOMING)
return cmd return cmd
def _gcode_X_sent(self, cmd, cmd_type=None):
self._changeState(self.STATE_HOMING) # TODO: maybe change to seperate $X mode
return cmd
def _gcode_Hold_sent(self, cmd, cmd_type=None): def _gcode_Hold_sent(self, cmd, cmd_type=None):
self._changeState(self.STATE_PAUSED) self._changeState(self.STATE_PAUSED)
return cmd return cmd
@ -830,6 +846,12 @@ class MachineCom(object):
if self._currentFile is None: if self._currentFile is None:
raise ValueError("No file selected for printing") raise ValueError("No file selected for printing")
# reset feedrate and intesity factor in case they where changed in a previous run
self._feedrate_factor = 1
self._intensity_factor = 1
self._passes = 1
self._finished_passes = 0
try: try:
# ensure fan is on whatever gcode follows. # ensure fan is on whatever gcode follows.
self.sendCommand("M08") self.sendCommand("M08")
@ -900,10 +922,12 @@ class MachineCom(object):
eventManager().fire(Events.PRINT_PAUSED, payload) eventManager().fire(Events.PRINT_PAUSED, payload)
def increasePasses(self): def increasePasses(self):
self._log("increase Passes") self._passes += 1
self._log("increased Passes to %d" % self._passes)
def degreasePasses(self): def degreasePasses(self):
self._log("degrease Passes") self._passes -= 1
self._log("degrease Passes to %d" % self._passes)
def getStateString(self): def getStateString(self):
if self._state == self.STATE_NONE: if self._state == self.STATE_NONE:
@ -1145,6 +1169,9 @@ class PrintingGcodeFileInformation(PrintingFileInformation):
if not os.path.exists(self._filename) or not os.path.isfile(self._filename): if not os.path.exists(self._filename) or not os.path.isfile(self._filename):
raise IOError("File %s does not exist" % self._filename) raise IOError("File %s does not exist" % self._filename)
self._stripCommments()
self._size = os.stat(self._filename).st_size self._size = os.stat(self._filename).st_size
self._pos = 0 self._pos = 0
@ -1167,6 +1194,12 @@ class PrintingGcodeFileInformation(PrintingFileInformation):
pass pass
self._handle = None self._handle = None
def resetToBeginning(self):
"""
resets the file handle so you can read from the beginning again.
"""
self._handle = open(self._filename, "r")
def getNext(self): def getNext(self):
""" """
Retrieves the next line for printing. Retrieves the next line for printing.
@ -1192,6 +1225,16 @@ class PrintingGcodeFileInformation(PrintingFileInformation):
self._logger.exception("Exception while processing line") self._logger.exception("Exception while processing line")
raise e raise e
def _stripCommments(self):
dir = os.path.dirname(os.path.abspath(self._filename))
tmpfile = open(dir + '/gcode.tmp', 'w')
with open(self._filename, "r") as fileobject:
for line in fileobject:
if process_gcode_line(line) is not None:
tmpfile.write(line)
tmpfile.close()
self._filename = dir + '/gcode.tmp'
def convert_pause_triggers(configured_triggers): def convert_pause_triggers(configured_triggers):
triggers = { triggers = {
"enable": [], "enable": [],
@ -1256,6 +1299,7 @@ def serialList():
baselist = baselist \ baselist = baselist \
+ glob.glob("/dev/ttyUSB*") \ + glob.glob("/dev/ttyUSB*") \
+ glob.glob("/dev/ttyACM*") \ + glob.glob("/dev/ttyACM*") \
+ glob.glob("/dev/ttyAMA*") \
+ glob.glob("/dev/tty.usb*") \ + glob.glob("/dev/tty.usb*") \
+ glob.glob("/dev/cu.*") \ + glob.glob("/dev/cu.*") \
+ glob.glob("/dev/cuaU*") \ + glob.glob("/dev/cuaU*") \